1 /*
2  *  This file is part of RawTherapee.
3  *
4  *  Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
5  *
6  *  RawTherapee is free software: you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation, either version 3 of the License, or
9  *  (at your option) any later version.
10  *
11  *  RawTherapee is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with RawTherapee.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 #include <cstring>
20 #include <cstdio>
21 #include "image8.h"
22 #include "rtengine.h"
23 
24 using namespace rtengine;
25 
26 
Image8()27 Image8::Image8 ()
28 {
29 }
30 
Image8(int w,int h)31 Image8::Image8 (int w, int h)
32 {
33     allocate (w, h);
34 }
35 
~Image8()36 Image8::~Image8 ()
37 {
38 }
39 
getScanline(int row,unsigned char * buffer,int bps,bool isFloat) const40 void Image8::getScanline (int row, unsigned char* buffer, int bps, bool isFloat) const
41 {
42 
43     if (data == nullptr) {
44         return;
45     }
46 
47     if (bps == 8) {
48         memcpy (buffer, data + row * width * 3, width * 3);
49     } else if (bps == 16) {
50         unsigned short* sbuffer = (unsigned short*) buffer;
51 
52         for (int i = 0, ix = row * width * 3; i < width * 3; ++i, ++ix) {
53             sbuffer[i] = static_cast<unsigned short>(data[ix]) * 257;
54         }
55     }
56 }
57 
setScanline(int row,unsigned char * buffer,int bps,unsigned int numSamples)58 void Image8::setScanline (int row, unsigned char* buffer, int bps, unsigned int numSamples)
59 {
60 
61     if (data == nullptr) {
62         return;
63     }
64 
65     switch (sampleFormat) {
66     case (IIOSF_UNSIGNED_CHAR):
67         if(numSamples == 1) {
68             for(size_t i = 0; i < static_cast<size_t>(width); ++i) {
69                 data[row * width * 3 + 3 * i] = data[row * width * 3 + 3 * i + 1] = data[row * width * 3 + 3 * i + 2] = buffer[i];
70             }
71         } else {
72             memcpy (data + (uint64_t)row * (uint64_t)width * (uint64_t)3u, buffer, width * 3);
73         }
74         break;
75 
76     case (IIOSF_UNSIGNED_SHORT): {
77         unsigned short* sbuffer = (unsigned short*) buffer;
78 
79         for (int i = 0, ix = row * width * 3; i < width * 3; ++i, ++ix) {
80             data[ix] = uint16ToUint8Rounded(sbuffer[i]);
81         }
82 
83         break;
84     }
85 
86     default:
87         // Other type are ignored, but could be implemented if necessary
88         break;
89     }
90 }
91 
copy() const92 Image8* Image8::copy () const
93 {
94 
95     Image8* cp = new Image8 (width, height);
96     copyData(cp);
97     return cp;
98 }
99 
getStdImage(const ColorTemp & ctemp,int tran,Imagefloat * image,PreviewProps pp) const100 void Image8::getStdImage (const ColorTemp &ctemp, int tran, Imagefloat* image, PreviewProps pp) const
101 {
102     // compute channel multipliers
103     float rm = 1.f, gm = 1.f, bm = 1.f;
104     if (ctemp.getTemp() >= 0) {
105         double drm, dgm, dbm;
106         ctemp.getMultipliers (drm, dgm, dbm);
107         rm = drm;
108         gm = dgm;
109         bm = dbm;
110 
111         rm = 1.0 / rm;
112         gm = 1.0 / gm;
113         bm = 1.0 / bm;
114         float mul_lum = 0.299 * rm + 0.587 * gm + 0.114 * bm;
115         rm /= mul_lum;
116         gm /= mul_lum;
117         bm /= mul_lum;
118     }
119 
120     int sx1, sy1, sx2, sy2;
121 
122     transform (pp, tran, sx1, sy1, sx2, sy2);
123 
124     int imwidth = image->getWidth(); // Destination image
125     int imheight = image->getHeight(); // Destination image
126 
127     if (((tran & TR_ROT) == TR_R90) || ((tran & TR_ROT) == TR_R270)) {
128         int swap = imwidth;
129         imwidth = imheight;
130         imheight = swap;
131     }
132 
133     int maxx = width; // Source image
134     int maxy = height; // Source image
135     int mtran = tran & TR_ROT;
136     int skip = pp.getSkip();
137 
138     //if ((sx1 + skip*imwidth)>maxx) imwidth -- ; // we have a boundary condition that can cause errors
139 
140     // improve speed by integrating the area division into the multipliers
141     // switched to using ints for the red/green/blue channel buffer.
142     // Incidentally this improves accuracy too.
143     float area = skip * skip;
144     float rm2 = rm;
145     float gm2 = gm;
146     float bm2 = bm;
147     rm /= area;
148     gm /= area;
149     bm /= area;
150 
151 #define GCLIP( x ) Color::gamma_srgb(CLIP(x))
152 
153 #ifdef _OPENMP
154     #pragma omp parallel
155     {
156 #endif
157         AlignedBuffer<float> abR(imwidth);
158         AlignedBuffer<float> abG(imwidth);
159         AlignedBuffer<float> abB(imwidth);
160         float *lineR  = abR.data;
161         float *lineG  = abG.data;
162         float *lineB =  abB.data;
163 
164 #ifdef _OPENMP
165         #pragma omp for
166 #endif
167 
168         // Iterating all the rows of the destination image
169         for (int iy = 0; iy < imheight; iy++) {
170             if (skip == 1) {
171                 // special case (speedup for 1:1 scale)
172                 // i: source image, first line of the current destination row
173                 int src_y = sy1 + iy;
174 
175                 // overflow security check, not sure that it's necessary
176                 if (src_y >= maxy) {
177                     continue;
178                 }
179 
180                 for (int dst_x = 0, src_x = sx1; dst_x < imwidth; dst_x++, src_x++) {
181                     float r_, g_, b_;
182 
183                     // overflow security check, not sure that it's necessary
184                     if (src_x >= maxx) {
185                         continue;
186                     }
187 
188                     convertTo(r(src_y, src_x), r_);
189                     convertTo(g(src_y, src_x), g_);
190                     convertTo(b(src_y, src_x), b_);
191                     lineR[dst_x] = CLIP(rm2 * r_);
192                     lineG[dst_x] = CLIP(gm2 * g_);
193                     lineB[dst_x] = CLIP(bm2 * b_);
194                 }
195             } else {
196                 // source image, first line of the current destination row
197                 int src_y = sy1 + skip * iy;
198 
199                 if (src_y >= maxy) {
200                     continue;
201                 }
202 
203                 for (int dst_x = 0, src_x = sx1; dst_x < imwidth; dst_x++, src_x += skip) {
204                     if (src_x >= maxx) {
205                         continue;
206                     }
207 
208                     int src_sub_width = MIN(maxx - src_x, skip);
209                     int src_sub_height = MIN(maxy - src_y, skip);
210 
211                     float rtot, gtot, btot; // RGB accumulators
212                     rtot = gtot = btot = 0.;
213 
214                     for (int src_sub_y = 0; src_sub_y < src_sub_height; src_sub_y++)
215                         for (int src_sub_x = 0; src_sub_x < src_sub_width; src_sub_x++) {
216                             float r_, g_, b_;
217                             convertTo(r(src_y + src_sub_y, src_x + src_sub_x), r_);
218                             convertTo(g(src_y + src_sub_y, src_x + src_sub_x), g_);
219                             convertTo(b(src_y + src_sub_y, src_x + src_sub_x), b_);
220                             rtot += r_;
221                             gtot += g_;
222                             btot += b_;
223                         }
224 
225                     // convert back to gamma and clip
226                     if (src_sub_width == skip && src_sub_height == skip) {
227                         // Common case where the sub-region is complete
228                         lineR[dst_x] = CLIP(rm * rtot);
229                         lineG[dst_x] = CLIP(gm * gtot);
230                         lineB[dst_x] = CLIP(bm * btot);
231                     } else {
232                         // computing a special factor for this incomplete sub-region
233                         float area = src_sub_width * src_sub_height;
234                         lineR[dst_x] = CLIP(rm2 * rtot / area);
235                         lineG[dst_x] = CLIP(gm2 * gtot / area);
236                         lineB[dst_x] = CLIP(bm2 * btot / area);
237                     }
238                 }
239             }
240 
241             if      (mtran == TR_NONE)
242                 for (int dst_x = 0, src_x = sx1; dst_x < imwidth; dst_x++, src_x += skip) {
243                     image->r(iy, dst_x) = lineR[dst_x];
244                     image->g(iy, dst_x) = lineG[dst_x];
245                     image->b(iy, dst_x) = lineB[dst_x];
246                 }
247             else if (mtran == TR_R180)
248                 for (int dst_x = 0; dst_x < imwidth; dst_x++) {
249                     image->r(imheight - 1 - iy, imwidth - 1 - dst_x) = lineR[dst_x];
250                     image->g(imheight - 1 - iy, imwidth - 1 - dst_x) = lineG[dst_x];
251                     image->b(imheight - 1 - iy, imwidth - 1 - dst_x) = lineB[dst_x];
252                 }
253             else if (mtran == TR_R90)
254                 for (int dst_x = 0, src_x = sx1; dst_x < imwidth; dst_x++, src_x += skip) {
255                     image->r(dst_x, imheight - 1 - iy) = lineR[dst_x];
256                     image->g(dst_x, imheight - 1 - iy) = lineG[dst_x];
257                     image->b(dst_x, imheight - 1 - iy) = lineB[dst_x];
258                 }
259             else if (mtran == TR_R270)
260                 for (int dst_x = 0, src_x = sx1; dst_x < imwidth; dst_x++, src_x += skip) {
261                     image->r(imwidth - 1 - dst_x, iy) = lineR[dst_x];
262                     image->g(imwidth - 1 - dst_x, iy) = lineG[dst_x];
263                     image->b(imwidth - 1 - dst_x, iy) = lineB[dst_x];
264                 }
265         }
266 
267 #ifdef _OPENMP
268     }
269 #endif
270 #undef GCLIP
271 }
272