1 /*
2 * tkImgPNG.c --
3 *
4 * A Tk photo image file handler for PNG files.
5 *
6 * Copyright © 2006-2008 Muonics, Inc.
7 * Copyright © 2008 Donal K. Fellows
8 *
9 * See the file "license.terms" for information on usage and redistribution of
10 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
11 */
12
13 #include "tkInt.h"
14
15 #define PNG_INT32(a,b,c,d) \
16 (((long)(a) << 24) | ((long)(b) << 16) | ((long)(c) << 8) | (long)(d))
17 #define PNG_BLOCK_SZ 1024 /* Process up to 1k at a time. */
18 #define PNG_MIN(a, b) (((a) < (b)) ? (a) : (b))
19
20 /*
21 * Every PNG image starts with the following 8-byte signature.
22 */
23
24 #define PNG_SIG_SZ 8
25 static const unsigned char pngSignature[] = {
26 137, 80, 78, 71, 13, 10, 26, 10
27 };
28
29 static const int startLine[8] = {
30 0, 0, 0, 4, 0, 2, 0, 1
31 };
32
33 /*
34 * Chunk type flags.
35 */
36
37 #define PNG_CF_ANCILLARY 0x20000000L /* Non-critical chunk (can ignore). */
38 #define PNG_CF_PRIVATE 0x00100000L /* Application-specific chunk. */
39 #define PNG_CF_RESERVED 0x00001000L /* Not used. */
40 #define PNG_CF_COPYSAFE 0x00000010L /* Opaque data safe for copying. */
41
42 /*
43 * Chunk types, not all of which have support implemented. Note that there are
44 * others in the official extension set which we will never support (as they
45 * are officially deprecated).
46 */
47
48 #define CHUNK_IDAT PNG_INT32('I','D','A','T') /* Pixel data. */
49 #define CHUNK_IEND PNG_INT32('I','E','N','D') /* End of Image. */
50 #define CHUNK_IHDR PNG_INT32('I','H','D','R') /* Header. */
51 #define CHUNK_PLTE PNG_INT32('P','L','T','E') /* Palette. */
52
53 #define CHUNK_bKGD PNG_INT32('b','K','G','D') /* Background Color */
54 #define CHUNK_cHRM PNG_INT32('c','H','R','M') /* Chroma values. */
55 #define CHUNK_gAMA PNG_INT32('g','A','M','A') /* Gamma. */
56 #define CHUNK_hIST PNG_INT32('h','I','S','T') /* Histogram. */
57 #define CHUNK_iCCP PNG_INT32('i','C','C','P') /* Color profile. */
58 #define CHUNK_iTXt PNG_INT32('i','T','X','t') /* Internationalized
59 * text (comments,
60 * etc.) */
61 #define CHUNK_oFFs PNG_INT32('o','F','F','s') /* Image offset. */
62 #define CHUNK_pCAL PNG_INT32('p','C','A','L') /* Pixel calibration
63 * data. */
64 #define CHUNK_pHYs PNG_INT32('p','H','Y','s') /* Physical pixel
65 * dimensions. */
66 #define CHUNK_sBIT PNG_INT32('s','B','I','T') /* Significant bits */
67 #define CHUNK_sCAL PNG_INT32('s','C','A','L') /* Physical scale. */
68 #define CHUNK_sPLT PNG_INT32('s','P','L','T') /* Suggested
69 * palette. */
70 #define CHUNK_sRGB PNG_INT32('s','R','G','B') /* Standard RGB space
71 * declaration. */
72 #define CHUNK_tEXt PNG_INT32('t','E','X','t') /* Plain Latin-1
73 * text. */
74 #define CHUNK_tIME PNG_INT32('t','I','M','E') /* Time stamp. */
75 #define CHUNK_tRNS PNG_INT32('t','R','N','S') /* Transparency. */
76 #define CHUNK_zTXt PNG_INT32('z','T','X','t') /* Compressed Latin-1
77 * text. */
78
79 /*
80 * Color flags.
81 */
82
83 #define PNG_COLOR_INDEXED 1
84 #define PNG_COLOR_USED 2
85 #define PNG_COLOR_ALPHA 4
86
87 /*
88 * Actual color types.
89 */
90
91 #define PNG_COLOR_GRAY 0
92 #define PNG_COLOR_RGB (PNG_COLOR_USED)
93 #define PNG_COLOR_PLTE (PNG_COLOR_USED | PNG_COLOR_INDEXED)
94 #define PNG_COLOR_GRAYALPHA (PNG_COLOR_GRAY | PNG_COLOR_ALPHA)
95 #define PNG_COLOR_RGBA (PNG_COLOR_USED | PNG_COLOR_ALPHA)
96
97 /*
98 * Compression Methods.
99 */
100
101 #define PNG_COMPRESS_DEFLATE 0
102
103 /*
104 * Filter Methods.
105 */
106
107 #define PNG_FILTMETH_STANDARD 0
108
109 /*
110 * Interlacing Methods.
111 */
112
113 #define PNG_INTERLACE_NONE 0
114 #define PNG_INTERLACE_ADAM7 1
115
116 /*
117 * State information, used to store everything about the PNG image being
118 * currently parsed or created.
119 */
120
121 typedef struct {
122 /*
123 * PNG data source/destination channel/object/byte array.
124 */
125
126 Tcl_Channel channel; /* Channel for from-file reads. */
127 Tcl_Obj *objDataPtr;
128 unsigned char *strDataBuf; /* Raw source data for from-string reads. */
129 TkSizeT strDataLen; /* Length of source data. */
130 unsigned char *base64Data; /* base64 encoded string data. */
131 unsigned char base64Bits; /* Remaining bits from last base64 read. */
132 unsigned char base64State; /* Current state of base64 decoder. */
133 double alpha; /* Alpha from -format option. */
134
135 /*
136 * Image header information.
137 */
138
139 unsigned char bitDepth; /* Number of bits per pixel. */
140 unsigned char colorType; /* Grayscale, TrueColor, etc. */
141 unsigned char compression; /* Compression Mode (always zlib). */
142 unsigned char filter; /* Filter mode (0 - 3). */
143 unsigned char interlace; /* Type of interlacing (if any). */
144 unsigned char numChannels; /* Number of channels per pixel. */
145 unsigned char bytesPerPixel;/* Bytes per pixel in scan line. */
146 int bitScale; /* Scale factor for RGB/Gray depths < 8. */
147 int currentLine; /* Current line being unfiltered. */
148 unsigned char phase; /* Interlacing phase (0..6). */
149 Tk_PhotoImageBlock block;
150 int blockLen; /* Number of bytes in Tk image pixels. */
151
152 /*
153 * For containing data read from PLTE (palette) and tRNS (transparency)
154 * chunks.
155 */
156
157 int paletteLen; /* Number of PLTE entries (1..256). */
158 int useTRNS; /* Flag to indicate whether there was a
159 * palette given. */
160 struct {
161 unsigned char red;
162 unsigned char green;
163 unsigned char blue;
164 unsigned char alpha;
165 } palette[256]; /* Palette RGB/Transparency table. */
166 unsigned char transVal[6]; /* Fully-transparent RGB/Gray Value. */
167
168 /*
169 * For compressing and decompressing IDAT chunks.
170 */
171
172 Tcl_ZlibStream stream; /* Inflating or deflating stream; this one is
173 * not bound to a Tcl command. */
174 Tcl_Obj *lastLineObj; /* Last line of pixels, for unfiltering. */
175 Tcl_Obj *thisLineObj; /* Current line of pixels to process. */
176 int lineSize; /* Number of bytes in a PNG line. */
177 int phaseSize; /* Number of bytes/line in current phase. */
178
179
180 /*
181 * Physical size: pHYS chunks.
182 */
183
184 double DPI;
185 double aspect;
186
187 } PNGImage;
188
189 /*
190 * Maximum size of various chunks.
191 */
192
193 #define PNG_PLTE_MAXSZ 768 /* 3 bytes/RGB entry, 256 entries max */
194 #define PNG_TRNS_MAXSZ 256 /* 1-byte alpha, 256 entries max */
195
196 /*
197 * Forward declarations of non-global functions defined in this file:
198 */
199
200 static void ApplyAlpha(PNGImage *pngPtr);
201 static int CheckColor(Tcl_Interp *interp, PNGImage *pngPtr);
202 static inline int CheckCRC(Tcl_Interp *interp, PNGImage *pngPtr,
203 unsigned long calculated);
204 static void CleanupPNGImage(PNGImage *pngPtr);
205 static int DecodeLine(Tcl_Interp *interp, PNGImage *pngPtr);
206 static int DecodePNG(Tcl_Interp *interp, PNGImage *pngPtr,
207 Tcl_Obj *fmtObj, Tk_PhotoHandle imageHandle,
208 int destX, int destY);
209 static int EncodePNG(Tcl_Interp *interp,
210 Tk_PhotoImageBlock *blockPtr, PNGImage *pngPtr,
211 Tcl_Obj *metadataInObj);
212 static int FileMatchPNG(Tcl_Interp *interp, Tcl_Channel chan,
213 const char *fileName, Tcl_Obj *fmtObj,
214 Tcl_Obj *metadataInObj, int *widthPtr,
215 int *heightPtr, Tcl_Obj *metadataOut);
216 static int FileReadPNG(Tcl_Interp *interp, Tcl_Channel chan,
217 const char *fileName, Tcl_Obj *fmtObj,
218 Tcl_Obj *metadataInObj, Tk_PhotoHandle imageHandle,
219 int destX, int destY, int width, int height,
220 int srcX, int srcY, Tcl_Obj *metadataOutPtr);
221 static int FileWritePNG(Tcl_Interp *interp, const char *filename,
222 Tcl_Obj *fmtObj, Tcl_Obj *metadataInObj,
223 Tk_PhotoImageBlock *blockPtr);
224 static int InitPNGImage(Tcl_Interp *interp, PNGImage *pngPtr,
225 Tcl_Channel chan, Tcl_Obj *objPtr, int dir);
226 static inline unsigned char Paeth(int a, int b, int c);
227 static int ParseFormat(Tcl_Interp *interp, Tcl_Obj *fmtObj,
228 PNGImage *pngPtr);
229 static int ReadBase64(Tcl_Interp *interp, PNGImage *pngPtr,
230 unsigned char *destPtr, size_t destSz,
231 unsigned long *crcPtr);
232 static int ReadByteArray(Tcl_Interp *interp, PNGImage *pngPtr,
233 unsigned char *destPtr, size_t destSz,
234 unsigned long *crcPtr);
235 static int ReadData(Tcl_Interp *interp, PNGImage *pngPtr,
236 unsigned char *destPtr, size_t destSz,
237 unsigned long *crcPtr);
238 static int ReadChunkHeader(Tcl_Interp *interp, PNGImage *pngPtr,
239 size_t *sizePtr, unsigned long *typePtr,
240 unsigned long *crcPtr);
241 static int ReadIDAT(Tcl_Interp *interp, PNGImage *pngPtr,
242 int chunkSz, unsigned long crc);
243 static int ReadIHDR(Tcl_Interp *interp, PNGImage *pngPtr);
244 static inline int ReadInt32(Tcl_Interp *interp, PNGImage *pngPtr,
245 unsigned long *resultPtr, unsigned long *crcPtr);
246 static int ReadPLTE(Tcl_Interp *interp, PNGImage *pngPtr,
247 int chunkSz, unsigned long crc);
248 static int ReadTRNS(Tcl_Interp *interp, PNGImage *pngPtr,
249 int chunkSz, unsigned long crc);
250 static int SkipChunk(Tcl_Interp *interp, PNGImage *pngPtr,
251 int chunkSz, unsigned long crc);
252 static int StringMatchPNG(Tcl_Interp *interp, Tcl_Obj *pObjData,
253 Tcl_Obj *fmtObj, Tcl_Obj *metadataInObj,
254 int *widthPtr, int *heightPtr,
255 Tcl_Obj *metadataOutObj);
256 static int StringReadPNG(Tcl_Interp *interp, Tcl_Obj *pObjData,
257 Tcl_Obj *fmtObj, Tcl_Obj *metadataInObj,
258 Tk_PhotoHandle imageHandle,
259 int destX, int destY, int width, int height,
260 int srcX, int srcY, Tcl_Obj *metadataOutObj);
261
262 static int StringWritePNG(Tcl_Interp *interp, Tcl_Obj *fmtObj,
263 Tcl_Obj *metadataInObj,
264 Tk_PhotoImageBlock *blockPtr);
265 static int UnfilterLine(Tcl_Interp *interp, PNGImage *pngPtr);
266 static inline int WriteByte(Tcl_Interp *interp, PNGImage *pngPtr,
267 unsigned char c, unsigned long *crcPtr);
268 static inline int WriteChunk(Tcl_Interp *interp, PNGImage *pngPtr,
269 unsigned long chunkType,
270 const unsigned char *dataPtr, size_t dataSize);
271 static int WriteData(Tcl_Interp *interp, PNGImage *pngPtr,
272 const unsigned char *srcPtr, size_t srcSz,
273 unsigned long *crcPtr);
274 static int WriteExtraChunks(Tcl_Interp *interp,
275 PNGImage *pngPtr, Tcl_Obj *metadataInObj);
276 static int WriteIHDR(Tcl_Interp *interp, PNGImage *pngPtr,
277 Tk_PhotoImageBlock *blockPtr);
278 static int WriteIDAT(Tcl_Interp *interp, PNGImage *pngPtr,
279 Tk_PhotoImageBlock *blockPtr);
280 static inline int WriteInt32(Tcl_Interp *interp, PNGImage *pngPtr,
281 unsigned long l, unsigned long *crcPtr);
282
283 /*
284 * The format record for the PNG file format:
285 */
286
287 Tk_PhotoImageFormatVersion3 tkImgFmtPNG = {
288 "png", /* name */
289 FileMatchPNG, /* fileMatchProc */
290 StringMatchPNG, /* stringMatchProc */
291 FileReadPNG, /* fileReadProc */
292 StringReadPNG, /* stringReadProc */
293 FileWritePNG, /* fileWriteProc */
294 StringWritePNG, /* stringWriteProc */
295 NULL
296 };
297
298 /*
299 *----------------------------------------------------------------------
300 *
301 * InitPNGImage --
302 *
303 * This function is invoked by each of the Tk image handler procs
304 * (MatchStringProc, etc.) to initialize state information used during
305 * the course of encoding or decoding a PNG image.
306 *
307 * Results:
308 * TCL_OK, or TCL_ERROR if initialization failed.
309 *
310 * Side effects:
311 * The reference count of the -data Tcl_Obj*, if any, is incremented.
312 *
313 *----------------------------------------------------------------------
314 */
315
316 static int
InitPNGImage(Tcl_Interp * interp,PNGImage * pngPtr,Tcl_Channel chan,Tcl_Obj * objPtr,int dir)317 InitPNGImage(
318 Tcl_Interp *interp,
319 PNGImage *pngPtr,
320 Tcl_Channel chan,
321 Tcl_Obj *objPtr,
322 int dir)
323 {
324 memset(pngPtr, 0, sizeof(PNGImage));
325
326 pngPtr->channel = chan;
327 pngPtr->alpha = 1.0;
328
329 /*
330 * If decoding from a -data string object, increment its reference count
331 * for the duration of the decode and get its length and byte array for
332 * reading with ReadData().
333 */
334
335 if (objPtr) {
336 Tcl_IncrRefCount(objPtr);
337 pngPtr->objDataPtr = objPtr;
338 pngPtr->strDataBuf =
339 Tcl_GetByteArrayFromObj(objPtr, &pngPtr->strDataLen);
340 }
341
342 /*
343 * Initialize the palette transparency table to fully opaque.
344 */
345
346 memset(pngPtr->palette, 255, sizeof(pngPtr->palette));
347
348 /*
349 * Initialize Zlib inflate/deflate stream.
350 */
351
352 if (Tcl_ZlibStreamInit(NULL, dir, TCL_ZLIB_FORMAT_ZLIB,
353 TCL_ZLIB_COMPRESS_DEFAULT, NULL, &pngPtr->stream) != TCL_OK) {
354 if (interp) {
355 Tcl_SetObjResult(interp, Tcl_NewStringObj(
356 "zlib initialization failed", -1));
357 Tcl_SetErrorCode(interp, "TK", "IMAGE", "PNG", "ZLIB_INIT", NULL);
358 }
359 if (objPtr) {
360 Tcl_DecrRefCount(objPtr);
361 }
362 return TCL_ERROR;
363 }
364
365 /*
366 * Initialize physical size pHYS values
367 */
368
369 pngPtr->DPI = -1;
370 pngPtr->aspect = -1;
371
372 return TCL_OK;
373 }
374
375 /*
376 *----------------------------------------------------------------------
377 *
378 * CleanupPNGImage --
379 *
380 * This function is invoked by each of the Tk image handler procs
381 * (MatchStringProc, etc.) prior to returning to Tcl in order to clean up
382 * any allocated memory and call other cleanup handlers such as zlib's
383 * inflateEnd/deflateEnd.
384 *
385 * Results:
386 * None.
387 *
388 * Side effects:
389 * The reference count of the -data Tcl_Obj*, if any, is decremented.
390 * Buffers are freed, streams are closed. The PNGImage should not be used
391 * for any purpose without being reinitialized post-cleanup.
392 *
393 *----------------------------------------------------------------------
394 */
395
396 static void
CleanupPNGImage(PNGImage * pngPtr)397 CleanupPNGImage(
398 PNGImage *pngPtr)
399 {
400 /*
401 * Don't need the object containing the -data value anymore.
402 */
403
404 if (pngPtr->objDataPtr) {
405 Tcl_DecrRefCount(pngPtr->objDataPtr);
406 }
407
408 /*
409 * Discard pixel buffer.
410 */
411
412 if (pngPtr->stream) {
413 Tcl_ZlibStreamClose(pngPtr->stream);
414 }
415
416 if (pngPtr->block.pixelPtr) {
417 ckfree(pngPtr->block.pixelPtr);
418 }
419 if (pngPtr->thisLineObj) {
420 Tcl_DecrRefCount(pngPtr->thisLineObj);
421 }
422 if (pngPtr->lastLineObj) {
423 Tcl_DecrRefCount(pngPtr->lastLineObj);
424 }
425
426 memset(pngPtr, 0, sizeof(PNGImage));
427 }
428
429 /*
430 *----------------------------------------------------------------------
431 *
432 * ReadBase64 --
433 *
434 * This function is invoked to read the specified number of bytes from
435 * base-64 encoded image data.
436 *
437 * Note: It would be better if the Tk_PhotoImage stuff handled this by
438 * creating a channel from the -data value, which would take care of
439 * base64 decoding and made the data readable as if it were coming from a
440 * file.
441 *
442 * Results:
443 * TCL_OK, or TCL_ERROR if an I/O error occurs.
444 *
445 * Side effects:
446 * The file position will change. The running CRC is updated if a pointer
447 * to it is provided.
448 *
449 *----------------------------------------------------------------------
450 */
451
452 static int
ReadBase64(Tcl_Interp * interp,PNGImage * pngPtr,unsigned char * destPtr,size_t destSz,unsigned long * crcPtr)453 ReadBase64(
454 Tcl_Interp *interp,
455 PNGImage *pngPtr,
456 unsigned char *destPtr,
457 size_t destSz,
458 unsigned long *crcPtr)
459 {
460 static const unsigned char from64[] = {
461 0x82, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x80, 0x80,
462 0x83, 0x80, 0x80, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
463 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x80,
464 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x3e,
465 0x83, 0x83, 0x83, 0x3f, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a,
466 0x3b, 0x3c, 0x3d, 0x83, 0x83, 0x83, 0x81, 0x83, 0x83, 0x83, 0x00,
467 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
468 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
469 0x17, 0x18, 0x19, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x1a, 0x1b,
470 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26,
471 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31,
472 0x32, 0x33, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
473 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
474 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
475 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
476 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
477 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
478 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
479 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
480 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
481 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
482 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
483 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
484 0x83, 0x83
485 };
486
487 /*
488 * Definitions for the base-64 decoder.
489 */
490
491 #define PNG64_SPECIAL 0x80 /* Flag bit */
492 #define PNG64_SPACE 0x80 /* Whitespace */
493 #define PNG64_PAD 0x81 /* Padding */
494 #define PNG64_DONE 0x82 /* End of data */
495 #define PNG64_BAD 0x83 /* Ooooh, naughty! */
496
497 while (destSz && pngPtr->strDataLen) {
498 unsigned char c = 0;
499 unsigned char c64 = from64[*pngPtr->strDataBuf++];
500
501 pngPtr->strDataLen--;
502
503 if (PNG64_SPACE == c64) {
504 continue;
505 }
506
507 if (c64 & PNG64_SPECIAL) {
508 c = (unsigned char) pngPtr->base64Bits;
509 } else {
510 switch (pngPtr->base64State++) {
511 case 0:
512 pngPtr->base64Bits = c64 << 2;
513 continue;
514 case 1:
515 c = (unsigned char) (pngPtr->base64Bits | (c64 >> 4));
516 pngPtr->base64Bits = (c64 & 0xF) << 4;
517 break;
518 case 2:
519 c = (unsigned char) (pngPtr->base64Bits | (c64 >> 2));
520 pngPtr->base64Bits = (c64 & 0x3) << 6;
521 break;
522 case 3:
523 c = (unsigned char) (pngPtr->base64Bits | c64);
524 pngPtr->base64State = 0;
525 pngPtr->base64Bits = 0;
526 break;
527 }
528 }
529
530 if (crcPtr) {
531 *crcPtr = Tcl_ZlibCRC32(*crcPtr, &c, 1);
532 }
533
534 if (destPtr) {
535 *destPtr++ = c;
536 }
537
538 destSz--;
539
540 if (c64 & PNG64_SPECIAL) {
541 break;
542 }
543 }
544
545 if (destSz) {
546 Tcl_SetObjResult(interp, Tcl_NewStringObj(
547 "unexpected end of image data", -1));
548 Tcl_SetErrorCode(interp, "TK", "IMAGE", "PNG", "EARLY_END", NULL);
549 return TCL_ERROR;
550 }
551
552 return TCL_OK;
553 }
554
555 /*
556 *----------------------------------------------------------------------
557 *
558 * ReadByteArray --
559 *
560 * This function is invoked to read the specified number of bytes from a
561 * non-base64-encoded byte array provided via the -data option.
562 *
563 * Note: It would be better if the Tk_PhotoImage stuff handled this by
564 * creating a channel from the -data value and made the data readable as
565 * if it were coming from a file.
566 *
567 * Results:
568 * TCL_OK, or TCL_ERROR if an I/O error occurs.
569 *
570 * Side effects:
571 * The file position will change. The running CRC is updated if a pointer
572 * to it is provided.
573 *
574 *----------------------------------------------------------------------
575 */
576
577 static int
ReadByteArray(Tcl_Interp * interp,PNGImage * pngPtr,unsigned char * destPtr,size_t destSz,unsigned long * crcPtr)578 ReadByteArray(
579 Tcl_Interp *interp,
580 PNGImage *pngPtr,
581 unsigned char *destPtr,
582 size_t destSz,
583 unsigned long *crcPtr)
584 {
585 /*
586 * Check to make sure the number of requested bytes are available.
587 */
588
589 if ((size_t)pngPtr->strDataLen < destSz) {
590 Tcl_SetObjResult(interp, Tcl_NewStringObj(
591 "unexpected end of image data", -1));
592 Tcl_SetErrorCode(interp, "TK", "IMAGE", "PNG", "EARLY_END", NULL);
593 return TCL_ERROR;
594 }
595
596 while (destSz) {
597 size_t blockSz = PNG_MIN(destSz, PNG_BLOCK_SZ);
598
599 memcpy(destPtr, pngPtr->strDataBuf, blockSz);
600
601 pngPtr->strDataBuf += blockSz;
602 pngPtr->strDataLen -= blockSz;
603
604 if (crcPtr) {
605 *crcPtr = Tcl_ZlibCRC32(*crcPtr, destPtr, blockSz);
606 }
607
608 destPtr += blockSz;
609 destSz -= blockSz;
610 }
611
612 return TCL_OK;
613 }
614
615 /*
616 *----------------------------------------------------------------------
617 *
618 * ReadData --
619 *
620 * This function is invoked to read the specified number of bytes from
621 * the image file or data. It is a wrapper around the choice of byte
622 * array Tcl_Obj or Tcl_Channel which depends on whether the image data
623 * is coming from a file or -data.
624 *
625 * Results:
626 * TCL_OK, or TCL_ERROR if an I/O error occurs.
627 *
628 * Side effects:
629 * The file position will change. The running CRC is updated if a pointer
630 * to it is provided.
631 *
632 *----------------------------------------------------------------------
633 */
634
635 static int
ReadData(Tcl_Interp * interp,PNGImage * pngPtr,unsigned char * destPtr,size_t destSz,unsigned long * crcPtr)636 ReadData(
637 Tcl_Interp *interp,
638 PNGImage *pngPtr,
639 unsigned char *destPtr,
640 size_t destSz,
641 unsigned long *crcPtr)
642 {
643 if (pngPtr->base64Data) {
644 return ReadBase64(interp, pngPtr, destPtr, destSz, crcPtr);
645 } else if (pngPtr->strDataBuf) {
646 return ReadByteArray(interp, pngPtr, destPtr, destSz, crcPtr);
647 }
648
649 while (destSz) {
650 TkSizeT blockSz = PNG_MIN(destSz, PNG_BLOCK_SZ);
651
652 blockSz = Tcl_Read(pngPtr->channel, (char *)destPtr, blockSz);
653 if (blockSz == TCL_IO_FAILURE) {
654 /* TODO: failure info... */
655 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
656 "channel read failed: %s", Tcl_PosixError(interp)));
657 return TCL_ERROR;
658 }
659
660 /*
661 * Update CRC, pointer, and remaining count if anything was read.
662 */
663
664 if (blockSz) {
665 if (crcPtr) {
666 *crcPtr = Tcl_ZlibCRC32(*crcPtr, destPtr, blockSz);
667 }
668
669 destPtr += blockSz;
670 destSz -= blockSz;
671 }
672
673 /*
674 * Check for EOF before all desired data was read.
675 */
676
677 if (destSz && Tcl_Eof(pngPtr->channel)) {
678 Tcl_SetObjResult(interp, Tcl_NewStringObj(
679 "unexpected end of file", -1));
680 Tcl_SetErrorCode(interp, "TK", "IMAGE", "PNG", "EOF", NULL);
681 return TCL_ERROR;
682 }
683 }
684
685 return TCL_OK;
686 }
687
688 /*
689 *----------------------------------------------------------------------
690 *
691 * ReadInt32 --
692 *
693 * This function is invoked to read a 32-bit integer in network byte
694 * order from the image data and return the value in host byte order.
695 * This is used, for example, to read the 32-bit CRC value for a chunk
696 * stored in the image file for comparison with the calculated CRC value.
697 *
698 * Results:
699 * TCL_OK, or TCL_ERROR if an I/O error occurs.
700 *
701 * Side effects:
702 * The file position will change. The running CRC is updated if a pointer
703 * to it is provided.
704 *
705 *----------------------------------------------------------------------
706 */
707
708 static inline int
ReadInt32(Tcl_Interp * interp,PNGImage * pngPtr,unsigned long * resultPtr,unsigned long * crcPtr)709 ReadInt32(
710 Tcl_Interp *interp,
711 PNGImage *pngPtr,
712 unsigned long *resultPtr,
713 unsigned long *crcPtr)
714 {
715 unsigned char p[4];
716
717 if (ReadData(interp, pngPtr, p, 4, crcPtr) == TCL_ERROR) {
718 return TCL_ERROR;
719 }
720
721 *resultPtr = PNG_INT32(p[0], p[1], p[2], p[3]);
722
723 return TCL_OK;
724 }
725
726 /*
727 *----------------------------------------------------------------------
728 *
729 * CheckCRC --
730 *
731 * This function is reads the final 4-byte integer CRC from a chunk and
732 * compares it to the running CRC calculated over the chunk type and data
733 * fields.
734 *
735 * Results:
736 * TCL_OK, or TCL_ERROR if an I/O error or CRC mismatch occurs.
737 *
738 * Side effects:
739 * The file position will change.
740 *
741 *----------------------------------------------------------------------
742 */
743
744 static inline int
CheckCRC(Tcl_Interp * interp,PNGImage * pngPtr,unsigned long calculated)745 CheckCRC(
746 Tcl_Interp *interp,
747 PNGImage *pngPtr,
748 unsigned long calculated)
749 {
750 unsigned long chunked;
751
752 /*
753 * Read the CRC field at the end of the chunk.
754 */
755
756 if (ReadInt32(interp, pngPtr, &chunked, NULL) == TCL_ERROR) {
757 return TCL_ERROR;
758 }
759
760 /*
761 * Compare the read CRC to what we calculate to make sure they match.
762 */
763
764 if (calculated != chunked) {
765 Tcl_SetObjResult(interp, Tcl_NewStringObj("CRC check failed", -1));
766 Tcl_SetErrorCode(interp, "TK", "IMAGE", "PNG", "CRC", NULL);
767 return TCL_ERROR;
768 }
769
770 return TCL_OK;
771 }
772
773 /*
774 *----------------------------------------------------------------------
775 *
776 * SkipChunk --
777 *
778 * This function is used to skip a PNG chunk that is not used by this
779 * implementation. Given the input stream has had the chunk length and
780 * chunk type fields already read, this function will read the number of
781 * bytes indicated by the chunk length, plus four for the CRC, and will
782 * verify that CRC is correct for the skipped data.
783 *
784 * Results:
785 * TCL_OK, or TCL_ERROR if an I/O error or CRC mismatch occurs.
786 *
787 * Side effects:
788 * The file position will change.
789 *
790 *----------------------------------------------------------------------
791 */
792
793 static int
SkipChunk(Tcl_Interp * interp,PNGImage * pngPtr,int chunkSz,unsigned long crc)794 SkipChunk(
795 Tcl_Interp *interp,
796 PNGImage *pngPtr,
797 int chunkSz,
798 unsigned long crc)
799 {
800 unsigned char buffer[PNG_BLOCK_SZ];
801
802 /*
803 * Skip data in blocks until none is left. Read up to PNG_BLOCK_SZ bytes
804 * at a time, rather than trusting the claimed chunk size, which may not
805 * be trustworthy.
806 */
807
808 while (chunkSz) {
809 int blockSz = PNG_MIN(chunkSz, PNG_BLOCK_SZ);
810
811 if (ReadData(interp, pngPtr, buffer, blockSz, &crc) == TCL_ERROR) {
812 return TCL_ERROR;
813 }
814
815 chunkSz -= blockSz;
816 }
817
818 if (CheckCRC(interp, pngPtr, crc) == TCL_ERROR) {
819 return TCL_ERROR;
820 }
821
822 return TCL_OK;
823 }
824
825 /*
826 * 4.3. Summary of standard chunks
827 *
828 * This table summarizes some properties of the standard chunk types.
829 *
830 * Critical chunks (must appear in this order, except PLTE is optional):
831 *
832 * Name Multiple Ordering constraints OK?
833 *
834 * IHDR No Must be first
835 * PLTE No Before IDAT
836 * IDAT Yes Multiple IDATs must be consecutive
837 * IEND No Must be last
838 *
839 * Ancillary chunks (need not appear in this order):
840 *
841 * Name Multiple Ordering constraints OK?
842 *
843 * cHRM No Before PLTE and IDAT
844 * gAMA No Before PLTE and IDAT
845 * iCCP No Before PLTE and IDAT
846 * sBIT No Before PLTE and IDAT
847 * sRGB No Before PLTE and IDAT
848 * bKGD No After PLTE; before IDAT
849 * hIST No After PLTE; before IDAT
850 * tRNS No After PLTE; before IDAT
851 * pHYs No Before IDAT
852 * sPLT Yes Before IDAT
853 * tIME No None
854 * iTXt Yes None
855 * tEXt Yes None
856 * zTXt Yes None
857 *
858 * [From the PNG specification.]
859 */
860
861 /*
862 *----------------------------------------------------------------------
863 *
864 * ReadChunkHeader --
865 *
866 * This function is used at the start of each chunk to extract the
867 * four-byte chunk length and four-byte chunk type fields. It will
868 * continue reading until it finds a chunk type that is handled by this
869 * implementation, checking the CRC of any chunks it skips.
870 *
871 * Results:
872 * TCL_OK, or TCL_ERROR if an I/O error occurs or an unknown critical
873 * chunk type is encountered.
874 *
875 * Side effects:
876 * The file position will change. The running CRC is updated.
877 *
878 *----------------------------------------------------------------------
879 */
880
881 static int
ReadChunkHeader(Tcl_Interp * interp,PNGImage * pngPtr,size_t * sizePtr,unsigned long * typePtr,unsigned long * crcPtr)882 ReadChunkHeader(
883 Tcl_Interp *interp,
884 PNGImage *pngPtr,
885 size_t *sizePtr,
886 unsigned long *typePtr,
887 unsigned long *crcPtr)
888 {
889 unsigned long chunkType = 0;
890 int chunkSz = 0;
891 unsigned long crc = 0;
892
893 /*
894 * Continue until finding a chunk type that is handled.
895 */
896
897 while (!chunkType) {
898 unsigned long temp;
899 unsigned char pc[4];
900 int i;
901
902 /*
903 * Read the 4-byte length field for the chunk. The length field is not
904 * included in the CRC calculation, so the running CRC must be reset
905 * afterward. Limit chunk lengths to INT_MAX, to align with the
906 * maximum size for Tcl_Read, Tcl_GetByteArrayFromObj, etc.
907 */
908
909 if (ReadData(interp, pngPtr, pc, 4, NULL) == TCL_ERROR) {
910 return TCL_ERROR;
911 }
912
913 temp = PNG_INT32(pc[0], pc[1], pc[2], pc[3]);
914
915 if (temp > INT_MAX) {
916 Tcl_SetObjResult(interp, Tcl_NewStringObj(
917 "chunk size is out of supported range on this architecture",
918 -1));
919 Tcl_SetErrorCode(interp, "TK", "IMAGE", "PNG", "OUTSIZE", NULL);
920 return TCL_ERROR;
921 }
922
923 chunkSz = (int) temp;
924 crc = Tcl_ZlibCRC32(0, NULL, 0);
925
926 /*
927 * Read the 4-byte chunk type.
928 */
929
930 if (ReadData(interp, pngPtr, pc, 4, &crc) == TCL_ERROR) {
931 return TCL_ERROR;
932 }
933
934 /*
935 * Convert it to a host-order integer for simple comparison.
936 */
937
938 chunkType = PNG_INT32(pc[0], pc[1], pc[2], pc[3]);
939
940 /*
941 * Check to see if this is a known/supported chunk type. Note that the
942 * PNG specs require non-critical (i.e., ancillary) chunk types that
943 * are not recognized to be ignored, rather than be treated as an
944 * error. It does, however, recommend that an unknown critical chunk
945 * type be treated as a failure.
946 *
947 * This switch/loop acts as a filter of sorts for undesired chunk
948 * types. The chunk type should still be checked elsewhere for
949 * determining it is in the correct order.
950 */
951
952 switch (chunkType) {
953 /*
954 * These chunk types are required and/or supported.
955 */
956
957 case CHUNK_IDAT:
958 case CHUNK_IEND:
959 case CHUNK_IHDR:
960 case CHUNK_pHYs:
961 case CHUNK_PLTE:
962 case CHUNK_tRNS:
963 break;
964
965 /*
966 * These chunk types are part of the standard, but are not used by
967 * this implementation (at least not yet). Note that these are all
968 * ancillary chunks (lowercase first letter).
969 */
970
971 case CHUNK_bKGD:
972 case CHUNK_cHRM:
973 case CHUNK_gAMA:
974 case CHUNK_hIST:
975 case CHUNK_iCCP:
976 case CHUNK_iTXt:
977 case CHUNK_oFFs:
978 case CHUNK_pCAL:
979 case CHUNK_sBIT:
980 case CHUNK_sCAL:
981 case CHUNK_sPLT:
982 case CHUNK_sRGB:
983 case CHUNK_tEXt:
984 case CHUNK_tIME:
985 case CHUNK_zTXt:
986 /*
987 * TODO: might want to check order here.
988 */
989
990 if (SkipChunk(interp, pngPtr, chunkSz, crc) == TCL_ERROR) {
991 return TCL_ERROR;
992 }
993
994 chunkType = 0;
995 break;
996
997 default:
998 /*
999 * Unknown chunk type. If it's critical, we can't continue.
1000 */
1001
1002 if (!(chunkType & PNG_CF_ANCILLARY)) {
1003 if (chunkType & PNG_INT32(128,128,128,128)) {
1004 /*
1005 * No nice ASCII conversion; shouldn't happen either, but
1006 * we'll be doubly careful.
1007 */
1008
1009 Tcl_SetObjResult(interp, Tcl_NewStringObj(
1010 "encountered an unsupported critical chunk type",
1011 -1));
1012 } else {
1013 char typeString[5];
1014
1015 typeString[0] = (char) ((chunkType >> 24) & 255);
1016 typeString[1] = (char) ((chunkType >> 16) & 255);
1017 typeString[2] = (char) ((chunkType >> 8) & 255);
1018 typeString[3] = (char) (chunkType & 255);
1019 typeString[4] = '\0';
1020 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
1021 "encountered an unsupported critical chunk type"
1022 " \"%s\"", typeString));
1023 }
1024 Tcl_SetErrorCode(interp, "TK", "IMAGE", "PNG",
1025 "UNSUPPORTED_CRITICAL", NULL);
1026 return TCL_ERROR;
1027 }
1028
1029 /*
1030 * Check to see if the chunk type has legal bytes.
1031 */
1032
1033 for (i=0 ; i<4 ; i++) {
1034 if ((pc[i] < 65) || (pc[i] > 122) ||
1035 ((pc[i] > 90) && (pc[i] < 97))) {
1036 Tcl_SetObjResult(interp, Tcl_NewStringObj(
1037 "invalid chunk type", -1));
1038 Tcl_SetErrorCode(interp, "TK", "IMAGE", "PNG",
1039 "INVALID_CHUNK", NULL);
1040 return TCL_ERROR;
1041 }
1042 }
1043
1044 /*
1045 * It seems to be an otherwise legally labelled ancillary chunk
1046 * that we don't want, so skip it after at least checking its CRC.
1047 */
1048
1049 if (SkipChunk(interp, pngPtr, chunkSz, crc) == TCL_ERROR) {
1050 return TCL_ERROR;
1051 }
1052
1053 chunkType = 0;
1054 }
1055 }
1056
1057 /*
1058 * Found a known chunk type that's handled, albiet possibly not in the
1059 * right order. Send back the chunk type (for further checking or
1060 * handling), the chunk size and the current CRC for the rest of the
1061 * calculation.
1062 */
1063
1064 *typePtr = chunkType;
1065 *sizePtr = chunkSz;
1066 *crcPtr = crc;
1067
1068 return TCL_OK;
1069 }
1070
1071 /*
1072 *----------------------------------------------------------------------
1073 *
1074 * CheckColor --
1075 *
1076 * Do validation on color type, depth, and related information, and
1077 * calculates storage requirements and offsets based on image dimensions
1078 * and color.
1079 *
1080 * Results:
1081 * TCL_OK, or TCL_ERROR if color information is invalid or some other
1082 * failure occurs.
1083 *
1084 * Side effects:
1085 * None
1086 *
1087 *----------------------------------------------------------------------
1088 */
1089
1090 static int
CheckColor(Tcl_Interp * interp,PNGImage * pngPtr)1091 CheckColor(
1092 Tcl_Interp *interp,
1093 PNGImage *pngPtr)
1094 {
1095 int offset;
1096
1097 /*
1098 * Verify the color type is valid and the bit depth is allowed.
1099 */
1100
1101 switch (pngPtr->colorType) {
1102 case PNG_COLOR_GRAY:
1103 pngPtr->numChannels = 1;
1104 if ((1 != pngPtr->bitDepth) && (2 != pngPtr->bitDepth) &&
1105 (4 != pngPtr->bitDepth) && (8 != pngPtr->bitDepth) &&
1106 (16 != pngPtr->bitDepth)) {
1107 goto unsupportedDepth;
1108 }
1109 break;
1110
1111 case PNG_COLOR_RGB:
1112 pngPtr->numChannels = 3;
1113 if ((8 != pngPtr->bitDepth) && (16 != pngPtr->bitDepth)) {
1114 goto unsupportedDepth;
1115 }
1116 break;
1117
1118 case PNG_COLOR_PLTE:
1119 pngPtr->numChannels = 1;
1120 if ((1 != pngPtr->bitDepth) && (2 != pngPtr->bitDepth) &&
1121 (4 != pngPtr->bitDepth) && (8 != pngPtr->bitDepth)) {
1122 goto unsupportedDepth;
1123 }
1124 break;
1125
1126 case PNG_COLOR_GRAYALPHA:
1127 pngPtr->numChannels = 2;
1128 if ((8 != pngPtr->bitDepth) && (16 != pngPtr->bitDepth)) {
1129 goto unsupportedDepth;
1130 }
1131 break;
1132
1133 case PNG_COLOR_RGBA:
1134 pngPtr->numChannels = 4;
1135 if ((8 != pngPtr->bitDepth) && (16 != pngPtr->bitDepth)) {
1136 unsupportedDepth:
1137 Tcl_SetObjResult(interp, Tcl_NewStringObj(
1138 "bit depth is not allowed for given color type", -1));
1139 Tcl_SetErrorCode(interp, "TK", "IMAGE", "PNG", "BAD_DEPTH", NULL);
1140 return TCL_ERROR;
1141 }
1142 break;
1143
1144 default:
1145 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
1146 "unknown color type field %d", pngPtr->colorType));
1147 Tcl_SetErrorCode(interp, "TK", "IMAGE", "PNG", "UNKNOWN_COLOR", NULL);
1148 return TCL_ERROR;
1149 }
1150
1151 /*
1152 * Set up the Tk photo block's pixel size and channel offsets. offset
1153 * array elements should already be 0 from the memset during InitPNGImage.
1154 */
1155
1156 offset = (pngPtr->bitDepth > 8) ? 2 : 1;
1157
1158 if (pngPtr->colorType & PNG_COLOR_USED) {
1159 pngPtr->block.pixelSize = offset * 4;
1160 pngPtr->block.offset[1] = offset;
1161 pngPtr->block.offset[2] = offset * 2;
1162 pngPtr->block.offset[3] = offset * 3;
1163 } else {
1164 pngPtr->block.pixelSize = offset * 2;
1165 pngPtr->block.offset[3] = offset;
1166 }
1167
1168 /*
1169 * Calculate the block pitch, which is the number of bytes per line in the
1170 * image, given image width and depth of color. Make sure that it it isn't
1171 * larger than Tk can handle.
1172 */
1173
1174 if (pngPtr->block.width > INT_MAX / pngPtr->block.pixelSize) {
1175 Tcl_SetObjResult(interp, Tcl_NewStringObj(
1176 "image pitch is out of supported range on this architecture",
1177 -1));
1178 Tcl_SetErrorCode(interp, "TK", "IMAGE", "PNG", "PITCH", NULL);
1179 return TCL_ERROR;
1180 }
1181
1182 pngPtr->block.pitch = pngPtr->block.pixelSize * pngPtr->block.width;
1183
1184 /*
1185 * Calculate the total size of the image as represented to Tk given pitch
1186 * and image height. Make sure that it isn't larger than Tk can handle.
1187 */
1188
1189 if (pngPtr->block.height > INT_MAX / pngPtr->block.pitch) {
1190 Tcl_SetObjResult(interp, Tcl_NewStringObj(
1191 "image total size is out of supported range on this architecture",
1192 -1));
1193 Tcl_SetErrorCode(interp, "TK", "IMAGE", "PNG", "SIZE", NULL);
1194 return TCL_ERROR;
1195 }
1196
1197 pngPtr->blockLen = pngPtr->block.height * pngPtr->block.pitch;
1198
1199 /*
1200 * Determine number of bytes per pixel in the source for later use.
1201 */
1202
1203 switch (pngPtr->colorType) {
1204 case PNG_COLOR_GRAY:
1205 pngPtr->bytesPerPixel = (pngPtr->bitDepth > 8) ? 2 : 1;
1206 break;
1207 case PNG_COLOR_RGB:
1208 pngPtr->bytesPerPixel = (pngPtr->bitDepth > 8) ? 6 : 3;
1209 break;
1210 case PNG_COLOR_PLTE:
1211 pngPtr->bytesPerPixel = 1;
1212 break;
1213 case PNG_COLOR_GRAYALPHA:
1214 pngPtr->bytesPerPixel = (pngPtr->bitDepth > 8) ? 4 : 2;
1215 break;
1216 case PNG_COLOR_RGBA:
1217 pngPtr->bytesPerPixel = (pngPtr->bitDepth > 8) ? 8 : 4;
1218 break;
1219 default:
1220 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
1221 "unknown color type %d", pngPtr->colorType));
1222 Tcl_SetErrorCode(interp, "TK", "IMAGE", "PNG", "UNKNOWN_COLOR", NULL);
1223 return TCL_ERROR;
1224 }
1225
1226 /*
1227 * Calculate scale factor for bit depths less than 8, in order to adjust
1228 * them to a minimum of 8 bits per pixel in the Tk image.
1229 */
1230
1231 if (pngPtr->bitDepth < 8) {
1232 pngPtr->bitScale = 255 / (int)(pow(2, pngPtr->bitDepth) - 1);
1233 } else {
1234 pngPtr->bitScale = 1;
1235 }
1236
1237 return TCL_OK;
1238 }
1239
1240 /*
1241 *----------------------------------------------------------------------
1242 *
1243 * ReadIHDR --
1244 *
1245 * This function reads the PNG header from the beginning of a PNG file
1246 * and returns the dimensions of the image.
1247 *
1248 * Results:
1249 * The return value is 1 if file "f" appears to start with a valid PNG
1250 * header, 0 otherwise. If the header is valid, then *widthPtr and
1251 * *heightPtr are modified to hold the dimensions of the image.
1252 *
1253 * Side effects:
1254 * The access position in f advances.
1255 *
1256 *----------------------------------------------------------------------
1257 */
1258
1259 static int
ReadIHDR(Tcl_Interp * interp,PNGImage * pngPtr)1260 ReadIHDR(
1261 Tcl_Interp *interp,
1262 PNGImage *pngPtr)
1263 {
1264 unsigned char sigBuf[PNG_SIG_SZ];
1265 unsigned long chunkType;
1266 size_t chunkSz;
1267 unsigned long crc;
1268 unsigned long width, height;
1269 int mismatch;
1270
1271 /*
1272 * Read the appropriate number of bytes for the PNG signature.
1273 */
1274
1275 if (ReadData(interp, pngPtr, sigBuf, PNG_SIG_SZ, NULL) == TCL_ERROR) {
1276 return TCL_ERROR;
1277 }
1278
1279 /*
1280 * Compare the read bytes to the expected signature.
1281 */
1282
1283 mismatch = memcmp(sigBuf, pngSignature, PNG_SIG_SZ);
1284
1285 /*
1286 * If reading from string, reset position and try base64 decode.
1287 */
1288
1289 if (mismatch && pngPtr->strDataBuf) {
1290 pngPtr->strDataBuf = Tcl_GetByteArrayFromObj(pngPtr->objDataPtr,
1291 &pngPtr->strDataLen);
1292 pngPtr->base64Data = pngPtr->strDataBuf;
1293
1294 if (ReadData(interp, pngPtr, sigBuf, PNG_SIG_SZ, NULL) == TCL_ERROR) {
1295 return TCL_ERROR;
1296 }
1297
1298 mismatch = memcmp(sigBuf, pngSignature, PNG_SIG_SZ);
1299 }
1300
1301 if (mismatch) {
1302 Tcl_SetObjResult(interp, Tcl_NewStringObj(
1303 "data stream does not have a PNG signature", -1));
1304 Tcl_SetErrorCode(interp, "TK", "IMAGE", "PNG", "NO_SIG", NULL);
1305 return TCL_ERROR;
1306 }
1307
1308 if (ReadChunkHeader(interp, pngPtr, &chunkSz, &chunkType,
1309 &crc) == TCL_ERROR) {
1310 return TCL_ERROR;
1311 }
1312
1313 /*
1314 * Read in the IHDR (header) chunk for width, height, etc.
1315 *
1316 * The first chunk in the file must be the IHDR (headr) chunk.
1317 */
1318
1319 if (chunkType != CHUNK_IHDR) {
1320 Tcl_SetObjResult(interp, Tcl_NewStringObj(
1321 "expected IHDR chunk type", -1));
1322 Tcl_SetErrorCode(interp, "TK", "IMAGE", "PNG", "NO_IHDR", NULL);
1323 return TCL_ERROR;
1324 }
1325
1326 if (chunkSz != 13) {
1327 Tcl_SetObjResult(interp, Tcl_NewStringObj(
1328 "invalid IHDR chunk size", -1));
1329 Tcl_SetErrorCode(interp, "TK", "IMAGE", "PNG", "BAD_IHDR", NULL);
1330 return TCL_ERROR;
1331 }
1332
1333 /*
1334 * Read and verify the image width and height to be sure Tk can handle its
1335 * dimensions. The PNG specification does not permit zero-width or
1336 * zero-height images.
1337 */
1338
1339 if (ReadInt32(interp, pngPtr, &width, &crc) == TCL_ERROR) {
1340 return TCL_ERROR;
1341 }
1342
1343 if (ReadInt32(interp, pngPtr, &height, &crc) == TCL_ERROR) {
1344 return TCL_ERROR;
1345 }
1346
1347 if (!width || !height || (width > INT_MAX) || (height > INT_MAX)) {
1348 Tcl_SetObjResult(interp, Tcl_NewStringObj(
1349 "image dimensions are invalid or beyond architecture limits",
1350 -1));
1351 Tcl_SetErrorCode(interp, "TK", "IMAGE", "PNG", "DIMENSIONS", NULL);
1352 return TCL_ERROR;
1353 }
1354
1355 /*
1356 * Set height and width for the Tk photo block.
1357 */
1358
1359 pngPtr->block.width = (int) width;
1360 pngPtr->block.height = (int) height;
1361
1362 /*
1363 * Read and the Bit Depth and Color Type.
1364 */
1365
1366 if (ReadData(interp, pngPtr, &pngPtr->bitDepth, 1, &crc) == TCL_ERROR) {
1367 return TCL_ERROR;
1368 }
1369
1370 if (ReadData(interp, pngPtr, &pngPtr->colorType, 1, &crc) == TCL_ERROR) {
1371 return TCL_ERROR;
1372 }
1373
1374 /*
1375 * Verify that the color type is valid, the bit depth is allowed for the
1376 * color type, and calculate the number of channels and pixel depth (bits
1377 * per pixel * channels). Also set up offsets and sizes in the Tk photo
1378 * block for the pixel data.
1379 */
1380
1381 if (CheckColor(interp, pngPtr) == TCL_ERROR) {
1382 return TCL_ERROR;
1383 }
1384
1385 /*
1386 * Only one compression method is currently defined by the standard.
1387 */
1388
1389 if (ReadData(interp, pngPtr, &pngPtr->compression, 1, &crc) == TCL_ERROR) {
1390 return TCL_ERROR;
1391 }
1392
1393 if (pngPtr->compression != PNG_COMPRESS_DEFLATE) {
1394 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
1395 "unknown compression method %d", pngPtr->compression));
1396 Tcl_SetErrorCode(interp, "TK", "IMAGE", "PNG", "BAD_COMPRESS", NULL);
1397 return TCL_ERROR;
1398 }
1399
1400 /*
1401 * Only one filter method is currently defined by the standard; the method
1402 * has five actual filter types associated with it.
1403 */
1404
1405 if (ReadData(interp, pngPtr, &pngPtr->filter, 1, &crc) == TCL_ERROR) {
1406 return TCL_ERROR;
1407 }
1408
1409 if (pngPtr->filter != PNG_FILTMETH_STANDARD) {
1410 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
1411 "unknown filter method %d", pngPtr->filter));
1412 Tcl_SetErrorCode(interp, "TK", "IMAGE", "PNG", "BAD_FILTER", NULL);
1413 return TCL_ERROR;
1414 }
1415
1416 if (ReadData(interp, pngPtr, &pngPtr->interlace, 1, &crc) == TCL_ERROR) {
1417 return TCL_ERROR;
1418 }
1419
1420 switch (pngPtr->interlace) {
1421 case PNG_INTERLACE_NONE:
1422 case PNG_INTERLACE_ADAM7:
1423 break;
1424
1425 default:
1426 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
1427 "unknown interlace method %d", pngPtr->interlace));
1428 Tcl_SetErrorCode(interp, "TK", "IMAGE", "PNG", "BAD_INTERLACE", NULL);
1429 return TCL_ERROR;
1430 }
1431
1432 return CheckCRC(interp, pngPtr, crc);
1433 }
1434
1435 /*
1436 *----------------------------------------------------------------------
1437 *
1438 * ReadPLTE --
1439 *
1440 * This function reads the PLTE (indexed color palette) chunk data from
1441 * the PNG file and populates the palette table in the PNGImage
1442 * structure.
1443 *
1444 * Results:
1445 * TCL_OK, or TCL_ERROR if an I/O error occurs or the PLTE chunk is
1446 * invalid.
1447 *
1448 * Side effects:
1449 * The access position in f advances.
1450 *
1451 *----------------------------------------------------------------------
1452 */
1453
1454 static int
ReadPLTE(Tcl_Interp * interp,PNGImage * pngPtr,int chunkSz,unsigned long crc)1455 ReadPLTE(
1456 Tcl_Interp *interp,
1457 PNGImage *pngPtr,
1458 int chunkSz,
1459 unsigned long crc)
1460 {
1461 unsigned char buffer[PNG_PLTE_MAXSZ];
1462 int i, c;
1463
1464 /*
1465 * This chunk is mandatory for color type 3 and forbidden for 2 and 6.
1466 */
1467
1468 switch (pngPtr->colorType) {
1469 case PNG_COLOR_GRAY:
1470 case PNG_COLOR_GRAYALPHA:
1471 Tcl_SetObjResult(interp, Tcl_NewStringObj(
1472 "PLTE chunk type forbidden for grayscale", -1));
1473 Tcl_SetErrorCode(interp, "TK", "IMAGE", "PNG", "PLTE_UNEXPECTED",
1474 NULL);
1475 return TCL_ERROR;
1476
1477 default:
1478 break;
1479 }
1480
1481 /*
1482 * The palette chunk contains from 1 to 256 palette entries. Each entry
1483 * consists of a 3-byte RGB value. It must therefore contain a non-zero
1484 * multiple of 3 bytes, up to 768.
1485 */
1486
1487 if (!chunkSz || (chunkSz > PNG_PLTE_MAXSZ) || (chunkSz % 3)) {
1488 Tcl_SetObjResult(interp, Tcl_NewStringObj(
1489 "invalid palette chunk size", -1));
1490 Tcl_SetErrorCode(interp, "TK", "IMAGE", "PNG", "BAD_PLTE", NULL);
1491 return TCL_ERROR;
1492 }
1493
1494 /*
1495 * Read the palette contents and stash them for later, possibly.
1496 */
1497
1498 if (ReadData(interp, pngPtr, buffer, chunkSz, &crc) == TCL_ERROR) {
1499 return TCL_ERROR;
1500 }
1501
1502 if (CheckCRC(interp, pngPtr, crc) == TCL_ERROR) {
1503 return TCL_ERROR;
1504 }
1505
1506 /*
1507 * Stash away the palette entries and entry count for later mapping each
1508 * pixel's palette index to its color.
1509 */
1510
1511 for (i=0, c=0 ; c<chunkSz ; i++) {
1512 pngPtr->palette[i].red = buffer[c++];
1513 pngPtr->palette[i].green = buffer[c++];
1514 pngPtr->palette[i].blue = buffer[c++];
1515 }
1516
1517 pngPtr->paletteLen = i;
1518 return TCL_OK;
1519 }
1520
1521 /*
1522 *----------------------------------------------------------------------
1523 *
1524 * ReadTRNS --
1525 *
1526 * This function reads the tRNS (transparency) chunk data from the PNG
1527 * file and populates the alpha field of the palette table in the
1528 * PNGImage structure or the single color transparency, as appropriate
1529 * for the color type.
1530 *
1531 * Results:
1532 * TCL_OK, or TCL_ERROR if an I/O error occurs or the tRNS chunk is
1533 * invalid.
1534 *
1535 * Side effects:
1536 * The access position in f advances.
1537 *
1538 *----------------------------------------------------------------------
1539 */
1540
1541 static int
ReadTRNS(Tcl_Interp * interp,PNGImage * pngPtr,int chunkSz,unsigned long crc)1542 ReadTRNS(
1543 Tcl_Interp *interp,
1544 PNGImage *pngPtr,
1545 int chunkSz,
1546 unsigned long crc)
1547 {
1548 unsigned char buffer[PNG_TRNS_MAXSZ];
1549 int i;
1550
1551 if (pngPtr->colorType & PNG_COLOR_ALPHA) {
1552 Tcl_SetObjResult(interp, Tcl_NewStringObj(
1553 "tRNS chunk not allowed color types with a full alpha channel",
1554 -1));
1555 Tcl_SetErrorCode(interp, "TK", "IMAGE", "PNG", "INVALID_TRNS", NULL);
1556 return TCL_ERROR;
1557 }
1558
1559 /*
1560 * For indexed color, there is up to one single-byte transparency value
1561 * per palette entry (thus a max of 256).
1562 */
1563
1564 if (chunkSz > PNG_TRNS_MAXSZ) {
1565 Tcl_SetObjResult(interp, Tcl_NewStringObj(
1566 "invalid tRNS chunk size", -1));
1567 Tcl_SetErrorCode(interp, "TK", "IMAGE", "PNG", "BAD_TRNS", NULL);
1568 return TCL_ERROR;
1569 }
1570
1571 /*
1572 * Read in the raw transparency information.
1573 */
1574
1575 if (ReadData(interp, pngPtr, buffer, chunkSz, &crc) == TCL_ERROR) {
1576 return TCL_ERROR;
1577 }
1578
1579 if (CheckCRC(interp, pngPtr, crc) == TCL_ERROR) {
1580 return TCL_ERROR;
1581 }
1582
1583 switch (pngPtr->colorType) {
1584 case PNG_COLOR_GRAYALPHA:
1585 case PNG_COLOR_RGBA:
1586 break;
1587
1588 case PNG_COLOR_PLTE:
1589 /*
1590 * The number of tRNS entries must be less than or equal to the number
1591 * of PLTE entries, and consists of a single-byte alpha level for the
1592 * corresponding PLTE entry.
1593 */
1594
1595 if (chunkSz > pngPtr->paletteLen) {
1596 Tcl_SetObjResult(interp, Tcl_NewStringObj(
1597 "size of tRNS chunk is too large for the palette", -1));
1598 Tcl_SetErrorCode(interp, "TK", "IMAGE", "PNG", "TRNS_SIZE", NULL);
1599 return TCL_ERROR;
1600 }
1601
1602 for (i=0 ; i<chunkSz ; i++) {
1603 pngPtr->palette[i].alpha = buffer[i];
1604 }
1605 break;
1606
1607 case PNG_COLOR_GRAY:
1608 /*
1609 * Grayscale uses a single 2-byte gray level, which we'll store in
1610 * palette index 0, since we're not using the palette.
1611 */
1612
1613 if (chunkSz != 2) {
1614 Tcl_SetObjResult(interp, Tcl_NewStringObj(
1615 "invalid tRNS chunk size - must 2 bytes for grayscale",
1616 -1));
1617 Tcl_SetErrorCode(interp, "TK", "IMAGE", "PNG", "BAD_TRNS", NULL);
1618 return TCL_ERROR;
1619 }
1620
1621 /*
1622 * According to the PNG specs, if the bit depth is less than 16, then
1623 * only the lower byte is used.
1624 */
1625
1626 if (16 == pngPtr->bitDepth) {
1627 pngPtr->transVal[0] = buffer[0];
1628 pngPtr->transVal[1] = buffer[1];
1629 } else {
1630 pngPtr->transVal[0] = buffer[1];
1631 }
1632 pngPtr->useTRNS = 1;
1633 break;
1634
1635 case PNG_COLOR_RGB:
1636 /*
1637 * TrueColor uses a single RRGGBB triplet.
1638 */
1639
1640 if (chunkSz != 6) {
1641 Tcl_SetObjResult(interp, Tcl_NewStringObj(
1642 "invalid tRNS chunk size - must 6 bytes for RGB", -1));
1643 Tcl_SetErrorCode(interp, "TK", "IMAGE", "PNG", "BAD_TRNS", NULL);
1644 return TCL_ERROR;
1645 }
1646
1647 /*
1648 * According to the PNG specs, if the bit depth is less than 16, then
1649 * only the lower byte is used. But the tRNS chunk still contains two
1650 * bytes per channel.
1651 */
1652
1653 if (16 == pngPtr->bitDepth) {
1654 memcpy(pngPtr->transVal, buffer, 6);
1655 } else {
1656 pngPtr->transVal[0] = buffer[1];
1657 pngPtr->transVal[1] = buffer[3];
1658 pngPtr->transVal[2] = buffer[5];
1659 }
1660 pngPtr->useTRNS = 1;
1661 break;
1662 }
1663
1664 return TCL_OK;
1665 }
1666
1667 /*
1668 *----------------------------------------------------------------------
1669 *
1670 * ReadPHYS --
1671 *
1672 * This function reads the PHYS (physical size) chunk data from
1673 * the PNG file and populates the fields in the PNGImage
1674 * structure.
1675 *
1676 * Results:
1677 * TCL_OK, or TCL_ERROR if an I/O error occurs or the PHYS chunk is
1678 * invalid.
1679 *
1680 * Side effects:
1681 * The access position in f advances.
1682 *
1683 *----------------------------------------------------------------------
1684 */
1685
1686 static int
ReadPHYS(Tcl_Interp * interp,PNGImage * pngPtr,int chunkSz,unsigned long crc)1687 ReadPHYS(
1688 Tcl_Interp *interp,
1689 PNGImage *pngPtr,
1690 int chunkSz,
1691 unsigned long crc)
1692 {
1693 unsigned long PPUx, PPUy;
1694 char unitSpecifier;
1695
1696 /*
1697 * Check chunk size equal 9 bytes
1698 */
1699
1700 if (chunkSz != 9) {
1701 Tcl_SetObjResult(interp, Tcl_NewStringObj(
1702 "invalid physical chunk size", -1));
1703 Tcl_SetErrorCode(interp, "TK", "IMAGE", "PNG", "BAD_PHYS", NULL);
1704 return TCL_ERROR;
1705 }
1706
1707 /*
1708 * Read the chunk data
1709 * 4 bytes: Pixels per unit, x axis
1710 * 4 bytes: Pixels per unit, y axis
1711 * 1 byte: unit specifier
1712 */
1713
1714 if (ReadInt32(interp, pngPtr, &PPUx, &crc) == TCL_ERROR) {
1715 return TCL_ERROR;
1716 }
1717 if (ReadInt32(interp, pngPtr, &PPUy, &crc) == TCL_ERROR) {
1718 return TCL_ERROR;
1719 }
1720 if (ReadData(interp, pngPtr, (unsigned char *)&unitSpecifier, 1, &crc) == TCL_ERROR) {
1721 return TCL_ERROR;
1722 }
1723
1724 if (CheckCRC(interp, pngPtr, crc) == TCL_ERROR) {
1725 return TCL_ERROR;
1726 }
1727
1728 if ( PPUx > 2147483647 || PPUy > 2147483647
1729 || unitSpecifier > 1 ) {
1730 Tcl_SetObjResult(interp, Tcl_NewStringObj(
1731 "invalid physical size value", -1));
1732 Tcl_SetErrorCode(interp, "TK", "IMAGE", "PNG", "BAD_PHYS", NULL);
1733 return TCL_ERROR;
1734 }
1735
1736 if (PPUx > 0) {
1737 pngPtr->aspect = ((double) PPUy) / ((double) PPUx);
1738 }
1739 if (1 == unitSpecifier) {
1740 pngPtr->DPI = ((double) PPUx) * 0.0254;
1741 }
1742 return TCL_OK;
1743 }
1744
1745 /*
1746 *----------------------------------------------------------------------
1747 *
1748 * Paeth --
1749 *
1750 * Utility function for applying the Paeth filter to a pixel. The Paeth
1751 * filter is a linear function of the pixel to be filtered and the pixels
1752 * to the left, above, and above-left of the pixel to be unfiltered.
1753 *
1754 * Results:
1755 * Result of the Paeth function for the left, above, and above-left
1756 * pixels.
1757 *
1758 * Side effects:
1759 * None
1760 *
1761 *----------------------------------------------------------------------
1762 */
1763
1764 static inline unsigned char
Paeth(int a,int b,int c)1765 Paeth(
1766 int a,
1767 int b,
1768 int c)
1769 {
1770 int pa = abs(b - c);
1771 int pb = abs(a - c);
1772 int pc = abs(a + b - c - c);
1773
1774 if ((pa <= pb) && (pa <= pc)) {
1775 return (unsigned char) a;
1776 }
1777
1778 if (pb <= pc) {
1779 return (unsigned char) b;
1780 }
1781
1782 return (unsigned char) c;
1783 }
1784
1785 /*
1786 *----------------------------------------------------------------------
1787 *
1788 * UnfilterLine --
1789 *
1790 * Applies the filter algorithm specified in first byte of a line to the
1791 * line of pixels being read from a PNG image.
1792 *
1793 * PNG specifies four filter algorithms (Sub, Up, Average, and Paeth)
1794 * that combine a pixel's value with those of other pixels in the same
1795 * and/or previous lines. Filtering is intended to make an image more
1796 * compressible.
1797 *
1798 * Results:
1799 * TCL_OK, or TCL_ERROR if the filter type is not recognized.
1800 *
1801 * Side effects:
1802 * Pixel data in thisLineObj are modified.
1803 *
1804 *----------------------------------------------------------------------
1805 */
1806
1807 static int
UnfilterLine(Tcl_Interp * interp,PNGImage * pngPtr)1808 UnfilterLine(
1809 Tcl_Interp *interp,
1810 PNGImage *pngPtr)
1811 {
1812 unsigned char *thisLine =
1813 Tcl_GetByteArrayFromObj(pngPtr->thisLineObj, (int *)NULL);
1814 unsigned char *lastLine =
1815 Tcl_GetByteArrayFromObj(pngPtr->lastLineObj, (int *)NULL);
1816
1817 #define PNG_FILTER_NONE 0
1818 #define PNG_FILTER_SUB 1
1819 #define PNG_FILTER_UP 2
1820 #define PNG_FILTER_AVG 3
1821 #define PNG_FILTER_PAETH 4
1822
1823 switch (*thisLine) {
1824 case PNG_FILTER_NONE: /* Nothing to do */
1825 break;
1826 case PNG_FILTER_SUB: { /* Sub(x) = Raw(x) - Raw(x-bpp) */
1827 unsigned char *rawBpp = thisLine + 1;
1828 unsigned char *raw = rawBpp + pngPtr->bytesPerPixel;
1829 unsigned char *end = thisLine + pngPtr->phaseSize;
1830
1831 while (raw < end) {
1832 *raw++ += *rawBpp++;
1833 }
1834 break;
1835 }
1836 case PNG_FILTER_UP: /* Up(x) = Raw(x) - Prior(x) */
1837 if (pngPtr->currentLine > startLine[pngPtr->phase]) {
1838 unsigned char *prior = lastLine + 1;
1839 unsigned char *raw = thisLine + 1;
1840 unsigned char *end = thisLine + pngPtr->phaseSize;
1841
1842 while (raw < end) {
1843 *raw++ += *prior++;
1844 }
1845 }
1846 break;
1847 case PNG_FILTER_AVG:
1848 /* Avg(x) = Raw(x) - floor((Raw(x-bpp)+Prior(x))/2) */
1849 if (pngPtr->currentLine > startLine[pngPtr->phase]) {
1850 unsigned char *prior = lastLine + 1;
1851 unsigned char *rawBpp = thisLine + 1;
1852 unsigned char *raw = rawBpp;
1853 unsigned char *end = thisLine + pngPtr->phaseSize;
1854 unsigned char *end2 = raw + pngPtr->bytesPerPixel;
1855
1856 while ((raw < end2) && (raw < end)) {
1857 *raw++ += *prior++ / 2;
1858 }
1859
1860 while (raw < end) {
1861 *raw++ += (unsigned char)
1862 (((int) *rawBpp++ + (int) *prior++) / 2);
1863 }
1864 } else {
1865 unsigned char *rawBpp = thisLine + 1;
1866 unsigned char *raw = rawBpp + pngPtr->bytesPerPixel;
1867 unsigned char *end = thisLine + pngPtr->phaseSize;
1868
1869 while (raw < end) {
1870 *raw++ += *rawBpp++ / 2;
1871 }
1872 }
1873 break;
1874 case PNG_FILTER_PAETH:
1875 /* Paeth(x) = Raw(x) - PaethPredictor(Raw(x-bpp), Prior(x), Prior(x-bpp)) */
1876 if (pngPtr->currentLine > startLine[pngPtr->phase]) {
1877 unsigned char *priorBpp = lastLine + 1;
1878 unsigned char *prior = priorBpp;
1879 unsigned char *rawBpp = thisLine + 1;
1880 unsigned char *raw = rawBpp;
1881 unsigned char *end = thisLine + pngPtr->phaseSize;
1882 unsigned char *end2 = rawBpp + pngPtr->bytesPerPixel;
1883
1884 while ((raw < end) && (raw < end2)) {
1885 *raw++ += *prior++;
1886 }
1887
1888 while (raw < end) {
1889 *raw++ += Paeth(*rawBpp++, *prior++, *priorBpp++);
1890 }
1891 } else {
1892 unsigned char *rawBpp = thisLine + 1;
1893 unsigned char *raw = rawBpp + pngPtr->bytesPerPixel;
1894 unsigned char *end = thisLine + pngPtr->phaseSize;
1895
1896 while (raw < end) {
1897 *raw++ += *rawBpp++;
1898 }
1899 }
1900 break;
1901 default:
1902 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
1903 "invalid filter type %d", *thisLine));
1904 Tcl_SetErrorCode(interp, "TK", "IMAGE", "PNG", "BAD_FILTER", NULL);
1905 return TCL_ERROR;
1906 }
1907
1908 return TCL_OK;
1909 }
1910
1911 /*
1912 *----------------------------------------------------------------------
1913 *
1914 * DecodeLine --
1915 *
1916 * Unfilters a line of pixels from the PNG source data and decodes the
1917 * data into the Tk_PhotoImageBlock for later copying into the Tk image.
1918 *
1919 * Results:
1920 * TCL_OK, or TCL_ERROR if the filter type is not recognized.
1921 *
1922 * Side effects:
1923 * Pixel data in thisLine and block are modified and state information
1924 * updated.
1925 *
1926 *----------------------------------------------------------------------
1927 */
1928
1929 static int
DecodeLine(Tcl_Interp * interp,PNGImage * pngPtr)1930 DecodeLine(
1931 Tcl_Interp *interp,
1932 PNGImage *pngPtr)
1933 {
1934 unsigned char *pixelPtr = pngPtr->block.pixelPtr;
1935 int colNum = 0; /* Current pixel column */
1936 unsigned char chan = 0; /* Current channel (0..3) = (R, G, B, A) */
1937 unsigned char readByte = 0; /* Current scan line byte */
1938 int haveBits = 0; /* Number of bits remaining in current byte */
1939 unsigned char pixBits = 0; /* Extracted bits for current channel */
1940 int shifts = 0; /* Number of channels extracted from byte */
1941 int offset = 0; /* Current offset into pixelPtr */
1942 int colStep = 1; /* Column increment each pass */
1943 int pixStep = 0; /* extra pixelPtr increment each pass */
1944 unsigned char lastPixel[6];
1945 unsigned char *p = Tcl_GetByteArrayFromObj(pngPtr->thisLineObj, (int *)NULL);
1946
1947 p++;
1948 if (UnfilterLine(interp, pngPtr) == TCL_ERROR) {
1949 return TCL_ERROR;
1950 }
1951 if (pngPtr->currentLine >= pngPtr->block.height) {
1952 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
1953 "PNG image data overflow"));
1954 Tcl_SetErrorCode(interp, "TK", "IMAGE", "PNG", "DATA_OVERFLOW", NULL);
1955 return TCL_ERROR;
1956 }
1957
1958
1959 if (pngPtr->interlace) {
1960 switch (pngPtr->phase) {
1961 case 1: /* Phase 1: */
1962 colStep = 8; /* 1 pixel per block of 8 per line */
1963 break; /* Start at column 0 */
1964 case 2: /* Phase 2: */
1965 colStep = 8; /* 1 pixels per block of 8 per line */
1966 colNum = 4; /* Start at column 4 */
1967 break;
1968 case 3: /* Phase 3: */
1969 colStep = 4; /* 2 pixels per block of 8 per line */
1970 break; /* Start at column 0 */
1971 case 4: /* Phase 4: */
1972 colStep = 4; /* 2 pixels per block of 8 per line */
1973 colNum = 2; /* Start at column 2 */
1974 break;
1975 case 5: /* Phase 5: */
1976 colStep = 2; /* 4 pixels per block of 8 per line */
1977 break; /* Start at column 0 */
1978 case 6: /* Phase 6: */
1979 colStep = 2; /* 4 pixels per block of 8 per line */
1980 colNum = 1; /* Start at column 1 */
1981 break;
1982 /* Phase 7: */
1983 /* 8 pixels per block of 8 per line */
1984 /* Start at column 0 */
1985 }
1986 }
1987
1988 /*
1989 * Calculate offset into pixelPtr for the first pixel of the line.
1990 */
1991
1992 offset = pngPtr->currentLine * pngPtr->block.pitch;
1993
1994 /*
1995 * Adjust up for the starting pixel of the line.
1996 */
1997
1998 offset += colNum * pngPtr->block.pixelSize;
1999
2000 /*
2001 * Calculate the extra number of bytes to skip between columns.
2002 */
2003
2004 pixStep = (colStep - 1) * pngPtr->block.pixelSize;
2005
2006 for ( ; colNum < pngPtr->block.width ; colNum += colStep) {
2007 if (haveBits < (pngPtr->bitDepth * pngPtr->numChannels)) {
2008 haveBits = 0;
2009 }
2010
2011 for (chan = 0 ; chan < pngPtr->numChannels ; chan++) {
2012 if (!haveBits) {
2013 shifts = 0;
2014 readByte = *p++;
2015 haveBits += 8;
2016 }
2017
2018 if (16 == pngPtr->bitDepth) {
2019 pngPtr->block.pixelPtr[offset++] = readByte;
2020
2021 if (pngPtr->useTRNS) {
2022 lastPixel[chan * 2] = readByte;
2023 }
2024
2025 readByte = *p++;
2026
2027 if (pngPtr->useTRNS) {
2028 lastPixel[(chan * 2) + 1] = readByte;
2029 }
2030
2031 pngPtr->block.pixelPtr[offset++] = readByte;
2032
2033 haveBits = 0;
2034 continue;
2035 }
2036
2037 switch (pngPtr->bitDepth) {
2038 case 1:
2039 pixBits = (unsigned char)((readByte >> (7-shifts)) & 0x01);
2040 break;
2041 case 2:
2042 pixBits = (unsigned char)((readByte >> (6-shifts*2)) & 0x03);
2043 break;
2044 case 4:
2045 pixBits = (unsigned char)((readByte >> (4-shifts*4)) & 0x0f);
2046 break;
2047 case 8:
2048 pixBits = readByte;
2049 break;
2050 }
2051
2052 if (PNG_COLOR_PLTE == pngPtr->colorType) {
2053 pixelPtr[offset++] = pngPtr->palette[pixBits].red;
2054 pixelPtr[offset++] = pngPtr->palette[pixBits].green;
2055 pixelPtr[offset++] = pngPtr->palette[pixBits].blue;
2056 pixelPtr[offset++] = pngPtr->palette[pixBits].alpha;
2057 chan += 2;
2058 } else {
2059 pixelPtr[offset++] = (unsigned char)
2060 (pixBits * pngPtr->bitScale);
2061
2062 if (pngPtr->useTRNS) {
2063 lastPixel[chan] = pixBits;
2064 }
2065 }
2066
2067 haveBits -= pngPtr->bitDepth;
2068 shifts++;
2069 }
2070
2071 /*
2072 * Apply boolean transparency via tRNS data if necessary (where
2073 * necessary means a tRNS chunk was provided and we're not using an
2074 * alpha channel or indexed alpha).
2075 */
2076
2077 if ((PNG_COLOR_PLTE != pngPtr->colorType) &&
2078 !(pngPtr->colorType & PNG_COLOR_ALPHA)) {
2079 unsigned char alpha;
2080
2081 if (pngPtr->useTRNS) {
2082 if (memcmp(lastPixel, pngPtr->transVal,
2083 pngPtr->bytesPerPixel) == 0) {
2084 alpha = 0x00;
2085 } else {
2086 alpha = 0xff;
2087 }
2088 } else {
2089 alpha = 0xff;
2090 }
2091
2092 pixelPtr[offset++] = alpha;
2093
2094 if (16 == pngPtr->bitDepth) {
2095 pixelPtr[offset++] = alpha;
2096 }
2097 }
2098
2099 offset += pixStep;
2100 }
2101
2102 if (pngPtr->interlace) {
2103 /* Skip lines */
2104
2105 switch (pngPtr->phase) {
2106 case 1: case 2: case 3:
2107 pngPtr->currentLine += 8;
2108 break;
2109 case 4: case 5:
2110 pngPtr->currentLine += 4;
2111 break;
2112 case 6: case 7:
2113 pngPtr->currentLine += 2;
2114 break;
2115 }
2116
2117 /*
2118 * Start the next phase if there are no more lines to do.
2119 */
2120
2121 if (pngPtr->currentLine >= pngPtr->block.height) {
2122 unsigned long pixels = 0;
2123
2124 while ((!pixels || (pngPtr->currentLine >= pngPtr->block.height))
2125 && (pngPtr->phase < 7)) {
2126 pngPtr->phase++;
2127
2128 switch (pngPtr->phase) {
2129 case 2:
2130 pixels = (pngPtr->block.width + 3) >> 3;
2131 pngPtr->currentLine = 0;
2132 break;
2133 case 3:
2134 pixels = (pngPtr->block.width + 3) >> 2;
2135 pngPtr->currentLine = 4;
2136 break;
2137 case 4:
2138 pixels = (pngPtr->block.width + 1) >> 2;
2139 pngPtr->currentLine = 0;
2140 break;
2141 case 5:
2142 pixels = (pngPtr->block.width + 1) >> 1;
2143 pngPtr->currentLine = 2;
2144 break;
2145 case 6:
2146 pixels = pngPtr->block.width >> 1;
2147 pngPtr->currentLine = 0;
2148 break;
2149 case 7:
2150 pngPtr->currentLine = 1;
2151 pixels = pngPtr->block.width;
2152 break;
2153 }
2154 }
2155
2156 if (16 == pngPtr->bitDepth) {
2157 pngPtr->phaseSize = 1 + (pngPtr->numChannels * pixels * 2);
2158 } else {
2159 pngPtr->phaseSize = 1 + ((pngPtr->numChannels * pixels *
2160 pngPtr->bitDepth + 7) >> 3);
2161 }
2162 }
2163 } else {
2164 pngPtr->currentLine++;
2165 }
2166
2167 return TCL_OK;
2168 }
2169
2170 /*
2171 *----------------------------------------------------------------------
2172 *
2173 * ReadIDAT --
2174 *
2175 * This function reads the IDAT (pixel data) chunk from the PNG file to
2176 * build the image. It will continue reading until all IDAT chunks have
2177 * been processed or an error occurs.
2178 *
2179 * Results:
2180 * TCL_OK, or TCL_ERROR if an I/O error occurs or an IDAT chunk is
2181 * invalid.
2182 *
2183 * Side effects:
2184 * The access position in f advances. Memory may be allocated by zlib
2185 * through PNGZAlloc.
2186 *
2187 *----------------------------------------------------------------------
2188 */
2189
2190 static int
ReadIDAT(Tcl_Interp * interp,PNGImage * pngPtr,int chunkSz,unsigned long crc)2191 ReadIDAT(
2192 Tcl_Interp *interp,
2193 PNGImage *pngPtr,
2194 int chunkSz,
2195 unsigned long crc)
2196 {
2197 /*
2198 * Process IDAT contents until there is no more in this chunk.
2199 */
2200
2201 while (chunkSz && !Tcl_ZlibStreamEof(pngPtr->stream)) {
2202 TkSizeT len1, len2;
2203
2204 /*
2205 * Read another block of input into the zlib stream if data remains.
2206 */
2207
2208 if (chunkSz) {
2209 Tcl_Obj *inputObj = NULL;
2210 int blockSz = PNG_MIN(chunkSz, PNG_BLOCK_SZ);
2211 unsigned char *inputPtr = NULL;
2212
2213 /*
2214 * Check for end of zlib stream.
2215 */
2216
2217 if (Tcl_ZlibStreamEof(pngPtr->stream)) {
2218 Tcl_SetObjResult(interp, Tcl_NewStringObj(
2219 "extra data after end of zlib stream", -1));
2220 Tcl_SetErrorCode(interp, "TK", "IMAGE", "PNG", "EXTRA_DATA",
2221 NULL);
2222 return TCL_ERROR;
2223 }
2224
2225 inputObj = Tcl_NewObj();
2226 Tcl_IncrRefCount(inputObj);
2227 inputPtr = Tcl_SetByteArrayLength(inputObj, blockSz);
2228
2229 /*
2230 * Read the next bit of IDAT chunk data, up to read buffer size.
2231 */
2232
2233 if (ReadData(interp, pngPtr, inputPtr, blockSz,
2234 &crc) == TCL_ERROR) {
2235 Tcl_DecrRefCount(inputObj);
2236 return TCL_ERROR;
2237 }
2238
2239 chunkSz -= blockSz;
2240
2241 Tcl_ZlibStreamPut(pngPtr->stream, inputObj, TCL_ZLIB_NO_FLUSH);
2242 Tcl_DecrRefCount(inputObj);
2243 }
2244
2245 /*
2246 * Inflate, processing each output buffer's worth as a line of pixels,
2247 * until we cannot fill the buffer any more.
2248 */
2249
2250 getNextLine:
2251 Tcl_GetByteArrayFromObj(pngPtr->thisLineObj, &len1);
2252 if (Tcl_ZlibStreamGet(pngPtr->stream, pngPtr->thisLineObj,
2253 pngPtr->phaseSize - len1) == TCL_ERROR) {
2254 return TCL_ERROR;
2255 }
2256 Tcl_GetByteArrayFromObj(pngPtr->thisLineObj, &len2);
2257
2258 if (len2 == (TkSizeT)pngPtr->phaseSize) {
2259 if (pngPtr->phase > 7) {
2260 Tcl_SetObjResult(interp, Tcl_NewStringObj(
2261 "extra data after final scan line of final phase",
2262 -1));
2263 Tcl_SetErrorCode(interp, "TK", "IMAGE", "PNG", "EXTRA_DATA",
2264 NULL);
2265 return TCL_ERROR;
2266 }
2267
2268 if (DecodeLine(interp, pngPtr) == TCL_ERROR) {
2269 return TCL_ERROR;
2270 }
2271
2272 /*
2273 * Swap the current/last lines so that we always have the last
2274 * line processed available, which is necessary for filtering.
2275 */
2276
2277 {
2278 Tcl_Obj *temp = pngPtr->lastLineObj;
2279
2280 pngPtr->lastLineObj = pngPtr->thisLineObj;
2281 pngPtr->thisLineObj = temp;
2282 }
2283 Tcl_SetByteArrayLength(pngPtr->thisLineObj, 0);
2284
2285 /*
2286 * Try to read another line of pixels out of the buffer
2287 * immediately, but don't allow write past end of block.
2288 */
2289
2290 if (pngPtr->currentLine < pngPtr->block.height) {
2291 goto getNextLine;
2292 }
2293
2294 }
2295
2296 /*
2297 * Got less than a whole buffer-load of pixels. Either we're going to
2298 * be getting more data from the next IDAT, or we've done what we can
2299 * here.
2300 */
2301 }
2302
2303 /*
2304 * Ensure that if we've got to the end of the compressed data, we've
2305 * also got to the end of the compressed stream. This sanity check is
2306 * enforced by most PNG readers.
2307 */
2308
2309 if (chunkSz != 0) {
2310 Tcl_SetObjResult(interp, Tcl_NewStringObj(
2311 "compressed data after stream finalize in PNG data", -1));
2312 Tcl_SetErrorCode(interp, "TK", "IMAGE", "PNG", "EXTRA_DATA", NULL);
2313 return TCL_ERROR;
2314 }
2315
2316 return CheckCRC(interp, pngPtr, crc);
2317 }
2318
2319 /*
2320 *----------------------------------------------------------------------
2321 *
2322 * ApplyAlpha --
2323 *
2324 * Applies an overall alpha value to a complete image that has been read.
2325 * This alpha value is specified using the -format option to [image
2326 * create photo].
2327 *
2328 * Results:
2329 * N/A
2330 *
2331 * Side effects:
2332 * The access position in f may change.
2333 *
2334 *----------------------------------------------------------------------
2335 */
2336
2337 static void
ApplyAlpha(PNGImage * pngPtr)2338 ApplyAlpha(
2339 PNGImage *pngPtr)
2340 {
2341 if (pngPtr->alpha != 1.0) {
2342 unsigned char *p = pngPtr->block.pixelPtr;
2343 unsigned char *endPtr = p + pngPtr->blockLen;
2344 int offset = pngPtr->block.offset[3];
2345
2346 p += offset;
2347
2348 if (16 == pngPtr->bitDepth) {
2349 unsigned int channel;
2350
2351 while (p < endPtr) {
2352 channel = (unsigned int)
2353 (((p[0] << 8) | p[1]) * pngPtr->alpha);
2354
2355 *p++ = (unsigned char) (channel >> 8);
2356 *p++ = (unsigned char) (channel & 0xff);
2357
2358 p += offset;
2359 }
2360 } else {
2361 while (p < endPtr) {
2362 p[0] = (unsigned char) (pngPtr->alpha * p[0]);
2363 p += 1 + offset;
2364 }
2365 }
2366 }
2367 }
2368
2369 /*
2370 *----------------------------------------------------------------------
2371 *
2372 * ParseFormat --
2373 *
2374 * This function parses the -format string that can be specified to the
2375 * [image create photo] command to extract options for postprocessing of
2376 * loaded images. Currently, this just allows specifying and applying an
2377 * overall alpha value to the loaded image (for example, to make it
2378 * entirely 50% as transparent as the actual image file).
2379 *
2380 * Results:
2381 * TCL_OK, or TCL_ERROR if the format specification is invalid.
2382 *
2383 * Side effects:
2384 * None
2385 *
2386 *----------------------------------------------------------------------
2387 */
2388
2389 static int
ParseFormat(Tcl_Interp * interp,Tcl_Obj * fmtObj,PNGImage * pngPtr)2390 ParseFormat(
2391 Tcl_Interp *interp,
2392 Tcl_Obj *fmtObj,
2393 PNGImage *pngPtr)
2394 {
2395 Tcl_Obj **objv = NULL;
2396 int objc = 0;
2397 static const char *const fmtOptions[] = {
2398 "-alpha", NULL
2399 };
2400 enum fmtOptionsEnum {
2401 OPT_ALPHA
2402 };
2403
2404 /*
2405 * Extract elements of format specification as a list.
2406 */
2407
2408 if (fmtObj &&
2409 Tcl_ListObjGetElements(interp, fmtObj, &objc, &objv) != TCL_OK) {
2410 return TCL_ERROR;
2411 }
2412
2413 for (; objc>0 ; objc--, objv++) {
2414 int optIndex;
2415
2416 /*
2417 * Ignore the "png" part of the format specification.
2418 */
2419
2420 if (!strcasecmp(Tcl_GetString(objv[0]), "png")) {
2421 continue;
2422 }
2423
2424 if (Tcl_GetIndexFromObjStruct(interp, objv[0], fmtOptions,
2425 sizeof(char *), "option", 0, &optIndex) == TCL_ERROR) {
2426 return TCL_ERROR;
2427 }
2428
2429 if (objc < 2) {
2430 Tcl_WrongNumArgs(interp, 1, objv, "value");
2431 return TCL_ERROR;
2432 }
2433
2434 objc--;
2435 objv++;
2436
2437 switch ((enum fmtOptionsEnum) optIndex) {
2438 case OPT_ALPHA:
2439 if (Tcl_GetDoubleFromObj(interp, objv[0],
2440 &pngPtr->alpha) == TCL_ERROR) {
2441 return TCL_ERROR;
2442 }
2443
2444 if ((pngPtr->alpha < 0.0) || (pngPtr->alpha > 1.0)) {
2445 Tcl_SetObjResult(interp, Tcl_NewStringObj(
2446 "-alpha value must be between 0.0 and 1.0", -1));
2447 Tcl_SetErrorCode(interp, "TK", "IMAGE", "PNG", "BAD_ALPHA",
2448 NULL);
2449 return TCL_ERROR;
2450 }
2451 break;
2452 }
2453 }
2454
2455 return TCL_OK;
2456 }
2457
2458 /*
2459 *----------------------------------------------------------------------
2460 *
2461 * DecodePNG --
2462 *
2463 * This function handles the entirety of reading a PNG file (or data)
2464 * from the first byte to the last.
2465 *
2466 * Results:
2467 * TCL_OK, or TCL_ERROR if an I/O error occurs or any problems are
2468 * detected in the PNG file.
2469 *
2470 * Side effects:
2471 * The access position in f advances. Memory may be allocated and image
2472 * dimensions and contents may change.
2473 *
2474 *----------------------------------------------------------------------
2475 */
2476
2477 static int
DecodePNG(Tcl_Interp * interp,PNGImage * pngPtr,Tcl_Obj * fmtObj,Tk_PhotoHandle imageHandle,int destX,int destY)2478 DecodePNG(
2479 Tcl_Interp *interp,
2480 PNGImage *pngPtr,
2481 Tcl_Obj *fmtObj,
2482 Tk_PhotoHandle imageHandle,
2483 int destX,
2484 int destY)
2485 {
2486 unsigned long chunkType;
2487 size_t chunkSz;
2488 unsigned long crc;
2489
2490 /*
2491 * Parse the PNG signature and IHDR (header) chunk.
2492 */
2493
2494 if (ReadIHDR(interp, pngPtr) == TCL_ERROR) {
2495 return TCL_ERROR;
2496 }
2497
2498 /*
2499 * Extract alpha value from -format object, if specified.
2500 */
2501
2502 if (ParseFormat(interp, fmtObj, pngPtr) == TCL_ERROR) {
2503 return TCL_ERROR;
2504 }
2505
2506 /*
2507 * The next chunk may either be a PLTE (Palette) chunk or the first of at
2508 * least one IDAT (data) chunks. It could also be one of a number of
2509 * ancillary chunks, but those are skipped for us by the switch in
2510 * ReadChunkHeader().
2511 *
2512 * PLTE is mandatory for color type 3 and forbidden for 2 and 6
2513 */
2514
2515 if (ReadChunkHeader(interp, pngPtr, &chunkSz, &chunkType,
2516 &crc) == TCL_ERROR) {
2517 return TCL_ERROR;
2518 }
2519
2520 /*
2521 * Physical header may be present here so try to parse it
2522 */
2523
2524 if (CHUNK_pHYs == chunkType) {
2525 /*
2526 * Finish parsing the PHYS chunk.
2527 */
2528
2529 if (ReadPHYS(interp, pngPtr, chunkSz, crc) == TCL_ERROR) {
2530 return TCL_ERROR;
2531 }
2532
2533 /*
2534 * Begin the next chunk.
2535 */
2536
2537 if (ReadChunkHeader(interp, pngPtr, &chunkSz, &chunkType,
2538 &crc) == TCL_ERROR) {
2539 return TCL_ERROR;
2540 }
2541 }
2542
2543 if (CHUNK_PLTE == chunkType) {
2544 /*
2545 * Finish parsing the PLTE chunk.
2546 */
2547
2548 if (ReadPLTE(interp, pngPtr, chunkSz, crc) == TCL_ERROR) {
2549 return TCL_ERROR;
2550 }
2551
2552 /*
2553 * Begin the next chunk.
2554 */
2555
2556 if (ReadChunkHeader(interp, pngPtr, &chunkSz, &chunkType,
2557 &crc) == TCL_ERROR) {
2558 return TCL_ERROR;
2559 }
2560 } else if (PNG_COLOR_PLTE == pngPtr->colorType) {
2561 Tcl_SetObjResult(interp, Tcl_NewStringObj(
2562 "PLTE chunk required for indexed color", -1));
2563 Tcl_SetErrorCode(interp, "TK", "IMAGE", "PNG", "NEED_PLTE", NULL);
2564 return TCL_ERROR;
2565 }
2566
2567 /*
2568 * The next chunk may be a tRNS (palette transparency) chunk, depending on
2569 * the color type. It must come after the PLTE chunk and before the IDAT
2570 * chunk, but can be present if there is no PLTE chunk because it can be
2571 * used for Grayscale and TrueColor in lieu of an alpha channel.
2572 */
2573
2574 if (CHUNK_tRNS == chunkType) {
2575 /*
2576 * Finish parsing the tRNS chunk.
2577 */
2578
2579 if (ReadTRNS(interp, pngPtr, chunkSz, crc) == TCL_ERROR) {
2580 return TCL_ERROR;
2581 }
2582
2583 /*
2584 * Begin the next chunk.
2585 */
2586
2587 if (ReadChunkHeader(interp, pngPtr, &chunkSz, &chunkType,
2588 &crc) == TCL_ERROR) {
2589 return TCL_ERROR;
2590 }
2591 }
2592
2593 /*
2594 * Physical header may be present here so try to parse it
2595 */
2596
2597 if (CHUNK_pHYs == chunkType) {
2598 /*
2599 * Finish parsing the PHYS chunk.
2600 */
2601
2602 if (ReadPHYS(interp, pngPtr, chunkSz, crc) == TCL_ERROR) {
2603 return TCL_ERROR;
2604 }
2605
2606 /*
2607 * Begin the next chunk.
2608 */
2609
2610 if (ReadChunkHeader(interp, pngPtr, &chunkSz, &chunkType,
2611 &crc) == TCL_ERROR) {
2612 return TCL_ERROR;
2613 }
2614 }
2615
2616 /*
2617 * Other ancillary chunk types could appear here, but for now we're only
2618 * interested in IDAT. The others should have been skipped.
2619 */
2620
2621 if (chunkType != CHUNK_IDAT) {
2622 Tcl_SetObjResult(interp, Tcl_NewStringObj(
2623 "at least one IDAT chunk is required", -1));
2624 Tcl_SetErrorCode(interp, "TK", "IMAGE", "PNG", "NEED_IDAT", NULL);
2625 return TCL_ERROR;
2626 }
2627
2628 /*
2629 * Expand the photo size (if not set by the user) to provide enough space
2630 * for the image being parsed. It does not matter if width or height wrap
2631 * to negative here: Tk will not shrink the image.
2632 */
2633
2634 if (Tk_PhotoExpand(interp, imageHandle, destX + pngPtr->block.width,
2635 destY + pngPtr->block.height) == TCL_ERROR) {
2636 return TCL_ERROR;
2637 }
2638
2639 /*
2640 * A scan line consists of one byte for a filter type, plus the number of
2641 * bits per color sample times the number of color samples per pixel.
2642 */
2643
2644 if (pngPtr->block.width > ((INT_MAX - 1) / (pngPtr->numChannels * 2))) {
2645 Tcl_SetObjResult(interp, Tcl_NewStringObj(
2646 "line size is out of supported range on this architecture",
2647 -1));
2648 Tcl_SetErrorCode(interp, "TK", "IMAGE", "PNG", "LINE_SIZE", NULL);
2649 return TCL_ERROR;
2650 }
2651
2652 if (16 == pngPtr->bitDepth) {
2653 pngPtr->lineSize = 1 + (pngPtr->numChannels * pngPtr->block.width*2);
2654 } else {
2655 pngPtr->lineSize = 1 + ((pngPtr->numChannels * pngPtr->block.width) /
2656 (8 / pngPtr->bitDepth));
2657 if (pngPtr->block.width % (8 / pngPtr->bitDepth)) {
2658 pngPtr->lineSize++;
2659 }
2660 }
2661
2662 /*
2663 * Allocate space for decoding the scan lines.
2664 */
2665
2666 pngPtr->lastLineObj = Tcl_NewObj();
2667 Tcl_IncrRefCount(pngPtr->lastLineObj);
2668 pngPtr->thisLineObj = Tcl_NewObj();
2669 Tcl_IncrRefCount(pngPtr->thisLineObj);
2670
2671 pngPtr->block.pixelPtr = (unsigned char *)attemptckalloc(pngPtr->blockLen);
2672 if (!pngPtr->block.pixelPtr) {
2673 Tcl_SetObjResult(interp, Tcl_NewStringObj(
2674 "memory allocation failed", -1));
2675 Tcl_SetErrorCode(interp, "TK", "MALLOC", NULL);
2676 return TCL_ERROR;
2677 }
2678
2679 /*
2680 * Determine size of the first phase if interlaced. Phase size should
2681 * always be <= line size, so probably not necessary to check for
2682 * arithmetic overflow here: should be covered by line size check.
2683 */
2684
2685 if (pngPtr->interlace) {
2686 /*
2687 * Only one pixel per block of 8 per line in the first phase.
2688 */
2689
2690 unsigned int pixels = (pngPtr->block.width + 7) >> 3;
2691
2692 pngPtr->phase = 1;
2693 if (16 == pngPtr->bitDepth) {
2694 pngPtr->phaseSize = 1 + pngPtr->numChannels*pixels*2;
2695 } else {
2696 pngPtr->phaseSize = 1 +
2697 ((pngPtr->numChannels*pixels*pngPtr->bitDepth + 7) >> 3);
2698 }
2699 } else {
2700 pngPtr->phaseSize = pngPtr->lineSize;
2701 }
2702
2703 /*
2704 * All of the IDAT (data) chunks must be consecutive.
2705 */
2706
2707 while (CHUNK_IDAT == chunkType) {
2708 if (ReadIDAT(interp, pngPtr, chunkSz, crc) == TCL_ERROR) {
2709 return TCL_ERROR;
2710 }
2711
2712 if (ReadChunkHeader(interp, pngPtr, &chunkSz, &chunkType,
2713 &crc) == TCL_ERROR) {
2714 return TCL_ERROR;
2715 }
2716 }
2717
2718 /*
2719 * Ensure that we've got to the end of the compressed stream now that
2720 * there are no more IDAT segments. This sanity check is enforced by most
2721 * PNG readers.
2722 */
2723
2724 if (!Tcl_ZlibStreamEof(pngPtr->stream)) {
2725 Tcl_SetObjResult(interp, Tcl_NewStringObj(
2726 "unfinalized data stream in PNG data", -1));
2727 Tcl_SetErrorCode(interp, "TK", "IMAGE", "PNG", "EXTRA_DATA", NULL);
2728 return TCL_ERROR;
2729 }
2730
2731 /*
2732 * Now skip the remaining chunks which we're also not interested in.
2733 */
2734
2735 while (CHUNK_IEND != chunkType) {
2736 if (SkipChunk(interp, pngPtr, chunkSz, crc) == TCL_ERROR) {
2737 return TCL_ERROR;
2738 }
2739
2740 if (ReadChunkHeader(interp, pngPtr, &chunkSz, &chunkType,
2741 &crc) == TCL_ERROR) {
2742 return TCL_ERROR;
2743 }
2744 }
2745
2746 /*
2747 * Got the IEND (end of image) chunk. Do some final checks...
2748 */
2749
2750 if (chunkSz) {
2751 Tcl_SetObjResult(interp, Tcl_NewStringObj(
2752 "IEND chunk contents must be empty", -1));
2753 Tcl_SetErrorCode(interp, "TK", "IMAGE", "PNG", "BAD_IEND", NULL);
2754 return TCL_ERROR;
2755 }
2756
2757 /*
2758 * Check the CRC on the IEND chunk.
2759 */
2760
2761 if (CheckCRC(interp, pngPtr, crc) == TCL_ERROR) {
2762 return TCL_ERROR;
2763 }
2764
2765 /*
2766 * TODO: verify that nothing else comes after the IEND chunk, or do we
2767 * really care?
2768 */
2769
2770 #if 0
2771 if (ReadData(interp, pngPtr, &c, 1, NULL) != TCL_ERROR) {
2772 Tcl_SetObjResult(interp, Tcl_NewStringObj(
2773 "extra data following IEND chunk", -1));
2774 Tcl_SetErrorCode(interp, "TK", "IMAGE", "PNG", "BAD_IEND", NULL);
2775 return TCL_ERROR;
2776 }
2777 #endif
2778
2779 /*
2780 * Apply overall image alpha if specified.
2781 */
2782
2783 ApplyAlpha(pngPtr);
2784
2785 /*
2786 * Copy the decoded image block into the Tk photo image.
2787 */
2788
2789 if (Tk_PhotoPutBlock(interp, imageHandle, &pngPtr->block, destX, destY,
2790 pngPtr->block.width, pngPtr->block.height,
2791 TK_PHOTO_COMPOSITE_SET) == TCL_ERROR) {
2792 return TCL_ERROR;
2793 }
2794
2795 return TCL_OK;
2796 }
2797
2798 /*
2799 *----------------------------------------------------------------------
2800 *
2801 * FileMatchPNG --
2802 *
2803 * This function is invoked by the photo image type to see if a file
2804 * contains image data in PNG format.
2805 *
2806 * Results:
2807 * The return value is 1 if the first characters in file f look like PNG
2808 * data, and 0 otherwise.
2809 *
2810 * Side effects:
2811 * The access position in f may change.
2812 *
2813 *----------------------------------------------------------------------
2814 */
2815
2816 static int
FileMatchPNG(Tcl_Interp * interp,Tcl_Channel chan,TCL_UNUSED (const char *),TCL_UNUSED (Tcl_Obj *),TCL_UNUSED (Tcl_Obj *),int * widthPtr,int * heightPtr,TCL_UNUSED (Tcl_Obj *))2817 FileMatchPNG(
2818 Tcl_Interp *interp, /* Interpreter to use for reporting errors. */
2819 Tcl_Channel chan, /* The image file, open for reading. */
2820 TCL_UNUSED(const char *), /* The name of the image file. */
2821 TCL_UNUSED(Tcl_Obj *), /* User-specified format object, or NULL. */
2822 TCL_UNUSED(Tcl_Obj *), /* metadata input, may be NULL */
2823 int *widthPtr, int *heightPtr,
2824 /* The dimensions of the image are returned
2825 * here if the file is a valid raw GIF file. */
2826 TCL_UNUSED(Tcl_Obj *)) /* metadata return dict, may be NULL */
2827 {
2828 PNGImage png;
2829 int match = 0;
2830
2831 InitPNGImage(NULL, &png, chan, NULL, TCL_ZLIB_STREAM_INFLATE);
2832
2833 if (ReadIHDR(interp, &png) == TCL_OK) {
2834 *widthPtr = png.block.width;
2835 *heightPtr = png.block.height;
2836 match = 1;
2837 }
2838
2839 CleanupPNGImage(&png);
2840
2841 return match;
2842 }
2843
2844 /*
2845 *----------------------------------------------------------------------
2846 *
2847 * FileReadPNG --
2848 *
2849 * This function is called by the photo image type to read PNG format
2850 * data from a file and write it into a given photo image.
2851 *
2852 * Results:
2853 * A standard TCL completion code. If TCL_ERROR is returned then an error
2854 * message is left in the interp's result.
2855 *
2856 * Side effects:
2857 * The access position in file f is changed, and new data is added to the
2858 * image given by imageHandle.
2859 *
2860 *----------------------------------------------------------------------
2861 */
2862
2863 static int
FileReadPNG(Tcl_Interp * interp,Tcl_Channel chan,TCL_UNUSED (const char *),Tcl_Obj * fmtObj,TCL_UNUSED (Tcl_Obj *),Tk_PhotoHandle imageHandle,int destX,int destY,TCL_UNUSED (int),TCL_UNUSED (int),TCL_UNUSED (int),TCL_UNUSED (int),Tcl_Obj * metadataOutObj)2864 FileReadPNG(
2865 Tcl_Interp *interp, /* Interpreter to use for reporting errors. */
2866 Tcl_Channel chan, /* The image file, open for reading. */
2867 TCL_UNUSED(const char *), /* The name of the image file. */
2868 Tcl_Obj *fmtObj, /* User-specified format object, or NULL. */
2869 TCL_UNUSED(Tcl_Obj *), /* metadata input, may be NULL */
2870 Tk_PhotoHandle imageHandle, /* The photo image to write into. */
2871 int destX, int destY, /* Coordinates of top-left pixel in photo
2872 * image to be written to. */
2873 TCL_UNUSED(int), /* Dimensions of block of photo image to be
2874 * written to. */
2875 TCL_UNUSED(int),
2876 TCL_UNUSED(int), /* Coordinates of top-left pixel to be used in
2877 * image being read. */
2878 TCL_UNUSED(int),
2879 Tcl_Obj *metadataOutObj) /* metadata return dict, may be NULL */
2880 {
2881 PNGImage png;
2882 int result = TCL_ERROR;
2883
2884 result = InitPNGImage(interp, &png, chan, NULL, TCL_ZLIB_STREAM_INFLATE);
2885
2886 if (TCL_OK == result) {
2887 result = DecodePNG(interp, &png, fmtObj, imageHandle, destX, destY);
2888 }
2889
2890 if (TCL_OK == result && metadataOutObj != NULL && png.DPI != -1) {
2891 result = Tcl_DictObjPut(NULL, metadataOutObj,
2892 Tcl_NewStringObj("DPI",-1),
2893 Tcl_NewDoubleObj(png.DPI));
2894 }
2895
2896 if (TCL_OK == result && metadataOutObj != NULL && png.aspect != -1) {
2897 result = Tcl_DictObjPut(NULL, metadataOutObj,
2898 Tcl_NewStringObj("aspect",-1),
2899 Tcl_NewDoubleObj(png.aspect));
2900 }
2901
2902 CleanupPNGImage(&png);
2903 return result;
2904 }
2905
2906 /*
2907 *----------------------------------------------------------------------
2908 *
2909 * StringMatchPNG --
2910 *
2911 * This function is invoked by the photo image type to see if an object
2912 * contains image data in PNG format.
2913 *
2914 * Results:
2915 * The return value is 1 if the first characters in the data are like PNG
2916 * data, and 0 otherwise.
2917 *
2918 * Side effects:
2919 * The size of the image is placed in widthPre and heightPtr.
2920 *
2921 *----------------------------------------------------------------------
2922 */
2923
2924 static int
StringMatchPNG(Tcl_Interp * interp,Tcl_Obj * pObjData,TCL_UNUSED (Tcl_Obj *),TCL_UNUSED (Tcl_Obj *),int * widthPtr,int * heightPtr,TCL_UNUSED (Tcl_Obj *))2925 StringMatchPNG(
2926 Tcl_Interp *interp, /* Interpreter to use for reporting errors. */
2927 Tcl_Obj *pObjData, /* the object containing the image data */
2928 TCL_UNUSED(Tcl_Obj *), /* the image format object, or NULL */
2929 TCL_UNUSED(Tcl_Obj *), /* metadata input, may be NULL */
2930 int *widthPtr, /* where to put the string width */
2931 int *heightPtr, /* where to put the string height */
2932 TCL_UNUSED(Tcl_Obj *)) /* metadata return dict, may be NULL */
2933 {
2934 PNGImage png;
2935 int match = 0;
2936
2937 InitPNGImage(NULL, &png, NULL, pObjData, TCL_ZLIB_STREAM_INFLATE);
2938
2939 png.strDataBuf = Tcl_GetByteArrayFromObj(pObjData, &png.strDataLen);
2940
2941 if (ReadIHDR(interp, &png) == TCL_OK) {
2942 *widthPtr = png.block.width;
2943 *heightPtr = png.block.height;
2944 match = 1;
2945 }
2946
2947 CleanupPNGImage(&png);
2948 return match;
2949 }
2950
2951 /*
2952 *----------------------------------------------------------------------
2953 *
2954 * StringReadPNG --
2955 *
2956 * This function is called by the photo image type to read PNG format
2957 * data from an object and give it to the photo image.
2958 *
2959 * Results:
2960 * A standard TCL completion code. If TCL_ERROR is returned then an error
2961 * message is left in the interp's result.
2962 *
2963 * Side effects:
2964 * New data is added to the image given by imageHandle.
2965 *
2966 *----------------------------------------------------------------------
2967 */
2968
2969 static int
StringReadPNG(Tcl_Interp * interp,Tcl_Obj * pObjData,Tcl_Obj * fmtObj,TCL_UNUSED (Tcl_Obj *),Tk_PhotoHandle imageHandle,int destX,int destY,TCL_UNUSED (int),TCL_UNUSED (int),TCL_UNUSED (int),TCL_UNUSED (int),Tcl_Obj * metadataOutObj)2970 StringReadPNG(
2971 Tcl_Interp *interp, /* interpreter for reporting errors in */
2972 Tcl_Obj *pObjData, /* object containing the image */
2973 Tcl_Obj *fmtObj, /* format object, or NULL */
2974 TCL_UNUSED(Tcl_Obj *), /* metadata input, may be NULL */
2975 Tk_PhotoHandle imageHandle, /* the image to write this data into */
2976 int destX, int destY, /* The rectangular region of the */
2977 TCL_UNUSED(int), /* image to copy */
2978 TCL_UNUSED(int),
2979 TCL_UNUSED(int),
2980 TCL_UNUSED(int),
2981 Tcl_Obj *metadataOutObj) /* metadata return dict, may be NULL */
2982 {
2983 PNGImage png;
2984 int result = TCL_ERROR;
2985
2986 result = InitPNGImage(interp, &png, NULL, pObjData,
2987 TCL_ZLIB_STREAM_INFLATE);
2988
2989 if (TCL_OK == result) {
2990 result = DecodePNG(interp, &png, fmtObj, imageHandle, destX, destY);
2991 }
2992
2993 if (TCL_OK == result && metadataOutObj != NULL && png.DPI != -1) {
2994 result = Tcl_DictObjPut(NULL, metadataOutObj,
2995 Tcl_NewStringObj("DPI",-1),
2996 Tcl_NewDoubleObj(png.DPI));
2997 }
2998
2999 if (TCL_OK == result && metadataOutObj != NULL && png.aspect != -1) {
3000 result = Tcl_DictObjPut(NULL, metadataOutObj,
3001 Tcl_NewStringObj("aspect",-1),
3002 Tcl_NewDoubleObj(png.aspect));
3003 }
3004
3005 CleanupPNGImage(&png);
3006 return result;
3007 }
3008
3009 /*
3010 *----------------------------------------------------------------------
3011 *
3012 * WriteData --
3013 *
3014 * This function writes a bytes from a buffer out to the PNG image.
3015 *
3016 * Results:
3017 * TCL_OK, or TCL_ERROR if the write fails.
3018 *
3019 * Side effects:
3020 * File or buffer will be modified.
3021 *
3022 *----------------------------------------------------------------------
3023 */
3024
3025 static int
WriteData(Tcl_Interp * interp,PNGImage * pngPtr,const unsigned char * srcPtr,size_t srcSz,unsigned long * crcPtr)3026 WriteData(
3027 Tcl_Interp *interp,
3028 PNGImage *pngPtr,
3029 const unsigned char *srcPtr,
3030 size_t srcSz,
3031 unsigned long *crcPtr)
3032 {
3033 if (!srcPtr || !srcSz) {
3034 return TCL_OK;
3035 }
3036
3037 if (crcPtr) {
3038 *crcPtr = Tcl_ZlibCRC32(*crcPtr, srcPtr, srcSz);
3039 }
3040
3041 /*
3042 * TODO: is Tcl_AppendObjToObj faster here? i.e., does Tcl join the
3043 * objects immediately or store them in a multi-object rep?
3044 */
3045
3046 if (pngPtr->objDataPtr) {
3047 TkSizeT objSz;
3048 unsigned char *destPtr;
3049
3050 Tcl_GetByteArrayFromObj(pngPtr->objDataPtr, &objSz);
3051
3052 if (objSz + srcSz > INT_MAX) {
3053 Tcl_SetObjResult(interp, Tcl_NewStringObj(
3054 "image too large to store completely in byte array", -1));
3055 Tcl_SetErrorCode(interp, "TK", "IMAGE", "PNG", "TOO_LARGE", NULL);
3056 return TCL_ERROR;
3057 }
3058
3059 destPtr = Tcl_SetByteArrayLength(pngPtr->objDataPtr, objSz + srcSz);
3060
3061 if (!destPtr) {
3062 Tcl_SetObjResult(interp, Tcl_NewStringObj(
3063 "memory allocation failed", -1));
3064 Tcl_SetErrorCode(interp, "TK", "MALLOC", NULL);
3065 return TCL_ERROR;
3066 }
3067
3068 memcpy(destPtr+objSz, srcPtr, srcSz);
3069 } else if (Tcl_Write(pngPtr->channel, (const char *) srcPtr, srcSz) == TCL_IO_FAILURE) {
3070 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
3071 "write to channel failed: %s", Tcl_PosixError(interp)));
3072 return TCL_ERROR;
3073 }
3074
3075 return TCL_OK;
3076 }
3077
3078 static inline int
WriteByte(Tcl_Interp * interp,PNGImage * pngPtr,unsigned char c,unsigned long * crcPtr)3079 WriteByte(
3080 Tcl_Interp *interp,
3081 PNGImage *pngPtr,
3082 unsigned char c,
3083 unsigned long *crcPtr)
3084 {
3085 return WriteData(interp, pngPtr, &c, 1, crcPtr);
3086 }
3087
3088 /*
3089 *----------------------------------------------------------------------
3090 *
3091 * LongToInt32 --
3092 *
3093 * This function transforms to a 32-bit integer value as
3094 * four bytes in network byte order.
3095 *
3096 * Results:
3097 * None
3098 *
3099 * Side effects:
3100 * Buffer will be modified.
3101 *
3102 *----------------------------------------------------------------------
3103 */
3104
3105 static inline void
LongToInt32(unsigned long l,unsigned char * pc)3106 LongToInt32(
3107 unsigned long l,
3108 unsigned char *pc)
3109 {
3110 pc[0] = (unsigned char) ((l & 0xff000000) >> 24);
3111 pc[1] = (unsigned char) ((l & 0x00ff0000) >> 16);
3112 pc[2] = (unsigned char) ((l & 0x0000ff00) >> 8);
3113 pc[3] = (unsigned char) ((l & 0x000000ff) >> 0);
3114 }
3115
3116 /*
3117 *----------------------------------------------------------------------
3118 *
3119 * WriteInt32 --
3120 *
3121 * This function writes a 32-bit integer value out to the PNG image as
3122 * four bytes in network byte order.
3123 *
3124 * Results:
3125 * TCL_OK, or TCL_ERROR if the write fails.
3126 *
3127 * Side effects:
3128 * File or buffer will be modified.
3129 *
3130 *----------------------------------------------------------------------
3131 */
3132
3133 static inline int
WriteInt32(Tcl_Interp * interp,PNGImage * pngPtr,unsigned long l,unsigned long * crcPtr)3134 WriteInt32(
3135 Tcl_Interp *interp,
3136 PNGImage *pngPtr,
3137 unsigned long l,
3138 unsigned long *crcPtr)
3139 {
3140 unsigned char pc[4];
3141 LongToInt32(l,pc);
3142 return WriteData(interp, pngPtr, pc, 4, crcPtr);
3143 }
3144
3145 /*
3146 *----------------------------------------------------------------------
3147 *
3148 * WriteChunk --
3149 *
3150 * Writes a complete chunk to the PNG image, including chunk type,
3151 * length, contents, and CRC.
3152 *
3153 * Results:
3154 * TCL_OK, or TCL_ERROR if the write fails.
3155 *
3156 * Side effects:
3157 * None
3158 *
3159 *----------------------------------------------------------------------
3160 */
3161
3162 static inline int
WriteChunk(Tcl_Interp * interp,PNGImage * pngPtr,unsigned long chunkType,const unsigned char * dataPtr,size_t dataSize)3163 WriteChunk(
3164 Tcl_Interp *interp,
3165 PNGImage *pngPtr,
3166 unsigned long chunkType,
3167 const unsigned char *dataPtr,
3168 size_t dataSize)
3169 {
3170 unsigned long crc = Tcl_ZlibCRC32(0, NULL, 0);
3171 int result = TCL_OK;
3172
3173 /*
3174 * Write the length field for the chunk.
3175 */
3176
3177 result = WriteInt32(interp, pngPtr, dataSize, NULL);
3178
3179 /*
3180 * Write the Chunk Type.
3181 */
3182
3183 if (TCL_OK == result) {
3184 result = WriteInt32(interp, pngPtr, chunkType, &crc);
3185 }
3186
3187 /*
3188 * Write the contents (if any).
3189 */
3190
3191 if (TCL_OK == result) {
3192 result = WriteData(interp, pngPtr, dataPtr, dataSize, &crc);
3193 }
3194
3195 /*
3196 * Write out the CRC at the end of the chunk.
3197 */
3198
3199 if (TCL_OK == result) {
3200 result = WriteInt32(interp, pngPtr, crc, NULL);
3201 }
3202
3203 return result;
3204 }
3205
3206 /*
3207 *----------------------------------------------------------------------
3208 *
3209 * WriteIHDR --
3210 *
3211 * This function writes the PNG header at the beginning of a PNG file,
3212 * which includes information such as dimensions and color type.
3213 *
3214 * Results:
3215 * TCL_OK, or TCL_ERROR if the write fails.
3216 *
3217 * Side effects:
3218 * File or buffer will be modified.
3219 *
3220 *----------------------------------------------------------------------
3221 */
3222
3223 static int
WriteIHDR(Tcl_Interp * interp,PNGImage * pngPtr,Tk_PhotoImageBlock * blockPtr)3224 WriteIHDR(
3225 Tcl_Interp *interp,
3226 PNGImage *pngPtr,
3227 Tk_PhotoImageBlock *blockPtr)
3228 {
3229 unsigned long crc = Tcl_ZlibCRC32(0, NULL, 0);
3230 int result = TCL_OK;
3231
3232 /*
3233 * The IHDR (header) chunk has a fixed size of 13 bytes.
3234 */
3235
3236 result = WriteInt32(interp, pngPtr, 13, NULL);
3237
3238 /*
3239 * Write the IHDR Chunk Type.
3240 */
3241
3242 if (TCL_OK == result) {
3243 result = WriteInt32(interp, pngPtr, CHUNK_IHDR, &crc);
3244 }
3245
3246 /*
3247 * Write the image width, height.
3248 */
3249
3250 if (TCL_OK == result) {
3251 result = WriteInt32(interp, pngPtr, (unsigned long) blockPtr->width,
3252 &crc);
3253 }
3254
3255 if (TCL_OK == result) {
3256 result = WriteInt32(interp, pngPtr, (unsigned long) blockPtr->height,
3257 &crc);
3258 }
3259
3260 /*
3261 * Write bit depth. Although the PNG format supports 16 bits per channel,
3262 * Tk supports only 8 in the internal representation, which blockPtr
3263 * points to.
3264 */
3265
3266 if (TCL_OK == result) {
3267 result = WriteByte(interp, pngPtr, 8, &crc);
3268 }
3269
3270 /*
3271 * Write out the color type, previously determined.
3272 */
3273
3274 if (TCL_OK == result) {
3275 result = WriteByte(interp, pngPtr, pngPtr->colorType, &crc);
3276 }
3277
3278 /*
3279 * Write compression method (only one method is defined).
3280 */
3281
3282 if (TCL_OK == result) {
3283 result = WriteByte(interp, pngPtr, PNG_COMPRESS_DEFLATE, &crc);
3284 }
3285
3286 /*
3287 * Write filter method (only one method is defined).
3288 */
3289
3290 if (TCL_OK == result) {
3291 result = WriteByte(interp, pngPtr, PNG_FILTMETH_STANDARD, &crc);
3292 }
3293
3294 /*
3295 * Write interlace method as not interlaced.
3296 *
3297 * TODO: support interlace through -format?
3298 */
3299
3300 if (TCL_OK == result) {
3301 result = WriteByte(interp, pngPtr, PNG_INTERLACE_NONE, &crc);
3302 }
3303
3304 /*
3305 * Write out the CRC at the end of the chunk.
3306 */
3307
3308 if (TCL_OK == result) {
3309 result = WriteInt32(interp, pngPtr, crc, NULL);
3310 }
3311
3312 return result;
3313 }
3314
3315 /*
3316 *----------------------------------------------------------------------
3317 *
3318 * WriteIDAT --
3319 *
3320 * Writes the IDAT (data) chunk to the PNG image, containing the pixel
3321 * channel data. Currently, image lines are not filtered and writing
3322 * interlaced pixels is not supported.
3323 *
3324 * Results:
3325 * TCL_OK, or TCL_ERROR if the write fails.
3326 *
3327 * Side effects:
3328 * None
3329 *
3330 *----------------------------------------------------------------------
3331 */
3332
3333 static int
WriteIDAT(Tcl_Interp * interp,PNGImage * pngPtr,Tk_PhotoImageBlock * blockPtr)3334 WriteIDAT(
3335 Tcl_Interp *interp,
3336 PNGImage *pngPtr,
3337 Tk_PhotoImageBlock *blockPtr)
3338 {
3339 int rowNum, flush = TCL_ZLIB_NO_FLUSH, result;
3340 Tcl_Obj *outputObj;
3341 unsigned char *outputBytes;
3342 TkSizeT outputSize;
3343
3344 /*
3345 * Filter and compress each row one at a time.
3346 */
3347
3348 for (rowNum=0 ; rowNum < blockPtr->height ; rowNum++) {
3349 int colNum;
3350 unsigned char *srcPtr, *destPtr;
3351
3352 srcPtr = blockPtr->pixelPtr + (rowNum * blockPtr->pitch);
3353 destPtr = Tcl_SetByteArrayLength(pngPtr->thisLineObj,
3354 pngPtr->lineSize);
3355
3356 /*
3357 * TODO: use Paeth filtering.
3358 */
3359
3360 *destPtr++ = PNG_FILTER_NONE;
3361
3362 /*
3363 * Copy each pixel into the destination buffer after the filter type
3364 * before filtering.
3365 */
3366
3367 for (colNum = 0 ; colNum < blockPtr->width ; colNum++) {
3368 /*
3369 * Copy red or gray channel.
3370 */
3371
3372 *destPtr++ = srcPtr[blockPtr->offset[0]];
3373
3374 /*
3375 * If not grayscale, copy the green and blue channels.
3376 */
3377
3378 if (pngPtr->colorType & PNG_COLOR_USED) {
3379 *destPtr++ = srcPtr[blockPtr->offset[1]];
3380 *destPtr++ = srcPtr[blockPtr->offset[2]];
3381 }
3382
3383 /*
3384 * Copy the alpha channel, if used.
3385 */
3386
3387 if (pngPtr->colorType & PNG_COLOR_ALPHA) {
3388 *destPtr++ = srcPtr[blockPtr->offset[3]];
3389 }
3390
3391 /*
3392 * Point to the start of the next pixel.
3393 */
3394
3395 srcPtr += blockPtr->pixelSize;
3396 }
3397
3398 /*
3399 * Compress the line of pixels into the destination. If this is the
3400 * last line, finalize the compressor at the same time. Note that this
3401 * can't be just a flush; that leads to a file that some PNG readers
3402 * choke on. [Bug 2984787]
3403 */
3404
3405 if (rowNum + 1 == blockPtr->height) {
3406 flush = TCL_ZLIB_FINALIZE;
3407 }
3408 if (Tcl_ZlibStreamPut(pngPtr->stream, pngPtr->thisLineObj,
3409 flush) != TCL_OK) {
3410 Tcl_SetObjResult(interp, Tcl_NewStringObj(
3411 "deflate() returned error", -1));
3412 Tcl_SetErrorCode(interp, "TK", "IMAGE", "PNG", "DEFLATE", NULL);
3413 return TCL_ERROR;
3414 }
3415
3416 /*
3417 * Swap line buffers to keep the last around for filtering next.
3418 */
3419
3420 {
3421 Tcl_Obj *temp = pngPtr->lastLineObj;
3422
3423 pngPtr->lastLineObj = pngPtr->thisLineObj;
3424 pngPtr->thisLineObj = temp;
3425 }
3426 }
3427
3428 /*
3429 * Now get the compressed data and write it as one big IDAT chunk.
3430 */
3431
3432 outputObj = Tcl_NewObj();
3433 (void) Tcl_ZlibStreamGet(pngPtr->stream, outputObj, -1);
3434 outputBytes = Tcl_GetByteArrayFromObj(outputObj, &outputSize);
3435 result = WriteChunk(interp, pngPtr, CHUNK_IDAT, outputBytes, outputSize);
3436 Tcl_DecrRefCount(outputObj);
3437 return result;
3438 }
3439
3440 /*
3441 *----------------------------------------------------------------------
3442 *
3443 * WriteExtraChunks --
3444 *
3445 * Writes an sBIT and a tEXt chunks to the PNG image, describing a bunch
3446 * of not very important metadata that many readers seem to need anyway.
3447 *
3448 * Results:
3449 * TCL_OK, or TCL_ERROR if the write fails.
3450 *
3451 * Side effects:
3452 * None
3453 *
3454 *----------------------------------------------------------------------
3455 */
3456
3457 static int
WriteExtraChunks(Tcl_Interp * interp,PNGImage * pngPtr,Tcl_Obj * metadataInObj)3458 WriteExtraChunks(
3459 Tcl_Interp *interp,
3460 PNGImage *pngPtr,
3461 Tcl_Obj *metadataInObj)
3462 {
3463 static const unsigned char sBIT_contents[] = {
3464 8, 8, 8, 8
3465 };
3466 int sBIT_length = 4;
3467 Tcl_DString buf;
3468
3469 /*
3470 * Each byte of each channel is always significant; we always write RGBA
3471 * images with 8 bits per channel as that is what the photo image's basic
3472 * data model is.
3473 */
3474
3475 switch (pngPtr->colorType) {
3476 case PNG_COLOR_GRAY:
3477 sBIT_length = 1;
3478 break;
3479 case PNG_COLOR_GRAYALPHA:
3480 sBIT_length = 2;
3481 break;
3482 case PNG_COLOR_RGB:
3483 case PNG_COLOR_PLTE:
3484 sBIT_length = 3;
3485 break;
3486 case PNG_COLOR_RGBA:
3487 sBIT_length = 4;
3488 break;
3489 }
3490 if (WriteChunk(interp, pngPtr, CHUNK_sBIT, sBIT_contents, sBIT_length)
3491 != TCL_OK) {
3492 return TCL_ERROR;
3493 }
3494
3495 /*
3496 * Say that it is Tk that made the PNG. Note that we *need* the NUL at the
3497 * end of "Software" to be transferred; do *not* change the length
3498 * parameter to -1 there!
3499 */
3500
3501 Tcl_DStringInit(&buf);
3502 Tcl_DStringAppend(&buf, "Software", 9);
3503 Tcl_DStringAppend(&buf, "Tk Toolkit v", -1);
3504 Tcl_DStringAppend(&buf, TK_PATCH_LEVEL, -1);
3505 if (WriteChunk(interp, pngPtr, CHUNK_tEXt,
3506 (unsigned char *) Tcl_DStringValue(&buf),
3507 Tcl_DStringLength(&buf)) != TCL_OK) {
3508 Tcl_DStringFree(&buf);
3509 return TCL_ERROR;
3510 }
3511 Tcl_DStringFree(&buf);
3512
3513 /*
3514 * Add a pHYs chunk if there is metadata for DPI and/or aspect
3515 * aspect = PPUy / PPUx
3516 * DPI = PPUx * 0.0254
3517 * The physical chunk consists of:
3518 * - Points per meter in x direction (32 bit)
3519 * - Points per meter in x direction (32 bit)
3520 * - Unit specifier: 0: no unit (only aspect), 1: Points per meter
3521 */
3522
3523 if (metadataInObj != NULL) {
3524
3525 Tcl_Obj *aspectObj, *DPIObj;
3526 double aspectValue=-1, DPIValue=-1;
3527 unsigned long PPUx = 65536, PPUy = 65536;
3528 char unitSpecifier;
3529
3530 if (TCL_ERROR == Tcl_DictObjGet(interp, metadataInObj,
3531 Tcl_NewStringObj("aspect",-1),
3532 &aspectObj) ||
3533 TCL_ERROR == Tcl_DictObjGet(interp, metadataInObj,
3534 Tcl_NewStringObj("DPI",-1),
3535 &DPIObj) ) {
3536 return TCL_ERROR;
3537 }
3538 if (DPIObj != NULL) {
3539 if (TCL_ERROR == Tcl_GetDoubleFromObj(interp, DPIObj, &DPIValue))
3540 {
3541 return TCL_ERROR;
3542 }
3543 PPUx = (unsigned long)floor(DPIValue / 0.0254+0.5);
3544 if (aspectObj == NULL) {
3545 PPUy = PPUx;
3546 }
3547 unitSpecifier = 1;
3548 }
3549 if (aspectObj != NULL) {
3550 if (TCL_ERROR == Tcl_GetDoubleFromObj(interp, aspectObj,
3551 &aspectValue)) {
3552 return TCL_ERROR;
3553 }
3554
3555 /*
3556 * aspect = PPUy / PPUx
3557 */
3558
3559 if (DPIObj == NULL) {
3560 unitSpecifier = 0;
3561 PPUx = 65536;
3562 PPUy = (unsigned long)floor(65536.0 * aspectValue+0.5);
3563 } else {
3564 PPUy = (unsigned long)floor(DPIValue * aspectValue / 0.0254+0.5);
3565 }
3566 }
3567 if (DPIObj != NULL || aspectObj != NULL) {
3568 unsigned char buffer[9];
3569
3570 if ( PPUx > 2147483647 || PPUy > 2147483647 ) {
3571 Tcl_SetObjResult(interp, Tcl_NewStringObj(
3572 "DPI or aspect out of range", -1));
3573 Tcl_SetErrorCode(interp, "TK", "IMAGE", "PNG", "PHYS", NULL);
3574 return TCL_ERROR;
3575 }
3576
3577 LongToInt32(PPUx, buffer);
3578 LongToInt32(PPUy, buffer+4);
3579 buffer[8] = unitSpecifier;
3580 if (WriteChunk(interp, pngPtr, CHUNK_pHYs, buffer, 9)
3581 != TCL_OK) {
3582 return TCL_ERROR;
3583 }
3584 }
3585 }
3586 return TCL_OK;
3587 }
3588
3589 /*
3590 *----------------------------------------------------------------------
3591 *
3592 * EncodePNG --
3593 *
3594 * This function handles the entirety of writing a PNG file (or data)
3595 * from the first byte to the last. No effort is made to optimize the
3596 * image data for best compression.
3597 *
3598 * Results:
3599 * TCL_OK, or TCL_ERROR if an I/O or memory error occurs.
3600 *
3601 * Side effects:
3602 * None
3603 *
3604 *----------------------------------------------------------------------
3605 */
3606
3607 static int
EncodePNG(Tcl_Interp * interp,Tk_PhotoImageBlock * blockPtr,PNGImage * pngPtr,Tcl_Obj * metadataInObj)3608 EncodePNG(
3609 Tcl_Interp *interp,
3610 Tk_PhotoImageBlock *blockPtr,
3611 PNGImage *pngPtr,
3612 Tcl_Obj *metadataInObj)
3613 {
3614 int greenOffset, blueOffset, alphaOffset;
3615
3616 /*
3617 * Determine appropriate color type based on color usage (e.g., only red
3618 * and maybe alpha channel = grayscale).
3619 *
3620 * TODO: Check whether this is doing any good; Tk might just be pushing
3621 * full RGBA data all the time through here, even though the actual image
3622 * doesn't need it...
3623 */
3624
3625 greenOffset = blockPtr->offset[1] - blockPtr->offset[0];
3626 blueOffset = blockPtr->offset[2] - blockPtr->offset[0];
3627 alphaOffset = blockPtr->offset[3];
3628 if ((alphaOffset >= blockPtr->pixelSize) || (alphaOffset < 0)) {
3629 alphaOffset = 0;
3630 } else {
3631 alphaOffset -= blockPtr->offset[0];
3632 }
3633
3634 if ((greenOffset != 0) || (blueOffset != 0)) {
3635 if (alphaOffset) {
3636 pngPtr->colorType = PNG_COLOR_RGBA;
3637 pngPtr->bytesPerPixel = 4;
3638 } else {
3639 pngPtr->colorType = PNG_COLOR_RGB;
3640 pngPtr->bytesPerPixel = 3;
3641 }
3642 } else {
3643 if (alphaOffset) {
3644 pngPtr->colorType = PNG_COLOR_GRAYALPHA;
3645 pngPtr->bytesPerPixel = 2;
3646 } else {
3647 pngPtr->colorType = PNG_COLOR_GRAY;
3648 pngPtr->bytesPerPixel = 1;
3649 }
3650 }
3651
3652 /*
3653 * Allocate buffers for lines for filtering and compressed data.
3654 */
3655
3656 pngPtr->lineSize = 1 + (pngPtr->bytesPerPixel * blockPtr->width);
3657 pngPtr->blockLen = pngPtr->lineSize * blockPtr->height;
3658
3659 if ((blockPtr->width > (INT_MAX - 1) / (pngPtr->bytesPerPixel)) ||
3660 (blockPtr->height > INT_MAX / pngPtr->lineSize)) {
3661 Tcl_SetObjResult(interp, Tcl_NewStringObj(
3662 "image is too large to encode pixel data", -1));
3663 Tcl_SetErrorCode(interp, "TK", "IMAGE", "PNG", "TOO_LARGE", NULL);
3664 return TCL_ERROR;
3665 }
3666
3667 pngPtr->lastLineObj = Tcl_NewObj();
3668 Tcl_IncrRefCount(pngPtr->lastLineObj);
3669 pngPtr->thisLineObj = Tcl_NewObj();
3670 Tcl_IncrRefCount(pngPtr->thisLineObj);
3671
3672 /*
3673 * Write out the PNG Signature that all PNGs begin with.
3674 */
3675
3676 if (WriteData(interp, pngPtr, pngSignature, PNG_SIG_SZ,
3677 NULL) == TCL_ERROR) {
3678 return TCL_ERROR;
3679 }
3680
3681 /*
3682 * Write out the IHDR (header) chunk containing image dimensions, color
3683 * type, etc.
3684 */
3685
3686 if (WriteIHDR(interp, pngPtr, blockPtr) == TCL_ERROR) {
3687 return TCL_ERROR;
3688 }
3689
3690 /*
3691 * Write out the extra chunks containing metadata that is of interest to
3692 * other programs more than us.
3693 */
3694
3695 if (WriteExtraChunks(interp, pngPtr, metadataInObj) == TCL_ERROR) {
3696 return TCL_ERROR;
3697 }
3698
3699 /*
3700 * Write out the image pixels in the IDAT (data) chunk.
3701 */
3702
3703 if (WriteIDAT(interp, pngPtr, blockPtr) == TCL_ERROR) {
3704 return TCL_ERROR;
3705 }
3706
3707 /*
3708 * Write out the IEND chunk that all PNGs end with.
3709 */
3710
3711 return WriteChunk(interp, pngPtr, CHUNK_IEND, NULL, 0);
3712 }
3713
3714 /*
3715 *----------------------------------------------------------------------
3716 *
3717 * FileWritePNG --
3718 *
3719 * This function is called by the photo image type to write PNG format
3720 * data to a file.
3721 *
3722 * Results:
3723 * A standard TCL completion code. If TCL_ERROR is returned then an error
3724 * message is left in the interp's result.
3725 *
3726 * Side effects:
3727 * The specified file is overwritten.
3728 *
3729 *----------------------------------------------------------------------
3730 */
3731
3732 static int
FileWritePNG(Tcl_Interp * interp,const char * filename,TCL_UNUSED (Tcl_Obj *),Tcl_Obj * metadataInObj,Tk_PhotoImageBlock * blockPtr)3733 FileWritePNG(
3734 Tcl_Interp *interp,
3735 const char *filename,
3736 TCL_UNUSED(Tcl_Obj *),
3737 Tcl_Obj *metadataInObj,
3738 Tk_PhotoImageBlock *blockPtr)
3739 {
3740 Tcl_Channel chan;
3741 PNGImage png;
3742 int result = TCL_ERROR;
3743
3744 /*
3745 * Open a Tcl file channel where the image data will be stored. Tk ought
3746 * to take care of this, and just provide a channel, but it doesn't.
3747 */
3748
3749 chan = Tcl_OpenFileChannel(interp, filename, "w", 0644);
3750
3751 if (!chan) {
3752 return TCL_ERROR;
3753 }
3754
3755 /*
3756 * Initalize PNGImage instance for encoding.
3757 */
3758
3759 if (InitPNGImage(interp, &png, chan, NULL,
3760 TCL_ZLIB_STREAM_DEFLATE) == TCL_ERROR) {
3761 goto cleanup;
3762 }
3763
3764 /*
3765 * Set the translation mode to binary so that CR and LF are not to the
3766 * platform's EOL sequence.
3767 */
3768
3769 if (Tcl_SetChannelOption(interp, chan, "-translation",
3770 "binary") != TCL_OK) {
3771 goto cleanup;
3772 }
3773
3774 /*
3775 * Write the raw PNG data out to the file.
3776 */
3777
3778 result = EncodePNG(interp, blockPtr, &png, metadataInObj);
3779
3780 cleanup:
3781 Tcl_Close(interp, chan);
3782 CleanupPNGImage(&png);
3783 return result;
3784 }
3785
3786 /*
3787 *----------------------------------------------------------------------
3788 *
3789 * StringWritePNG --
3790 *
3791 * This function is called by the photo image type to write PNG format
3792 * data to a Tcl object and return it in the result.
3793 *
3794 * Results:
3795 * A standard TCL completion code. If TCL_ERROR is returned then an error
3796 * message is left in the interp's result.
3797 *
3798 * Side effects:
3799 * None
3800 *
3801 *----------------------------------------------------------------------
3802 */
3803
3804 static int
StringWritePNG(Tcl_Interp * interp,TCL_UNUSED (Tcl_Obj *),Tcl_Obj * metadataInObj,Tk_PhotoImageBlock * blockPtr)3805 StringWritePNG(
3806 Tcl_Interp *interp,
3807 TCL_UNUSED(Tcl_Obj *),
3808 Tcl_Obj *metadataInObj,
3809 Tk_PhotoImageBlock *blockPtr)
3810 {
3811 Tcl_Obj *resultObj = Tcl_NewObj();
3812 PNGImage png;
3813 int result = TCL_ERROR;
3814
3815 /*
3816 * Initalize PNGImage instance for encoding.
3817 */
3818
3819 if (InitPNGImage(interp, &png, NULL, resultObj,
3820 TCL_ZLIB_STREAM_DEFLATE) == TCL_ERROR) {
3821 goto cleanup;
3822 }
3823
3824 /*
3825 * Write the raw PNG data into the prepared Tcl_Obj buffer. Set the result
3826 * back to the interpreter if successful.
3827 */
3828
3829 result = EncodePNG(interp, blockPtr, &png, metadataInObj);
3830
3831 if (TCL_OK == result) {
3832 Tcl_SetObjResult(interp, png.objDataPtr);
3833 }
3834
3835 cleanup:
3836 CleanupPNGImage(&png);
3837 return result;
3838 }
3839
3840 /*
3841 * Local Variables:
3842 * c-basic-offset: 4
3843 * fill-column: 78
3844 * End:
3845 */
3846