1 /*
2 * gd_gd2.c
3 *
4 * Implements the I/O and support for the GD2 format.
5 *
6 * Changing the definition of GD2_DBG (below) will cause copious messages
7 * to be displayed while it processes requests.
8 *
9 * Designed, Written & Copyright 1999, Philip Warner.
10 *
11 */
12
13 /**
14 * File: GD2 IO
15 *
16 * Read and write GD2 images.
17 *
18 * The GD2 image format is a proprietary image format of libgd. *It has to be*
19 * *regarded as being obsolete, and should only be used for development and*
20 * *testing purposes.*
21 *
22 * Structure of a GD2 image file:
23 * - file header
24 * - chunk headers (only for compressed data)
25 * - color header (either truecolor or palette)
26 * - chunks of image data (chunk-row-major, top to bottom, left to right)
27 *
28 * All numbers are stored in big-endian format.
29 *
30 * File header structure:
31 * signature - 4 bytes (always "gd2\0")
32 * version - 1 word (e.g. "\0\002")
33 * width - 1 word
34 * height - 1 word
35 * chunk_size - 1 word
36 * format - 1 word
37 * x_chunk_count - 1 word
38 * y_chunk_count - 1 word
39 *
40 * Recognized formats:
41 * 1 - raw palette image data
42 * 2 - compressed palette image data
43 * 3 - raw truecolor image data
44 * 4 - compressed truecolor image data
45 *
46 * Chunk header:
47 * offset - 1 dword
48 * size - 1 dword
49 *
50 * There are x_chunk_count * y_chunk_count chunk headers.
51 *
52 * Truecolor image color header:
53 * truecolor - 1 byte (always "\001")
54 * transparent - 1 dword (ARGB color); "\377\377\377\377" means that no
55 * transparent color is set
56 *
57 * Palette image color header:
58 * truecolor - 1 byte (always "\0")
59 * count - 1 word (the number of used palette colors)
60 * transparent - 1 dword (palette index); "\377\377\377\377" means that no
61 * transparent color is set
62 * palette - 256 dwords (RGBA colors)
63 *
64 * Chunk structure:
65 * Sequential pixel data of a rectangular area (chunk_size x chunk_size),
66 * row-major from top to bottom, left to right:
67 * - 1 byte per pixel for palette images
68 * - 1 dword (ARGB) per pixel for truecolor images
69 *
70 * Depending on format, the chunk may be ZLIB compressed.
71 */
72
73 #ifdef HAVE_CONFIG_H
74 #include "config.h"
75 #endif
76
77 /* 2.0.29: no more errno.h, makes windows happy */
78 #include <math.h>
79 #include <limits.h>
80 #include <string.h>
81 #include "gd.h"
82 #include "gd_errors.h"
83 #include "gdhelpers.h"
84
85 /* 2.03: gd2 is no longer mandatory */
86 /* JCE - test after including gd.h so that HAVE_LIBZ can be set in
87 * a config.h file included by gd.h */
88 #if defined(HAVE_LIBZ) && ENABLE_GD_FORMATS
89 #include <zlib.h>
90
91 #define TRUE 1
92 #define FALSE 0
93
94 /* 2.11: not part of the API, as the save routine can figure it out
95 from im->trueColor, and the load routine doesn't need to tell
96 the end user the saved format. NOTE: adding 2 is assumed
97 to result in the correct format value for truecolor! */
98 #define GD2_FMT_TRUECOLOR_RAW 3
99 #define GD2_FMT_TRUECOLOR_COMPRESSED 4
100
101 #define gd2_compressed(fmt) (((fmt) == GD2_FMT_COMPRESSED) || \
102 ((fmt) == GD2_FMT_TRUECOLOR_COMPRESSED))
103
104 #define gd2_truecolor(fmt) (((fmt) == GD2_FMT_TRUECOLOR_RAW) || \
105 ((fmt) == GD2_FMT_TRUECOLOR_COMPRESSED))
106
107 /* Use this for commenting out debug-print statements. */
108 /* Just use the first '#define' to allow all the prints... */
109 /*#define GD2_DBG(s) (s) */
110 #define GD2_DBG(s)
111
112 typedef struct {
113 int offset;
114 int size;
115 }
116 t_chunk_info;
117
118 extern int _gdGetColors (gdIOCtx * in, gdImagePtr im, int gd2xFlag);
119 extern void _gdPutColors (gdImagePtr im, gdIOCtx * out);
120
121 /* */
122 /* Read the extra info in the gd2 header. */
123 /* */
124 static int
_gd2GetHeader(gdIOCtxPtr in,int * sx,int * sy,int * cs,int * vers,int * fmt,int * ncx,int * ncy,t_chunk_info ** chunkIdx)125 _gd2GetHeader (gdIOCtxPtr in, int *sx, int *sy,
126 int *cs, int *vers, int *fmt, int *ncx, int *ncy,
127 t_chunk_info ** chunkIdx)
128 {
129 int i;
130 int ch;
131 char id[5];
132 t_chunk_info *cidx;
133 int sidx;
134 int nc;
135
136 GD2_DBG (printf ("Reading gd2 header info\n"));
137
138 for (i = 0; i < 4; i++) {
139 ch = gdGetC (in);
140 if (ch == EOF) {
141 goto fail1;
142 };
143 id[i] = ch;
144 };
145 id[4] = 0;
146
147 GD2_DBG (printf ("Got file code: %s\n", id));
148
149 /* Equiv. of 'magick'. */
150 if (strcmp (id, GD2_ID) != 0) {
151 GD2_DBG (printf ("Not a valid gd2 file\n"));
152 goto fail1;
153 };
154
155 /* Version */
156 if (gdGetWord (vers, in) != 1) {
157 goto fail1;
158 };
159 GD2_DBG (printf ("Version: %d\n", *vers));
160
161 if ((*vers != 1) && (*vers != 2)) {
162 GD2_DBG (printf ("Bad version: %d\n", *vers));
163 goto fail1;
164 };
165
166 /* Image Size */
167 if (!gdGetWord (sx, in)) {
168 GD2_DBG (printf ("Could not get x-size\n"));
169 goto fail1;
170 }
171 if (!gdGetWord (sy, in)) {
172 GD2_DBG (printf ("Could not get y-size\n"));
173 goto fail1;
174 }
175 GD2_DBG (printf ("Image is %dx%d\n", *sx, *sy));
176
177 /* Chunk Size (pixels, not bytes!) */
178 if (gdGetWord (cs, in) != 1) {
179 goto fail1;
180 };
181 GD2_DBG (printf ("ChunkSize: %d\n", *cs));
182
183 if ((*cs < GD2_CHUNKSIZE_MIN) || (*cs > GD2_CHUNKSIZE_MAX)) {
184 GD2_DBG (printf ("Bad chunk size: %d\n", *cs));
185 goto fail1;
186 };
187
188 /* Data Format */
189 if (gdGetWord (fmt, in) != 1) {
190 goto fail1;
191 };
192 GD2_DBG (printf ("Format: %d\n", *fmt));
193
194 if ((*fmt != GD2_FMT_RAW) && (*fmt != GD2_FMT_COMPRESSED) &&
195 (*fmt != GD2_FMT_TRUECOLOR_RAW) &&
196 (*fmt != GD2_FMT_TRUECOLOR_COMPRESSED)) {
197 GD2_DBG (printf ("Bad data format: %d\n", *fmt));
198 goto fail1;
199 };
200
201
202 /* # of chunks wide */
203 if (gdGetWord (ncx, in) != 1) {
204 goto fail1;
205 };
206 GD2_DBG (printf ("%d Chunks Wide\n", *ncx));
207
208 /* # of chunks high */
209 if (gdGetWord (ncy, in) != 1) {
210 goto fail1;
211 };
212 GD2_DBG (printf ("%d Chunks vertically\n", *ncy));
213
214 if (gd2_compressed (*fmt)) {
215 if (overflow2(*ncx, *ncy)) {
216 GD2_DBG(printf ("Illegal chunk counts: %d * %d\n", *ncx, *ncy));
217 goto fail1;
218 }
219 nc = (*ncx) * (*ncy);
220
221 GD2_DBG (printf ("Reading %d chunk index entries\n", nc));
222 if (overflow2(sizeof(t_chunk_info), nc)) {
223 goto fail1;
224 }
225 sidx = sizeof (t_chunk_info) * nc;
226 if (sidx <= 0) {
227 goto fail1;
228 }
229
230 cidx = gdCalloc (sidx, 1);
231 if (cidx == NULL) {
232 goto fail1;
233 }
234 for (i = 0; i < nc; i++) {
235 if (gdGetInt (&cidx[i].offset, in) != 1) {
236 goto fail2;
237 };
238 if (gdGetInt (&cidx[i].size, in) != 1) {
239 goto fail2;
240 };
241 if (cidx[i].offset < 0 || cidx[i].size < 0 || cidx[i].size == INT_MAX)
242 goto fail2;
243 };
244 *chunkIdx = cidx;
245 };
246
247 GD2_DBG (printf ("gd2 header complete\n"));
248
249 return 1;
250 fail2:
251 gdFree(cidx);
252 fail1:
253 return 0;
254 }
255
256 static gdImagePtr
_gd2CreateFromFile(gdIOCtxPtr in,int * sx,int * sy,int * cs,int * vers,int * fmt,int * ncx,int * ncy,t_chunk_info ** cidx)257 _gd2CreateFromFile (gdIOCtxPtr in, int *sx, int *sy,
258 int *cs, int *vers, int *fmt,
259 int *ncx, int *ncy, t_chunk_info ** cidx)
260 {
261 gdImagePtr im;
262
263 if (_gd2GetHeader (in, sx, sy, cs, vers, fmt, ncx, ncy, cidx) != 1) {
264 GD2_DBG (printf ("Bad GD2 header\n"));
265 goto fail1;
266 }
267 if (gd2_truecolor (*fmt)) {
268 im = gdImageCreateTrueColor (*sx, *sy);
269 } else {
270 im = gdImageCreate (*sx, *sy);
271 }
272 if (im == NULL) {
273 GD2_DBG (printf ("Could not create gdImage\n"));
274 goto fail2;
275 };
276
277 if (!_gdGetColors (in, im, (*vers) == 2)) {
278 GD2_DBG (printf ("Could not read color palette\n"));
279 goto fail3;
280 }
281 GD2_DBG (printf ("Image palette completed: %d colours\n", im->colorsTotal));
282
283 return im;
284
285 fail3:
286 gdImageDestroy (im);
287 fail2:
288 gdFree(*cidx);
289 fail1:
290 return 0;
291
292 }
293
294 static int
_gd2ReadChunk(int offset,char * compBuf,int compSize,char * chunkBuf,uLongf * chunkLen,gdIOCtx * in)295 _gd2ReadChunk (int offset, char *compBuf, int compSize, char *chunkBuf,
296 uLongf * chunkLen, gdIOCtx * in)
297 {
298 int zerr;
299
300 if (gdTell (in) != offset) {
301 GD2_DBG (printf ("Positioning in file to %d\n", offset));
302 gdSeek (in, offset);
303 } else {
304 GD2_DBG (printf ("Already Positioned in file to %d\n", offset));
305 };
306
307 /* Read and uncompress an entire chunk. */
308 GD2_DBG (printf ("Reading file\n"));
309 if (gdGetBuf (compBuf, compSize, in) != compSize) {
310 return FALSE;
311 };
312 GD2_DBG (printf
313 ("Got %d bytes. Uncompressing into buffer of %d bytes\n", compSize,
314 *chunkLen));
315 zerr =
316 uncompress ((unsigned char *) chunkBuf, chunkLen,
317 (unsigned char *) compBuf, compSize);
318 if (zerr != Z_OK) {
319 GD2_DBG (printf ("Error %d from uncompress\n", zerr));
320 return FALSE;
321 };
322 GD2_DBG (printf ("Got chunk\n"));
323 return TRUE;
324 }
325
326
327 /*
328 Function: gdImageCreateFromGd2
329
330 <gdImageCreateFromGd2> is called to load images from gd2 format
331 files. Invoke <gdImageCreateFromGd2> with an already opened
332 pointer to a file containing the desired image in the gd2 file
333 format, which is specific to gd2 and intended for fast loading of
334 parts of large images. (It is a compressed format, but generally
335 not as good as maximum compression of the entire image would be.)
336
337 <gdImageCreateFromGd2> returns a <gdImagePtr> to the new image, or
338 NULL if unable to load the image (most often because the file is
339 corrupt or does not contain a gd format
340 image). <gdImageCreateFromGd2> does not close the file. You can
341 inspect the sx and sy members of the image to determine its
342 size. The image must eventually be destroyed using
343 <gdImageDestroy>.
344
345
346 Variants:
347
348 <gdImageCreateFromGd2Ptr> creates an image from GD data (i.e. the
349 contents of a GD2 file) already in memory.
350
351 <gdImageCreateFromGd2Ctx> reads in an image using the functions in
352 a <gdIOCtx> struct.
353
354 Parameters:
355
356 infile - The input FILE pointer
357
358 Returns:
359
360 A pointer to the new image or NULL if an error occurred.
361
362 Example:
363
364 > gdImagePtr im;
365 > FILE *in;
366 > in = fopen("mygd.gd2", "rb");
367 > im = gdImageCreateFromGd2(in);
368 > fclose(in);
369 > // ... Use the image ...
370 > gdImageDestroy(im);
371 */
gdImageCreateFromGd2(FILE * inFile)372 BGD_DECLARE(gdImagePtr) gdImageCreateFromGd2 (FILE * inFile)
373 {
374 gdIOCtx *in = gdNewFileCtx (inFile);
375 gdImagePtr im;
376
377 if (in == NULL) return NULL;
378 im = gdImageCreateFromGd2Ctx (in);
379
380 in->gd_free (in);
381
382 return im;
383 }
384
385 /*
386 Function: gdImageCreateFromGd2Ptr
387
388 Parameters:
389
390 size - size of GD2 data in bytes.
391 data - GD2 data (i.e. contents of a GIF file).
392
393 See <gdImageCreateFromGd2>.
394 */
gdImageCreateFromGd2Ptr(int size,void * data)395 BGD_DECLARE(gdImagePtr) gdImageCreateFromGd2Ptr (int size, void *data)
396 {
397 gdImagePtr im;
398 gdIOCtx *in = gdNewDynamicCtxEx (size, data, 0);
399 if(!in)
400 return 0;
401 im = gdImageCreateFromGd2Ctx (in);
402 in->gd_free (in);
403 return im;
404 }
405
406 /*
407 Function: gdImageCreateFromGd2Ctx
408
409 Reads in a GD2 image via a <gdIOCtx> struct. See
410 <gdImageCreateFromGd2>.
411 */
gdImageCreateFromGd2Ctx(gdIOCtxPtr in)412 BGD_DECLARE(gdImagePtr) gdImageCreateFromGd2Ctx (gdIOCtxPtr in)
413 {
414 int sx, sy;
415 int i;
416 int ncx, ncy, nc, cs, cx, cy;
417 int x, y, ylo, yhi, xlo, xhi;
418 int vers, fmt;
419 t_chunk_info *chunkIdx = NULL; /* So we can gdFree it with impunity. */
420 unsigned char *chunkBuf = NULL; /* So we can gdFree it with impunity. */
421 int chunkNum = 0;
422 int chunkMax = 0;
423 uLongf chunkLen;
424 int chunkPos = 0;
425 int compMax = 0;
426 int bytesPerPixel;
427 char *compBuf = NULL; /* So we can gdFree it with impunity. */
428
429 gdImagePtr im;
430
431 /* Get the header */
432 im =
433 _gd2CreateFromFile (in, &sx, &sy, &cs, &vers, &fmt, &ncx, &ncy,
434 &chunkIdx);
435 if (im == NULL) {
436 /* No need to free chunkIdx as _gd2CreateFromFile does it for us. */
437 return 0;
438 }
439
440 bytesPerPixel = im->trueColor ? 4 : 1;
441 if (overflow2(ncx, ncy))
442 goto fail;
443 nc = ncx * ncy;
444
445 if (overflow2(ncy, cs) || overflow2(ncx, cs) || overflow2(bytesPerPixel, cs))
446 goto fail;
447
448 if (gd2_compressed (fmt)) {
449 /* Find the maximum compressed chunk size. */
450 compMax = 0;
451 for (i = 0; (i < nc); i++) {
452 if (chunkIdx[i].size > compMax) {
453 compMax = chunkIdx[i].size;
454 };
455 };
456 compMax++;
457
458 /* Allocate buffers */
459 chunkMax = cs * bytesPerPixel * cs;
460 chunkBuf = gdCalloc (chunkMax, 1);
461 if (!chunkBuf) {
462 goto fail;
463 }
464 compBuf = gdCalloc (compMax, 1);
465 if (!compBuf) {
466 goto fail;
467 }
468
469 GD2_DBG (printf ("Largest compressed chunk is %d bytes\n", compMax));
470 };
471
472 /* if ( (ncx != sx / cs) || (ncy != sy / cs)) { */
473 /* goto fail2; */
474 /* }; */
475
476 /* Read the data... */
477 for (cy = 0; (cy < ncy); cy++) {
478 for (cx = 0; (cx < ncx); cx++) {
479
480 ylo = cy * cs;
481 yhi = ylo + cs;
482 if (yhi > im->sy) {
483 yhi = im->sy;
484 };
485
486 GD2_DBG (printf
487 ("Processing Chunk %d (%d, %d), y from %d to %d\n",
488 chunkNum, cx, cy, ylo, yhi));
489
490 if (gd2_compressed (fmt)) {
491
492 chunkLen = chunkMax;
493
494 if (!_gd2ReadChunk (chunkIdx[chunkNum].offset,
495 compBuf,
496 chunkIdx[chunkNum].size,
497 (char *) chunkBuf, &chunkLen, in)) {
498 GD2_DBG (printf ("Error reading comproessed chunk\n"));
499 goto fail;
500 };
501
502 chunkPos = 0;
503 };
504
505 for (y = ylo; (y < yhi); y++) {
506
507 xlo = cx * cs;
508 xhi = xlo + cs;
509 if (xhi > im->sx) {
510 xhi = im->sx;
511 };
512 /*GD2_DBG(printf("y=%d: ",y)); */
513 if (!gd2_compressed (fmt)) {
514 for (x = xlo; x < xhi; x++) {
515
516 if (im->trueColor) {
517 if (!gdGetInt (&im->tpixels[y][x], in)) {
518 gd_error("gd2: EOF while reading\n");
519 goto fail;
520 }
521 } else {
522 int ch;
523 if (!gdGetByte (&ch, in)) {
524 gd_error("gd2: EOF while reading\n");
525 goto fail;
526 }
527 im->pixels[y][x] = ch;
528 }
529 }
530 } else {
531 for (x = xlo; x < xhi; x++) {
532 if (im->trueColor) {
533 /* 2.0.1: work around a gcc bug by being verbose.
534 TBB */
535 int a = chunkBuf[chunkPos++] << 24;
536 int r = chunkBuf[chunkPos++] << 16;
537 int g = chunkBuf[chunkPos++] << 8;
538 int b = chunkBuf[chunkPos++];
539 /* 2.0.11: tpixels */
540 im->tpixels[y][x] = a + r + g + b;
541 } else {
542 im->pixels[y][x] = chunkBuf[chunkPos++];
543 }
544 };
545 };
546 /*GD2_DBG(printf("\n")); */
547 };
548 chunkNum++;
549 };
550 };
551
552 GD2_DBG (printf ("Freeing memory\n"));
553
554 gdFree (chunkBuf);
555 gdFree (compBuf);
556 gdFree (chunkIdx);
557
558 GD2_DBG (printf ("Done\n"));
559
560 return im;
561
562 fail:
563 gdImageDestroy (im);
564 if (chunkBuf) {
565 gdFree (chunkBuf);
566 }
567 if (compBuf) {
568 gdFree (compBuf);
569 }
570 if (chunkIdx) {
571 gdFree (chunkIdx);
572 }
573 return 0;
574 }
575
576
577 /*
578 Function: gdImageCreateFromGd2Part
579
580 <gdImageCreateFromGd2Part> is called to load parts of images from
581 gd2 format files. Invoked in the same way as <gdImageCreateFromGd2>,
582 but with extra parameters indicating the source (x, y) and
583 width/height of the desired image. <gdImageCreateFromGd2Part>
584 returns a <gdImagePtr> to the new image, or NULL if unable to load
585 the image. The image must eventually be destroyed using
586 <gdImageDestroy>.
587
588 Variants:
589
590 <gdImageCreateFromGd2PartPtr> creates an image from GD2 data
591 (i.e. the contents of a GD2 file) already in memory.
592
593 <gdImageCreateFromGd2Ctx> reads in an image using the functions in
594 a <gdIOCtx> struct.
595
596 Parameters:
597
598 infile - The input FILE pointer
599 srcx, srcy - The source X and Y coordinates
600 w, h - The resulting image's width and height
601
602 Returns:
603
604 A pointer to the new image or NULL if an error occurred.
605
606 */
gdImageCreateFromGd2Part(FILE * inFile,int srcx,int srcy,int w,int h)607 BGD_DECLARE(gdImagePtr) gdImageCreateFromGd2Part (FILE * inFile, int srcx, int srcy, int w, int h)
608 {
609 gdImagePtr im;
610 gdIOCtx *in = gdNewFileCtx (inFile);
611
612 if (in == NULL) return NULL;
613 im = gdImageCreateFromGd2PartCtx (in, srcx, srcy, w, h);
614
615 in->gd_free (in);
616
617 return im;
618 }
619
620 /*
621 Function: gdImageCreateFromGd2PartPtr
622
623 Parameters:
624
625 size - size of GD data in bytes.
626 data - GD data (i.e. contents of a GIF file).
627 srcx, srcy - The source X and Y coordinates
628 w, h - The resulting image's width and height
629
630 Reads in part of a GD2 image file stored from memory. See
631 <gdImageCreateFromGd2Part>.
632 */
gdImageCreateFromGd2PartPtr(int size,void * data,int srcx,int srcy,int w,int h)633 BGD_DECLARE(gdImagePtr) gdImageCreateFromGd2PartPtr (int size, void *data, int srcx, int srcy, int w,
634 int h)
635 {
636 gdImagePtr im;
637 gdIOCtx *in = gdNewDynamicCtxEx (size, data, 0);
638 if(!in)
639 return 0;
640 im = gdImageCreateFromGd2PartCtx (in, srcx, srcy, w, h);
641 in->gd_free (in);
642 return im;
643 }
644
645
646 /*
647 Function: gdImageCreateFromGd2PartCtx
648
649 Parameters:
650
651 in - The data source.
652 srcx, srcy - The source X and Y coordinates
653 w, h - The resulting image's width and height
654
655 Reads in part of a GD2 data image file via a <gdIOCtx> struct. See
656 <gdImageCreateFromGd2Part>.
657 */
gdImageCreateFromGd2PartCtx(gdIOCtx * in,int srcx,int srcy,int w,int h)658 BGD_DECLARE(gdImagePtr) gdImageCreateFromGd2PartCtx (gdIOCtx * in, int srcx, int srcy, int w, int h)
659 {
660 int scx, scy, ecx, ecy, fsx, fsy;
661 int nc, ncx, ncy, cs, cx, cy;
662 int x, y, ylo, yhi, xlo, xhi;
663 int dstart, dpos;
664 int i;
665 /* 2.0.12: unsigned is correct; fixes problems with color munging.
666 Thanks to Steven Brown. */
667 unsigned int ch;
668 int vers, fmt;
669 t_chunk_info *chunkIdx = NULL;
670 unsigned char *chunkBuf = NULL;
671 int chunkNum;
672 int chunkMax = 0;
673 uLongf chunkLen;
674 int chunkPos = 0;
675 int compMax;
676 char *compBuf = NULL;
677
678 gdImagePtr im;
679
680 /* */
681 /* The next few lines are basically copied from gd2CreateFromFile */
682 /* - we change the file size, so don't want to use the code directly. */
683 /* but we do need to know the file size. */
684 /* */
685 if (_gd2GetHeader (in, &fsx, &fsy, &cs, &vers, &fmt, &ncx, &ncy, &chunkIdx)
686 != 1) {
687 goto fail1;
688 }
689
690 GD2_DBG (printf ("File size is %dx%d\n", fsx, fsy));
691
692 /* This is the difference - make a file based on size of chunks. */
693 if (gd2_truecolor (fmt)) {
694 im = gdImageCreateTrueColor (w, h);
695 } else {
696 im = gdImageCreate (w, h);
697 }
698 if (im == NULL) {
699 goto fail1;
700 };
701
702 if (!_gdGetColors (in, im, vers == 2)) {
703 goto fail2;
704 }
705 GD2_DBG (printf ("Image palette completed: %d colours\n", im->colorsTotal));
706
707 /* Process the header info */
708 nc = ncx * ncy;
709
710 if (gd2_compressed (fmt)) {
711 /* Find the maximum compressed chunk size. */
712 compMax = 0;
713 for (i = 0; (i < nc); i++) {
714 if (chunkIdx[i].size > compMax) {
715 compMax = chunkIdx[i].size;
716 };
717 };
718 compMax++;
719
720 if (im->trueColor) {
721 chunkMax = cs * cs * 4;
722 } else {
723 chunkMax = cs * cs;
724 }
725 chunkBuf = gdCalloc (chunkMax, 1);
726 if (!chunkBuf) {
727 goto fail2;
728 }
729 compBuf = gdCalloc (compMax, 1);
730 if (!compBuf) {
731 goto fail2;
732 }
733
734 };
735
736 /* Don't bother with this... */
737 /* if ( (ncx != sx / cs) || (ncy != sy / cs)) { */
738 /* goto fail2; */
739 /* }; */
740
741
742 /* Work out start/end chunks */
743 scx = srcx / cs;
744 scy = srcy / cs;
745 if (scx < 0) {
746 scx = 0;
747 };
748 if (scy < 0) {
749 scy = 0;
750 };
751
752 ecx = (srcx + w) / cs;
753 ecy = (srcy + h) / cs;
754 if (ecx >= ncx) {
755 ecx = ncx - 1;
756 };
757 if (ecy >= ncy) {
758 ecy = ncy - 1;
759 };
760
761 /* Remember file position of image data. */
762 dstart = gdTell (in);
763 GD2_DBG (printf ("Data starts at %d\n", dstart));
764
765 /* Loop through the chunks. */
766 for (cy = scy; (cy <= ecy); cy++) {
767
768 ylo = cy * cs;
769 yhi = ylo + cs;
770 if (yhi > fsy) {
771 yhi = fsy;
772 };
773
774 for (cx = scx; (cx <= ecx); cx++) {
775
776 xlo = cx * cs;
777 xhi = xlo + cs;
778 if (xhi > fsx) {
779 xhi = fsx;
780 };
781
782 GD2_DBG (printf
783 ("Processing Chunk (%d, %d), from %d to %d\n", cx, cy, ylo,
784 yhi));
785
786 if (!gd2_compressed (fmt)) {
787 GD2_DBG (printf ("Using raw format data\n"));
788 if (im->trueColor) {
789 dpos =
790 (cy * (cs * fsx) * 4 + cx * cs * (yhi - ylo) * 4) +
791 dstart;
792 } else {
793 dpos = cy * (cs * fsx) + cx * cs * (yhi - ylo) + dstart;
794 }
795 /* gd 2.0.11: gdSeek returns TRUE on success, not 0.
796 Longstanding bug. 01/16/03 */
797 if (!gdSeek (in, dpos)) {
798 gd_error("Seek error\n");
799 goto fail2;
800 };
801 GD2_DBG (printf
802 ("Reading (%d, %d) from position %d\n", cx, cy,
803 dpos - dstart));
804 } else {
805 chunkNum = cx + cy * ncx;
806
807 chunkLen = chunkMax;
808 if (!_gd2ReadChunk (chunkIdx[chunkNum].offset,
809 compBuf,
810 chunkIdx[chunkNum].size,
811 (char *) chunkBuf, &chunkLen, in)) {
812 printf ("Error reading comproessed chunk\n");
813 goto fail2;
814 };
815 chunkPos = 0;
816 GD2_DBG (printf
817 ("Reading (%d, %d) from chunk %d\n", cx, cy,
818 chunkNum));
819 };
820
821 GD2_DBG (printf
822 (" into (%d, %d) - (%d, %d)\n", xlo, ylo, xhi, yhi));
823 for (y = ylo; (y < yhi); y++) {
824
825 for (x = xlo; x < xhi; x++) {
826 if (!gd2_compressed (fmt)) {
827 if (im->trueColor) {
828 if (!gdGetInt ((int *) &ch, in)) {
829 ch = 0;
830 /*printf("EOF while reading file\n"); */
831 /*goto fail2; */
832 }
833 } else {
834 ch = gdGetC (in);
835 if ((int) ch == EOF) {
836 ch = 0;
837 /*printf("EOF while reading file\n"); */
838 /*goto fail2; */
839 }
840 }
841 } else {
842 if (im->trueColor) {
843 ch = chunkBuf[chunkPos++];
844 ch = (ch << 8) + chunkBuf[chunkPos++];
845 ch = (ch << 8) + chunkBuf[chunkPos++];
846 ch = (ch << 8) + chunkBuf[chunkPos++];
847 } else {
848 ch = chunkBuf[chunkPos++];
849 }
850 };
851
852 /* Only use a point that is in the image. */
853 if ((x >= srcx) && (x < (srcx + w)) && (x < fsx) && (x >= 0)
854 && (y >= srcy) && (y < (srcy + h)) && (y < fsy)
855 && (y >= 0)) {
856 /* 2.0.11: tpixels */
857 if (im->trueColor) {
858 im->tpixels[y - srcy][x - srcx] = ch;
859 } else {
860 im->pixels[y - srcy][x - srcx] = ch;
861 }
862 }
863 };
864 };
865 };
866 };
867
868 gdFree (chunkBuf);
869 gdFree (compBuf);
870 gdFree (chunkIdx);
871
872 return im;
873
874 fail2:
875 gdImageDestroy (im);
876 fail1:
877 if (chunkBuf) {
878 gdFree (chunkBuf);
879 }
880 if (compBuf) {
881 gdFree (compBuf);
882 }
883 if (chunkIdx) {
884 gdFree (chunkIdx);
885 }
886 return 0;
887
888 }
889
890 static void
_gd2PutHeader(gdImagePtr im,gdIOCtx * out,int cs,int fmt,int cx,int cy)891 _gd2PutHeader (gdImagePtr im, gdIOCtx * out, int cs, int fmt, int cx, int cy)
892 {
893 int i;
894
895 /* Send the gd2 id, to verify file format. */
896 for (i = 0; i < 4; i++) {
897 gdPutC ((unsigned char) (GD2_ID[i]), out);
898 };
899
900 /* */
901 /* We put the version info first, so future versions can easily change header info. */
902 /* */
903 gdPutWord (GD2_VERS, out);
904 gdPutWord (im->sx, out);
905 gdPutWord (im->sy, out);
906 gdPutWord (cs, out);
907 gdPutWord (fmt, out);
908 gdPutWord (cx, out);
909 gdPutWord (cy, out);
910
911 }
912
913 static void
_gdImageGd2(gdImagePtr im,gdIOCtx * out,int cs,int fmt)914 _gdImageGd2 (gdImagePtr im, gdIOCtx * out, int cs, int fmt)
915 {
916 int ncx, ncy, cx, cy;
917 int x, y, ylo, yhi, xlo, xhi;
918 int chunkLen;
919 int chunkNum = 0;
920 char *chunkData = NULL; /* So we can gdFree it with impunity. */
921 char *compData = NULL; /* So we can gdFree it with impunity. */
922 uLongf compLen;
923 int idxPos = 0;
924 int idxSize;
925 t_chunk_info *chunkIdx = NULL;
926 int posSave;
927 int bytesPerPixel = im->trueColor ? 4 : 1;
928 int compMax = 0;
929
930 /*printf("Trying to write GD2 file\n"); */
931
932 /* */
933 /* Force fmt to a valid value since we don't return anything. */
934 /* */
935 if ((fmt != GD2_FMT_RAW) && (fmt != GD2_FMT_COMPRESSED)) {
936 fmt = GD2_FMT_COMPRESSED;
937 };
938 if (im->trueColor) {
939 fmt += 2;
940 }
941 /* */
942 /* Make sure chunk size is valid. These are arbitrary values; 64 because it seems */
943 /* a little silly to expect performance improvements on a 64x64 bit scale, and */
944 /* 4096 because we buffer one chunk, and a 16MB buffer seems a little large - it may be */
945 /* OK for one user, but for another to read it, they require the buffer. */
946 /* */
947 if (cs == 0) {
948 cs = GD2_CHUNKSIZE;
949 } else if (cs < GD2_CHUNKSIZE_MIN) {
950 cs = GD2_CHUNKSIZE_MIN;
951 } else if (cs > GD2_CHUNKSIZE_MAX) {
952 cs = GD2_CHUNKSIZE_MAX;
953 };
954
955 /* Work out number of chunks. */
956 ncx = (im->sx + cs - 1) / cs;
957 ncy = (im->sy + cs - 1) / cs;
958
959 /* Write the standard header. */
960 _gd2PutHeader (im, out, cs, fmt, ncx, ncy);
961
962 if (gd2_compressed (fmt)) {
963 /* */
964 /* Work out size of buffer for compressed data, If CHUNKSIZE is large, */
965 /* then these will be large! */
966 /* */
967 /* The zlib notes say output buffer size should be (input size) * 1.01 * 12 */
968 /* - we'll use 1.02 to be paranoid. */
969 /* */
970 compMax = cs * bytesPerPixel * cs * 1.02 + 12;
971
972 /* */
973 /* Allocate the buffers. */
974 /* */
975 chunkData = gdCalloc (cs * bytesPerPixel * cs, 1);
976 if (!chunkData) {
977 goto fail;
978 }
979 compData = gdCalloc (compMax, 1);
980 if (!compData) {
981 goto fail;
982 }
983
984 /* */
985 /* Save the file position of chunk index, and allocate enough space for */
986 /* each chunk_info block . */
987 /* */
988 idxPos = gdTell (out);
989 idxSize = ncx * ncy * sizeof (t_chunk_info);
990 GD2_DBG (printf ("Index size is %d\n", idxSize));
991 gdSeek (out, idxPos + idxSize);
992
993 chunkIdx = gdCalloc (idxSize * sizeof (t_chunk_info), 1);
994 if (!chunkIdx) {
995 goto fail;
996 }
997 };
998
999 _gdPutColors (im, out);
1000
1001 GD2_DBG (printf ("Size: %dx%d\n", im->sx, im->sy));
1002 GD2_DBG (printf ("Chunks: %dx%d\n", ncx, ncy));
1003
1004 for (cy = 0; (cy < ncy); cy++) {
1005 for (cx = 0; (cx < ncx); cx++) {
1006
1007 ylo = cy * cs;
1008 yhi = ylo + cs;
1009 if (yhi > im->sy) {
1010 yhi = im->sy;
1011 };
1012
1013 GD2_DBG (printf
1014 ("Processing Chunk (%dx%d), y from %d to %d\n", cx, cy,
1015 ylo, yhi));
1016 chunkLen = 0;
1017 for (y = ylo; (y < yhi); y++) {
1018
1019 /*GD2_DBG(printf("y=%d: ",y)); */
1020
1021 xlo = cx * cs;
1022 xhi = xlo + cs;
1023 if (xhi > im->sx) {
1024 xhi = im->sx;
1025 };
1026
1027 if (gd2_compressed (fmt)) {
1028 for (x = xlo; x < xhi; x++) {
1029 /* 2.0.11: use truecolor pixel array. TBB */
1030 /*GD2_DBG(printf("%d...",x)); */
1031 if (im->trueColor) {
1032 int p = im->tpixels[y][x];
1033 chunkData[chunkLen++] = gdTrueColorGetAlpha (p);
1034 chunkData[chunkLen++] = gdTrueColorGetRed (p);
1035 chunkData[chunkLen++] = gdTrueColorGetGreen (p);
1036 chunkData[chunkLen++] = gdTrueColorGetBlue (p);
1037 } else {
1038 int p = im->pixels[y][x];
1039 chunkData[chunkLen++] = p;
1040 }
1041 };
1042 } else {
1043 for (x = xlo; x < xhi; x++) {
1044 /*GD2_DBG(printf("%d, ",x)); */
1045
1046 if (im->trueColor) {
1047 gdPutInt (im->tpixels[y][x], out);
1048 } else {
1049 gdPutC ((unsigned char) im->pixels[y][x], out);
1050 }
1051 };
1052 };
1053 /*GD2_DBG(printf("y=%d done.\n",y)); */
1054 };
1055 if (gd2_compressed (fmt)) {
1056 compLen = compMax;
1057 if (compress ((unsigned char *)
1058 &compData[0], &compLen,
1059 (unsigned char *) &chunkData[0],
1060 chunkLen) != Z_OK) {
1061 printf ("Error from compressing\n");
1062 } else {
1063 chunkIdx[chunkNum].offset = gdTell (out);
1064 chunkIdx[chunkNum++].size = compLen;
1065 GD2_DBG (printf
1066 ("Chunk %d size %d offset %d\n", chunkNum,
1067 chunkIdx[chunkNum - 1].size,
1068 chunkIdx[chunkNum - 1].offset));
1069
1070 if (gdPutBuf (compData, compLen, out) <= 0) {
1071 gd_error("gd write error\n");
1072 };
1073 };
1074 };
1075 };
1076 };
1077 if (gd2_compressed (fmt)) {
1078 /* Save the position, write the index, restore position (paranoia). */
1079 GD2_DBG (printf ("Seeking %d to write index\n", idxPos));
1080 posSave = gdTell (out);
1081 gdSeek (out, idxPos);
1082 GD2_DBG (printf ("Writing index\n"));
1083 for (x = 0; x < chunkNum; x++) {
1084 GD2_DBG (printf
1085 ("Chunk %d size %d offset %d\n", x, chunkIdx[x].size,
1086 chunkIdx[x].offset));
1087 gdPutInt (chunkIdx[x].offset, out);
1088 gdPutInt (chunkIdx[x].size, out);
1089 };
1090 /* We don't use fwrite for *endian reasons. */
1091 /*fwrite(chunkIdx, sizeof(int)*2, chunkNum, out); */
1092 gdSeek (out, posSave);
1093 };
1094
1095 /*printf("Memory block size is %d\n",gdTell(out)); */
1096 fail:
1097 GD2_DBG (printf ("Freeing memory\n"));
1098
1099 if (chunkData) {
1100 gdFree (chunkData);
1101 }
1102 if (compData) {
1103 gdFree (compData);
1104 }
1105 if (chunkIdx) {
1106 gdFree (chunkIdx);
1107 }
1108 GD2_DBG (printf ("Done\n"));
1109
1110 }
1111
1112 /*
1113 Function: gdImageGd2
1114 */
gdImageGd2(gdImagePtr im,FILE * outFile,int cs,int fmt)1115 BGD_DECLARE(void) gdImageGd2 (gdImagePtr im, FILE * outFile, int cs, int fmt)
1116 {
1117 gdIOCtx *out = gdNewFileCtx (outFile);
1118 if (out == NULL) return;
1119 _gdImageGd2 (im, out, cs, fmt);
1120 out->gd_free (out);
1121 }
1122
1123 /*
1124 Function: gdImageGd2Ptr
1125 */
gdImageGd2Ptr(gdImagePtr im,int cs,int fmt,int * size)1126 BGD_DECLARE(void *) gdImageGd2Ptr (gdImagePtr im, int cs, int fmt, int *size)
1127 {
1128 void *rv;
1129 gdIOCtx *out = gdNewDynamicCtx (2048, NULL);
1130 if (out == NULL) return NULL;
1131 _gdImageGd2 (im, out, cs, fmt);
1132 rv = gdDPExtractData (out, size);
1133 out->gd_free (out);
1134 return rv;
1135 }
1136
1137 #else /* no HAVE_LIBZ or !ENABLE_GD_FORMATS */
_noGd2Error(void)1138 static void _noGd2Error (void)
1139 {
1140 #if !ENABLE_GD_FORMATS
1141 gd_error("GD2 image support has been disabled\n");
1142 #else
1143 gd_error("GD2 support is not available - no libz\n");
1144 #endif
1145 }
1146
gdImageCreateFromGd2(FILE * inFile)1147 BGD_DECLARE(gdImagePtr) gdImageCreateFromGd2 (FILE * inFile)
1148 {
1149 _noGd2Error();
1150 return NULL;
1151 }
1152
gdImageCreateFromGd2Ctx(gdIOCtxPtr in)1153 BGD_DECLARE(gdImagePtr) gdImageCreateFromGd2Ctx (gdIOCtxPtr in)
1154 {
1155 _noGd2Error();
1156 return NULL;
1157 }
1158
gdImageCreateFromGd2Part(FILE * inFile,int srcx,int srcy,int w,int h)1159 BGD_DECLARE(gdImagePtr) gdImageCreateFromGd2Part (FILE * inFile, int srcx, int srcy, int w, int h)
1160 {
1161 _noGd2Error();
1162 return NULL;
1163 }
1164
gdImageCreateFromGd2Ptr(int size,void * data)1165 BGD_DECLARE(gdImagePtr) gdImageCreateFromGd2Ptr (int size, void *data)
1166 {
1167 _noGd2Error();
1168 return NULL;
1169 }
1170
gdImageCreateFromGd2PartCtx(gdIOCtx * in,int srcx,int srcy,int w,int h)1171 BGD_DECLARE(gdImagePtr) gdImageCreateFromGd2PartCtx (gdIOCtx * in, int srcx, int srcy, int w, int h)
1172 {
1173 _noGd2Error();
1174 return NULL;
1175 }
1176
gdImageCreateFromGd2PartPtr(int size,void * data,int srcx,int srcy,int w,int h)1177 BGD_DECLARE(gdImagePtr) gdImageCreateFromGd2PartPtr (int size, void *data, int srcx, int srcy, int w,
1178 int h)
1179 {
1180 _noGd2Error();
1181 return NULL;
1182 }
1183
gdImageGd2(gdImagePtr im,FILE * outFile,int cs,int fmt)1184 BGD_DECLARE(void) gdImageGd2 (gdImagePtr im, FILE * outFile, int cs, int fmt)
1185 {
1186 _noGd2Error();
1187 }
1188
gdImageGd2Ptr(gdImagePtr im,int cs,int fmt,int * size)1189 BGD_DECLARE(void *) gdImageGd2Ptr (gdImagePtr im, int cs, int fmt, int *size)
1190 {
1191 _noGd2Error();
1192 return NULL;
1193 }
1194 #endif /* HAVE_LIBZ */
1195