Annotation of embedaddon/php/ext/gd/libgd/gd_gd2.c, revision 1.1.1.1
1.1 misho 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: #include <stdio.h>
14: #include <errno.h>
15: #include <math.h>
16: #include <string.h>
17: #include <stdlib.h>
18: #include "gd.h"
19: #include "gdhelpers.h"
20:
21: #include <zlib.h>
22:
23: #define TRUE 1
24: #define FALSE 0
25:
26: /* 2.11: not part of the API, as the save routine can figure it out
27: * from im->trueColor, and the load routine doesn't need to tell
28: * the end user the saved format. NOTE: adding 2 is assumed
29: * to result in the correct format value for truecolor!
30: */
31: #define GD2_FMT_TRUECOLOR_RAW 3
32: #define GD2_FMT_TRUECOLOR_COMPRESSED 4
33:
34: #define gd2_compressed(fmt) (((fmt) == GD2_FMT_COMPRESSED) || ((fmt) == GD2_FMT_TRUECOLOR_COMPRESSED))
35: #define gd2_truecolor(fmt) (((fmt) == GD2_FMT_TRUECOLOR_RAW) || ((fmt) == GD2_FMT_TRUECOLOR_COMPRESSED))
36:
37: /* Use this for commenting out debug-print statements. */
38: /* Just use the first '#define' to allow all the prints... */
39: /* #define GD2_DBG(s) (s) */
40: #define GD2_DBG(s)
41:
42: typedef struct
43: {
44: int offset;
45: int size;
46: } t_chunk_info;
47:
48: extern int _gdGetColors(gdIOCtx * in, gdImagePtr im, int gd2xFlag);
49: extern void _gdPutColors(gdImagePtr im, gdIOCtx * out);
50:
51: /* */
52: /* Read the extra info in the gd2 header. */
53: /* */
54: static int _gd2GetHeader(gdIOCtxPtr in, int *sx, int *sy, int *cs, int *vers, int *fmt, int *ncx, int *ncy, t_chunk_info ** chunkIdx)
55: {
56: int i;
57: int ch;
58: char id[5];
59: t_chunk_info *cidx;
60: int sidx;
61: int nc;
62:
63: GD2_DBG(php_gd_error("Reading gd2 header info"));
64:
65: for (i = 0; i < 4; i++) {
66: ch = gdGetC(in);
67: if (ch == EOF) {
68: goto fail1;
69: }
70: id[i] = ch;
71: }
72: id[4] = 0;
73:
74: GD2_DBG(php_gd_error("Got file code: %s", id));
75:
76: /* Equiv. of 'magick'. */
77: if (strcmp(id, GD2_ID) != 0) {
78: GD2_DBG(php_gd_error("Not a valid gd2 file"));
79: goto fail1;
80: }
81:
82: /* Version */
83: if (gdGetWord(vers, in) != 1) {
84: goto fail1;
85: }
86: GD2_DBG(php_gd_error("Version: %d", *vers));
87:
88: if ((*vers != 1) && (*vers != 2)) {
89: GD2_DBG(php_gd_error("Bad version: %d", *vers));
90: goto fail1;
91: }
92:
93: /* Image Size */
94: if (!gdGetWord(sx, in)) {
95: GD2_DBG(php_gd_error("Could not get x-size"));
96: goto fail1;
97: }
98: if (!gdGetWord(sy, in)) {
99: GD2_DBG(php_gd_error("Could not get y-size"));
100: goto fail1;
101: }
102: GD2_DBG(php_gd_error("Image is %dx%d", *sx, *sy));
103:
104: /* Chunk Size (pixels, not bytes!) */
105: if (gdGetWord(cs, in) != 1) {
106: goto fail1;
107: }
108: GD2_DBG(php_gd_error("ChunkSize: %d", *cs));
109:
110: if ((*cs < GD2_CHUNKSIZE_MIN) || (*cs > GD2_CHUNKSIZE_MAX)) {
111: GD2_DBG(php_gd_error("Bad chunk size: %d", *cs));
112: goto fail1;
113: }
114:
115: /* Data Format */
116: if (gdGetWord(fmt, in) != 1) {
117: goto fail1;
118: }
119: GD2_DBG(php_gd_error("Format: %d", *fmt));
120:
121: if ((*fmt != GD2_FMT_RAW) && (*fmt != GD2_FMT_COMPRESSED) && (*fmt != GD2_FMT_TRUECOLOR_RAW) && (*fmt != GD2_FMT_TRUECOLOR_COMPRESSED)) {
122: GD2_DBG(php_gd_error("Bad data format: %d", *fmt));
123: goto fail1;
124: }
125:
126: /* # of chunks wide */
127: if (gdGetWord(ncx, in) != 1) {
128: goto fail1;
129: }
130: GD2_DBG(php_gd_error("%d Chunks Wide", *ncx));
131:
132: /* # of chunks high */
133: if (gdGetWord(ncy, in) != 1) {
134: goto fail1;
135: }
136: GD2_DBG(php_gd_error("%d Chunks vertically", *ncy));
137:
138: if (gd2_compressed(*fmt)) {
139: nc = (*ncx) * (*ncy);
140: GD2_DBG(php_gd_error("Reading %d chunk index entries", nc));
141: sidx = sizeof(t_chunk_info) * nc;
142: if (sidx <= 0) {
143: goto fail1;
144: }
145: cidx = gdCalloc(sidx, 1);
146: for (i = 0; i < nc; i++) {
147: if (gdGetInt(&cidx[i].offset, in) != 1) {
148: goto fail1;
149: }
150: if (gdGetInt(&cidx[i].size, in) != 1) {
151: goto fail1;
152: }
153: }
154: *chunkIdx = cidx;
155: }
156:
157: GD2_DBG(php_gd_error("gd2 header complete"));
158:
159: return 1;
160:
161: fail1:
162: return 0;
163: }
164:
165: static gdImagePtr _gd2CreateFromFile (gdIOCtxPtr in, int *sx, int *sy, int *cs, int *vers, int *fmt, int *ncx, int *ncy, t_chunk_info ** cidx)
166: {
167: gdImagePtr im;
168:
169: if (_gd2GetHeader (in, sx, sy, cs, vers, fmt, ncx, ncy, cidx) != 1) {
170: GD2_DBG(php_gd_error("Bad GD2 header"));
171: goto fail1;
172: }
173:
174: if (gd2_truecolor(*fmt)) {
175: im = gdImageCreateTrueColor(*sx, *sy);
176: } else {
177: im = gdImageCreate(*sx, *sy);
178: }
179: if (im == NULL) {
180: GD2_DBG(php_gd_error("Could not create gdImage"));
181: goto fail1;
182: }
183:
184: if (!_gdGetColors(in, im, (*vers) == 2)) {
185: GD2_DBG(php_gd_error("Could not read color palette"));
186: goto fail2;
187: }
188: GD2_DBG(php_gd_error("Image palette completed: %d colours", im->colorsTotal));
189:
190: return im;
191:
192: fail2:
193: gdImageDestroy(im);
194: return 0;
195:
196: fail1:
197: return 0;
198: }
199:
200: static int _gd2ReadChunk (int offset, char *compBuf, int compSize, char *chunkBuf, uLongf * chunkLen, gdIOCtx * in)
201: {
202: int zerr;
203:
204: if (gdTell(in) != offset) {
205: GD2_DBG(php_gd_error("Positioning in file to %d", offset));
206: gdSeek(in, offset);
207: } else {
208: GD2_DBG(php_gd_error("Already Positioned in file to %d", offset));
209: }
210:
211: /* Read and uncompress an entire chunk. */
212: GD2_DBG(php_gd_error("Reading file"));
213: if (gdGetBuf(compBuf, compSize, in) != compSize) {
214: return FALSE;
215: }
216: GD2_DBG(php_gd_error("Got %d bytes. Uncompressing into buffer of %d bytes", compSize, (int)*chunkLen));
217: zerr = uncompress((unsigned char *) chunkBuf, chunkLen, (unsigned char *) compBuf, compSize);
218: if (zerr != Z_OK) {
219: GD2_DBG(php_gd_error("Error %d from uncompress", zerr));
220: return FALSE;
221: }
222: GD2_DBG(php_gd_error("Got chunk"));
223:
224: return TRUE;
225: }
226:
227: gdImagePtr gdImageCreateFromGd2 (FILE * inFile)
228: {
229: gdIOCtx *in = gdNewFileCtx(inFile);
230: gdImagePtr im;
231:
232: im = gdImageCreateFromGd2Ctx(in);
233:
234: in->gd_free(in);
235:
236: return im;
237: }
238:
239: gdImagePtr gdImageCreateFromGd2Ptr (int size, void *data)
240: {
241: gdImagePtr im;
242: gdIOCtx *in = gdNewDynamicCtxEx(size, data, 0);
243: im = gdImageCreateFromGd2Ctx(in);
244: in->gd_free(in);
245:
246: return im;
247: }
248:
249: gdImagePtr gdImageCreateFromGd2Ctx (gdIOCtxPtr in)
250: {
251: int sx, sy;
252: int i;
253: int ncx, ncy, nc, cs, cx, cy;
254: int x, y, ylo, yhi, xlo, xhi;
255: int vers, fmt;
256: t_chunk_info *chunkIdx = NULL; /* So we can gdFree it with impunity. */
257: unsigned char *chunkBuf = NULL; /* So we can gdFree it with impunity. */
258: int chunkNum = 0;
259: int chunkMax = 0;
260: uLongf chunkLen;
261: int chunkPos = 0;
262: int compMax = 0;
263: int bytesPerPixel;
264: char *compBuf = NULL; /* So we can gdFree it with impunity. */
265:
266: gdImagePtr im;
267:
268: /* Get the header */
269: if (!(im = _gd2CreateFromFile(in, &sx, &sy, &cs, &vers, &fmt, &ncx, &ncy, &chunkIdx))) {
270: return 0;
271: }
272:
273: bytesPerPixel = im->trueColor ? 4 : 1;
274: nc = ncx * ncy;
275:
276: if (gd2_compressed(fmt)) {
277: /* Find the maximum compressed chunk size. */
278: compMax = 0;
279: for (i = 0; (i < nc); i++) {
280: if (chunkIdx[i].size > compMax) {
281: compMax = chunkIdx[i].size;
282: }
283: }
284: compMax++;
285:
286: /* Allocate buffers */
287: chunkMax = cs * bytesPerPixel * cs;
288: if (chunkMax <= 0) {
289: return 0;
290: }
291: chunkBuf = gdCalloc(chunkMax, 1);
292: compBuf = gdCalloc(compMax, 1);
293:
294: GD2_DBG(php_gd_error("Largest compressed chunk is %d bytes", compMax));
295: }
296:
297: /* Read the data... */
298: for (cy = 0; (cy < ncy); cy++) {
299: for (cx = 0; (cx < ncx); cx++) {
300: ylo = cy * cs;
301: yhi = ylo + cs;
302: if (yhi > im->sy) {
303: yhi = im->sy;
304: }
305:
306: GD2_DBG(php_gd_error("Processing Chunk %d (%d, %d), y from %d to %d", chunkNum, cx, cy, ylo, yhi));
307:
308: if (gd2_compressed(fmt)) {
309: chunkLen = chunkMax;
310:
311: if (!_gd2ReadChunk(chunkIdx[chunkNum].offset, compBuf, chunkIdx[chunkNum].size, (char *) chunkBuf, &chunkLen, in)) {
312: GD2_DBG(php_gd_error("Error reading comproessed chunk"));
313: goto fail2;
314: }
315:
316: chunkPos = 0;
317: }
318:
319: for (y = ylo; (y < yhi); y++) {
320: xlo = cx * cs;
321: xhi = xlo + cs;
322: if (xhi > im->sx) {
323: xhi = im->sx;
324: }
325:
326: if (!gd2_compressed(fmt)) {
327: for (x = xlo; x < xhi; x++) {
328: if (im->trueColor) {
329: if (!gdGetInt(&im->tpixels[y][x], in)) {
330: im->tpixels[y][x] = 0;
331: }
332: } else {
333: int ch;
334: if (!gdGetByte(&ch, in)) {
335: ch = 0;
336: }
337: im->pixels[y][x] = ch;
338: }
339: }
340: } else {
341: for (x = xlo; x < xhi; x++) {
342: if (im->trueColor) {
343: /* 2.0.1: work around a gcc bug by being verbose. TBB */
344: int a = chunkBuf[chunkPos++] << 24;
345: int r = chunkBuf[chunkPos++] << 16;
346: int g = chunkBuf[chunkPos++] << 8;
347: int b = chunkBuf[chunkPos++];
348: im->tpixels[y][x] = a + r + g + b;
349: } else {
350: im->pixels[y][x] = chunkBuf[chunkPos++];
351: }
352: }
353: }
354: }
355: chunkNum++;
356: }
357: }
358:
359: GD2_DBG(php_gd_error("Freeing memory"));
360:
361: if (chunkBuf) {
362: gdFree(chunkBuf);
363: }
364: if (compBuf) {
365: gdFree(compBuf);
366: }
367: if (chunkIdx) {
368: gdFree(chunkIdx);
369: }
370:
371: GD2_DBG(php_gd_error("Done"));
372:
373: return im;
374:
375: fail2:
376: gdImageDestroy(im);
377: if (chunkBuf) {
378: gdFree(chunkBuf);
379: }
380: if (compBuf) {
381: gdFree(compBuf);
382: }
383: if (chunkIdx) {
384: gdFree(chunkIdx);
385: }
386:
387: return 0;
388: }
389:
390: gdImagePtr gdImageCreateFromGd2PartPtr (int size, void *data, int srcx, int srcy, int w, int h)
391: {
392: gdImagePtr im;
393: gdIOCtx *in = gdNewDynamicCtxEx(size, data, 0);
394: im = gdImageCreateFromGd2PartCtx(in, srcx, srcy, w, h);
395: in->gd_free(in);
396:
397: return im;
398: }
399:
400: gdImagePtr gdImageCreateFromGd2Part (FILE * inFile, int srcx, int srcy, int w, int h)
401: {
402: gdImagePtr im;
403: gdIOCtx *in = gdNewFileCtx(inFile);
404:
405: im = gdImageCreateFromGd2PartCtx(in, srcx, srcy, w, h);
406:
407: in->gd_free(in);
408:
409: return im;
410: }
411:
412: gdImagePtr gdImageCreateFromGd2PartCtx (gdIOCtx * in, int srcx, int srcy, int w, int h)
413: {
414: int scx, scy, ecx, ecy, fsx, fsy;
415: int nc, ncx, ncy, cs, cx, cy;
416: int x, y, ylo, yhi, xlo, xhi;
417: int dstart, dpos;
418: int i;
419: /* 2.0.12: unsigned is correct; fixes problems with color munging. Thanks to Steven Brown. */
420: unsigned int ch;
421: int vers, fmt;
422: t_chunk_info *chunkIdx = NULL;
423: unsigned char *chunkBuf = NULL;
424: int chunkNum;
425: int chunkMax = 0;
426: uLongf chunkLen;
427: int chunkPos = 0;
428: int compMax;
429: char *compBuf = NULL;
430:
431: gdImagePtr im;
432:
433: if (w<1 || h <1) {
434: return 0;
435: }
436:
437: /* The next few lines are basically copied from gd2CreateFromFile
438: * we change the file size, so don't want to use the code directly.
439: * but we do need to know the file size.
440: */
441: if (_gd2GetHeader(in, &fsx, &fsy, &cs, &vers, &fmt, &ncx, &ncy, &chunkIdx) != 1) {
442: goto fail1;
443: }
444:
445: GD2_DBG(php_gd_error("File size is %dx%d", fsx, fsy));
446:
447: /* This is the difference - make a file based on size of chunks. */
448: if (gd2_truecolor(fmt)) {
449: im = gdImageCreateTrueColor(w, h);
450: } else {
451: im = gdImageCreate(w, h);
452: }
453: if (im == NULL) {
454: goto fail1;
455: }
456:
457: if (!_gdGetColors(in, im, vers == 2)) {
458: goto fail2;
459: }
460: GD2_DBG(php_gd_error("Image palette completed: %d colours", im->colorsTotal));
461:
462: /* Process the header info */
463: nc = ncx * ncy;
464:
465: if (gd2_compressed(fmt)) {
466: /* Find the maximum compressed chunk size. */
467: compMax = 0;
468: for (i = 0; (i < nc); i++) {
469: if (chunkIdx[i].size > compMax) {
470: compMax = chunkIdx[i].size;
471: }
472: }
473: compMax++;
474:
475: if (im->trueColor) {
476: chunkMax = cs * cs * 4;
477: } else {
478: chunkMax = cs * cs;
479: }
480: if (chunkMax <= 0) {
481: goto fail2;
482: }
483:
484: chunkBuf = gdCalloc(chunkMax, 1);
485: compBuf = gdCalloc(compMax, 1);
486: }
487:
488: /* Work out start/end chunks */
489: scx = srcx / cs;
490: scy = srcy / cs;
491: if (scx < 0) {
492: scx = 0;
493: }
494: if (scy < 0) {
495: scy = 0;
496: }
497:
498: ecx = (srcx + w) / cs;
499: ecy = (srcy + h) / cs;
500: if (ecx >= ncx) {
501: ecx = ncx - 1;
502: }
503: if (ecy >= ncy) {
504: ecy = ncy - 1;
505: }
506:
507: /* Remember file position of image data. */
508: dstart = gdTell(in);
509: GD2_DBG(php_gd_error("Data starts at %d", dstart));
510:
511: /* Loop through the chunks. */
512: for (cy = scy; (cy <= ecy); cy++) {
513: ylo = cy * cs;
514: yhi = ylo + cs;
515: if (yhi > fsy) {
516: yhi = fsy;
517: }
518:
519: for (cx = scx; cx <= ecx; cx++) {
520:
521: xlo = cx * cs;
522: xhi = xlo + cs;
523: if (xhi > fsx) {
524: xhi = fsx;
525: }
526:
527: GD2_DBG(php_gd_error("Processing Chunk (%d, %d), from %d to %d", cx, cy, ylo, yhi));
528:
529: if (!gd2_compressed(fmt)) {
530: GD2_DBG(php_gd_error("Using raw format data"));
531: if (im->trueColor) {
532: dpos = (cy * (cs * fsx) * 4 + cx * cs * (yhi - ylo) * 4) + dstart;
533: } else {
534: dpos = cy * (cs * fsx) + cx * cs * (yhi - ylo) + dstart;
535: }
536:
537: /* gd 2.0.11: gdSeek returns TRUE on success, not 0. Longstanding bug. 01/16/03 */
538: if (!gdSeek(in, dpos)) {
539: php_gd_error_ex(E_WARNING, "Error from seek: %d", errno);
540: goto fail2;
541: }
542: GD2_DBG(php_gd_error("Reading (%d, %d) from position %d", cx, cy, dpos - dstart));
543: } else {
544: chunkNum = cx + cy * ncx;
545:
546: chunkLen = chunkMax;
547: if (!_gd2ReadChunk (chunkIdx[chunkNum].offset, compBuf, chunkIdx[chunkNum].size, (char *)chunkBuf, &chunkLen, in)) {
548: php_gd_error("Error reading comproessed chunk");
549: goto fail2;
550: }
551: chunkPos = 0;
552: GD2_DBG(php_gd_error("Reading (%d, %d) from chunk %d", cx, cy, chunkNum));
553: }
554:
555: GD2_DBG(php_gd_error(" into (%d, %d) - (%d, %d)", xlo, ylo, xhi, yhi));
556:
557: for (y = ylo; (y < yhi); y++) {
558: for (x = xlo; x < xhi; x++) {
559: if (!gd2_compressed(fmt)) {
560: if (im->trueColor) {
561: if (!gdGetInt((int *)&ch, in)) {
562: ch = 0;
563: }
564: } else {
565: ch = gdGetC(in);
566: if ((int)ch == EOF) {
567: ch = 0;
568: }
569: }
570: } else {
571: if (im->trueColor) {
572: ch = chunkBuf[chunkPos++];
573: ch = (ch << 8) + chunkBuf[chunkPos++];
574: ch = (ch << 8) + chunkBuf[chunkPos++];
575: ch = (ch << 8) + chunkBuf[chunkPos++];
576: } else {
577: ch = chunkBuf[chunkPos++];
578: }
579: }
580:
581: /* Only use a point that is in the image. */
582: if ((x >= srcx) && (x < (srcx + w)) && (x < fsx) && (x >= 0) && (y >= srcy) && (y < (srcy + h)) && (y < fsy) && (y >= 0)) {
583: if (im->trueColor) {
584: im->tpixels[y - srcy][x - srcx] = ch;
585: } else {
586: im->pixels[y - srcy][x - srcx] = ch;
587: }
588: }
589: }
590: }
591: }
592: }
593:
594: if (chunkBuf) {
595: gdFree(chunkBuf);
596: }
597: if (compBuf) {
598: gdFree(compBuf);
599: }
600: if (chunkIdx) {
601: gdFree(chunkIdx);
602: }
603:
604: return im;
605:
606: fail2:
607: gdImageDestroy(im);
608: fail1:
609: if (chunkBuf) {
610: gdFree(chunkBuf);
611: }
612: if (compBuf) {
613: gdFree(compBuf);
614: }
615: if (chunkIdx) {
616: gdFree(chunkIdx);
617: }
618:
619: return 0;
620: }
621:
622: static void _gd2PutHeader (gdImagePtr im, gdIOCtx * out, int cs, int fmt, int cx, int cy)
623: {
624: int i;
625:
626: /* Send the gd2 id, to verify file format. */
627: for (i = 0; i < 4; i++) {
628: gdPutC((unsigned char) (GD2_ID[i]), out);
629: }
630:
631: /* We put the version info first, so future versions can easily change header info. */
632:
633: gdPutWord(GD2_VERS, out);
634: gdPutWord(im->sx, out);
635: gdPutWord(im->sy, out);
636: gdPutWord(cs, out);
637: gdPutWord(fmt, out);
638: gdPutWord(cx, out);
639: gdPutWord(cy, out);
640: }
641:
642: static void _gdImageGd2 (gdImagePtr im, gdIOCtx * out, int cs, int fmt)
643: {
644: int ncx, ncy, cx, cy;
645: int x, y, ylo, yhi, xlo, xhi;
646: int chunkLen;
647: int chunkNum = 0;
648: char *chunkData = NULL; /* So we can gdFree it with impunity. */
649: char *compData = NULL; /* So we can gdFree it with impunity. */
650: uLongf compLen;
651: int idxPos = 0;
652: int idxSize;
653: t_chunk_info *chunkIdx = NULL; /* So we can gdFree it with impunity. */
654: int posSave;
655: int bytesPerPixel = im->trueColor ? 4 : 1;
656: int compMax = 0;
657:
658: /* Force fmt to a valid value since we don't return anything. */
659: if ((fmt != GD2_FMT_RAW) && (fmt != GD2_FMT_COMPRESSED)) {
660: fmt = im->trueColor ? GD2_FMT_TRUECOLOR_COMPRESSED : GD2_FMT_COMPRESSED;
661: }
662: if (im->trueColor) {
663: fmt += 2;
664: }
665: /* Make sure chunk size is valid. These are arbitrary values; 64 because it seems
666: * a little silly to expect performance improvements on a 64x64 bit scale, and
667: * 4096 because we buffer one chunk, and a 16MB buffer seems a little large - it may be
668: * OK for one user, but for another to read it, they require the buffer.
669: */
670: if (cs == 0) {
671: cs = GD2_CHUNKSIZE;
672: } else if (cs < GD2_CHUNKSIZE_MIN) {
673: cs = GD2_CHUNKSIZE_MIN;
674: } else if (cs > GD2_CHUNKSIZE_MAX) {
675: cs = GD2_CHUNKSIZE_MAX;
676: }
677:
678: /* Work out number of chunks. */
679: ncx = im->sx / cs + 1;
680: ncy = im->sy / cs + 1;
681:
682: /* Write the standard header. */
683: _gd2PutHeader (im, out, cs, fmt, ncx, ncy);
684:
685: if (gd2_compressed(fmt)) {
686: /* Work out size of buffer for compressed data, If CHUNKSIZE is large,
687: * then these will be large!
688: */
689:
690: /* The zlib notes say output buffer size should be (input size) * 1.01 * 12
691: * - we'll use 1.02 to be paranoid.
692: */
693: compMax = (int)(cs * bytesPerPixel * cs * 1.02f) + 12;
694:
695: /* Allocate the buffers. */
696: chunkData = safe_emalloc(cs * bytesPerPixel, cs, 0);
697: memset(chunkData, 0, cs * bytesPerPixel * cs);
698: if (compMax <= 0) {
699: goto fail;
700: }
701: compData = gdCalloc(compMax, 1);
702:
703: /* Save the file position of chunk index, and allocate enough space for
704: * each chunk_info block .
705: */
706: idxPos = gdTell(out);
707: idxSize = ncx * ncy * sizeof(t_chunk_info);
708: GD2_DBG(php_gd_error("Index size is %d", idxSize));
709: gdSeek(out, idxPos + idxSize);
710:
711: chunkIdx = safe_emalloc(idxSize, sizeof(t_chunk_info), 0);
712: memset(chunkIdx, 0, idxSize * sizeof(t_chunk_info));
713: }
714:
715: _gdPutColors (im, out);
716:
717: GD2_DBG(php_gd_error("Size: %dx%d", im->sx, im->sy));
718: GD2_DBG(php_gd_error("Chunks: %dx%d", ncx, ncy));
719:
720: for (cy = 0; (cy < ncy); cy++) {
721: for (cx = 0; (cx < ncx); cx++) {
722: ylo = cy * cs;
723: yhi = ylo + cs;
724: if (yhi > im->sy) {
725: yhi = im->sy;
726: }
727:
728: GD2_DBG(php_gd_error("Processing Chunk (%dx%d), y from %d to %d", cx, cy, ylo, yhi));
729: chunkLen = 0;
730: for (y = ylo; (y < yhi); y++) {
731: GD2_DBG(php_gd_error("y=%d: ",y));
732: xlo = cx * cs;
733: xhi = xlo + cs;
734: if (xhi > im->sx) {
735: xhi = im->sx;
736: }
737:
738: if (gd2_compressed(fmt)) {
739: for (x = xlo; x < xhi; x++) {
740: GD2_DBG(php_gd_error("%d...",x));
741: if (im->trueColor) {
742: int p = im->tpixels[y][x];
743: chunkData[chunkLen++] = gdTrueColorGetAlpha(p);
744: chunkData[chunkLen++] = gdTrueColorGetRed(p);
745: chunkData[chunkLen++] = gdTrueColorGetGreen(p);
746: chunkData[chunkLen++] = gdTrueColorGetBlue(p);
747: } else {
748: chunkData[chunkLen++] = im->pixels[y][x];
749: }
750: }
751: } else {
752: for (x = xlo; x < xhi; x++) {
753: GD2_DBG(php_gd_error("%d, ",x));
754:
755: if (im->trueColor) {
756: gdPutInt(im->tpixels[y][x], out);
757: } else {
758: gdPutC((unsigned char) im->pixels[y][x], out);
759: }
760: }
761: }
762: GD2_DBG(php_gd_error("y=%d done.",y));
763: }
764:
765: if (gd2_compressed(fmt)) {
766: compLen = compMax;
767: if (compress((unsigned char *) &compData[0], &compLen, (unsigned char *) &chunkData[0], chunkLen) != Z_OK) {
768: php_gd_error("Error from compressing");
769: } else {
770: chunkIdx[chunkNum].offset = gdTell(out);
771: chunkIdx[chunkNum++].size = compLen;
772: GD2_DBG(php_gd_error("Chunk %d size %d offset %d", chunkNum, chunkIdx[chunkNum - 1].size, chunkIdx[chunkNum - 1].offset));
773:
774: if (gdPutBuf (compData, compLen, out) <= 0) {
775: /* Any alternate suggestions for handling this? */
776: php_gd_error_ex(E_WARNING, "Error %d on write", errno);
777: }
778: }
779: }
780: }
781: }
782:
783: if (gd2_compressed(fmt)) {
784: /* Save the position, write the index, restore position (paranoia). */
785: GD2_DBG(php_gd_error("Seeking %d to write index", idxPos));
786: posSave = gdTell(out);
787: gdSeek(out, idxPos);
788: GD2_DBG(php_gd_error("Writing index"));
789: for (x = 0; x < chunkNum; x++) {
790: GD2_DBG(php_gd_error("Chunk %d size %d offset %d", x, chunkIdx[x].size, chunkIdx[x].offset));
791: gdPutInt(chunkIdx[x].offset, out);
792: gdPutInt(chunkIdx[x].size, out);
793: }
794: gdSeek(out, posSave);
795: }
796: fail:
797: GD2_DBG(php_gd_error("Freeing memory"));
798: if (chunkData) {
799: gdFree(chunkData);
800: }
801: if (compData) {
802: gdFree(compData);
803: }
804: if (chunkIdx) {
805: gdFree(chunkIdx);
806: }
807: GD2_DBG(php_gd_error("Done"));
808: }
809:
810: void gdImageGd2 (gdImagePtr im, FILE * outFile, int cs, int fmt)
811: {
812: gdIOCtx *out = gdNewFileCtx(outFile);
813:
814: _gdImageGd2(im, out, cs, fmt);
815:
816: out->gd_free(out);
817: }
818:
819: void *gdImageGd2Ptr (gdImagePtr im, int cs, int fmt, int *size)
820: {
821: void *rv;
822: gdIOCtx *out = gdNewDynamicCtx(2048, NULL);
823:
824: _gdImageGd2(im, out, cs, fmt);
825: rv = gdDPExtractData(out, size);
826: out->gd_free(out);
827:
828: return rv;
829: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>