-
Notifications
You must be signed in to change notification settings - Fork 16
/
image.hpp
405 lines (392 loc) · 16.5 KB
/
image.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
/* image.hpp -- classes for sampled (indexed, gray and rgb) images
* by [email protected] Wed Feb 27 09:24:47 CET 2002
*/
/* Imp: keep future transparency in toIndexed(...) */
#ifdef __GNUC__
#ifndef __clang__
#pragma interface
#endif
#endif
#ifndef SAMPLED_HPP
#define SAMPLED_HPP 1
#include "config2.h"
#include "gensi.hpp"
class Image {
public:
class RGB;
class Gray;
class Indexed;
/** Generic, sampled, rectangular image data. Abstract class.
* Each sample is 1, 2, 4 or 8 bits. Regions:
* beg..head-1: comment, ignored (e.g unused part of the indexed palette)
* headp..rowbeg-1: header: not predicted or compressed (e.g the indexed palette)
* rowbeg+0*rlen..rowbeg+0*rlen+rlen-1: sample data of the 0th row, compressed and predicted
* rowbeg+1*rlen..rowbeg+1*rlen+rlen-1: sample data of the 1st row
* rowbeg+2*rlen..rowbeg+2*rlen+rlen-1: sample data of the 1st row
* ...
* rowbeg+(h-1)*rlen..rowbeg+h*rlen-1: sample data of the last row
* trail..beg+len: trailer, ignored. Its length must be >=bpc.
* TODO: Remove trail, and see what breaks (e.g. setBpc).
*/
class Sampled: public SimBuffer::Flat {
public:
/** Can hold 1 component of a sample of a single pixel. */
typedef unsigned char sample_t;
/** Can hold a height or depth of the image */
typedef unsigned int dimen_t;
/** Can hold a row length (in byte), which isn't greater than 3*(image width). */
typedef unsigned int rlen_t;
/** RGB = (red<<16)+(green<<8)+(blue). red, green and blue are 0..255 */
#if SIZEOF_LONG>4 && SIZEOF_INT>=4
typedef unsigned int rgb_t;
#else
typedef unsigned long rgb_t;
#endif
BEGIN_STATIC_ENUM1(unsigned char)
TY_INDEXED=1, TY_GRAY=2, TY_RGB=3, TY_OTHER=4, TY_BLACKBOX=5
END_STATIC_ENUM()
BEGIN_STATIC_ENUM1(unsigned char) // static const unsigned char
CS_UNKNOWN=0, /* error/unspecified */
CS_GRAYSCALE=1, /* monochrome */
CS_RGB=2, /* red/green/blue */
CS_YCbCr=3, /* Y/Cb/Cr (also known as YUV) */
CS_CMYK=4, /* C/M/Y/K */
CS_YCCK=5, /* Y/Cb/Cr/K */
CS_Indexed_RGB=12
END_STATIC_ENUM()
static const unsigned char cs2cpp[6];
/** @return NULLP on error */
static char const *cs2devcs(unsigned char cs);
protected:
char *headp;
char *rowbeg;
char *trail;
/** Extra offset */
slen_t xoffs;
/** Length of one row, in bytes. Each row must begin on a byte boundary, so
* extra bits are appended after the rightmost pixel. These bits are
* arbitrary, and are ignored by the PostScript interpreter.
*/
rlen_t rlen;
/** Image height, in pixels. */
dimen_t ht;
/** Image width, in pixels. */
dimen_t wd;
/** Color space. */
unsigned char cs;
/** Components per pixel. (number of planes, image depth). 1 for indexed,
* 1 for gray, 3 for RGB
*/
unsigned char cpp;
/** BitsPerComponent: 1, 2, 4 or 8. PostScript allows 12 too. */
unsigned char bpc;
/** Transparent color value. Imp: ... */
rgb_t transpc;
/** Image type, TY_... */
unsigned char ty;
/** Initializes various fields, allocates memory. Called from descendants'
* constructors.
*/
void init(slen_t l_comment, slen_t l_header, dimen_t wd_, dimen_t ht_,
unsigned char bpc_, unsigned char ty_, unsigned char cpp_);
/** Convert samples, make bpc=8, multiplication. */
void to8mul();
/** Convert samples, make bpc=8, no multiplication. */
void to8nomul();
/** Calls copyRGBRow.
* @return an Image::Indexed version of (this) iff the number of
* colors<=256. Otherwise, returns NULLP.
*/
Indexed* toIndexed0()/* const*/;
/** No averaging is done, only the red component is extracted */
Gray* toGray0(unsigned char bpc_);
RGB * toRGB0(unsigned char bpc_);
/** @return if any pixels are not gray: false. otherwise: true or false. */
public:
inline bool hasTransp() const { return transpc!=0x1000000UL; }
virtual bool canGray() const =0;
/** @return an RGB BitsPerComponent number (1,2,4 or 8) to which the image
* could be converted without any loss. The default implementation calls
* copyRGBRow().
*/
virtual unsigned char minRGBBpc() const;
inline virtual ~Sampled() { delete [] const_cast<char*>(beg); }
/** Copies whichrow as wd*3 bytes (R0,G0,B0,R1,G1,B1...) to `to' */
virtual void copyRGBRow(char *to, dimen_t whichrow) const =0;
virtual bool hasPixelRGB(Image::Sampled::rgb_t rgb) const;
inline char *getRowbeg() const { return rowbeg; }
inline dimen_t getWd() const { return wd; }
inline dimen_t getHt() const { return ht; }
inline unsigned char getTy() const { return ty; }
inline unsigned char getBpc() const { return bpc; }
inline unsigned char getCpp() const { return cpp; }
inline unsigned char getCs() const { return cs; }
inline slen_t getXoffs() const { return xoffs; }
inline rlen_t getRlen() const { return rlen; }
inline rgb_t getTranspc() const { return transpc; }
inline char *getHeadp() const { return headp; }
/** Convert samples, make bpc=8. */
virtual void to8() =0;
/** @return NULLP if too many colors for indexed; otherwise a new Image::Indexed.
* The caller should `delete' (this) if toIndexed()==NULLP.
*/
virtual /*Image::*/Indexed* toIndexed() =0;
virtual /*Image::*/RGB* toRGB(unsigned char bpc_) =0;
virtual /*Image::*/Gray* toGray(unsigned char bpc_) =0;
// virtual void setBpc(unsigned char bpc_) =0;
friend GenBuffer::Writable& operator<<(GenBuffer::Writable&, /*Image::*/Sampled const&);
/** @return address of static buffer: "#RRGGBB" */
static char *rgb2webhash(rgb_t);
/** @return (this) or an image containing (this) composed with alpha
* channel `al'
*/
virtual Sampled* addAlpha(/*Image::*/Gray *al) =0;
/** assert(al.bpp=8) etc. Imp: document this */
static Indexed* addAlpha0(Indexed *iimg, Gray *al);
};
class Indexed: public Sampled {
public:
/** @param ncols_ must be >= the colors used */
Indexed(dimen_t wd_, dimen_t ht_, unsigned short ncols_, unsigned char bpc_);
/** This includes the transparent color as well. */
inline unsigned short getNcols() const { return (rowbeg-headp)/3; }
/** Destroys the color table, and creates one with ncols_ colors.
* @param ncols_ must be <= the ncols_ specified in the constructor
*/
void setNcols(unsigned short ncols_);
/** Decreases the size of the palette (forgets last colors) to the
* specified amount.
*/
void setNcolsMove(unsigned short ncols_);
void setPal(unsigned char coloridx, rgb_t rgb);
rgb_t getPal(unsigned char coloridx) const;
/** @param coloridx must be >=0, transp must be -1 */
void setTransp(unsigned char coloridx);
/** @return new hasTransp */
bool setTranspc(rgb_t color);
/** Returns like setTranspc, but doesn't change the image.
* @return new hasTransp
*/
bool wouldSetTranspc(rgb_t color) const;
/** Like setTranspc, but if it makes any changes, then it calls
* packPal() and changes back bpc to its old value.
*/
void setTranspcAndRepack(rgb_t color);
virtual void copyRGBRow(char *to, dimen_t whichrow) const;
/* virtual bool hasPixelRGB(Image::Sampled::rgb_t rgb) const; */
/** Packs (compresses) the palette so that it will be continuous in
* 0..ncols-1, and each color will be used exactly once. The
* transparent color (if present) will become black. As a side-effect,
* packPal() may set (this)->bpc=8.
*/
void packPal();
virtual void to8();
virtual /*Image::*/Indexed* toIndexed();
virtual /*Image::*/RGB* toRGB(unsigned char bpc_);
virtual /*Image::*/Gray* toGray(unsigned char bpc_);
virtual bool canGray() const;
inline signed short getTransp() const { return transp; }
inline signed short getClearTransp() { signed short ret=transp; transp=-1; return ret; }
/** if (transp>0) transp=0;, converts image data. Does not change bpc. */
void makeTranspZero();
virtual unsigned char minRGBBpc() const;
/** Separates the current image into Indexed1 images. The caller is
* recommended to call packPal() first to reduce the number of required
* images.
* As a side-effect,
* separate() may set (this)->bpc=8.
* @return the array of images after full color separation: that is
* a dynamically allocated array of `getNcols()-(getTransp()!=-1)'
* Indexed images: each image is Indexed1, color 0 is opaque (with the
* color obtained from (this)), color 1 is transparent. The returned
* array is NULLP-terminated.
*/
Indexed **separate();
/** Also calls packPal(). As a side effect, changes all transparent
* pixels to color index 0.
* @return NULLP if no transparent pixels.
*/
Indexed *calcAlpha();
/** Deletes all elements of p, but not p itself.
* @param p a NULLP-terminated list of (Indexed*)s.
*/
static void delete_separated(Indexed **p);
/** Reorganizes the image so it will have the specified bpc. Issues a
* runtime error if the specified bpc cannot be achieved.
* @param bpc_ the desired bpc, or 0: the best achievable.
*/
virtual void setBpc(unsigned char bpc_);
void dumpDebug(GenBuffer::Writable& gw);
protected:
/* Index of the transparent color, or -1. */
signed short transp;
virtual /*Image::*/Sampled* addAlpha(/*Image::*/Gray *al);
/** Sorts the palette colors in lexicographic, stable order.
* Called from packPal() to get a consistent palette.
*/
void sortPal();
};
class Gray: public Sampled {
public:
Gray(dimen_t wd_, dimen_t ht_, unsigned char bpc_);
virtual void copyRGBRow(char *to, dimen_t whichrow) const;
virtual bool hasPixelRGB(Image::Sampled::rgb_t rgb) const;
virtual void to8();
virtual /*Image::*/Indexed* toIndexed();
virtual bool canGray() const;
// virtual void setBpc(unsigned char bpc_);
virtual /*Image::*/RGB * toRGB(unsigned char bpc_);
virtual /*Image::*/Gray * toGray(unsigned char bpc_);
virtual /*Image::*/Sampled* addAlpha(/*Image::*/Gray *al);
/** Calls to8(). */
void calcExtrema(unsigned char &lightest, unsigned char &darkest);
};
class RGB: public Sampled {
public:
RGB(dimen_t wd_, dimen_t ht_, unsigned char bpc_);
virtual void copyRGBRow(char *to, dimen_t whichrow) const;
/* virtual bool hasPixelRGB(Image::Sampled::rgb_t rgb) const; */
virtual void to8();
virtual /*Image::*/Indexed* toIndexed();
virtual bool canGray() const;
// virtual void setBpc(unsigned char bpc_);
virtual /*Image::*/RGB * toRGB(unsigned char bpc_);
virtual /*Image::*/Gray * toGray(unsigned char bpc_);
virtual /*Image::*/Sampled* addAlpha(/*Image::*/Gray *al);
};
/** Avoid including <stdio.h> */
typedef void *filep_t;
/** Describes a driver that can load a specific image file format. */
struct Loader {
/** Filter::UngetFILED */
class UFD;
/** A function that can (allocate and) load a sampled image. Never
* returns NULL. On error, it calls Error::.... The filep_t argument
* should be really cast back to FILE*. The reader must fclose the FILE*.
*/
// typedef Sampled*(*reader_t)(filep_t, SimBuffer::Flat const& loadHints);
typedef Sampled*(*reader_t)(UFD* ufd, SimBuffer::Flat const& loadHints);
BEGIN_STATIC_ENUM1(unsigned) MAGIC_LEN=64 END_STATIC_ENUM()
/** A function that checks the magic numbers at the beginning of a file
* (already read into buf), and returns NULL if it cannot load an image
* of that type, or a reader_t that will load the image. If (and only if!)
* file is shorter than 64 bytes, the buf is padded with '\000' bytes.
* @param f may read from freely if necessary (MAGIC_LEN is short), but
* has to call rewind(f) before reading
*/
typedef reader_t(*checker_t)(char buf[MAGIC_LEN], char bufend[MAGIC_LEN], SimBuffer::Flat const& loadHints, UFD* ufd);
/** A null-terminated, compact string describing (not defining!) the image
* file format.
* Examples: "GIF", "XPM", "PNM"
*/
char const*format;
checker_t checker;
/** Null or next loader. */
Loader *next;
};
/** Registers a new type of image Loader, i.e a new image file format. The
* new image format will be put in front of all others, and will be checked
* first
*/
static void register0(Loader *);
/** Loads the image contained in te file `filename'.
* @param format NULLP is unknown (load any format)
* or an Image::Loader::format already registered
*/
static Sampled* load(Loader::UFD* ufd, SimBuffer::Flat const& loadHints, char const* format);
static Sampled* load(char const *filename, SimBuffer::Flat const& loadHints, filep_t stdin_f=(filep_t*)NULLP, char const* format=(char const*)NULLP);
/* Prints the list of available Loaders (->format), separated by spaces.
* Returns the number of available Loaders. Prepends a space if >= loaders.
*/
static unsigned printLoaders(GenBuffer::Writable &);
/** SampleFormat constants */
BEGIN_STATIC_ENUM(unsigned, sf_t)
SF_None=0, /* no specific sample format */
SF_Opaque=1,
SF_Transparent=2,
SF_Gray1=3,
SF_Indexed1=4,
SF_Mask=5,
SF_Transparent2=6,
SF_Gray2=7,
SF_Indexed2=8,
SF_Transparent4=9,
SF_Rgb1=10,
SF_Gray4=11,
SF_Indexed4=12,
SF_Transparent8=13,
SF_Rgb2=14,
SF_Gray8=15,
SF_Indexed8=16,
SF_Rgb4=17,
SF_Rgb8=18,
SF_Asis=19,
SF_Bbox=20,
SF_max=31
END_STATIC_ENUM()
/** Contains (and memory-manages) an image, and optimization information
* as a cache.
*
* A SampledInfo contains an image in a canonical format. That is, if two
* images have the same RGB8 (identical width, height and pixels) or
* blackbox (identical bytes) representation, and SampledInfo{} are
* created for both of them, it is guaranteed that the two SampledInfo{}s
* contain the same image data (width, height, canGray, minRGBBpc,
* SampleFormat (except for bpc), pixel data, palette (same size, colors
* and color order)).
*/
class SampledInfo {
public:
/** This constructor call takes ownership of the `img_' pointer: it either
* reuses the original image (and will delete it in ~SampledInfo), or it
* immediately deletes the image, and uses another image.
*/
SampledInfo(Sampled *img_);
~SampledInfo();
inline Sampled* getImage() const { return img; }
/**
* Source image, may be modified even if TryOnly==false. If
* modified, the original will be freed.
* @param sf desired sample format, see Image::SF_* constants
* @param WarningOK if false: make the conversion fail if it would produces
* a Warning
* @param TryOnly if true: don't do the real conversion (but may do auxilary,
* idempontent, helper conversion), assume it has succeeded
* @param Transparent: as part of the conversion, try to make this RGB color
* transparent
* @return true iff the conversion succeeded. Note that img may be the same
* pointer even when true is returned. If false is returned, keeps
* the image unchanged.
*/
bool setSampleFormat(sf_t sf, bool WarningOK, bool TryOnly, Sampled::rgb_t Transparent);
inline Indexed **getImgs() const { return imgs; }
inline Sampled *getImg() const { return img; }
inline unsigned getNncols() const { return nncols; }
void separate();
inline bool canGrayy() const { return canGray; }
inline unsigned char minRGBBpcc() const { return minRGBBpc; }
inline bool hasTranspp() const { return hasTransp; }
inline unsigned char minGrayBpcc() const { return canGray ? minRGBBpc : 0; }
inline void clearTransp() { hasTransp=false; }
protected:
bool hasTransp;
/** Number of non-transparent colors, or 257 if >=257. */
unsigned nncols;
/** Has only gray colors. */
bool canGray;
unsigned char minRGBBpc;
Sampled *img;
/** The array of images after full color separation. May be NULLP (default),
* or a dynamically allocated array of `nncols' Indexed images: each
* image is Indexed1, color 0 is opaque (with any value), color 1
* is transparent.
*/
Indexed **imgs;
sf_t sf;
};
};
/** Dumps this Image as a rawbits PPM file (plus a comment indicating transparency)
* @return the Writable.
*/
GenBuffer::Writable& operator<<(GenBuffer::Writable&, Image::Sampled const&);
#endif