/* * 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 "imagefloat.h" #include "image16.h" #include "image8.h" #include #include "rtengine.h" #include "mytime.h" #include "iccstore.h" #include "alignedbuffer.h" #include "rt_math.h" #include "color.h" using namespace rtengine; Imagefloat::Imagefloat () { } Imagefloat::Imagefloat (int w, int h) { allocate (w, h); } Imagefloat::~Imagefloat () { } // Call this method to handle floating points input values of different size void Imagefloat::setScanline (int row, unsigned char* buffer, int bps, float *minValue, float *maxValue) { if (data==NULL) return; switch (sampleFormat) { case (IIOSF_FLOAT): { int ix = 0; float* sbuffer = (float*) buffer; for (int i=0; imaxValue[0]) maxValue[0] = sbuffer[ix]; ++ix; } g(row,i) = sbuffer[ix]; if (minValue) { if (sbuffer[ix]maxValue[1]) maxValue[1] = sbuffer[ix]; ++ix; } b(row,i) = sbuffer[ix]; if (minValue) { if (sbuffer[ix]maxValue[2]) maxValue[2] = sbuffer[ix]; ++ix; } } break; } case (IIOSF_LOGLUV24): case (IIOSF_LOGLUV32): { int ix = 0; float* sbuffer = (float*) buffer; float xyzvalues[3], rgbvalues[3]; for (int i=0; imaxValue[0]) maxValue[0] = rgbvalues[0]; } g(row,i) = rgbvalues[1]; if (minValue) { if (rgbvalues[1]maxValue[1]) maxValue[1] = rgbvalues[1]; } b(row,i) = rgbvalues[2]; if (minValue) { if (rgbvalues[2]maxValue[2]) maxValue[2] = rgbvalues[2]; } } break; } default: // Other type are ignored, but could be implemented if necessary break; } } void Imagefloat::getScanline (int row, unsigned char* buffer, int bps) { if (data==NULL) return; if (bps==32) { int ix = 0; float* sbuffer = (float*) buffer; for (int i=0; iwidth; // Destination image int imheight=image->height; // Destination image if (((tran & TR_ROT) == TR_R90)||((tran & TR_ROT) == TR_R270)) { int swap = imwidth; imwidth=imheight; imheight=swap; } int maxx=width; // Source image int maxy=height; // Source image int mtran = tran & TR_ROT; int skip = pp.skip; // improve speed by integrating the area division into the multipliers // switched to using ints for the red/green/blue channel buffer. // Incidentally this improves accuracy too. float area=skip*skip; float rm2=rm; float gm2=gm; float bm2=bm; rm/=area; gm/=area; bm/=area; #ifdef _OPENMP #pragma omp parallel { #endif AlignedBuffer abR(imwidth); AlignedBuffer abG(imwidth); AlignedBuffer abB(imwidth); float *lineR = abR.data; float *lineG = abG.data; float *lineB = abB.data; #ifdef _OPENMP #pragma omp for #endif for (int iy=0; iy=maxy) continue; for (int dst_x=0,src_x=sx1; dst_x=maxx) continue; lineR[dst_x] = CLIP(rm2*r(src_y, src_x)); lineG[dst_x] = CLIP(gm2*g(src_y, src_x)); lineB[dst_x] = CLIP(bm2*b(src_y, src_x)); } } else { // source image, first line of the current destination row int src_y=sy1+skip*iy; if (src_y>=maxy) continue; for (int dst_x=0,src_x=sx1; dst_x=maxx) continue; int src_sub_width = MIN(maxx-src_x, skip); int src_sub_height = MIN(maxy-src_y, skip); float rtot,gtot,btot; // RGB accumulators rtot=gtot=btot=0.; for (int src_sub_y=0; src_sub_yr(iy, dst_x) = lineR[dst_x]; image->g(iy, dst_x) = lineG[dst_x]; image->b(iy, dst_x) = lineB[dst_x]; } else if (mtran == TR_R180) for (int dst_x=0; dst_xr(imheight-1-iy, imwidth-1-dst_x) = lineR[dst_x]; image->g(imheight-1-iy, imwidth-1-dst_x) = lineG[dst_x]; image->b(imheight-1-iy, imwidth-1-dst_x) = lineB[dst_x]; } else if (mtran == TR_R90) for (int dst_x=0,src_x=sx1; dst_xr(dst_x, imheight-1-iy) = lineR[dst_x]; image->g(dst_x, imheight-1-iy) = lineG[dst_x]; image->b(dst_x, imheight-1-iy) = lineB[dst_x]; } else if (mtran == TR_R270) for (int dst_x=0,src_x=sx1; dst_xr(imwidth-1-dst_x, iy) = lineR[dst_x]; image->g(imwidth-1-dst_x, iy) = lineG[dst_x]; image->b(imwidth-1-dst_x, iy) = lineB[dst_x]; } } #ifdef _OPENMP } #endif } Image8* Imagefloat::to8() { Image8* img8 = new Image8(width,height); #ifdef _OPENMP #pragma omp parallel for schedule(static) #endif for ( int h=0; h < height; ++h ) { for ( int w=0; w < width; ++w ) { img8->r(h, w) = (unsigned char)( (unsigned short)(r(h,w)) >> 8); img8->g(h, w) = (unsigned char)( (unsigned short)(g(h,w)) >> 8); img8->b(h, w) = (unsigned char)( (unsigned short)(b(h,w)) >> 8); } } return img8; } Image16* Imagefloat::to16() { Image16* img16 = new Image16(width,height); #ifdef _OPENMP #pragma omp parallel for schedule(static) #endif for ( int h=0; h < height; ++h ) { for ( int w=0; w < width; ++w ) { img16->r( h,w) = (unsigned short)(r(h,w)); img16->g( h,w) = (unsigned short)(g(h,w)); img16->b( h,w) = (unsigned short)(b(h,w)); } } return img16; } void Imagefloat::normalizeFloat(float srcMinVal, float srcMaxVal) { float scale = MAXVALD / (srcMaxVal-srcMinVal); int w = width; int h = height; #ifdef _OPENMP #pragma omp parallel for firstprivate(w, h, srcMinVal, scale) schedule(dynamic, 5) #endif for (int y=0; yworkingSpaceMatrix (params.icm.working); float facRed = wprof[1][0]; float facGreen = wprof[1][1]; float facBlue = wprof[1][2]; // calc pixel size int x1, x2, y1, y2; params.crop.mapToResized(width, height, scale, x1, x2, y1, y2); #pragma omp parallel { LUTu histThr(65536); histThr.clear(); #pragma omp for nowait for (int y=y1; y65535) i=65535; histThr[i]++; } } #pragma omp critical { for(int i=0;i<=0xffff;i++) hist[i] += histThr[i]; } } } // Parallelized transformation; create transform with cmsFLAGS_NOCACHE! void Imagefloat::ExecCMSTransform(cmsHTRANSFORM hTransform) { // LittleCMS cannot parallelize planar setups -- Hombre: LCMS2.4 can! But it we use this new feature, memory allocation // have to be modified too to build temporary buffers that allow multi processor execution #ifdef _OPENMP #pragma omp parallel #endif { AlignedBuffer pBuf(width*3); #ifdef _OPENMP #pragma omp for schedule(static) #endif for (int y=0; y