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