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         void SetRGBAValue(unsigned int x, unsigned int y, unsigned int red, unsigned int green, unsigned int blue, unsigned int alpha)
1655         {
1656             CHECK_BOUNDS(x, y);
1657             pixels[(x + y * size_t(width)) * 4]     = T(red);
1658             pixels[(x + y * size_t(width)) * 4 + 1] = T(green);
1659             pixels[(x + y * size_t(width)) * 4 + 2] = T(blue);
1660             pixels[(x + y * size_t(width)) * 4 + 3] = T(alpha);
1661         }
SetRGBTValue(unsigned int x,unsigned int y,float red,float green,float blue,float transm)1662         void SetRGBTValue(unsigned int x, unsigned int y, float red, float green, float blue, float transm)
1663         {
1664             SetRGBAValue(x, y, red, green, blue, 1.0 - transm);
1665         }
SetRGBTValue(unsigned int x,unsigned int y,const RGBTColour & col)1666         void SetRGBTValue(unsigned int x, unsigned int y, const RGBTColour& col)
1667         {
1668             CHECK_BOUNDS(x, y);
1669             pixels[(x + y * size_t(width)) * 4]     = T(col.red()   * float(TMAX));
1670             pixels[(x + y * size_t(width)) * 4 + 1] = T(col.green() * float(TMAX));
1671             pixels[(x + y * size_t(width)) * 4 + 2] = T(col.blue()  * float(TMAX));
1672             pixels[(x + y * size_t(width)) * 4 + 3] = T(col.alpha() * float(TMAX));
1673         }
SetRGBFTValue(unsigned int x,unsigned int y,float red,float green,float blue,float filter,float transm)1674         void SetRGBFTValue(unsigned int x, unsigned int y, float red, float green, float blue, float filter, float transm)
1675         {
1676             SetRGBAValue(x, y, red, green, blue, RGBFTColour::FTtoA(filter, transm));
1677         }
SetRGBFTValue(unsigned int x,unsigned int y,const RGBFTColour & col)1678         void SetRGBFTValue(unsigned int x, unsigned int y, const RGBFTColour& col)
1679         {
1680             CHECK_BOUNDS(x, y);
1681             pixels[(x + y * size_t(width)) * 4]     = T(col.red()   * float(TMAX));
1682             pixels[(x + y * size_t(width)) * 4 + 1] = T(col.green() * float(TMAX));
1683             pixels[(x + y * size_t(width)) * 4 + 2] = T(col.blue()  * float(TMAX));
1684             pixels[(x + y * size_t(width)) * 4 + 3] = T(col.FTtoA() * float(TMAX));
1685         }
1686 
FillBitValue(bool bit)1687         void FillBitValue(bool bit)
1688         {
1689             if(bit == true)
1690                 FillGrayValue(TMAX);
1691             else
1692                 FillGrayValue((unsigned int)0);
1693         }
FillGrayValue(float gray)1694         void FillGrayValue(float gray)
1695         {
1696             FillRGBAValue(gray, gray, gray, ALPHA_OPAQUE);
1697         }
FillGrayValue(unsigned int gray)1698         void FillGrayValue(unsigned int gray)
1699         {
1700             FillRGBAValue(gray, gray, gray, ALPHA_OPAQUE_INT(TMAX));
1701         }
FillGrayAValue(float gray,float alpha)1702         void FillGrayAValue(float gray, float alpha)
1703         {
1704             FillRGBAValue(gray, gray, gray, alpha);
1705         }
FillGrayAValue(unsigned int gray,unsigned int alpha)1706         void FillGrayAValue(unsigned int gray, unsigned int alpha)
1707         {
1708             FillRGBAValue(gray, gray, gray, alpha);
1709         }
FillRGBValue(float red,float green,float blue)1710         void FillRGBValue(float red, float green, float blue)
1711         {
1712             FillRGBAValue(red, green, blue, ALPHA_OPAQUE);
1713         }
FillRGBValue(unsigned int red,unsigned int green,unsigned int blue)1714         void FillRGBValue(unsigned int red, unsigned int green, unsigned int blue)
1715         {
1716             FillRGBAValue(red, green, blue, ALPHA_OPAQUE_INT(TMAX));
1717         }
FillRGBAValue(float red,float green,float blue,float alpha)1718         void FillRGBAValue(float red, float green, float blue, float alpha)
1719         {
1720             // [CLi 2009-09] this was dividing by float(TMAX) - which I presume to have been a bug.
1721             T r(red * float(TMAX)), g(green * float(TMAX)), b(blue * float(TMAX)), a(alpha * float(TMAX));
1722             for(typename vector<T, Allocator>::iterator i(pixels.begin()); i != pixels.end(); i++)
1723             {
1724                 *i = r;
1725                 i++;
1726                 *i = g;
1727                 i++;
1728                 *i = b;
1729                 i++;
1730                 *i = a;
1731             }
1732         }
FillRGBAValue(unsigned int red,unsigned int green,unsigned int blue,unsigned int alpha)1733         void FillRGBAValue(unsigned int red, unsigned int green, unsigned int blue, unsigned int alpha)
1734         {
1735             for(typename vector<T, Allocator>::iterator i(pixels.begin()); i != pixels.end(); i++)
1736             {
1737                 *i = T(red);
1738                 i++;
1739                 *i = T(green);
1740                 i++;
1741                 *i = T(blue);
1742                 i++;
1743                 *i = T(alpha);
1744             }
1745         }
FillRGBTValue(float red,float green,float blue,float transm)1746         void FillRGBTValue(float red, float green, float blue, float transm)
1747         {
1748             FillRGBAValue(red, green, blue, 1.0 - transm);
1749         }
FillRGBFTValue(float red,float green,float blue,float filter,float transm)1750         void FillRGBFTValue(float red, float green, float blue, float filter, float transm)
1751         {
1752             FillRGBAValue(red, green, blue, RGBFTColour::FTtoA(filter, transm));
1753         }
1754     private:
1755         vector<T, Allocator> pixels;
1756 };
1757 
1758 typedef RGBAImage<unsigned char, 255, Image::RGBA_Int8> MemoryRGBA8Image;
1759 
1760 typedef RGBAImage<unsigned short, 65535, Image::RGBA_Int16> MemoryRGBA16Image;
1761 
1762 template<class PixelContainer = vector<float, allocator<float> > >
1763 class RGBFTImage : public Image
1764 {
1765     public:
RGBFTImage(unsigned int w,unsigned int h)1766         RGBFTImage(unsigned int w, unsigned int h) :
1767             Image(w, h, RGBFT_Float) { pixels.resize(SafeUnsignedProduct<size_t>(w, h, 5u)); FillBitValue(false); }
RGBFTImage(unsigned int w,unsigned int h,const vector<RGBMapEntry> & m)1768         RGBFTImage(unsigned int w, unsigned int h, const vector<RGBMapEntry>& m) :
1769             Image(w, h, RGBFT_Float, m) { pixels.resize(SafeUnsignedProduct<size_t>(w, h, 5u)); FillBitValue(false); }
RGBFTImage(unsigned int w,unsigned int h,const vector<RGBAMapEntry> & m)1770         RGBFTImage(unsigned int w, unsigned int h, const vector<RGBAMapEntry>& m) :
1771             Image(w, h, RGBFT_Float, m) { pixels.resize(SafeUnsignedProduct<size_t>(w, h, 5u)); FillBitValue(false); }
RGBFTImage(unsigned int w,unsigned int h,const vector<RGBFTMapEntry> & m)1772         RGBFTImage(unsigned int w, unsigned int h, const vector<RGBFTMapEntry>& m) :
1773             Image(w, h, RGBFT_Float, m) { pixels.resize(SafeUnsignedProduct<size_t>(w, h, 5u)); FillBitValue(false); }
~RGBFTImage()1774         ~RGBFTImage() { }
1775 
IsOpaque() const1776         bool IsOpaque() const
1777         {
1778             for(typename PixelContainer::const_iterator i(pixels.begin()); i != pixels.end(); i += 5)
1779             {
1780                 if(i[4] > 0.0f) // TODO FIXME - this ignores filter
1781                     return false;
1782             }
1783             return true;
1784         }
IsGrayscale() const1785         bool IsGrayscale() const
1786         {
1787             return false;
1788         }
IsColour() const1789         bool IsColour() const
1790         {
1791             return true;
1792         }
IsFloat() const1793         bool IsFloat() const
1794         {
1795             return true;
1796         }
IsInt() const1797         bool IsInt() const
1798         {
1799             return false;
1800         }
IsIndexed() const1801         bool IsIndexed() const
1802         {
1803             return false;
1804         }
IsGammaEncoded() const1805         bool IsGammaEncoded() const
1806         {
1807             return false;
1808         }
HasAlphaChannel() const1809         bool HasAlphaChannel() const
1810         {
1811             return false;
1812         }
HasFilterTransmit() const1813         bool HasFilterTransmit() const
1814         {
1815             return true;
1816         }
GetMaxIntValue() const1817         unsigned int GetMaxIntValue() const
1818         {
1819             return 255;
1820         }
TryDeferDecoding(GammaCurvePtr &,unsigned int)1821         bool TryDeferDecoding(GammaCurvePtr&, unsigned int)
1822         {
1823             return false;
1824         }
1825 
GetBitValue(unsigned int x,unsigned int y) const1826         bool GetBitValue(unsigned int x, unsigned int y) const
1827         {
1828             // TODO FIXME - [CLi] This ignores opacity information; other bit-based code doesn't.
1829             float red, green, blue, filter, transm;
1830             GetRGBFTValue(x, y, red, green, blue, filter, transm);
1831             return IS_NONZERO_RGB(red, green, blue);
1832         }
GetGrayValue(unsigned int x,unsigned int y) const1833         float GetGrayValue(unsigned int x, unsigned int y) const
1834         {
1835             float red, green, blue, filter, transm;
1836             GetRGBFTValue(x, y, red, green, blue, filter, transm);
1837             return RGB2Gray(red, green, blue);
1838         }
GetGrayAValue(unsigned int x,unsigned int y,float & gray,float & alpha) const1839         void GetGrayAValue(unsigned int x, unsigned int y, float& gray, float& alpha) const
1840         {
1841             float red, green, blue, filter, transm;
1842             GetRGBFTValue(x, y, red, green, blue, filter, transm);
1843             gray = RGB2Gray(red, green, blue);
1844             alpha = RGBFTColour::FTtoA(filter, transm);
1845         }
GetRGBValue(unsigned int x,unsigned int y,float & red,float & green,float & blue) const1846         void GetRGBValue(unsigned int x, unsigned int y, float& red, float& green, float& blue) const
1847         {
1848             float filter, transm;
1849             GetRGBFTValue(x, y, red, green, blue, filter, transm);
1850         }
GetRGBAValue(unsigned int x,unsigned int y,float & red,float & green,float & blue,float & alpha) const1851         void GetRGBAValue(unsigned int x, unsigned int y, float& red, float& green, float& blue, float& alpha) const
1852         {
1853             float filter, transm;
1854             GetRGBFTValue(x, y, red, green, blue, filter, transm);
1855             alpha = RGBFTColour::FTtoA(filter, transm);
1856         }
GetRGBTValue(unsigned int x,unsigned int y,float & red,float & green,float & blue,float & transm) const1857         void GetRGBTValue(unsigned int x, unsigned int y, float& red, float& green, float& blue, float& transm) const
1858         {
1859             float filter;
1860             GetRGBFTValue(x, y, red, green, blue, filter, transm);
1861             transm = 1.0 - RGBFTColour::FTtoA(filter, transm);
1862         }
GetRGBFTValue(unsigned int x,unsigned int y,float & red,float & green,float & blue,float & filter,float & transm) const1863         void GetRGBFTValue(unsigned int x, unsigned int y, float& red, float& green, float& blue, float& filter, float& transm) const
1864         {
1865             CHECK_BOUNDS(x, y);
1866             red    = pixels[(x + y * size_t(width)) * 5];
1867             green  = pixels[(x + y * size_t(width)) * 5 + 1];
1868             blue   = pixels[(x + y * size_t(width)) * 5 + 2];
1869             filter = pixels[(x + y * size_t(width)) * 5 + 3];
1870             transm = pixels[(x + y * size_t(width)) * 5 + 4];
1871         }
1872 
SetBitValue(unsigned int x,unsigned int y,bool bit)1873         void SetBitValue(unsigned int x, unsigned int y, bool bit)
1874         {
1875             if(bit == true)
1876                 SetGrayValue(x, y, 1.0f);
1877             else
1878                 SetGrayValue(x, y, 0.0f);
1879         }
SetGrayValue(unsigned int x,unsigned int y,float gray)1880         void SetGrayValue(unsigned int x, unsigned int y, float gray)
1881         {
1882             SetRGBFTValue(x, y, gray, gray, gray, FT_OPAQUE, FT_OPAQUE);
1883         }
SetGrayValue(unsigned int x,unsigned int y,unsigned int gray)1884         void SetGrayValue(unsigned int x, unsigned int y, unsigned int gray)
1885         {
1886             SetGrayValue(x, y, float(gray) / 255.0f);
1887         }
SetGrayAValue(unsigned int x,unsigned int y,float gray,float alpha)1888         void SetGrayAValue(unsigned int x, unsigned int y, float gray, float alpha)
1889         {
1890             float filter, transm;
1891             RGBFTColour::AtoFT(alpha, filter, transm);
1892             SetRGBFTValue(x, y, gray, gray, gray, filter, transm);
1893         }
SetGrayAValue(unsigned int x,unsigned int y,unsigned int gray,unsigned int alpha)1894         void SetGrayAValue(unsigned int x, unsigned int y, unsigned int gray, unsigned int alpha)
1895         {
1896             float c = float(gray) / 255.0f;
1897             float filter, transm;
1898             RGBFTColour::AtoFT(float(alpha) / 255.0f, filter, transm);
1899             SetRGBFTValue(x, y, c, c, c, filter, transm);
1900         }
SetRGBValue(unsigned int x,unsigned int y,float red,float green,float blue)1901         void SetRGBValue(unsigned int x, unsigned int y, float red, float green, float blue)
1902         {
1903             SetRGBFTValue(x, y, red, green, blue, FT_OPAQUE, FT_OPAQUE);
1904         }
SetRGBValue(unsigned int x,unsigned int y,unsigned int red,unsigned int green,unsigned int blue)1905         void SetRGBValue(unsigned int x, unsigned int y, unsigned int red, unsigned int green, unsigned int blue)
1906         {
1907             SetRGBFTValue(x, y, float(red) / 255.0f, float(green) / 255.0f, float(blue) / 255.0f, FT_OPAQUE, FT_OPAQUE);
1908         }
SetRGBAValue(unsigned int x,unsigned int y,float red,float green,float blue,float alpha)1909         void SetRGBAValue(unsigned int x, unsigned int y, float red, float green, float blue, float alpha)
1910         {
1911             float filter, transm;
1912             RGBFTColour::AtoFT(alpha, filter, transm);
1913             SetRGBFTValue(x, y, red, green, blue, filter, transm);
1914         }
SetRGBAValue(unsigned int x,unsigned int y,unsigned int red,unsigned int green,unsigned int blue,unsigned int alpha)1915         void SetRGBAValue(unsigned int x, unsigned int y, unsigned int red, unsigned int green, unsigned int blue, unsigned int alpha)
1916         {
1917             float filter, transm;
1918             RGBFTColour::AtoFT(float(alpha) / 255.0f, filter, transm);
1919             SetRGBFTValue(x, y, float(red) / 255.0f, float(green) / 255.0f, float(blue) / 255.0f, filter, transm);
1920         }
SetRGBTValue(unsigned int x,unsigned int y,float red,float green,float blue,float transm)1921         void SetRGBTValue(unsigned int x, unsigned int y, float red, float green, float blue, float transm)
1922         {
1923             SetRGBFTValue(x, y, red, green, blue, FT_OPAQUE, transm);
1924         }
SetRGBTValue(unsigned int x,unsigned int y,const RGBTColour & col)1925         void SetRGBTValue(unsigned int x, unsigned int y, const RGBTColour& col)
1926         {
1927             SetRGBFTValue(x, y, col.red(), col.green(), col.blue(), FT_OPAQUE, col.transm());
1928         }
SetRGBFTValue(unsigned int x,unsigned int y,float red,float green,float blue,float filter,float transm)1929         void SetRGBFTValue(unsigned int x, unsigned int y, float red, float green, float blue, float filter, float transm)
1930         {
1931             CHECK_BOUNDS(x, y);
1932             pixels[(x + y * size_t(width)) * 5]     = red;
1933             pixels[(x + y * size_t(width)) * 5 + 1] = green;
1934             pixels[(x + y * size_t(width)) * 5 + 2] = blue;
1935             pixels[(x + y * size_t(width)) * 5 + 3] = filter;
1936             pixels[(x + y * size_t(width)) * 5 + 4] = transm;
1937         }
SetRGBFTValue(unsigned int x,unsigned int y,const RGBFTColour & col)1938         void SetRGBFTValue(unsigned int x, unsigned int y, const RGBFTColour& col)
1939         {
1940             CHECK_BOUNDS(x, y);
1941             pixels[(x + y * size_t(width)) * 5]     = col.red();
1942             pixels[(x + y * size_t(width)) * 5 + 1] = col.green();
1943             pixels[(x + y * size_t(width)) * 5 + 2] = col.blue();
1944             pixels[(x + y * size_t(width)) * 5 + 3] = col.filter();
1945             pixels[(x + y * size_t(width)) * 5 + 4] = col.transm();
1946         }
1947 
FillBitValue(bool bit)1948         void FillBitValue(bool bit)
1949         {
1950             if(bit == true)
1951                 FillGrayValue(1.0f);
1952             else
1953                 FillGrayValue(0.0f);
1954         }
FillGrayValue(float gray)1955         void FillGrayValue(float gray)
1956         {
1957             FillRGBFTValue(gray, gray, gray, FT_OPAQUE, FT_OPAQUE);
1958         }
FillGrayValue(unsigned int gray)1959         void FillGrayValue(unsigned int gray)
1960         {
1961             FillGrayValue(float(gray) / 255.0f);
1962         }
FillGrayAValue(float gray,float alpha)1963         void FillGrayAValue(float gray, float alpha)
1964         {
1965             float filter, transm;
1966             RGBFTColour::AtoFT(alpha, filter, transm);
1967             FillRGBFTValue(gray, gray, gray, filter, transm);
1968         }
FillGrayAValue(unsigned int gray,unsigned int alpha)1969         void FillGrayAValue(unsigned int gray, unsigned int alpha)
1970         {
1971             FillGrayAValue(float(gray) / 255.0f, float(alpha) / 255.0f);
1972         }
FillRGBValue(float red,float green,float blue)1973         void FillRGBValue(float red, float green, float blue)
1974         {
1975             FillRGBFTValue(red, green, blue, FT_OPAQUE, FT_OPAQUE);
1976         }
FillRGBValue(unsigned int red,unsigned int green,unsigned int blue)1977         void FillRGBValue(unsigned int red, unsigned int green, unsigned int blue)
1978         {
1979             FillRGBFTValue(float(red) / 255.0f, float(green) / 255.0f, float(blue) / 255.0f, FT_OPAQUE, FT_OPAQUE);
1980         }
FillRGBAValue(float red,float green,float blue,float alpha)1981         void FillRGBAValue(float red, float green, float blue, float alpha)
1982         {
1983             float filter, transm;
1984             RGBFTColour::AtoFT(alpha, filter, transm);
1985             FillRGBFTValue(red, green, blue, filter, transm);
1986         }
FillRGBAValue(unsigned int red,unsigned int green,unsigned int blue,unsigned int alpha)1987         void FillRGBAValue(unsigned int red, unsigned int green, unsigned int blue, unsigned int alpha)
1988         {
1989             float filter, transm;
1990             RGBFTColour::AtoFT(float(alpha) / 255.0f, filter, transm);
1991             FillRGBFTValue(float(red) / 255.0f, float(green) / 255.0f, float(blue) / 255.0f, filter, transm);
1992         }
FillRGBTValue(float red,float green,float blue,float transm)1993         void FillRGBTValue(float red, float green, float blue, float transm)
1994         {
1995             FillRGBFTValue(red, green, blue, FT_OPAQUE, transm);
1996         }
FillRGBFTValue(float red,float green,float blue,float filter,float transm)1997         void FillRGBFTValue(float red, float green, float blue, float filter, float transm)
1998         {
1999             for(typename PixelContainer::iterator i(pixels.begin()); i != pixels.end(); i++)
2000             {
2001                 *i = red;
2002                 i++;
2003                 *i = green;
2004                 i++;
2005                 *i = blue;
2006                 i++;
2007                 *i = filter;
2008                 i++;
2009                 *i = transm;
2010             }
2011         }
2012     private:
2013         PixelContainer pixels;
2014 };
2015 
2016 typedef RGBFTImage<> MemoryRGBFTImage;
2017 
2018 template<typename T, unsigned int TMAX, int IDT, class Allocator = allocator<T> >
2019 class NonlinearGrayImage : public Image
2020 {
2021     public:
NonlinearGrayImage(unsigned int w,unsigned int h)2022         NonlinearGrayImage(unsigned int w, unsigned int h) :
2023             Image(w, h, ImageDataType(IDT)), gamma(NeutralGammaCurve::Get()) { gammaLUT = gamma->GetLookupTable(TMAX); pixels.resize(SafeUnsignedProduct<size_t>(w, h)); FillBitValue(false); }
NonlinearGrayImage(unsigned int w,unsigned int h,const vector<RGBMapEntry> & m)2024         NonlinearGrayImage(unsigned int w, unsigned int h, const vector<RGBMapEntry>& m) :
2025             Image(w, h, ImageDataType(IDT), m), gamma(NeutralGammaCurve::Get()) { gammaLUT = gamma->GetLookupTable(TMAX); pixels.resize(SafeUnsignedProduct<size_t>(w, h)); FillBitValue(false); }
NonlinearGrayImage(unsigned int w,unsigned int h,const vector<RGBAMapEntry> & m)2026         NonlinearGrayImage(unsigned int w, unsigned int h, const vector<RGBAMapEntry>& m) :
2027             Image(w, h, ImageDataType(IDT), m), gamma(NeutralGammaCurve::Get()) { gammaLUT = gamma->GetLookupTable(TMAX); pixels.resize(SafeUnsignedProduct<size_t>(w, h)); FillBitValue(false); }
NonlinearGrayImage(unsigned int w,unsigned int h,const vector<RGBFTMapEntry> & m)2028         NonlinearGrayImage(unsigned int w, unsigned int h, const vector<RGBFTMapEntry>& m) :
2029             Image(w, h, ImageDataType(IDT), m), gamma(NeutralGammaCurve::Get()) { gammaLUT = gamma->GetLookupTable(TMAX); pixels.resize(SafeUnsignedProduct<size_t>(w, h)); FillBitValue(false); }
~NonlinearGrayImage()2030         ~NonlinearGrayImage() { }
2031 
IsOpaque() const2032         bool IsOpaque() const
2033         {
2034             return true;
2035         }
IsGrayscale() const2036         bool IsGrayscale() const
2037         {
2038             return true;
2039         }
IsColour() const2040         bool IsColour() const
2041         {
2042             return false;
2043         }
IsFloat() const2044         bool IsFloat() const
2045         {
2046             return false;
2047         }
IsInt() const2048         bool IsInt() const
2049         {
2050             return true;
2051         }
IsIndexed() const2052         bool IsIndexed() const
2053         {
2054             return false;
2055         }
IsGammaEncoded() const2056         bool IsGammaEncoded() const
2057         {
2058             return true;
2059         }
HasAlphaChannel() const2060         bool HasAlphaChannel() const
2061         {
2062             return false;
2063         }
HasFilterTransmit() const2064         bool HasFilterTransmit() const
2065         {
2066             return false;
2067         }
GetMaxIntValue() const2068         unsigned int GetMaxIntValue() const
2069         {
2070             return TMAX;
2071         }
TryDeferDecoding(GammaCurvePtr & g,unsigned int max)2072         bool TryDeferDecoding(GammaCurvePtr& g, unsigned int max)
2073         {
2074             if (max != TMAX) return false;
2075             if (!GammaCurve::IsNeutral(gamma)) return !g;
2076             gamma.swap(g);
2077             gammaLUT = gamma->GetLookupTable(TMAX);
2078             return true;
2079         }
2080 
GetBitValue(unsigned int x,unsigned int y) const2081         bool GetBitValue(unsigned int x, unsigned int y) const
2082         {
2083             CHECK_BOUNDS(x, y);
2084             return (pixels[x + y * size_t(width)] != 0);
2085         }
GetGrayValue(unsigned int x,unsigned int y) const2086         float GetGrayValue(unsigned int x, unsigned int y) const
2087         {
2088             CHECK_BOUNDS(x, y);
2089             return gammaLUT[pixels[x + y * size_t(width)]];
2090         }
GetGrayAValue(unsigned int x,unsigned int y,float & gray,float & alpha) const2091         void GetGrayAValue(unsigned int x, unsigned int y, float& gray, float& alpha) const
2092         {
2093             CHECK_BOUNDS(x, y);
2094             gray = gammaLUT[pixels[x + y * size_t(width)]];
2095             alpha = ALPHA_OPAQUE;
2096         }
GetRGBValue(unsigned int x,unsigned int y,float & red,float & green,float & blue) const2097         void GetRGBValue(unsigned int x, unsigned int y, float& red, float& green, float& blue) const
2098         {
2099             red = green = blue = GetGrayValue(x, y);
2100         }
GetRGBAValue(unsigned int x,unsigned int y,float & red,float & green,float & blue,float & alpha) const2101         void GetRGBAValue(unsigned int x, unsigned int y, float& red, float& green, float& blue, float& alpha) const
2102         {
2103             red = green = blue = GetGrayValue(x, y);
2104             alpha = ALPHA_OPAQUE;
2105         }
GetRGBTValue(unsigned int x,unsigned int y,float & red,float & green,float & blue,float & transm) const2106         void GetRGBTValue(unsigned int x, unsigned int y, float& red, float& green, float& blue, float& transm) const
2107         {
2108             red = green = blue = GetGrayValue(x, y);
2109             transm = FT_OPAQUE;
2110         }
GetRGBFTValue(unsigned int x,unsigned int y,float & red,float & green,float & blue,float & filter,float & transm) const2111         void GetRGBFTValue(unsigned int x, unsigned int y, float& red, float& green, float& blue, float& filter, float& transm) const
2112         {
2113             red = green = blue = GetGrayValue(x, y);
2114             filter = transm = FT_OPAQUE;
2115         }
GetIndexedValue(unsigned int x,unsigned int y)2116         unsigned char GetIndexedValue(unsigned int x, unsigned int y)
2117         {
2118             CHECK_BOUNDS(x, y);
2119             return (unsigned char)(int(pixels[x + y * size_t(width)]) / ((TMAX + 1) >> 8));
2120         }
2121 
SetBitValue(unsigned int x,unsigned int y,bool bit)2122         void SetBitValue(unsigned int x, unsigned int y, bool bit)
2123         {
2124             if(bit == true)
2125                 SetGrayValue(x, y, TMAX);
2126             else
2127                 SetGrayValue(x, y, (unsigned int)0);
2128         }
SetGrayValue(unsigned int x,unsigned int y,float gray)2129         void SetGrayValue(unsigned int x, unsigned int y, float gray)
2130         {
2131             CHECK_BOUNDS(x, y);
2132             pixels[x + y * size_t(width)] = IntEncode(gamma, gray, TMAX);
2133         }
SetGrayValue(unsigned int x,unsigned int y,unsigned int gray)2134         void SetGrayValue(unsigned int x, unsigned int y, unsigned int gray)
2135         {
2136             CHECK_BOUNDS(x, y);
2137             pixels[x + y * size_t(width)] = T(gray);
2138         }
SetGrayAValue(unsigned int x,unsigned int y,float gray,float)2139         void SetGrayAValue(unsigned int x, unsigned int y, float gray, float)
2140         {
2141             CHECK_BOUNDS(x, y);
2142             pixels[x + y * size_t(width)] = IntEncode(gamma, gray, TMAX);
2143         }
SetGrayAValue(unsigned int x,unsigned int y,unsigned int gray,unsigned int)2144         void SetGrayAValue(unsigned int x, unsigned int y, unsigned int gray, unsigned int)
2145         {
2146             CHECK_BOUNDS(x, y);
2147             pixels[x + y * size_t(width)] = T(gray);
2148         }
SetRGBValue(unsigned int x,unsigned int y,float red,float green,float blue)2149         void SetRGBValue(unsigned int x, unsigned int y, float red, float green, float blue)
2150         {
2151             SetGrayValue(x, y, RGB2Gray(red, green, blue));
2152         }
SetRGBValue(unsigned int x,unsigned int y,unsigned int red,unsigned int green,unsigned int blue)2153         void SetRGBValue(unsigned int x, unsigned int y, unsigned int red, unsigned int green, unsigned int blue)
2154         {
2155             SetGrayValue(x, y, RGB2Gray(gammaLUT[red], gammaLUT[green], gammaLUT[blue]));
2156         }
SetRGBAValue(unsigned int x,unsigned int y,float red,float green,float blue,float)2157         void SetRGBAValue(unsigned int x, unsigned int y, float red, float green, float blue, float)
2158         {
2159             SetRGBValue(x, y, red, green, blue);
2160         }
SetRGBAValue(unsigned int x,unsigned int y,unsigned int red,unsigned int green,unsigned int blue,unsigned int)2161         void SetRGBAValue(unsigned int x, unsigned int y, unsigned int red, unsigned int green, unsigned int blue, unsigned int)
2162         {
2163             SetRGBValue(x, y, red, green, blue);
2164         }
SetRGBTValue(unsigned int x,unsigned int y,float red,float green,float blue,float transm)2165         void SetRGBTValue(unsigned int x, unsigned int y, float red, float green, float blue, float transm)
2166         {
2167             SetRGBValue(x, y, red, green, blue);
2168         }
SetRGBTValue(unsigned int x,unsigned int y,const RGBTColour & col)2169         void SetRGBTValue(unsigned int x, unsigned int y, const RGBTColour& col)
2170         {
2171             SetRGBValue(x, y, col.red(), col.green(), col.blue());
2172         }
SetRGBFTValue(unsigned int x,unsigned int y,float red,float green,float blue,float,float)2173         void SetRGBFTValue(unsigned int x, unsigned int y, float red, float green, float blue, float, float)
2174         {
2175             SetRGBValue(x, y, red, green, blue);
2176         }
SetRGBFTValue(unsigned int x,unsigned int y,const RGBFTColour & col)2177         void SetRGBFTValue(unsigned int x, unsigned int y, const RGBFTColour& col)
2178         {
2179             SetRGBValue(x, y, col.red(), col.green(), col.blue());
2180         }
2181 
FillBitValue(bool bit)2182         void FillBitValue(bool bit)
2183         {
2184             if(bit == true)
2185                 FillGrayValue(TMAX);
2186             else
2187                 FillGrayValue((unsigned int)0);
2188         }
FillGrayValue(float gray)2189         void FillGrayValue(float gray)
2190         {
2191             FillGrayValue(IntEncode(gamma, gray, TMAX));
2192         }
FillGrayValue(unsigned int gray)2193         void FillGrayValue(unsigned int gray)
2194         {
2195             fill(pixels.begin(), pixels.end(), T(gray));
2196         }
FillGrayAValue(float gray,float)2197         void FillGrayAValue(float gray, float)
2198         {
2199             FillGrayValue(gray);
2200         }
FillGrayAValue(unsigned int gray,unsigned int)2201         void FillGrayAValue(unsigned int gray, unsigned int)
2202         {
2203             FillGrayValue(gray);
2204         }
FillRGBValue(float red,float green,float blue)2205         void FillRGBValue(float red, float green, float blue)
2206         {
2207             FillGrayValue(RGB2Gray(red, green, blue));
2208         }
FillRGBValue(unsigned int red,unsigned int green,unsigned int blue)2209         void FillRGBValue(unsigned int red, unsigned int green, unsigned int blue)
2210         {
2211             FillGrayValue(RGB2Gray(gammaLUT[red], gammaLUT[green], gammaLUT[blue]));
2212         }
FillRGBAValue(float red,float green,float blue,float)2213         void FillRGBAValue(float red, float green, float blue, float)
2214         {
2215             FillRGBValue(red, green, blue);
2216         }
FillRGBAValue(unsigned int red,unsigned int green,unsigned int blue,unsigned int)2217         void FillRGBAValue(unsigned int red, unsigned int green, unsigned int blue, unsigned int)
2218         {
2219             FillRGBValue(red, green, blue);
2220         }
FillRGBTValue(float red,float green,float blue,float)2221         void FillRGBTValue(float red, float green, float blue, float)
2222         {
2223             FillRGBValue(red, green, blue);
2224         }
FillRGBFTValue(float red,float green,float blue,float,float)2225         void FillRGBFTValue(float red, float green, float blue, float, float)
2226         {
2227             FillRGBValue(red, green, blue);
2228         }
2229     private:
2230         vector<T, Allocator> pixels;
2231         GammaCurvePtr gamma;
2232         const float* gammaLUT;
2233 };
2234 
2235 typedef NonlinearGrayImage<unsigned char, 255, Image::Gray_Gamma8> MemoryNonlinearGray8Image;
2236 
2237 typedef NonlinearGrayImage<unsigned short, 65535, Image::Gray_Gamma16> MemoryNonlinearGray16Image;
2238 
2239 template<typename T, unsigned int TMAX, int IDT, class Allocator = allocator<T> >
2240 class NonlinearGrayAImage : public Image
2241 {
2242     public:
NonlinearGrayAImage(unsigned int w,unsigned int h)2243         NonlinearGrayAImage(unsigned int w, unsigned int h) :
2244             Image(w, h, ImageDataType(IDT)), gamma(NeutralGammaCurve::Get()) { gammaLUT = gamma->GetLookupTable(TMAX); pixels.resize(SafeUnsignedProduct<size_t>(w, h, 2u)); FillBitValue(false); }
NonlinearGrayAImage(unsigned int w,unsigned int h,const vector<RGBMapEntry> & m)2245         NonlinearGrayAImage(unsigned int w, unsigned int h, const vector<RGBMapEntry>& m) :
2246             Image(w, h, ImageDataType(IDT), m), gamma(NeutralGammaCurve::Get()) { gammaLUT = gamma->GetLookupTable(TMAX); pixels.resize(SafeUnsignedProduct<size_t>(w, h, 2u)); FillBitValue(false); }
NonlinearGrayAImage(unsigned int w,unsigned int h,const vector<RGBAMapEntry> & m)2247         NonlinearGrayAImage(unsigned int w, unsigned int h, const vector<RGBAMapEntry>& m) :
2248             Image(w, h, ImageDataType(IDT), m), gamma(NeutralGammaCurve::Get()) { gammaLUT = gamma->GetLookupTable(TMAX); pixels.resize(SafeUnsignedProduct<size_t>(w, h, 2u)); FillBitValue(false); }
NonlinearGrayAImage(unsigned int w,unsigned int h,const vector<RGBFTMapEntry> & m)2249         NonlinearGrayAImage(unsigned int w, unsigned int h, const vector<RGBFTMapEntry>& m) :
2250             Image(w, h, ImageDataType(IDT), m), gamma(NeutralGammaCurve::Get()) { gammaLUT = gamma->GetLookupTable(TMAX); pixels.resize(SafeUnsignedProduct<size_t>(w, h, 2u)); FillBitValue(false); }
~NonlinearGrayAImage()2251         ~NonlinearGrayAImage() { }
2252 
IsOpaque() const2253         bool IsOpaque() const
2254         {
2255             for(typename vector<T, Allocator>::const_iterator i(pixels.begin()); i != pixels.end(); i += 2)
2256             {
2257                 if(i[1] < TMAX)
2258                     return false;
2259             }
2260 
2261             return true;
2262         }
IsGrayscale() const2263         bool IsGrayscale() const
2264         {
2265             return true;
2266         }
IsColour() const2267         bool IsColour() const
2268         {
2269             return false;
2270         }
IsFloat() const2271         bool IsFloat() const
2272         {
2273             return false;
2274         }
IsInt() const2275         bool IsInt() const
2276         {
2277             return true;
2278         }
IsIndexed() const2279         bool IsIndexed() const
2280         {
2281             return false;
2282         }
IsGammaEncoded() const2283         bool IsGammaEncoded() const
2284         {
2285             return true;
2286         }
HasAlphaChannel() const2287         bool HasAlphaChannel() const
2288         {
2289             return true;
2290         }
HasFilterTransmit() const2291         bool HasFilterTransmit() const
2292         {
2293             return false;
2294         }
GetMaxIntValue() const2295         unsigned int GetMaxIntValue() const
2296         {
2297             return TMAX;
2298         }
TryDeferDecoding(GammaCurvePtr & g,unsigned int max)2299         bool TryDeferDecoding(GammaCurvePtr& g, unsigned int max)
2300         {
2301             if (max != TMAX) return false;
2302             if (!GammaCurve::IsNeutral(gamma)) return !g;
2303             gamma.swap(g);
2304             gammaLUT = gamma->GetLookupTable(TMAX);
2305             return true;
2306         }
2307 
GetBitValue(unsigned int x,unsigned int y) const2308         bool GetBitValue(unsigned int x, unsigned int y) const
2309         {
2310             // TODO FIXME - [CLi] This ignores opacity information; other bit-based code doesn't.
2311             CHECK_BOUNDS(x, y);
2312             return (pixels[(x + y * size_t(width)) * 2] != 0);
2313         }
GetGrayValue(unsigned int x,unsigned int y) const2314         float GetGrayValue(unsigned int x, unsigned int y) const
2315         {
2316             CHECK_BOUNDS(x, y);
2317             return gammaLUT[pixels[(x + y * size_t(width)) * 2]];
2318         }
GetGrayAValue(unsigned int x,unsigned int y,float & gray,float & alpha) const2319         void GetGrayAValue(unsigned int x, unsigned int y, float& gray, float& alpha) const
2320         {
2321             CHECK_BOUNDS(x, y);
2322             gray  = gammaLUT[pixels[(x + y * size_t(width)) * 2]];
2323             alpha =          pixels[(x + y * size_t(width)) * 2 + 1] / float(TMAX);
2324         }
GetRGBValue(unsigned int x,unsigned int y,float & red,float & green,float & blue) const2325         void GetRGBValue(unsigned int x, unsigned int y, float& red, float& green, float& blue) const
2326         {
2327             red = green = blue = GetGrayValue(x, y);
2328         }
GetRGBAValue(unsigned int x,unsigned int y,float & red,float & green,float & blue,float & alpha) const2329         void GetRGBAValue(unsigned int x, unsigned int y, float& red, float& green, float& blue, float& alpha) const
2330         {
2331             GetGrayAValue(x, y, red, alpha);
2332             green = blue = red;
2333         }
GetRGBTValue(unsigned int x,unsigned int y,float & red,float & green,float & blue,float & transm) const2334         void GetRGBTValue(unsigned int x, unsigned int y, float& red, float& green, float& blue, float& transm) const
2335         {
2336             float alpha;
2337             GetGrayAValue(x, y, red, alpha);
2338             green = blue = red;
2339             transm = 1.0 - alpha;
2340         }
GetRGBFTValue(unsigned int x,unsigned int y,float & red,float & green,float & blue,float & filter,float & transm) const2341         void GetRGBFTValue(unsigned int x, unsigned int y, float& red, float& green, float& blue, float& filter, float& transm) const
2342         {
2343             float alpha;
2344             GetGrayAValue(x, y, red, alpha);
2345             green = blue = red;
2346             RGBFTColour::AtoFT(alpha, filter, transm);
2347         }
2348 
SetBitValue(unsigned int x,unsigned int y,bool bit)2349         void SetBitValue(unsigned int x, unsigned int y, bool bit)
2350         {
2351             if(bit == true)
2352                 SetGrayAValue(x, y, TMAX, ALPHA_OPAQUE_INT(TMAX));
2353             else
2354                 SetGrayAValue(x, y, (unsigned int)0, ALPHA_OPAQUE_INT(TMAX));
2355         }
SetGrayValue(unsigned int x,unsigned int y,float gray)2356         void SetGrayValue(unsigned int x, unsigned int y, float gray)
2357         {
2358             SetGrayAValue(x, y, gray, ALPHA_OPAQUE);
2359         }
SetGrayValue(unsigned int x,unsigned int y,unsigned int gray)2360         void SetGrayValue(unsigned int x, unsigned int y, unsigned int gray)
2361         {
2362             SetGrayAValue(x, y, gray, ALPHA_OPAQUE_INT(TMAX));
2363         }
SetGrayAValue(unsigned int x,unsigned int y,float gray,float alpha)2364         void SetGrayAValue(unsigned int x, unsigned int y, float gray, float alpha)
2365         {
2366             CHECK_BOUNDS(x, y);
2367             pixels[(x + y * size_t(width)) * 2]     = IntEncode(gamma, gray, TMAX);
2368             pixels[(x + y * size_t(width)) * 2 + 1] = T(alpha * float(TMAX));
2369         }
SetGrayAValue(unsigned int x,unsigned int y,unsigned int gray,unsigned int alpha)2370         void SetGrayAValue(unsigned int x, unsigned int y, unsigned int gray, unsigned int alpha)
2371         {
2372             CHECK_BOUNDS(x, y);
2373             pixels[(x + y * size_t(width)) * 2]     = gray;
2374             pixels[(x + y * size_t(width)) * 2 + 1] = alpha;
2375         }
SetRGBValue(unsigned int x,unsigned int y,float red,float green,float blue)2376         void SetRGBValue(unsigned int x, unsigned int y, float red, float green, float blue)
2377         {
2378             SetGrayValue(x, y, RGB2Gray(red, green, blue));
2379         }
SetRGBValue(unsigned int x,unsigned int y,unsigned int red,unsigned int green,unsigned int blue)2380         void SetRGBValue(unsigned int x, unsigned int y, unsigned int red, unsigned int green, unsigned int blue)
2381         {
2382             // not really pretty here, but we're doing color math, so we need to decode and re-encode
2383             SetGrayValue(x, y, RGB2Gray(gammaLUT[red], gammaLUT[green], gammaLUT[blue]));
2384         }
SetRGBAValue(unsigned int x,unsigned int y,float red,float green,float blue,float alpha)2385         void SetRGBAValue(unsigned int x, unsigned int y, float red, float green, float blue, float alpha)
2386         {
2387             SetGrayAValue(x, y, RGB2Gray(red, green, blue), alpha);
2388         }
SetRGBAValue(unsigned int x,unsigned int y,unsigned int red,unsigned int green,unsigned int blue,unsigned int alpha)2389         void SetRGBAValue(unsigned int x, unsigned int y, unsigned int red, unsigned int green, unsigned int blue, unsigned int alpha)
2390         {
2391             // not really pretty here, but we're doing color math, so we need to decode and re-encode
2392             // TODO FIXME - this unnecessarily converts alpha from int to float, requiring it to be converted back to int
2393             SetGrayAValue(x, y, RGB2Gray(gammaLUT[red], gammaLUT[green], gammaLUT[blue]), float(alpha) / float(TMAX));
2394         }
SetRGBTValue(unsigned int x,unsigned int y,float red,float green,float blue,float transm)2395         void SetRGBTValue(unsigned int x, unsigned int y, float red, float green, float blue, float transm)
2396         {
2397             SetGrayAValue(x, y, RGB2Gray(red, green, blue), 1.0 - transm);
2398         }
SetRGBTValue(unsigned int x,unsigned int y,const RGBTColour & col)2399         void SetRGBTValue(unsigned int x, unsigned int y, const RGBTColour& col)
2400         {
2401             SetGrayAValue(x, y, RGB2Gray(col.red(), col.green(), col.blue()), col.alpha());
2402         }
SetRGBFTValue(unsigned int x,unsigned int y,float red,float green,float blue,float filter,float transm)2403         void SetRGBFTValue(unsigned int x, unsigned int y, float red, float green, float blue, float filter, float transm)
2404         {
2405             SetGrayAValue(x, y, RGB2Gray(red, green, blue), RGBFTColour::FTtoA(filter, transm));
2406         }
SetRGBFTValue(unsigned int x,unsigned int y,const RGBFTColour & col)2407         void SetRGBFTValue(unsigned int x, unsigned int y, const RGBFTColour& col)
2408         {
2409             SetGrayAValue(x, y, RGB2Gray(col.red(), col.green(), col.blue()), col.FTtoA());
2410         }
2411 
FillBitValue(bool bit)2412         void FillBitValue(bool bit)
2413         {
2414             if(bit == true)
2415                 FillGrayValue(TMAX);
2416             else
2417                 FillGrayValue((unsigned int)0);
2418         }
FillGrayValue(float gray)2419         void FillGrayValue(float gray)
2420         {
2421             FillGrayValue(IntEncode(gamma, gray, TMAX));
2422         }
FillGrayValue(unsigned int gray)2423         void FillGrayValue(unsigned int gray)
2424         {
2425             FillGrayAValue(gray, ALPHA_OPAQUE_INT(TMAX));
2426         }
FillGrayAValue(float gray,float alpha)2427         void FillGrayAValue(float gray, float alpha)
2428         {
2429             // [CLi 2009-09] this was dividing by float(TMAX) - which I presume to have been a bug.
2430             T g(IntEncode(gamma, gray, TMAX)), a(IntEncode(alpha, TMAX));
2431             for(typename vector<T, Allocator>::iterator i(pixels.begin()); i != pixels.end(); i++)
2432             {
2433                 *i = g;
2434                 i++;
2435                 *i = a;
2436             }
2437         }
FillGrayAValue(unsigned int gray,unsigned int alpha)2438         void FillGrayAValue(unsigned int gray, unsigned int alpha)
2439         {
2440             for(typename vector<T, Allocator>::iterator i(pixels.begin()); i != pixels.end(); i++)
2441             {
2442                 *i = T(gray);
2443                 i++;
2444                 *i = T(alpha);
2445             }
2446         }
FillRGBValue(float red,float green,float blue)2447         void FillRGBValue(float red, float green, float blue)
2448         {
2449             FillGrayValue(RGB2Gray(red, green, blue));
2450         }
FillRGBValue(unsigned int red,unsigned int green,unsigned int blue)2451         void FillRGBValue(unsigned int red, unsigned int green, unsigned int blue)
2452         {
2453             // not really pretty here, but we're doing color math, so we need to decode and re-encode
2454             FillGrayValue(RGB2Gray(gammaLUT[red], gammaLUT[green], gammaLUT[blue]));
2455         }
FillRGBAValue(float red,float green,float blue,float alpha)2456         void FillRGBAValue(float red, float green, float blue, float alpha)
2457         {
2458             FillGrayAValue(RGB2Gray(red, green, blue), alpha);
2459         }
FillRGBAValue(unsigned int red,unsigned int green,unsigned int blue,unsigned int alpha)2460         void FillRGBAValue(unsigned int red, unsigned int green, unsigned int blue, unsigned int alpha)
2461         {
2462             // not really pretty here, but we're doing color math, so we need to decode and re-encode
2463             // TODO FIXME - this unnecessarily converts alpha from int to float, requiring it to be converted back to int
2464             FillGrayAValue(RGB2Gray(gammaLUT[red], gammaLUT[green], gammaLUT[blue]), float(alpha) / float(TMAX));
2465         }
FillRGBTValue(float red,float green,float blue,float transm)2466         void FillRGBTValue(float red, float green, float blue, float transm)
2467         {
2468             FillGrayAValue(RGB2Gray(red, green, blue), 1.0 - transm);
2469         }
FillRGBFTValue(float red,float green,float blue,float filter,float transm)2470         void FillRGBFTValue(float red, float green, float blue, float filter, float transm)
2471         {
2472             FillGrayAValue(RGB2Gray(red, green, blue), RGBFTColour::FTtoA(filter, transm));
2473         }
2474     private:
2475         vector<T, Allocator> pixels;
2476         GammaCurvePtr gamma;
2477         const float* gammaLUT;
2478 };
2479 
2480 typedef NonlinearGrayAImage<unsigned char, 255, Image::GrayA_Gamma8> MemoryNonlinearGrayA8Image;
2481 
2482 typedef NonlinearGrayAImage<unsigned short, 65535, Image::GrayA_Gamma16> MemoryNonlinearGrayA16Image;
2483 
2484 template<typename T, unsigned int TMAX, int IDT, class Allocator = allocator<T> >
2485 class NonlinearRGBImage : public Image
2486 {
2487     public:
NonlinearRGBImage(unsigned int w,unsigned int h)2488         NonlinearRGBImage(unsigned int w, unsigned int h) :
2489             Image(w, h, ImageDataType(IDT)), gamma(NeutralGammaCurve::Get()) { gammaLUT = gamma->GetLookupTable(TMAX); pixels.resize(SafeUnsignedProduct<size_t>(w, h, 3u)); FillBitValue(false); }
NonlinearRGBImage(unsigned int w,unsigned int h,const vector<RGBMapEntry> & m)2490         NonlinearRGBImage(unsigned int w, unsigned int h, const vector<RGBMapEntry>& m) :
2491             Image(w, h, ImageDataType(IDT), m), gamma(NeutralGammaCurve::Get()) { gammaLUT = gamma->GetLookupTable(TMAX); pixels.resize(SafeUnsignedProduct<size_t>(w, h, 3u)); FillBitValue(false); }
NonlinearRGBImage(unsigned int w,unsigned int h,const vector<RGBAMapEntry> & m)2492         NonlinearRGBImage(unsigned int w, unsigned int h, const vector<RGBAMapEntry>& m) :
2493             Image(w, h, ImageDataType(IDT), m), gamma(NeutralGammaCurve::Get()) { gammaLUT = gamma->GetLookupTable(TMAX); pixels.resize(SafeUnsignedProduct<size_t>(w, h, 3u)); FillBitValue(false); }
NonlinearRGBImage(unsigned int w,unsigned int h,const vector<RGBFTMapEntry> & m)2494         NonlinearRGBImage(unsigned int w, unsigned int h, const vector<RGBFTMapEntry>& m) :
2495             Image(w, h, ImageDataType(IDT), m), gamma(NeutralGammaCurve::Get()) { gammaLUT = gamma->GetLookupTable(TMAX); pixels.resize(SafeUnsignedProduct<size_t>(w, h, 3u)); FillBitValue(false); }
~NonlinearRGBImage()2496         ~NonlinearRGBImage() { }
2497 
IsOpaque() const2498         bool IsOpaque() const
2499         {
2500             return true;
2501         }
IsGrayscale() const2502         bool IsGrayscale() const
2503         {
2504             return false;
2505         }
IsColour() const2506         bool IsColour() const
2507         {
2508             return true;
2509         }
IsFloat() const2510         bool IsFloat() const
2511         {
2512             return false;
2513         }
IsInt() const2514         bool IsInt() const
2515         {
2516             return true;
2517         }
IsIndexed() const2518         bool IsIndexed() const
2519         {
2520             return false;
2521         }
IsGammaEncoded() const2522         bool IsGammaEncoded() const
2523         {
2524             return true;
2525         }
HasAlphaChannel() const2526         bool HasAlphaChannel() const
2527         {
2528             return false;
2529         }
HasFilterTransmit() const2530         bool HasFilterTransmit() const
2531         {
2532             return false;
2533         }
GetMaxIntValue() const2534         unsigned int GetMaxIntValue() const
2535         {
2536             return TMAX;
2537         }
TryDeferDecoding(GammaCurvePtr & g,unsigned int max)2538         bool TryDeferDecoding(GammaCurvePtr& g, unsigned int max)
2539         {
2540             if (max != TMAX) return false;
2541             if (!GammaCurve::IsNeutral(gamma)) return !g;
2542             gamma.swap(g);
2543             gammaLUT = gamma->GetLookupTable(TMAX);
2544             return true;
2545         }
2546 
GetBitValue(unsigned int x,unsigned int y) const2547         bool GetBitValue(unsigned int x, unsigned int y) const
2548         {
2549             float red, green, blue;
2550             GetRGBValue(x, y, red, green, blue);
2551             return IS_NONZERO_RGB(red, green, blue);
2552         }
GetGrayValue(unsigned int x,unsigned int y) const2553         float GetGrayValue(unsigned int x, unsigned int y) const
2554         {
2555             float red, green, blue;
2556             GetRGBValue(x, y, red, green, blue);
2557             return RGB2Gray(red, green, blue);
2558         }
GetGrayAValue(unsigned int x,unsigned int y,float & gray,float & alpha) const2559         void GetGrayAValue(unsigned int x, unsigned int y, float& gray, float& alpha) const
2560         {
2561             gray = GetGrayValue(x, y);
2562             alpha = ALPHA_OPAQUE;
2563         }
GetRGBValue(unsigned int x,unsigned int y,float & red,float & green,float & blue) const2564         void GetRGBValue(unsigned int x, unsigned int y, float& red, float& green, float& blue) const
2565         {
2566             CHECK_BOUNDS(x, y);
2567             red   = gammaLUT[pixels[(x + y * size_t(width)) * 3]];
2568             green = gammaLUT[pixels[(x + y * size_t(width)) * 3 + 1]];
2569             blue  = gammaLUT[pixels[(x + y * size_t(width)) * 3 + 2]];
2570         }
GetRGBAValue(unsigned int x,unsigned int y,float & red,float & green,float & blue,float & alpha) const2571         void GetRGBAValue(unsigned int x, unsigned int y, float& red, float& green, float& blue, float& alpha) const
2572         {
2573             GetRGBValue(x, y, red, green, blue);
2574             alpha = ALPHA_OPAQUE;
2575         }
GetRGBTValue(unsigned int x,unsigned int y,float & red,float & green,float & blue,float & transm) const2576         void GetRGBTValue(unsigned int x, unsigned int y, float& red, float& green, float& blue, float& transm) const
2577         {
2578             GetRGBValue(x, y, red, green, blue);
2579             transm = FT_OPAQUE;
2580         }
GetRGBFTValue(unsigned int x,unsigned int y,float & red,float & green,float & blue,float & filter,float & transm) const2581         void GetRGBFTValue(unsigned int x, unsigned int y, float& red, float& green, float& blue, float& filter, float& transm) const
2582         {
2583             GetRGBValue(x, y, red, green, blue);
2584             filter = transm = FT_OPAQUE;
2585         }
2586 
SetBitValue(unsigned int x,unsigned int y,bool bit)2587         void SetBitValue(unsigned int x, unsigned int y, bool bit)
2588         {
2589             if(bit == true)
2590                 SetGrayValue(x, y, TMAX);
2591             else
2592                 SetGrayValue(x, y, (unsigned int)0);
2593         }
SetGrayValue(unsigned int x,unsigned int y,float gray)2594         void SetGrayValue(unsigned int x, unsigned int y, float gray)
2595         {
2596             SetRGBValue(x, y, gray, gray, gray);
2597         }
SetGrayValue(unsigned int x,unsigned int y,unsigned int gray)2598         void SetGrayValue(unsigned int x, unsigned int y, unsigned int gray)
2599         {
2600             CHECK_BOUNDS(x, y);
2601             pixels[x + y * size_t(width) * 3]     =
2602             pixels[x + y * size_t(width) * 3 + 1] =
2603             pixels[x + y * size_t(width) * 3 + 2] = gray;
2604         }
SetGrayAValue(unsigned int x,unsigned int y,float gray,float)2605         void SetGrayAValue(unsigned int x, unsigned int y, float gray, float)
2606         {
2607             CHECK_BOUNDS(x, y);
2608             pixels[x + y * size_t(width) * 3]     =
2609             pixels[x + y * size_t(width) * 3 + 1] =
2610             pixels[x + y * size_t(width) * 3 + 2] = IntEncode(gamma, gray, TMAX);
2611         }
SetGrayAValue(unsigned int x,unsigned int y,unsigned int gray,unsigned int)2612         void SetGrayAValue(unsigned int x, unsigned int y, unsigned int gray, unsigned int)
2613         {
2614             CHECK_BOUNDS(x, y);
2615             pixels[x + y * size_t(width) * 3]     =
2616             pixels[x + y * size_t(width) * 3 + 1] =
2617             pixels[x + y * size_t(width) * 3 + 2] = gray;
2618         }
SetRGBValue(unsigned int x,unsigned int y,float red,float green,float blue)2619         void SetRGBValue(unsigned int x, unsigned int y, float red, float green, float blue)
2620         {
2621             CHECK_BOUNDS(x, y);
2622             pixels[(x + y * size_t(width)) * 3]     = IntEncode(gamma, red,   TMAX);
2623             pixels[(x + y * size_t(width)) * 3 + 1] = IntEncode(gamma, green, TMAX);
2624             pixels[(x + y * size_t(width)) * 3 + 2] = IntEncode(gamma, blue,  TMAX);
2625         }
SetRGBValue(unsigned int x,unsigned int y,unsigned int red,unsigned int green,unsigned int blue)2626         void SetRGBValue(unsigned int x, unsigned int y, unsigned int red, unsigned int green, unsigned int blue)
2627         {
2628             CHECK_BOUNDS(x, y);
2629             pixels[(x + y * size_t(width)) * 3]     = T(red);
2630             pixels[(x + y * size_t(width)) * 3 + 1] = T(green);
2631             pixels[(x + y * size_t(width)) * 3 + 2] = T(blue);
2632         }
SetRGBAValue(unsigned int x,unsigned int y,float red,float green,float blue,float)2633         void SetRGBAValue(unsigned int x, unsigned int y, float red, float green, float blue, float)
2634         {
2635             SetRGBValue(x, y, red, green, blue);
2636         }
SetRGBAValue(unsigned int x,unsigned int y,unsigned int red,unsigned int green,unsigned int blue,unsigned int)2637         void SetRGBAValue(unsigned int x, unsigned int y, unsigned int red, unsigned int green, unsigned int blue, unsigned int)
2638         {
2639             SetRGBValue(x, y, red, green, blue);
2640         }
SetRGBTValue(unsigned int x,unsigned int y,float red,float green,float blue,float transm)2641         void SetRGBTValue(unsigned int x, unsigned int y, float red, float green, float blue, float transm)
2642         {
2643             SetRGBValue(x, y, red, green, blue);
2644         }
SetRGBTValue(unsigned int x,unsigned int y,const RGBTColour & col)2645         void SetRGBTValue(unsigned int x, unsigned int y, const RGBTColour& col)
2646         {
2647             SetRGBValue(x, y, col.red(), col.green(), col.blue());
2648         }
SetRGBFTValue(unsigned int x,unsigned int y,float red,float green,float blue,float,float)2649         void SetRGBFTValue(unsigned int x, unsigned int y, float red, float green, float blue, float, float)
2650         {
2651             SetRGBValue(x, y, red, green, blue);
2652         }
SetRGBFTValue(unsigned int x,unsigned int y,const RGBFTColour & col)2653         void SetRGBFTValue(unsigned int x, unsigned int y, const RGBFTColour& col)
2654         {
2655             SetRGBValue(x, y, col.red(), col.green(), col.blue());
2656         }
2657 
FillBitValue(bool bit)2658         void FillBitValue(bool bit)
2659         {
2660             if(bit == true)
2661                 FillGrayValue(TMAX);
2662             else
2663                 FillGrayValue((unsigned int)0);
2664         }
FillGrayValue(float gray)2665         void FillGrayValue(float gray)
2666         {
2667             FillGrayValue((unsigned int)(IntEncode(gamma, gray, TMAX)));
2668         }
FillGrayValue(unsigned int gray)2669         void FillGrayValue(unsigned int gray)
2670         {
2671             fill(pixels.begin(), pixels.end(), gray);
2672         }
FillGrayAValue(float gray,float)2673         void FillGrayAValue(float gray, float)
2674         {
2675             FillRGBValue(gray, gray, gray);
2676         }
FillGrayAValue(unsigned int gray,unsigned int)2677         void FillGrayAValue(unsigned int gray, unsigned int)
2678         {
2679             FillRGBValue(gray, gray, gray);
2680         }
FillRGBValue(float red,float green,float blue)2681         void FillRGBValue(float red, float green, float blue)
2682         {
2683             // [CLi 2009-09] this was dividing by float(TMAX) - which I presume to have been a bug.
2684             T r(IntEncode(gamma, red, TMAX)), g(IntEncode(gamma, green, TMAX)), b(IntEncode(gamma, blue, TMAX));
2685             for(typename vector<T, Allocator>::iterator i(pixels.begin()); i != pixels.end(); i++)
2686             {
2687                 *i = r;
2688                 i++;
2689                 *i = g;
2690                 i++;
2691                 *i = b;
2692             }
2693         }
FillRGBValue(unsigned int red,unsigned int green,unsigned int blue)2694         void FillRGBValue(unsigned int red, unsigned int green, unsigned int blue)
2695         {
2696             for(typename vector<T, Allocator>::iterator i(pixels.begin()); i != pixels.end(); i++)
2697             {
2698                 *i = T(red);
2699                 i++;
2700                 *i = T(green);
2701                 i++;
2702                 *i = T(blue);
2703             }
2704         }
FillRGBAValue(float red,float green,float blue,float)2705         void FillRGBAValue(float red, float green, float blue, float)
2706         {
2707             FillRGBValue(red, green, blue);
2708         }
FillRGBAValue(unsigned int red,unsigned int green,unsigned int blue,unsigned int)2709         void FillRGBAValue(unsigned int red, unsigned int green, unsigned int blue, unsigned int)
2710         {
2711             FillRGBValue(red, green, blue);
2712         }
FillRGBTValue(float red,float green,float blue,float)2713         void FillRGBTValue(float red, float green, float blue, float)
2714         {
2715             FillRGBValue(red, green, blue);
2716         }
FillRGBFTValue(float red,float green,float blue,float,float)2717         void FillRGBFTValue(float red, float green, float blue, float, float)
2718         {
2719             FillRGBValue(red, green, blue);
2720         }
2721     private:
2722         vector<T, Allocator> pixels;
2723         GammaCurvePtr gamma;
2724         const float* gammaLUT;
2725 };
2726 
2727 typedef NonlinearRGBImage<unsigned char, 255, Image::RGB_Gamma8> MemoryNonlinearRGB8Image;
2728 
2729 typedef NonlinearRGBImage<unsigned short, 65535, Image::RGB_Gamma16> MemoryNonlinearRGB16Image;
2730 
2731 template<typename T, unsigned int TMAX, int IDT, class Allocator = allocator<T> >
2732 class NonlinearRGBAImage : public Image
2733 {
2734     public:
NonlinearRGBAImage(unsigned int w,unsigned int h)2735         NonlinearRGBAImage(unsigned int w, unsigned int h) :
2736             Image(w, h, ImageDataType(IDT)), gamma(NeutralGammaCurve::Get()) { gammaLUT = gamma->GetLookupTable(TMAX); pixels.resize(SafeUnsignedProduct<size_t>(w, h, 4u)); FillBitValue(false); }
NonlinearRGBAImage(unsigned int w,unsigned int h,const vector<RGBMapEntry> & m)2737         NonlinearRGBAImage(unsigned int w, unsigned int h, const vector<RGBMapEntry>& m) :
2738             Image(w, h, ImageDataType(IDT), m), gamma(NeutralGammaCurve::Get()) { gammaLUT = gamma->GetLookupTable(TMAX); pixels.resize(SafeUnsignedProduct<size_t>(w, h, 4u)); FillBitValue(false); }
NonlinearRGBAImage(unsigned int w,unsigned int h,const vector<RGBAMapEntry> & m)2739         NonlinearRGBAImage(unsigned int w, unsigned int h, const vector<RGBAMapEntry>& m) :
2740             Image(w, h, ImageDataType(IDT), m), gamma(NeutralGammaCurve::Get()) { gammaLUT = gamma->GetLookupTable(TMAX); pixels.resize(SafeUnsignedProduct<size_t>(w, h, 4u)); FillBitValue(false); }
NonlinearRGBAImage(unsigned int w,unsigned int h,const vector<RGBFTMapEntry> & m)2741         NonlinearRGBAImage(unsigned int w, unsigned int h, const vector<RGBFTMapEntry>& m) :
2742             Image(w, h, ImageDataType(IDT), m), gamma(NeutralGammaCurve::Get()) { gammaLUT = gamma->GetLookupTable(TMAX); pixels.resize(SafeUnsignedProduct<size_t>(w, h, 4u)); FillBitValue(false); }
~NonlinearRGBAImage()2743         ~NonlinearRGBAImage() { }
2744 
IsOpaque() const2745         bool IsOpaque() const
2746         {
2747             for(typename vector<T, Allocator>::const_iterator i(pixels.begin()); i != pixels.end(); i += 4)
2748             {
2749                 if(i[3] < TMAX)
2750                     return false;
2751             }
2752 
2753             return true;
2754         }
IsGrayscale() const2755         bool IsGrayscale() const
2756         {
2757             return false;
2758         }
IsColour() const2759         bool IsColour() const
2760         {
2761             return true;
2762         }
IsFloat() const2763         bool IsFloat() const
2764         {
2765             return false;
2766         }
IsInt() const2767         bool IsInt() const
2768         {
2769             return true;
2770         }
IsIndexed() const2771         bool IsIndexed() const
2772         {
2773             return false;
2774         }
IsGammaEncoded() const2775         bool IsGammaEncoded() const
2776         {
2777             return true;
2778         }
HasAlphaChannel() const2779         bool HasAlphaChannel() const
2780         {
2781             return true;
2782         }
HasFilterTransmit() const2783         bool HasFilterTransmit() const
2784         {
2785             return false;
2786         }
GetMaxIntValue() const2787         unsigned int GetMaxIntValue() const
2788         {
2789             return TMAX;
2790         }
TryDeferDecoding(GammaCurvePtr & g,unsigned int max)2791         bool TryDeferDecoding(GammaCurvePtr& g, unsigned int max)
2792         {
2793             if (max != TMAX) return false;
2794             if (!GammaCurve::IsNeutral(gamma)) return !g;
2795             gamma.swap(g);
2796             gammaLUT = gamma->GetLookupTable(TMAX);
2797             return true;
2798         }
2799 
GetBitValue(unsigned int x,unsigned int y) const2800         bool GetBitValue(unsigned int x, unsigned int y) const
2801         {
2802             // TODO FIXME - [CLi] This ignores opacity information; other bit-based code doesn't.
2803             float red, green, blue, alpha;
2804             GetRGBAValue(x, y, red, green, blue, alpha);
2805             return IS_NONZERO_RGB(red, green, blue);
2806         }
GetGrayValue(unsigned int x,unsigned int y) const2807         float GetGrayValue(unsigned int x, unsigned int y) const
2808         {
2809             float red, green, blue, alpha;
2810             GetRGBAValue(x, y, red, green, blue, alpha);
2811             return RGB2Gray(red, green, blue);
2812         }
GetGrayAValue(unsigned int x,unsigned int y,float & gray,float & alpha) const2813         void GetGrayAValue(unsigned int x, unsigned int y, float& gray, float& alpha) const
2814         {
2815             float red, green, blue;
2816             GetRGBAValue(x, y, red, green, blue, alpha);
2817             gray = RGB2Gray(red, green, blue);
2818         }
GetRGBValue(unsigned int x,unsigned int y,float & red,float & green,float & blue) const2819         void GetRGBValue(unsigned int x, unsigned int y, float& red, float& green, float& blue) const
2820         {
2821             float alpha;
2822             GetRGBAValue(x, y, red, green, blue, alpha);
2823         }
GetRGBAValue(unsigned int x,unsigned int y,float & red,float & green,float & blue,float & alpha) const2824         void GetRGBAValue(unsigned int x, unsigned int y, float& red, float& green, float& blue, float& alpha) const
2825         {
2826             CHECK_BOUNDS(x, y);
2827             red   = gammaLUT[pixels[(x + y * size_t(width)) * 4]];
2828             green = gammaLUT[pixels[(x + y * size_t(width)) * 4 + 1]];
2829             blue  = gammaLUT[pixels[(x + y * size_t(width)) * 4 + 2]];
2830             alpha =    float(pixels[(x + y * size_t(width)) * 4 + 3]) / float(TMAX);
2831         }
GetRGBTValue(unsigned int x,unsigned int y,float & red,float & green,float & blue,float & transm) const2832         void GetRGBTValue(unsigned int x, unsigned int y, float& red, float& green, float& blue, float& transm) const
2833         {
2834             float alpha;
2835             GetRGBAValue(x, y, red, green, blue, alpha);
2836             transm = 1.0 - alpha;
2837         }
GetRGBFTValue(unsigned int x,unsigned int y,float & red,float & green,float & blue,float & filter,float & transm) const2838         void GetRGBFTValue(unsigned int x, unsigned int y, float& red, float& green, float& blue, float& filter, float& transm) const
2839         {
2840             float alpha;
2841             GetRGBAValue(x, y, red, green, blue, alpha);
2842             RGBFTColour::AtoFT(alpha, filter, transm);
2843         }
2844 
SetBitValue(unsigned int x,unsigned int y,bool bit)2845         void SetBitValue(unsigned int x, unsigned int y, bool bit)
2846         {
2847             if(bit == true)
2848                 SetGrayValue(x, y, TMAX);
2849             else
2850                 SetGrayValue(x, y, (unsigned int)0);
2851         }
SetGrayValue(unsigned int x,unsigned int y,float gray)2852         void SetGrayValue(unsigned int x, unsigned int y, float gray)
2853         {
2854             SetRGBAValue(x, y, gray, gray, gray, ALPHA_OPAQUE);
2855         }
SetGrayValue(unsigned int x,unsigned int y,unsigned int gray)2856         void SetGrayValue(unsigned int x, unsigned int y, unsigned int gray)
2857         {
2858             SetRGBAValue(x, y, gray, gray, gray, ALPHA_OPAQUE_INT(TMAX));
2859         }
SetGrayAValue(unsigned int x,unsigned int y,float gray,float alpha)2860         void SetGrayAValue(unsigned int x, unsigned int y, float gray, float alpha)
2861         {
2862             SetRGBAValue(x, y, gray, gray, gray, alpha);
2863         }
SetGrayAValue(unsigned int x,unsigned int y,unsigned int gray,unsigned int alpha)2864         void SetGrayAValue(unsigned int x, unsigned int y, unsigned int gray, unsigned int alpha)
2865         {
2866             SetRGBAValue(x, y, gray, gray, gray, alpha);
2867         }
SetRGBValue(unsigned int x,unsigned int y,float red,float green,float blue)2868         void SetRGBValue(unsigned int x, unsigned int y, float red, float green, float blue)
2869         {
2870             SetRGBAValue(x, y, red, green, blue, ALPHA_OPAQUE);
2871         }
SetRGBValue(unsigned int x,unsigned int y,unsigned int red,unsigned int green,unsigned int blue)2872         void SetRGBValue(unsigned int x, unsigned int y, unsigned int red, unsigned int green, unsigned int blue)
2873         {
2874             SetRGBAValue(x, y, red, green, blue, ALPHA_OPAQUE_INT(TMAX));
2875         }
SetRGBAValue(unsigned int x,unsigned int y,float red,float green,float blue,float alpha)2876         void SetRGBAValue(unsigned int x, unsigned int y, float red, float green, float blue, float alpha)
2877         {
2878             CHECK_BOUNDS(x, y);
2879             pixels[(x + y * size_t(width)) * 4]     = T(IntEncode(gamma, red,   TMAX));
2880             pixels[(x + y * size_t(width)) * 4 + 1] = T(IntEncode(gamma, green, TMAX));
2881             pixels[(x + y * size_t(width)) * 4 + 2] = T(IntEncode(gamma, blue,  TMAX));
2882             pixels[(x + y * size_t(width)) * 4 + 3] = T(IntEncode(       alpha, TMAX));
2883         }
SetRGBAValue(unsigned int x,unsigned int y,unsigned int red,unsigned int green,unsigned int blue,unsigned int alpha)2884         void SetRGBAValue(unsigned int x, unsigned int y, unsigned int red, unsigned int green, unsigned int blue, unsigned int alpha)
2885         {
2886             CHECK_BOUNDS(x, y);
2887             pixels[(x + y * size_t(width)) * 4]     = T(red);
2888             pixels[(x + y * size_t(width)) * 4 + 1] = T(green);
2889             pixels[(x + y * size_t(width)) * 4 + 2] = T(blue);
2890             pixels[(x + y * size_t(width)) * 4 + 3] = T(alpha);
2891         }
SetRGBTValue(unsigned int x,unsigned int y,float red,float green,float blue,float transm)2892         void SetRGBTValue(unsigned int x, unsigned int y, float red, float green, float blue, float transm)
2893         {
2894             SetRGBAValue(x, y, red, green, blue, 1.0 - transm);
2895         }
SetRGBTValue(unsigned int x,unsigned int y,const RGBTColour & col)2896         void SetRGBTValue(unsigned int x, unsigned int y, const RGBTColour& col)
2897         {
2898             CHECK_BOUNDS(x, y);
2899             pixels[(x + y * size_t(width)) * 4]     = T(col.red());
2900             pixels[(x + y * size_t(width)) * 4 + 1] = T(col.green());
2901             pixels[(x + y * size_t(width)) * 4 + 2] = T(col.blue());
2902             pixels[(x + y * size_t(width)) * 4 + 3] = T(col.alpha());
2903         }
SetRGBFTValue(unsigned int x,unsigned int y,float red,float green,float blue,float filter,float transm)2904         void SetRGBFTValue(unsigned int x, unsigned int y, float red, float green, float blue, float filter, float transm)
2905         {
2906             SetRGBAValue(x, y, red, green, blue, RGBFTColour::FTtoA(filter, transm));
2907         }
SetRGBFTValue(unsigned int x,unsigned int y,const RGBFTColour & col)2908         void SetRGBFTValue(unsigned int x, unsigned int y, const RGBFTColour& col)
2909         {
2910             CHECK_BOUNDS(x, y);
2911             pixels[(x + y * size_t(width)) * 4]     = T(col.red());
2912             pixels[(x + y * size_t(width)) * 4 + 1] = T(col.green());
2913             pixels[(x + y * size_t(width)) * 4 + 2] = T(col.blue());
2914             pixels[(x + y * size_t(width)) * 4 + 3] = T(col.FTtoA());
2915         }
2916 
FillBitValue(bool bit)2917         void FillBitValue(bool bit)
2918         {
2919             if(bit == true)
2920                 FillGrayValue(TMAX);
2921             else
2922                 FillGrayValue((unsigned int)0);
2923         }
FillGrayValue(float gray)2924         void FillGrayValue(float gray)
2925         {
2926             FillRGBAValue(gray, gray, gray, ALPHA_OPAQUE);
2927         }
FillGrayValue(unsigned int gray)2928         void FillGrayValue(unsigned int gray)
2929         {
2930             FillRGBAValue(gray, gray, gray, ALPHA_OPAQUE_INT(TMAX));
2931         }
FillGrayAValue(float gray,float alpha)2932         void FillGrayAValue(float gray, float alpha)
2933         {
2934             FillRGBAValue(gray, gray, gray, alpha);
2935         }
FillGrayAValue(unsigned int gray,unsigned int alpha)2936         void FillGrayAValue(unsigned int gray, unsigned int alpha)
2937         {
2938             FillRGBAValue(gray, gray, gray, alpha);
2939         }
FillRGBValue(float red,float green,float blue)2940         void FillRGBValue(float red, float green, float blue)
2941         {
2942             FillRGBAValue(red, green, blue, ALPHA_OPAQUE);
2943         }
FillRGBValue(unsigned int red,unsigned int green,unsigned int blue)2944         void FillRGBValue(unsigned int red, unsigned int green, unsigned int blue)
2945         {
2946             FillRGBAValue(red, green, blue, ALPHA_OPAQUE_INT(TMAX));
2947         }
FillRGBAValue(float red,float green,float blue,float alpha)2948         void FillRGBAValue(float red, float green, float blue, float alpha)
2949         {
2950             // [CLi 2009-09] this was dividing by float(TMAX) - which I presume to have been a bug.
2951             T r(IntEncode(gamma, red, TMAX)), g(IntEncode(gamma, green, TMAX)), b(IntEncode(gamma, blue, TMAX)), a(IntEncode(alpha, TMAX));
2952             for(typename vector<T, Allocator>::iterator i(pixels.begin()); i != pixels.end(); i++)
2953             {
2954                 *i = r;
2955                 i++;
2956                 *i = g;
2957                 i++;
2958                 *i = b;
2959                 i++;
2960                 *i = a;
2961             }
2962         }
FillRGBAValue(unsigned int red,unsigned int green,unsigned int blue,unsigned int alpha)2963         void FillRGBAValue(unsigned int red, unsigned int green, unsigned int blue, unsigned int alpha)
2964         {
2965             for(typename vector<T, Allocator>::iterator i(pixels.begin()); i != pixels.end(); i++)
2966             {
2967                 *i = T(red);
2968                 i++;
2969                 *i = T(green);
2970                 i++;
2971                 *i = T(blue);
2972                 i++;
2973                 *i = T(alpha);
2974             }
2975         }
FillRGBTValue(float red,float green,float blue,float transm)2976         void FillRGBTValue(float red, float green, float blue, float transm)
2977         {
2978             FillRGBAValue(red, green, blue, 1.0 - transm);
2979         }
FillRGBFTValue(float red,float green,float blue,float filter,float transm)2980         void FillRGBFTValue(float red, float green, float blue, float filter, float transm)
2981         {
2982             FillRGBAValue(red, green, blue, RGBFTColour::FTtoA(filter, transm));
2983         }
2984     private:
2985         vector<T, Allocator> pixels;
2986         GammaCurvePtr gamma;
2987         const float* gammaLUT;
2988 };
2989 
2990 typedef NonlinearRGBAImage<unsigned char, 255, Image::RGBA_Gamma8> MemoryNonlinearRGBA8Image;
2991 
2992 typedef NonlinearRGBAImage<unsigned short, 65535, Image::RGBA_Gamma16> MemoryNonlinearRGBA16Image;
2993 
2994 // sample basic file-based pixel container. not very efficient.
2995 // it is expected that for performance reasons, platforms will provide their own specific
2996 // implementation of this; hence, this should be considered only a fall-back default.
2997 
2998 // [JG] That code is hostile to the system, as the file seek are just passed directly.
2999 // (and there is a lot, out of sequence!)
3000 // On the render (1st write), the cache will always miss, but as post-process might access more than once to
3001 // this container, it is mandatory to still read the file every time.
3002 // Measurement about the small read cache (compared to the alternative) show no significant delta in performance
3003 // to read the contained data into a PNG.
3004 // (it's a linear read, the system is able to anticipate it, so we are fine!)
3005 class FileBackedPixelContainer
3006 {
3007     public:
3008         typedef long size_type;
3009         enum
3010         {
3011             RED    = 0,
3012             GREEN  = 1,
3013             BLUE   = 2,
3014             FILTER = 3,
3015             TRANSM = 4
3016         };
3017         class pixel_type
3018         {
3019             public:
pixel_type()3020                 pixel_type()
3021                 {
3022                     elements[RED] = 0.0;
3023                     elements[GREEN] = 0.0;
3024                     elements[BLUE] = 0.0;
3025                     elements[FILTER] = 0.0;
3026                     elements[TRANSM] = 0.0;
3027                 }
pixel_type(const ColourChannel * vals)3028                 pixel_type(const ColourChannel *vals)
3029                 {
3030                     memcpy(elements, vals, sizeof(elements));
3031                 }
pixel_type(const RGBFTColour & vals)3032                 pixel_type(const RGBFTColour& vals)
3033                 {
3034                     elements[RED]    = vals.red();
3035                     elements[GREEN]  = vals.green();
3036                     elements[BLUE]   = vals.blue();
3037                     elements[FILTER] = vals.filter();
3038                     elements[TRANSM] = vals.transm();
3039                 }
pixel_type(const RGBTColour & vals)3040                 pixel_type(const RGBTColour& vals)
3041                 {
3042                     elements[RED]    = vals.red();
3043                     elements[GREEN]  = vals.green();
3044                     elements[BLUE]   = vals.blue();
3045                     elements[FILTER] = 0.0;
3046                     elements[TRANSM] = vals.transm();
3047                 }
pixel_type(float r,float g,float b,float f,float t)3048                 pixel_type(float r, float g, float b, float f, float t)
3049                 {
3050                     elements[RED] = r;
3051                     elements[GREEN] = g;
3052                     elements[BLUE] = b;
3053                     elements[FILTER] = f;
3054                     elements[TRANSM] = t;
3055                 }
~pixel_type()3056                 ~pixel_type() {}
operator ColourChannel*()3057                 operator ColourChannel *() { return elements; }
operator const ColourChannel*() const3058                 operator const ColourChannel *() const { return elements; }
operator ==(float val) const3059                 bool operator==(float val) const { return elements[RED] == val && elements[GREEN] == val && elements[BLUE] == val && elements[FILTER] == val && elements[TRANSM] == val; }
operator !=(float val) const3060                 bool operator!=(float val) const { return !(*this == val); }
3061 
3062             protected:
3063                 ColourChannel elements[5];
3064         };
3065 
FileBackedPixelContainer(size_type width,size_type height,size_type bs)3066         FileBackedPixelContainer(size_type width, size_type height, size_type bs):
3067             m_File(-1), m_Width(width), m_Height(height), m_xPos(0), m_yPos(0), m_Dirty(false), m_Path(PlatformBase::GetInstance().CreateTemporaryFile())
3068         {
3069             if ((m_File = open(UCS2toASCIIString(m_Path).c_str(), O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR)) == -1)
3070                 throw POV_EXCEPTION(kCannotOpenFileErr, "Cannot open backing file for intermediate image storage.");
3071             m_Blocksize = bs;
3072             m_Buffer.resize(m_Blocksize);
3073             // write extra data to create the big file and help 3rd party reader
3074             POV_OFF_T pos;
3075             // NB: The following use of SafeUnsignedProduct also safeguards later computations of
3076             // pixel positions within the file, as long as x and y coordinates are sane
3077             pos = SafeUnsignedProduct<POV_OFF_T>(m_Width, m_Height);
3078             if ( pos% m_Blocksize)
3079             { /* issue: the block would overlap the end of file */
3080                 pos /= m_Blocksize;
3081                 pos++;
3082                 pos = SafeUnsignedProduct<POV_OFF_T>(pos, m_Blocksize);
3083             }
3084             /* else fine case: the boundary of block match the boundary of pixels in file */
3085             pos = SafeUnsignedProduct<POV_OFF_T>(pos, sizeof(pixel_type));
3086             size_type meta[3];
3087             meta[0] = sizeof(pixel_type);
3088             meta[1] = m_Width;
3089             meta[2] = m_Height;
3090             if (POV_LSEEK(m_File, pos, SEEK_SET) != pos)
3091                 throw POV_EXCEPTION(kFileDataErr, "Intermediate image storage backing file write/seek failed at creation.");
3092             if (write(m_File, &meta[0], (int) sizeof(size_type)*3) != (sizeof(size_type)*3))
3093                 throw POV_EXCEPTION(kFileDataErr, "Intermediate image storage backing file write failed at creation.");
3094             // m_Committed.resize(width * height / m_Blocksize);
3095         }
3096 
~FileBackedPixelContainer()3097         virtual ~FileBackedPixelContainer()
3098         {
3099             if (m_File != -1)
3100             {
3101                 Flush();
3102                 close(m_File);
3103             }
3104             if (m_Path.empty() == false)
3105             {
3106                 // if shutdown has been delayed, by the time we reach here, the platform base
3107                 // may no longer be valid (see crashdump #77 for an example of this). we need
3108                 // to take the address of the reference to see if it's now `nullptr` before we use it.
3109                 PlatformBase *pb(&PlatformBase::GetInstance());
3110                 if (pb != nullptr)
3111                     pb->DeleteTemporaryFile(m_Path);
3112             }
3113         }
3114 
Flush(void)3115         void Flush(void)
3116         {
3117             WriteCurrentBlock();
3118         }
3119 
SetPixel(size_type x,size_type y,const pixel_type & pixel)3120         void SetPixel(size_type x, size_type y, const pixel_type& pixel)
3121         {
3122             WritePixel(x, y, pixel);
3123             NextPixel();
3124         }
3125 
SetPixel(size_type x,size_type y,float red,float green,float blue,float filter,float transm)3126         void SetPixel(size_type x, size_type y, float red, float green, float blue, float filter, float transm)
3127         {
3128             pixel_type pixel;
3129 
3130             pixel[RED] = red;
3131             pixel[GREEN] = green;
3132             pixel[BLUE] = blue;
3133             pixel[FILTER] = filter;
3134             pixel[TRANSM] = transm;
3135             WritePixel(x, y, pixel);
3136         }
3137 
SetPixel(float red,float green,float blue,float filter,float transm)3138         void SetPixel(float red, float green, float blue, float filter, float transm)
3139         {
3140             SetPixel(m_xPos, m_yPos, red, green, blue, filter, transm);
3141             NextPixel();
3142         }
3143 
GetPixel(pixel_type & pixel)3144         void GetPixel(pixel_type& pixel)
3145         {
3146             ReadPixel(m_xPos, m_yPos, pixel);
3147             NextPixel();
3148         }
3149 
GetPixel(float & red,float & green,float & blue,float & filter,float & transm)3150         void GetPixel(float& red, float& green, float& blue, float& filter, float& transm)
3151         {
3152             pixel_type pixel;
3153 
3154             GetPixel(pixel);    // advances NextPixel
3155             red = pixel[RED];
3156             green = pixel[GREEN];
3157             blue = pixel[BLUE];
3158             filter = pixel[FILTER];
3159             transm = pixel[TRANSM];
3160         }
3161 
GetPixel(size_type x,size_type y,pixel_type & pixel)3162         void GetPixel(size_type x, size_type y, pixel_type& pixel)
3163         {
3164             SetPos(x, y);
3165             ReadPixel(x, y, pixel);
3166         }
3167 
GetPixel(size_type x,size_type y,float & red,float & green,float & blue,float & filter,float & transm)3168         void GetPixel(size_type x, size_type y, float& red, float& green, float& blue, float& filter, float& transm)
3169         {
3170             pixel_type pixel;
3171 
3172             GetPixel(x, y, pixel);  // sets Position
3173             red = pixel[RED];
3174             green = pixel[GREEN];
3175             blue = pixel[BLUE];
3176             filter = pixel[FILTER];
3177             transm = pixel[TRANSM];
3178         }
3179 
3180         /* void ClearCache(const pixel_type& pixel = pixel_type())
3181         {
3182             for (int i = 0; i < m_Width; i++)
3183                 memcpy(&m_Buffer[i], &pixel, sizeof(pixel));
3184         } */
3185 
FillLine(size_type y,const pixel_type & pixel)3186         void FillLine(size_type y, const pixel_type& pixel)
3187         {
3188             // bool notBlank(pixel != 0.0);
3189 
3190             for (size_type x = 0; x < m_Width; x++)
3191                 // if (notBlank)
3192                     WritePixel(x, y, pixel);
3193         }
3194 
Fill(const pixel_type & pixel)3195         void Fill(const pixel_type& pixel)
3196         {
3197             for (size_type y = 0; y < m_Height; y++)
3198                 FillLine(y, pixel);
3199         }
3200 
Fill(float red,float green,float blue,float filter,float transm)3201         void Fill(float red, float green, float blue, float filter, float transm)
3202         {
3203             pixel_type pixel(red, green, blue, filter, transm);
3204             Fill(pixel);
3205         }
3206 
3207     protected:
3208         int                 m_File;
3209         bool                m_Dirty;
3210         size_type           m_Blocksize;
3211         POV_OFF_T           m_CurrentBlock;
3212         size_type           m_Width;
3213         size_type           m_Height;
3214         size_type           m_xPos;
3215         size_type           m_yPos;
3216         UCS2String          m_Path;
3217         //vector<bool>        m_Committed;
3218         vector<pixel_type>  m_Buffer;
3219 
SetPos(size_type x,size_type y,bool cache=true)3220         void SetPos(size_type x, size_type y, bool cache = true)
3221         {
3222             if (x < 0 || x >= m_Width || y < 0 || y >= m_Height)
3223                 throw POV_EXCEPTION(kFileDataErr, "Invalid coordinates in intermediate image file seek.");
3224             if (y == m_yPos)
3225             {
3226                 m_xPos = x;
3227                 return;
3228             }
3229             m_xPos = x;
3230             m_yPos = y;
3231         }
3232 
NextPixel(void)3233         void NextPixel(void)
3234         {
3235             if (m_xPos == m_Width - 1)
3236             {
3237                 if (m_yPos == m_Height - 1)
3238                     return;
3239             }
3240             else
3241                 m_xPos++;
3242         }
3243 
ReadPixel(size_type x,size_type y,pixel_type & pixel)3244         void ReadPixel(size_type x, size_type y, pixel_type& pixel)
3245         {
3246             POV_OFF_T pos, block = (y * (POV_OFF_T)(m_Width) + x) / m_Blocksize;
3247 
3248             if (block != m_CurrentBlock) {
3249                 WriteCurrentBlock();
3250 #if 0
3251                 if (m_Committed[block] == false) {
3252                     ColourChannel pixel[5] = {0.0, 0.0, 0.0, 0.0, 0.0};
3253                     for (size_type i = 0; i < m_Blocksize; i++)
3254                         memcpy(&m_Buffer[i], pixel, sizeof(pixel));
3255                     m_CurrentBlock = block;
3256                     return;
3257                 }
3258 #endif
3259                 pos = block * sizeof(pixel_type) * m_Blocksize;
3260                 int chunk = sizeof(pixel_type) * m_Blocksize;
3261                 if (POV_LSEEK(m_File, pos, SEEK_SET) != pos)
3262                     throw POV_EXCEPTION(kFileDataErr, "Intermediate image storage backing file read/seek failed.");
3263                 int bytes = read(m_File, &m_Buffer[0], chunk);
3264                 if (bytes != (sizeof(pixel_type) * m_Blocksize))
3265                     throw POV_EXCEPTION(kFileDataErr, "Intermediate image storage backing file read failed.");
3266                 m_CurrentBlock = block;
3267             }
3268             POV_IMAGE_ASSERT (m_Blocksize != 0);
3269             memcpy(&pixel, m_Buffer[(y * (POV_OFF_T)(m_Width) + x) % m_Blocksize], sizeof(pixel));
3270         }
3271 #if 0
3272         bool BlockCommitted(size_type x, size_type y)
3273         {
3274             POV_OFF_T block = (y * POV_OFF_T(m_Width) + x) / m_Blocksize;
3275 
3276             return(m_Committed[block]);
3277         }
3278 #endif
WriteCurrentBlock()3279         void WriteCurrentBlock()
3280         {
3281             POV_OFF_T pos;
3282 
3283             if (m_Dirty) {
3284                 pos = m_CurrentBlock * sizeof(pixel_type) * m_Blocksize;
3285                 if (POV_LSEEK(m_File, pos, SEEK_SET) != pos)
3286                     throw POV_EXCEPTION(kFileDataErr, "Intermediate image storage backing file write/seek failed.");
3287                 if (write(m_File, &m_Buffer[0], (int) sizeof(pixel_type) * m_Blocksize) != (sizeof(pixel_type) * m_Blocksize))
3288                     throw POV_EXCEPTION(kFileDataErr, "Intermediate image storage backing file write failed.");
3289             //  m_Committed[m_CurrentBlock] = true;
3290                 m_Dirty = false;
3291             }
3292         }
3293 
WritePixel(size_type x,size_type y,const pixel_type & pixel)3294         void WritePixel(size_type x, size_type y, const pixel_type& pixel)
3295         {
3296             pixel_type dummy;
3297 
3298             ReadPixel(x, y, dummy);
3299             memcpy(m_Buffer[(y * (POV_OFF_T)(m_Width) + x) % m_Blocksize], &pixel, sizeof(pixel));
3300             m_Dirty = true;
3301         }
3302 
3303     private:
3304         // not available
FileBackedPixelContainer(void)3305         FileBackedPixelContainer(void) {}
3306 };
3307 
3308 class FileRGBFTImage : public Image
3309 {
3310     public:
3311         typedef FileBackedPixelContainer::pixel_type pixel_type;
3312 
FileRGBFTImage(unsigned int w,unsigned int h,unsigned int bs)3313         FileRGBFTImage(unsigned int w, unsigned int h, unsigned int bs): Image(w, h, RGBFT_Float), pixels(width, height, bs) { }
~FileRGBFTImage()3314         ~FileRGBFTImage() { }
3315 
IsGrayscale() const3316         bool IsGrayscale() const { return false; }
IsColour() const3317         bool IsColour() const { return true; }
IsFloat() const3318         bool IsFloat() const { return true; }
IsInt() const3319         bool IsInt() const { return false; }
IsIndexed() const3320         bool IsIndexed() const { return false; }
IsGammaEncoded() const3321         bool IsGammaEncoded() const { return false; }
HasAlphaChannel() const3322         bool HasAlphaChannel() const { return false; }
HasFilterTransmit() const3323         bool HasFilterTransmit() const { return true; }
GetMaxIntValue() const3324         unsigned int GetMaxIntValue() const { return 255; }
SetEncodingGamma(GammaCurvePtr gamma)3325         void SetEncodingGamma(GammaCurvePtr gamma) { ; }
TryDeferDecoding(GammaCurvePtr &,unsigned int)3326         bool TryDeferDecoding(GammaCurvePtr&, unsigned int) { return false; }
IsOpaque() const3327         bool IsOpaque() const { throw POV_EXCEPTION(kUncategorizedError, "Internal error: IsOpaque() not supported in FileRGBFTImage"); }
GetBitValue(unsigned int x,unsigned int y) const3328         bool GetBitValue(unsigned int x, unsigned int y) const
3329         {
3330             // TODO FIXME - [CLi] This ignores opacity information; other bit-based code doesn't.
3331             float red, green, blue, filter, transm;
3332             GetRGBFTValue(x, y, red, green, blue, filter, transm);
3333             return IS_NONZERO_RGB(red, green, blue);
3334         }
GetGrayValue(unsigned int x,unsigned int y) const3335         float GetGrayValue(unsigned int x, unsigned int y) const
3336         {
3337             float red, green, blue, filter, transm;
3338             GetRGBFTValue(x, y, red, green, blue, filter, transm);
3339             return RGB2Gray(red, green, blue);
3340         }
GetGrayAValue(unsigned int x,unsigned int y,float & gray,float & alpha) const3341         void GetGrayAValue(unsigned int x, unsigned int y, float& gray, float& alpha) const
3342         {
3343             float red, green, blue, filter, transm;
3344             GetRGBFTValue(x, y, red, green, blue, filter, transm);
3345             gray = RGB2Gray(red, green, blue);
3346             alpha = RGBFTColour::FTtoA(filter, transm);
3347         }
GetRGBValue(unsigned int x,unsigned int y,float & red,float & green,float & blue) const3348         void GetRGBValue(unsigned int x, unsigned int y, float& red, float& green, float& blue) const
3349         {
3350             float filter, transm;
3351             GetRGBFTValue(x, y, red, green, blue, filter, transm);
3352         }
GetRGBAValue(unsigned int x,unsigned int y,float & red,float & green,float & blue,float & alpha) const3353         void GetRGBAValue(unsigned int x, unsigned int y, float& red, float& green, float& blue, float& alpha) const
3354         {
3355             float filter, transm;
3356             GetRGBFTValue(x, y, red, green, blue, filter, transm);
3357             alpha = RGBFTColour::FTtoA(filter, transm);
3358         }
GetRGBTValue(unsigned int x,unsigned int y,float & red,float & green,float & blue,float & transm) const3359         void GetRGBTValue(unsigned int x, unsigned int y, float& red, float& green, float& blue, float& transm) const
3360         {
3361             float filter;
3362             GetRGBFTValue(x, y, red, green, blue, filter, transm);
3363             transm = 1.0 - RGBFTColour::FTtoA(filter, transm);
3364         }
GetRGBFTValue(unsigned int x,unsigned int y,float & red,float & green,float & blue,float & filter,float & transm) const3365         void GetRGBFTValue(unsigned int x, unsigned int y, float& red, float& green, float& blue, float& filter, float& transm) const
3366         {
3367             CHECK_BOUNDS(x, y);
3368             pixels.GetPixel(x, y, red, green, blue, filter, transm);
3369         }
3370 
SetBitValue(unsigned int x,unsigned int y,bool bit)3371         void SetBitValue(unsigned int x, unsigned int y, bool bit)
3372         {
3373             if(bit == true)
3374                 SetGrayValue(x, y, 1.0f);
3375             else
3376                 SetGrayValue(x, y, 0.0f);
3377         }
SetGrayValue(unsigned int x,unsigned int y,float gray)3378         void SetGrayValue(unsigned int x, unsigned int y, float gray)
3379         {
3380             SetRGBFTValue(x, y, gray, gray, gray, FT_OPAQUE, FT_OPAQUE);
3381         }
SetGrayValue(unsigned int x,unsigned int y,unsigned int gray)3382         void SetGrayValue(unsigned int x, unsigned int y, unsigned int gray)
3383         {
3384             SetGrayValue(x, y, float(gray) / 255.0f);
3385         }
SetGrayAValue(unsigned int x,unsigned int y,float gray,float alpha)3386         void SetGrayAValue(unsigned int x, unsigned int y, float gray, float alpha)
3387         {
3388             // TODO - should alpha be converted to filter and transm? [trf]
3389             float filter, transm;
3390             RGBFTColour::AtoFT(alpha, filter, transm);
3391             SetRGBFTValue(x, y, gray, gray, gray, filter, transm);
3392         }
SetGrayAValue(unsigned int x,unsigned int y,unsigned int gray,unsigned int alpha)3393         void SetGrayAValue(unsigned int x, unsigned int y, unsigned int gray, unsigned int alpha)
3394         {
3395             // TODO - should alpha be converted to filter and transm? [trf]
3396             float c = float(gray) / 255.0f;
3397             float filter, transm;
3398             RGBFTColour::AtoFT(float(alpha) / 255.0f, filter, transm);
3399             SetRGBFTValue(x, y, c, c, c, filter, transm);
3400         }
SetRGBValue(unsigned int x,unsigned int y,float red,float green,float blue)3401         void SetRGBValue(unsigned int x, unsigned int y, float red, float green, float blue)
3402         {
3403             SetRGBFTValue(x, y, red, green, blue, FT_OPAQUE, FT_OPAQUE);
3404         }
SetRGBValue(unsigned int x,unsigned int y,unsigned int red,unsigned int green,unsigned int blue)3405         void SetRGBValue(unsigned int x, unsigned int y, unsigned int red, unsigned int green, unsigned int blue)
3406         {
3407             SetRGBFTValue(x, y, float(red) / 255.0f, float(green) / 255.0f, float(blue) / 255.0f, FT_OPAQUE, FT_OPAQUE);
3408         }
SetRGBAValue(unsigned int x,unsigned int y,float red,float green,float blue,float alpha)3409         void SetRGBAValue(unsigned int x, unsigned int y, float red, float green, float blue, float alpha)
3410         {
3411             // TODO - should alpha be converted to filter and transm? [trf]
3412             float filter, transm;
3413             RGBFTColour::AtoFT(alpha, filter, transm);
3414             SetRGBFTValue(x, y, red, green, blue, filter, transm);
3415         }
SetRGBAValue(unsigned int x,unsigned int y,unsigned int red,unsigned int green,unsigned int blue,unsigned int alpha)3416         void SetRGBAValue(unsigned int x, unsigned int y, unsigned int red, unsigned int green, unsigned int blue, unsigned int alpha)
3417         {
3418             // TODO - should alpha be converted to filter and transm? [trf]
3419             float filter, transm;
3420             RGBFTColour::AtoFT(float(alpha) / 255.0f, filter, transm);
3421             SetRGBFTValue(x, y, float(red) / 255.0f, float(green) / 255.0f, float(blue) / 255.0f, filter, transm);
3422         }
SetRGBTValue(unsigned int x,unsigned int y,float red,float green,float blue,float transm)3423         void SetRGBTValue(unsigned int x, unsigned int y, float red, float green, float blue, float transm)
3424         {
3425             SetRGBFTValue(x, y, red, green, blue, FT_OPAQUE, transm);
3426         }
SetRGBTValue(unsigned int x,unsigned int y,const RGBTColour & col)3427         void SetRGBTValue(unsigned int x, unsigned int y, const RGBTColour& col)
3428         {
3429             SetRGBFTValue(x, y, col.red(), col.green(), col.blue(), FT_OPAQUE, col.transm());
3430         }
SetRGBFTValue(unsigned int x,unsigned int y,float red,float green,float blue,float filter,float transm)3431         void SetRGBFTValue(unsigned int x, unsigned int y, float red, float green, float blue, float filter, float transm)
3432         {
3433             CHECK_BOUNDS(x, y);
3434             pixels.SetPixel(x, y, red, green, blue, filter, transm);
3435         }
SetRGBFTValue(unsigned int x,unsigned int y,const RGBFTColour & col)3436         void SetRGBFTValue(unsigned int x, unsigned int y, const RGBFTColour& col)
3437         {
3438             CHECK_BOUNDS(x, y);
3439             pixels.SetPixel(x, y, col);
3440         }
3441 
FillBitValue(bool bit)3442         void FillBitValue(bool bit)
3443         {
3444             if(bit == true)
3445                 FillGrayValue(1.0f);
3446             else
3447                 FillGrayValue(0.0f);
3448         }
FillGrayValue(float gray)3449         void FillGrayValue(float gray)
3450         {
3451             FillRGBFTValue(gray, gray, gray, FT_OPAQUE, FT_OPAQUE);
3452         }
FillGrayValue(unsigned int gray)3453         void FillGrayValue(unsigned int gray)
3454         {
3455             FillGrayValue(float(gray) / 255.0f);
3456         }
FillGrayAValue(float gray,float alpha)3457         void FillGrayAValue(float gray, float alpha)
3458         {
3459             // TODO - should alpha be converted to filter and transm? [trf]
3460             float filter, transm;
3461             RGBFTColour::AtoFT(alpha, filter, transm);
3462             FillRGBFTValue(gray, gray, gray, filter, transm);
3463         }
FillGrayAValue(unsigned int gray,unsigned int alpha)3464         void FillGrayAValue(unsigned int gray, unsigned int alpha)
3465         {
3466             // TODO - should alpha be converted to filter and transm? [trf]
3467             FillGrayAValue(float(gray) / 255.0f, float(alpha) / 255.0f);
3468         }
FillRGBValue(float red,float green,float blue)3469         void FillRGBValue(float red, float green, float blue)
3470         {
3471             FillRGBFTValue(red, green, blue, FT_OPAQUE, FT_OPAQUE);
3472         }
FillRGBValue(unsigned int red,unsigned int green,unsigned int blue)3473         void FillRGBValue(unsigned int red, unsigned int green, unsigned int blue)
3474         {
3475             FillRGBFTValue(float(red) / 255.0f, float(green) / 255.0f, float(blue) / 255.0f, FT_OPAQUE, FT_OPAQUE);
3476         }
FillRGBAValue(float red,float green,float blue,float alpha)3477         void FillRGBAValue(float red, float green, float blue, float alpha)
3478         {
3479             // TODO - should alpha be converted to filter and transm? [trf]
3480             float filter, transm;
3481             RGBFTColour::AtoFT(alpha, filter, transm);
3482             FillRGBFTValue(red, green, blue, filter, transm);
3483         }
FillRGBAValue(unsigned int red,unsigned int green,unsigned int blue,unsigned int alpha)3484         void FillRGBAValue(unsigned int red, unsigned int green, unsigned int blue, unsigned int alpha)
3485         {
3486             // TODO - should alpha be converted to filter and transm? [trf]
3487             float filter, transm;
3488             RGBFTColour::AtoFT(float(alpha) / 255.0f, filter, transm);
3489             FillRGBFTValue(float(red) / 255.0f, float(green) / 255.0f, float(blue) / 255.0f, filter, transm);
3490         }
FillRGBTValue(float red,float green,float blue,float transm)3491         void FillRGBTValue(float red, float green, float blue, float transm)
3492         {
3493             FillRGBFTValue(red, green, blue, FT_OPAQUE, transm);
3494         }
FillRGBFTValue(float red,float green,float blue,float filter,float transm)3495         void FillRGBFTValue(float red, float green, float blue, float filter, float transm)
3496         {
3497             pixels.Fill(red, green, blue, filter, transm);
3498         }
3499 
3500     protected:
3501         mutable FileBackedPixelContainer pixels;
3502 };
3503 
3504 void RGBMap2RGBAMap(const vector<Image::RGBMapEntry>& m, vector<Image::RGBAMapEntry>& n);
3505 void RGBMap2RGBFTMap(const vector<Image::RGBMapEntry>& m, vector<Image::RGBFTMapEntry>& n);
3506 void RGBAMap2RGBMap(const vector<Image::RGBAMapEntry>& m, vector<Image::RGBMapEntry>& n);
3507 void RGBAMap2RGBFTMap(const vector<Image::RGBAMapEntry>& m, vector<Image::RGBFTMapEntry>& n);
3508 void RGBFTMap2RGBMap(const vector<Image::RGBFTMapEntry>& m, vector<Image::RGBMapEntry>& n);
3509 void RGBFTMap2RGBAMap(const vector<Image::RGBFTMapEntry>& m, vector<Image::RGBAMapEntry>& n);
3510 
RGBMap2RGBAMap(const vector<Image::RGBMapEntry> & m,vector<Image::RGBAMapEntry> & n)3511 void RGBMap2RGBAMap(const vector<Image::RGBMapEntry>& m, vector<Image::RGBAMapEntry>& n)
3512 {
3513     n.clear();
3514     n.reserve(m.size());
3515 
3516     for(vector<Image::RGBMapEntry>::const_iterator i(m.begin()); i != m.end(); i++)
3517         n.push_back(Image::RGBAMapEntry(i->red, i->green, i->blue, ALPHA_OPAQUE));
3518 }
3519 
RGBMap2RGBFTMap(const vector<Image::RGBMapEntry> & m,vector<Image::RGBFTMapEntry> & n)3520 void RGBMap2RGBFTMap(const vector<Image::RGBMapEntry>& m, vector<Image::RGBFTMapEntry>& n)
3521 {
3522     n.clear();
3523     n.reserve(m.size());
3524 
3525     for(vector<Image::RGBMapEntry>::const_iterator i(m.begin()); i != m.end(); i++)
3526         n.push_back(Image::RGBFTMapEntry(i->red, i->green, i->blue, FT_OPAQUE, FT_OPAQUE));
3527 }
3528 
RGBAMap2RGBMap(const vector<Image::RGBAMapEntry> & m,vector<Image::RGBMapEntry> & n)3529 void RGBAMap2RGBMap(const vector<Image::RGBAMapEntry>& m, vector<Image::RGBMapEntry>& n)
3530 {
3531     n.clear();
3532     n.reserve(m.size());
3533 
3534     for(vector<Image::RGBAMapEntry>::const_iterator i(m.begin()); i != m.end(); i++)
3535         n.push_back(Image::RGBMapEntry(i->red, i->green, i->blue));
3536 }
3537 
RGBAMap2RGBFTMap(const vector<Image::RGBAMapEntry> & m,vector<Image::RGBFTMapEntry> & n)3538 void RGBAMap2RGBFTMap(const vector<Image::RGBAMapEntry>& m, vector<Image::RGBFTMapEntry>& n)
3539 {
3540     n.clear();
3541     n.reserve(m.size());
3542 
3543     for(vector<Image::RGBAMapEntry>::const_iterator i(m.begin()); i != m.end(); i++)
3544     {
3545         float filter, transm;
3546         RGBFTColour::AtoFT(i->alpha, filter, transm);
3547         n.push_back(Image::RGBFTMapEntry(i->red, i->green, i->blue, filter, transm));
3548     }
3549 }
3550 
RGBFTMap2RGBMap(const vector<Image::RGBFTMapEntry> & m,vector<Image::RGBMapEntry> & n)3551 void RGBFTMap2RGBMap(const vector<Image::RGBFTMapEntry>& m, vector<Image::RGBMapEntry>& n)
3552 {
3553     n.clear();
3554     n.reserve(m.size());
3555 
3556     for(vector<Image::RGBFTMapEntry>::const_iterator i(m.begin()); i != m.end(); i++)
3557         n.push_back(Image::RGBMapEntry(i->red, i->green, i->blue));
3558 }
3559 
RGBFTMap2RGBAMap(const vector<Image::RGBFTMapEntry> & m,vector<Image::RGBAMapEntry> & n)3560 void RGBFTMap2RGBAMap(const vector<Image::RGBFTMapEntry>& m, vector<Image::RGBAMapEntry>& n)
3561 {
3562     n.clear();
3563     n.reserve(m.size());
3564 
3565     for(vector<Image::RGBFTMapEntry>::const_iterator i(m.begin()); i != m.end(); i++)
3566         n.push_back(Image::RGBAMapEntry(i->red, i->green, i->blue, RGBFTColour::FTtoA(i->filter, i->transm)));
3567 }
3568 
GetImageDataType(ImageChannelDataType channelType,ImageChannelLayout layout)3569 Image::ImageDataType Image::GetImageDataType (ImageChannelDataType channelType, ImageChannelLayout layout)
3570 {
3571     switch (layout)
3572     {
3573     case kImageChannelLayout_Gray:
3574         switch (channelType)
3575         {
3576         case kImageChannelDataType_Int8:    return Image::Gray_Int8;
3577         case kImageChannelDataType_Int16:   return Image::Gray_Int16;
3578         case kImageChannelDataType_Gamma8:  return Image::Gray_Gamma8;
3579         case kImageChannelDataType_Gamma16: return Image::Gray_Gamma16;
3580         default:
3581             POV_IMAGE_ASSERT(false);
3582             break;
3583         }
3584         break;
3585 
3586     case kImageChannelLayout_GrayA:
3587         switch (channelType)
3588         {
3589         case kImageChannelDataType_Int8:    return Image::GrayA_Int8;
3590         case kImageChannelDataType_Int16:   return Image::GrayA_Int16;
3591         case kImageChannelDataType_Gamma8:  return Image::GrayA_Gamma8;
3592         case kImageChannelDataType_Gamma16: return Image::GrayA_Gamma16;
3593         default:
3594             POV_IMAGE_ASSERT(false);
3595             break;
3596         }
3597         break;
3598 
3599     case kImageChannelLayout_RGB:
3600         switch (channelType)
3601         {
3602         case kImageChannelDataType_Int8:    return Image::RGB_Int8;
3603         case kImageChannelDataType_Int16:   return Image::RGB_Int16;
3604         case kImageChannelDataType_Gamma8:  return Image::RGB_Gamma8;
3605         case kImageChannelDataType_Gamma16: return Image::RGB_Gamma16;
3606         default:
3607             POV_IMAGE_ASSERT(false);
3608             break;
3609         }
3610         break;
3611 
3612     case kImageChannelLayout_RGBA:
3613         switch (channelType)
3614         {
3615         case kImageChannelDataType_Int8:    return Image::RGBA_Int8;
3616         case kImageChannelDataType_Int16:   return Image::RGBA_Int16;
3617         case kImageChannelDataType_Gamma8:  return Image::RGBA_Gamma8;
3618         case kImageChannelDataType_Gamma16: return Image::RGBA_Gamma16;
3619         default:
3620             POV_IMAGE_ASSERT(false);
3621             break;
3622         }
3623         break;
3624 
3625     default:
3626         POV_IMAGE_ASSERT(false);
3627         break;
3628     }
3629 
3630     return Image::Undefined;
3631 }
3632 
Create(unsigned int w,unsigned int h,ImageDataType t,unsigned int maxRAMmbHint,unsigned int pixelsPerBlockHint)3633 Image *Image::Create(unsigned int w, unsigned int h, ImageDataType t, unsigned int maxRAMmbHint, unsigned int pixelsPerBlockHint)
3634 {
3635     try
3636     {
3637         switch(t)
3638         {
3639             case Bit_Map:
3640                 return new MemoryBitMapImage(w, h);
3641             case Gray_Int8:
3642                 return new MemoryGray8Image(w, h);
3643             case Gray_Int16:
3644                 return new MemoryGray16Image(w, h);
3645             case GrayA_Int8:
3646                 return new MemoryGrayA8Image(w, h);
3647             case GrayA_Int16:
3648                 return new MemoryGrayA16Image(w, h);
3649             case RGB_Int8:
3650                 return new MemoryRGB8Image(w, h);
3651             case RGB_Int16:
3652                 return new MemoryRGB16Image(w, h);
3653             case RGBA_Int8:
3654                 return new MemoryRGBA8Image (w, h);
3655             case RGBA_Int16:
3656                 return new MemoryRGBA16Image(w, h);
3657             case RGBFT_Float:
3658                 if (maxRAMmbHint > 0)
3659                     if (SafeUnsignedProduct<POV_ULONG>(w, h, sizeof(FileRGBFTImage::pixel_type)) / 1048576 > maxRAMmbHint)
3660                         return new FileRGBFTImage(w, h, pixelsPerBlockHint);
3661                 return new MemoryRGBFTImage(w, h);
3662             case RGB_Gamma8:
3663                 return new MemoryNonlinearRGB8Image(w, h);
3664             case RGB_Gamma16:
3665                 return new MemoryNonlinearRGB16Image(w, h);
3666             case RGBA_Gamma8:
3667                 return new MemoryNonlinearRGBA8Image (w, h);
3668             case RGBA_Gamma16:
3669                 return new MemoryNonlinearRGBA16Image(w, h);
3670             case Gray_Gamma8:
3671                 return new MemoryNonlinearGray8Image(w, h);
3672             case Gray_Gamma16:
3673                 return new MemoryNonlinearGray16Image(w, h);
3674             case GrayA_Gamma8:
3675                 return new MemoryNonlinearGrayA8Image(w, h);
3676             case GrayA_Gamma16:
3677                 return new MemoryNonlinearGrayA16Image(w, h);
3678             default:
3679                 throw POV_EXCEPTION_STRING("Undefined image format in Image::Create");
3680         }
3681     }
3682     catch(std::bad_alloc&)
3683     {
3684         throw POV_EXCEPTION(kOutOfMemoryErr, "Insufficient memory to allocate intermediate image storage.");
3685     }
3686 }
3687 
Create(unsigned int w,unsigned int h,ImageDataType t,bool allowFileBacking)3688 Image *Image::Create(unsigned int w, unsigned int h, ImageDataType t, bool allowFileBacking)
3689 {
3690     try
3691     {
3692         switch(t)
3693         {
3694             case Bit_Map:
3695                 return new MemoryBitMapImage(w, h);
3696             case Gray_Int8:
3697                 return new MemoryGray8Image(w, h);
3698             case Gray_Int16:
3699                 return new MemoryGray16Image(w, h);
3700             case GrayA_Int8:
3701                 return new MemoryGrayA8Image(w, h);
3702             case GrayA_Int16:
3703                 return new MemoryGrayA16Image(w, h);
3704             case RGB_Int8:
3705                 return new MemoryRGB8Image(w, h);
3706             case RGB_Int16:
3707                 return new MemoryRGB16Image(w, h);
3708             case RGBA_Int8:
3709                 return new MemoryRGBA8Image (w, h);
3710             case RGBA_Int16:
3711                 return new MemoryRGBA16Image(w, h);
3712             case RGBFT_Float:
3713 #ifdef FILE_MAPPED_IMAGE_ALLOCATOR
3714                 if (allowFileBacking)
3715                     return new RGBFTImage<FILE_MAPPED_IMAGE_ALLOCATOR<float> >(w, h);
3716 #endif
3717                 return new MemoryRGBFTImage(w, h);
3718             case RGB_Gamma8:
3719                 return new MemoryNonlinearRGB8Image(w, h);
3720             case RGB_Gamma16:
3721                 return new MemoryNonlinearRGB16Image(w, h);
3722             case RGBA_Gamma8:
3723                 return new MemoryNonlinearRGBA8Image (w, h);
3724             case RGBA_Gamma16:
3725                 return new MemoryNonlinearRGBA16Image(w, h);
3726             case Gray_Gamma8:
3727                 return new MemoryNonlinearGray8Image(w, h);
3728             case Gray_Gamma16:
3729                 return new MemoryNonlinearGray16Image(w, h);
3730             case GrayA_Gamma8:
3731                 return new MemoryNonlinearGrayA8Image(w, h);
3732             case GrayA_Gamma16:
3733                 return new MemoryNonlinearGrayA16Image(w, h);
3734             default:
3735                 throw POV_EXCEPTION_STRING("Undefined image format in Image::Create");
3736         }
3737     }
3738     catch(std::bad_alloc&)
3739     {
3740         throw POV_EXCEPTION(kOutOfMemoryErr, "Insufficient memory to allocate intermediate image storage.");
3741     }
3742 }
3743 
Create(unsigned int w,unsigned int h,ImageDataType t,const vector<RGBMapEntry> & m,bool allowFileBacking)3744 Image *Image::Create(unsigned int w, unsigned int h, ImageDataType t, const vector<RGBMapEntry>& m, bool allowFileBacking)
3745 {
3746     try
3747     {
3748         switch(t)
3749         {
3750             case Bit_Map:
3751                 return new MemoryBitMapImage(w, h, m);
3752             case Colour_Map:
3753                 return new MemoryColourMapImage(w, h, m);
3754             case Gray_Int8:
3755                 return new MemoryGray8Image(w, h, m);
3756             case Gray_Int16:
3757                 return new MemoryGray16Image(w, h, m);
3758             case GrayA_Int8:
3759                 return new MemoryGrayA8Image(w, h, m);
3760             case GrayA_Int16:
3761                 return new MemoryGrayA16Image(w, h, m);
3762             case RGB_Int8:
3763                 return new MemoryRGB8Image(w, h, m);
3764             case RGB_Int16:
3765                 return new MemoryRGB16Image(w, h, m);
3766             case RGBA_Int8:
3767                 return new MemoryRGBA8Image (w, h, m);
3768             case RGBA_Int16:
3769                 return new MemoryRGBA16Image(w, h, m);
3770             case RGBFT_Float:
3771 #ifdef FILE_MAPPED_IMAGE_ALLOCATOR
3772                 if (allowFileBacking)
3773                     return new RGBFTImage<FILE_MAPPED_IMAGE_ALLOCATOR<float> >(w, h, m);
3774 #endif
3775                 return new MemoryRGBFTImage(w, h, m);
3776             case RGB_Gamma8:
3777                 return new MemoryNonlinearRGB8Image(w, h, m);
3778             case RGB_Gamma16:
3779                 return new MemoryNonlinearRGB16Image(w, h, m);
3780             case RGBA_Gamma8:
3781                 return new MemoryNonlinearRGBA8Image (w, h, m);
3782             case RGBA_Gamma16:
3783                 return new MemoryNonlinearRGBA16Image(w, h, m);
3784             case Gray_Gamma8:
3785                 return new MemoryNonlinearGray8Image(w, h, m);
3786             case Gray_Gamma16:
3787                 return new MemoryNonlinearGray16Image(w, h, m);
3788             case GrayA_Gamma8:
3789                 return new MemoryNonlinearGrayA8Image(w, h, m);
3790             case GrayA_Gamma16:
3791                 return new MemoryNonlinearGrayA16Image(w, h, m);
3792             default:
3793                 throw POV_EXCEPTION_STRING("Image::Create Exception TODO"); // TODO FIXME WIP
3794         }
3795     }
3796     catch(std::bad_alloc&)
3797     {
3798         throw POV_EXCEPTION(kOutOfMemoryErr, "Insufficient memory to allocate intermediate image storage.");
3799     }
3800 }
3801 
Create(unsigned int w,unsigned int h,ImageDataType t,const vector<RGBAMapEntry> & m,bool allowFileBacking)3802 Image *Image::Create(unsigned int w, unsigned int h, ImageDataType t, const vector<RGBAMapEntry>& m, bool allowFileBacking)
3803 {
3804     try
3805     {
3806         switch(t)
3807         {
3808             case Bit_Map:
3809                 return new MemoryBitMapImage(w, h, m);
3810             case Colour_Map:
3811                 return new MemoryColourMapImage(w, h, m);
3812             case Gray_Int8:
3813                 return new MemoryGray8Image(w, h, m);
3814             case Gray_Int16:
3815                 return new MemoryGray16Image(w, h, m);
3816             case GrayA_Int8:
3817                 return new MemoryGrayA8Image(w, h, m);
3818             case GrayA_Int16:
3819                 return new MemoryGrayA16Image(w, h, m);
3820             case RGB_Int8:
3821                 return new MemoryRGB8Image(w, h, m);
3822             case RGB_Int16:
3823                 return new MemoryRGB16Image(w, h, m);
3824             case RGBA_Int8:
3825                 return new MemoryRGBA8Image (w, h, m);
3826             case RGBA_Int16:
3827                 return new MemoryRGBA16Image(w, h, m);
3828             case RGBFT_Float:
3829 #ifdef FILE_MAPPED_RGBFT_IMAGE_ALLOCATOR
3830                 if (allowFileBacking)
3831                     return new RGBFTImage<FILE_MAPPED_RGBFT_IMAGE_ALLOCATOR<float> >(w, h, m);
3832 #endif
3833                 return new MemoryRGBFTImage(w, h, m);
3834             case RGB_Gamma8:
3835                 return new MemoryNonlinearRGB8Image(w, h, m);
3836             case RGB_Gamma16:
3837                 return new MemoryNonlinearRGB16Image(w, h, m);
3838             case RGBA_Gamma8:
3839                 return new MemoryNonlinearRGBA8Image (w, h, m);
3840             case RGBA_Gamma16:
3841                 return new MemoryNonlinearRGBA16Image(w, h, m);
3842             case Gray_Gamma8:
3843                 return new MemoryNonlinearGray8Image(w, h, m);
3844             case Gray_Gamma16:
3845                 return new MemoryNonlinearGray16Image(w, h, m);
3846             case GrayA_Gamma8:
3847                 return new MemoryNonlinearGrayA8Image(w, h, m);
3848             case GrayA_Gamma16:
3849                 return new MemoryNonlinearGrayA16Image(w, h, m);
3850             default:
3851                 throw POV_EXCEPTION_STRING("Image::Create Exception TODO"); // TODO FIXME WIP
3852         }
3853     }
3854     catch(std::bad_alloc&)
3855     {
3856         throw POV_EXCEPTION(kOutOfMemoryErr, "Insufficient memory to allocate intermediate image storage.");
3857     }
3858 }
3859 
Create(unsigned int w,unsigned int h,ImageDataType t,const vector<RGBFTMapEntry> & m,bool allowFileBacking)3860 Image *Image::Create(unsigned int w, unsigned int h, ImageDataType t, const vector<RGBFTMapEntry>& m, bool allowFileBacking)
3861 {
3862     try
3863     {
3864         switch(t)
3865         {
3866             case Bit_Map:
3867                 return new MemoryBitMapImage(w, h, m);
3868             case Colour_Map:
3869                 return new MemoryColourMapImage(w, h, m);
3870             case Gray_Int8:
3871                 return new MemoryGray8Image(w, h, m);
3872             case Gray_Int16:
3873                 return new MemoryGray16Image(w, h, m);
3874             case GrayA_Int8:
3875                 return new MemoryGrayA8Image(w, h, m);
3876             case GrayA_Int16:
3877                 return new MemoryGrayA16Image(w, h, m);
3878             case RGB_Int8:
3879                 return new MemoryRGB8Image(w, h, m);
3880             case RGB_Int16:
3881                 return new MemoryRGB16Image(w, h, m);
3882             case RGBA_Int8:
3883                 return new MemoryRGBA8Image (w, h, m);
3884             case RGBA_Int16:
3885                 return new MemoryRGBA16Image(w, h, m);
3886             case RGBFT_Float:
3887 #ifdef FILE_MAPPED_IMAGE_ALLOCATOR
3888                 if (allowFileBacking)
3889                     return new RGBFTImage<FILE_MAPPED_IMAGE_ALLOCATOR<float> >(w, h, m);
3890 #endif
3891                 return new MemoryRGBFTImage(w, h, m);
3892             case RGB_Gamma8:
3893                 return new MemoryNonlinearRGB8Image(w, h, m);
3894             case RGB_Gamma16:
3895                 return new MemoryNonlinearRGB16Image(w, h, m);
3896             case RGBA_Gamma8:
3897                 return new MemoryNonlinearRGBA8Image (w, h, m);
3898             case RGBA_Gamma16:
3899                 return new MemoryNonlinearRGBA16Image(w, h, m);
3900             case Gray_Gamma8:
3901                 return new MemoryNonlinearGray8Image(w, h, m);
3902             case Gray_Gamma16:
3903                 return new MemoryNonlinearGray16Image(w, h, m);
3904             case GrayA_Gamma8:
3905                 return new MemoryNonlinearGrayA8Image(w, h, m);
3906             case GrayA_Gamma16:
3907                 return new MemoryNonlinearGrayA16Image(w, h, m);
3908             default:
3909                 throw POV_EXCEPTION_STRING("Image::Create Exception TODO"); // TODO FIXME WIP
3910         }
3911     }
3912     catch(std::bad_alloc&)
3913     {
3914         throw POV_EXCEPTION(kOutOfMemoryErr, "Insufficient memory to allocate intermediate image storage.");
3915     }
3916 }
3917 
Read(ImageFileType type,IStream * file,const ReadOptions & options)3918 Image *Image::Read(ImageFileType type, IStream *file, const ReadOptions& options)
3919 {
3920     #ifdef POV_SYS_IMAGE_TYPE
3921         if (type == SYS)
3922             type = POV_SYS_IMAGE_TYPE;
3923     #endif
3924 
3925     switch (type)
3926     {
3927         case HDR:
3928             return (HDR::Read(file, options));
3929 
3930         case EXR:
3931 #ifndef OPENEXR_MISSING
3932             return (OpenEXR::Read(file, options));
3933 #else
3934             throw POV_EXCEPTION(kCannotOpenFileErr,
3935 "This unofficial POV-Ray binary was built without support for the OpenEXR \
3936 file format.  You must either use an official POV-Ray binary or recompile \
3937 the POV-Ray sources on a system providing you with the OpenEXR library \
3938 to make use of this facility.  Alternatively, you may use any of the \
3939 following built-in formats: HDR.");
3940             return nullptr;
3941 #endif
3942 
3943         case PNG:
3944 #ifndef LIBPNG_MISSING
3945             return (Png::Read(file, options));
3946 #else
3947             throw POV_EXCEPTION(kCannotOpenFileErr,
3948 "This unofficial POV-Ray binary was built without support for the PNG \
3949 file format.  You must either use an official POV-Ray binary or recompile \
3950 the POV-Ray sources on a system providing you with the libPNG library \
3951 to make use of this facility.  Alternatively, you may use any of the \
3952 following built-in formats: GIF, TGA, IFF, PGM, PPM, BMP.");
3953             return nullptr;
3954 #endif
3955 
3956         case GIF:
3957             return (Gif::Read(file, options, false));
3958 
3959         case POT:
3960             return (Gif::Read(file, options, true));
3961 
3962         case TGA:
3963             return (Targa::Read(file, options));
3964 
3965         case JPEG:
3966 #ifndef LIBJPEG_MISSING
3967             return (Jpeg::Read(file, options));
3968 #else
3969             throw POV_EXCEPTION(kCannotOpenFileErr,
3970 "This unofficial POV-Ray binary was built without support for the JPEG \
3971 file format.  You must either use an official POV-Ray binary or recompile \
3972 the POV-Ray sources on a system providing you with the libJPEG library \
3973 to make use of this facility.  Alternatively, you may use any of the \
3974 following built-in formats: GIF, TGA, IFF, PGM, PPM, BMP.");
3975             return nullptr;
3976 #endif
3977 
3978         case IFF:
3979             return (Iff::Read(file, options));
3980 
3981         case PGM:
3982             return (Netpbm::Read(file, options));
3983 
3984         case PPM:
3985             return (Netpbm::Read(file, options));
3986 
3987         case BMP:
3988             return (Bmp::Read(file, options));
3989 
3990         case TIFF:
3991 #ifndef LIBTIFF_MISSING
3992             return (Tiff::Read(file, options));
3993 #else
3994             throw POV_EXCEPTION(kCannotOpenFileErr,
3995 "This unofficial POV-Ray binary was built without support for the TIFF \
3996 file format.  You must either use an official POV-Ray binary or recompile \
3997 the POV-Ray sources on a system providing you with the libTIFF library \
3998 to make use of this facility.  Alternatively, you may use any of the \
3999 following built-in formats: GIF, TGA, IFF, PGM, PPM, BMP.");
4000             return nullptr;
4001 #endif
4002 
4003         case SYS:
4004             throw POV_EXCEPTION(kCannotOpenFileErr, "This platform has not defined a SYS file type");
4005             return nullptr;
4006 
4007         default :
4008             throw POV_EXCEPTION(kParamErr, "Invalid file type");
4009             return nullptr;
4010     }
4011 }
4012 
Write(ImageFileType type,OStream * file,const Image * image,const WriteOptions & options)4013 void Image::Write(ImageFileType type, OStream *file, const Image *image, const WriteOptions& options)
4014 {
4015     if (image->GetWidth() == 0 || image->GetHeight() == 0)
4016         throw POV_EXCEPTION(kParamErr, "Invalid image size for output");
4017 
4018     if (file == nullptr)
4019         throw POV_EXCEPTION(kCannotOpenFileErr, "Invalid image file");
4020 
4021 #ifdef POV_SYS_IMAGE_TYPE
4022     if (type == SYS)
4023         type = POV_SYS_IMAGE_TYPE;
4024 #endif
4025 
4026     switch (type)
4027     {
4028         case GIF:
4029         case IFF:
4030         case PGM:
4031         case TIFF:
4032         case POT:
4033             throw POV_EXCEPTION(kParamErr, "Unsupported file type for output");
4034             break;
4035 
4036         case SYS:
4037             throw POV_EXCEPTION(kCannotOpenFileErr, "This platform has not defined a SYS file type");
4038             break;
4039 
4040         case HDR:
4041             HDR::Write(file, image, options);
4042             break;
4043 
4044         case EXR:
4045 #ifndef OPENEXR_MISSING
4046             OpenEXR::Write(file, image, options);
4047 #else
4048             throw POV_EXCEPTION(kParamErr,
4049 "This unofficial POV-Ray binary was built without support for the OpenEXR \
4050 file format.  You must either use an official POV-Ray binary or recompile \
4051 the POV-Ray sources on a system providing you with the OpenEXR library \
4052 to make use of this facility.  Alternatively, you may use any of the \
4053 following built-in formats: HDR.");
4054 #endif
4055             break;
4056 
4057         case PNG:
4058 #ifndef LIBPNG_MISSING
4059             Png::Write(file, image, options);
4060 #else
4061             throw POV_EXCEPTION(kParamErr,
4062 "This unofficial POV-Ray binary was built without support for the PNG \
4063 file format.  You must either use an official POV-Ray binary or recompile \
4064 the POV-Ray sources on a system providing you with the libPNG library \
4065 to make use of this facility.  Alternatively, you may use any of the \
4066 following built-in formats: TGA, PPM, BMP.");
4067 #endif
4068             break;
4069 
4070         case TGA:
4071             Targa::Write(file, image, options);
4072             break;
4073 
4074         case PPM:
4075             Netpbm::Write(file, image, options);
4076             break;
4077 
4078         case BMP:
4079             Bmp::Write(file, image, options);
4080             break;
4081 
4082         case JPEG:
4083 #ifndef LIBJPEG_MISSING
4084             Jpeg::Write(file, image, options);
4085 #else
4086             throw POV_EXCEPTION(kParamErr,
4087 "This unofficial POV-Ray binary was built without support for the JPEG \
4088 file format.  You must either use an official POV-Ray binary or recompile \
4089 the POV-Ray sources on a system providing you with the libJPEG library \
4090 to make use of this facility.  Alternatively, you may use any of the \
4091 following built-in formats: TGA, PPM, BMP.");
4092 #endif
4093             break;
4094 
4095         default :
4096             throw POV_EXCEPTION(kParamErr, "Invalid file type");
4097             break;
4098     }
4099 }
4100 
GetRGBIndexedValue(unsigned char index,float & red,float & green,float & blue) const4101 void Image::GetRGBIndexedValue(unsigned char index, float& red, float& green, float& blue) const
4102 {
4103     switch(colormaptype)
4104     {
4105         case NoColourMap:
4106             red = 0.0f;
4107             green = 0.0f;
4108             blue = 0.0f;
4109             break;
4110         case RGBColourMap:
4111         case RGBAColourMap:
4112         case RGBFTColourMap:
4113             red = colormap[index].red;
4114             green = colormap[index].green;
4115             blue = colormap[index].blue;
4116             break;
4117     }
4118 }
4119 
GetRGBAIndexedValue(unsigned char index,float & red,float & green,float & blue,float & alpha) const4120 void Image::GetRGBAIndexedValue(unsigned char index, float& red, float& green, float& blue, float& alpha) const
4121 {
4122     switch(colormaptype)
4123     {
4124         case NoColourMap:
4125             red = 0.0f;
4126             green = 0.0f;
4127             blue = 0.0f;
4128             alpha = ALPHA_OPAQUE;
4129             break;
4130         case RGBColourMap:
4131             red = colormap[index].red;
4132             green = colormap[index].green;
4133             blue = colormap[index].blue;
4134             alpha = ALPHA_OPAQUE;
4135             break;
4136         case RGBAColourMap:
4137             red = colormap[index].red;
4138             green = colormap[index].green;
4139             blue = colormap[index].blue;
4140             alpha = colormap[index].filter; // with RGBAColourMap, .filter is actually alpha
4141             break;
4142         case RGBFTColourMap:
4143             red = colormap[index].red;
4144             green = colormap[index].green;
4145             blue = colormap[index].blue;
4146             alpha = RGBFTColour::FTtoA(colormap[index].filter, colormap[index].transm);
4147             break;
4148     }
4149 }
4150 
GetRGBFTIndexedValue(unsigned char index,float & red,float & green,float & blue,float & filter,float & transm) const4151 void Image::GetRGBFTIndexedValue(unsigned char index, float& red, float& green, float& blue, float& filter, float& transm) const
4152 {
4153     switch(colormaptype)
4154     {
4155         case NoColourMap:
4156             red = 0.0f;
4157             green = 0.0f;
4158             blue = 0.0f;
4159             filter = FT_OPAQUE;
4160             transm = FT_OPAQUE;
4161             break;
4162         case RGBColourMap:
4163             red = colormap[index].red;
4164             green = colormap[index].green;
4165             blue = colormap[index].blue;
4166             filter = transm = FT_OPAQUE;
4167             break;
4168         case RGBAColourMap:
4169             red = colormap[index].red;
4170             green = colormap[index].green;
4171             blue = colormap[index].blue;
4172             RGBFTColour::AtoFT(colormap[index].filter, filter, transm); // with RGBAColourMap, .filter is actually alpha
4173             break;
4174         case RGBFTColourMap:
4175             red = colormap[index].red;
4176             green = colormap[index].green;
4177             blue = colormap[index].blue;
4178             filter = colormap[index].filter;
4179             transm = colormap[index].transm;
4180             break;
4181     }
4182 }
4183 
SetRGBIndexedValue(unsigned char index,float red,float green,float blue)4184 void Image::SetRGBIndexedValue(unsigned char index, float red, float green, float blue)
4185 {
4186     switch(colormaptype)
4187     {
4188         case NoColourMap:
4189             break;
4190         case RGBColourMap:
4191             colormap[index].red = red;
4192             colormap[index].green = green;
4193             colormap[index].blue = blue;
4194             colormap[index].filter = 0.0f; // not used with RGBColourMap
4195             colormap[index].transm = 0.0f; // not used with RGBColourMap
4196             break;
4197         case RGBAColourMap:
4198             colormap[index].red = red;
4199             colormap[index].green = green;
4200             colormap[index].blue = blue;
4201             colormap[index].filter = ALPHA_OPAQUE; // with RGBAColourMap, .filter is actually alpha
4202             colormap[index].transm = 0.0f; // not used with RGBAColourMap
4203             break;
4204         case RGBFTColourMap:
4205             colormap[index].red = red;
4206             colormap[index].green = green;
4207             colormap[index].blue = blue;
4208             colormap[index].filter = FT_OPAQUE;
4209             colormap[index].transm = FT_OPAQUE;
4210             break;
4211     }
4212 }
4213 
SetRGBAIndexedValue(unsigned char index,float red,float green,float blue,float alpha)4214 void Image::SetRGBAIndexedValue(unsigned char index, float red, float green, float blue, float alpha)
4215 {
4216     switch(colormaptype)
4217     {
4218         case NoColourMap:
4219             break;
4220         case RGBColourMap:
4221             colormap[index].red = red;
4222             colormap[index].green = green;
4223             colormap[index].blue = blue;
4224             colormap[index].filter = 0.0f; // not used with RGBColourMap
4225             colormap[index].transm = 0.0f; // not used with RGBColourMap
4226             break;
4227         case RGBAColourMap:
4228             colormap[index].red = red;
4229             colormap[index].green = green;
4230             colormap[index].blue = blue;
4231             colormap[index].filter = alpha; // with RGBAColourMap, .filter is actually alpha
4232             colormap[index].transm = 0.0f; // not used with RGBAColourMap
4233             break;
4234         case RGBFTColourMap:
4235             colormap[index].red = red;
4236             colormap[index].green = green;
4237             colormap[index].blue = blue;
4238             RGBFTColour::AtoFT(alpha, colormap[index].filter, colormap[index].transm);
4239             break;
4240     }
4241 }
4242 
SetRGBFTIndexedValue(unsigned char index,float red,float green,float blue,float filter,float transm)4243 void Image::SetRGBFTIndexedValue(unsigned char index, float red, float green, float blue, float filter, float transm)
4244 {
4245     switch(colormaptype)
4246     {
4247         case NoColourMap:
4248             break;
4249         case RGBColourMap:
4250             colormap[index].red = red;
4251             colormap[index].green = green;
4252             colormap[index].blue = blue;
4253             colormap[index].filter = 0.0f; // not used with RGBColourMap
4254             colormap[index].transm = 0.0f; // not used with RGBColourMap
4255             break;
4256         case RGBAColourMap:
4257             colormap[index].red = red;
4258             colormap[index].green = green;
4259             colormap[index].blue = blue;
4260             colormap[index].filter = RGBFTColour::FTtoA(filter, transm); // note: filter is alpha in RGBA maps
4261             colormap[index].transm = 0.0f; // not used with RGBAColourMap
4262             break;
4263         case RGBFTColourMap:
4264             colormap[index].red = red;
4265             colormap[index].green = green;
4266             colormap[index].blue = blue;
4267             colormap[index].filter = filter;
4268             colormap[index].transm = transm;
4269             break;
4270     }
4271 }
4272 
SetRGBFTIndexedValue(unsigned char index,const RGBFTColour & col)4273 void Image::SetRGBFTIndexedValue(unsigned char index, const RGBFTColour& col)
4274 {
4275     switch(colormaptype)
4276     {
4277         case NoColourMap:
4278             break;
4279         case RGBColourMap:
4280             colormap[index].red = col.red();
4281             colormap[index].green = col.green();
4282             colormap[index].blue = col.blue();
4283             colormap[index].filter = 0.0f; // not used with RGBColourMap
4284             colormap[index].transm = 0.0f; // not used with RGBColourMap
4285             break;
4286         case RGBAColourMap:
4287             colormap[index].red = col.red();
4288             colormap[index].green = col.green();
4289             colormap[index].blue = col.blue();
4290             colormap[index].filter = col.FTtoA(); // note: filter is alpha in RGBA maps
4291             colormap[index].transm = 0.0f; // not used with RGBAColourMap
4292             break;
4293         case RGBFTColourMap:
4294             colormap[index].red = col.red();
4295             colormap[index].green = col.green();
4296             colormap[index].blue = col.blue();
4297             colormap[index].filter = col.filter();
4298             colormap[index].transm = col.transm();
4299             break;
4300     }
4301 }
4302 
GetIndexedValue(unsigned int,unsigned int)4303 unsigned char Image::GetIndexedValue(unsigned int, unsigned int)
4304 {
4305     return 0;
4306 }
4307 
SetIndexedValue(unsigned int x,unsigned int y,unsigned char index)4308 void Image::SetIndexedValue(unsigned int x, unsigned int y, unsigned char index)
4309 {
4310     CHECK_BOUNDS(x, y);
4311     switch(colormaptype)
4312     {
4313         case NoColourMap:
4314             SetBitValue(x,y, false);
4315             break;
4316         case RGBColourMap:
4317             SetRGBValue(x, y, colormap[index].red, colormap[index].green, colormap[index].blue);
4318             break;
4319         case RGBAColourMap:
4320             SetRGBAValue(x, y, colormap[index].red, colormap[index].green, colormap[index].blue, colormap[index].filter); // with RGBAColourMap, .filter is actually alpha
4321             break;
4322         case RGBFTColourMap:
4323             SetRGBFTValue(x, y, colormap[index].red, colormap[index].green, colormap[index].blue, colormap[index].filter, colormap[index].transm);
4324             break;
4325     }
4326 }
4327 
GetRGBValue(unsigned int x,unsigned int y,RGBColour & colour,bool premul) const4328 void Image::GetRGBValue(unsigned int x, unsigned int y, RGBColour& colour, bool premul) const
4329 {
4330     if (premul && !premultiplied && HasTransparency())
4331     {
4332         // data is non-premultiplied, but caller expects premultiplied data
4333         float alpha;
4334         GetRGBAValue(x, y, colour.red(), colour.green(), colour.blue(), alpha);
4335         AlphaPremultiply(colour, alpha);
4336     }
4337     if (!premul && premultiplied && HasTransparency())
4338     {
4339         // data is premultiplied, but caller expects non-premultiplied data
4340         float alpha;
4341         GetRGBAValue(x, y, colour.red(), colour.green(), colour.blue(), alpha);
4342         AlphaUnPremultiply(colour, alpha);
4343     }
4344     else
4345     {
4346         GetRGBValue(x, y, colour.red(), colour.green(), colour.blue());
4347     }
4348 }
GetRGBTValue(unsigned int x,unsigned int y,RGBTColour & colour,bool premul) const4349 void Image::GetRGBTValue(unsigned int x, unsigned int y, RGBTColour& colour, bool premul) const
4350 {
4351     float alpha;
4352     GetRGBAValue(x, y, colour.red(), colour.green(), colour.blue(), alpha);
4353     if (premul && !premultiplied && HasTransparency())
4354     {
4355         // data is non-premultiplied, but caller expects premultiplied data
4356         AlphaPremultiply(colour.rgb(), alpha);
4357     }
4358     else if (!premul && premultiplied && HasTransparency())
4359     {
4360         // data is premultiplied, but caller expects non-premultiplied data
4361         AlphaUnPremultiply(colour.rgb(), alpha);
4362     }
4363     colour.transm() = 1.0 - alpha;
4364 }
GetRGBFTValue(unsigned int x,unsigned int y,RGBFTColour & colour,bool premul) const4365 void Image::GetRGBFTValue(unsigned int x, unsigned int y, RGBFTColour& colour, bool premul) const
4366 {
4367     GetRGBFTValue(x, y, colour.red(), colour.green(), colour.blue(), colour.filter(), colour.transm());
4368     if (premul && !premultiplied && HasTransparency())
4369     {
4370         // data is non-premultiplied, but caller expects premultiplied data
4371         AlphaPremultiply(colour);
4372     }
4373     else if (!premul && premultiplied && HasTransparency())
4374     {
4375         // data is premultiplied, but caller expects non-premultiplied data
4376         AlphaUnPremultiply(colour);
4377     }
4378 }
4379 
GetColourMapSize() const4380 unsigned int Image::GetColourMapSize() const
4381 {
4382     return colormap.size();
4383 }
4384 
GetColourMap(vector<RGBMapEntry> & m) const4385 void Image::GetColourMap(vector<RGBMapEntry>& m) const
4386 {
4387     m.resize(colormap.size());
4388     for(size_t i = 0; i < colormap.size(); i++)
4389         GetRGBIndexedValue((unsigned char)(i), m[i].red, m[i].green, m[i].blue);
4390 }
4391 
GetColourMap(vector<RGBAMapEntry> & m) const4392 void Image::GetColourMap(vector<RGBAMapEntry>& m) const
4393 {
4394     m.resize(colormap.size());
4395     for(size_t i = 0; i < colormap.size(); i++)
4396         GetRGBAIndexedValue((unsigned char)(i), m[i].red, m[i].green, m[i].blue, m[i].alpha);
4397 }
4398 
GetColourMap(vector<RGBFTMapEntry> & m) const4399 void Image::GetColourMap(vector<RGBFTMapEntry>& m) const
4400 {
4401     m.resize(colormap.size());
4402     for(size_t i = 0; i < colormap.size(); i++)
4403         GetRGBFTIndexedValue((unsigned char)(i), m[i].red, m[i].green, m[i].blue, m[i].filter, m[i].transm);
4404 }
4405 
SetColourMap(const vector<RGBMapEntry> & m)4406 void Image::SetColourMap(const vector<RGBMapEntry>& m)
4407 {
4408     colormap.resize(max(m.size(), sizeof(unsigned char) * 256));
4409     colormaptype = RGBColourMap;
4410     colormap.assign(m.begin(), m.end());
4411 }
4412 
SetColourMap(const vector<RGBAMapEntry> & m)4413 void Image::SetColourMap(const vector<RGBAMapEntry>& m)
4414 {
4415     colormap.resize(max(m.size(), sizeof(unsigned char) * 256));
4416     colormaptype = RGBAColourMap;
4417     colormap.assign(m.begin(), m.end());
4418 }
4419 
SetColourMap(const vector<RGBFTMapEntry> & m)4420 void Image::SetColourMap(const vector<RGBFTMapEntry>& m)
4421 {
4422     colormap.resize(max(m.size(), sizeof(unsigned char) * 256));
4423     colormaptype = RGBFTColourMap;
4424     colormap.assign(m.begin(), m.end());
4425 }
4426 
4427 }
4428