1 //******************************************************************************
2 ///
3 /// @file base/image/image.cpp
4 ///
5 /// Implementation of image containers.
6 ///
7 /// @copyright
8 /// @parblock
9 ///
10 /// Persistence of Vision Ray Tracer ('POV-Ray') version 3.8.
11 /// Copyright 1991-2018 Persistence of Vision Raytracer Pty. Ltd.
12 ///
13 /// POV-Ray is free software: you can redistribute it and/or modify
14 /// it under the terms of the GNU Affero General Public License as
15 /// published by the Free Software Foundation, either version 3 of the
16 /// License, or (at your option) any later version.
17 ///
18 /// POV-Ray is distributed in the hope that it will be useful,
19 /// but WITHOUT ANY WARRANTY; without even the implied warranty of
20 /// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 /// GNU Affero General Public License for more details.
22 ///
23 /// You should have received a copy of the GNU Affero General Public License
24 /// along with this program. If not, see <http://www.gnu.org/licenses/>.
25 ///
26 /// ----------------------------------------------------------------------------
27 ///
28 /// POV-Ray is based on the popular DKB raytracer version 2.12.
29 /// DKBTrace was originally written by David K. Buck.
30 /// DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
31 ///
32 /// @endparblock
33 ///
34 //******************************************************************************
35
36 // Unit header file must be the first file included within POV-Ray *.cpp files (pulls in config)
37 #include "base/image/image.h"
38
39 // Standard C++ header files
40 #include <algorithm>
41 #include <vector>
42
43 // Standard POSIX header files
44 #include <fcntl.h>
45 #include <sys/stat.h>
46 #include <sys/types.h>
47
48 // POV-Ray header files (base module)
49 #include "base/platformbase.h"
50 #include "base/safemath.h"
51 #include "base/image/bmp.h"
52 #include "base/image/dither.h"
53 #include "base/image/gif.h"
54 #include "base/image/hdr.h"
55 #include "base/image/iff.h"
56 #include "base/image/jpeg_pov.h"
57 #include "base/image/openexr.h"
58 #include "base/image/png_pov.h"
59 #include "base/image/ppm.h"
60 #include "base/image/targa.h"
61 #include "base/image/tiff_pov.h"
62
63 // this must be the last file included
64 #include "base/povdebug.h"
65
66 #define CHECK_BOUNDS(x,y) POV_IMAGE_ASSERT(((x) < width) && ((y) < height))
67
68 #define ALPHA_OPAQUE (1.0f)
69 #define ALPHA_OPAQUE_INT(MAX) (MAX)
70
71 #define FT_OPAQUE (0.0f)
72 #define FT_OPAQUE_INT(MAX) (0)
73
74 #define IS_NONZERO_RGB(r,g,b) ((r)*(g)*(b) != 0.0f) // TODO FIXME - [CLi] this tests whether *all* channels are nonzero - is this desired?
75 #define IS_NONZERO_RGB_INT(r,g,b) ((r)*(g)*(b) != 0) // TODO FIXME - [CLi] this tests whether *all* channels are nonzero - is this desired?
76
77 namespace pov_base
78 {
79
80 using std::allocator;
81
WriteOptions()82 Image::WriteOptions::WriteOptions() :
83 ditherStrategy(GetNoOpDitherStrategy()),
84 offset_x(0),
85 offset_y(0),
86 alphaMode(kAlphaMode_None),
87 bitsPerChannel(8),
88 compression(-1),
89 grayscale(false)
90 {}
91
92 template<class Allocator = allocator<bool> >
93 class BitMapImage : public Image
94 {
95 public:
BitMapImage(unsigned int w,unsigned int h)96 BitMapImage(unsigned int w, unsigned int h) :
97 Image(w, h, Bit_Map) { pixels.resize(SafeUnsignedProduct<size_t>(w, h)); FillBitValue(false); }
BitMapImage(unsigned int w,unsigned int h,const vector<RGBMapEntry> & m)98 BitMapImage(unsigned int w, unsigned int h, const vector<RGBMapEntry>& m) :
99 Image(w, h, Bit_Map, m) { pixels.resize(SafeUnsignedProduct<size_t>(w, h)); FillBitValue(false); }
BitMapImage(unsigned int w,unsigned int h,const vector<RGBAMapEntry> & m)100 BitMapImage(unsigned int w, unsigned int h, const vector<RGBAMapEntry>& m) :
101 Image(w, h, Bit_Map, m) { pixels.resize(SafeUnsignedProduct<size_t>(w, h)); FillBitValue(false); }
BitMapImage(unsigned int w,unsigned int h,const vector<RGBFTMapEntry> & m)102 BitMapImage(unsigned int w, unsigned int h, const vector<RGBFTMapEntry>& m) :
103 Image(w, h, Bit_Map, m) { pixels.resize(SafeUnsignedProduct<size_t>(w, h)); FillBitValue(false); }
~BitMapImage()104 ~BitMapImage() { }
105
IsOpaque() const106 bool IsOpaque() const
107 {
108 return true;
109 }
IsGrayscale() const110 bool IsGrayscale() const
111 {
112 return true;
113 }
IsColour() const114 bool IsColour() const
115 {
116 return false;
117 }
IsFloat() const118 bool IsFloat() const
119 {
120 return false;
121 }
IsInt() const122 bool IsInt() const
123 {
124 return true;
125 }
IsIndexed() const126 bool IsIndexed() const
127 {
128 return false;
129 }
IsGammaEncoded() const130 bool IsGammaEncoded() const
131 {
132 return false;
133 }
HasAlphaChannel() const134 bool HasAlphaChannel() const
135 {
136 return false;
137 }
HasFilterTransmit() const138 bool HasFilterTransmit() const
139 {
140 return false;
141 }
GetMaxIntValue() const142 unsigned int GetMaxIntValue() const
143 {
144 return 1;
145 }
TryDeferDecoding(GammaCurvePtr &,unsigned int)146 bool TryDeferDecoding(GammaCurvePtr&, unsigned int)
147 {
148 return false;
149 }
150
GetBitValue(unsigned int x,unsigned int y) const151 bool GetBitValue(unsigned int x, unsigned int y) const
152 {
153 CHECK_BOUNDS(x, y);
154 return pixels[x + y * size_t(width)];
155 }
GetGrayValue(unsigned int x,unsigned int y) const156 float GetGrayValue(unsigned int x, unsigned int y) const
157 {
158 CHECK_BOUNDS(x, y);
159 if(pixels[x + y * size_t(width)] == true)
160 return 1.0f;
161 else
162 return 0.0f;
163 }
GetGrayAValue(unsigned int x,unsigned int y,float & gray,float & alpha) const164 void GetGrayAValue(unsigned int x, unsigned int y, float& gray, float& alpha) const
165 {
166 gray = GetGrayValue(x, y);
167 alpha = ALPHA_OPAQUE;
168 }
GetRGBValue(unsigned int x,unsigned int y,float & red,float & green,float & blue) const169 void GetRGBValue(unsigned int x, unsigned int y, float& red, float& green, float& blue) const
170 {
171 red = green = blue = GetGrayValue(x, y);
172 }
GetRGBAValue(unsigned int x,unsigned int y,float & red,float & green,float & blue,float & alpha) const173 void GetRGBAValue(unsigned int x, unsigned int y, float& red, float& green, float& blue, float& alpha) const
174 {
175 red = green = blue = GetGrayValue(x, y);
176 alpha = ALPHA_OPAQUE;
177 }
GetRGBTValue(unsigned int x,unsigned int y,float & red,float & green,float & blue,float & transm) const178 void GetRGBTValue(unsigned int x, unsigned int y, float& red, float& green, float& blue, float& transm) const
179 {
180 red = green = blue = GetGrayValue(x, y);
181 transm = FT_OPAQUE;
182 }
GetRGBFTValue(unsigned int x,unsigned int y,float & red,float & green,float & blue,float & filter,float & transm) const183 void GetRGBFTValue(unsigned int x, unsigned int y, float& red, float& green, float& blue, float& filter, float& transm) const
184 {
185 red = green = blue = GetGrayValue(x, y);
186 filter = transm = FT_OPAQUE;
187 }
188
SetBitValue(unsigned int x,unsigned int y,bool bit)189 void SetBitValue(unsigned int x, unsigned int y, bool bit)
190 {
191 CHECK_BOUNDS(x, y);
192 pixels[x + y * size_t(width)] = bit;
193 }
SetGrayValue(unsigned int x,unsigned int y,float gray)194 void SetGrayValue(unsigned int x, unsigned int y, float gray)
195 {
196 CHECK_BOUNDS(x, y);
197 pixels[x + y * size_t(width)] = (gray != 0.0f);
198 }
SetGrayValue(unsigned int x,unsigned int y,unsigned int gray)199 void SetGrayValue(unsigned int x, unsigned int y, unsigned int gray)
200 {
201 CHECK_BOUNDS(x, y);
202 pixels[x + y * size_t(width)] = (gray != 0);
203 }
SetGrayAValue(unsigned int x,unsigned int y,float gray,float)204 void SetGrayAValue(unsigned int x, unsigned int y, float gray, float)
205 {
206 // TODO FIXME - [CLi] This ignores opacity information; other bit-based code doesn't.
207 CHECK_BOUNDS(x, y);
208 pixels[x + y * size_t(width)] = (gray != 0.0f);
209 }
SetGrayAValue(unsigned int x,unsigned int y,unsigned int gray,unsigned int)210 void SetGrayAValue(unsigned int x, unsigned int y, unsigned int gray, unsigned int)
211 {
212 // TODO FIXME - [CLi] This ignores opacity information; other bit-based code doesn't.
213 CHECK_BOUNDS(x, y);
214 pixels[x + y * size_t(width)] = (gray != 0);
215 }
SetRGBValue(unsigned int x,unsigned int y,float red,float green,float blue)216 void SetRGBValue(unsigned int x, unsigned int y, float red, float green, float blue)
217 {
218 CHECK_BOUNDS(x, y);
219 pixels[x + y * size_t(width)] = IS_NONZERO_RGB(red, green, blue);
220 }
SetRGBValue(unsigned int x,unsigned int y,unsigned int red,unsigned int green,unsigned int blue)221 void SetRGBValue(unsigned int x, unsigned int y, unsigned int red, unsigned int green, unsigned int blue)
222 {
223 CHECK_BOUNDS(x, y);
224 pixels[x + y * size_t(width)] = IS_NONZERO_RGB_INT(red, green, blue);
225 }
SetRGBAValue(unsigned int x,unsigned int y,float red,float green,float blue,float)226 void SetRGBAValue(unsigned int x, unsigned int y, float red, float green, float blue, float)
227 {
228 // TODO FIXME - [CLi] This ignores opacity information; other bit-based code doesn't.
229 SetRGBValue(x, y, red, green, blue);
230 }
SetRGBAValue(unsigned int x,unsigned int y,unsigned int red,unsigned int green,unsigned int blue,unsigned int)231 void SetRGBAValue(unsigned int x, unsigned int y, unsigned int red, unsigned int green, unsigned int blue, unsigned int)
232 {
233 // TODO FIXME - [CLi] This ignores opacity information; other bit-based code doesn't.
234 SetRGBValue(x, y, red, green, blue);
235 }
SetRGBTValue(unsigned int x,unsigned int y,float red,float green,float blue,float transm)236 void SetRGBTValue(unsigned int x, unsigned int y, float red, float green, float blue, float transm)
237 {
238 // TODO FIXME - [CLi] This ignores opacity information; other bit-based code doesn't.
239 SetRGBValue(x, y, red, green, blue);
240 }
SetRGBTValue(unsigned int x,unsigned int y,const RGBTColour & col)241 void SetRGBTValue(unsigned int x, unsigned int y, const RGBTColour& col)
242 {
243 // TODO FIXME - [CLi] This ignores opacity information; other bit-based code doesn't.
244 SetRGBValue(x, y, col.red(), col.green(), col.blue());
245 }
SetRGBFTValue(unsigned int x,unsigned int y,float red,float green,float blue,float,float)246 void SetRGBFTValue(unsigned int x, unsigned int y, float red, float green, float blue, float, float)
247 {
248 // TODO FIXME - [CLi] This ignores opacity information; other bit-based code doesn't.
249 SetRGBValue(x, y, red, green, blue);
250 }
SetRGBFTValue(unsigned int x,unsigned int y,const RGBFTColour & col)251 void SetRGBFTValue(unsigned int x, unsigned int y, const RGBFTColour& col)
252 {
253 // TODO FIXME - [CLi] This ignores opacity information; other bit-based code doesn't.
254 SetRGBValue(x, y, col.red(), col.green(), col.blue());
255 }
256
FillBitValue(bool bit)257 void FillBitValue(bool bit)
258 {
259 fill(pixels.begin(), pixels.end(), bit);
260 }
FillGrayValue(float gray)261 void FillGrayValue(float gray)
262 {
263 FillBitValue(gray != 0.0f);
264 }
FillGrayValue(unsigned int gray)265 void FillGrayValue(unsigned int gray)
266 {
267 FillBitValue(gray != 0);
268 }
FillGrayAValue(float gray,float)269 void FillGrayAValue(float gray, float)
270 {
271 FillBitValue(gray != 0.0f);
272 }
FillGrayAValue(unsigned int gray,unsigned int)273 void FillGrayAValue(unsigned int gray, unsigned int)
274 {
275 FillBitValue(gray != 0);
276 }
FillRGBValue(float red,float green,float blue)277 void FillRGBValue(float red, float green, float blue)
278 {
279 FillBitValue(IS_NONZERO_RGB(red, green, blue));
280 }
FillRGBValue(unsigned int red,unsigned int green,unsigned int blue)281 void FillRGBValue(unsigned int red, unsigned int green, unsigned int blue)
282 {
283 FillBitValue(IS_NONZERO_RGB_INT(red, green, blue));
284 }
FillRGBAValue(float red,float green,float blue,float)285 void FillRGBAValue(float red, float green, float blue, float)
286 {
287 // TODO FIXME - [CLi] This ignores opacity information; other bit-based code doesn't.
288 FillRGBValue(red, green, blue);
289 }
FillRGBAValue(unsigned int red,unsigned int green,unsigned int blue,unsigned int)290 void FillRGBAValue(unsigned int red, unsigned int green, unsigned int blue, unsigned int)
291 {
292 // TODO FIXME - [CLi] This ignores opacity information; other bit-based code doesn't.
293 FillRGBValue(red, green, blue);
294 }
FillRGBTValue(float red,float green,float blue,float)295 void FillRGBTValue(float red, float green, float blue, float)
296 {
297 // TODO FIXME - [CLi] This ignores opacity information; other bit-based code doesn't.
298 FillRGBValue(red, green, blue);
299 }
FillRGBFTValue(float red,float green,float blue,float,float)300 void FillRGBFTValue(float red, float green, float blue, float, float)
301 {
302 // TODO FIXME - [CLi] This ignores opacity information; other bit-based code doesn't.
303 FillRGBValue(red, green, blue);
304 }
305 private:
306 vector<bool, Allocator> pixels;
307 };
308
309 typedef BitMapImage<> MemoryBitMapImage;
310
311 template<class Allocator = allocator<unsigned char> >
312 class ColourMapImage : public Image
313 {
314 public:
ColourMapImage(unsigned int w,unsigned int h,const vector<RGBMapEntry> & m)315 ColourMapImage(unsigned int w, unsigned int h, const vector<RGBMapEntry>& m) :
316 Image(w, h, Colour_Map, m) { pixels.resize(SafeUnsignedProduct<size_t>(w, h)); FillBitValue(false); }
ColourMapImage(unsigned int w,unsigned int h,const vector<RGBAMapEntry> & m)317 ColourMapImage(unsigned int w, unsigned int h, const vector<RGBAMapEntry>& m) :
318 Image(w, h, Colour_Map, m) { pixels.resize(SafeUnsignedProduct<size_t>(w, h)); FillBitValue(false); }
ColourMapImage(unsigned int w,unsigned int h,const vector<RGBFTMapEntry> & m)319 ColourMapImage(unsigned int w, unsigned int h, const vector<RGBFTMapEntry>& m) :
320 Image(w, h, Colour_Map, m) { pixels.resize(SafeUnsignedProduct<size_t>(w, h)); FillBitValue(false); }
~ColourMapImage()321 ~ColourMapImage() { }
322
IsOpaque() const323 bool IsOpaque() const
324 {
325 if((colormaptype != RGBAColourMap) && (colormaptype != RGBFTColourMap))
326 return true;
327
328 bool transp = false;
329
330 for(size_t i = 0; i < colormap.size(); i++)
331 {
332 if(colormaptype == RGBAColourMap)
333 transp = (colormap[i].filter != ALPHA_OPAQUE); // with RGBAColourMap, .filter is actually alpha
334 else if(colormaptype == RGBFTColourMap)
335 transp = (colormap[i].transm != FT_OPAQUE);
336 if(transp == true)
337 break;
338 }
339
340 if(transp == false)
341 return true;
342
343 if(colormaptype == RGBAColourMap)
344 {
345 for(typename vector<unsigned char, Allocator>::const_iterator i(pixels.begin()); i != pixels.end(); i++)
346 {
347 if(colormap[*i].filter != ALPHA_OPAQUE) // with RGBAColourMap, .filter is actually alpha
348 return false;
349 }
350 }
351 else
352 {
353 for(typename vector<unsigned char, Allocator>::const_iterator i(pixels.begin()); i != pixels.end(); i++)
354 {
355 if(colormap[*i].transm != FT_OPAQUE)
356 return false;
357 }
358 }
359
360 return true;
361 }
IsGrayscale() const362 bool IsGrayscale() const
363 {
364 return false;
365 }
IsColour() const366 bool IsColour() const
367 {
368 return true;
369 }
IsFloat() const370 bool IsFloat() const
371 {
372 return false;
373 }
IsInt() const374 bool IsInt() const
375 {
376 return true;
377 }
IsIndexed() const378 bool IsIndexed() const
379 {
380 return true;
381 }
IsGammaEncoded() const382 bool IsGammaEncoded() const
383 {
384 return false;
385 }
HasAlphaChannel() const386 bool HasAlphaChannel() const
387 {
388 return (colormaptype == RGBAColourMap);
389 }
HasFilterTransmit() const390 bool HasFilterTransmit() const
391 {
392 return (colormaptype == RGBFTColourMap);
393 }
GetMaxIntValue() const394 unsigned int GetMaxIntValue() const
395 {
396 return 255;
397 }
TryDeferDecoding(GammaCurvePtr &,unsigned int)398 bool TryDeferDecoding(GammaCurvePtr&, unsigned int)
399 {
400 return false;
401 }
402
GetBitValue(unsigned int x,unsigned int y) const403 bool GetBitValue(unsigned int x, unsigned int y) const
404 {
405 float red, green, blue, filter, transm, alpha;
406 switch(colormaptype)
407 {
408 case RGBColourMap:
409 GetRGBValue(x, y, red, green, blue);
410 return IS_NONZERO_RGB(red, green, blue);
411 case RGBAColourMap:
412 // TODO FIXME - [CLi] This takes into account opacity information; other bit-based code doesn't.
413 GetRGBAValue(x, y, red, green, blue, alpha);
414 return IS_NONZERO_RGB(red, green, blue) && (alpha == ALPHA_OPAQUE);
415 case RGBFTColourMap:
416 // TODO FIXME - [CLi] This takes into account opacity information; other bit-based code doesn't.
417 GetRGBFTValue(x, y, red, green, blue, filter, transm);
418 return IS_NONZERO_RGB(red, green, blue) && (filter == FT_OPAQUE) && (transm == FT_OPAQUE);
419 default:
420 return false;
421 }
422 }
GetGrayValue(unsigned int x,unsigned int y) const423 float GetGrayValue(unsigned int x, unsigned int y) const
424 {
425 float red, green, blue, filter, transm, alpha;
426 switch(colormaptype)
427 {
428 case RGBColourMap:
429 GetRGBValue(x, y, red, green, blue);
430 return RGB2Gray(red, green, blue);
431 case RGBAColourMap:
432 GetRGBAValue(x, y, red, green, blue, alpha);
433 return RGB2Gray(red, green, blue);
434 case RGBFTColourMap:
435 GetRGBFTValue(x, y, red, green, blue, filter, transm);
436 return RGB2Gray(red, green, blue);
437 default:
438 return 0.0f;
439 }
440 }
GetGrayAValue(unsigned int x,unsigned int y,float & gray,float & alpha) const441 void GetGrayAValue(unsigned int x, unsigned int y, float& gray, float& alpha) const
442 {
443 float red, green, blue, filter, transm;
444 alpha = ALPHA_OPAQUE; // (unless noted otherwise)
445 switch(colormaptype)
446 {
447 case RGBColourMap:
448 GetRGBValue(x, y, red, green, blue);
449 gray = RGB2Gray(red, green, blue);
450 return;
451 case RGBAColourMap:
452 GetRGBAValue(x, y, red, green, blue, alpha);
453 gray = RGB2Gray(red, green, blue);
454 return;
455 case RGBFTColourMap:
456 GetRGBFTValue(x, y, red, green, blue, filter, transm);
457 gray = RGB2Gray(red, green, blue);
458 alpha = RGBFTColour::FTtoA(filter, transm);
459 return;
460 default:
461 gray = 0.0f;
462 return;
463 }
464 }
GetRGBValue(unsigned int x,unsigned int y,float & red,float & green,float & blue) const465 void GetRGBValue(unsigned int x, unsigned int y, float& red, float& green, float& blue) const
466 {
467 CHECK_BOUNDS(x, y);
468 MapEntry e(colormap[pixels[x + y * size_t(width)]]);
469 red = e.red;
470 green = e.green;
471 blue = e.blue;
472 }
GetRGBAValue(unsigned int x,unsigned int y,float & red,float & green,float & blue,float & alpha) const473 void GetRGBAValue(unsigned int x, unsigned int y, float& red, float& green, float& blue, float& alpha) const
474 {
475 CHECK_BOUNDS(x, y);
476 MapEntry e(colormap[pixels[x + y * size_t(width)]]);
477 red = e.red;
478 green = e.green;
479 blue = e.blue;
480 alpha = ALPHA_OPAQUE; // (unless noted otherwise)
481 switch(colormaptype)
482 {
483 case RGBAColourMap:
484 alpha = e.filter; // with RGBAColourMap, .filter is actually alpha
485 return;
486 case RGBFTColourMap:
487 alpha = RGBFTColour::FTtoA(e.filter, e.transm);
488 return;
489 default:
490 return;
491 }
492 }
GetRGBTValue(unsigned int x,unsigned int y,float & red,float & green,float & blue,float & transm) const493 void GetRGBTValue(unsigned int x, unsigned int y, float& red, float& green, float& blue, float& transm) const
494 {
495 CHECK_BOUNDS(x, y);
496 MapEntry e(colormap[pixels[x + y * size_t(width)]]);
497 red = e.red;
498 green = e.green;
499 blue = e.blue;
500 transm = FT_OPAQUE; // (unless noted otherwise)
501 switch(colormaptype)
502 {
503 case RGBAColourMap:
504 transm = 1.0 - e.filter; // with RGBAColourMap, .filter is actually alpha
505 return;
506 case RGBFTColourMap:
507 transm = 1.0 - RGBFTColour::FTtoA(e.filter, e.transm);
508 return;
509 default:
510 return;
511 }
512 }
GetRGBFTValue(unsigned int x,unsigned int y,float & red,float & green,float & blue,float & filter,float & transm) const513 void GetRGBFTValue(unsigned int x, unsigned int y, float& red, float& green, float& blue, float& filter, float& transm) const
514 {
515 CHECK_BOUNDS(x, y);
516 MapEntry e(colormap[pixels[x + y * size_t(width)]]);
517 red = e.red;
518 green = e.green;
519 blue = e.blue;
520 filter = FT_OPAQUE; // (unless noted otherwise)
521 transm = FT_OPAQUE; // (unless noted otherwise)
522 switch(colormaptype)
523 {
524 case RGBAColourMap:
525 RGBFTColour::AtoFT(e.filter, filter, transm); // with RGBAColourMap, .filter is actually alpha
526 return;
527 case RGBFTColourMap:
528 filter = e.filter;
529 transm = e.transm;
530 return;
531 default:
532 return;
533 }
534 }
GetIndexedValue(unsigned int x,unsigned int y)535 unsigned char GetIndexedValue(unsigned int x, unsigned int y)
536 {
537 CHECK_BOUNDS(x, y);
538 return pixels[x + y * size_t(width)];
539 }
540
SetBitValue(unsigned int x,unsigned int y,bool bit)541 void SetBitValue(unsigned int x, unsigned int y, bool bit)
542 {
543 CHECK_BOUNDS(x, y);
544 pixels[x + y * size_t(width)] = Bit2Map(bit);
545 }
SetGrayValue(unsigned int x,unsigned int y,float gray)546 void SetGrayValue(unsigned int x, unsigned int y, float gray)
547 {
548 CHECK_BOUNDS(x, y);
549 pixels[x + y * size_t(width)] = Gray2Map(gray);
550 }
SetGrayValue(unsigned int x,unsigned int y,unsigned int gray)551 void SetGrayValue(unsigned int x, unsigned int y, unsigned int gray)
552 {
553 CHECK_BOUNDS(x, y);
554 pixels[x + y * size_t(width)] = Gray2Map(float(gray) / 255.0);
555 }
SetGrayAValue(unsigned int x,unsigned int y,float gray,float alpha)556 void SetGrayAValue(unsigned int x, unsigned int y, float gray, float alpha)
557 {
558 CHECK_BOUNDS(x, y);
559 pixels[x + y * size_t(width)] = GrayA2Map(gray, alpha);
560 }
SetGrayAValue(unsigned int x,unsigned int y,unsigned int gray,unsigned int alpha)561 void SetGrayAValue(unsigned int x, unsigned int y, unsigned int gray, unsigned int alpha)
562 {
563 CHECK_BOUNDS(x, y);
564 pixels[x + y * size_t(width)] = GrayA2Map(float(gray) / 255.0, float(alpha) / 255.0);
565 }
SetRGBValue(unsigned int x,unsigned int y,float red,float green,float blue)566 void SetRGBValue(unsigned int x, unsigned int y, float red, float green, float blue)
567 {
568 CHECK_BOUNDS(x, y);
569 pixels[x + y * size_t(width)] = RGB2Map(red, green, blue);
570 }
SetRGBValue(unsigned int x,unsigned int y,unsigned int red,unsigned int green,unsigned int blue)571 void SetRGBValue(unsigned int x, unsigned int y, unsigned int red, unsigned int green, unsigned int blue)
572 {
573 CHECK_BOUNDS(x, y);
574 pixels[x + y * size_t(width)] = RGB2Map(float(red) / 255.0, float(green) / 255.0, float(blue) / 255.0);
575 }
SetRGBAValue(unsigned int x,unsigned int y,float red,float green,float blue,float alpha)576 void SetRGBAValue(unsigned int x, unsigned int y, float red, float green, float blue, float alpha)
577 {
578 CHECK_BOUNDS(x, y);
579 pixels[x + y * size_t(width)] = RGBA2Map(red, green, blue, alpha);
580 }
SetRGBAValue(unsigned int x,unsigned int y,unsigned int red,unsigned int green,unsigned int blue,unsigned int alpha)581 void SetRGBAValue(unsigned int x, unsigned int y, unsigned int red, unsigned int green, unsigned int blue, unsigned int alpha)
582 {
583 CHECK_BOUNDS(x, y);
584 pixels[x + y * size_t(width)] = RGBA2Map(float(red) / 255.0, float(green) / 255.0, float(blue) / 255.0, float(alpha) / 255.0);
585 }
SetRGBTValue(unsigned int x,unsigned int y,float red,float green,float blue,float transm)586 void SetRGBTValue(unsigned int x, unsigned int y, float red, float green, float blue, float transm)
587 {
588 CHECK_BOUNDS(x, y);
589 pixels[x + y * size_t(width)] = RGBT2Map(red, green, blue, transm);
590 }
SetRGBTValue(unsigned int x,unsigned int y,const RGBTColour & col)591 void SetRGBTValue(unsigned int x, unsigned int y, const RGBTColour& col)
592 {
593 CHECK_BOUNDS(x, y);
594 pixels[x + y * size_t(width)] = RGBA2Map(col.red(), col.green(), col.blue(), col.alpha());
595 }
SetRGBFTValue(unsigned int x,unsigned int y,float red,float green,float blue,float filter,float transm)596 void SetRGBFTValue(unsigned int x, unsigned int y, float red, float green, float blue, float filter, float transm)
597 {
598 CHECK_BOUNDS(x, y);
599 // [CLi 2009-09] this was dividing by 255 - which I presume to have been a bug.
600 pixels[x + y * size_t(width)] = RGBFT2Map(red, green, blue, filter, transm);
601 }
SetRGBFTValue(unsigned int x,unsigned int y,const RGBFTColour & col)602 void SetRGBFTValue(unsigned int x, unsigned int y, const RGBFTColour& col)
603 {
604 CHECK_BOUNDS(x, y);
605 // [CLi 2009-09] this was dividing by 255 - which I presume to have been a bug.
606 pixels[x + y * size_t(width)] = RGBFT2Map(col.red(), col.green(), col.blue(), col.filter(), col.transm());
607 }
SetIndexedValue(unsigned int x,unsigned int y,unsigned char index)608 void SetIndexedValue(unsigned int x, unsigned int y, unsigned char index)
609 {
610 CHECK_BOUNDS(x, y);
611 pixels[x + y * size_t(width)] = index;
612 }
613
FillBitValue(bool bit)614 void FillBitValue(bool bit)
615 {
616 fill(pixels.begin(), pixels.end(), Bit2Map(bit));
617 }
FillGrayValue(float gray)618 void FillGrayValue(float gray)
619 {
620 fill(pixels.begin(), pixels.end(), Gray2Map(gray));
621 }
FillGrayValue(unsigned int gray)622 void FillGrayValue(unsigned int gray)
623 {
624 fill(pixels.begin(), pixels.end(), Gray2Map(float(gray) / 255.0));
625 }
FillGrayAValue(float gray,float alpha)626 void FillGrayAValue(float gray, float alpha)
627 {
628 fill(pixels.begin(), pixels.end(), GrayA2Map(gray, alpha));
629 }
FillGrayAValue(unsigned int gray,unsigned int alpha)630 void FillGrayAValue(unsigned int gray, unsigned int alpha)
631 {
632 fill(pixels.begin(), pixels.end(), GrayA2Map(float(gray) / 255.0, float(alpha) / 255.0));
633 }
FillRGBValue(float red,float green,float blue)634 void FillRGBValue(float red, float green, float blue)
635 {
636 fill(pixels.begin(), pixels.end(), RGB2Map(red, green, blue));
637 }
FillRGBValue(unsigned int red,unsigned int green,unsigned int blue)638 void FillRGBValue(unsigned int red, unsigned int green, unsigned int blue)
639 {
640 fill(pixels.begin(), pixels.end(), RGB2Map(float(red) / 255.0, float(green) / 255.0, float(blue) / 255.0));
641 }
FillRGBAValue(float red,float green,float blue,float alpha)642 void FillRGBAValue(float red, float green, float blue, float alpha)
643 {
644 fill(pixels.begin(), pixels.end(), RGBA2Map(red, green, blue, alpha));
645 }
FillRGBAValue(unsigned int red,unsigned int green,unsigned int blue,unsigned int alpha)646 void FillRGBAValue(unsigned int red, unsigned int green, unsigned int blue, unsigned int alpha)
647 {
648 fill(pixels.begin(), pixels.end(), RGBA2Map(float(red) / 255.0, float(green) / 255.0, float(blue) / 255.0, float(alpha) / 255.0));
649 }
FillRGBTValue(float red,float green,float blue,float transm)650 void FillRGBTValue(float red, float green, float blue, float transm)
651 {
652 fill(pixels.begin(), pixels.end(), RGBT2Map(red, green, blue, transm));
653 }
FillRGBFTValue(float red,float green,float blue,float filter,float transm)654 void FillRGBFTValue(float red, float green, float blue, float filter, float transm)
655 {
656 // [CLi 2009-09] this was dividing by 255 - which I presume to have been a bug.
657 fill(pixels.begin(), pixels.end(), RGBFT2Map(red, green, blue, filter, transm));
658 }
659 private:
660 vector<unsigned char, Allocator> pixels;
661
Bit2Map(bool bit) const662 unsigned char Bit2Map(bool bit) const
663 {
664 if(bit == true)
665 return Gray2Map(1.0f);
666 else
667 return Gray2Map(0.0f);
668 }
Gray2Map(float gray) const669 unsigned char Gray2Map(float gray) const
670 {
671 switch(colormaptype)
672 {
673 case RGBColourMap:
674 return FindBestRGB(gray, gray, gray);
675 case RGBAColourMap:
676 return FindBestRGBA(gray, gray, gray, ALPHA_OPAQUE);
677 case RGBFTColourMap:
678 return FindBestRGBFT(gray, gray, gray, FT_OPAQUE, FT_OPAQUE);
679 default:
680 return 0;
681 }
682 }
GrayA2Map(float gray,float alpha) const683 unsigned char GrayA2Map(float gray, float alpha) const
684 {
685 float filter, transm;
686 switch(colormaptype)
687 {
688 case RGBColourMap:
689 return FindBestRGB(gray, gray, gray);
690 case RGBAColourMap:
691 return FindBestRGBA(gray, gray, gray, alpha);
692 case RGBFTColourMap:
693 RGBFTColour::AtoFT(alpha, filter, transm);
694 return FindBestRGBFT(gray, gray, gray, filter, transm);
695 default:
696 return 0;
697 }
698 }
RGB2Map(float red,float green,float blue) const699 unsigned char RGB2Map(float red, float green, float blue) const
700 {
701 switch(colormaptype)
702 {
703 case RGBColourMap:
704 return FindBestRGB(red, green, blue);
705 case RGBAColourMap:
706 return FindBestRGBA(red, green, blue, ALPHA_OPAQUE);
707 case RGBFTColourMap:
708 return FindBestRGBFT(red, green, blue, FT_OPAQUE, FT_OPAQUE);
709 default:
710 return 0;
711 }
712 }
RGBA2Map(float red,float green,float blue,float alpha) const713 unsigned char RGBA2Map(float red, float green, float blue, float alpha) const
714 {
715 float filter, transm;
716 switch(colormaptype)
717 {
718 case RGBColourMap:
719 return FindBestRGB(red, green, blue);
720 case RGBAColourMap:
721 return FindBestRGBA(red, green, blue, alpha);
722 case RGBFTColourMap:
723 RGBFTColour::AtoFT(alpha, filter, transm);
724 return FindBestRGBFT(red, green, blue, filter, transm);
725 default:
726 return 0;
727 }
728 }
RGBT2Map(float red,float green,float blue,float transm) const729 unsigned char RGBT2Map(float red, float green, float blue, float transm) const
730 {
731 switch(colormaptype)
732 {
733 case RGBColourMap:
734 return FindBestRGB(red, green, blue);
735 case RGBAColourMap:
736 return FindBestRGBA(red, green, blue, 1.0 - transm);
737 case RGBFTColourMap:
738 return FindBestRGBFT(red, green, blue, FT_OPAQUE, transm);
739 default:
740 return 0;
741 }
742 }
RGBFT2Map(float red,float green,float blue,float filter,float transm) const743 unsigned char RGBFT2Map(float red, float green, float blue, float filter, float transm) const
744 {
745 switch(colormaptype)
746 {
747 case RGBColourMap:
748 return FindBestRGB(red, green, blue);
749 case RGBAColourMap:
750 return FindBestRGBA(red, green, blue, RGBFTColour::FTtoA(filter, transm));
751 case RGBFTColourMap:
752 return FindBestRGBFT(red, green, blue, filter, transm);
753 default:
754 return 0;
755 }
756 }
FindBestRGB(float red,float green,float blue) const757 unsigned char FindBestRGB(float red, float green, float blue) const
758 {
759 unsigned char best = 0;
760 float diff = 3.0f;
761
762 for(size_t i = 0; i < colormap.size(); i++)
763 {
764 float d(RGB2Gray(fabs(colormap[i].red - red), fabs(colormap[i].green - green), fabs(colormap[i].red - blue)));
765 if(d < diff)
766 {
767 d = diff;
768 best = (unsigned char)i;
769 }
770 }
771
772 return best;
773 }
FindBestRGBA(float red,float green,float blue,float alpha) const774 unsigned char FindBestRGBA(float red, float green, float blue, float alpha) const
775 {
776 unsigned char best = 0;
777 float diff = 3.0f;
778
779 for(size_t i = 0; i < colormap.size(); i++)
780 {
781 float d((RGB2Gray(fabs(colormap[i].red - red), fabs(colormap[i].green - green), fabs(colormap[i].red - blue)) * 3.0f +
782 fabs(colormap[i].filter - alpha)) / 4.0f); // with RGBAColourMap, .filter is actually alpha
783 if(d < diff)
784 {
785 d = diff;
786 best = (unsigned char)i;
787 }
788 }
789
790 return best;
791 }
FindBestRGBFT(float red,float green,float blue,float filter,float transm) const792 unsigned char FindBestRGBFT(float red, float green, float blue, float filter, float transm) const
793 {
794 unsigned char best = 0;
795 float diff = 3.0f;
796
797 for(size_t i = 0; i < colormap.size(); i++)
798 {
799 float d((RGB2Gray(fabs(colormap[i].red - red), fabs(colormap[i].green - green), fabs(colormap[i].red - blue)) * 3.0f +
800 fabs(colormap[i].filter - filter) + fabs(colormap[i].transm - transm)) / 5.0f);
801 if(d < diff)
802 {
803 d = diff;
804 best = (unsigned char)i;
805 }
806 }
807
808 return best;
809 }
810 };
811
812 typedef ColourMapImage<> MemoryColourMapImage;
813
814 template<typename T, unsigned int TMAX, int IDT, class Allocator = allocator<T> >
815 class GrayImage : public Image
816 {
817 public:
GrayImage(unsigned int w,unsigned int h)818 GrayImage(unsigned int w, unsigned int h) :
819 Image(w, h, ImageDataType(IDT)) { pixels.resize(SafeUnsignedProduct<size_t>(w, h)); FillBitValue(false); }
GrayImage(unsigned int w,unsigned int h,const vector<RGBMapEntry> & m)820 GrayImage(unsigned int w, unsigned int h, const vector<RGBMapEntry>& m) :
821 Image(w, h, ImageDataType(IDT), m) { pixels.resize(SafeUnsignedProduct<size_t>(w, h)); FillBitValue(false); }
GrayImage(unsigned int w,unsigned int h,const vector<RGBAMapEntry> & m)822 GrayImage(unsigned int w, unsigned int h, const vector<RGBAMapEntry>& m) :
823 Image(w, h, ImageDataType(IDT), m) { pixels.resize(SafeUnsignedProduct<size_t>(w, h)); FillBitValue(false); }
GrayImage(unsigned int w,unsigned int h,const vector<RGBFTMapEntry> & m)824 GrayImage(unsigned int w, unsigned int h, const vector<RGBFTMapEntry>& m) :
825 Image(w, h, ImageDataType(IDT), m) { pixels.resize(SafeUnsignedProduct<size_t>(w, h)); FillBitValue(false); }
~GrayImage()826 ~GrayImage() { }
827
IsOpaque() const828 bool IsOpaque() const
829 {
830 return true;
831 }
IsGrayscale() const832 bool IsGrayscale() const
833 {
834 return true;
835 }
IsColour() const836 bool IsColour() const
837 {
838 return false;
839 }
IsFloat() const840 bool IsFloat() const
841 {
842 return false;
843 }
IsInt() const844 bool IsInt() const
845 {
846 return true;
847 }
IsGammaEncoded() const848 bool IsGammaEncoded() const
849 {
850 return false;
851 }
IsIndexed() const852 bool IsIndexed() const
853 {
854 return false;
855 }
HasAlphaChannel() const856 bool HasAlphaChannel() const
857 {
858 return false;
859 }
HasFilterTransmit() const860 bool HasFilterTransmit() const
861 {
862 return false;
863 }
GetMaxIntValue() const864 unsigned int GetMaxIntValue() const
865 {
866 return TMAX;
867 }
TryDeferDecoding(GammaCurvePtr &,unsigned int)868 bool TryDeferDecoding(GammaCurvePtr&, unsigned int)
869 {
870 return false;
871 }
872
GetBitValue(unsigned int x,unsigned int y) const873 bool GetBitValue(unsigned int x, unsigned int y) const
874 {
875 CHECK_BOUNDS(x, y);
876 return (pixels[x + y * size_t(width)] != 0);
877 }
GetGrayValue(unsigned int x,unsigned int y) const878 float GetGrayValue(unsigned int x, unsigned int y) const
879 {
880 CHECK_BOUNDS(x, y);
881 return float(pixels[x + y * size_t(width)]) / float(TMAX);
882 }
GetGrayAValue(unsigned int x,unsigned int y,float & gray,float & alpha) const883 void GetGrayAValue(unsigned int x, unsigned int y, float& gray, float& alpha) const
884 {
885 CHECK_BOUNDS(x, y);
886 gray = float(pixels[x + y * size_t(width)]) / float(TMAX);
887 alpha = ALPHA_OPAQUE;
888 }
GetRGBValue(unsigned int x,unsigned int y,float & red,float & green,float & blue) const889 void GetRGBValue(unsigned int x, unsigned int y, float& red, float& green, float& blue) const
890 {
891 red = green = blue = GetGrayValue(x, y);
892 }
GetRGBAValue(unsigned int x,unsigned int y,float & red,float & green,float & blue,float & alpha) const893 void GetRGBAValue(unsigned int x, unsigned int y, float& red, float& green, float& blue, float& alpha) const
894 {
895 red = green = blue = GetGrayValue(x, y);
896 alpha = ALPHA_OPAQUE;
897 }
GetRGBTValue(unsigned int x,unsigned int y,float & red,float & green,float & blue,float & transm) const898 void GetRGBTValue(unsigned int x, unsigned int y, float& red, float& green, float& blue, float& transm) const
899 {
900 red = green = blue = GetGrayValue(x, y);
901 transm = FT_OPAQUE;
902 }
GetRGBFTValue(unsigned int x,unsigned int y,float & red,float & green,float & blue,float & filter,float & transm) const903 void GetRGBFTValue(unsigned int x, unsigned int y, float& red, float& green, float& blue, float& filter, float& transm) const
904 {
905 red = green = blue = GetGrayValue(x, y);
906 filter = transm = FT_OPAQUE;
907 }
GetIndexedValue(unsigned int x,unsigned int y)908 unsigned char GetIndexedValue(unsigned int x, unsigned int y)
909 {
910 CHECK_BOUNDS(x, y);
911 return (unsigned char)(int(pixels[x + y * size_t(width)]) / ((TMAX + 1) >> 8));
912 }
913
SetBitValue(unsigned int x,unsigned int y,bool bit)914 void SetBitValue(unsigned int x, unsigned int y, bool bit)
915 {
916 if(bit == true)
917 SetGrayValue(x, y, TMAX);
918 else
919 SetGrayValue(x, y, (unsigned int)0);
920 }
SetGrayValue(unsigned int x,unsigned int y,float gray)921 void SetGrayValue(unsigned int x, unsigned int y, float gray)
922 {
923 CHECK_BOUNDS(x, y);
924 pixels[x + y * size_t(width)] = T(gray * float(TMAX));
925 }
SetGrayValue(unsigned int x,unsigned int y,unsigned int gray)926 void SetGrayValue(unsigned int x, unsigned int y, unsigned int gray)
927 {
928 CHECK_BOUNDS(x, y);
929 pixels[x + y * size_t(width)] = T(gray);
930 }
SetGrayAValue(unsigned int x,unsigned int y,float gray,float)931 void SetGrayAValue(unsigned int x, unsigned int y, float gray, float)
932 {
933 CHECK_BOUNDS(x, y);
934 pixels[x + y * size_t(width)] = T(gray * float(TMAX));
935 }
SetGrayAValue(unsigned int x,unsigned int y,unsigned int gray,unsigned int)936 void SetGrayAValue(unsigned int x, unsigned int y, unsigned int gray, unsigned int)
937 {
938 CHECK_BOUNDS(x, y);
939 pixels[x + y * size_t(width)] = T(gray);
940 }
SetRGBValue(unsigned int x,unsigned int y,float red,float green,float blue)941 void SetRGBValue(unsigned int x, unsigned int y, float red, float green, float blue)
942 {
943 SetGrayValue(x, y, RGB2Gray(red, green, blue));
944 }
SetRGBValue(unsigned int x,unsigned int y,unsigned int red,unsigned int green,unsigned int blue)945 void SetRGBValue(unsigned int x, unsigned int y, unsigned int red, unsigned int green, unsigned int blue)
946 {
947 SetGrayValue(x, y, RGB2Gray(float(red) / float(TMAX), float(green) / float(TMAX), float(blue) / float(TMAX)));
948 }
SetRGBAValue(unsigned int x,unsigned int y,float red,float green,float blue,float)949 void SetRGBAValue(unsigned int x, unsigned int y, float red, float green, float blue, float)
950 {
951 SetRGBValue(x, y, red, green, blue);
952 }
SetRGBAValue(unsigned int x,unsigned int y,unsigned int red,unsigned int green,unsigned int blue,unsigned int)953 void SetRGBAValue(unsigned int x, unsigned int y, unsigned int red, unsigned int green, unsigned int blue, unsigned int)
954 {
955 SetRGBValue(x, y, red, green, blue);
956 }
SetRGBTValue(unsigned int x,unsigned int y,float red,float green,float blue,float transm)957 void SetRGBTValue(unsigned int x, unsigned int y, float red, float green, float blue, float transm)
958 {
959 SetRGBValue(x, y, red, green, blue);
960 }
SetRGBTValue(unsigned int x,unsigned int y,const RGBTColour & col)961 void SetRGBTValue(unsigned int x, unsigned int y, const RGBTColour& col)
962 {
963 SetRGBValue(x, y, col.red(), col.green(), col.blue());
964 }
SetRGBFTValue(unsigned int x,unsigned int y,float red,float green,float blue,float,float)965 void SetRGBFTValue(unsigned int x, unsigned int y, float red, float green, float blue, float, float)
966 {
967 SetRGBValue(x, y, red, green, blue);
968 }
SetRGBFTValue(unsigned int x,unsigned int y,const RGBFTColour & col)969 void SetRGBFTValue(unsigned int x, unsigned int y, const RGBFTColour& col)
970 {
971 SetRGBValue(x, y, col.red(), col.green(), col.blue());
972 }
973
FillBitValue(bool bit)974 void FillBitValue(bool bit)
975 {
976 if(bit == true)
977 FillGrayValue(TMAX);
978 else
979 FillGrayValue((unsigned int)0);
980 }
FillGrayValue(float gray)981 void FillGrayValue(float gray)
982 {
983 FillGrayValue((unsigned int)(gray * float(TMAX)));
984 }
FillGrayValue(unsigned int gray)985 void FillGrayValue(unsigned int gray)
986 {
987 fill(pixels.begin(), pixels.end(), T(gray));
988 }
FillGrayAValue(float gray,float)989 void FillGrayAValue(float gray, float)
990 {
991 FillGrayValue(gray);
992 }
FillGrayAValue(unsigned int gray,unsigned int)993 void FillGrayAValue(unsigned int gray, unsigned int)
994 {
995 FillGrayValue(gray);
996 }
FillRGBValue(float red,float green,float blue)997 void FillRGBValue(float red, float green, float blue)
998 {
999 FillGrayValue(RGB2Gray(red, green, blue));
1000 }
FillRGBValue(unsigned int red,unsigned int green,unsigned int blue)1001 void FillRGBValue(unsigned int red, unsigned int green, unsigned int blue)
1002 {
1003 FillGrayValue(RGB2Gray(float(red) / float(TMAX), float(green) / float(TMAX), float(blue) / float(TMAX)));
1004 }
FillRGBAValue(float red,float green,float blue,float)1005 void FillRGBAValue(float red, float green, float blue, float)
1006 {
1007 FillRGBValue(red, green, blue);
1008 }
FillRGBAValue(unsigned int red,unsigned int green,unsigned int blue,unsigned int)1009 void FillRGBAValue(unsigned int red, unsigned int green, unsigned int blue, unsigned int)
1010 {
1011 FillRGBValue(red, green, blue);
1012 }
FillRGBTValue(float red,float green,float blue,float)1013 void FillRGBTValue(float red, float green, float blue, float)
1014 {
1015 FillRGBValue(red, green, blue);
1016 }
FillRGBFTValue(float red,float green,float blue,float,float)1017 void FillRGBFTValue(float red, float green, float blue, float, float)
1018 {
1019 FillRGBValue(red, green, blue);
1020 }
1021 private:
1022 vector<T, Allocator> pixels;
1023 };
1024
1025 typedef GrayImage<unsigned char, 255, Image::Gray_Int8> MemoryGray8Image;
1026
1027 typedef GrayImage<unsigned short, 65535, Image::Gray_Int16> MemoryGray16Image;
1028
1029 template<typename T, unsigned int TMAX, int IDT, class Allocator = allocator<T> >
1030 class GrayAImage : public Image
1031 {
1032 public:
GrayAImage(unsigned int w,unsigned int h)1033 GrayAImage(unsigned int w, unsigned int h) :
1034 Image(w, h, ImageDataType(IDT)) { pixels.resize(SafeUnsignedProduct<size_t>(w, h, 2u)); FillBitValue(false); }
GrayAImage(unsigned int w,unsigned int h,const vector<RGBMapEntry> & m)1035 GrayAImage(unsigned int w, unsigned int h, const vector<RGBMapEntry>& m) :
1036 Image(w, h, ImageDataType(IDT), m) { pixels.resize(SafeUnsignedProduct<size_t>(w, h, 2u)); FillBitValue(false); }
GrayAImage(unsigned int w,unsigned int h,const vector<RGBAMapEntry> & m)1037 GrayAImage(unsigned int w, unsigned int h, const vector<RGBAMapEntry>& m) :
1038 Image(w, h, ImageDataType(IDT), m) { pixels.resize(SafeUnsignedProduct<size_t>(w, h, 2u)); FillBitValue(false); }
GrayAImage(unsigned int w,unsigned int h,const vector<RGBFTMapEntry> & m)1039 GrayAImage(unsigned int w, unsigned int h, const vector<RGBFTMapEntry>& m) :
1040 Image(w, h, ImageDataType(IDT), m) { pixels.resize(SafeUnsignedProduct<size_t>(w, h, 2u)); FillBitValue(false); }
~GrayAImage()1041 ~GrayAImage() { }
1042
IsOpaque() const1043 bool IsOpaque() const
1044 {
1045 for(typename vector<T, Allocator>::const_iterator i(pixels.begin()); i != pixels.end(); i += 2)
1046 {
1047 if(i[1] < TMAX)
1048 return false;
1049 }
1050
1051 return true;
1052 }
IsGrayscale() const1053 bool IsGrayscale() const
1054 {
1055 return true;
1056 }
IsColour() const1057 bool IsColour() const
1058 {
1059 return false;
1060 }
IsFloat() const1061 bool IsFloat() const
1062 {
1063 return false;
1064 }
IsInt() const1065 bool IsInt() const
1066 {
1067 return true;
1068 }
IsIndexed() const1069 bool IsIndexed() const
1070 {
1071 return false;
1072 }
IsGammaEncoded() const1073 bool IsGammaEncoded() const
1074 {
1075 return false;
1076 }
HasAlphaChannel() const1077 bool HasAlphaChannel() const
1078 {
1079 return true;
1080 }
HasFilterTransmit() const1081 bool HasFilterTransmit() const
1082 {
1083 return false;
1084 }
GetMaxIntValue() const1085 unsigned int GetMaxIntValue() const
1086 {
1087 return TMAX;
1088 }
TryDeferDecoding(GammaCurvePtr &,unsigned int)1089 bool TryDeferDecoding(GammaCurvePtr&, unsigned int)
1090 {
1091 return false;
1092 }
1093
GetBitValue(unsigned int x,unsigned int y) const1094 bool GetBitValue(unsigned int x, unsigned int y) const
1095 {
1096 // TODO FIXME - [CLi] This ignores opacity information; other bit-based code doesn't.
1097 CHECK_BOUNDS(x, y);
1098 return (pixels[(x + y * size_t(width)) * 2] != 0);
1099 }
GetGrayValue(unsigned int x,unsigned int y) const1100 float GetGrayValue(unsigned int x, unsigned int y) const
1101 {
1102 CHECK_BOUNDS(x, y);
1103 return float(pixels[(x + y * size_t(width)) * 2]) / float(TMAX);
1104 }
GetGrayAValue(unsigned int x,unsigned int y,float & gray,float & alpha) const1105 void GetGrayAValue(unsigned int x, unsigned int y, float& gray, float& alpha) const
1106 {
1107 CHECK_BOUNDS(x, y);
1108 gray = float(pixels[(x + y * size_t(width)) * 2]) / float(TMAX);
1109 alpha = float(pixels[(x + y * size_t(width)) * 2 + 1]) / float(TMAX);
1110 }
GetRGBValue(unsigned int x,unsigned int y,float & red,float & green,float & blue) const1111 void GetRGBValue(unsigned int x, unsigned int y, float& red, float& green, float& blue) const
1112 {
1113 red = green = blue = GetGrayValue(x, y);
1114 }
GetRGBAValue(unsigned int x,unsigned int y,float & red,float & green,float & blue,float & alpha) const1115 void GetRGBAValue(unsigned int x, unsigned int y, float& red, float& green, float& blue, float& alpha) const
1116 {
1117 GetGrayAValue(x, y, red, alpha);
1118 green = blue = red;
1119 }
GetRGBTValue(unsigned int x,unsigned int y,float & red,float & green,float & blue,float & transm) const1120 void GetRGBTValue(unsigned int x, unsigned int y, float& red, float& green, float& blue, float& transm) const
1121 {
1122 float alpha;
1123 GetGrayAValue(x, y, red, alpha);
1124 green = blue = red;
1125 transm = 1.0 - alpha;
1126 }
GetRGBFTValue(unsigned int x,unsigned int y,float & red,float & green,float & blue,float & filter,float & transm) const1127 void GetRGBFTValue(unsigned int x, unsigned int y, float& red, float& green, float& blue, float& filter, float& transm) const
1128 {
1129 float alpha;
1130 GetGrayAValue(x, y, red, alpha);
1131 green = blue = red;
1132 RGBFTColour::AtoFT(alpha, filter, transm);
1133 }
1134
SetBitValue(unsigned int x,unsigned int y,bool bit)1135 void SetBitValue(unsigned int x, unsigned int y, bool bit)
1136 {
1137 if(bit == true)
1138 SetGrayAValue(x, y, TMAX, ALPHA_OPAQUE_INT(TMAX));
1139 else
1140 SetGrayAValue(x, y, (unsigned int)0, ALPHA_OPAQUE_INT(TMAX));
1141 }
SetGrayValue(unsigned int x,unsigned int y,float gray)1142 void SetGrayValue(unsigned int x, unsigned int y, float gray)
1143 {
1144 SetGrayAValue(x, y, gray, ALPHA_OPAQUE);
1145 }
SetGrayValue(unsigned int x,unsigned int y,unsigned int gray)1146 void SetGrayValue(unsigned int x, unsigned int y, unsigned int gray)
1147 {
1148 SetGrayAValue(x, y, gray, ALPHA_OPAQUE_INT(TMAX));
1149 }
SetGrayAValue(unsigned int x,unsigned int y,float gray,float alpha)1150 void SetGrayAValue(unsigned int x, unsigned int y, float gray, float alpha)
1151 {
1152 CHECK_BOUNDS(x, y);
1153 pixels[(x + y * size_t(width)) * 2] = T(gray * float(TMAX));
1154 pixels[(x + y * size_t(width)) * 2 + 1] = T(alpha * float(TMAX));
1155 }
SetGrayAValue(unsigned int x,unsigned int y,unsigned int gray,unsigned int alpha)1156 void SetGrayAValue(unsigned int x, unsigned int y, unsigned int gray, unsigned int alpha)
1157 {
1158 CHECK_BOUNDS(x, y);
1159 pixels[(x + y * size_t(width)) * 2] = gray;
1160 pixels[(x + y * size_t(width)) * 2 + 1] = alpha;
1161 }
SetRGBValue(unsigned int x,unsigned int y,float red,float green,float blue)1162 void SetRGBValue(unsigned int x, unsigned int y, float red, float green, float blue)
1163 {
1164 SetGrayValue(x, y, RGB2Gray(red, green, blue));
1165 }
SetRGBValue(unsigned int x,unsigned int y,unsigned int red,unsigned int green,unsigned int blue)1166 void SetRGBValue(unsigned int x, unsigned int y, unsigned int red, unsigned int green, unsigned int blue)
1167 {
1168 SetGrayValue(x, y, RGB2Gray(float(red) / float(TMAX), float(green) / float(TMAX), float(blue) / float(TMAX)));
1169 }
SetRGBAValue(unsigned int x,unsigned int y,float red,float green,float blue,float alpha)1170 void SetRGBAValue(unsigned int x, unsigned int y, float red, float green, float blue, float alpha)
1171 {
1172 SetGrayAValue(x, y, RGB2Gray(red, green, blue), alpha);
1173 }
SetRGBAValue(unsigned int x,unsigned int y,unsigned int red,unsigned int green,unsigned int blue,unsigned int alpha)1174 void SetRGBAValue(unsigned int x, unsigned int y, unsigned int red, unsigned int green, unsigned int blue, unsigned int alpha)
1175 {
1176 // TODO FIXME - this unnecessarily converts alpha from int to float, requiring it to be converted back to int
1177 SetGrayAValue(x, y, RGB2Gray(float(red) / float(TMAX), float(green) / float(TMAX), float(blue) / float(TMAX)), float(alpha) / float(TMAX));
1178 }
SetRGBTValue(unsigned int x,unsigned int y,float red,float green,float blue,float transm)1179 void SetRGBTValue(unsigned int x, unsigned int y, float red, float green, float blue, float transm)
1180 {
1181 SetGrayAValue(x, y, RGB2Gray(red, green, blue), 1.0 - transm);
1182 }
SetRGBTValue(unsigned int x,unsigned int y,const RGBTColour & col)1183 void SetRGBTValue(unsigned int x, unsigned int y, const RGBTColour& col)
1184 {
1185 SetGrayAValue(x, y, RGB2Gray(col.red(), col.green(), col.blue()), col.alpha());
1186 }
SetRGBFTValue(unsigned int x,unsigned int y,float red,float green,float blue,float filter,float transm)1187 void SetRGBFTValue(unsigned int x, unsigned int y, float red, float green, float blue, float filter, float transm)
1188 {
1189 SetGrayAValue(x, y, RGB2Gray(red, green, blue), RGBFTColour::FTtoA(filter, transm));
1190 }
SetRGBFTValue(unsigned int x,unsigned int y,const RGBFTColour & col)1191 void SetRGBFTValue(unsigned int x, unsigned int y, const RGBFTColour& col)
1192 {
1193 SetGrayAValue(x, y, RGB2Gray(col.red(), col.green(), col.blue()), col.FTtoA());
1194 }
1195
FillBitValue(bool bit)1196 void FillBitValue(bool bit)
1197 {
1198 if(bit == true)
1199 FillGrayValue(TMAX);
1200 else
1201 FillGrayValue((unsigned int)0);
1202 }
FillGrayValue(float gray)1203 void FillGrayValue(float gray)
1204 {
1205 FillGrayValue((unsigned int)(gray * float(TMAX)));
1206 }
FillGrayValue(unsigned int gray)1207 void FillGrayValue(unsigned int gray)
1208 {
1209 FillGrayAValue(gray, ALPHA_OPAQUE_INT(TMAX));
1210 }
FillGrayAValue(float gray,float alpha)1211 void FillGrayAValue(float gray, float alpha)
1212 {
1213 // [CLi 2009-09] this was dividing by float(TMAX) - which I presume to have been a bug.
1214 T g(gray * float(TMAX)), a(alpha * float(TMAX));
1215 for(typename vector<T, Allocator>::iterator i(pixels.begin()); i != pixels.end(); i++)
1216 {
1217 *i = g;
1218 i++;
1219 *i = a;
1220 }
1221 }
FillGrayAValue(unsigned int gray,unsigned int alpha)1222 void FillGrayAValue(unsigned int gray, unsigned int alpha)
1223 {
1224 for(typename vector<T, Allocator>::iterator i(pixels.begin()); i != pixels.end(); i++)
1225 {
1226 *i = T(gray);
1227 i++;
1228 *i = T(alpha);
1229 }
1230 }
FillRGBValue(float red,float green,float blue)1231 void FillRGBValue(float red, float green, float blue)
1232 {
1233 FillGrayValue(RGB2Gray(red, green, blue));
1234 }
FillRGBValue(unsigned int red,unsigned int green,unsigned int blue)1235 void FillRGBValue(unsigned int red, unsigned int green, unsigned int blue)
1236 {
1237 FillGrayValue(RGB2Gray(float(red) / float(TMAX), float(green) / float(TMAX), float(blue) / float(TMAX)));
1238 }
FillRGBAValue(float red,float green,float blue,float alpha)1239 void FillRGBAValue(float red, float green, float blue, float alpha)
1240 {
1241 FillGrayAValue(RGB2Gray(red, green, blue), alpha);
1242 }
FillRGBAValue(unsigned int red,unsigned int green,unsigned int blue,unsigned int alpha)1243 void FillRGBAValue(unsigned int red, unsigned int green, unsigned int blue, unsigned int alpha)
1244 {
1245 // TODO FIXME - this unnecessarily converts alpha from int to float, requiring it to be converted back to int
1246 FillGrayAValue(RGB2Gray(float(red) / float(TMAX), float(green) / float(TMAX), float(blue) / float(TMAX)), float(alpha) / float(TMAX));
1247 }
FillRGBTValue(float red,float green,float blue,float transm)1248 void FillRGBTValue(float red, float green, float blue, float transm)
1249 {
1250 FillGrayAValue(RGB2Gray(red, green, blue), 1.0 - transm);
1251 }
FillRGBFTValue(float red,float green,float blue,float filter,float transm)1252 void FillRGBFTValue(float red, float green, float blue, float filter, float transm)
1253 {
1254 FillGrayAValue(RGB2Gray(red, green, blue), RGBFTColour::FTtoA(filter, transm));
1255 }
1256 private:
1257 vector<T, Allocator> pixels;
1258 };
1259
1260 typedef GrayAImage<unsigned char, 255, Image::GrayA_Int8> MemoryGrayA8Image;
1261
1262 typedef GrayAImage<unsigned short, 65535, Image::GrayA_Int16> MemoryGrayA16Image;
1263
1264 template<typename T, unsigned int TMAX, int IDT, class Allocator = allocator<T> >
1265 class RGBImage : public Image
1266 {
1267 public:
RGBImage(unsigned int w,unsigned int h)1268 RGBImage(unsigned int w, unsigned int h) :
1269 Image(w, h, ImageDataType(IDT)) { pixels.resize(SafeUnsignedProduct<size_t>(w, h, 3u)); FillBitValue(false); }
RGBImage(unsigned int w,unsigned int h,const vector<RGBMapEntry> & m)1270 RGBImage(unsigned int w, unsigned int h, const vector<RGBMapEntry>& m) :
1271 Image(w, h, ImageDataType(IDT), m) { pixels.resize(SafeUnsignedProduct<size_t>(w, h, 3u)); FillBitValue(false); }
RGBImage(unsigned int w,unsigned int h,const vector<RGBAMapEntry> & m)1272 RGBImage(unsigned int w, unsigned int h, const vector<RGBAMapEntry>& m) :
1273 Image(w, h, ImageDataType(IDT), m) { pixels.resize(SafeUnsignedProduct<size_t>(w, h, 3u)); FillBitValue(false); }
RGBImage(unsigned int w,unsigned int h,const vector<RGBFTMapEntry> & m)1274 RGBImage(unsigned int w, unsigned int h, const vector<RGBFTMapEntry>& m) :
1275 Image(w, h, ImageDataType(IDT), m) { pixels.resize(SafeUnsignedProduct<size_t>(w, h, 3u)); FillBitValue(false); }
~RGBImage()1276 ~RGBImage() { }
1277
IsOpaque() const1278 bool IsOpaque() const
1279 {
1280 return true;
1281 }
IsGrayscale() const1282 bool IsGrayscale() const
1283 {
1284 return false;
1285 }
IsColour() const1286 bool IsColour() const
1287 {
1288 return true;
1289 }
IsFloat() const1290 bool IsFloat() const
1291 {
1292 return false;
1293 }
IsInt() const1294 bool IsInt() const
1295 {
1296 return true;
1297 }
IsIndexed() const1298 bool IsIndexed() const
1299 {
1300 return false;
1301 }
IsGammaEncoded() const1302 bool IsGammaEncoded() const
1303 {
1304 return false;
1305 }
HasAlphaChannel() const1306 bool HasAlphaChannel() const
1307 {
1308 return false;
1309 }
HasFilterTransmit() const1310 bool HasFilterTransmit() const
1311 {
1312 return false;
1313 }
GetMaxIntValue() const1314 unsigned int GetMaxIntValue() const
1315 {
1316 return TMAX;
1317 }
TryDeferDecoding(GammaCurvePtr &,unsigned int)1318 bool TryDeferDecoding(GammaCurvePtr&, unsigned int)
1319 {
1320 return false;
1321 }
1322
GetBitValue(unsigned int x,unsigned int y) const1323 bool GetBitValue(unsigned int x, unsigned int y) const
1324 {
1325 float red, green, blue;
1326 GetRGBValue(x, y, red, green, blue);
1327 return IS_NONZERO_RGB(red, green, blue);
1328 }
GetGrayValue(unsigned int x,unsigned int y) const1329 float GetGrayValue(unsigned int x, unsigned int y) const
1330 {
1331 float red, green, blue;
1332 GetRGBValue(x, y, red, green, blue);
1333 return RGB2Gray(red, green, blue);
1334 }
GetGrayAValue(unsigned int x,unsigned int y,float & gray,float & alpha) const1335 void GetGrayAValue(unsigned int x, unsigned int y, float& gray, float& alpha) const
1336 {
1337 gray = GetGrayValue(x, y);
1338 alpha = ALPHA_OPAQUE;
1339 }
GetRGBValue(unsigned int x,unsigned int y,float & red,float & green,float & blue) const1340 void GetRGBValue(unsigned int x, unsigned int y, float& red, float& green, float& blue) const
1341 {
1342 CHECK_BOUNDS(x, y);
1343 red = float(pixels[(x + y * size_t(width)) * 3]) / float(TMAX);
1344 green = float(pixels[(x + y * size_t(width)) * 3 + 1]) / float(TMAX);
1345 blue = float(pixels[(x + y * size_t(width)) * 3 + 2]) / float(TMAX);
1346 }
GetRGBAValue(unsigned int x,unsigned int y,float & red,float & green,float & blue,float & alpha) const1347 void GetRGBAValue(unsigned int x, unsigned int y, float& red, float& green, float& blue, float& alpha) const
1348 {
1349 GetRGBValue(x, y, red, green, blue);
1350 alpha = ALPHA_OPAQUE;
1351 }
GetRGBTValue(unsigned int x,unsigned int y,float & red,float & green,float & blue,float & transm) const1352 void GetRGBTValue(unsigned int x, unsigned int y, float& red, float& green, float& blue, float& transm) const
1353 {
1354 GetRGBValue(x, y, red, green, blue);
1355 transm = FT_OPAQUE;
1356 }
GetRGBFTValue(unsigned int x,unsigned int y,float & red,float & green,float & blue,float & filter,float & transm) const1357 void GetRGBFTValue(unsigned int x, unsigned int y, float& red, float& green, float& blue, float& filter, float& transm) const
1358 {
1359 GetRGBValue(x, y, red, green, blue);
1360 filter = transm = FT_OPAQUE;
1361 }
1362
SetBitValue(unsigned int x,unsigned int y,bool bit)1363 void SetBitValue(unsigned int x, unsigned int y, bool bit)
1364 {
1365 if(bit == true)
1366 SetGrayValue(x, y, TMAX);
1367 else
1368 SetGrayValue(x, y, (unsigned int)0);
1369 }
SetGrayValue(unsigned int x,unsigned int y,float gray)1370 void SetGrayValue(unsigned int x, unsigned int y, float gray)
1371 {
1372 SetRGBValue(x, y, gray, gray, gray);
1373 }
SetGrayValue(unsigned int x,unsigned int y,unsigned int gray)1374 void SetGrayValue(unsigned int x, unsigned int y, unsigned int gray)
1375 {
1376 CHECK_BOUNDS(x, y);
1377 pixels[x + y * size_t(width) * 3] =
1378 pixels[x + y * size_t(width) * 3 + 1] =
1379 pixels[x + y * size_t(width) * 3 + 2] = gray;
1380 }
SetGrayAValue(unsigned int x,unsigned int y,float gray,float)1381 void SetGrayAValue(unsigned int x, unsigned int y, float gray, float)
1382 {
1383 CHECK_BOUNDS(x, y);
1384 pixels[x + y * size_t(width) * 3] =
1385 pixels[x + y * size_t(width) * 3 + 1] =
1386 pixels[x + y * size_t(width) * 3 + 2] = T(gray * float(TMAX));
1387 }
SetGrayAValue(unsigned int x,unsigned int y,unsigned int gray,unsigned int)1388 void SetGrayAValue(unsigned int x, unsigned int y, unsigned int gray, unsigned int)
1389 {
1390 CHECK_BOUNDS(x, y);
1391 pixels[x + y * size_t(width) * 3] =
1392 pixels[x + y * size_t(width) * 3 + 1] =
1393 pixels[x + y * size_t(width) * 3 + 2] = gray;
1394 }
SetRGBValue(unsigned int x,unsigned int y,float red,float green,float blue)1395 void SetRGBValue(unsigned int x, unsigned int y, float red, float green, float blue)
1396 {
1397 CHECK_BOUNDS(x, y);
1398 pixels[(x + y * size_t(width)) * 3] = T(red * float(TMAX));
1399 pixels[(x + y * size_t(width)) * 3 + 1] = T(green * float(TMAX));
1400 pixels[(x + y * size_t(width)) * 3 + 2] = T(blue * float(TMAX));
1401 }
SetRGBValue(unsigned int x,unsigned int y,unsigned int red,unsigned int green,unsigned int blue)1402 void SetRGBValue(unsigned int x, unsigned int y, unsigned int red, unsigned int green, unsigned int blue)
1403 {
1404 CHECK_BOUNDS(x, y);
1405 pixels[(x + y * size_t(width)) * 3] = T(red);
1406 pixels[(x + y * size_t(width)) * 3 + 1] = T(green);
1407 pixels[(x + y * size_t(width)) * 3 + 2] = T(blue);
1408 }
SetRGBAValue(unsigned int x,unsigned int y,float red,float green,float blue,float)1409 void SetRGBAValue(unsigned int x, unsigned int y, float red, float green, float blue, float)
1410 {
1411 SetRGBValue(x, y, red, green, blue);
1412 }
SetRGBAValue(unsigned int x,unsigned int y,unsigned int red,unsigned int green,unsigned int blue,unsigned int)1413 void SetRGBAValue(unsigned int x, unsigned int y, unsigned int red, unsigned int green, unsigned int blue, unsigned int)
1414 {
1415 SetRGBValue(x, y, red, green, blue);
1416 }
SetRGBTValue(unsigned int x,unsigned int y,float red,float green,float blue,float transm)1417 void SetRGBTValue(unsigned int x, unsigned int y, float red, float green, float blue, float transm)
1418 {
1419 SetRGBValue(x, y, red, green, blue);
1420 }
SetRGBTValue(unsigned int x,unsigned int y,const RGBTColour & col)1421 void SetRGBTValue(unsigned int x, unsigned int y, const RGBTColour& col)
1422 {
1423 SetRGBValue(x, y, col.red(), col.green(), col.blue());
1424 }
SetRGBFTValue(unsigned int x,unsigned int y,float red,float green,float blue,float,float)1425 void SetRGBFTValue(unsigned int x, unsigned int y, float red, float green, float blue, float, float)
1426 {
1427 SetRGBValue(x, y, red, green, blue);
1428 }
SetRGBFTValue(unsigned int x,unsigned int y,const RGBFTColour & col)1429 void SetRGBFTValue(unsigned int x, unsigned int y, const RGBFTColour& col)
1430 {
1431 SetRGBValue(x, y, col.red(), col.green(), col.blue());
1432 }
1433
FillBitValue(bool bit)1434 void FillBitValue(bool bit)
1435 {
1436 if(bit == true)
1437 FillGrayValue(TMAX);
1438 else
1439 FillGrayValue((unsigned int)0);
1440 }
FillGrayValue(float gray)1441 void FillGrayValue(float gray)
1442 {
1443 FillGrayValue((unsigned int)(gray * float(TMAX)));
1444 }
FillGrayValue(unsigned int gray)1445 void FillGrayValue(unsigned int gray)
1446 {
1447 fill(pixels.begin(), pixels.end(), gray);
1448 }
FillGrayAValue(float gray,float)1449 void FillGrayAValue(float gray, float)
1450 {
1451 FillRGBValue(gray, gray, gray);
1452 }
FillGrayAValue(unsigned int gray,unsigned int)1453 void FillGrayAValue(unsigned int gray, unsigned int)
1454 {
1455 FillRGBValue(gray, gray, gray);
1456 }
FillRGBValue(float red,float green,float blue)1457 void FillRGBValue(float red, float green, float blue)
1458 {
1459 // [CLi 2009-09] this was dividing by float(TMAX) - which I presume to have been a bug.
1460 T r(red * float(TMAX)), g(green * float(TMAX)), b(blue * float(TMAX));
1461 for(typename vector<T, Allocator>::iterator i(pixels.begin()); i != pixels.end(); i++)
1462 {
1463 *i = r;
1464 i++;
1465 *i = g;
1466 i++;
1467 *i = b;
1468 }
1469 }
FillRGBValue(unsigned int red,unsigned int green,unsigned int blue)1470 void FillRGBValue(unsigned int red, unsigned int green, unsigned int blue)
1471 {
1472 for(typename vector<T, Allocator>::iterator i(pixels.begin()); i != pixels.end(); i++)
1473 {
1474 *i = T(red);
1475 i++;
1476 *i = T(green);
1477 i++;
1478 *i = T(blue);
1479 }
1480 }
FillRGBAValue(float red,float green,float blue,float)1481 void FillRGBAValue(float red, float green, float blue, float)
1482 {
1483 FillRGBValue(red, green, blue);
1484 }
FillRGBAValue(unsigned int red,unsigned int green,unsigned int blue,unsigned int)1485 void FillRGBAValue(unsigned int red, unsigned int green, unsigned int blue, unsigned int)
1486 {
1487 FillRGBValue(red, green, blue);
1488 }
FillRGBTValue(float red,float green,float blue,float)1489 void FillRGBTValue(float red, float green, float blue, float)
1490 {
1491 FillRGBValue(red, green, blue);
1492 }
FillRGBFTValue(float red,float green,float blue,float,float)1493 void FillRGBFTValue(float red, float green, float blue, float, float)
1494 {
1495 FillRGBValue(red, green, blue);
1496 }
1497 private:
1498 vector<T, Allocator> pixels;
1499 };
1500
1501 typedef RGBImage<unsigned char, 255, Image::RGB_Int8> MemoryRGB8Image;
1502
1503 typedef RGBImage<unsigned short, 65535, Image::RGB_Int16> MemoryRGB16Image;
1504
1505 template<typename T, unsigned int TMAX, int IDT, class Allocator = allocator<T> >
1506 class RGBAImage : public Image
1507 {
1508 public:
RGBAImage(unsigned int w,unsigned int h)1509 RGBAImage(unsigned int w, unsigned int h) :
1510 Image(w, h, ImageDataType(IDT)) { pixels.resize(SafeUnsignedProduct<size_t>(w, h, 4u)); FillBitValue(false); }
RGBAImage(unsigned int w,unsigned int h,const vector<RGBMapEntry> & m)1511 RGBAImage(unsigned int w, unsigned int h, const vector<RGBMapEntry>& m) :
1512 Image(w, h, ImageDataType(IDT), m) { pixels.resize(SafeUnsignedProduct<size_t>(w, h, 4u)); FillBitValue(false); }
RGBAImage(unsigned int w,unsigned int h,const vector<RGBAMapEntry> & m)1513 RGBAImage(unsigned int w, unsigned int h, const vector<RGBAMapEntry>& m) :
1514 Image(w, h, ImageDataType(IDT), m) { pixels.resize(SafeUnsignedProduct<size_t>(w, h, 4u)); FillBitValue(false); }
RGBAImage(unsigned int w,unsigned int h,const vector<RGBFTMapEntry> & m)1515 RGBAImage(unsigned int w, unsigned int h, const vector<RGBFTMapEntry>& m) :
1516 Image(w, h, ImageDataType(IDT), m) { pixels.resize(SafeUnsignedProduct<size_t>(w, h, 4u)); FillBitValue(false); }
~RGBAImage()1517 ~RGBAImage() { }
1518
IsOpaque() const1519 bool IsOpaque() const
1520 {
1521 for(typename vector<T, Allocator>::const_iterator i(pixels.begin()); i != pixels.end(); i += 4)
1522 {
1523 if(i[3] < TMAX)
1524 return false;
1525 }
1526
1527 return true;
1528 }
IsGrayscale() const1529 bool IsGrayscale() const
1530 {
1531 return false;
1532 }
IsColour() const1533 bool IsColour() const
1534 {
1535 return true;
1536 }
IsFloat() const1537 bool IsFloat() const
1538 {
1539 return false;
1540 }
IsInt() const1541 bool IsInt() const
1542 {
1543 return true;
1544 }
IsIndexed() const1545 bool IsIndexed() const
1546 {
1547 return false;
1548 }
IsGammaEncoded() const1549 bool IsGammaEncoded() const
1550 {
1551 return false;
1552 }
HasAlphaChannel() const1553 bool HasAlphaChannel() const
1554 {
1555 return true;
1556 }
HasFilterTransmit() const1557 bool HasFilterTransmit() const
1558 {
1559 return false;
1560 }
GetMaxIntValue() const1561 unsigned int GetMaxIntValue() const
1562 {
1563 return TMAX;
1564 }
TryDeferDecoding(GammaCurvePtr &,unsigned int)1565 bool TryDeferDecoding(GammaCurvePtr&, unsigned int)
1566 {
1567 return false;
1568 }
1569
GetBitValue(unsigned int x,unsigned int y) const1570 bool GetBitValue(unsigned int x, unsigned int y) const
1571 {
1572 // TODO FIXME - [CLi] This ignores opacity information; other bit-based code doesn't.
1573 float red, green, blue, alpha;
1574 GetRGBAValue(x, y, red, green, blue, alpha);
1575 return IS_NONZERO_RGB(red, green, blue);
1576 }
GetGrayValue(unsigned int x,unsigned int y) const1577 float GetGrayValue(unsigned int x, unsigned int y) const
1578 {
1579 float red, green, blue, alpha;
1580 GetRGBAValue(x, y, red, green, blue, alpha);
1581 return RGB2Gray(red, green, blue);
1582 }
GetGrayAValue(unsigned int x,unsigned int y,float & gray,float & alpha) const1583 void GetGrayAValue(unsigned int x, unsigned int y, float& gray, float& alpha) const
1584 {
1585 float red, green, blue;
1586 GetRGBAValue(x, y, red, green, blue, alpha);
1587 gray = RGB2Gray(red, green, blue);
1588 }
GetRGBValue(unsigned int x,unsigned int y,float & red,float & green,float & blue) const1589 void GetRGBValue(unsigned int x, unsigned int y, float& red, float& green, float& blue) const
1590 {
1591 float alpha;
1592 GetRGBAValue(x, y, red, green, blue, alpha);
1593 }
GetRGBAValue(unsigned int x,unsigned int y,float & red,float & green,float & blue,float & alpha) const1594 void GetRGBAValue(unsigned int x, unsigned int y, float& red, float& green, float& blue, float& alpha) const
1595 {
1596 CHECK_BOUNDS(x, y);
1597 red = float(pixels[(x + y * size_t(width)) * 4]) / float(TMAX);
1598 green = float(pixels[(x + y * size_t(width)) * 4 + 1]) / float(TMAX);
1599 blue = float(pixels[(x + y * size_t(width)) * 4 + 2]) / float(TMAX);
1600 alpha = float(pixels[(x + y * size_t(width)) * 4 + 3]) / float(TMAX);
1601 }
GetRGBTValue(unsigned int x,unsigned int y,float & red,float & green,float & blue,float & transm) const1602 void GetRGBTValue(unsigned int x, unsigned int y, float& red, float& green, float& blue, float& transm) const
1603 {
1604 float alpha;
1605 GetRGBAValue(x, y, red, green, blue, alpha);
1606 transm = 1.0 - alpha;
1607 }
GetRGBFTValue(unsigned int x,unsigned int y,float & red,float & green,float & blue,float & filter,float & transm) const1608 void GetRGBFTValue(unsigned int x, unsigned int y, float& red, float& green, float& blue, float& filter, float& transm) const
1609 {
1610 float alpha;
1611 GetRGBAValue(x, y, red, green, blue, alpha);
1612 RGBFTColour::AtoFT(alpha, filter, transm);
1613 }
1614
SetBitValue(unsigned int x,unsigned int y,bool bit)1615 void SetBitValue(unsigned int x, unsigned int y, bool bit)
1616 {
1617 if(bit == true)
1618 SetGrayValue(x, y, TMAX);
1619 else
1620 SetGrayValue(x, y, (unsigned int)0);
1621 }
SetGrayValue(unsigned int x,unsigned int y,float gray)1622 void SetGrayValue(unsigned int x, unsigned int y, float gray)
1623 {
1624 SetRGBAValue(x, y, gray, gray, gray, ALPHA_OPAQUE);
1625 }
SetGrayValue(unsigned int x,unsigned int y,unsigned int gray)1626 void SetGrayValue(unsigned int x, unsigned int y, unsigned int gray)
1627 {
1628 SetRGBAValue(x, y, gray, gray, gray, ALPHA_OPAQUE_INT(TMAX));
1629 }
SetGrayAValue(unsigned int x,unsigned int y,float gray,float alpha)1630 void SetGrayAValue(unsigned int x, unsigned int y, float gray, float alpha)
1631 {
1632 SetRGBAValue(x, y, gray, gray, gray, alpha);
1633 }
SetGrayAValue(unsigned int x,unsigned int y,unsigned int gray,unsigned int alpha)1634 void SetGrayAValue(unsigned int x, unsigned int y, unsigned int gray, unsigned int alpha)
1635 {
1636 SetRGBAValue(x, y, gray, gray, gray, alpha);
1637 }
SetRGBValue(unsigned int x,unsigned int y,float red,float green,float blue)1638 void SetRGBValue(unsigned int x, unsigned int y, float red, float green, float blue)
1639 {
1640 SetRGBAValue(x, y, red, green, blue, ALPHA_OPAQUE);
1641 }
SetRGBValue(unsigned int x,unsigned int y,unsigned int red,unsigned int green,unsigned int blue)1642 void SetRGBValue(unsigned int x, unsigned int y, unsigned int red, unsigned int green, unsigned int blue)
1643 {
1644 SetRGBAValue(x, y, red, green, blue, ALPHA_OPAQUE_INT(TMAX));
1645 }
SetRGBAValue(unsigned int x,unsigned int y,float red,float green,float blue,float alpha)1646 void SetRGBAValue(unsigned int x, unsigned int y, float red, float green, float blue, float alpha)
1647 {
1648 CHECK_BOUNDS(x, y);
1649 pixels[(x + y * size_t(width)) * 4] = T(red * float(TMAX));
1650 pixels[(x + y * size_t(width)) * 4 + 1] = T(green * float(TMAX));
1651 pixels[(x + y * size_t(width)) * 4 + 2] = T(blue * float(TMAX));
1652 pixels[(x + y * size_t(width)) * 4 + 3] = T(alpha * float(TMAX));
1653 }
SetRGBAValue(unsigned int x,unsigned int y,unsigned int red,unsigned int green,unsigned int blue,unsigned int alpha)1654