/* * This file is part of RawTherapee. * * Copyright (c) 2004-2010 Gabor Horvath * * RawTherapee is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * RawTherapee is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ #include #include #ifdef _OPENMP #include #endif #include namespace rtengine { #undef CMAXVAL #undef MAX #undef MIN #undef CLIP #undef CLIPTO #undef CLIPTOC #define CMAXVAL 0xffff #define MAX(a,b) ((a)<(b)?(b):(a)) #define MIN(a,b) ((a)>(b)?(b):(a)) #define CLIP(a) ((a)>0?((a)(b)?((a)<(c)?(a):(c)):(b)) #define CLIPTOC(a,b,c,d) ((a)>=(b)?((a)<=(c)?(a):(d=true,(c))):(d=true,(b))) bool ImProcFunctions::transCoord (int W, int H, std::vector &src, std::vector &red, std::vector &green, std::vector &blue, double ascaleDef) { bool clipresize = true; bool clipped = false; red.clear (); green.clear (); blue.clear (); if (!needsCA() && !needsDistortion() && !needsRotation() && !needsPerspective()) { if (clipresize) { // Apply resizing if (fabs(params->resize.scale-1.0)>=1e-7) { for (int i=0; iresize.scale, src[i].y / params->resize.scale)); green.push_back (Coord2D (src[i].x / params->resize.scale, src[i].y / params->resize.scale)); blue.push_back (Coord2D (src[i].x / params->resize.scale, src[i].y / params->resize.scale)); } for (int i=0; iresize.scale; double oH = H*params->resize.scale; double w2 = (double) oW / 2.0 - 0.5; double h2 = (double) oH / 2.0 - 0.5; double a = params->distortion.amount; double cost = cos(params->rotate.degree * 3.14/180.0); double sint = sin(params->rotate.degree * 3.14/180.0); double maxRadius = sqrt( (double)( oW*oW + oH*oH ) ) / 2; double vpdeg = params->perspective.vertical / 100.0 * 45.0; double vpalpha = (90.0 - vpdeg) / 180.0 * 3.14; double vpteta = fabs(vpalpha-3.14/2)<1e-3 ? 0.0 : acos ((vpdeg>0 ? 1.0 : -1.0) * sqrt((-oW*oW*tan(vpalpha)*tan(vpalpha) + (vpdeg>0 ? 1.0 : -1.0) * oW*tan(vpalpha)*sqrt(16*maxRadius*maxRadius+oW*oW*tan(vpalpha)*tan(vpalpha)))/(maxRadius*maxRadius*8))); double vpcospt = (vpdeg>=0 ? 1.0 : -1.0) * cos (vpteta), vptanpt = tan (vpteta); double hpdeg = params->perspective.horizontal / 100.0 * 45.0; double hpalpha = (90.0 - hpdeg) / 180.0 * 3.14; double hpteta = fabs(hpalpha-3.14/2)<1e-3 ? 0.0 : acos ((hpdeg>0 ? 1.0 : -1.0) * sqrt((-oH*oH*tan(hpalpha)*tan(hpalpha) + (hpdeg>0 ? 1.0 : -1.0) * oH*tan(hpalpha)*sqrt(16*maxRadius*maxRadius+oH*oH*tan(hpalpha)*tan(hpalpha)))/(maxRadius*maxRadius*8))); double hpcospt = (hpdeg>=0 ? 1.0 : -1.0) * cos (hpteta), hptanpt = tan (hpteta); double ascale = ascaleDef>0 ? ascaleDef : (params->commonTrans.autofill ? getTransformAutoFill (oW, oH) : 1.0); for (int i=0; icacorrection.red)+w2, Dy*(s+params->cacorrection.red)+h2)); green.push_back (Coord2D(Dx*s+w2, Dy*s+h2)); blue.push_back (Coord2D(Dx*(s+params->cacorrection.blue)+w2, Dy*(s+params->cacorrection.blue)+h2)); } if (clipresize) { if (fabs(params->resize.scale-1.0)>=1e-7) { for (int i=0; iresize.scale; red[i].y /= params->resize.scale; green[i].x /= params->resize.scale; green[i].y /= params->resize.scale; blue[i].x /= params->resize.scale; blue[i].y /= params->resize.scale; } } for (int i=0; i corners (8); corners[0].set (x1, y1); corners[1].set (x1, y2); corners[2].set (x2, y2); corners[3].set (x2, y1); corners[4].set ((x1+x2)/2, y1); corners[5].set ((x1+x2)/2, y2); corners[6].set (x1, (y1+y2)/2); corners[7].set (x2, (y1+y2)/2); int xstep = (x2-x1)/16; if (xstep<1) xstep = 1; for (int i=x1+xstep; i<=x2-xstep; i+=xstep) { corners.push_back (Coord2D (i, y1)); corners.push_back (Coord2D (i, y2)); } int ystep = (y2-y1)/16; if (ystep<1) ystep = 1; for (int i=y1+ystep; i<=y2-ystep; i+=ystep) { corners.push_back (Coord2D (x1, i)); corners.push_back (Coord2D (x2, i)); } std::vector r, g, b; bool result = transCoord (W, H, corners, r, g, b, ascaleDef); std::vector transCorners; transCorners.insert (transCorners.end(), r.begin(), r.end()); transCorners.insert (transCorners.end(), g.begin(), g.end()); transCorners.insert (transCorners.end(), b.begin(), b.end()); double x1d = transCorners[0].x; for (int i=1; ix2d) x2d = transCorners[i].x; int x2v = (int)ceil(x2d); double y2d = transCorners[0].y; for (int i=1; iy2d) y2d = transCorners[i].y; int y2v = (int)ceil(y2d); xv = x1v; yv = y1v; wv = x2v - x1v + 1; hv = y2v - y1v + 1; return result; } void ImProcFunctions::transform (Image16* original, Image16* transformed, int cx, int cy, int sx, int sy, int oW, int oH) { if (!(needsCA() || needsDistortion() || needsRotation() || needsPerspective()) && needsVignetting()) vignetting (original, transformed, cx, cy, oW, oH); else if (!needsCA()) { if (scale==1) transformNonSep (original, transformed, cx, cy, sx, sy, oW, oH); else simpltransform (original, transformed, cx, cy, sx, sy, oW, oH); } else transformSep (original, transformed, cx, cy, sx, sy, oW, oH); } void calcVignettingParams(int oW, int oH, const VignettingParams& vignetting, double &w2, double &h2, double& maxRadius, double &v, double &b, double &mul) { // vignette center is a point with coordinates between -1 and +1 double x = vignetting.centerX / 100.0; double y = vignetting.centerY / 100.0; // calculate vignette center in pixels w2 = (double) oW / 2.0 - 0.5 + x * oW; h2 = (double) oH / 2.0 - 0.5 + y * oH; // max vignette radius in pixels maxRadius = sqrt( (double)( oW*oW + oH*oH ) ) / 2.; // vignette variables with applied strength v = 1.0 - vignetting.strength * vignetting.amount * 3.0 / 400.0; b = 1.0 + vignetting.radius * 7.0 / 100.0; mul = (1.0-v) / tanh(b); } void ImProcFunctions::vignetting (Image16* original, Image16* transformed, int cx, int cy, int oW, int oH) { double vig_w2; double vig_h2; double maxRadius; double v; double b; double mul; calcVignettingParams(oW, oH, params->vignetting, vig_w2, vig_h2, maxRadius, v, b, mul); #pragma omp parallel for if (multiThread) for (int y=0; yheight; y++) { double vig_y_d = (double) (y + cy) - vig_h2 ; int val; for (int x=0; xwidth; x++) { double vig_x_d = (double) (x + cx) - vig_w2 ; double r = sqrt(vig_x_d*vig_x_d + vig_y_d*vig_y_d); double vign = v + mul * tanh (b*(maxRadius-r) / maxRadius); val = original->r[y][x] / vign; transformed->r[y][x] = CLIP(val); val = original->g[y][x] / vign; transformed->g[y][x] = CLIP(val); val = original->b[y][x] / vign; transformed->b[y][x] = CLIP(val); } } } #include "cubint.cc" void ImProcFunctions::transformNonSep (Image16* original, Image16* transformed, int cx, int cy, int sx, int sy, int oW, int oH) { double w2 = (double) oW / 2.0 - 0.5; double h2 = (double) oH / 2.0 - 0.5; double vig_w2; double vig_h2; double maxRadius; double v; double b; double mul; calcVignettingParams(oW, oH, params->vignetting, vig_w2, vig_h2, maxRadius, v, b, mul); // auxiliary variables for distortion correction double a = params->distortion.amount; // auxiliary variables for rotation double cost = cos(params->rotate.degree * 3.14/180.0); double sint = sin(params->rotate.degree * 3.14/180.0); bool dovign = params->vignetting.amount != 0; // auxiliary variables for vertical perspective correction double vpdeg = params->perspective.vertical / 100.0 * 45.0; double vpalpha = (90.0 - vpdeg) / 180.0 * 3.14; double vpteta = fabs(vpalpha-3.14/2)<1e-3 ? 0.0 : acos ((vpdeg>0 ? 1.0 : -1.0) * sqrt((-oW*oW*tan(vpalpha)*tan(vpalpha) + (vpdeg>0 ? 1.0 : -1.0) * oW*tan(vpalpha)*sqrt(16*maxRadius*maxRadius+oW*oW*tan(vpalpha)*tan(vpalpha)))/(maxRadius*maxRadius*8))); double vpcospt = (vpdeg>=0 ? 1.0 : -1.0) * cos (vpteta), vptanpt = tan (vpteta); // auxiliary variables for horizontal perspective correction double hpdeg = params->perspective.horizontal / 100.0 * 45.0; double hpalpha = (90.0 - hpdeg) / 180.0 * 3.14; double hpteta = fabs(hpalpha-3.14/2)<1e-3 ? 0.0 : acos ((hpdeg>0 ? 1.0 : -1.0) * sqrt((-oH*oH*tan(hpalpha)*tan(hpalpha) + (hpdeg>0 ? 1.0 : -1.0) * oH*tan(hpalpha)*sqrt(16*maxRadius*maxRadius+oH*oH*tan(hpalpha)*tan(hpalpha)))/(maxRadius*maxRadius*8))); double hpcospt = (hpdeg>=0 ? 1.0 : -1.0) * cos (hpteta), hptanpt = tan (hpteta); double ascale = params->commonTrans.autofill ? getTransformAutoFill (oW, oH) : 1.0; // main cycle #pragma omp parallel for if (multiThread) for (int y=0; yheight; y++) { for (int x=0; xwidth; x++) { double x_d = ascale * (x + cx - w2); // centering x coord & scale double y_d = ascale * (y + cy - h2); // centering y coord & scale double vig_x_d = ascale * (x + cx - vig_w2); // centering x coord & scale double vig_y_d = ascale * (y + cy - vig_h2); // centering y coord & scale // horizontal perspective transformation y_d = y_d * maxRadius / (maxRadius + x_d*hptanpt); x_d = x_d * maxRadius * hpcospt / (maxRadius + x_d*hptanpt); // vertical perspective transformation x_d = x_d * maxRadius / (maxRadius - y_d*vptanpt); y_d = y_d * maxRadius * vpcospt / (maxRadius - y_d*vptanpt); // rotate double Dx = x_d * cost - y_d * sint; double Dy = x_d * sint + y_d * cost; // distortion correction double r = sqrt(Dx*Dx + Dy*Dy) / maxRadius; double s = 1.0 - a + a * r ; Dx *= s; Dy *= s; double vig_Dx = vig_x_d * cost - vig_y_d * sint; double vig_Dy = vig_x_d * sint + vig_y_d * cost; double r2 = sqrt(vig_Dx*vig_Dx + vig_Dy*vig_Dy); // de-center Dx += w2; Dy += h2; // Extract integer and fractions of source screen coordinates int xc = (int)Dx; Dx -= (double)xc; xc -= sx; int yc = (int)Dy; Dy -= (double)yc; yc -= sy; // Convert only valid pixels if (yc>=0 && ycheight && xc>=0 && xcwidth) { // multiplier for vignetting correction double vignmul = 1.0; if (dovign) vignmul /= (v + mul * tanh (b*(maxRadius-s*r2) / maxRadius)); if (yc > 0 && yc < original->height-2 && xc > 0 && xc < original->width-2) // all interpolation pixels inside image cubint (original, xc-1, yc-1, Dx, Dy, &(transformed->r[y][x]), &(transformed->g[y][x]), &(transformed->b[y][x]), vignmul); else { // edge pixels int y1 = CLIPTO(yc, 0, original->height-1); int y2 = CLIPTO(yc+1, 0, original->height-1); int x1 = CLIPTO(xc, 0, original->width-1); int x2 = CLIPTO(xc+1, 0, original->width-1); int r = vignmul*(original->r[y1][x1]*(1.0-Dx)*(1.0-Dy) + original->r[y1][x2]*Dx*(1.0-Dy) + original->r[y2][x1]*(1.0-Dx)*Dy + original->r[y2][x2]*Dx*Dy); int g = vignmul*(original->g[y1][x1]*(1.0-Dx)*(1.0-Dy) + original->g[y1][x2]*Dx*(1.0-Dy) + original->g[y2][x1]*(1.0-Dx)*Dy + original->g[y2][x2]*Dx*Dy); int b = vignmul*(original->b[y1][x1]*(1.0-Dx)*(1.0-Dy) + original->b[y1][x2]*Dx*(1.0-Dy) + original->b[y2][x1]*(1.0-Dx)*Dy + original->b[y2][x2]*Dx*Dy); transformed->r[y][x] = CLIP(r); transformed->g[y][x] = CLIP(g); transformed->b[y][x] = CLIP(b); } } else { // not valid (source pixel x,y not inside source image, etc.) transformed->r[y][x] = 0; transformed->g[y][x] = 0; transformed->b[y][x] = 0; } } } } #include "cubintch.cc" void ImProcFunctions::transformSep (Image16* original, Image16* transformed, int cx, int cy, int sx, int sy, int oW, int oH) { double w2 = (double) oW / 2.0 - 0.5; double h2 = (double) oH / 2.0 - 0.5; double vig_w2; double vig_h2; double maxRadius; double v; double b; double mul; calcVignettingParams(oW, oH, params->vignetting, vig_w2, vig_h2, maxRadius, v, b, mul); // auxiliary variables for c/a correction double cdist[3]; cdist[0] = params->cacorrection.red; cdist[1] = 0.0; cdist[2] = params->cacorrection.blue; unsigned short** chorig[3]; chorig[0] = original->r; chorig[1] = original->g; chorig[2] = original->b; unsigned short** chtrans[3]; chtrans[0] = transformed->r; chtrans[1] = transformed->g; chtrans[2] = transformed->b; // auxiliary variables for distortion correction double a = params->distortion.amount; // auxiliary variables for rotation double cost = cos(params->rotate.degree * 3.14/180.0); double sint = sin(params->rotate.degree * 3.14/180.0); bool dovign = params->vignetting.amount != 0; // auxiliary variables for vertical perspective correction double vpdeg = params->perspective.vertical / 100.0 * 45.0; double vpalpha = (90.0 - vpdeg) / 180.0 * 3.14; double vpteta = fabs(vpalpha-3.14/2)<1e-3 ? 0.0 : acos ((vpdeg>0 ? 1.0 : -1.0) * sqrt((-oW*oW*tan(vpalpha)*tan(vpalpha) + (vpdeg>0 ? 1.0 : -1.0) * oW*tan(vpalpha)*sqrt(16*maxRadius*maxRadius+oW*oW*tan(vpalpha)*tan(vpalpha)))/(maxRadius*maxRadius*8))); double vpcospt = (vpdeg>=0 ? 1.0 : -1.0) * cos (vpteta), vptanpt = tan (vpteta); // auxiliary variables for horizontal perspective correction double hpdeg = params->perspective.horizontal / 100.0 * 45.0; double hpalpha = (90.0 - hpdeg) / 180.0 * 3.14; double hpteta = fabs(hpalpha-3.14/2)<1e-3 ? 0.0 : acos ((hpdeg>0 ? 1.0 : -1.0) * sqrt((-oH*oH*tan(hpalpha)*tan(hpalpha) + (hpdeg>0 ? 1.0 : -1.0) * oH*tan(hpalpha)*sqrt(16*maxRadius*maxRadius+oH*oH*tan(hpalpha)*tan(hpalpha)))/(maxRadius*maxRadius*8))); double hpcospt = (hpdeg>=0 ? 1.0 : -1.0) * cos (hpteta), hptanpt = tan (hpteta); double ascale = params->commonTrans.autofill ? getTransformAutoFill (oW, oH) : 1.0; // main cycle #pragma omp parallel for if (multiThread) for (int y=0; yheight; y++) { for (int x=0; xwidth; x++) { double x_d = ascale * (x + cx - w2); // centering x coord & scale double y_d = ascale * (y + cy - h2); // centering y coord & scale double vig_x_d = ascale * (x + cx - vig_w2); // centering x coord & scale double vig_y_d = ascale * (y + cy - vig_h2); // centering y coord & scale // horizontal perspective transformation y_d = y_d * maxRadius / (maxRadius + x_d*hptanpt); x_d = x_d * maxRadius * hpcospt / (maxRadius + x_d*hptanpt); // vertical perspective transformation x_d = x_d * maxRadius / (maxRadius - y_d*vptanpt); y_d = y_d * maxRadius * vpcospt / (maxRadius - y_d*vptanpt); // rotate double Dxc = x_d * cost - y_d * sint; double Dyc = x_d * sint + y_d * cost; // distortion correction double r = sqrt(Dxc*Dxc + Dyc*Dyc) / maxRadius; double s = 1.0 - a + a * r ; double vig_Dx = vig_x_d * cost - vig_y_d * sint; double vig_Dy = vig_x_d * sint + vig_y_d * cost; double r2 = sqrt(vig_Dx*vig_Dx + vig_Dy*vig_Dy); for (int c=0; c<3; c++) { double Dx = Dxc * (s + cdist[c]); double Dy = Dyc * (s + cdist[c]); // de-center Dx += w2; Dy += h2; // Extract integer and fractions of source screen coordinates int xc = (int)Dx; Dx -= (double)xc; xc -= sx; int yc = (int)Dy; Dy -= (double)yc; yc -= sy; // Convert only valid pixels if (yc>=0 && ycheight && xc>=0 && xcwidth) { // multiplier for vignetting correction double vignmul = 1.0; if (dovign) vignmul /= (v + mul * tanh (b*(maxRadius-s*r2) / maxRadius)); if (yc > 0 && yc < original->height-2 && xc > 0 && xc < original->width-2) // all interpolation pixels inside image cubintch (chorig[c], xc-1, yc-1, Dx, Dy, &(chtrans[c][y][x]), vignmul); else { // edge pixels int y1 = CLIPTO(yc, 0, original->height-1); int y2 = CLIPTO(yc+1, 0, original->height-1); int x1 = CLIPTO(xc, 0, original->width-1); int x2 = CLIPTO(xc+1, 0, original->width-1); int val = vignmul*(chorig[c][y1][x1]*(1.0-Dx)*(1.0-Dy) + chorig[c][y1][x2]*Dx*(1.0-Dy) + chorig[c][y2][x1]*(1.0-Dx)*Dy + chorig[c][y2][x2]*Dx*Dy); chtrans[c][y][x] = CLIP(val); } } else // not valid (source pixel x,y not inside source image, etc.) chtrans[c][y][x] = 0; } } } } void ImProcFunctions::simpltransform (Image16* original, Image16* transformed, int cx, int cy, int sx, int sy, int oW, int oH) { double w2 = (double) oW / 2.0 - 0.5; double h2 = (double) oH / 2.0 - 0.5; double vig_w2; double vig_h2; double maxRadius; double v; double b; double mul; calcVignettingParams(oW, oH, params->vignetting, vig_w2, vig_h2, maxRadius, v, b, mul); // auxiliary variables for distortion correction double a = params->distortion.amount; // auxiliary variables for rotation double cost = cos(params->rotate.degree * 3.14/180.0); double sint = sin(params->rotate.degree * 3.14/180.0); bool dovign = params->vignetting.amount != 0; // auxiliary variables for vertical perspective correction double vpdeg = params->perspective.vertical / 100.0 * 45.0; double vpalpha = (90 - vpdeg) / 180.0 * 3.14; double vpteta = fabs(vpalpha-3.14/2)<1e-3 ? 0.0 : acos ((vpdeg>0 ? 1.0 : -1.0) * sqrt((-oW*oW*tan(vpalpha)*tan(vpalpha) + (vpdeg>0 ? 1.0 : -1.0) * oW*tan(vpalpha)*sqrt(16*maxRadius*maxRadius+oW*oW*tan(vpalpha)*tan(vpalpha)))/(maxRadius*maxRadius*8))); double vpcospt = (vpdeg>=0 ? 1.0 : -1.0) * cos (vpteta), vptanpt = tan (vpteta); // auxiliary variables for horizontal perspective correction double hpdeg = params->perspective.horizontal / 100.0 * 45.0; double hpalpha = (90 - hpdeg) / 180.0 * 3.14; double hpteta = fabs(hpalpha-3.14/2)<1e-3 ? 0.0 : acos ((hpdeg>0 ? 1.0 : -1.0) * sqrt((-oH*oH*tan(hpalpha)*tan(hpalpha) + (hpdeg>0 ? 1.0 : -1.0) * oH*tan(hpalpha)*sqrt(16*maxRadius*maxRadius+oH*oH*tan(hpalpha)*tan(hpalpha)))/(maxRadius*maxRadius*8))); double hpcospt = (hpdeg>=0 ? 1.0 : -1.0) * cos (hpteta), hptanpt = tan (hpteta); double ascale = params->commonTrans.autofill ? getTransformAutoFill (oW, oH) : 1.0; // main cycle #pragma omp parallel for if (multiThread) for (int y=0; yheight; y++) { for (int x=0; xwidth; x++) { double y_d = ascale * (y + cy - h2); // centering y coord & scale double x_d = ascale * (x + cx - w2); // centering x coord & scale double vig_x_d = ascale * (x + cx - vig_w2); // centering x coord & scale double vig_y_d = ascale * (y + cy - vig_h2); // centering y coord & scale // horizontal perspective transformation y_d = y_d * maxRadius / (maxRadius + x_d*hptanpt); x_d = x_d * maxRadius * hpcospt / (maxRadius + x_d*hptanpt); // vertical perspective transformation x_d = x_d * maxRadius / (maxRadius - y_d*vptanpt); y_d = y_d * maxRadius * vpcospt / (maxRadius - y_d*vptanpt); // rotate double Dx = x_d * cost - y_d * sint; double Dy = x_d * sint + y_d * cost; // distortion correction double r = sqrt(Dx*Dx + Dy*Dy) / maxRadius; double s = 1.0 - a + a * r ; Dx *= s; Dy *= s; double vig_Dx = vig_x_d * cost - vig_y_d * sint; double vig_Dy = vig_x_d * sint + vig_y_d * cost; double r2 = sqrt(vig_Dx*vig_Dx + vig_Dy*vig_Dy); // de-center Dx += w2; Dy += h2; // Extract integer and fractions of source screen coordinates int xc = (int)Dx; Dx -= (double)xc; xc -= sx; int yc = (int)Dy; Dy -= (double)yc; yc -= sy; // Convert only valid pixels if (yc>=0 && ycheight && xc>=0 && xcwidth) { // multiplier for vignetting correction double vignmul = 1.0; if (dovign) vignmul /= (v + mul * tanh (b*(maxRadius-s*r2) / maxRadius)); if (yc < original->height-1 && xc < original->width-1) { // all interpolation pixels inside image int r = vignmul*(original->r[yc][xc]*(1.0-Dx)*(1.0-Dy) + original->r[yc][xc+1]*Dx*(1.0-Dy) + original->r[yc+1][xc]*(1.0-Dx)*Dy + original->r[yc+1][xc+1]*Dx*Dy); int g = vignmul*(original->g[yc][xc]*(1.0-Dx)*(1.0-Dy) + original->g[yc][xc+1]*Dx*(1.0-Dy) + original->g[yc+1][xc]*(1.0-Dx)*Dy + original->g[yc+1][xc+1]*Dx*Dy); int b = vignmul*(original->b[yc][xc]*(1.0-Dx)*(1.0-Dy) + original->b[yc][xc+1]*Dx*(1.0-Dy) + original->b[yc+1][xc]*(1.0-Dx)*Dy + original->b[yc+1][xc+1]*Dx*Dy); transformed->r[y][x] = CLIP(r); transformed->g[y][x] = CLIP(g); transformed->b[y][x] = CLIP(b); } else { // edge pixels int y1 = CLIPTO(yc, 0, original->height-1); int y2 = CLIPTO(yc+1, 0, original->height-1); int x1 = CLIPTO(xc, 0, original->width-1); int x2 = CLIPTO(xc+1, 0, original->width-1); int r = vignmul*(original->r[y1][x1]*(1.0-Dx)*(1.0-Dy) + original->r[y1][x2]*Dx*(1.0-Dy) + original->r[y2][x1]*(1.0-Dx)*Dy + original->r[y2][x2]*Dx*Dy); int g = vignmul*(original->g[y1][x1]*(1.0-Dx)*(1.0-Dy) + original->g[y1][x2]*Dx*(1.0-Dy) + original->g[y2][x1]*(1.0-Dx)*Dy + original->g[y2][x2]*Dx*Dy); int b = vignmul*(original->b[y1][x1]*(1.0-Dx)*(1.0-Dy) + original->b[y1][x2]*Dx*(1.0-Dy) + original->b[y2][x1]*(1.0-Dx)*Dy + original->b[y2][x2]*Dx*Dy); transformed->r[y][x] = CLIP(r); transformed->g[y][x] = CLIP(g); transformed->b[y][x] = CLIP(b); } } else { // not valid (source pixel x,y not inside source image, etc.) transformed->r[y][x] = 0; transformed->g[y][x] = 0; transformed->b[y][x] = 0; } } } } double ImProcFunctions::getTransformAutoFill (int oW, int oH) { double scaleU = 1.0; double scaleL = 0.001; while (scaleU - scaleL > 0.001) { double scale = (scaleU + scaleL) / 2.0; int orx, ory, orw, orh; bool clipped = transCoord (oW, oH, 0, 0, oW, oH, orx, ory, orw, orh, scale); if (clipped) scaleU = scale; else scaleL = scale; } return scaleL; } bool ImProcFunctions::needsCA () { return fabs (params->cacorrection.red) > 1e-15 || fabs (params->cacorrection.blue) > 1e-15; } bool ImProcFunctions::needsDistortion () { return fabs (params->distortion.amount) > 1e-15; } bool ImProcFunctions::needsRotation () { return fabs (params->rotate.degree) > 1e-15; } bool ImProcFunctions::needsPerspective () { return params->perspective.horizontal || params->perspective.vertical; } bool ImProcFunctions::needsVignetting () { return params->vignetting.amount; } bool ImProcFunctions::needsTransform () { return needsCA () || needsDistortion () || needsRotation () || needsPerspective () || needsVignetting (); } }