cvs: php4 /ext/gd gd.c /ext/gd/libgd gd.c gd.h gd_gd2.c gd_jpeg.c
| From: | Ilia Alshanetsky | Date: | Fri, 17 Jan 2003 18:34:07 +0000 |
| Subject: | cvs: php4 /ext/gd gd.c /ext/gd/libgd gd.c gd.h gd_gd2.c gd_jpeg.c | ||
| Groups: | php.cvs | ||
| Request: | Send a blank email to php-cvs+get-17976@lists.php.net to get a copy of this message | ||
iliaa Fri Jan 17 13:34:07 2003 EDT
Modified files:
/php4/ext/gd gd.c
/php4/ext/gd/libgd gd.c gd.h gd_gd2.c gd_jpeg.c
Log:
Syncronize bundled GD library with latest GD (2.0.11).
Index: php4/ext/gd/gd.c diff -u php4/ext/gd/gd.c:1.243 php4/ext/gd/gd.c:1.244 --- php4/ext/gd/gd.c:1.243 Wed Jan 8 13:11:40 2003 +++ php4/ext/gd/gd.c Fri Jan 17 13:34:07 2003 @@ -18,7 +18,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: gd.c,v 1.243 2003/01/08 18:11:40 iliaa Exp $ */ +/* $Id: gd.c,v 1.244 2003/01/17 18:34:07 iliaa Exp $ */ /* gd 1.2 is copyright 1994, 1995, Quest Protein Database Center, Cold Spring Harbor Labs. */ @@ -1562,17 +1562,18 @@ */ static void _php_image_output(INTERNAL_FUNCTION_PARAMETERS, int image_type, char *tn, void (*func_p)()) { - zval **imgind, **file, **quality; + zval **imgind, **file, **quality, **type; gdImagePtr im; char *fn = NULL; FILE *fp; int argc = ZEND_NUM_ARGS(); - int q = -1, i; + int q = -1, i, t = 1; /* The quality parameter for Wbmp stands for the threshold when called from image2wbmp() */ /* When called from imagewbmp() the quality parameter stands for the foreground color. Default: black. */ + /* The quality parameter for gd2 stands for chunk size */ - if (argc < 1 || argc > 3 || zend_get_parameters_ex(argc, &imgind, &file, &quality) == FAILURE) { + if (argc < 1 || argc > 4 || zend_get_parameters_ex(argc, &imgind, &file, &quality, &type) == FAILURE) { ZEND_WRONG_PARAM_COUNT(); } @@ -1585,6 +1586,10 @@ convert_to_long_ex(quality); q = Z_LVAL_PP(quality); } + if (argc == 4) { + convert_to_long_ex(type); + t = Z_LVAL_PP(type); + } } if ((argc == 2) || (argc == 3 && Z_STRLEN_PP(file))) { @@ -1622,7 +1627,10 @@ break; #endif default: - (*func_p)(im, fp); + if (q == -1) { + q = 128; + } + (*func_p)(im, fp, q, t); break; } fflush(fp); @@ -1749,7 +1757,7 @@ /* }}} */ #ifdef HAVE_GD_GD2 -/* {{{ proto int imagegd2(int im [, string filename]) +/* {{{ proto int imagegd2(int im [, string filename, [, int chunk_size, [, int type]]]) Output GD2 image to browser or file */ PHP_FUNCTION(imagegd2) { Index: php4/ext/gd/libgd/gd.c diff -u php4/ext/gd/libgd/gd.c:1.40 php4/ext/gd/libgd/gd.c:1.41 --- php4/ext/gd/libgd/gd.c:1.40 Thu Jan 9 21:00:39 2003 +++ php4/ext/gd/libgd/gd.c Fri Jan 17 13:34:07 2003 @@ -81,6 +81,9 @@ }; #endif /*CHARSET_EBCDIC */ +/* 2.0.10: cast instead of floor() yields 35% performance improvement. Thanks to John Buckman. */ +#define floor_cast(exp) ((long) exp) + extern int gdCosT[]; extern int gdSinT[]; @@ -661,6 +664,76 @@ } +/* 2.0.10: before the drawing routines, some code to clip points that are + * outside the drawing window. Nick Atty (nick@canalplan.org.uk) + * + * This is the Sutherland Hodgman Algorithm, as implemented by + * Duvanenko, Robbins and Gyurcsik - SH(DRG) for short. See Dr Dobb's + * Journal, January 1996, pp107-110 and 116-117 + * + * Given the end points of a line, and a bounding rectangle (which we + * know to be from (0,0) to (SX,SY)), adjust the endpoints to be on + * the edges of the rectangle if the line should be drawn at all, + * otherwise return a failure code + */ + +/* this does "one-dimensional" clipping: note that the second time it + * is called, all the x parameters refer to height and the y to width + * - the comments ignore this (if you can understand it when it's + * looking at the X parameters, it should become clear what happens on + * the second call!) The code is simplified from that in the article, + * as we know that gd images always start at (0,0) + */ + +static int clip_1d(int *x0, int *y0, int *x1, int *y1, int maxdim) { + double m; /* gradient of line */ + + if (*x0 < 0) { /* start of line is left of window */ + if(*x1 < 0) { /* as is the end, so the line never cuts the window */ + return 0; + } + m = (*y1 - *y0)/(double)(*x1 - *x0); /* calculate the slope of the line */ + /* adjust x0 to be on the left boundary (ie to be zero), and y0 to match */ + *y0 -= m * *x0; + *x0 = 0; + /* now, perhaps, adjust the far end of the line as well */ + if (*x1 > maxdim) { + *y1 += m * (maxdim - *x1); + *x1 = maxdim; + } + return 1; + } + if (*x0 > maxdim) { /* start of line is right of window - complement of above */ + if (*x1 > maxdim) { /* as is the end, so the line misses the window */ + return 0; + } + m = (*y1 - *y0)/(double)(*x1 - *x0); /* calculate the slope of the line */ + *y0 += m * (maxdim - *x0); /* adjust so point is on the right boundary */ + *x0 = maxdim; + /* now, perhaps, adjust the end of the line */ + if (*x1 < 0) { + *y1 -= m * *x1; + *x1 = 0; + } + return 1; + } + /* the final case - the start of the line is inside the window */ + if (*x1 > maxdim) { /* other end is outside to the right */ + m = (*y1 - *y0)/(double)(*x1 - *x0); /* calculate the slope of the line */ + *y1 += m * (maxdim - *x1); + *x1 = maxdim; + return 1; + } + if (*x1 < 0) { /* other end is outside to the left */ + m = (*y1 - *y0)/(double)(*x1 - *x0); /* calculate the slope of the line */ + *y1 -= m * *x1; + *x1 = 0; + return 1; + } + /* only get here if both points are inside the window */ + return 1; +} + void gdImageSetPixel (gdImagePtr im, int x, int y, int color) { @@ -871,158 +944,139 @@ void gdImageLine (gdImagePtr im, int x1, int y1, int x2, int y2, int color) { - int dx, dy, incr1, incr2, d, x, y, xend, yend, xdirflag, ydirflag; - int wid; - int w, wstart; - int thick = im->thick; - dx = abs (x2 - x1); - dy = abs (y2 - y1); - if (dy <= dx) - { - /* More-or-less horizontal. use wid for vertical stroke */ - /* Doug Claar: watch out for NaN in atan2 (2.0.5) */ - if ((dx == 0) && (dy == 0)) { - wid = 1; - } else { - wid = (int)(thick * cos (atan2 (dy, dx))); - if (wid == 0) { - wid = 1; - } - } - d = 2 * dy - dx; - incr1 = 2 * dy; - incr2 = 2 * (dy - dx); - if (x1 > x2) - { - x = x2; - y = y2; - ydirflag = (-1); - xend = x1; - } - else - { - x = x1; - y = y1; - ydirflag = 1; - xend = x2; - } - - /* Set up line thickness */ - wstart = y - wid / 2; - for (w = wstart; w < wstart + wid; w++) - gdImageSetPixel (im, x, w, color); - - if (((y2 - y1) * ydirflag) > 0) - { - while (x < xend) - { - x++; - if (d < 0) - { - d += incr1; - } - else - { - y++; - d += incr2; - } - wstart = y - wid / 2; - for (w = wstart; w < wstart + wid; w++) - gdImageSetPixel (im, x, w, color); - } - } - else - { - while (x < xend) - { - x++; - if (d < 0) - { - d += incr1; - } - else - { - y--; - d += incr2; - } - wstart = y - wid / 2; - for (w = wstart; w < wstart + wid; w++) - gdImageSetPixel (im, x, w, color); - } - } - } - else - { - /* More-or-less vertical. use wid for horizontal stroke */ - wid = (int)(thick * sin (atan2 (dy, dx))); - if (wid == 0) - wid = 1; + int dx, dy, incr1, incr2, d, x, y, xend, yend, xdirflag, ydirflag; + int wid; + int w, wstart; + int thick = im->thick; - d = 2 * dx - dy; - incr1 = 2 * dx; - incr2 = 2 * (dx - dy); - if (y1 > y2) - { - y = y2; - x = x2; - yend = y1; - xdirflag = (-1); - } - else - { - y = y1; - x = x1; - yend = y2; - xdirflag = 1; + /* 2.0.10: Nick Atty: clip to edges of drawing rectangle, return if no points need to be drawn */ + if (!clip_1d(&x1,&y1,&x2,&y2,gdImageSX(im)) || !clip_1d(&y1,&x1,&y2,&x2,gdImageSY(im))) { + return; } - - /* Set up line thickness */ - wstart = x - wid / 2; - for (w = wstart; w < wstart + wid; w++) - gdImageSetPixel (im, w, y, color); - - if (((x2 - x1) * xdirflag) > 0) - { - while (y < yend) - { - y++; - if (d < 0) - { - d += incr1; + + dx = abs(x2 - x1); + dy = abs(y2 - y1); + if (dy <= dx) { + /* More-or-less horizontal. use wid for vertical stroke */ + /* Doug Claar: watch out for NaN in atan2 (2.0.5) */ + if ((dx == 0) && (dy == 0)) { + wid = 1; + } else { + wid = (int)(thick * cos (atan2 (dy, dx))); + if (wid == 0) { + wid = 1; + } } - else - { - x++; - d += incr2; + d = 2 * dy - dx; + incr1 = 2 * dy; + incr2 = 2 * (dy - dx); + if (x1 > x2) { + x = x2; + y = y2; + ydirflag = (-1); + xend = x1; + } else { + x = x1; + y = y1; + ydirflag = 1; + xend = x2; + } + + /* Set up line thickness */ + wstart = y - wid / 2; + for (w = wstart; w < wstart + wid; w++) { + gdImageSetPixel(im, x, w, color); + } + + if (((y2 - y1) * ydirflag) > 0) { + while (x < xend) { + x++; + if (d < 0) { + d += incr1; + } else { + y++; + d += incr2; + } + wstart = y - wid / 2; + for (w = wstart; w < wstart + wid; w++) { + gdImageSetPixel (im, x, w, color); + } + } + } else { + while (x < xend) { + x++; + if (d < 0) { + d += incr1; + } else { + y--; + d += incr2; + } + wstart = y - wid / 2; + for (w = wstart; w < wstart + wid; w++) { + gdImageSetPixel (im, x, w, color); + } + } } - wstart = x - wid / 2; - for (w = wstart; w < wstart + wid; w++) - gdImageSetPixel (im, w, y, color); - } - } - else - { - while (y < yend) - { - y++; - if (d < 0) - { - d += incr1; + } else { + /* More-or-less vertical. use wid for horizontal stroke */ + wid = (int)(thick * sin (atan2 (dy, dx))); + if (wid == 0) { + wid = 1; } - else - { - x--; - d += incr2; + + d = 2 * dx - dy; + incr1 = 2 * dx; + incr2 = 2 * (dx - dy); + if (y1 > y2) { + y = y2; + x = x2; + yend = y1; + xdirflag = (-1); + } else { + y = y1; + x = x1; + yend = y2; + xdirflag = 1; + } + + /* Set up line thickness */ + wstart = x - wid / 2; + for (w = wstart; w < wstart + wid; w++) { + gdImageSetPixel (im, w, y, color); + } + + if (((x2 - x1) * xdirflag) > 0) { + while (y < yend) { + y++; + if (d < 0) { + d += incr1; + } else { + x++; + d += incr2; + } + wstart = x - wid / 2; + for (w = wstart; w < wstart + wid; w++) { + gdImageSetPixel (im, w, y, color); + } + } + } else { + while (y < yend) { + y++; + if (d < 0) { + d += incr1; + } else { + x--; + d += incr2; + } + wstart = x - wid / 2; + for (w = wstart; w < wstart + wid; w++) { + gdImageSetPixel (im, w, y, color); + } + } } - wstart = x - wid / 2; - for (w = wstart; w < wstart + wid; w++) - gdImageSetPixel (im, w, y, color); - } } - } } - #define BLEND_COLOR(a, nc, c, cc) \ nc = (cc) + (((((c) - (cc)) * (a)) + ((((c) - (cc)) * (a)) >> 8) + 0x80) >> 8); @@ -1317,13 +1371,6 @@ *onP = on; } -int -gdImageBoundsSafe (gdImagePtr im, int x, int y) -{ - return (!(((y < 0) || (y >= im->sy)) || - ((x < 0) || (x >= im->sx)))); -} - void gdImageChar (gdImagePtr im, gdFontPtr f, int x, int y, int c, int color) @@ -1831,154 +1878,127 @@ void gdImageFilledRectangle (gdImagePtr im, int x1, int y1, int x2, int y2, int color) { - int x, y; - for (y = y1; (y <= y2); y++) - { - for (x = x1; (x <= x2); x++) - { - gdImageSetPixel (im, x, y, color); + int x, y; + + /* Nick Atty: limit the points at the edge. Note that this also + * nicely kills any plotting for rectangles completely outside the + * window as it makes the tests in the for loops fail + */ + if (x1 < 0) { + x1 = 0; + } + if (x1 > gdImageSX(im)) { + x1 = gdImageSX(im); + } + if(y1 < 0) { + y1 = 0; + } + if (y1 > gdImageSY(im)) { + y1 = gdImageSY(im); + } + + for (y = y1; (y <= y2); y++) { + for (x = x1; (x <= x2); x++) { + gdImageSetPixel (im, x, y, color); + } } - } } void gdImageCopy (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int w, int h) { - int c; - int x, y; - int tox, toy; - int i; - int colorMap[gdMaxColors]; - if (dst->trueColor) - { - /* 2.0: much easier when the destination is truecolor. */ + int c; + int x, y; + int tox, toy; + int i; + int colorMap[gdMaxColors]; + if (dst->trueColor) { + /* 2.0: much easier when the destination is truecolor. */ + /* 2.0.10: needs a transparent-index check that is still valid if + * the source is not truecolor. Thanks to Frank Warmerdam. + */ - if (src->trueColor) { - for (y = 0; (y < h); y++) - { - for (x = 0; (x < w); x++) - { - int c = gdImageGetTrueColorPixel (src, srcX + x, - srcY + y); - gdImageSetPixel (dst, - dstX + x, - dstY + y, - c); + if (src->trueColor) { + for (y = 0; (y < h); y++) { + for (x = 0; (x < w); x++) { + int c = gdImageGetTrueColorPixel (src, srcX + x, srcY + y); + gdImageSetPixel (dst, dstX + x, dstY + y, c); } } - - } - else { + } else { /* source is palette based */ - for (y = 0; (y < h); y++) - { - for (x = 0; (x < w); x++) - { - int c = gdImageGetPixel (src, srcX + x, - srcY + y); - if (c != src->transparent) - { - gdImageSetPixel (dst, - dstX + x, - dstY + y, - gdTrueColor(src->red[c], src->green[c], src->blue[c])); + for (y = 0; (y < h); y++) { + for (x = 0; (x < w); x++) { + int c = gdImageGetPixel (src, srcX + x, srcY + y); + if (c != src->transparent) { + gdImageSetPixel (dst, dstX + x, dstY + y, gdTrueColor(src->red[c], src->green[c], src->blue[c])); } + } + } } - } + return; } - return; - } - /* Destination is palette based */ + /* Destination is palette based */ + if (src->trueColor) { /* But source is truecolor (Ouch!) */ + toy = dstY; + for (y = srcY; (y < (srcY + h)); y++) { + tox = dstX; + for (x = srcX; (x < (srcX + w)); x++) { + int nc; + c = gdImageGetPixel (src, x, y); - if (src->trueColor) { /* But source is truecolor (Ouch!) */ - toy = dstY; - for (y = srcY; (y < (srcY + h)); y++) - { - tox = dstX; - for (x = srcX; (x < (srcX + w)); x++) - { - int nc; - c = gdImageGetPixel (src, x, y); - - /* Get best match possible. */ - nc = gdImageColorResolveAlpha ( - dst, - gdTrueColorGetRed(c), - gdTrueColorGetGreen(c), - gdTrueColorGetBlue(c), - gdTrueColorGetAlpha(c)); - - gdImageSetPixel (dst, tox, toy, nc); - tox++; - } - toy++; - } - return; - } + /* Get best match possible. */ + nc = gdImageColorResolveAlpha (dst, gdTrueColorGetRed(c), gdTrueColorGetGreen(c), gdTrueColorGetBlue(c), gdTrueColorGetAlpha(c)); - /* Palette based to palette based */ + gdImageSetPixel (dst, tox, toy, nc); + tox++; + } + toy++; + } + return; + } - for (i = 0; (i < gdMaxColors); i++) - { - colorMap[i] = (-1); - } - toy = dstY; - for (y = srcY; (y < (srcY + h)); y++) - { - tox = dstX; - for (x = srcX; (x < (srcX + w)); x++) - { - int nc; - int mapTo; - c = gdImageGetPixel (src, x, y); - /* Added 7/24/95: support transparent copies */ - if (gdImageGetTransparent (src) == c) - { - tox++; - continue; - } - /* Have we established a mapping for this color? */ - if (src->trueColor) - { - /* 2.05: remap to the palette available in the - destination image. This is slow and - works badly, but it beats crashing! Thanks - to Padhrig McCarthy. */ - mapTo = gdImageColorResolveAlpha (dst, - gdTrueColorGetRed (c), - gdTrueColorGetGreen (c), - gdTrueColorGetBlue (c), - gdTrueColorGetAlpha (c)); - } - else if (colorMap[c] == (-1)) - { - /* If it's the same image, mapping is trivial */ - if (dst == src) - { - nc = c; + /* Palette based to palette based */ + for (i = 0; (i < gdMaxColors); i++) { + colorMap[i] = (-1); + } + toy = dstY; + for (y = srcY; (y < (srcY + h)); y++) { + tox = dstX; + for (x = srcX; (x < (srcX + w)); x++) { + int nc; + int mapTo; + c = gdImageGetPixel (src, x, y); + /* Added 7/24/95: support transparent copies */ + if (gdImageGetTransparent (src) == c) { + tox++; + continue; + } + /* Have we established a mapping for this color? */ + if (src->trueColor) { + /* 2.05: remap to the palette available in the destination image. This is slow and + * works badly, but it beats crashing! Thanks to Padhrig McCarthy. + */ + mapTo = gdImageColorResolveAlpha (dst, gdTrueColorGetRed (c), gdTrueColorGetGreen (c), gdTrueColorGetBlue (c), gdTrueColorGetAlpha (c)); + } else if (colorMap[c] == (-1)) { + /* If it's the same image, mapping is trivial */ + if (dst == src) { + nc = c; + } else { + /* Get best match possible. This function never returns error. */ + nc = gdImageColorResolveAlpha (dst, src->red[c], src->green[c], src->blue[c], src->alpha[c]); + } + colorMap[c] = nc; + mapTo = colorMap[c]; + } else { + mapTo = colorMap[c]; + } + gdImageSetPixel (dst, tox, toy, mapTo); + tox++; } - else - { - /* Get best match possible. This - function never returns error. */ - nc = gdImageColorResolveAlpha ( - dst, - src->red[c], src->green[c], - src->blue[c], src->alpha[c]); - } - colorMap[c] = nc; - mapTo = colorMap[c]; - } - else - { - mapTo = colorMap[c]; - } - gdImageSetPixel (dst, tox, toy, mapTo); - tox++; + toy++; } - toy++; - } } /* This function is a substitute for real alpha channel operations, @@ -2230,14 +2250,14 @@ sy = sy1; do { float yportion; - if (floorf(sy) == floorf(sy1)) { - yportion = 1.0f - (sy - floorf(sy)); + if (floor_cast(sy) == floor_cast(sy1)) { + yportion = 1.0f - (sy - floor_cast(sy)); if (yportion > sy2 - sy1) { yportion = sy2 - sy1; } - sy = floorf(sy); + sy = floor_cast(sy); } else if (sy == floorf(sy2)) { - yportion = sy2 - floorf(sy2); + yportion = sy2 - floor_cast(sy2); } else { yportion = 1.0f; } @@ -2248,14 +2268,14 @@ float xportion; float pcontribution; int p; - if (floorf(sx) == floorf(sx1)) { - xportion = 1.0f - (sx - floorf(sx)); + if (floorf(sx) == floor_cast(sx1)) { + xportion = 1.0f - (sx - floor_cast(sx)); if (xportion > sx2 - sx1) { xportion = sx2 - sx1; } - sx = floorf(sx); + sx = floor_cast(sx); } else if (sx == floorf(sx2)) { - xportion = sx2 - floorf(sx2); + xportion = sx2 - floor_cast(sx2); } else { xportion = 1.0f; } Index: php4/ext/gd/libgd/gd.h diff -u php4/ext/gd/libgd/gd.h:1.13 php4/ext/gd/libgd/gd.h:1.14 --- php4/ext/gd/libgd/gd.h:1.13 Sun Jan 5 19:47:40 2003 +++ php4/ext/gd/libgd/gd.h Fri Jan 17 13:34:07 2003 @@ -256,7 +256,6 @@ void gdImageRectangle(gdImagePtr im, int x1, int y1, int x2, int y2, int color); /* Solid bar. Upper left corner first, lower right corner second. */ void gdImageFilledRectangle(gdImagePtr im, int x1, int y1, int x2, int y2, int color); -int gdImageBoundsSafe(gdImagePtr im, int x, int y); void gdImageChar(gdImagePtr im, gdFontPtr f, int x, int y, int c, int color); void gdImageCharUp(gdImagePtr im, gdFontPtr f, int x, int y, int c, int color); void gdImageString(gdImagePtr im, gdFontPtr f, int x, int y, unsigned char *s, int color); @@ -585,5 +584,7 @@ #ifdef __cplusplus } #endif + +#define gdImageBoundsSafe(im, x, y) (!(y < 0 || y >= (im)->sy || x < 0 || x >= (im)->sx)) #endif /* GD_H */ Index: php4/ext/gd/libgd/gd_gd2.c diff -u php4/ext/gd/libgd/gd_gd2.c:1.9 php4/ext/gd/libgd/gd_gd2.c:1.10 --- php4/ext/gd/libgd/gd_gd2.c:1.9 Tue Dec 3 10:43:17 2002 +++ php4/ext/gd/libgd/gd_gd2.c Fri Jan 17 13:34:07 2003 @@ -23,902 +23,767 @@ #define TRUE 1 #define FALSE 0 +/* 2.11: not part of the API, as the save routine can figure it out + * from im->trueColor, and the load routine doesn't need to tell + * the end user the saved format. NOTE: adding 2 is assumed + * to result in the correct format value for truecolor! +*/ +#define GD2_FMT_TRUECOLOR_RAW 3 +#define GD2_FMT_TRUECOLOR_COMPRESSED 4 + +#define gd2_compressed(fmt) (((fmt) == GD2_FMT_COMPRESSED) || ((fmt) == GD2_FMT_TRUECOLOR_COMPRESSED)) +#define gd2_truecolor(fmt) (((fmt) == GD2_FMT_TRUECOLOR_RAW) || ((fmt) == GD2_FMT_TRUECOLOR_COMPRESSED)) + /* Use this for commenting out debug-print statements. */ /* Just use the first '#define' to allow all the prints... */ /* #define GD2_DBG(s) (s) */ #define GD2_DBG(s) typedef struct - { - int offset; - int size; - } +{ + int offset; + int size; +} t_chunk_info; -extern int _gdGetColors (gdIOCtx * in, gdImagePtr im, int gd2xFlag); -extern void _gdPutColors (gdImagePtr im, gdIOCtx * out); +extern int _gdGetColors(gdIOCtx * in, gdImagePtr im, int gd2xFlag); +extern void _gdPutColors(gdImagePtr im, gdIOCtx * out); /* */ /* Read the extra info in the gd2 header. */ /* */ -static -int -_gd2GetHeader (gdIOCtxPtr in, int *sx, int *sy, - int *cs, int *vers, int *fmt, int *ncx, int *ncy, t_chunk_info ** chunkIdx) -{ - int i; - int ch; - char id[5]; - t_chunk_info *cidx; - int sidx; - int nc; - - GD2_DBG(php_gd_error("Reading gd2 header info\n")); - - for (i = 0; i < 4; i++) - { - ch = gdGetC (in); - if (ch == EOF) - { - goto fail1; - }; - id[i] = ch; - }; - id[4] = 0; - - GD2_DBG(php_gd_error("Got file code: %s\n", id)); - - /* Equiv. of 'magick'. */ - if (strcmp (id, GD2_ID) != 0) - { - GD2_DBG(php_gd_error("Not a valid gd2 file\n")); - goto fail1; - }; - - /* Version */ - if (gdGetWord (vers, in) != 1) - { - goto fail1; - }; - GD2_DBG(php_gd_error("Version: %d\n", *vers)); - - if ((*vers != 1) && (*vers != 2)) - { - GD2_DBG(php_gd_error("Bad version: %d\n", *vers)); - goto fail1; - }; - - /* Image Size */ - if (!gdGetWord (sx, in)) - { - GD2_DBG(php_gd_error("Could not get x-size\n")); - goto fail1; - } - if (!gdGetWord (sy, in)) - { - GD2_DBG(php_gd_error("Could not get y-size\n")); - goto fail1; - } - GD2_DBG(php_gd_error("Image is %dx%d\n", *sx, *sy)); - - /* Chunk Size (pixels, not bytes!) */ - if (gdGetWord (cs, in) != 1) - { - goto fail1; - }; - GD2_DBG(php_gd_error("ChunkSize: %d\n", *cs)); - - if ((*cs < GD2_CHUNKSIZE_MIN) || (*cs > GD2_CHUNKSIZE_MAX)) - { - GD2_DBG(php_gd_error("Bad chunk size: %d\n", *cs)); - goto fail1; - }; - - /* Data Format */ - if (gdGetWord (fmt, in) != 1) - { - goto fail1; - }; - GD2_DBG(php_gd_error("Format: %d\n", *fmt)); - - if ((*fmt != GD2_FMT_RAW) && (*fmt != GD2_FMT_COMPRESSED)) - { - GD2_DBG(php_gd_error("Bad data format: %d\n", *fmt)); - goto fail1; - }; - - - /* # of chunks wide */ - if (gdGetWord (ncx, in) != 1) - { - goto fail1; - }; - GD2_DBG(php_gd_error("%d Chunks Wide\n", *ncx)); - - /* # of chunks high */ - if (gdGetWord (ncy, in) != 1) - { - goto fail1; - }; - GD2_DBG(php_gd_error("%d Chunks vertically\n", *ncy)); - - if ((*fmt) == GD2_FMT_COMPRESSED) - { - nc = (*ncx) * (*ncy); - GD2_DBG(php_gd_error("Reading %d chunk index entries\n", nc)); - sidx = sizeof (t_chunk_info) * nc; - cidx = gdCalloc (sidx, 1); - for (i = 0; i < nc; i++) - { - if (gdGetInt (&cidx[i].offset, in) != 1) - { - goto fail1; - }; - if (gdGetInt (&cidx[i].size, in) != 1) - { - goto fail1; - }; - }; - *chunkIdx = cidx; - }; +static int _gd2GetHeader(gdIOCtxPtr in, int *sx, int *sy, int *cs, int *vers, int *fmt, int *ncx, int *ncy, t_chunk_info ** chunkIdx) +{ + int i; + int ch; + char id[5]; + t_chunk_info *cidx; + int sidx; + int nc; + + GD2_DBG(php_gd_error("Reading gd2 header info\n")); + + for (i = 0; i < 4; i++) { + ch = gdGetC(in); + if (ch == EOF) { + goto fail1; + } + id[i] = ch; + } + id[4] = 0; + + GD2_DBG(php_gd_error("Got file code: %s\n", id)); + + /* Equiv. of 'magick'. */ + if (strcmp(id, GD2_ID) != 0) { + GD2_DBG(php_gd_error("Not a valid gd2 file\n")); + goto fail1; + } + + /* Version */ + if (gdGetWord(vers, in) != 1) { + goto fail1; + } + GD2_DBG(php_gd_error("Version: %d\n", *vers)); + + if ((*vers != 1) && (*vers != 2)) { + GD2_DBG(php_gd_error("Bad version: %d\n", *vers)); + goto fail1; + } + + /* Image Size */ + if (!gdGetWord(sx, in)) { + GD2_DBG(php_gd_error("Could not get x-size\n")); + goto fail1; + } + if (!gdGetWord(sy, in)) { + GD2_DBG(php_gd_error("Could not get y-size\n")); + goto fail1; + } + GD2_DBG(php_gd_error("Image is %dx%d\n", *sx, *sy)); + + /* Chunk Size (pixels, not bytes!) */ + if (gdGetWord(cs, in) != 1) { + goto fail1; + } + GD2_DBG(php_gd_error("ChunkSize: %d\n", *cs)); + + if ((*cs < GD2_CHUNKSIZE_MIN) || (*cs > GD2_CHUNKSIZE_MAX)) { + GD2_DBG(php_gd_error("Bad chunk size: %d\n", *cs)); + goto fail1; + } + + /* Data Format */ + if (gdGetWord(fmt, in) != 1) { + goto fail1; + } + GD2_DBG(php_gd_error("Format: %d\n", *fmt)); + + if ((*fmt != GD2_FMT_RAW) && (*fmt != GD2_FMT_COMPRESSED) && (*fmt != GD2_FMT_TRUECOLOR_RAW) && (*fmt != GD2_FMT_TRUECOLOR_COMPRESSED)) { + GD2_DBG(php_gd_error("Bad data format: %d\n", *fmt)); + goto fail1; + } + + /* # of chunks wide */ + if (gdGetWord(ncx, in) != 1) { + goto fail1; + } + GD2_DBG(php_gd_error("%d Chunks Wide\n", *ncx)); - GD2_DBG(php_gd_error("gd2 header complete\n")); + /* # of chunks high */ + if (gdGetWord(ncy, in) != 1) { + goto fail1; + } + GD2_DBG(php_gd_error("%d Chunks vertically\n", *ncy)); - return 1; + if (gd2_compressed(*fmt)) { + nc = (*ncx) * (*ncy); + GD2_DBG(php_gd_error("Reading %d chunk index entries\n", nc)); + sidx = sizeof(t_chunk_info) * nc; + cidx = gdCalloc(sidx, 1); + for (i = 0; i < nc; i++) { + if (gdGetInt(&cidx[i].offset, in) != 1) { + goto fail1; + } + if (gdGetInt(&cidx[i].size, in) != 1) { + goto fail1; + } + } + *chunkIdx = cidx; + } + + GD2_DBG(php_gd_error("gd2 header complete\n")); + + return 1; fail1: - return 0; + return 0; } -static - gdImagePtr -_gd2CreateFromFile (gdIOCtxPtr in, int *sx, int *sy, - int *cs, int *vers, int *fmt, - int *ncx, int *ncy, t_chunk_info ** cidx) -{ - gdImagePtr im; - - if (_gd2GetHeader (in, sx, sy, cs, vers, fmt, ncx, ncy, cidx) != 1) - { - GD2_DBG(php_gd_error("Bad GD2 header\n")); - goto fail1; - } - - im = gdImageCreateTrueColor(*sx, *sy); - if (im == NULL) - { - GD2_DBG(php_gd_error("Could not create gdImage\n")); - goto fail1; - }; - - if (!_gdGetColors (in, im, (*vers) == 2)) - { - GD2_DBG(php_gd_error("Could not read color palette\n")); - goto fail2; - } - GD2_DBG(php_gd_error("Image palette completed: %d colours\n", im->colorsTotal)); +static gdImagePtr _gd2CreateFromFile (gdIOCtxPtr in, int *sx, int *sy, int *cs, int *vers, int *fmt, int *ncx, int *ncy, t_chunk_info ** cidx) +{ + gdImagePtr im; + + if (_gd2GetHeader (in, sx, sy, cs, vers, fmt, ncx, ncy, cidx) != 1) { + GD2_DBG(php_gd_error("Bad GD2 header\n")); + goto fail1; + } - return im; + if (gd2_truecolor(*fmt)) { + im = gdImageCreateTrueColor(*sx, *sy); + } else { + im = gdImageCreate(*sx, *sy); + } + if (im == NULL) { + GD2_DBG(php_gd_error("Could not create gdImage\n")); + goto fail1; + } + + if (!_gdGetColors(in, im, (*vers) == 2)) { + GD2_DBG(php_gd_error("Could not read color palette\n")); + goto fail2; + } + GD2_DBG(php_gd_error("Image palette completed: %d colours\n", im->colorsTotal)); + + return im; fail2: - gdImageDestroy (im); - return 0; + gdImageDestroy(im); + return 0; fail1: - return 0; + return 0; +} + +static int _gd2ReadChunk (int offset, char *compBuf, int compSize, char *chunkBuf, uLongf * chunkLen, gdIOCtx * in) +{ + int zerr; + + if (gdTell(in) != offset) { + GD2_DBG(php_gd_error("Positioning in file to %d\n", offset)); + gdSeek(in, offset); + } else { + GD2_DBG(php_gd_error("Already Positioned in file to %d\n", offset)); + } + + /* Read and uncompress an entire chunk. */ + GD2_DBG(php_gd_error("Reading file\n")); + if (gdGetBuf(compBuf, compSize, in) != compSize) { + return FALSE; + } + GD2_DBG(php_gd_error("Got %d bytes. Uncompressing into buffer of %d bytes\n", compSize, (int)*chunkLen)); + zerr = uncompress((unsigned char *) chunkBuf, chunkLen, (unsigned char *) compBuf, compSize); + if (zerr != Z_OK) { + GD2_DBG(php_gd_error("Error %d from uncompress\n", zerr)); + return FALSE; + } + GD2_DBG(php_gd_error("Got chunk\n")); + + return TRUE; +} + +gdImagePtr gdImageCreateFromGd2 (FILE * inFile) +{ + gdIOCtx *in = gdNewFileCtx(inFile); + gdImagePtr im; + + im = gdImageCreateFromGd2Ctx(in); + in->gd_free(in); + + return im; } -static -int -_gd2ReadChunk (int offset, char *compBuf, int compSize, char *chunkBuf, uLongf * chunkLen, gdIOCtx * in) -{ - int zerr; - - if (gdTell (in) != offset) - { - GD2_DBG(php_gd_error("Positioning in file to %d\n", offset)); - gdSeek (in, offset); - } - else - { - GD2_DBG(php_gd_error("Already Positioned in file to %d\n", offset)); - }; - - /* Read and uncompress an entire chunk. */ - GD2_DBG(php_gd_error("Reading file\n")); - if (gdGetBuf (compBuf, compSize, in) != compSize) - { - return FALSE; - }; - GD2_DBG(php_gd_error("Got %d bytes. Uncompressing into buffer of %d bytes\n", compSize, (int)*chunkLen)); - zerr = uncompress ((unsigned char *) chunkBuf, chunkLen, - (unsigned char *) compBuf, compSize); - if (zerr != Z_OK) - { - GD2_DBG(php_gd_error("Error %d from uncompress\n", zerr)); - return FALSE; - }; - GD2_DBG(php_gd_error("Got chunk\n")); - return TRUE; -} - -gdImagePtr -gdImageCreateFromGd2 (FILE * inFile) -{ - gdIOCtx *in = gdNewFileCtx (inFile); - gdImagePtr im; - - im = gdImageCreateFromGd2Ctx (in); - - in->gd_free (in); - - return im; -} - -gdImagePtr -gdImageCreateFromGd2Ctx (gdIOCtxPtr in) -{ - int sx, sy; - int i; - int ncx, ncy, nc, cs, cx, cy; - int x, y, ylo, yhi, xlo, xhi; - int vers, fmt; - t_chunk_info *chunkIdx = NULL; /* So we can gdFree it with impunity. */ - unsigned char *chunkBuf = NULL; /* So we can gdFree it with impunity. */ - int chunkNum = 0; - int chunkMax = 0; - uLongf chunkLen; - int chunkPos = 0; - int compMax = 0; - int bytesPerPixel; - char *compBuf = NULL; /* So we can gdFree it with impunity. */ - - gdImagePtr im; - - /* Get the header */ - im = _gd2CreateFromFile (in, &sx, &sy, &cs, &vers, &fmt, &ncx, &ncy, &chunkIdx); - - if (im == NULL) - { - return 0; - }; - bytesPerPixel = im->trueColor ? 4 : 1; - nc = ncx * ncy; - - if (fmt == GD2_FMT_COMPRESSED) - { - /* Find the maximum compressed chunk size. */ - compMax = 0; - for (i = 0; (i < nc); i++) - { - if (chunkIdx[i].size > compMax) - { - compMax = chunkIdx[i].size; - }; - }; - compMax++; - - /* Allocate buffers */ - chunkMax = cs * bytesPerPixel * cs; - chunkBuf = gdCalloc (chunkMax, 1); - compBuf = gdCalloc (compMax, 1); - GD2_DBG(php_gd_error("Largest compressed chunk is %d bytes\n", compMax)); - }; - -/* if ( (ncx != sx / cs) || (ncy != sy / cs)) { */ -/* goto fail2; */ -/* }; */ - - /* Read the data... */ - for (cy = 0; (cy < ncy); cy++) - { - for (cx = 0; (cx < ncx); cx++) - { - - ylo = cy * cs; - yhi = ylo + cs; - if (yhi > im->sy) - { - yhi = im->sy; - }; - - GD2_DBG(php_gd_error("Processing Chunk %d (%d, %d), y from %d to %d\n", chunkNum, cx, cy, ylo, yhi)); - - if (fmt == GD2_FMT_COMPRESSED) - { - - chunkLen = chunkMax; - - if (!_gd2ReadChunk (chunkIdx[chunkNum].offset, - compBuf, - chunkIdx[chunkNum].size, - chunkBuf, &chunkLen, in)) - { - GD2_DBG(php_gd_error("Error reading comproessed chunk\n")); - goto fail2; - }; - - chunkPos = 0; - }; - - for (y = ylo; (y < yhi); y++) - { - - xlo = cx * cs; - xhi = xlo + cs; - if (xhi > im->sx) - { - xhi = im->sx; - }; - /*GD2_DBG(php_gd_error("y=%d: ",y)); */ - if (fmt == GD2_FMT_RAW) - { - for (x = xlo; x < xhi; x++) - { - - if (im->trueColor) - { - if (!gdGetInt (&im->tpixels[y][x], in)) - { - /*php_gd_error("EOF while reading\n"); */ - /*gdImageDestroy(im); */ - /*return 0; */ - im->tpixels[y][x] = 0; - } - } - else - { - int ch; - if (!gdGetByte (&ch, in)) - { - /*php_gd_error("EOF while reading\n"); */ - /*gdImageDestroy(im); */ - /*return 0; */ - ch = 0; - } - im->pixels[y][x] = ch; +gdImagePtr gdImageCreateFromGd2Ctx (gdIOCtxPtr in) +{ + int sx, sy; + int i; + int ncx, ncy, nc, cs, cx, cy; + int x, y, ylo, yhi, xlo, xhi; + int vers, fmt; + t_chunk_info *chunkIdx = NULL; /* So we can gdFree it with impunity. */ + unsigned char *chunkBuf = NULL; /* So we can gdFree it with impunity. */ + int chunkNum = 0; + int chunkMax = 0; + uLongf chunkLen; + int chunkPos = 0; + int compMax = 0; + int bytesPerPixel; + char *compBuf = NULL; /* So we can gdFree it with impunity. */ + + gdImagePtr im; + + /* Get the header */ + if (!(im = _gd2CreateFromFile(in, &sx, &sy, &cs, &vers, &fmt, &ncx, &ncy, &chunkIdx))) { + return 0; + } + + bytesPerPixel = im->trueColor ? 4 : 1; + nc = ncx * ncy; + + if (gd2_compressed(fmt)) { + /* Find the maximum compressed chunk size. */ + compMax = 0; + for (i = 0; (i < nc); i++) { + if (chunkIdx[i].size > compMax) { + compMax = chunkIdx[i].size; + } + } + compMax++; + + /* Allocate buffers */ + chunkMax = cs * bytesPerPixel * cs; + chunkBuf = gdCalloc(chunkMax, 1); + compBuf = gdCalloc(compMax, 1); + + GD2_DBG(php_gd_error("Largest compressed chunk is %d bytes\n", compMax)); + } + + /* Read the data... */ + for (cy = 0; (cy < ncy); cy++) { + for (cx = 0; (cx < ncx); cx++) { + ylo = cy * cs; + yhi = ylo + cs; + if (yhi > im->sy) { + yhi = im->sy; + } + + GD2_DBG(php_gd_error("Processing Chunk %d (%d, %d), y from %d to %d\n", chunkNum, cx, cy, ylo, yhi)); + + if (gd2_compressed(fmt)) { + chunkLen = chunkMax; + + if (!_gd2ReadChunk(chunkIdx[chunkNum].offset, compBuf, chunkIdx[chunkNum].size, chunkBuf, &chunkLen, in)) { + GD2_DBG(php_gd_error("Error reading comproessed chunk\n")); + goto fail2; + } + + chunkPos = 0; + } + + for (y = ylo; (y < yhi); y++) { + xlo = cx * cs; + xhi = xlo + cs; + if (xhi > im->sx) { + xhi = im->sx; + } + + if (!gd2_compressed(fmt)) { + for (x = xlo; x < xhi; x++) { + if (im->trueColor) { + if (!gdGetInt(&im->tpixels[y][x], in)) { + im->tpixels[y][x] = 0; + } + } else { + int ch; + if (!gdGetByte(&ch, in)) { + ch = 0; + } + im->pixels[y][x] = ch; + } + } + } else { + for (x = xlo; x < xhi; x++) { + if (im->trueColor) { + /* 2.0.1: work around a gcc bug by being verbose. TBB */ + int a = chunkBuf[chunkPos++] << 24; + int r = chunkBuf[chunkPos++] << 16; + int g = chunkBuf[chunkPos++] << 8; + int b = chunkBuf[chunkPos++]; + im->tpixels[y][x] = a + r + g + b; + } else { + im->pixels[y][x] = chunkBuf[chunkPos++]; + } + } + } } - } + chunkNum++; } - else - { - for (x = xlo; x < xhi; x++) - { - if (im->trueColor) - { - /* 2.0.1: work around a gcc bug by being verbose. - TBB */ - int a = chunkBuf[chunkPos++] << 24; - int r = chunkBuf[chunkPos++] << 16; - int g = chunkBuf[chunkPos++] << 8; - int b = chunkBuf[chunkPos++]; - im->tpixels[y][x] = a + r + g + b; - } - else - { - im->pixels[y][x] = chunkBuf[chunkPos++]; - } - }; - }; - /*GD2_DBG(php_gd_error("\n")); */ - }; - chunkNum++; - }; - }; - - GD2_DBG(php_gd_error("Freeing memory\n")); - - gdFree (chunkBuf); - gdFree (compBuf); - gdFree (chunkIdx); + } - GD2_DBG(php_gd_error("Done\n")); + GD2_DBG(php_gd_error("Freeing memory\n")); - return im; + if (chunkBuf) { + gdFree(chunkBuf); + } + if (compBuf) { + gdFree(compBuf); + } + if (chunkIdx) { + gdFree(chunkIdx); + } + + GD2_DBG(php_gd_error("Done\n")); + + return im; fail2: - gdImageDestroy (im); - gdFree (chunkBuf); - gdFree (compBuf); - gdFree (chunkIdx); - return 0; - -} - -gdImagePtr -gdImageCreateFromGd2Part (FILE * inFile, int srcx, int srcy, int w, int h) -{ - gdImagePtr im; - gdIOCtx *in = gdNewFileCtx (inFile); - - im = gdImageCreateFromGd2PartCtx (in, srcx, srcy, w, h); - - in->gd_free (in); - - return im; -} - -gdImagePtr -gdImageCreateFromGd2PartCtx (gdIOCtx * in, int srcx, int srcy, int w, int h) -{ - int scx, scy, ecx, ecy, fsx, fsy; - int nc, ncx, ncy, cs, cx, cy; - int x, y, ylo, yhi, xlo, xhi; - int dstart, dpos; - int i; - int ch, vers, fmt; - t_chunk_info *chunkIdx = NULL; - char *chunkBuf = NULL; - int chunkNum; - int chunkMax = 0; - uLongf chunkLen; - int chunkPos = 0; - int compMax; - char *compBuf = NULL; - - gdImagePtr im; - - /* */ - /* The next few lines are basically copied from gd2CreateFromFile */ - /* - we change the file size, so don't want to use the code directly. */ - /* but we do need to know the file size. */ - /* */ - if (_gd2GetHeader (in, &fsx, &fsy, &cs, &vers, &fmt, &ncx, &ncy, &chunkIdx) != 1) - { - goto fail1; - } - - GD2_DBG(php_gd_error("File size is %dx%d\n", fsx, fsy)); - - /* This is the difference - make a file based on size of chunks. */ - im = gdImageCreate (w, h); - if (im == NULL) - { - goto fail1; - }; - - if (!_gdGetColors (in, im, vers == 2)) - { - goto fail2; - } - GD2_DBG(php_gd_error("Image palette completed: %d colours\n", im->colorsTotal)); - - /* Process the header info */ - nc = ncx * ncy; - - if (fmt == GD2_FMT_COMPRESSED) - { - /* Find the maximum compressed chunk size. */ - compMax = 0; - for (i = 0; (i < nc); i++) - { - if (chunkIdx[i].size > compMax) - { - compMax = chunkIdx[i].size; - }; - }; - compMax++; - - if (im->trueColor) - { - chunkMax = cs * cs * 4; - } - else - { - chunkMax = cs * cs; - } - chunkBuf = gdCalloc (chunkMax, 1); - compBuf = gdCalloc (compMax, 1); - }; - -/* Don't bother with this... */ -/* if ( (ncx != sx / cs) || (ncy != sy / cs)) { */ -/* goto fail2; */ -/* }; */ - - - /* Work out start/end chunks */ - scx = srcx / cs; - scy = srcy / cs; - if (scx < 0) - { - scx = 0; - }; - if (scy < 0) - { - scy = 0; - }; - - ecx = (srcx + w) / cs; - ecy = (srcy + h) / cs; - if (ecx >= ncx) - { - ecx = ncx - 1; - }; - if (ecy >= ncy) - { - ecy = ncy - 1; - }; - - /* Remember file position of image data. */ - dstart = gdTell (in); - GD2_DBG(php_gd_error("Data starts at %d\n", dstart)); - - /* Loop through the chunks. */ - for (cy = scy; (cy <= ecy); cy++) - { - - ylo = cy * cs; - yhi = ylo + cs; - if (yhi > fsy) - { - yhi = fsy; - }; - - for (cx = scx; (cx <= ecx); cx++) - { - - xlo = cx * cs; - xhi = xlo + cs; - if (xhi > fsx) - { - xhi = fsx; - }; - - GD2_DBG(php_gd_error("Processing Chunk (%d, %d), from %d to %d\n", cx, cy, ylo, yhi)); - - if (fmt == GD2_FMT_RAW) - { - GD2_DBG(php_gd_error("Using raw format data\n")); - if (im->trueColor) - { - dpos = (cy * (cs * fsx) + cx * cs * (yhi - ylo) * 4) + dstart; + gdImageDestroy(im); + if (chunkBuf) { + gdFree(chunkBuf); + } + if (compBuf) { + gdFree(compBuf); + } + if (chunkIdx) { + gdFree(chunkIdx); + } + + return 0; +} + +gdImagePtr gdImageCreateFromGd2Part (FILE * inFile, int srcx, int srcy, int w, int h) +{ + gdImagePtr im; + gdIOCtx *in = gdNewFileCtx(inFile); + + im = gdImageCreateFromGd2PartCtx(in, srcx, srcy, w, h); + + in->gd_free(in); + + return im; +} + +gdImagePtr gdImageCreateFromGd2PartCtx (gdIOCtx * in, int srcx, int srcy, int w, int h) +{ + int scx, scy, ecx, ecy, fsx, fsy; + int nc, ncx, ncy, cs, cx, cy; + int x, y, ylo, yhi, xlo, xhi; + int dstart, dpos; + int i; + int ch, vers, fmt; + t_chunk_info *chunkIdx = NULL; + char *chunkBuf = NULL; + int chunkNum; + int chunkMax = 0; + uLongf chunkLen; + int chunkPos = 0; + int compMax; + char *compBuf = NULL; + + gdImagePtr im; + + /* The next few lines are basically copied from gd2CreateFromFile + * we change the file size, so don't want to use the code directly. + * but we do need to know the file size. + */ + if (_gd2GetHeader(in, &fsx, &fsy, &cs, &vers, &fmt, &ncx, &ncy, &chunkIdx) != 1) { + goto fail1; + } + + GD2_DBG(php_gd_error("File size is %dx%d\n", fsx, fsy)); + + /* This is the difference - make a file based on size of chunks. */ + if (gd2_truecolor(fmt)) { + im = gdImageCreateTrueColor(w, h); + } else { + im = gdImageCreate(w, h); + } + if (im == NULL) { + goto fail1; + } + + if (!_gdGetColors(in, im, vers == 2)) { + goto fail2; + } + GD2_DBG(php_gd_error("Image palette completed: %d colours\n", im->colorsTotal)); + + /* Process the header info */ + nc = ncx * ncy; + + if (gd2_compressed(fmt)) { + /* Find the maximum compressed chunk size. */ + compMax = 0; + for (i = 0; (i < nc); i++) { + if (chunkIdx[i].size > compMax) { + compMax = chunkIdx[i].size; + } + } + compMax++; + + if (im->trueColor) { + chunkMax = cs * cs * 4; + } else { + chunkMax = cs * cs; } - else - { - dpos = cy * (cs * fsx) + cx * cs * (yhi - ylo) + dstart; + chunkBuf = gdCalloc(chunkMax, 1); + compBuf = gdCalloc(compMax, 1); + } + + /* Work out start/end chunks */ + scx = srcx / cs; + scy = srcy / cs; + if (scx < 0) { + scx = 0; + } + if (scy < 0) { + scy = 0; + } + + ecx = (srcx + w) / cs; + ecy = (srcy + h) / cs; + if (ecx >= ncx) { + ecx = ncx - 1; + } + if (ecy >= ncy) { + ecy = ncy - 1; + } + + /* Remember file position of image data. */ + dstart = gdTell(in); + GD2_DBG(php_gd_error("Data starts at %d\n", dstart)); + + /* Loop through the chunks. */ + for (cy = scy; (cy <= ecy); cy++) { + ylo = cy * cs; + yhi = ylo + cs; + if (yhi > fsy) { + yhi = fsy; } - if (gdSeek (in, dpos) != 0) - { - php_gd_error_ex(E_WARNING, "Error from seek: %d\n", errno); - goto fail2; - }; - GD2_DBG(php_gd_error("Reading (%d, %d) from position %d\n", cx, cy, dpos - dstart)); - } - else - { - chunkNum = cx + cy * ncx; - - chunkLen = chunkMax; - if (!_gd2ReadChunk (chunkIdx[chunkNum].offset, - compBuf, - chunkIdx[chunkNum].size, - chunkBuf, &chunkLen, in)) - { - php_gd_error("Error reading comproessed chunk\n"); - goto fail2; - }; - chunkPos = 0; - GD2_DBG(php_gd_error("Reading (%d, %d) from chunk %d\n", cx, cy, chunkNum)); - }; - - GD2_DBG(php_gd_error(" into (%d, %d) - (%d, %d)\n", xlo, ylo, xhi, yhi)); - for (y = ylo; (y < yhi); y++) - { - - for (x = xlo; x < xhi; x++) - { - if (fmt == GD2_FMT_RAW) - { - if (im->trueColor) - { - if (!gdGetInt (&ch, in)) - { - ch = 0; - /*php_gd_error("EOF while reading file\n"); */ - /*goto fail2; */ - } - } - else - { - ch = gdGetC (in); - if (ch == EOF) - { - ch = 0; - /*php_gd_error("EOF while reading file\n"); */ - /*goto fail2; */ - } - } - } - else - { - if (im->trueColor) - { - ch = chunkBuf[chunkPos++]; - ch = (ch << 8) + chunkBuf[chunkPos++]; - ch = (ch << 8) + chunkBuf[chunkPos++]; - ch = (ch << 8) + chunkBuf[chunkPos++]; - } - else - { - ch = chunkBuf[chunkPos++]; - } - }; - - /* Only use a point that is in the image. */ - if ((x >= srcx) && (x < (srcx + w)) && (x < fsx) && (x >= 0) - && (y >= srcy) && (y < (srcy + h)) && (y < fsy) && (y >= 0) - ) - { - im->pixels[y - srcy][x - srcx] = ch; - } - }; - }; - }; - }; - - gdFree (chunkBuf); - gdFree (compBuf); - gdFree (chunkIdx); + for (cx = scx; cx <= ecx; cx++) { - return im; + xlo = cx * cs; + xhi = xlo + cs; + if (xhi > fsx) { + xhi = fsx; + } + + GD2_DBG(php_gd_error("Processing Chunk (%d, %d), from %d to %d\n", cx, cy, ylo, yhi)); + + if (!gd2_compressed(fmt)) { + GD2_DBG(php_gd_error("Using raw format data\n")); + if (im->trueColor) { + dpos = (cy * (cs * fsx) * 4 + cx * cs * (yhi - ylo) * 4) + dstart; + } else { + dpos = cy * (cs * fsx) + cx * cs * (yhi - ylo) + dstart; + } + + /* gd 2.0.11: gdSeek returns TRUE on success, not 0. Longstanding bug. 01/16/03 */ + if (!gdSeek(in, dpos)) { + php_gd_error_ex(E_WARNING, "Error from seek: %d\n", errno); + goto fail2; + } + GD2_DBG(php_gd_error("Reading (%d, %d) from position %d\n", cx, cy, dpos - dstart)); + } else { + chunkNum = cx + cy * ncx; + + chunkLen = chunkMax; + if (!_gd2ReadChunk (chunkIdx[chunkNum].offset, compBuf, chunkIdx[chunkNum].size, chunkBuf, &chunkLen, in)) { + php_gd_error("Error reading comproessed chunk\n"); + goto fail2; + } + chunkPos = 0; + GD2_DBG(php_gd_error("Reading (%d, %d) from chunk %d\n", cx, cy, chunkNum)); + } + + GD2_DBG(php_gd_error(" into (%d, %d) - (%d, %d)\n", xlo, ylo, xhi, yhi)); + + for (y = ylo; (y < yhi); y++) { + for (x = xlo; x < xhi; x++) { + if (!gd2_compressed(fmt)) { + if (im->trueColor) { + if (!gdGetInt(&ch, in)) { + ch = 0; + } + } else { + ch = gdGetC(in); + if (ch == EOF) { + ch = 0; + } + } + } else { + if (im->trueColor) { + ch = chunkBuf[chunkPos++]; + ch = (ch << 8) + chunkBuf[chunkPos++]; + ch = (ch << 8) + chunkBuf[chunkPos++]; + ch = (ch << 8) + chunkBuf[chunkPos++]; + } else { + ch = chunkBuf[chunkPos++]; + } + } + + /* Only use a point that is in the image. */ + if ((x >= srcx) && (x < (srcx + w)) && (x < fsx) && (x >= 0) && (y >= srcy) && (y < (srcy + h)) && (y < fsy) && (y >= 0)) { + if (im->trueColor) { + im->tpixels[y - srcy][x - srcx] = ch; + } else { + im->pixels[y - srcy][x - srcx] = ch; + } + } + } + } + } + } + + if (chunkBuf) { + gdFree(chunkBuf); + } + if (compBuf) { + gdFree(compBuf); + } + if (chunkIdx) { + gdFree(chunkIdx); + } + + return im; fail2: - gdImageDestroy (im); + gdImageDestroy(im); fail1: - gdFree (chunkBuf); - gdFree (compBuf); - gdFree (chunkIdx); - - return 0; - -} - -static -void -_gd2PutHeader (gdImagePtr im, gdIOCtx * out, int cs, int fmt, int cx, int cy) -{ - int i; - - /* Send the gd2 id, to verify file format. */ - for (i = 0; i < 4; i++) - { - gdPutC ((unsigned char) (GD2_ID[i]), out); - }; - - /* */ - /* We put the version info first, so future versions can easily change header info. */ - /* */ - gdPutWord (GD2_VERS, out); - gdPutWord (im->sx, out); - gdPutWord (im->sy, out); - gdPutWord (cs, out); - gdPutWord (fmt, out); - gdPutWord (cx, out); - gdPutWord (cy, out); - -} - -static void -_gdImageGd2 (gdImagePtr im, gdIOCtx * out, int cs, int fmt) -{ - int ncx, ncy, cx, cy; - int x, y, ylo, yhi, xlo, xhi; - int chunkLen; - int chunkNum = 0; - char *chunkData = NULL; /* So we can gdFree it with impunity. */ - char *compData = NULL; /* So we can gdFree it with impunity. */ - uLongf compLen; - int idxPos = 0; - int idxSize; - t_chunk_info *chunkIdx = NULL; - int posSave; - int bytesPerPixel = im->trueColor ? 4 : 1; - int compMax = 0; - - /*php_gd_error("Trying to write GD2 file\n"); */ - - /* */ - /* Force fmt to a valid value since we don't return anything. */ - /* */ - if ((fmt == 0) || ((fmt != GD2_FMT_RAW) && (fmt != GD2_FMT_COMPRESSED))) - { - fmt = GD2_FMT_COMPRESSED; - }; - - /* */ - /* Make sure chunk size is valid. These are arbitrary values; 64 because it seems */ - /* a little silly to expect performance improvements on a 64x64 bit scale, and */ - /* 4096 because we buffer one chunk, and a 16MB buffer seems a little largei - it may be */ - /* OK for one user, but for another to read it, they require the buffer. */ - /* */ - if (cs == 0) - { - cs = GD2_CHUNKSIZE; - } - else if (cs < GD2_CHUNKSIZE_MIN) - { - cs = GD2_CHUNKSIZE_MIN; - } - else if (cs > GD2_CHUNKSIZE_MAX) - { - cs = GD2_CHUNKSIZE_MAX; - }; - - /* Work out number of chunks. */ - ncx = im->sx / cs + 1; - ncy = im->sy / cs + 1; - - /* Write the standard header. */ - _gd2PutHeader (im, out, cs, fmt, ncx, ncy); - - if (fmt == GD2_FMT_COMPRESSED) - { - /* */ - /* Work out size of buffer for compressed data, If CHUNKSIZE is large, */ - /* then these will be large! */ - /* */ - /* The zlib notes say output buffer size should be (input size) * 1.01 * 12 */ - /* - we'll use 1.02 to be paranoid. */ - /* */ - compMax = (int)(cs * bytesPerPixel * cs * 1.02f) + 12; - - /* */ - /* Allocate the buffers. */ - /* */ - chunkData = gdCalloc (cs * bytesPerPixel * cs, 1); - compData = gdCalloc (compMax, 1); - - /* */ - /* Save the file position of chunk index, and allocate enough space for */ - /* each chunk_info block . */ - /* */ - idxPos = gdTell (out); - idxSize = ncx * ncy * sizeof (t_chunk_info); - GD2_DBG(php_gd_error("Index size is %d\n", idxSize)); - gdSeek (out, idxPos + idxSize); - - chunkIdx = gdCalloc (idxSize * sizeof (t_chunk_info), 1); - }; - - _gdPutColors (im, out); - - GD2_DBG(php_gd_error("Size: %dx%d\n", im->sx, im->sy)); - GD2_DBG(php_gd_error("Chunks: %dx%d\n", ncx, ncy)); - - for (cy = 0; (cy < ncy); cy++) - { - for (cx = 0; (cx < ncx); cx++) - { - - ylo = cy * cs; - yhi = ylo + cs; - if (yhi > im->sy) - { - yhi = im->sy; - }; - - GD2_DBG(php_gd_error("Processing Chunk (%dx%d), y from %d to %d\n", cx, cy, ylo, yhi)); - chunkLen = 0; - for (y = ylo; (y < yhi); y++) - { - - GD2_DBG(php_gd_error("y=%d: ",y)); - - xlo = cx * cs; - xhi = xlo + cs; - if (xhi > im->sx) - { - xhi = im->sx; - }; - - if (fmt == GD2_FMT_COMPRESSED) - { - for (x = xlo; x < xhi; x++) - { - GD2_DBG(php_gd_error("%d...",x)); - if (im->trueColor) - { - int p = im->tpixels[y][x]; - chunkData[chunkLen++] = gdTrueColorGetAlpha (p); - chunkData[chunkLen++] = gdTrueColorGetRed (p); - chunkData[chunkLen++] = gdTrueColorGetGreen (p); - chunkData[chunkLen++] = gdTrueColorGetBlue (p); - } - else - { - chunkData[chunkLen++] = im->pixels[y][x]; + if (chunkBuf) { + gdFree(chunkBuf); + } + if (compBuf) { + gdFree(compBuf); + } + if (chunkIdx) { + gdFree(chunkIdx); + } + + return 0; +} + +static void _gd2PutHeader (gdImagePtr im, gdIOCtx * out, int cs, int fmt, int cx, int cy) +{ + int i; + + /* Send the gd2 id, to verify file format. */ + for (i = 0; i < 4; i++) { + gdPutC((unsigned char) (GD2_ID[i]), out); + } + + /* We put the version info first, so future versions can easily change header info. */ + + gdPutWord(GD2_VERS, out); + gdPutWord(im->sx, out); + gdPutWord(im->sy, out); + gdPutWord(cs, out); + gdPutWord(fmt, out); + gdPutWord(cx, out); + gdPutWord(cy, out); +} + +static void _gdImageGd2 (gdImagePtr im, gdIOCtx * out, int cs, int fmt) +{ + int ncx, ncy, cx, cy; + int x, y, ylo, yhi, xlo, xhi; + int chunkLen; + int chunkNum = 0; + char *chunkData = NULL; /* So we can gdFree it with impunity. */ + char *compData = NULL; /* So we can gdFree it with impunity. */ + uLongf compLen; + int idxPos = 0; + int idxSize; + t_chunk_info *chunkIdx = NULL; /* So we can gdFree it with impunity. */ + int posSave; + int bytesPerPixel = im->trueColor ? 4 : 1; + int compMax = 0; + + /* Force fmt to a valid value since we don't return anything. */ + if ((fmt != GD2_FMT_RAW) && (fmt != GD2_FMT_COMPRESSED)) { + fmt = im->trueColor ? GD2_FMT_TRUECOLOR_COMPRESSED : GD2_FMT_COMPRESSED; + } + if (im->trueColor) { + fmt += 2; + } + /* Make sure chunk size is valid. These are arbitrary values; 64 because it seems + * a little silly to expect performance improvements on a 64x64 bit scale, and + * 4096 because we buffer one chunk, and a 16MB buffer seems a little large - it may be + * OK for one user, but for another to read it, they require the buffer. + */ + if (cs == 0) { + cs = GD2_CHUNKSIZE; + } else if (cs < GD2_CHUNKSIZE_MIN) { + cs = GD2_CHUNKSIZE_MIN; + } else if (cs > GD2_CHUNKSIZE_MAX) { + cs = GD2_CHUNKSIZE_MAX; + } + + /* Work out number of chunks. */ + ncx = im->sx / cs + 1; + ncy = im->sy / cs + 1; + + /* Write the standard header. */ + _gd2PutHeader (im, out, cs, fmt, ncx, ncy); + + if (gd2_compressed(fmt)) { + /* Work out size of buffer for compressed data, If CHUNKSIZE is large, + * then these will be large! + */ + + /* The zlib notes say output buffer size should be (input size) * 1.01 * 12 + * - we'll use 1.02 to be paranoid. + */ + compMax = (int)(cs * bytesPerPixel * cs * 1.02f) + 12; + + /* Allocate the buffers. */ + chunkData = gdCalloc(cs * bytesPerPixel * cs, 1); + compData = gdCalloc(compMax, 1); + + /* Save the file position of chunk index, and allocate enough space for + * each chunk_info block . + */ + idxPos = gdTell(out); + idxSize = ncx * ncy * sizeof(t_chunk_info); + GD2_DBG(php_gd_error("Index size is %d\n", idxSize)); + gdSeek(out, idxPos + idxSize); + + chunkIdx = gdCalloc(idxSize * sizeof(t_chunk_info), 1); + } + + _gdPutColors (im, out); + + GD2_DBG(php_gd_error("Size: %dx%d\n", im->sx, im->sy)); + GD2_DBG(php_gd_error("Chunks: %dx%d\n", ncx, ncy)); + + for (cy = 0; (cy < ncy); cy++) { + for (cx = 0; (cx < ncx); cx++) { + ylo = cy * cs; + yhi = ylo + cs; + if (yhi > im->sy) { + yhi = im->sy; + } + + GD2_DBG(php_gd_error("Processing Chunk (%dx%d), y from %d to %d\n", cx, cy, ylo, yhi)); + chunkLen = 0; + for (y = ylo; (y < yhi); y++) { + GD2_DBG(php_gd_error("y=%d: ",y)); + xlo = cx * cs; + xhi = xlo + cs; + if (xhi > im->sx) { + xhi = im->sx; + } + + if (gd2_compressed(fmt)) { + for (x = xlo; x < xhi; x++) { + GD2_DBG(php_gd_error("%d...",x)); + if (im->trueColor) { + int p = im->tpixels[y][x]; + chunkData[chunkLen++] = gdTrueColorGetAlpha(p); + chunkData[chunkLen++] = gdTrueColorGetRed(p); + chunkData[chunkLen++] = gdTrueColorGetGreen(p); + chunkData[chunkLen++] = gdTrueColorGetBlue(p); + } else { + chunkData[chunkLen++] = im->pixels[y][x]; + } + } + } else { + for (x = xlo; x < xhi; x++) { + GD2_DBG(php_gd_error("%d, ",x)); + + if (im->trueColor) { + gdPutInt(im->tpixels[y][x], out); + } else { + gdPutC((unsigned char) im->pixels[y][x], out); + } + } + } + GD2_DBG(php_gd_error("y=%d done.\n",y)); + } + + if (gd2_compressed(fmt)) { + compLen = compMax; + if (compress((unsigned char *) &compData[0], &compLen, (unsigned char *) &chunkData[0], chunkLen) != Z_OK) { + php_gd_error("Error from compressing\n"); + } else { + chunkIdx[chunkNum].offset = gdTell(out); + chunkIdx[chunkNum++].size = compLen; + GD2_DBG(php_gd_error("Chunk %d size %d offset %d\n", chunkNum, chunkIdx[chunkNum - 1].size, chunkIdx[chunkNum - 1].offset)); + + if (gdPutBuf (compData, compLen, out) <= 0) { + /* Any alternate suggestions for handling this? */ + php_gd_error_ex(E_WARNING, "Error %d on write\n", errno); + } + } } - }; } - else - { - for (x = xlo; x < xhi; x++) - { - GD2_DBG(php_gd_error("%d, ",x)); - - if (im->trueColor) - { - gdPutInt (im->tpixels[y][x], out); - } - else - { - gdPutC ((unsigned char) im->pixels[y][x], out); - } - }; - }; - GD2_DBG(php_gd_error("y=%d done.\n",y)); - }; - if (fmt == GD2_FMT_COMPRESSED) - { - compLen = compMax; - if (compress ((unsigned char *) - &compData[0], &compLen, - (unsigned char *) &chunkData[0], - chunkLen) != Z_OK) - { - php_gd_error ("Error from compressing\n"); + } + + if (gd2_compressed(fmt)) { + /* Save the position, write the index, restore position (paranoia). */ + GD2_DBG(php_gd_error("Seeking %d to write index\n", idxPos)); + posSave = gdTell(out); + gdSeek(out, idxPos); + GD2_DBG(php_gd_error("Writing index\n")); + for (x = 0; x < chunkNum; x++) { + GD2_DBG(php_gd_error("Chunk %d size %d offset %d\n", x, chunkIdx[x].size, chunkIdx[x].offset)); + gdPutInt(chunkIdx[x].offset, out); + gdPutInt(chunkIdx[x].size, out); } - else - { - chunkIdx[chunkNum].offset = gdTell (out); - chunkIdx[chunkNum++].size = compLen; - GD2_DBG(php_gd_error("Chunk %d size %d offset %d\n", chunkNum, chunkIdx[chunkNum - 1].size, chunkIdx[chunkNum - 1].offset)); - - if (gdPutBuf (compData, compLen, out) <= 0) - { - /* Any alternate suggestions for handling this? */ - php_gd_error_ex (E_WARNING, "Error %d on write\n", errno); - }; - }; - }; - }; - }; - if (fmt == GD2_FMT_COMPRESSED) - { - /* Save the position, write the index, restore position (paranoia). */ - GD2_DBG(php_gd_error("Seeking %d to write index\n", idxPos)); - posSave = gdTell (out); - gdSeek (out, idxPos); - GD2_DBG(php_gd_error("Writing index\n")); - for (x = 0; x < chunkNum; x++) - { - GD2_DBG(php_gd_error("Chunk %d size %d offset %d\n", x, chunkIdx[x].size, chunkIdx[x].offset)); - gdPutInt (chunkIdx[x].offset, out); - gdPutInt (chunkIdx[x].size, out); - }; - /* We don't use fwrite for *endian reasons. */ - /*fwrite(chunkIdx, sizeof(int)*2, chunkNum, out); */ - gdSeek (out, posSave); - }; - - GD2_DBG(php_gd_error("Freeing memory\n")); - gdFree (chunkData); - gdFree (compData); - gdFree (chunkIdx); - GD2_DBG(php_gd_error("Done\n")); - - /*php_gd_error("Memory block size is %d\n",gdTell(out)); */ + gdSeek(out, posSave); + } + GD2_DBG(php_gd_error("Freeing memory\n")); + if (chunkData) { + gdFree(chunkData); + } + if (compData) { + gdFree(compData); + } + if (chunkIdx) { + gdFree(chunkIdx); + } + GD2_DBG(php_gd_error("Done\n")); } -void -gdImageGd2 (gdImagePtr im, FILE * outFile, int cs, int fmt) -{ - gdIOCtx *out = gdNewFileCtx (outFile); - _gdImageGd2 (im, out, cs, fmt); - out->gd_free (out); -} - -void * -gdImageGd2Ptr (gdImagePtr im, int cs, int fmt, int *size) -{ - void *rv; - gdIOCtx *out = gdNewDynamicCtx (2048, NULL); - _gdImageGd2 (im, out, cs, fmt); - rv = gdDPExtractData (out, size); - out->gd_free (out); - return rv; +void gdImageGd2 (gdImagePtr im, FILE * outFile, int cs, int fmt) +{ + gdIOCtx *out = gdNewFileCtx(outFile); + + _gdImageGd2(im, out, cs, fmt); + + out->gd_free(out); +} + +void *gdImageGd2Ptr (gdImagePtr im, int cs, int fmt, int *size) +{ + void *rv; + gdIOCtx *out = gdNewDynamicCtx(2048, NULL); + + _gdImageGd2(im, out, cs, fmt); + rv = gdDPExtractData(out, size); + out->gd_free(out); + + return rv; } Index: php4/ext/gd/libgd/gd_jpeg.c diff -u php4/ext/gd/libgd/gd_jpeg.c:1.9 php4/ext/gd/libgd/gd_jpeg.c:1.10 --- php4/ext/gd/libgd/gd_jpeg.c:1.9 Sun Dec 1 06:43:54 2002 +++ php4/ext/gd/libgd/gd_jpeg.c Fri Jan 17 13:34:07 2003 @@ -16,6 +16,9 @@ * Modification 4/18/00 TBB: JPEG_DEBUG rather than just DEBUG, * so VC++ builds don't spew to standard output, causing * major CGI brain damage + * + * 2.0.10: more efficient gdImageCreateFromJpegCtx, thanks to + * Christian Aberger */ #include <stdio.h> @@ -38,36 +41,30 @@ static const char *const GD_JPEG_VERSION = "1.0"; typedef struct _jmpbuf_wrapper - { - jmp_buf jmpbuf; - } -jmpbuf_wrapper; +{ + jmp_buf jmpbuf; +} jmpbuf_wrapper; /* Called by the IJG JPEG library upon encountering a fatal error */ static void fatal_jpeg_error (j_common_ptr cinfo) { - jmpbuf_wrapper *jmpbufw; + jmpbuf_wrapper *jmpbufw; - php_gd_error("gd-jpeg: JPEG library reports unrecoverable error: "); - (*cinfo->err->output_message) (cinfo); + php_gd_error("gd-jpeg: JPEG library reports unrecoverable error: "); + (*cinfo->err->output_message) (cinfo); - jmpbufw = (jmpbuf_wrapper *) cinfo->client_data; - jpeg_destroy (cinfo); + jmpbufw = (jmpbuf_wrapper *) cinfo->client_data; + jpeg_destroy (cinfo); - if (jmpbufw != 0) - { - longjmp (jmpbufw->jmpbuf, 1); - php_gd_error_ex(E_ERROR, "gd-jpeg: EXTREMELY fatal error: longjmp" - " returned control; terminating\n"); - } - else - { - php_gd_error_ex(E_ERROR, "gd-jpeg: EXTREMELY fatal error: jmpbuf" - " unrecoverable; terminating\n"); - } + if (jmpbufw != 0) { + longjmp (jmpbufw->jmpbuf, 1); + php_gd_error_ex(E_ERROR, "gd-jpeg: EXTREMELY fatal error: longjmp returned control; terminating"); + } else { + php_gd_error_ex(E_ERROR, "gd-jpeg: EXTREMELY fatal error: jmpbuf unrecoverable; terminating"); + } - exit (99); + exit (99); } /* @@ -76,25 +73,27 @@ * represent higher quality but also larger image size. If QUALITY is * negative, the IJG JPEG library's default quality is used (which * should be near optimal for many applications). See the IJG JPEG - * library documentation for more details. */ + * library documentation for more details. + */ void gdImageJpeg (gdImagePtr im, FILE * outFile, int quality) { - gdIOCtx *out = gdNewFileCtx (outFile); - gdImageJpegCtx (im, out, quality); - out->gd_free (out); + gdIOCtx *out = gdNewFileCtx (outFile); + gdImageJpegCtx (im, out, quality); + out->gd_free (out); } void * gdImageJpegPtr (gdImagePtr im, int *size, int quality) { - void *rv; - gdIOCtx *out = gdNewDynamicCtx (2048, NULL); - gdImageJpegCtx (im, out, quality); - rv = gdDPExtractData (out, size); - out->gd_free (out); - return rv; + void *rv; + gdIOCtx *out = gdNewDynamicCtx (2048, NULL); + gdImageJpegCtx (im, out, quality); + rv = gdDPExtractData (out, size); + out->gd_free (out); + + return rv; } void jpeg_gdIOCtx_dest (j_compress_ptr cinfo, gdIOCtx * outfile); @@ -102,168 +101,127 @@ void gdImageJpegCtx (gdImagePtr im, gdIOCtx * outfile, int quality) { - struct jpeg_compress_struct cinfo; - struct jpeg_error_mgr jerr; - int i, j, jidx; - /* volatile so we can gdFree it on return from longjmp */ - volatile JSAMPROW row = 0; - JSAMPROW rowptr[1]; - jmpbuf_wrapper jmpbufw; - JDIMENSION nlines; - char comment[255]; - -#ifdef JPEG_DEBUG - printf ("gd-jpeg: gd JPEG version %s\n", GD_JPEG_VERSION); - printf ("gd-jpeg: JPEG library version %d, %d-bit sample values\n", - JPEG_LIB_VERSION, BITS_IN_JSAMPLE); - if (!im->trueColor) - { - for (i = 0; i < im->colorsTotal; i++) - { - if (!im->open[i]) - printf ("gd-jpeg: gd colormap index %d: (%d, %d, %d)\n", i, - im->red[i], im->green[i], im->blue[i]); - } - } -#endif /* JPEG_DEBUG */ - - memset (&cinfo, 0, sizeof (cinfo)); - memset (&jerr, 0, sizeof (jerr)); - - cinfo.err = jpeg_std_error (&jerr); - cinfo.client_data = &jmpbufw; - if (setjmp (jmpbufw.jmpbuf) != 0) - { - /* we're here courtesy of longjmp */ - if (row) - gdFree (row); - return; - } + struct jpeg_compress_struct cinfo; + struct jpeg_error_mgr jerr; + int i, j, jidx; + /* volatile so we can gdFree it on return from longjmp */ + volatile JSAMPROW row = 0; + JSAMPROW rowptr[1]; + jmpbuf_wrapper jmpbufw; + JDIMENSION nlines; + char comment[255]; + + memset (&cinfo, 0, sizeof (cinfo)); + memset (&jerr, 0, sizeof (jerr)); + + cinfo.err = jpeg_std_error (&jerr); + cinfo.client_data = &jmpbufw; + if (setjmp (jmpbufw.jmpbuf) != 0) { + /* we're here courtesy of longjmp */ + if (row) { + gdFree (row); + } + return; + } - cinfo.err->error_exit = fatal_jpeg_error; + cinfo.err->error_exit = fatal_jpeg_error; - jpeg_create_compress (&cinfo); + jpeg_create_compress (&cinfo); - cinfo.image_width = im->sx; - cinfo.image_height = im->sy; - cinfo.input_components = 3; /* # of color components per pixel */ - cinfo.in_color_space = JCS_RGB; /* colorspace of input image */ - jpeg_set_defaults (&cinfo); - if (quality >= 0) - jpeg_set_quality (&cinfo, quality, TRUE); - - /* If user requests interlace, translate that to progressive JPEG */ - if (gdImageGetInterlaced (im)) - { -#ifdef JPEG_DEBUG - printf ("gd-jpeg: interlace set, outputting progressive" - " JPEG image\n"); -#endif - jpeg_simple_progression (&cinfo); - } + cinfo.image_width = im->sx; + cinfo.image_height = im->sy; + cinfo.input_components = 3; /* # of color components per pixel */ + cinfo.in_color_space = JCS_RGB; /* colorspace of input image */ + jpeg_set_defaults (&cinfo); + if (quality >= 0) { + jpeg_set_quality (&cinfo, quality, TRUE); + } + + /* If user requests interlace, translate that to progressive JPEG */ + if (gdImageGetInterlaced (im)) { + jpeg_simple_progression (&cinfo); + } + + jpeg_gdIOCtx_dest (&cinfo, outfile); - jpeg_gdIOCtx_dest (&cinfo, outfile); + row = (JSAMPROW) gdCalloc (1, cinfo.image_width * cinfo.input_components * sizeof (JSAMPLE)); + rowptr[0] = row; + + jpeg_start_compress (&cinfo, TRUE); + + if (quality >= 0) { + snprintf(comment, sizeof(comment)-1, "CREATOR: gd-jpeg v%s (using IJG JPEG v%d), quality = %d\n", GD_JPEG_VERSION, JPEG_LIB_VERSION, quality); + } else { + snprintf(comment, sizeof(comment)-1, "CREATOR: gd-jpeg v%s (using IJG JPEG v%d), default quality\n", GD_JPEG_VERSION, JPEG_LIB_VERSION); + } + jpeg_write_marker (&cinfo, JPEG_COM, (unsigned char *) comment, (unsigned int) strlen (comment)); + if (im->trueColor) { - row = (JSAMPROW) gdCalloc (1, cinfo.image_width * cinfo.input_components - * sizeof (JSAMPLE)); - if (row == 0) - { - php_gd_error("gd-jpeg: error: unable to allocate JPEG row " - "structure: gdCalloc returns NULL\n"); - jpeg_destroy_compress (&cinfo); - return; - } - - rowptr[0] = row; - - jpeg_start_compress (&cinfo, TRUE); - - sprintf (comment, "CREATOR: gd-jpeg v%s (using IJG JPEG v%d),", - GD_JPEG_VERSION, JPEG_LIB_VERSION); - if (quality >= 0) - sprintf (comment + strlen (comment), " quality = %d\n", - quality); - else - strcat (comment + strlen (comment), " default quality\n"); - jpeg_write_marker (&cinfo, JPEG_COM, (unsigned char *) comment, - (unsigned int) strlen (comment)); - if (im->trueColor) - { #if BITS_IN_JSAMPLE == 12 - php_gd_error("gd-jpeg: error: jpeg library was compiled for 12-bit\n" - "precision. This is mostly useless, because JPEGs on the web are\n" - "8-bit and such versions of the jpeg library won't read or write\n" - "them. GD doesn't support these unusual images. Edit your\n" - "jmorecfg.h file to specify the correct precision and completely\n" - "'make clean' and 'make install' libjpeg again. Sorry.\n"); - goto error; + php_gd_error("gd-jpeg: error: jpeg library was compiled for 12-bit precision. This is mostly useless, because JPEGs on the web are 8-bit and such versions of the jpeg library won't read or write them. GD doesn't support these unusual images. Edit your jmorecfg.h file to specify the correct precision and completely 'make clean' and 'make install' libjpeg again. Sorry"); + goto error; #endif /* BITS_IN_JSAMPLE == 12 */ - for (i = 0; i < im->sy; i++) - { - for (jidx = 0, j = 0; j < im->sx; j++) - { - int val = im->tpixels[i][j]; - row[jidx++] = gdTrueColorGetRed (val); - row[jidx++] = gdTrueColorGetGreen (val); - row[jidx++] = gdTrueColorGetBlue (val); - } - - nlines = jpeg_write_scanlines (&cinfo, rowptr, 1); - if (nlines != 1) - php_gd_error_ex(E_WARNING, "gd_jpeg: warning: jpeg_write_scanlines" - " returns %u -- expected 1\n", nlines); - } - } - else - { - for (i = 0; i < im->sy; i++) - { - for (jidx = 0, j = 0; j < im->sx; j++) - { - int idx = im->pixels[i][j]; - - /* - * NB: Although gd RGB values are ints, their max value is - * 255 (see the documentation for gdImageColorAllocate()) - * -- perfect for 8-bit JPEG encoding (which is the norm) - */ + + for (i = 0; i < im->sy; i++) { + for (jidx = 0, j = 0; j < im->sx; j++) { + int val = im->tpixels[i][j]; + + row[jidx++] = gdTrueColorGetRed (val); + row[jidx++] = gdTrueColorGetGreen (val); + row[jidx++] = gdTrueColorGetBlue (val); + } + + nlines = jpeg_write_scanlines (&cinfo, rowptr, 1); + if (nlines != 1) { + php_gd_error_ex(E_WARNING, "gd_jpeg: warning: jpeg_write_scanlines returns %u -- expected 1\n", nlines); + } + } + } else { + for (i = 0; i < im->sy; i++) { + for (jidx = 0, j = 0; j < im->sx; j++) { + int idx = im->pixels[i][j]; + + /* NB: Although gd RGB values are ints, their max value is + * 255 (see the documentation for gdImageColorAllocate()) + * -- perfect for 8-bit JPEG encoding (which is the norm) + */ #if BITS_IN_JSAMPLE == 8 - row[jidx++] = im->red[idx]; - row[jidx++] = im->green[idx]; - row[jidx++] = im->blue[idx]; + row[jidx++] = im->red[idx]; + row[jidx++] = im->green[idx]; + row[jidx++] = im->blue[idx]; #elif BITS_IN_JSAMPLE == 12 - row[jidx++] = im->red[idx] << 4; - row[jidx++] = im->green[idx] << 4; - row[jidx++] = im->blue[idx] << 4; + row[jidx++] = im->red[idx] << 4; + row[jidx++] = im->green[idx] << 4; + row[jidx++] = im->blue[idx] << 4; #else #error IJG JPEG library BITS_IN_JSAMPLE value must be 8 or 12 #endif - } + } - nlines = jpeg_write_scanlines (&cinfo, rowptr, 1); - if (nlines != 1) - php_gd_error_ex(E_WARNING, "gd_jpeg: warning: jpeg_write_scanlines" - " returns %u -- expected 1\n", nlines); - } - } - jpeg_finish_compress (&cinfo); - jpeg_destroy_compress (&cinfo); - gdFree (row); + nlines = jpeg_write_scanlines (&cinfo, rowptr, 1); + if (nlines != 1) { + php_gd_error_ex(E_WARNING, "gd_jpeg: warning: jpeg_write_scanlines returns %u -- expected 1\n", nlines); + } + } + } + + jpeg_finish_compress (&cinfo); + jpeg_destroy_compress (&cinfo); + gdFree (row); } gdImagePtr gdImageCreateFromJpeg (FILE * inFile) { - gdImagePtr im; - gdIOCtx *in = gdNewFileCtx (inFile); - im = gdImageCreateFromJpegCtx (in); - in->gd_free (in); - return im; + gdImagePtr im; + gdIOCtx *in = gdNewFileCtx (inFile); + im = gdImageCreateFromJpegCtx (in); + in->gd_free (in); + + return im; } -void - jpeg_gdIOCtx_src (j_decompress_ptr cinfo, - gdIOCtx * infile); +void jpeg_gdIOCtx_src (j_decompress_ptr cinfo, gdIOCtx * infile); /* * Create a gd-format image from the JPEG-format INFILE. Returns the @@ -272,197 +230,122 @@ gdImagePtr gdImageCreateFromJpegCtx (gdIOCtx * infile) { - struct jpeg_decompress_struct cinfo; - struct jpeg_error_mgr jerr; - jmpbuf_wrapper jmpbufw; - /* volatile so we can gdFree them after longjmp */ - volatile JSAMPROW row = 0; - volatile gdImagePtr im = 0; - JSAMPROW rowptr[1]; - unsigned int i, j; - int retval; - JDIMENSION nrows; - -#ifdef JPEG_DEBUG - printf ("gd-jpeg: gd JPEG version %s\n", GD_JPEG_VERSION); - printf ("gd-jpeg: JPEG library version %d, %d-bit sample values\n", - JPEG_LIB_VERSION, BITS_IN_JSAMPLE); -#endif + struct jpeg_decompress_struct cinfo; + struct jpeg_error_mgr jerr; + jmpbuf_wrapper jmpbufw; + /* volatile so we can gdFree them after longjmp */ + volatile JSAMPROW row = 0; + volatile gdImagePtr im = 0; + JSAMPROW rowptr[1]; + unsigned int i, j; + int retval; + JDIMENSION nrows; + + memset (&cinfo, 0, sizeof (cinfo)); + memset (&jerr, 0, sizeof (jerr)); + + cinfo.err = jpeg_std_error (&jerr); + cinfo.client_data = &jmpbufw; + if (setjmp (jmpbufw.jmpbuf) != 0) { + /* we're here courtesy of longjmp */ + if (row) { + gdFree (row); + } + if (im) { + gdImageDestroy (im); + } + return 0; + } - memset (&cinfo, 0, sizeof (cinfo)); - memset (&jerr, 0, sizeof (jerr)); + cinfo.err->error_exit = fatal_jpeg_error; - cinfo.err = jpeg_std_error (&jerr); - cinfo.client_data = &jmpbufw; - if (setjmp (jmpbufw.jmpbuf) != 0) - { - /* we're here courtesy of longjmp */ - if (row) - gdFree (row); - if (im) - gdImageDestroy (im); - return 0; - } - - cinfo.err->error_exit = fatal_jpeg_error; - - jpeg_create_decompress (&cinfo); - - jpeg_gdIOCtx_src (&cinfo, infile); - - retval = jpeg_read_header (&cinfo, TRUE); - if (retval != JPEG_HEADER_OK) - php_gd_error_ex(E_WARNING, "gd-jpeg: warning: jpeg_read_header returns" - " %d, expected %d\n", retval, JPEG_HEADER_OK); - - if (cinfo.image_height > INT_MAX) - php_gd_error_ex(E_WARNING, "gd-jpeg: warning: JPEG image height (%u) is" - " greater than INT_MAX (%d) (and thus greater than" - " gd can handle)", cinfo.image_height, - INT_MAX); - - if (cinfo.image_width > INT_MAX) - php_gd_error_ex(E_WARNING, "gd-jpeg: warning: JPEG image width (%u) is" - " greater than INT_MAX (%d) (and thus greater than" - " gd can handle)\n", cinfo.image_width, INT_MAX); - - im = gdImageCreateTrueColor ((int) cinfo.image_width, - (int) cinfo.image_height); - if (im == 0) - { - php_gd_error("gd-jpeg error: cannot allocate gdImage" - " struct\n"); - goto error; - } - - /* - * Force the image into RGB colorspace, but don't - * reduce the number of colors anymore (GD 2.0) - */ - cinfo.out_color_space = JCS_RGB; - - if (jpeg_start_decompress (&cinfo) != TRUE) - php_gd_error("gd-jpeg: warning: jpeg_start_decompress" - " reports suspended data source\n"); - -#ifdef JPEG_DEBUG - printf ("gd-jpeg: JPEG image information:"); - if (cinfo.saw_JFIF_marker) - printf (" JFIF version %d.%.2d", - (int) cinfo.JFIF_major_version, - (int) cinfo.JFIF_minor_version); - else if (cinfo.saw_Adobe_marker) - printf (" Adobe format"); - else - printf (" UNKNOWN format"); - - printf (" %ux%u (raw) / %ux%u (scaled) %d-bit", cinfo.image_width, - cinfo.image_height, cinfo.output_width, - cinfo.output_height, cinfo.data_precision); - printf (" %s", (cinfo.progressive_mode ? "progressive" : - "baseline")); - printf (" image, %d quantized colors, ", - cinfo.actual_number_of_colors); - - switch (cinfo.jpeg_color_space) - { - case JCS_GRAYSCALE: - printf ("grayscale"); - break; - - case JCS_RGB: - printf ("RGB"); - break; - - case JCS_YCbCr: - printf ("YCbCr (a.k.a. YUV)"); - break; - - case JCS_CMYK: - printf ("CMYK"); - break; - - case JCS_YCCK: - printf ("YCbCrK"); - break; - - default: - printf ("UNKNOWN (value: %d)", (int) cinfo.jpeg_color_space); - break; - } - printf (" colorspace\n"); - fflush (stdout); -#endif /* JPEG_DEBUG */ - - /* REMOVED by TBB 2/12/01. This field of the structure is - documented as private, and sure enough it's gone in the - latest libjpeg, replaced by something else. Unfortunately - there is still no right way to find out if the file was - progressive or not; just declare your intent before you - write one by calling gdImageInterlace(im, 1) yourself. - After all, we're not really supposed to rework JPEGs and - write them out again anyway. Lossy compression, remember? */ + jpeg_create_decompress (&cinfo); + + jpeg_gdIOCtx_src (&cinfo, infile); + + retval = jpeg_read_header (&cinfo, TRUE); + if (retval != JPEG_HEADER_OK) { + php_gd_error_ex(E_WARNING, "gd-jpeg: warning: jpeg_read_header returned %d, expected %d", retval, JPEG_HEADER_OK); + } + + if (cinfo.image_height > INT_MAX) { + php_gd_error_ex(E_WARNING, "gd-jpeg: warning: JPEG image height (%u) is greater than INT_MAX (%d) (and thus greater than gd can handle)", cinfo.image_height, INT_MAX); + } + + if (cinfo.image_width > INT_MAX) { + php_gd_error_ex(E_WARNING, "gd-jpeg: warning: JPEG image width (%u) is greater than INT_MAX (%d) (and thus greater than gd can handle)", cinfo.image_width, INT_MAX); + } + + im = gdImageCreateTrueColor ((int) cinfo.image_width, (int) cinfo.image_height); + if (im == 0) { + php_gd_error("gd-jpeg error: cannot allocate gdImage struct"); + goto error; + } + + /* Force the image into RGB colorspace, but don't reduce the number of colors anymore (GD 2.0) */ + cinfo.out_color_space = JCS_RGB; + + if (jpeg_start_decompress (&cinfo) != TRUE) { + php_gd_error("gd-jpeg: warning: jpeg_start_decompress reports suspended data source"); + } + + /* REMOVED by TBB 2/12/01. This field of the structure is + * documented as private, and sure enough it's gone in the + * latest libjpeg, replaced by something else. Unfortunately + * there is still no right way to find out if the file was + * progressive or not; just declare your intent before you + * write one by calling gdImageInterlace(im, 1) yourself. + * After all, we're not really supposed to rework JPEGs and + * write them out again anyway. Lossy compression, remember? + */ #if 0 gdImageInterlace (im, cinfo.progressive_mode != 0); #endif - if (cinfo.output_components != 3) - { - php_gd_error_ex(E_WARNING, "gd-jpeg: error: JPEG color quantization" - " request resulted in output_components == %d" - " (expected 3)\n", cinfo.output_components); - goto error; - } + + if (cinfo.output_components != 3) { + php_gd_error_ex(E_WARNING, "gd-jpeg: error: JPEG color quantization request resulted in output_components == %d (expected 3)", cinfo.output_components); + goto error; + } #if BITS_IN_JSAMPLE == 12 - php_gd_error("gd-jpeg: error: jpeg library was compiled for 12-bit\n" - "precision. This is mostly useless, because JPEGs on the web are\n" - "8-bit and such versions of the jpeg library won't read or write\n" - "them. GD doesn't support these unusual images. Edit your\n" - "jmorecfg.h file to specify the correct precision and completely\n" - "'make clean' and 'make install' libjpeg again. Sorry.\n"); - goto error; + php_gd_error("gd-jpeg: error: jpeg library was compiled for 12-bit precision. This is mostly useless, because JPEGs on the web are 8-bit and such versions of the jpeg library won't read or write them. GD doesn't support these unusual images. Edit your jmorecfg.h file to specify the correct precision and completely 'make clean' and 'make install' libjpeg again. Sorry."); + goto error; #endif /* BITS_IN_JSAMPLE == 12 */ - row = gdCalloc (cinfo.output_width * 3, sizeof (JSAMPLE)); - if (row == 0) - { - php_gd_error("gd-jpeg: error: unable to allocate row for" - " JPEG scanline: gdCalloc returns NULL\n"); - goto error; - } - rowptr[0] = row; - - for (i = 0; i < cinfo.output_height; i++) - { - nrows = jpeg_read_scanlines (&cinfo, rowptr, 1); - if (nrows != 1) - { - php_gd_error_ex(E_WARNING, "gd-jpeg: error: jpeg_read_scanlines" - " returns %u, expected 1\n", nrows); - goto error; - } - - for (j = 0; j < cinfo.output_width; j++) - im->tpixels[i][j] = gdTrueColor (row[j * 3], row[j * 3 + 1], - row[j * 3 + 2]); - } - - if (jpeg_finish_decompress (&cinfo) != TRUE) - php_gd_error("gd-jpeg: warning: jpeg_finish_decompress" - " reports suspended data source\n"); - - - jpeg_destroy_decompress (&cinfo); - gdFree (row); - return im; + row = gdCalloc (cinfo.output_width * 3, sizeof (JSAMPLE)); + rowptr[0] = row; + + for (i = 0; i < cinfo.output_height; i++) { + register JSAMPROW currow = row; + register int *tpix = im->tpixels[i]; + nrows = jpeg_read_scanlines (&cinfo, rowptr, 1); + if (nrows != 1) { + php_gd_error_ex(E_WARNING, "gd-jpeg: error: jpeg_read_scanlines returns %u, expected 1", nrows); + goto error; + } + for (j = 0; j < cinfo.output_width; j++, currow += 3, tpix++) { + *tpix = gdTrueColor (currow[0], currow[1], currow[2]); + } + } + + if (jpeg_finish_decompress (&cinfo) != TRUE) { + php_gd_error("gd-jpeg: warning: jpeg_finish_decompress reports suspended data source"); + } + + jpeg_destroy_decompress (&cinfo); + gdFree (row); + + return im; error: - jpeg_destroy_decompress (&cinfo); - if (row) - gdFree (row); - if (im) - gdImageDestroy (im); - return 0; + jpeg_destroy_decompress (&cinfo); + if (row) { + gdFree (row); + } + if (im) { + gdImageDestroy (im); + } + return 0; } /* @@ -488,15 +371,13 @@ /* Expanded data source object for gdIOCtx input */ typedef struct - { - struct jpeg_source_mgr pub; /* public fields */ +{ + struct jpeg_source_mgr pub; /* public fields */ - gdIOCtx *infile; /* source stream */ - unsigned char *buffer; /* start of buffer */ - safeboolean start_of_file; /* have we gotten any data yet? */ - - } -my_source_mgr; + gdIOCtx *infile; /* source stream */ + unsigned char *buffer; /* start of buffer */ + safeboolean start_of_file; /* have we gotten any data yet? */ +} my_source_mgr; typedef my_source_mgr *my_src_ptr; @@ -510,13 +391,13 @@ void init_source (j_decompress_ptr cinfo) { - my_src_ptr src = (my_src_ptr) cinfo->src; + my_src_ptr src = (my_src_ptr) cinfo->src; - /* We reset the empty-input-file flag for each image, - * but we don't clear the input buffer. - * This is correct behavior for reading a series of images from one source. - */ - src->start_of_file = TRUE; + /* We reset the empty-input-file flag for each image, + * but we don't clear the input buffer. + * This is correct behavior for reading a series of images from one source. + */ + src->start_of_file = TRUE; } @@ -558,56 +439,42 @@ safeboolean fill_input_buffer (j_decompress_ptr cinfo) { - my_src_ptr src = (my_src_ptr) cinfo->src; - size_t nbytes = 0; + my_src_ptr src = (my_src_ptr) cinfo->src; + size_t nbytes = 0; - /* size_t got; */ - /* char *s; */ - memset (src->buffer, 0, INPUT_BUF_SIZE); + /* size_t got; */ + /* char *s; */ + memset (src->buffer, 0, INPUT_BUF_SIZE); - while (nbytes < INPUT_BUF_SIZE) - { - - int got = gdGetBuf (src->buffer + nbytes, - INPUT_BUF_SIZE - nbytes, - src->infile); + while (nbytes < INPUT_BUF_SIZE) { + int got = gdGetBuf (src->buffer + nbytes, INPUT_BUF_SIZE - nbytes, src->infile); - if ((got == EOF) || (got == 0)) - { - - /* EOF or error. If we got any data, don't worry about it. - If we didn't, then this is unexpected. */ - if (!nbytes) - { - - nbytes = -1; - - } - - break; - + if ((got == EOF) || (got == 0)) { + /* EOF or error. If we got any data, don't worry about it. If we didn't, then this is unexpected. */ + if (!nbytes) { + nbytes = -1; + } + break; + } + nbytes += got; } - - nbytes += got; - - } - if (nbytes <= 0) - { - if (src->start_of_file) /* Treat empty input file as fatal error */ - ERREXIT (cinfo, JERR_INPUT_EMPTY); - WARNMS (cinfo, JWRN_JPEG_EOF); - /* Insert a fake EOI marker */ - src->buffer[0] = (unsigned char) 0xFF; - src->buffer[1] = (unsigned char) JPEG_EOI; - nbytes = 2; - } - - src->pub.next_input_byte = src->buffer; - src->pub.bytes_in_buffer = nbytes; - src->start_of_file = FALSE; + if (nbytes <= 0) { + if (src->start_of_file) { /* Treat empty input file as fatal error */ + ERREXIT (cinfo, JERR_INPUT_EMPTY); + } + WARNMS (cinfo, JWRN_JPEG_EOF); + /* Insert a fake EOI marker */ + src->buffer[0] = (unsigned char) 0xFF; + src->buffer[1] = (unsigned char) JPEG_EOI; + nbytes = 2; + } + + src->pub.next_input_byte = src->buffer; + src->pub.bytes_in_buffer = nbytes; + src->start_of_file = FALSE; - return TRUE; + return TRUE; } @@ -626,24 +493,22 @@ void skip_input_data (j_decompress_ptr cinfo, long num_bytes) { - my_src_ptr src = (my_src_ptr) cinfo->src; + my_src_ptr src = (my_src_ptr) cinfo->src; - /* Just a dumb implementation for now. Not clear that being smart is worth - * any trouble anyway --- large skips are infrequent. - */ - if (num_bytes > 0) - { - while (num_bytes > (long) src->pub.bytes_in_buffer) - { - num_bytes -= (long) src->pub.bytes_in_buffer; - (void) fill_input_buffer (cinfo); - /* note we assume that fill_input_buffer will never return FALSE, - * so suspension need not be handled. - */ - } - src->pub.next_input_byte += (size_t) num_bytes; - src->pub.bytes_in_buffer -= (size_t) num_bytes; - } + /* Just a dumb implementation for now. Not clear that being smart is worth + * any trouble anyway --- large skips are infrequent. + */ + if (num_bytes > 0) { + while (num_bytes > (long) src->pub.bytes_in_buffer) { + num_bytes -= (long) src->pub.bytes_in_buffer; + (void) fill_input_buffer (cinfo); + /* note we assume that fill_input_buffer will never return FALSE, + * so suspension need not be handled. + */ + } + src->pub.next_input_byte += (size_t) num_bytes; + src->pub.bytes_in_buffer -= (size_t) num_bytes; + } } @@ -668,11 +533,9 @@ void term_source (j_decompress_ptr cinfo) { - #if 0 -/* never used */ - my_src_ptr src = (my_src_ptr) cinfo->src; - + * never used */ + my_src_ptr src = (my_src_ptr) cinfo->src; #endif } @@ -684,50 +547,44 @@ */ void -jpeg_gdIOCtx_src (j_decompress_ptr cinfo, - gdIOCtx * infile) +jpeg_gdIOCtx_src (j_decompress_ptr cinfo, gdIOCtx * infile) { - my_src_ptr src; + my_src_ptr src; - /* The source object and input buffer are made permanent so that a series - * of JPEG images can be read from the same file by calling jpeg_gdIOCtx_src - * only before the first one. (If we discarded the buffer at the end of - * one image, we'd likely lose the start of the next one.) - * This makes it unsafe to use this manager and a different source - * manager serially with the same JPEG object. Caveat programmer. - */ - if (cinfo->src == NULL) - { /* first time for this JPEG object? */ - cinfo->src = (struct jpeg_source_mgr *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, - sizeof (my_source_mgr)); - src = (my_src_ptr) cinfo->src; - src->buffer = (unsigned char *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, - INPUT_BUF_SIZE * sizeof (unsigned char)); + /* The source object and input buffer are made permanent so that a series + * of JPEG images can be read from the same file by calling jpeg_gdIOCtx_src + * only before the first one. (If we discarded the buffer at the end of + * one image, we'd likely lose the start of the next one.) + * This makes it unsafe to use this manager and a different source + * manager serially with the same JPEG object. Caveat programmer. + */ + if (cinfo->src == NULL) { /* first time for this JPEG object? */ + cinfo->src = (struct jpeg_source_mgr *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, sizeof (my_source_mgr)); + src = (my_src_ptr) cinfo->src; + src->buffer = (unsigned char *) (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, INPUT_BUF_SIZE * sizeof (unsigned char)); - } + } - src = (my_src_ptr) cinfo->src; - src->pub.init_source = init_source; - src->pub.fill_input_buffer = fill_input_buffer; - src->pub.skip_input_data = skip_input_data; - src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */ - src->pub.term_source = term_source; - src->infile = infile; - src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */ - src->pub.next_input_byte = NULL; /* until buffer loaded */ + src = (my_src_ptr) cinfo->src; + src->pub.init_source = init_source; + src->pub.fill_input_buffer = fill_input_buffer; + src->pub.skip_input_data = skip_input_data; + src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */ + src->pub.term_source = term_source; + src->infile = infile; + src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */ + src->pub.next_input_byte = NULL; /* until buffer loaded */ } /* Expanded data destination object for stdio output */ typedef struct { - struct jpeg_destination_mgr pub; /* public fields */ - gdIOCtx *outfile; /* target stream */ - unsigned char *buffer; /* start of buffer */ -} -my_destination_mgr; + struct jpeg_destination_mgr pub; /* public fields */ + gdIOCtx *outfile; /* target stream */ + unsigned char *buffer; /* start of buffer */ +} my_destination_mgr; typedef my_destination_mgr *my_dest_ptr; @@ -741,15 +598,13 @@ void init_destination (j_compress_ptr cinfo) { - my_dest_ptr dest = (my_dest_ptr) cinfo->dest; + my_dest_ptr dest = (my_dest_ptr) cinfo->dest; - /* Allocate the output buffer --- it will be released when done with image */ - dest->buffer = (unsigned char *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - OUTPUT_BUF_SIZE * sizeof (unsigned char)); + /* Allocate the output buffer --- it will be released when done with image */ + dest->buffer = (unsigned char *) (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, OUTPUT_BUF_SIZE * sizeof (unsigned char)); - dest->pub.next_output_byte = dest->buffer; - dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; + dest->pub.next_output_byte = dest->buffer; + dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; } @@ -779,16 +634,16 @@ safeboolean empty_output_buffer (j_compress_ptr cinfo) { - my_dest_ptr dest = (my_dest_ptr) cinfo->dest; + my_dest_ptr dest = (my_dest_ptr) cinfo->dest; - if (gdPutBuf (dest->buffer, OUTPUT_BUF_SIZE, dest->outfile) != - (size_t) OUTPUT_BUF_SIZE) - ERREXIT (cinfo, JERR_FILE_WRITE); + if (gdPutBuf (dest->buffer, OUTPUT_BUF_SIZE, dest->outfile) != (size_t) OUTPUT_BUF_SIZE) { + ERREXIT (cinfo, JERR_FILE_WRITE); + } - dest->pub.next_output_byte = dest->buffer; - dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; + dest->pub.next_output_byte = dest->buffer; + dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; - return TRUE; + return TRUE; } @@ -804,15 +659,13 @@ void term_destination (j_compress_ptr cinfo) { - my_dest_ptr dest = (my_dest_ptr) cinfo->dest; - size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer; + my_dest_ptr dest = (my_dest_ptr) cinfo->dest; + size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer; - /* Write any data remaining in the buffer */ - if (datacount > 0) - { - if ((size_t)gdPutBuf (dest->buffer, datacount, dest->outfile) != datacount) - ERREXIT (cinfo, JERR_FILE_WRITE); - } + /* Write any data remaining in the buffer */ + if (datacount > 0 && ((size_t)gdPutBuf (dest->buffer, datacount, dest->outfile) != datacount)) { + ERREXIT (cinfo, JERR_FILE_WRITE); + } } @@ -825,26 +678,23 @@ void jpeg_gdIOCtx_dest (j_compress_ptr cinfo, gdIOCtx * outfile) { - my_dest_ptr dest; + my_dest_ptr dest; + + /* The destination object is made permanent so that multiple JPEG images + * can be written to the same file without re-executing jpeg_stdio_dest. + * This makes it dangerous to use this manager and a different destination + * manager serially with the same JPEG object, because their private object + * sizes may be different. Caveat programmer. + */ + if (cinfo->dest == NULL) { /* first time for this JPEG object? */ + cinfo->dest = (struct jpeg_destination_mgr *) (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, sizeof (my_destination_mgr)); + } - /* The destination object is made permanent so that multiple JPEG images - * can be written to the same file without re-executing jpeg_stdio_dest. - * This makes it dangerous to use this manager and a different destination - * manager serially with the same JPEG object, because their private object - * sizes may be different. Caveat programmer. - */ - if (cinfo->dest == NULL) - { /* first time for this JPEG object? */ - cinfo->dest = (struct jpeg_destination_mgr *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, - sizeof (my_destination_mgr)); - } - - dest = (my_dest_ptr) cinfo->dest; - dest->pub.init_destination = init_destination; - dest->pub.empty_output_buffer = empty_output_buffer; - dest->pub.term_destination = term_destination; - dest->outfile = outfile; + dest = (my_dest_ptr) cinfo->dest; + dest->pub.init_destination = init_destination; + dest->pub.empty_output_buffer = empty_output_buffer; + dest->pub.term_destination = term_destination; + dest->outfile = outfile; } #endif /* HAVE_JPEG */
Index: php4/ext/gd/gd.c diff -u php4/ext/gd/gd.c:1.243 php4/ext/gd/gd.c:1.244 --- php4/ext/gd/gd.c:1.243 Wed Jan 8 13:11:40 2003 +++ php4/ext/gd/gd.c Fri Jan 17 13:34:07 2003 @@ -18,7 +18,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: gd.c,v 1.243 2003/01/08 18:11:40 iliaa Exp $ */ +/* $Id: gd.c,v 1.244 2003/01/17 18:34:07 iliaa Exp $ */ /* gd 1.2 is copyright 1994, 1995, Quest Protein Database Center, Cold Spring Harbor Labs. */ @@ -1562,17 +1562,18 @@ */ static void _php_image_output(INTERNAL_FUNCTION_PARAMETERS, int image_type, char *tn, void (*func_p)()) { - zval **imgind, **file, **quality; + zval **imgind, **file, **quality, **type; gdImagePtr im; char *fn = NULL; FILE *fp; int argc = ZEND_NUM_ARGS(); - int q = -1, i; + int q = -1, i, t = 1; /* The quality parameter for Wbmp stands for the threshold when called from image2wbmp() */ /* When called from imagewbmp() the quality parameter stands for the foreground color. Default: black. */ + /* The quality parameter for gd2 stands for chunk size */ - if (argc < 1 || argc > 3 || zend_get_parameters_ex(argc, &imgind, &file, &quality) == FAILURE) { + if (argc < 1 || argc > 4 || zend_get_parameters_ex(argc, &imgind, &file, &quality, &type) == FAILURE) { ZEND_WRONG_PARAM_COUNT(); } @@ -1585,6 +1586,10 @@ convert_to_long_ex(quality); q = Z_LVAL_PP(quality); } + if (argc == 4) { + convert_to_long_ex(type); + t = Z_LVAL_PP(type); + } } if ((argc == 2) || (argc == 3 && Z_STRLEN_PP(file))) { @@ -1622,7 +1627,10 @@ break; #endif default: - (*func_p)(im, fp); + if (q == -1) { + q = 128; + } + (*func_p)(im, fp, q, t); break; } fflush(fp); @@ -1749,7 +1757,7 @@ /* }}} */ #ifdef HAVE_GD_GD2 -/* {{{ proto int imagegd2(int im [, string filename]) +/* {{{ proto int imagegd2(int im [, string filename, [, int chunk_size, [, int type]]]) Output GD2 image to browser or file */ PHP_FUNCTION(imagegd2) { Index: php4/ext/gd/libgd/gd.c diff -u php4/ext/gd/libgd/gd.c:1.40 php4/ext/gd/libgd/gd.c:1.41 --- php4/ext/gd/libgd/gd.c:1.40 Thu Jan 9 21:00:39 2003 +++ php4/ext/gd/libgd/gd.c Fri Jan 17 13:34:07 2003 @@ -81,6 +81,9 @@ }; #endif /*CHARSET_EBCDIC */ +/* 2.0.10: cast instead of floor() yields 35% performance improvement. Thanks to John Buckman. */ +#define floor_cast(exp) ((long) exp) + extern int gdCosT[]; extern int gdSinT[]; @@ -661,6 +664,76 @@ } +/* 2.0.10: before the drawing routines, some code to clip points that are + * outside the drawing window. Nick Atty (nick@canalplan.org.uk) + * + * This is the Sutherland Hodgman Algorithm, as implemented by + * Duvanenko, Robbins and Gyurcsik - SH(DRG) for short. See Dr Dobb's + * Journal, January 1996, pp107-110 and 116-117 + * + * Given the end points of a line, and a bounding rectangle (which we + * know to be from (0,0) to (SX,SY)), adjust the endpoints to be on + * the edges of the rectangle if the line should be drawn at all, + * otherwise return a failure code + */ + +/* this does "one-dimensional" clipping: note that the second time it + * is called, all the x parameters refer to height and the y to width + * - the comments ignore this (if you can understand it when it's + * looking at the X parameters, it should become clear what happens on + * the second call!) The code is simplified from that in the article, + * as we know that gd images always start at (0,0) + */ + +static int clip_1d(int *x0, int *y0, int *x1, int *y1, int maxdim) { + double m; /* gradient of line */ + + if (*x0 < 0) { /* start of line is left of window */ + if(*x1 < 0) { /* as is the end, so the line never cuts the window */ + return 0; + } + m = (*y1 - *y0)/(double)(*x1 - *x0); /* calculate the slope of the line */ + /* adjust x0 to be on the left boundary (ie to be zero), and y0 to match */ + *y0 -= m * *x0; + *x0 = 0; + /* now, perhaps, adjust the far end of the line as well */ + if (*x1 > maxdim) { + *y1 += m * (maxdim - *x1); + *x1 = maxdim; + } + return 1; + } + if (*x0 > maxdim) { /* start of line is right of window - complement of above */ + if (*x1 > maxdim) { /* as is the end, so the line misses the window */ + return 0; + } + m = (*y1 - *y0)/(double)(*x1 - *x0); /* calculate the slope of the line */ + *y0 += m * (maxdim - *x0); /* adjust so point is on the right boundary */ + *x0 = maxdim; + /* now, perhaps, adjust the end of the line */ + if (*x1 < 0) { + *y1 -= m * *x1; + *x1 = 0; + } + return 1; + } + /* the final case - the start of the line is inside the window */ + if (*x1 > maxdim) { /* other end is outside to the right */ + m = (*y1 - *y0)/(double)(*x1 - *x0); /* calculate the slope of the line */ + *y1 += m * (maxdim - *x1); + *x1 = maxdim; + return 1; + } + if (*x1 < 0) { /* other end is outside to the left */ + m = (*y1 - *y0)/(double)(*x1 - *x0); /* calculate the slope of the line */ + *y1 -= m * *x1; + *x1 = 0; + return 1; + } + /* only get here if both points are inside the window */ + return 1; +} + void gdImageSetPixel (gdImagePtr im, int x, int y, int color) { @@ -871,158 +944,139 @@ void gdImageLine (gdImagePtr im, int x1, int y1, int x2, int y2, int color) { - int dx, dy, incr1, incr2, d, x, y, xend, yend, xdirflag, ydirflag; - int wid; - int w, wstart; - int thick = im->thick; - dx = abs (x2 - x1); - dy = abs (y2 - y1); - if (dy <= dx) - { - /* More-or-less horizontal. use wid for vertical stroke */ - /* Doug Claar: watch out for NaN in atan2 (2.0.5) */ - if ((dx == 0) && (dy == 0)) { - wid = 1; - } else { - wid = (int)(thick * cos (atan2 (dy, dx))); - if (wid == 0) { - wid = 1; - } - } - d = 2 * dy - dx; - incr1 = 2 * dy; - incr2 = 2 * (dy - dx); - if (x1 > x2) - { - x = x2; - y = y2; - ydirflag = (-1); - xend = x1; - } - else - { - x = x1; - y = y1; - ydirflag = 1; - xend = x2; - } - - /* Set up line thickness */ - wstart = y - wid / 2; - for (w = wstart; w < wstart + wid; w++) - gdImageSetPixel (im, x, w, color); - - if (((y2 - y1) * ydirflag) > 0) - { - while (x < xend) - { - x++; - if (d < 0) - { - d += incr1; - } - else - { - y++; - d += incr2; - } - wstart = y - wid / 2; - for (w = wstart; w < wstart + wid; w++) - gdImageSetPixel (im, x, w, color); - } - } - else - { - while (x < xend) - { - x++; - if (d < 0) - { - d += incr1; - } - else - { - y--; - d += incr2; - } - wstart = y - wid / 2; - for (w = wstart; w < wstart + wid; w++) - gdImageSetPixel (im, x, w, color); - } - } - } - else - { - /* More-or-less vertical. use wid for horizontal stroke */ - wid = (int)(thick * sin (atan2 (dy, dx))); - if (wid == 0) - wid = 1; + int dx, dy, incr1, incr2, d, x, y, xend, yend, xdirflag, ydirflag; + int wid; + int w, wstart; + int thick = im->thick; - d = 2 * dx - dy; - incr1 = 2 * dx; - incr2 = 2 * (dx - dy); - if (y1 > y2) - { - y = y2; - x = x2; - yend = y1; - xdirflag = (-1); - } - else - { - y = y1; - x = x1; - yend = y2; - xdirflag = 1; + /* 2.0.10: Nick Atty: clip to edges of drawing rectangle, return if no points need to be drawn */ + if (!clip_1d(&x1,&y1,&x2,&y2,gdImageSX(im)) || !clip_1d(&y1,&x1,&y2,&x2,gdImageSY(im))) { + return; } - - /* Set up line thickness */ - wstart = x - wid / 2; - for (w = wstart; w < wstart + wid; w++) - gdImageSetPixel (im, w, y, color); - - if (((x2 - x1) * xdirflag) > 0) - { - while (y < yend) - { - y++; - if (d < 0) - { - d += incr1; + + dx = abs(x2 - x1); + dy = abs(y2 - y1); + if (dy <= dx) { + /* More-or-less horizontal. use wid for vertical stroke */ + /* Doug Claar: watch out for NaN in atan2 (2.0.5) */ + if ((dx == 0) && (dy == 0)) { + wid = 1; + } else { + wid = (int)(thick * cos (atan2 (dy, dx))); + if (wid == 0) { + wid = 1; + } } - else - { - x++; - d += incr2; + d = 2 * dy - dx; + incr1 = 2 * dy; + incr2 = 2 * (dy - dx); + if (x1 > x2) { + x = x2; + y = y2; + ydirflag = (-1); + xend = x1; + } else { + x = x1; + y = y1; + ydirflag = 1; + xend = x2; + } + + /* Set up line thickness */ + wstart = y - wid / 2; + for (w = wstart; w < wstart + wid; w++) { + gdImageSetPixel(im, x, w, color); + } + + if (((y2 - y1) * ydirflag) > 0) { + while (x < xend) { + x++; + if (d < 0) { + d += incr1; + } else { + y++; + d += incr2; + } + wstart = y - wid / 2; + for (w = wstart; w < wstart + wid; w++) { + gdImageSetPixel (im, x, w, color); + } + } + } else { + while (x < xend) { + x++; + if (d < 0) { + d += incr1; + } else { + y--; + d += incr2; + } + wstart = y - wid / 2; + for (w = wstart; w < wstart + wid; w++) { + gdImageSetPixel (im, x, w, color); + } + } } - wstart = x - wid / 2; - for (w = wstart; w < wstart + wid; w++) - gdImageSetPixel (im, w, y, color); - } - } - else - { - while (y < yend) - { - y++; - if (d < 0) - { - d += incr1; + } else { + /* More-or-less vertical. use wid for horizontal stroke */ + wid = (int)(thick * sin (atan2 (dy, dx))); + if (wid == 0) { + wid = 1; } - else - { - x--; - d += incr2; + + d = 2 * dx - dy; + incr1 = 2 * dx; + incr2 = 2 * (dx - dy); + if (y1 > y2) { + y = y2; + x = x2; + yend = y1; + xdirflag = (-1); + } else { + y = y1; + x = x1; + yend = y2; + xdirflag = 1; + } + + /* Set up line thickness */ + wstart = x - wid / 2; + for (w = wstart; w < wstart + wid; w++) { + gdImageSetPixel (im, w, y, color); + } + + if (((x2 - x1) * xdirflag) > 0) { + while (y < yend) { + y++; + if (d < 0) { + d += incr1; + } else { + x++; + d += incr2; + } + wstart = x - wid / 2; + for (w = wstart; w < wstart + wid; w++) { + gdImageSetPixel (im, w, y, color); + } + } + } else { + while (y < yend) { + y++; + if (d < 0) { + d += incr1; + } else { + x--; + d += incr2; + } + wstart = x - wid / 2; + for (w = wstart; w < wstart + wid; w++) { + gdImageSetPixel (im, w, y, color); + } + } } - wstart = x - wid / 2; - for (w = wstart; w < wstart + wid; w++) - gdImageSetPixel (im, w, y, color); - } } - } } - #define BLEND_COLOR(a, nc, c, cc) \ nc = (cc) + (((((c) - (cc)) * (a)) + ((((c) - (cc)) * (a)) >> 8) + 0x80) >> 8); @@ -1317,13 +1371,6 @@ *onP = on; } -int -gdImageBoundsSafe (gdImagePtr im, int x, int y) -{ - return (!(((y < 0) || (y >= im->sy)) || - ((x < 0) || (x >= im->sx)))); -} - void gdImageChar (gdImagePtr im, gdFontPtr f, int x, int y, int c, int color) @@ -1831,154 +1878,127 @@ void gdImageFilledRectangle (gdImagePtr im, int x1, int y1, int x2, int y2, int color) { - int x, y; - for (y = y1; (y <= y2); y++) - { - for (x = x1; (x <= x2); x++) - { - gdImageSetPixel (im, x, y, color); + int x, y; + + /* Nick Atty: limit the points at the edge. Note that this also + * nicely kills any plotting for rectangles completely outside the + * window as it makes the tests in the for loops fail + */ + if (x1 < 0) { + x1 = 0; + } + if (x1 > gdImageSX(im)) { + x1 = gdImageSX(im); + } + if(y1 < 0) { + y1 = 0; + } + if (y1 > gdImageSY(im)) { + y1 = gdImageSY(im); + } + + for (y = y1; (y <= y2); y++) { + for (x = x1; (x <= x2); x++) { + gdImageSetPixel (im, x, y, color); + } } - } } void gdImageCopy (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int w, int h) { - int c; - int x, y; - int tox, toy; - int i; - int colorMap[gdMaxColors]; - if (dst->trueColor) - { - /* 2.0: much easier when the destination is truecolor. */ + int c; + int x, y; + int tox, toy; + int i; + int colorMap[gdMaxColors]; + if (dst->trueColor) { + /* 2.0: much easier when the destination is truecolor. */ + /* 2.0.10: needs a transparent-index check that is still valid if + * the source is not truecolor. Thanks to Frank Warmerdam. + */ - if (src->trueColor) { - for (y = 0; (y < h); y++) - { - for (x = 0; (x < w); x++) - { - int c = gdImageGetTrueColorPixel (src, srcX + x, - srcY + y); - gdImageSetPixel (dst, - dstX + x, - dstY + y, - c); + if (src->trueColor) { + for (y = 0; (y < h); y++) { + for (x = 0; (x < w); x++) { + int c = gdImageGetTrueColorPixel (src, srcX + x, srcY + y); + gdImageSetPixel (dst, dstX + x, dstY + y, c); } } - - } - else { + } else { /* source is palette based */ - for (y = 0; (y < h); y++) - { - for (x = 0; (x < w); x++) - { - int c = gdImageGetPixel (src, srcX + x, - srcY + y); - if (c != src->transparent) - { - gdImageSetPixel (dst, - dstX + x, - dstY + y, - gdTrueColor(src->red[c], src->green[c], src->blue[c])); + for (y = 0; (y < h); y++) { + for (x = 0; (x < w); x++) { + int c = gdImageGetPixel (src, srcX + x, srcY + y); + if (c != src->transparent) { + gdImageSetPixel (dst, dstX + x, dstY + y, gdTrueColor(src->red[c], src->green[c], src->blue[c])); } + } + } } - } + return; } - return; - } - /* Destination is palette based */ + /* Destination is palette based */ + if (src->trueColor) { /* But source is truecolor (Ouch!) */ + toy = dstY; + for (y = srcY; (y < (srcY + h)); y++) { + tox = dstX; + for (x = srcX; (x < (srcX + w)); x++) { + int nc; + c = gdImageGetPixel (src, x, y); - if (src->trueColor) { /* But source is truecolor (Ouch!) */ - toy = dstY; - for (y = srcY; (y < (srcY + h)); y++) - { - tox = dstX; - for (x = srcX; (x < (srcX + w)); x++) - { - int nc; - c = gdImageGetPixel (src, x, y); - - /* Get best match possible. */ - nc = gdImageColorResolveAlpha ( - dst, - gdTrueColorGetRed(c), - gdTrueColorGetGreen(c), - gdTrueColorGetBlue(c), - gdTrueColorGetAlpha(c)); - - gdImageSetPixel (dst, tox, toy, nc); - tox++; - } - toy++; - } - return; - } + /* Get best match possible. */ + nc = gdImageColorResolveAlpha (dst, gdTrueColorGetRed(c), gdTrueColorGetGreen(c), gdTrueColorGetBlue(c), gdTrueColorGetAlpha(c)); - /* Palette based to palette based */ + gdImageSetPixel (dst, tox, toy, nc); + tox++; + } + toy++; + } + return; + } - for (i = 0; (i < gdMaxColors); i++) - { - colorMap[i] = (-1); - } - toy = dstY; - for (y = srcY; (y < (srcY + h)); y++) - { - tox = dstX; - for (x = srcX; (x < (srcX + w)); x++) - { - int nc; - int mapTo; - c = gdImageGetPixel (src, x, y); - /* Added 7/24/95: support transparent copies */ - if (gdImageGetTransparent (src) == c) - { - tox++; - continue; - } - /* Have we established a mapping for this color? */ - if (src->trueColor) - { - /* 2.05: remap to the palette available in the - destination image. This is slow and - works badly, but it beats crashing! Thanks - to Padhrig McCarthy. */ - mapTo = gdImageColorResolveAlpha (dst, - gdTrueColorGetRed (c), - gdTrueColorGetGreen (c), - gdTrueColorGetBlue (c), - gdTrueColorGetAlpha (c)); - } - else if (colorMap[c] == (-1)) - { - /* If it's the same image, mapping is trivial */ - if (dst == src) - { - nc = c; + /* Palette based to palette based */ + for (i = 0; (i < gdMaxColors); i++) { + colorMap[i] = (-1); + } + toy = dstY; + for (y = srcY; (y < (srcY + h)); y++) { + tox = dstX; + for (x = srcX; (x < (srcX + w)); x++) { + int nc; + int mapTo; + c = gdImageGetPixel (src, x, y); + /* Added 7/24/95: support transparent copies */ + if (gdImageGetTransparent (src) == c) { + tox++; + continue; + } + /* Have we established a mapping for this color? */ + if (src->trueColor) { + /* 2.05: remap to the palette available in the destination image. This is slow and + * works badly, but it beats crashing! Thanks to Padhrig McCarthy. + */ + mapTo = gdImageColorResolveAlpha (dst, gdTrueColorGetRed (c), gdTrueColorGetGreen (c), gdTrueColorGetBlue (c), gdTrueColorGetAlpha (c)); + } else if (colorMap[c] == (-1)) { + /* If it's the same image, mapping is trivial */ + if (dst == src) { + nc = c; + } else { + /* Get best match possible. This function never returns error. */ + nc = gdImageColorResolveAlpha (dst, src->red[c], src->green[c], src->blue[c], src->alpha[c]); + } + colorMap[c] = nc; + mapTo = colorMap[c]; + } else { + mapTo = colorMap[c]; + } + gdImageSetPixel (dst, tox, toy, mapTo); + tox++; } - else - { - /* Get best match possible. This - function never returns error. */ - nc = gdImageColorResolveAlpha ( - dst, - src->red[c], src->green[c], - src->blue[c], src->alpha[c]); - } - colorMap[c] = nc; - mapTo = colorMap[c]; - } - else - { - mapTo = colorMap[c]; - } - gdImageSetPixel (dst, tox, toy, mapTo); - tox++; + toy++; } - toy++; - } } /* This function is a substitute for real alpha channel operations, @@ -2230,14 +2250,14 @@ sy = sy1; do { float yportion; - if (floorf(sy) == floorf(sy1)) { - yportion = 1.0f - (sy - floorf(sy)); + if (floor_cast(sy) == floor_cast(sy1)) { + yportion = 1.0f - (sy - floor_cast(sy)); if (yportion > sy2 - sy1) { yportion = sy2 - sy1; } - sy = floorf(sy); + sy = floor_cast(sy); } else if (sy == floorf(sy2)) { - yportion = sy2 - floorf(sy2); + yportion = sy2 - floor_cast(sy2); } else { yportion = 1.0f; } @@ -2248,14 +2268,14 @@ float xportion; float pcontribution; int p; - if (floorf(sx) == floorf(sx1)) { - xportion = 1.0f - (sx - floorf(sx)); + if (floorf(sx) == floor_cast(sx1)) { + xportion = 1.0f - (sx - floor_cast(sx)); if (xportion > sx2 - sx1) { xportion = sx2 - sx1; } - sx = floorf(sx); + sx = floor_cast(sx); } else if (sx == floorf(sx2)) { - xportion = sx2 - floorf(sx2); + xportion = sx2 - floor_cast(sx2); } else { xportion = 1.0f; } Index: php4/ext/gd/libgd/gd.h diff -u php4/ext/gd/libgd/gd.h:1.13 php4/ext/gd/libgd/gd.h:1.14 --- php4/ext/gd/libgd/gd.h:1.13 Sun Jan 5 19:47:40 2003 +++ php4/ext/gd/libgd/gd.h Fri Jan 17 13:34:07 2003 @@ -256,7 +256,6 @@ void gdImageRectangle(gdImagePtr im, int x1, int y1, int x2, int y2, int color); /* Solid bar. Upper left corner first, lower right corner second. */ void gdImageFilledRectangle(gdImagePtr im, int x1, int y1, int x2, int y2, int color); -int gdImageBoundsSafe(gdImagePtr im, int x, int y); void gdImageChar(gdImagePtr im, gdFontPtr f, int x, int y, int c, int color); void gdImageCharUp(gdImagePtr im, gdFontPtr f, int x, int y, int c, int color); void gdImageString(gdImagePtr im, gdFontPtr f, int x, int y, unsigned char *s, int color); @@ -585,5 +584,7 @@ #ifdef __cplusplus } #endif + +#define gdImageBoundsSafe(im, x, y) (!(y < 0 || y >= (im)->sy || x < 0 || x >= (im)->sx)) #endif /* GD_H */ Index: php4/ext/gd/libgd/gd_gd2.c diff -u php4/ext/gd/libgd/gd_gd2.c:1.9 php4/ext/gd/libgd/gd_gd2.c:1.10 --- php4/ext/gd/libgd/gd_gd2.c:1.9 Tue Dec 3 10:43:17 2002 +++ php4/ext/gd/libgd/gd_gd2.c Fri Jan 17 13:34:07 2003 @@ -23,902 +23,767 @@ #define TRUE 1 #define FALSE 0 +/* 2.11: not part of the API, as the save routine can figure it out + * from im->trueColor, and the load routine doesn't need to tell + * the end user the saved format. NOTE: adding 2 is assumed + * to result in the correct format value for truecolor! +*/ +#define GD2_FMT_TRUECOLOR_RAW 3 +#define GD2_FMT_TRUECOLOR_COMPRESSED 4 + +#define gd2_compressed(fmt) (((fmt) == GD2_FMT_COMPRESSED) || ((fmt) == GD2_FMT_TRUECOLOR_COMPRESSED)) +#define gd2_truecolor(fmt) (((fmt) == GD2_FMT_TRUECOLOR_RAW) || ((fmt) == GD2_FMT_TRUECOLOR_COMPRESSED)) + /* Use this for commenting out debug-print statements. */ /* Just use the first '#define' to allow all the prints... */ /* #define GD2_DBG(s) (s) */ #define GD2_DBG(s) typedef struct - { - int offset; - int size; - } +{ + int offset; + int size; +} t_chunk_info; -extern int _gdGetColors (gdIOCtx * in, gdImagePtr im, int gd2xFlag); -extern void _gdPutColors (gdImagePtr im, gdIOCtx * out); +extern int _gdGetColors(gdIOCtx * in, gdImagePtr im, int gd2xFlag); +extern void _gdPutColors(gdImagePtr im, gdIOCtx * out); /* */ /* Read the extra info in the gd2 header. */ /* */ -static -int -_gd2GetHeader (gdIOCtxPtr in, int *sx, int *sy, - int *cs, int *vers, int *fmt, int *ncx, int *ncy, t_chunk_info ** chunkIdx) -{ - int i; - int ch; - char id[5]; - t_chunk_info *cidx; - int sidx; - int nc; - - GD2_DBG(php_gd_error("Reading gd2 header info\n")); - - for (i = 0; i < 4; i++) - { - ch = gdGetC (in); - if (ch == EOF) - { - goto fail1; - }; - id[i] = ch; - }; - id[4] = 0; - - GD2_DBG(php_gd_error("Got file code: %s\n", id)); - - /* Equiv. of 'magick'. */ - if (strcmp (id, GD2_ID) != 0) - { - GD2_DBG(php_gd_error("Not a valid gd2 file\n")); - goto fail1; - }; - - /* Version */ - if (gdGetWord (vers, in) != 1) - { - goto fail1; - }; - GD2_DBG(php_gd_error("Version: %d\n", *vers)); - - if ((*vers != 1) && (*vers != 2)) - { - GD2_DBG(php_gd_error("Bad version: %d\n", *vers)); - goto fail1; - }; - - /* Image Size */ - if (!gdGetWord (sx, in)) - { - GD2_DBG(php_gd_error("Could not get x-size\n")); - goto fail1; - } - if (!gdGetWord (sy, in)) - { - GD2_DBG(php_gd_error("Could not get y-size\n")); - goto fail1; - } - GD2_DBG(php_gd_error("Image is %dx%d\n", *sx, *sy)); - - /* Chunk Size (pixels, not bytes!) */ - if (gdGetWord (cs, in) != 1) - { - goto fail1; - }; - GD2_DBG(php_gd_error("ChunkSize: %d\n", *cs)); - - if ((*cs < GD2_CHUNKSIZE_MIN) || (*cs > GD2_CHUNKSIZE_MAX)) - { - GD2_DBG(php_gd_error("Bad chunk size: %d\n", *cs)); - goto fail1; - }; - - /* Data Format */ - if (gdGetWord (fmt, in) != 1) - { - goto fail1; - }; - GD2_DBG(php_gd_error("Format: %d\n", *fmt)); - - if ((*fmt != GD2_FMT_RAW) && (*fmt != GD2_FMT_COMPRESSED)) - { - GD2_DBG(php_gd_error("Bad data format: %d\n", *fmt)); - goto fail1; - }; - - - /* # of chunks wide */ - if (gdGetWord (ncx, in) != 1) - { - goto fail1; - }; - GD2_DBG(php_gd_error("%d Chunks Wide\n", *ncx)); - - /* # of chunks high */ - if (gdGetWord (ncy, in) != 1) - { - goto fail1; - }; - GD2_DBG(php_gd_error("%d Chunks vertically\n", *ncy)); - - if ((*fmt) == GD2_FMT_COMPRESSED) - { - nc = (*ncx) * (*ncy); - GD2_DBG(php_gd_error("Reading %d chunk index entries\n", nc)); - sidx = sizeof (t_chunk_info) * nc; - cidx = gdCalloc (sidx, 1); - for (i = 0; i < nc; i++) - { - if (gdGetInt (&cidx[i].offset, in) != 1) - { - goto fail1; - }; - if (gdGetInt (&cidx[i].size, in) != 1) - { - goto fail1; - }; - }; - *chunkIdx = cidx; - }; +static int _gd2GetHeader(gdIOCtxPtr in, int *sx, int *sy, int *cs, int *vers, int *fmt, int *ncx, int *ncy, t_chunk_info ** chunkIdx) +{ + int i; + int ch; + char id[5]; + t_chunk_info *cidx; + int sidx; + int nc; + + GD2_DBG(php_gd_error("Reading gd2 header info\n")); + + for (i = 0; i < 4; i++) { + ch = gdGetC(in); + if (ch == EOF) { + goto fail1; + } + id[i] = ch; + } + id[4] = 0; + + GD2_DBG(php_gd_error("Got file code: %s\n", id)); + + /* Equiv. of 'magick'. */ + if (strcmp(id, GD2_ID) != 0) { + GD2_DBG(php_gd_error("Not a valid gd2 file\n")); + goto fail1; + } + + /* Version */ + if (gdGetWord(vers, in) != 1) { + goto fail1; + } + GD2_DBG(php_gd_error("Version: %d\n", *vers)); + + if ((*vers != 1) && (*vers != 2)) { + GD2_DBG(php_gd_error("Bad version: %d\n", *vers)); + goto fail1; + } + + /* Image Size */ + if (!gdGetWord(sx, in)) { + GD2_DBG(php_gd_error("Could not get x-size\n")); + goto fail1; + } + if (!gdGetWord(sy, in)) { + GD2_DBG(php_gd_error("Could not get y-size\n")); + goto fail1; + } + GD2_DBG(php_gd_error("Image is %dx%d\n", *sx, *sy)); + + /* Chunk Size (pixels, not bytes!) */ + if (gdGetWord(cs, in) != 1) { + goto fail1; + } + GD2_DBG(php_gd_error("ChunkSize: %d\n", *cs)); + + if ((*cs < GD2_CHUNKSIZE_MIN) || (*cs > GD2_CHUNKSIZE_MAX)) { + GD2_DBG(php_gd_error("Bad chunk size: %d\n", *cs)); + goto fail1; + } + + /* Data Format */ + if (gdGetWord(fmt, in) != 1) { + goto fail1; + } + GD2_DBG(php_gd_error("Format: %d\n", *fmt)); + + if ((*fmt != GD2_FMT_RAW) && (*fmt != GD2_FMT_COMPRESSED) && (*fmt != GD2_FMT_TRUECOLOR_RAW) && (*fmt != GD2_FMT_TRUECOLOR_COMPRESSED)) { + GD2_DBG(php_gd_error("Bad data format: %d\n", *fmt)); + goto fail1; + } + + /* # of chunks wide */ + if (gdGetWord(ncx, in) != 1) { + goto fail1; + } + GD2_DBG(php_gd_error("%d Chunks Wide\n", *ncx)); - GD2_DBG(php_gd_error("gd2 header complete\n")); + /* # of chunks high */ + if (gdGetWord(ncy, in) != 1) { + goto fail1; + } + GD2_DBG(php_gd_error("%d Chunks vertically\n", *ncy)); - return 1; + if (gd2_compressed(*fmt)) { + nc = (*ncx) * (*ncy); + GD2_DBG(php_gd_error("Reading %d chunk index entries\n", nc)); + sidx = sizeof(t_chunk_info) * nc; + cidx = gdCalloc(sidx, 1); + for (i = 0; i < nc; i++) { + if (gdGetInt(&cidx[i].offset, in) != 1) { + goto fail1; + } + if (gdGetInt(&cidx[i].size, in) != 1) { + goto fail1; + } + } + *chunkIdx = cidx; + } + + GD2_DBG(php_gd_error("gd2 header complete\n")); + + return 1; fail1: - return 0; + return 0; } -static - gdImagePtr -_gd2CreateFromFile (gdIOCtxPtr in, int *sx, int *sy, - int *cs, int *vers, int *fmt, - int *ncx, int *ncy, t_chunk_info ** cidx) -{ - gdImagePtr im; - - if (_gd2GetHeader (in, sx, sy, cs, vers, fmt, ncx, ncy, cidx) != 1) - { - GD2_DBG(php_gd_error("Bad GD2 header\n")); - goto fail1; - } - - im = gdImageCreateTrueColor(*sx, *sy); - if (im == NULL) - { - GD2_DBG(php_gd_error("Could not create gdImage\n")); - goto fail1; - }; - - if (!_gdGetColors (in, im, (*vers) == 2)) - { - GD2_DBG(php_gd_error("Could not read color palette\n")); - goto fail2; - } - GD2_DBG(php_gd_error("Image palette completed: %d colours\n", im->colorsTotal)); +static gdImagePtr _gd2CreateFromFile (gdIOCtxPtr in, int *sx, int *sy, int *cs, int *vers, int *fmt, int *ncx, int *ncy, t_chunk_info ** cidx) +{ + gdImagePtr im; + + if (_gd2GetHeader (in, sx, sy, cs, vers, fmt, ncx, ncy, cidx) != 1) { + GD2_DBG(php_gd_error("Bad GD2 header\n")); + goto fail1; + } - return im; + if (gd2_truecolor(*fmt)) { + im = gdImageCreateTrueColor(*sx, *sy); + } else { + im = gdImageCreate(*sx, *sy); + } + if (im == NULL) { + GD2_DBG(php_gd_error("Could not create gdImage\n")); + goto fail1; + } + + if (!_gdGetColors(in, im, (*vers) == 2)) { + GD2_DBG(php_gd_error("Could not read color palette\n")); + goto fail2; + } + GD2_DBG(php_gd_error("Image palette completed: %d colours\n", im->colorsTotal)); + + return im; fail2: - gdImageDestroy (im); - return 0; + gdImageDestroy(im); + return 0; fail1: - return 0; + return 0; +} + +static int _gd2ReadChunk (int offset, char *compBuf, int compSize, char *chunkBuf, uLongf * chunkLen, gdIOCtx * in) +{ + int zerr; + + if (gdTell(in) != offset) { + GD2_DBG(php_gd_error("Positioning in file to %d\n", offset)); + gdSeek(in, offset); + } else { + GD2_DBG(php_gd_error("Already Positioned in file to %d\n", offset)); + } + + /* Read and uncompress an entire chunk. */ + GD2_DBG(php_gd_error("Reading file\n")); + if (gdGetBuf(compBuf, compSize, in) != compSize) { + return FALSE; + } + GD2_DBG(php_gd_error("Got %d bytes. Uncompressing into buffer of %d bytes\n", compSize, (int)*chunkLen)); + zerr = uncompress((unsigned char *) chunkBuf, chunkLen, (unsigned char *) compBuf, compSize); + if (zerr != Z_OK) { + GD2_DBG(php_gd_error("Error %d from uncompress\n", zerr)); + return FALSE; + } + GD2_DBG(php_gd_error("Got chunk\n")); + + return TRUE; +} + +gdImagePtr gdImageCreateFromGd2 (FILE * inFile) +{ + gdIOCtx *in = gdNewFileCtx(inFile); + gdImagePtr im; + + im = gdImageCreateFromGd2Ctx(in); + in->gd_free(in); + + return im; } -static -int -_gd2ReadChunk (int offset, char *compBuf, int compSize, char *chunkBuf, uLongf * chunkLen, gdIOCtx * in) -{ - int zerr; - - if (gdTell (in) != offset) - { - GD2_DBG(php_gd_error("Positioning in file to %d\n", offset)); - gdSeek (in, offset); - } - else - { - GD2_DBG(php_gd_error("Already Positioned in file to %d\n", offset)); - }; - - /* Read and uncompress an entire chunk. */ - GD2_DBG(php_gd_error("Reading file\n")); - if (gdGetBuf (compBuf, compSize, in) != compSize) - { - return FALSE; - }; - GD2_DBG(php_gd_error("Got %d bytes. Uncompressing into buffer of %d bytes\n", compSize, (int)*chunkLen)); - zerr = uncompress ((unsigned char *) chunkBuf, chunkLen, - (unsigned char *) compBuf, compSize); - if (zerr != Z_OK) - { - GD2_DBG(php_gd_error("Error %d from uncompress\n", zerr)); - return FALSE; - }; - GD2_DBG(php_gd_error("Got chunk\n")); - return TRUE; -} - -gdImagePtr -gdImageCreateFromGd2 (FILE * inFile) -{ - gdIOCtx *in = gdNewFileCtx (inFile); - gdImagePtr im; - - im = gdImageCreateFromGd2Ctx (in); - - in->gd_free (in); - - return im; -} - -gdImagePtr -gdImageCreateFromGd2Ctx (gdIOCtxPtr in) -{ - int sx, sy; - int i; - int ncx, ncy, nc, cs, cx, cy; - int x, y, ylo, yhi, xlo, xhi; - int vers, fmt; - t_chunk_info *chunkIdx = NULL; /* So we can gdFree it with impunity. */ - unsigned char *chunkBuf = NULL; /* So we can gdFree it with impunity. */ - int chunkNum = 0; - int chunkMax = 0; - uLongf chunkLen; - int chunkPos = 0; - int compMax = 0; - int bytesPerPixel; - char *compBuf = NULL; /* So we can gdFree it with impunity. */ - - gdImagePtr im; - - /* Get the header */ - im = _gd2CreateFromFile (in, &sx, &sy, &cs, &vers, &fmt, &ncx, &ncy, &chunkIdx); - - if (im == NULL) - { - return 0; - }; - bytesPerPixel = im->trueColor ? 4 : 1; - nc = ncx * ncy; - - if (fmt == GD2_FMT_COMPRESSED) - { - /* Find the maximum compressed chunk size. */ - compMax = 0; - for (i = 0; (i < nc); i++) - { - if (chunkIdx[i].size > compMax) - { - compMax = chunkIdx[i].size; - }; - }; - compMax++; - - /* Allocate buffers */ - chunkMax = cs * bytesPerPixel * cs; - chunkBuf = gdCalloc (chunkMax, 1); - compBuf = gdCalloc (compMax, 1); - GD2_DBG(php_gd_error("Largest compressed chunk is %d bytes\n", compMax)); - }; - -/* if ( (ncx != sx / cs) || (ncy != sy / cs)) { */ -/* goto fail2; */ -/* }; */ - - /* Read the data... */ - for (cy = 0; (cy < ncy); cy++) - { - for (cx = 0; (cx < ncx); cx++) - { - - ylo = cy * cs; - yhi = ylo + cs; - if (yhi > im->sy) - { - yhi = im->sy; - }; - - GD2_DBG(php_gd_error("Processing Chunk %d (%d, %d), y from %d to %d\n", chunkNum, cx, cy, ylo, yhi)); - - if (fmt == GD2_FMT_COMPRESSED) - { - - chunkLen = chunkMax; - - if (!_gd2ReadChunk (chunkIdx[chunkNum].offset, - compBuf, - chunkIdx[chunkNum].size, - chunkBuf, &chunkLen, in)) - { - GD2_DBG(php_gd_error("Error reading comproessed chunk\n")); - goto fail2; - }; - - chunkPos = 0; - }; - - for (y = ylo; (y < yhi); y++) - { - - xlo = cx * cs; - xhi = xlo + cs; - if (xhi > im->sx) - { - xhi = im->sx; - }; - /*GD2_DBG(php_gd_error("y=%d: ",y)); */ - if (fmt == GD2_FMT_RAW) - { - for (x = xlo; x < xhi; x++) - { - - if (im->trueColor) - { - if (!gdGetInt (&im->tpixels[y][x], in)) - { - /*php_gd_error("EOF while reading\n"); */ - /*gdImageDestroy(im); */ - /*return 0; */ - im->tpixels[y][x] = 0; - } - } - else - { - int ch; - if (!gdGetByte (&ch, in)) - { - /*php_gd_error("EOF while reading\n"); */ - /*gdImageDestroy(im); */ - /*return 0; */ - ch = 0; - } - im->pixels[y][x] = ch; +gdImagePtr gdImageCreateFromGd2Ctx (gdIOCtxPtr in) +{ + int sx, sy; + int i; + int ncx, ncy, nc, cs, cx, cy; + int x, y, ylo, yhi, xlo, xhi; + int vers, fmt; + t_chunk_info *chunkIdx = NULL; /* So we can gdFree it with impunity. */ + unsigned char *chunkBuf = NULL; /* So we can gdFree it with impunity. */ + int chunkNum = 0; + int chunkMax = 0; + uLongf chunkLen; + int chunkPos = 0; + int compMax = 0; + int bytesPerPixel; + char *compBuf = NULL; /* So we can gdFree it with impunity. */ + + gdImagePtr im; + + /* Get the header */ + if (!(im = _gd2CreateFromFile(in, &sx, &sy, &cs, &vers, &fmt, &ncx, &ncy, &chunkIdx))) { + return 0; + } + + bytesPerPixel = im->trueColor ? 4 : 1; + nc = ncx * ncy; + + if (gd2_compressed(fmt)) { + /* Find the maximum compressed chunk size. */ + compMax = 0; + for (i = 0; (i < nc); i++) { + if (chunkIdx[i].size > compMax) { + compMax = chunkIdx[i].size; + } + } + compMax++; + + /* Allocate buffers */ + chunkMax = cs * bytesPerPixel * cs; + chunkBuf = gdCalloc(chunkMax, 1); + compBuf = gdCalloc(compMax, 1); + + GD2_DBG(php_gd_error("Largest compressed chunk is %d bytes\n", compMax)); + } + + /* Read the data... */ + for (cy = 0; (cy < ncy); cy++) { + for (cx = 0; (cx < ncx); cx++) { + ylo = cy * cs; + yhi = ylo + cs; + if (yhi > im->sy) { + yhi = im->sy; + } + + GD2_DBG(php_gd_error("Processing Chunk %d (%d, %d), y from %d to %d\n", chunkNum, cx, cy, ylo, yhi)); + + if (gd2_compressed(fmt)) { + chunkLen = chunkMax; + + if (!_gd2ReadChunk(chunkIdx[chunkNum].offset, compBuf, chunkIdx[chunkNum].size, chunkBuf, &chunkLen, in)) { + GD2_DBG(php_gd_error("Error reading comproessed chunk\n")); + goto fail2; + } + + chunkPos = 0; + } + + for (y = ylo; (y < yhi); y++) { + xlo = cx * cs; + xhi = xlo + cs; + if (xhi > im->sx) { + xhi = im->sx; + } + + if (!gd2_compressed(fmt)) { + for (x = xlo; x < xhi; x++) { + if (im->trueColor) { + if (!gdGetInt(&im->tpixels[y][x], in)) { + im->tpixels[y][x] = 0; + } + } else { + int ch; + if (!gdGetByte(&ch, in)) { + ch = 0; + } + im->pixels[y][x] = ch; + } + } + } else { + for (x = xlo; x < xhi; x++) { + if (im->trueColor) { + /* 2.0.1: work around a gcc bug by being verbose. TBB */ + int a = chunkBuf[chunkPos++] << 24; + int r = chunkBuf[chunkPos++] << 16; + int g = chunkBuf[chunkPos++] << 8; + int b = chunkBuf[chunkPos++]; + im->tpixels[y][x] = a + r + g + b; + } else { + im->pixels[y][x] = chunkBuf[chunkPos++]; + } + } + } } - } + chunkNum++; } - else - { - for (x = xlo; x < xhi; x++) - { - if (im->trueColor) - { - /* 2.0.1: work around a gcc bug by being verbose. - TBB */ - int a = chunkBuf[chunkPos++] << 24; - int r = chunkBuf[chunkPos++] << 16; - int g = chunkBuf[chunkPos++] << 8; - int b = chunkBuf[chunkPos++]; - im->tpixels[y][x] = a + r + g + b; - } - else - { - im->pixels[y][x] = chunkBuf[chunkPos++]; - } - }; - }; - /*GD2_DBG(php_gd_error("\n")); */ - }; - chunkNum++; - }; - }; - - GD2_DBG(php_gd_error("Freeing memory\n")); - - gdFree (chunkBuf); - gdFree (compBuf); - gdFree (chunkIdx); + } - GD2_DBG(php_gd_error("Done\n")); + GD2_DBG(php_gd_error("Freeing memory\n")); - return im; + if (chunkBuf) { + gdFree(chunkBuf); + } + if (compBuf) { + gdFree(compBuf); + } + if (chunkIdx) { + gdFree(chunkIdx); + } + + GD2_DBG(php_gd_error("Done\n")); + + return im; fail2: - gdImageDestroy (im); - gdFree (chunkBuf); - gdFree (compBuf); - gdFree (chunkIdx); - return 0; - -} - -gdImagePtr -gdImageCreateFromGd2Part (FILE * inFile, int srcx, int srcy, int w, int h) -{ - gdImagePtr im; - gdIOCtx *in = gdNewFileCtx (inFile); - - im = gdImageCreateFromGd2PartCtx (in, srcx, srcy, w, h); - - in->gd_free (in); - - return im; -} - -gdImagePtr -gdImageCreateFromGd2PartCtx (gdIOCtx * in, int srcx, int srcy, int w, int h) -{ - int scx, scy, ecx, ecy, fsx, fsy; - int nc, ncx, ncy, cs, cx, cy; - int x, y, ylo, yhi, xlo, xhi; - int dstart, dpos; - int i; - int ch, vers, fmt; - t_chunk_info *chunkIdx = NULL; - char *chunkBuf = NULL; - int chunkNum; - int chunkMax = 0; - uLongf chunkLen; - int chunkPos = 0; - int compMax; - char *compBuf = NULL; - - gdImagePtr im; - - /* */ - /* The next few lines are basically copied from gd2CreateFromFile */ - /* - we change the file size, so don't want to use the code directly. */ - /* but we do need to know the file size. */ - /* */ - if (_gd2GetHeader (in, &fsx, &fsy, &cs, &vers, &fmt, &ncx, &ncy, &chunkIdx) != 1) - { - goto fail1; - } - - GD2_DBG(php_gd_error("File size is %dx%d\n", fsx, fsy)); - - /* This is the difference - make a file based on size of chunks. */ - im = gdImageCreate (w, h); - if (im == NULL) - { - goto fail1; - }; - - if (!_gdGetColors (in, im, vers == 2)) - { - goto fail2; - } - GD2_DBG(php_gd_error("Image palette completed: %d colours\n", im->colorsTotal)); - - /* Process the header info */ - nc = ncx * ncy; - - if (fmt == GD2_FMT_COMPRESSED) - { - /* Find the maximum compressed chunk size. */ - compMax = 0; - for (i = 0; (i < nc); i++) - { - if (chunkIdx[i].size > compMax) - { - compMax = chunkIdx[i].size; - }; - }; - compMax++; - - if (im->trueColor) - { - chunkMax = cs * cs * 4; - } - else - { - chunkMax = cs * cs; - } - chunkBuf = gdCalloc (chunkMax, 1); - compBuf = gdCalloc (compMax, 1); - }; - -/* Don't bother with this... */ -/* if ( (ncx != sx / cs) || (ncy != sy / cs)) { */ -/* goto fail2; */ -/* }; */ - - - /* Work out start/end chunks */ - scx = srcx / cs; - scy = srcy / cs; - if (scx < 0) - { - scx = 0; - }; - if (scy < 0) - { - scy = 0; - }; - - ecx = (srcx + w) / cs; - ecy = (srcy + h) / cs; - if (ecx >= ncx) - { - ecx = ncx - 1; - }; - if (ecy >= ncy) - { - ecy = ncy - 1; - }; - - /* Remember file position of image data. */ - dstart = gdTell (in); - GD2_DBG(php_gd_error("Data starts at %d\n", dstart)); - - /* Loop through the chunks. */ - for (cy = scy; (cy <= ecy); cy++) - { - - ylo = cy * cs; - yhi = ylo + cs; - if (yhi > fsy) - { - yhi = fsy; - }; - - for (cx = scx; (cx <= ecx); cx++) - { - - xlo = cx * cs; - xhi = xlo + cs; - if (xhi > fsx) - { - xhi = fsx; - }; - - GD2_DBG(php_gd_error("Processing Chunk (%d, %d), from %d to %d\n", cx, cy, ylo, yhi)); - - if (fmt == GD2_FMT_RAW) - { - GD2_DBG(php_gd_error("Using raw format data\n")); - if (im->trueColor) - { - dpos = (cy * (cs * fsx) + cx * cs * (yhi - ylo) * 4) + dstart; + gdImageDestroy(im); + if (chunkBuf) { + gdFree(chunkBuf); + } + if (compBuf) { + gdFree(compBuf); + } + if (chunkIdx) { + gdFree(chunkIdx); + } + + return 0; +} + +gdImagePtr gdImageCreateFromGd2Part (FILE * inFile, int srcx, int srcy, int w, int h) +{ + gdImagePtr im; + gdIOCtx *in = gdNewFileCtx(inFile); + + im = gdImageCreateFromGd2PartCtx(in, srcx, srcy, w, h); + + in->gd_free(in); + + return im; +} + +gdImagePtr gdImageCreateFromGd2PartCtx (gdIOCtx * in, int srcx, int srcy, int w, int h) +{ + int scx, scy, ecx, ecy, fsx, fsy; + int nc, ncx, ncy, cs, cx, cy; + int x, y, ylo, yhi, xlo, xhi; + int dstart, dpos; + int i; + int ch, vers, fmt; + t_chunk_info *chunkIdx = NULL; + char *chunkBuf = NULL; + int chunkNum; + int chunkMax = 0; + uLongf chunkLen; + int chunkPos = 0; + int compMax; + char *compBuf = NULL; + + gdImagePtr im; + + /* The next few lines are basically copied from gd2CreateFromFile + * we change the file size, so don't want to use the code directly. + * but we do need to know the file size. + */ + if (_gd2GetHeader(in, &fsx, &fsy, &cs, &vers, &fmt, &ncx, &ncy, &chunkIdx) != 1) { + goto fail1; + } + + GD2_DBG(php_gd_error("File size is %dx%d\n", fsx, fsy)); + + /* This is the difference - make a file based on size of chunks. */ + if (gd2_truecolor(fmt)) { + im = gdImageCreateTrueColor(w, h); + } else { + im = gdImageCreate(w, h); + } + if (im == NULL) { + goto fail1; + } + + if (!_gdGetColors(in, im, vers == 2)) { + goto fail2; + } + GD2_DBG(php_gd_error("Image palette completed: %d colours\n", im->colorsTotal)); + + /* Process the header info */ + nc = ncx * ncy; + + if (gd2_compressed(fmt)) { + /* Find the maximum compressed chunk size. */ + compMax = 0; + for (i = 0; (i < nc); i++) { + if (chunkIdx[i].size > compMax) { + compMax = chunkIdx[i].size; + } + } + compMax++; + + if (im->trueColor) { + chunkMax = cs * cs * 4; + } else { + chunkMax = cs * cs; } - else - { - dpos = cy * (cs * fsx) + cx * cs * (yhi - ylo) + dstart; + chunkBuf = gdCalloc(chunkMax, 1); + compBuf = gdCalloc(compMax, 1); + } + + /* Work out start/end chunks */ + scx = srcx / cs; + scy = srcy / cs; + if (scx < 0) { + scx = 0; + } + if (scy < 0) { + scy = 0; + } + + ecx = (srcx + w) / cs; + ecy = (srcy + h) / cs; + if (ecx >= ncx) { + ecx = ncx - 1; + } + if (ecy >= ncy) { + ecy = ncy - 1; + } + + /* Remember file position of image data. */ + dstart = gdTell(in); + GD2_DBG(php_gd_error("Data starts at %d\n", dstart)); + + /* Loop through the chunks. */ + for (cy = scy; (cy <= ecy); cy++) { + ylo = cy * cs; + yhi = ylo + cs; + if (yhi > fsy) { + yhi = fsy; } - if (gdSeek (in, dpos) != 0) - { - php_gd_error_ex(E_WARNING, "Error from seek: %d\n", errno); - goto fail2; - }; - GD2_DBG(php_gd_error("Reading (%d, %d) from position %d\n", cx, cy, dpos - dstart)); - } - else - { - chunkNum = cx + cy * ncx; - - chunkLen = chunkMax; - if (!_gd2ReadChunk (chunkIdx[chunkNum].offset, - compBuf, - chunkIdx[chunkNum].size, - chunkBuf, &chunkLen, in)) - { - php_gd_error("Error reading comproessed chunk\n"); - goto fail2; - }; - chunkPos = 0; - GD2_DBG(php_gd_error("Reading (%d, %d) from chunk %d\n", cx, cy, chunkNum)); - }; - - GD2_DBG(php_gd_error(" into (%d, %d) - (%d, %d)\n", xlo, ylo, xhi, yhi)); - for (y = ylo; (y < yhi); y++) - { - - for (x = xlo; x < xhi; x++) - { - if (fmt == GD2_FMT_RAW) - { - if (im->trueColor) - { - if (!gdGetInt (&ch, in)) - { - ch = 0; - /*php_gd_error("EOF while reading file\n"); */ - /*goto fail2; */ - } - } - else - { - ch = gdGetC (in); - if (ch == EOF) - { - ch = 0; - /*php_gd_error("EOF while reading file\n"); */ - /*goto fail2; */ - } - } - } - else - { - if (im->trueColor) - { - ch = chunkBuf[chunkPos++]; - ch = (ch << 8) + chunkBuf[chunkPos++]; - ch = (ch << 8) + chunkBuf[chunkPos++]; - ch = (ch << 8) + chunkBuf[chunkPos++]; - } - else - { - ch = chunkBuf[chunkPos++]; - } - }; - - /* Only use a point that is in the image. */ - if ((x >= srcx) && (x < (srcx + w)) && (x < fsx) && (x >= 0) - && (y >= srcy) && (y < (srcy + h)) && (y < fsy) && (y >= 0) - ) - { - im->pixels[y - srcy][x - srcx] = ch; - } - }; - }; - }; - }; - - gdFree (chunkBuf); - gdFree (compBuf); - gdFree (chunkIdx); + for (cx = scx; cx <= ecx; cx++) { - return im; + xlo = cx * cs; + xhi = xlo + cs; + if (xhi > fsx) { + xhi = fsx; + } + + GD2_DBG(php_gd_error("Processing Chunk (%d, %d), from %d to %d\n", cx, cy, ylo, yhi)); + + if (!gd2_compressed(fmt)) { + GD2_DBG(php_gd_error("Using raw format data\n")); + if (im->trueColor) { + dpos = (cy * (cs * fsx) * 4 + cx * cs * (yhi - ylo) * 4) + dstart; + } else { + dpos = cy * (cs * fsx) + cx * cs * (yhi - ylo) + dstart; + } + + /* gd 2.0.11: gdSeek returns TRUE on success, not 0. Longstanding bug. 01/16/03 */ + if (!gdSeek(in, dpos)) { + php_gd_error_ex(E_WARNING, "Error from seek: %d\n", errno); + goto fail2; + } + GD2_DBG(php_gd_error("Reading (%d, %d) from position %d\n", cx, cy, dpos - dstart)); + } else { + chunkNum = cx + cy * ncx; + + chunkLen = chunkMax; + if (!_gd2ReadChunk (chunkIdx[chunkNum].offset, compBuf, chunkIdx[chunkNum].size, chunkBuf, &chunkLen, in)) { + php_gd_error("Error reading comproessed chunk\n"); + goto fail2; + } + chunkPos = 0; + GD2_DBG(php_gd_error("Reading (%d, %d) from chunk %d\n", cx, cy, chunkNum)); + } + + GD2_DBG(php_gd_error(" into (%d, %d) - (%d, %d)\n", xlo, ylo, xhi, yhi)); + + for (y = ylo; (y < yhi); y++) { + for (x = xlo; x < xhi; x++) { + if (!gd2_compressed(fmt)) { + if (im->trueColor) { + if (!gdGetInt(&ch, in)) { + ch = 0; + } + } else { + ch = gdGetC(in); + if (ch == EOF) { + ch = 0; + } + } + } else { + if (im->trueColor) { + ch = chunkBuf[chunkPos++]; + ch = (ch << 8) + chunkBuf[chunkPos++]; + ch = (ch << 8) + chunkBuf[chunkPos++]; + ch = (ch << 8) + chunkBuf[chunkPos++]; + } else { + ch = chunkBuf[chunkPos++]; + } + } + + /* Only use a point that is in the image. */ + if ((x >= srcx) && (x < (srcx + w)) && (x < fsx) && (x >= 0) && (y >= srcy) && (y < (srcy + h)) && (y < fsy) && (y >= 0)) { + if (im->trueColor) { + im->tpixels[y - srcy][x - srcx] = ch; + } else { + im->pixels[y - srcy][x - srcx] = ch; + } + } + } + } + } + } + + if (chunkBuf) { + gdFree(chunkBuf); + } + if (compBuf) { + gdFree(compBuf); + } + if (chunkIdx) { + gdFree(chunkIdx); + } + + return im; fail2: - gdImageDestroy (im); + gdImageDestroy(im); fail1: - gdFree (chunkBuf); - gdFree (compBuf); - gdFree (chunkIdx); - - return 0; - -} - -static -void -_gd2PutHeader (gdImagePtr im, gdIOCtx * out, int cs, int fmt, int cx, int cy) -{ - int i; - - /* Send the gd2 id, to verify file format. */ - for (i = 0; i < 4; i++) - { - gdPutC ((unsigned char) (GD2_ID[i]), out); - }; - - /* */ - /* We put the version info first, so future versions can easily change header info. */ - /* */ - gdPutWord (GD2_VERS, out); - gdPutWord (im->sx, out); - gdPutWord (im->sy, out); - gdPutWord (cs, out); - gdPutWord (fmt, out); - gdPutWord (cx, out); - gdPutWord (cy, out); - -} - -static void -_gdImageGd2 (gdImagePtr im, gdIOCtx * out, int cs, int fmt) -{ - int ncx, ncy, cx, cy; - int x, y, ylo, yhi, xlo, xhi; - int chunkLen; - int chunkNum = 0; - char *chunkData = NULL; /* So we can gdFree it with impunity. */ - char *compData = NULL; /* So we can gdFree it with impunity. */ - uLongf compLen; - int idxPos = 0; - int idxSize; - t_chunk_info *chunkIdx = NULL; - int posSave; - int bytesPerPixel = im->trueColor ? 4 : 1; - int compMax = 0; - - /*php_gd_error("Trying to write GD2 file\n"); */ - - /* */ - /* Force fmt to a valid value since we don't return anything. */ - /* */ - if ((fmt == 0) || ((fmt != GD2_FMT_RAW) && (fmt != GD2_FMT_COMPRESSED))) - { - fmt = GD2_FMT_COMPRESSED; - }; - - /* */ - /* Make sure chunk size is valid. These are arbitrary values; 64 because it seems */ - /* a little silly to expect performance improvements on a 64x64 bit scale, and */ - /* 4096 because we buffer one chunk, and a 16MB buffer seems a little largei - it may be */ - /* OK for one user, but for another to read it, they require the buffer. */ - /* */ - if (cs == 0) - { - cs = GD2_CHUNKSIZE; - } - else if (cs < GD2_CHUNKSIZE_MIN) - { - cs = GD2_CHUNKSIZE_MIN; - } - else if (cs > GD2_CHUNKSIZE_MAX) - { - cs = GD2_CHUNKSIZE_MAX; - }; - - /* Work out number of chunks. */ - ncx = im->sx / cs + 1; - ncy = im->sy / cs + 1; - - /* Write the standard header. */ - _gd2PutHeader (im, out, cs, fmt, ncx, ncy); - - if (fmt == GD2_FMT_COMPRESSED) - { - /* */ - /* Work out size of buffer for compressed data, If CHUNKSIZE is large, */ - /* then these will be large! */ - /* */ - /* The zlib notes say output buffer size should be (input size) * 1.01 * 12 */ - /* - we'll use 1.02 to be paranoid. */ - /* */ - compMax = (int)(cs * bytesPerPixel * cs * 1.02f) + 12; - - /* */ - /* Allocate the buffers. */ - /* */ - chunkData = gdCalloc (cs * bytesPerPixel * cs, 1); - compData = gdCalloc (compMax, 1); - - /* */ - /* Save the file position of chunk index, and allocate enough space for */ - /* each chunk_info block . */ - /* */ - idxPos = gdTell (out); - idxSize = ncx * ncy * sizeof (t_chunk_info); - GD2_DBG(php_gd_error("Index size is %d\n", idxSize)); - gdSeek (out, idxPos + idxSize); - - chunkIdx = gdCalloc (idxSize * sizeof (t_chunk_info), 1); - }; - - _gdPutColors (im, out); - - GD2_DBG(php_gd_error("Size: %dx%d\n", im->sx, im->sy)); - GD2_DBG(php_gd_error("Chunks: %dx%d\n", ncx, ncy)); - - for (cy = 0; (cy < ncy); cy++) - { - for (cx = 0; (cx < ncx); cx++) - { - - ylo = cy * cs; - yhi = ylo + cs; - if (yhi > im->sy) - { - yhi = im->sy; - }; - - GD2_DBG(php_gd_error("Processing Chunk (%dx%d), y from %d to %d\n", cx, cy, ylo, yhi)); - chunkLen = 0; - for (y = ylo; (y < yhi); y++) - { - - GD2_DBG(php_gd_error("y=%d: ",y)); - - xlo = cx * cs; - xhi = xlo + cs; - if (xhi > im->sx) - { - xhi = im->sx; - }; - - if (fmt == GD2_FMT_COMPRESSED) - { - for (x = xlo; x < xhi; x++) - { - GD2_DBG(php_gd_error("%d...",x)); - if (im->trueColor) - { - int p = im->tpixels[y][x]; - chunkData[chunkLen++] = gdTrueColorGetAlpha (p); - chunkData[chunkLen++] = gdTrueColorGetRed (p); - chunkData[chunkLen++] = gdTrueColorGetGreen (p); - chunkData[chunkLen++] = gdTrueColorGetBlue (p); - } - else - { - chunkData[chunkLen++] = im->pixels[y][x]; + if (chunkBuf) { + gdFree(chunkBuf); + } + if (compBuf) { + gdFree(compBuf); + } + if (chunkIdx) { + gdFree(chunkIdx); + } + + return 0; +} + +static void _gd2PutHeader (gdImagePtr im, gdIOCtx * out, int cs, int fmt, int cx, int cy) +{ + int i; + + /* Send the gd2 id, to verify file format. */ + for (i = 0; i < 4; i++) { + gdPutC((unsigned char) (GD2_ID[i]), out); + } + + /* We put the version info first, so future versions can easily change header info. */ + + gdPutWord(GD2_VERS, out); + gdPutWord(im->sx, out); + gdPutWord(im->sy, out); + gdPutWord(cs, out); + gdPutWord(fmt, out); + gdPutWord(cx, out); + gdPutWord(cy, out); +} + +static void _gdImageGd2 (gdImagePtr im, gdIOCtx * out, int cs, int fmt) +{ + int ncx, ncy, cx, cy; + int x, y, ylo, yhi, xlo, xhi; + int chunkLen; + int chunkNum = 0; + char *chunkData = NULL; /* So we can gdFree it with impunity. */ + char *compData = NULL; /* So we can gdFree it with impunity. */ + uLongf compLen; + int idxPos = 0; + int idxSize; + t_chunk_info *chunkIdx = NULL; /* So we can gdFree it with impunity. */ + int posSave; + int bytesPerPixel = im->trueColor ? 4 : 1; + int compMax = 0; + + /* Force fmt to a valid value since we don't return anything. */ + if ((fmt != GD2_FMT_RAW) && (fmt != GD2_FMT_COMPRESSED)) { + fmt = im->trueColor ? GD2_FMT_TRUECOLOR_COMPRESSED : GD2_FMT_COMPRESSED; + } + if (im->trueColor) { + fmt += 2; + } + /* Make sure chunk size is valid. These are arbitrary values; 64 because it seems + * a little silly to expect performance improvements on a 64x64 bit scale, and + * 4096 because we buffer one chunk, and a 16MB buffer seems a little large - it may be + * OK for one user, but for another to read it, they require the buffer. + */ + if (cs == 0) { + cs = GD2_CHUNKSIZE; + } else if (cs < GD2_CHUNKSIZE_MIN) { + cs = GD2_CHUNKSIZE_MIN; + } else if (cs > GD2_CHUNKSIZE_MAX) { + cs = GD2_CHUNKSIZE_MAX; + } + + /* Work out number of chunks. */ + ncx = im->sx / cs + 1; + ncy = im->sy / cs + 1; + + /* Write the standard header. */ + _gd2PutHeader (im, out, cs, fmt, ncx, ncy); + + if (gd2_compressed(fmt)) { + /* Work out size of buffer for compressed data, If CHUNKSIZE is large, + * then these will be large! + */ + + /* The zlib notes say output buffer size should be (input size) * 1.01 * 12 + * - we'll use 1.02 to be paranoid. + */ + compMax = (int)(cs * bytesPerPixel * cs * 1.02f) + 12; + + /* Allocate the buffers. */ + chunkData = gdCalloc(cs * bytesPerPixel * cs, 1); + compData = gdCalloc(compMax, 1); + + /* Save the file position of chunk index, and allocate enough space for + * each chunk_info block . + */ + idxPos = gdTell(out); + idxSize = ncx * ncy * sizeof(t_chunk_info); + GD2_DBG(php_gd_error("Index size is %d\n", idxSize)); + gdSeek(out, idxPos + idxSize); + + chunkIdx = gdCalloc(idxSize * sizeof(t_chunk_info), 1); + } + + _gdPutColors (im, out); + + GD2_DBG(php_gd_error("Size: %dx%d\n", im->sx, im->sy)); + GD2_DBG(php_gd_error("Chunks: %dx%d\n", ncx, ncy)); + + for (cy = 0; (cy < ncy); cy++) { + for (cx = 0; (cx < ncx); cx++) { + ylo = cy * cs; + yhi = ylo + cs; + if (yhi > im->sy) { + yhi = im->sy; + } + + GD2_DBG(php_gd_error("Processing Chunk (%dx%d), y from %d to %d\n", cx, cy, ylo, yhi)); + chunkLen = 0; + for (y = ylo; (y < yhi); y++) { + GD2_DBG(php_gd_error("y=%d: ",y)); + xlo = cx * cs; + xhi = xlo + cs; + if (xhi > im->sx) { + xhi = im->sx; + } + + if (gd2_compressed(fmt)) { + for (x = xlo; x < xhi; x++) { + GD2_DBG(php_gd_error("%d...",x)); + if (im->trueColor) { + int p = im->tpixels[y][x]; + chunkData[chunkLen++] = gdTrueColorGetAlpha(p); + chunkData[chunkLen++] = gdTrueColorGetRed(p); + chunkData[chunkLen++] = gdTrueColorGetGreen(p); + chunkData[chunkLen++] = gdTrueColorGetBlue(p); + } else { + chunkData[chunkLen++] = im->pixels[y][x]; + } + } + } else { + for (x = xlo; x < xhi; x++) { + GD2_DBG(php_gd_error("%d, ",x)); + + if (im->trueColor) { + gdPutInt(im->tpixels[y][x], out); + } else { + gdPutC((unsigned char) im->pixels[y][x], out); + } + } + } + GD2_DBG(php_gd_error("y=%d done.\n",y)); + } + + if (gd2_compressed(fmt)) { + compLen = compMax; + if (compress((unsigned char *) &compData[0], &compLen, (unsigned char *) &chunkData[0], chunkLen) != Z_OK) { + php_gd_error("Error from compressing\n"); + } else { + chunkIdx[chunkNum].offset = gdTell(out); + chunkIdx[chunkNum++].size = compLen; + GD2_DBG(php_gd_error("Chunk %d size %d offset %d\n", chunkNum, chunkIdx[chunkNum - 1].size, chunkIdx[chunkNum - 1].offset)); + + if (gdPutBuf (compData, compLen, out) <= 0) { + /* Any alternate suggestions for handling this? */ + php_gd_error_ex(E_WARNING, "Error %d on write\n", errno); + } + } } - }; } - else - { - for (x = xlo; x < xhi; x++) - { - GD2_DBG(php_gd_error("%d, ",x)); - - if (im->trueColor) - { - gdPutInt (im->tpixels[y][x], out); - } - else - { - gdPutC ((unsigned char) im->pixels[y][x], out); - } - }; - }; - GD2_DBG(php_gd_error("y=%d done.\n",y)); - }; - if (fmt == GD2_FMT_COMPRESSED) - { - compLen = compMax; - if (compress ((unsigned char *) - &compData[0], &compLen, - (unsigned char *) &chunkData[0], - chunkLen) != Z_OK) - { - php_gd_error ("Error from compressing\n"); + } + + if (gd2_compressed(fmt)) { + /* Save the position, write the index, restore position (paranoia). */ + GD2_DBG(php_gd_error("Seeking %d to write index\n", idxPos)); + posSave = gdTell(out); + gdSeek(out, idxPos); + GD2_DBG(php_gd_error("Writing index\n")); + for (x = 0; x < chunkNum; x++) { + GD2_DBG(php_gd_error("Chunk %d size %d offset %d\n", x, chunkIdx[x].size, chunkIdx[x].offset)); + gdPutInt(chunkIdx[x].offset, out); + gdPutInt(chunkIdx[x].size, out); } - else - { - chunkIdx[chunkNum].offset = gdTell (out); - chunkIdx[chunkNum++].size = compLen; - GD2_DBG(php_gd_error("Chunk %d size %d offset %d\n", chunkNum, chunkIdx[chunkNum - 1].size, chunkIdx[chunkNum - 1].offset)); - - if (gdPutBuf (compData, compLen, out) <= 0) - { - /* Any alternate suggestions for handling this? */ - php_gd_error_ex (E_WARNING, "Error %d on write\n", errno); - }; - }; - }; - }; - }; - if (fmt == GD2_FMT_COMPRESSED) - { - /* Save the position, write the index, restore position (paranoia). */ - GD2_DBG(php_gd_error("Seeking %d to write index\n", idxPos)); - posSave = gdTell (out); - gdSeek (out, idxPos); - GD2_DBG(php_gd_error("Writing index\n")); - for (x = 0; x < chunkNum; x++) - { - GD2_DBG(php_gd_error("Chunk %d size %d offset %d\n", x, chunkIdx[x].size, chunkIdx[x].offset)); - gdPutInt (chunkIdx[x].offset, out); - gdPutInt (chunkIdx[x].size, out); - }; - /* We don't use fwrite for *endian reasons. */ - /*fwrite(chunkIdx, sizeof(int)*2, chunkNum, out); */ - gdSeek (out, posSave); - }; - - GD2_DBG(php_gd_error("Freeing memory\n")); - gdFree (chunkData); - gdFree (compData); - gdFree (chunkIdx); - GD2_DBG(php_gd_error("Done\n")); - - /*php_gd_error("Memory block size is %d\n",gdTell(out)); */ + gdSeek(out, posSave); + } + GD2_DBG(php_gd_error("Freeing memory\n")); + if (chunkData) { + gdFree(chunkData); + } + if (compData) { + gdFree(compData); + } + if (chunkIdx) { + gdFree(chunkIdx); + } + GD2_DBG(php_gd_error("Done\n")); } -void -gdImageGd2 (gdImagePtr im, FILE * outFile, int cs, int fmt) -{ - gdIOCtx *out = gdNewFileCtx (outFile); - _gdImageGd2 (im, out, cs, fmt); - out->gd_free (out); -} - -void * -gdImageGd2Ptr (gdImagePtr im, int cs, int fmt, int *size) -{ - void *rv; - gdIOCtx *out = gdNewDynamicCtx (2048, NULL); - _gdImageGd2 (im, out, cs, fmt); - rv = gdDPExtractData (out, size); - out->gd_free (out); - return rv; +void gdImageGd2 (gdImagePtr im, FILE * outFile, int cs, int fmt) +{ + gdIOCtx *out = gdNewFileCtx(outFile); + + _gdImageGd2(im, out, cs, fmt); + + out->gd_free(out); +} + +void *gdImageGd2Ptr (gdImagePtr im, int cs, int fmt, int *size) +{ + void *rv; + gdIOCtx *out = gdNewDynamicCtx(2048, NULL); + + _gdImageGd2(im, out, cs, fmt); + rv = gdDPExtractData(out, size); + out->gd_free(out); + + return rv; } Index: php4/ext/gd/libgd/gd_jpeg.c diff -u php4/ext/gd/libgd/gd_jpeg.c:1.9 php4/ext/gd/libgd/gd_jpeg.c:1.10 --- php4/ext/gd/libgd/gd_jpeg.c:1.9 Sun Dec 1 06:43:54 2002 +++ php4/ext/gd/libgd/gd_jpeg.c Fri Jan 17 13:34:07 2003 @@ -16,6 +16,9 @@ * Modification 4/18/00 TBB: JPEG_DEBUG rather than just DEBUG, * so VC++ builds don't spew to standard output, causing * major CGI brain damage + * + * 2.0.10: more efficient gdImageCreateFromJpegCtx, thanks to + * Christian Aberger */ #include <stdio.h> @@ -38,36 +41,30 @@ static const char *const GD_JPEG_VERSION = "1.0"; typedef struct _jmpbuf_wrapper - { - jmp_buf jmpbuf; - } -jmpbuf_wrapper; +{ + jmp_buf jmpbuf; +} jmpbuf_wrapper; /* Called by the IJG JPEG library upon encountering a fatal error */ static void fatal_jpeg_error (j_common_ptr cinfo) { - jmpbuf_wrapper *jmpbufw; + jmpbuf_wrapper *jmpbufw; - php_gd_error("gd-jpeg: JPEG library reports unrecoverable error: "); - (*cinfo->err->output_message) (cinfo); + php_gd_error("gd-jpeg: JPEG library reports unrecoverable error: "); + (*cinfo->err->output_message) (cinfo); - jmpbufw = (jmpbuf_wrapper *) cinfo->client_data; - jpeg_destroy (cinfo); + jmpbufw = (jmpbuf_wrapper *) cinfo->client_data; + jpeg_destroy (cinfo); - if (jmpbufw != 0) - { - longjmp (jmpbufw->jmpbuf, 1); - php_gd_error_ex(E_ERROR, "gd-jpeg: EXTREMELY fatal error: longjmp" - " returned control; terminating\n"); - } - else - { - php_gd_error_ex(E_ERROR, "gd-jpeg: EXTREMELY fatal error: jmpbuf" - " unrecoverable; terminating\n"); - } + if (jmpbufw != 0) { + longjmp (jmpbufw->jmpbuf, 1); + php_gd_error_ex(E_ERROR, "gd-jpeg: EXTREMELY fatal error: longjmp returned control; terminating"); + } else { + php_gd_error_ex(E_ERROR, "gd-jpeg: EXTREMELY fatal error: jmpbuf unrecoverable; terminating"); + } - exit (99); + exit (99); } /* @@ -76,25 +73,27 @@ * represent higher quality but also larger image size. If QUALITY is * negative, the IJG JPEG library's default quality is used (which * should be near optimal for many applications). See the IJG JPEG - * library documentation for more details. */ + * library documentation for more details. + */ void gdImageJpeg (gdImagePtr im, FILE * outFile, int quality) { - gdIOCtx *out = gdNewFileCtx (outFile); - gdImageJpegCtx (im, out, quality); - out->gd_free (out); + gdIOCtx *out = gdNewFileCtx (outFile); + gdImageJpegCtx (im, out, quality); + out->gd_free (out); } void * gdImageJpegPtr (gdImagePtr im, int *size, int quality) { - void *rv; - gdIOCtx *out = gdNewDynamicCtx (2048, NULL); - gdImageJpegCtx (im, out, quality); - rv = gdDPExtractData (out, size); - out->gd_free (out); - return rv; + void *rv; + gdIOCtx *out = gdNewDynamicCtx (2048, NULL); + gdImageJpegCtx (im, out, quality); + rv = gdDPExtractData (out, size); + out->gd_free (out); + + return rv; } void jpeg_gdIOCtx_dest (j_compress_ptr cinfo, gdIOCtx * outfile); @@ -102,168 +101,127 @@ void gdImageJpegCtx (gdImagePtr im, gdIOCtx * outfile, int quality) { - struct jpeg_compress_struct cinfo; - struct jpeg_error_mgr jerr; - int i, j, jidx; - /* volatile so we can gdFree it on return from longjmp */ - volatile JSAMPROW row = 0; - JSAMPROW rowptr[1]; - jmpbuf_wrapper jmpbufw; - JDIMENSION nlines; - char comment[255]; - -#ifdef JPEG_DEBUG - printf ("gd-jpeg: gd JPEG version %s\n", GD_JPEG_VERSION); - printf ("gd-jpeg: JPEG library version %d, %d-bit sample values\n", - JPEG_LIB_VERSION, BITS_IN_JSAMPLE); - if (!im->trueColor) - { - for (i = 0; i < im->colorsTotal; i++) - { - if (!im->open[i]) - printf ("gd-jpeg: gd colormap index %d: (%d, %d, %d)\n", i, - im->red[i], im->green[i], im->blue[i]); - } - } -#endif /* JPEG_DEBUG */ - - memset (&cinfo, 0, sizeof (cinfo)); - memset (&jerr, 0, sizeof (jerr)); - - cinfo.err = jpeg_std_error (&jerr); - cinfo.client_data = &jmpbufw; - if (setjmp (jmpbufw.jmpbuf) != 0) - { - /* we're here courtesy of longjmp */ - if (row) - gdFree (row); - return; - } + struct jpeg_compress_struct cinfo; + struct jpeg_error_mgr jerr; + int i, j, jidx; + /* volatile so we can gdFree it on return from longjmp */ + volatile JSAMPROW row = 0; + JSAMPROW rowptr[1]; + jmpbuf_wrapper jmpbufw; + JDIMENSION nlines; + char comment[255]; + + memset (&cinfo, 0, sizeof (cinfo)); + memset (&jerr, 0, sizeof (jerr)); + + cinfo.err = jpeg_std_error (&jerr); + cinfo.client_data = &jmpbufw; + if (setjmp (jmpbufw.jmpbuf) != 0) { + /* we're here courtesy of longjmp */ + if (row) { + gdFree (row); + } + return; + } - cinfo.err->error_exit = fatal_jpeg_error; + cinfo.err->error_exit = fatal_jpeg_error; - jpeg_create_compress (&cinfo); + jpeg_create_compress (&cinfo); - cinfo.image_width = im->sx; - cinfo.image_height = im->sy; - cinfo.input_components = 3; /* # of color components per pixel */ - cinfo.in_color_space = JCS_RGB; /* colorspace of input image */ - jpeg_set_defaults (&cinfo); - if (quality >= 0) - jpeg_set_quality (&cinfo, quality, TRUE); - - /* If user requests interlace, translate that to progressive JPEG */ - if (gdImageGetInterlaced (im)) - { -#ifdef JPEG_DEBUG - printf ("gd-jpeg: interlace set, outputting progressive" - " JPEG image\n"); -#endif - jpeg_simple_progression (&cinfo); - } + cinfo.image_width = im->sx; + cinfo.image_height = im->sy; + cinfo.input_components = 3; /* # of color components per pixel */ + cinfo.in_color_space = JCS_RGB; /* colorspace of input image */ + jpeg_set_defaults (&cinfo); + if (quality >= 0) { + jpeg_set_quality (&cinfo, quality, TRUE); + } + + /* If user requests interlace, translate that to progressive JPEG */ + if (gdImageGetInterlaced (im)) { + jpeg_simple_progression (&cinfo); + } + + jpeg_gdIOCtx_dest (&cinfo, outfile); - jpeg_gdIOCtx_dest (&cinfo, outfile); + row = (JSAMPROW) gdCalloc (1, cinfo.image_width * cinfo.input_components * sizeof (JSAMPLE)); + rowptr[0] = row; + + jpeg_start_compress (&cinfo, TRUE); + + if (quality >= 0) { + snprintf(comment, sizeof(comment)-1, "CREATOR: gd-jpeg v%s (using IJG JPEG v%d), quality = %d\n", GD_JPEG_VERSION, JPEG_LIB_VERSION, quality); + } else { + snprintf(comment, sizeof(comment)-1, "CREATOR: gd-jpeg v%s (using IJG JPEG v%d), default quality\n", GD_JPEG_VERSION, JPEG_LIB_VERSION); + } + jpeg_write_marker (&cinfo, JPEG_COM, (unsigned char *) comment, (unsigned int) strlen (comment)); + if (im->trueColor) { - row = (JSAMPROW) gdCalloc (1, cinfo.image_width * cinfo.input_components - * sizeof (JSAMPLE)); - if (row == 0) - { - php_gd_error("gd-jpeg: error: unable to allocate JPEG row " - "structure: gdCalloc returns NULL\n"); - jpeg_destroy_compress (&cinfo); - return; - } - - rowptr[0] = row; - - jpeg_start_compress (&cinfo, TRUE); - - sprintf (comment, "CREATOR: gd-jpeg v%s (using IJG JPEG v%d),", - GD_JPEG_VERSION, JPEG_LIB_VERSION); - if (quality >= 0) - sprintf (comment + strlen (comment), " quality = %d\n", - quality); - else - strcat (comment + strlen (comment), " default quality\n"); - jpeg_write_marker (&cinfo, JPEG_COM, (unsigned char *) comment, - (unsigned int) strlen (comment)); - if (im->trueColor) - { #if BITS_IN_JSAMPLE == 12 - php_gd_error("gd-jpeg: error: jpeg library was compiled for 12-bit\n" - "precision. This is mostly useless, because JPEGs on the web are\n" - "8-bit and such versions of the jpeg library won't read or write\n" - "them. GD doesn't support these unusual images. Edit your\n" - "jmorecfg.h file to specify the correct precision and completely\n" - "'make clean' and 'make install' libjpeg again. Sorry.\n"); - goto error; + php_gd_error("gd-jpeg: error: jpeg library was compiled for 12-bit precision. This is mostly useless, because JPEGs on the web are 8-bit and such versions of the jpeg library won't read or write them. GD doesn't support these unusual images. Edit your jmorecfg.h file to specify the correct precision and completely 'make clean' and 'make install' libjpeg again. Sorry"); + goto error; #endif /* BITS_IN_JSAMPLE == 12 */ - for (i = 0; i < im->sy; i++) - { - for (jidx = 0, j = 0; j < im->sx; j++) - { - int val = im->tpixels[i][j]; - row[jidx++] = gdTrueColorGetRed (val); - row[jidx++] = gdTrueColorGetGreen (val); - row[jidx++] = gdTrueColorGetBlue (val); - } - - nlines = jpeg_write_scanlines (&cinfo, rowptr, 1); - if (nlines != 1) - php_gd_error_ex(E_WARNING, "gd_jpeg: warning: jpeg_write_scanlines" - " returns %u -- expected 1\n", nlines); - } - } - else - { - for (i = 0; i < im->sy; i++) - { - for (jidx = 0, j = 0; j < im->sx; j++) - { - int idx = im->pixels[i][j]; - - /* - * NB: Although gd RGB values are ints, their max value is - * 255 (see the documentation for gdImageColorAllocate()) - * -- perfect for 8-bit JPEG encoding (which is the norm) - */ + + for (i = 0; i < im->sy; i++) { + for (jidx = 0, j = 0; j < im->sx; j++) { + int val = im->tpixels[i][j]; + + row[jidx++] = gdTrueColorGetRed (val); + row[jidx++] = gdTrueColorGetGreen (val); + row[jidx++] = gdTrueColorGetBlue (val); + } + + nlines = jpeg_write_scanlines (&cinfo, rowptr, 1); + if (nlines != 1) { + php_gd_error_ex(E_WARNING, "gd_jpeg: warning: jpeg_write_scanlines returns %u -- expected 1\n", nlines); + } + } + } else { + for (i = 0; i < im->sy; i++) { + for (jidx = 0, j = 0; j < im->sx; j++) { + int idx = im->pixels[i][j]; + + /* NB: Although gd RGB values are ints, their max value is + * 255 (see the documentation for gdImageColorAllocate()) + * -- perfect for 8-bit JPEG encoding (which is the norm) + */ #if BITS_IN_JSAMPLE == 8 - row[jidx++] = im->red[idx]; - row[jidx++] = im->green[idx]; - row[jidx++] = im->blue[idx]; + row[jidx++] = im->red[idx]; + row[jidx++] = im->green[idx]; + row[jidx++] = im->blue[idx]; #elif BITS_IN_JSAMPLE == 12 - row[jidx++] = im->red[idx] << 4; - row[jidx++] = im->green[idx] << 4; - row[jidx++] = im->blue[idx] << 4; + row[jidx++] = im->red[idx] << 4; + row[jidx++] = im->green[idx] << 4; + row[jidx++] = im->blue[idx] << 4; #else #error IJG JPEG library BITS_IN_JSAMPLE value must be 8 or 12 #endif - } + } - nlines = jpeg_write_scanlines (&cinfo, rowptr, 1); - if (nlines != 1) - php_gd_error_ex(E_WARNING, "gd_jpeg: warning: jpeg_write_scanlines" - " returns %u -- expected 1\n", nlines); - } - } - jpeg_finish_compress (&cinfo); - jpeg_destroy_compress (&cinfo); - gdFree (row); + nlines = jpeg_write_scanlines (&cinfo, rowptr, 1); + if (nlines != 1) { + php_gd_error_ex(E_WARNING, "gd_jpeg: warning: jpeg_write_scanlines returns %u -- expected 1\n", nlines); + } + } + } + + jpeg_finish_compress (&cinfo); + jpeg_destroy_compress (&cinfo); + gdFree (row); } gdImagePtr gdImageCreateFromJpeg (FILE * inFile) { - gdImagePtr im; - gdIOCtx *in = gdNewFileCtx (inFile); - im = gdImageCreateFromJpegCtx (in); - in->gd_free (in); - return im; + gdImagePtr im; + gdIOCtx *in = gdNewFileCtx (inFile); + im = gdImageCreateFromJpegCtx (in); + in->gd_free (in); + + return im; } -void - jpeg_gdIOCtx_src (j_decompress_ptr cinfo, - gdIOCtx * infile); +void jpeg_gdIOCtx_src (j_decompress_ptr cinfo, gdIOCtx * infile); /* * Create a gd-format image from the JPEG-format INFILE. Returns the @@ -272,197 +230,122 @@ gdImagePtr gdImageCreateFromJpegCtx (gdIOCtx * infile) { - struct jpeg_decompress_struct cinfo; - struct jpeg_error_mgr jerr; - jmpbuf_wrapper jmpbufw; - /* volatile so we can gdFree them after longjmp */ - volatile JSAMPROW row = 0; - volatile gdImagePtr im = 0; - JSAMPROW rowptr[1]; - unsigned int i, j; - int retval; - JDIMENSION nrows; - -#ifdef JPEG_DEBUG - printf ("gd-jpeg: gd JPEG version %s\n", GD_JPEG_VERSION); - printf ("gd-jpeg: JPEG library version %d, %d-bit sample values\n", - JPEG_LIB_VERSION, BITS_IN_JSAMPLE); -#endif + struct jpeg_decompress_struct cinfo; + struct jpeg_error_mgr jerr; + jmpbuf_wrapper jmpbufw; + /* volatile so we can gdFree them after longjmp */ + volatile JSAMPROW row = 0; + volatile gdImagePtr im = 0; + JSAMPROW rowptr[1]; + unsigned int i, j; + int retval; + JDIMENSION nrows; + + memset (&cinfo, 0, sizeof (cinfo)); + memset (&jerr, 0, sizeof (jerr)); + + cinfo.err = jpeg_std_error (&jerr); + cinfo.client_data = &jmpbufw; + if (setjmp (jmpbufw.jmpbuf) != 0) { + /* we're here courtesy of longjmp */ + if (row) { + gdFree (row); + } + if (im) { + gdImageDestroy (im); + } + return 0; + } - memset (&cinfo, 0, sizeof (cinfo)); - memset (&jerr, 0, sizeof (jerr)); + cinfo.err->error_exit = fatal_jpeg_error; - cinfo.err = jpeg_std_error (&jerr); - cinfo.client_data = &jmpbufw; - if (setjmp (jmpbufw.jmpbuf) != 0) - { - /* we're here courtesy of longjmp */ - if (row) - gdFree (row); - if (im) - gdImageDestroy (im); - return 0; - } - - cinfo.err->error_exit = fatal_jpeg_error; - - jpeg_create_decompress (&cinfo); - - jpeg_gdIOCtx_src (&cinfo, infile); - - retval = jpeg_read_header (&cinfo, TRUE); - if (retval != JPEG_HEADER_OK) - php_gd_error_ex(E_WARNING, "gd-jpeg: warning: jpeg_read_header returns" - " %d, expected %d\n", retval, JPEG_HEADER_OK); - - if (cinfo.image_height > INT_MAX) - php_gd_error_ex(E_WARNING, "gd-jpeg: warning: JPEG image height (%u) is" - " greater than INT_MAX (%d) (and thus greater than" - " gd can handle)", cinfo.image_height, - INT_MAX); - - if (cinfo.image_width > INT_MAX) - php_gd_error_ex(E_WARNING, "gd-jpeg: warning: JPEG image width (%u) is" - " greater than INT_MAX (%d) (and thus greater than" - " gd can handle)\n", cinfo.image_width, INT_MAX); - - im = gdImageCreateTrueColor ((int) cinfo.image_width, - (int) cinfo.image_height); - if (im == 0) - { - php_gd_error("gd-jpeg error: cannot allocate gdImage" - " struct\n"); - goto error; - } - - /* - * Force the image into RGB colorspace, but don't - * reduce the number of colors anymore (GD 2.0) - */ - cinfo.out_color_space = JCS_RGB; - - if (jpeg_start_decompress (&cinfo) != TRUE) - php_gd_error("gd-jpeg: warning: jpeg_start_decompress" - " reports suspended data source\n"); - -#ifdef JPEG_DEBUG - printf ("gd-jpeg: JPEG image information:"); - if (cinfo.saw_JFIF_marker) - printf (" JFIF version %d.%.2d", - (int) cinfo.JFIF_major_version, - (int) cinfo.JFIF_minor_version); - else if (cinfo.saw_Adobe_marker) - printf (" Adobe format"); - else - printf (" UNKNOWN format"); - - printf (" %ux%u (raw) / %ux%u (scaled) %d-bit", cinfo.image_width, - cinfo.image_height, cinfo.output_width, - cinfo.output_height, cinfo.data_precision); - printf (" %s", (cinfo.progressive_mode ? "progressive" : - "baseline")); - printf (" image, %d quantized colors, ", - cinfo.actual_number_of_colors); - - switch (cinfo.jpeg_color_space) - { - case JCS_GRAYSCALE: - printf ("grayscale"); - break; - - case JCS_RGB: - printf ("RGB"); - break; - - case JCS_YCbCr: - printf ("YCbCr (a.k.a. YUV)"); - break; - - case JCS_CMYK: - printf ("CMYK"); - break; - - case JCS_YCCK: - printf ("YCbCrK"); - break; - - default: - printf ("UNKNOWN (value: %d)", (int) cinfo.jpeg_color_space); - break; - } - printf (" colorspace\n"); - fflush (stdout); -#endif /* JPEG_DEBUG */ - - /* REMOVED by TBB 2/12/01. This field of the structure is - documented as private, and sure enough it's gone in the - latest libjpeg, replaced by something else. Unfortunately - there is still no right way to find out if the file was - progressive or not; just declare your intent before you - write one by calling gdImageInterlace(im, 1) yourself. - After all, we're not really supposed to rework JPEGs and - write them out again anyway. Lossy compression, remember? */ + jpeg_create_decompress (&cinfo); + + jpeg_gdIOCtx_src (&cinfo, infile); + + retval = jpeg_read_header (&cinfo, TRUE); + if (retval != JPEG_HEADER_OK) { + php_gd_error_ex(E_WARNING, "gd-jpeg: warning: jpeg_read_header returned %d, expected %d", retval, JPEG_HEADER_OK); + } + + if (cinfo.image_height > INT_MAX) { + php_gd_error_ex(E_WARNING, "gd-jpeg: warning: JPEG image height (%u) is greater than INT_MAX (%d) (and thus greater than gd can handle)", cinfo.image_height, INT_MAX); + } + + if (cinfo.image_width > INT_MAX) { + php_gd_error_ex(E_WARNING, "gd-jpeg: warning: JPEG image width (%u) is greater than INT_MAX (%d) (and thus greater than gd can handle)", cinfo.image_width, INT_MAX); + } + + im = gdImageCreateTrueColor ((int) cinfo.image_width, (int) cinfo.image_height); + if (im == 0) { + php_gd_error("gd-jpeg error: cannot allocate gdImage struct"); + goto error; + } + + /* Force the image into RGB colorspace, but don't reduce the number of colors anymore (GD 2.0) */ + cinfo.out_color_space = JCS_RGB; + + if (jpeg_start_decompress (&cinfo) != TRUE) { + php_gd_error("gd-jpeg: warning: jpeg_start_decompress reports suspended data source"); + } + + /* REMOVED by TBB 2/12/01. This field of the structure is + * documented as private, and sure enough it's gone in the + * latest libjpeg, replaced by something else. Unfortunately + * there is still no right way to find out if the file was + * progressive or not; just declare your intent before you + * write one by calling gdImageInterlace(im, 1) yourself. + * After all, we're not really supposed to rework JPEGs and + * write them out again anyway. Lossy compression, remember? + */ #if 0 gdImageInterlace (im, cinfo.progressive_mode != 0); #endif - if (cinfo.output_components != 3) - { - php_gd_error_ex(E_WARNING, "gd-jpeg: error: JPEG color quantization" - " request resulted in output_components == %d" - " (expected 3)\n", cinfo.output_components); - goto error; - } + + if (cinfo.output_components != 3) { + php_gd_error_ex(E_WARNING, "gd-jpeg: error: JPEG color quantization request resulted in output_components == %d (expected 3)", cinfo.output_components); + goto error; + } #if BITS_IN_JSAMPLE == 12 - php_gd_error("gd-jpeg: error: jpeg library was compiled for 12-bit\n" - "precision. This is mostly useless, because JPEGs on the web are\n" - "8-bit and such versions of the jpeg library won't read or write\n" - "them. GD doesn't support these unusual images. Edit your\n" - "jmorecfg.h file to specify the correct precision and completely\n" - "'make clean' and 'make install' libjpeg again. Sorry.\n"); - goto error; + php_gd_error("gd-jpeg: error: jpeg library was compiled for 12-bit precision. This is mostly useless, because JPEGs on the web are 8-bit and such versions of the jpeg library won't read or write them. GD doesn't support these unusual images. Edit your jmorecfg.h file to specify the correct precision and completely 'make clean' and 'make install' libjpeg again. Sorry."); + goto error; #endif /* BITS_IN_JSAMPLE == 12 */ - row = gdCalloc (cinfo.output_width * 3, sizeof (JSAMPLE)); - if (row == 0) - { - php_gd_error("gd-jpeg: error: unable to allocate row for" - " JPEG scanline: gdCalloc returns NULL\n"); - goto error; - } - rowptr[0] = row; - - for (i = 0; i < cinfo.output_height; i++) - { - nrows = jpeg_read_scanlines (&cinfo, rowptr, 1); - if (nrows != 1) - { - php_gd_error_ex(E_WARNING, "gd-jpeg: error: jpeg_read_scanlines" - " returns %u, expected 1\n", nrows); - goto error; - } - - for (j = 0; j < cinfo.output_width; j++) - im->tpixels[i][j] = gdTrueColor (row[j * 3], row[j * 3 + 1], - row[j * 3 + 2]); - } - - if (jpeg_finish_decompress (&cinfo) != TRUE) - php_gd_error("gd-jpeg: warning: jpeg_finish_decompress" - " reports suspended data source\n"); - - - jpeg_destroy_decompress (&cinfo); - gdFree (row); - return im; + row = gdCalloc (cinfo.output_width * 3, sizeof (JSAMPLE)); + rowptr[0] = row; + + for (i = 0; i < cinfo.output_height; i++) { + register JSAMPROW currow = row; + register int *tpix = im->tpixels[i]; + nrows = jpeg_read_scanlines (&cinfo, rowptr, 1); + if (nrows != 1) { + php_gd_error_ex(E_WARNING, "gd-jpeg: error: jpeg_read_scanlines returns %u, expected 1", nrows); + goto error; + } + for (j = 0; j < cinfo.output_width; j++, currow += 3, tpix++) { + *tpix = gdTrueColor (currow[0], currow[1], currow[2]); + } + } + + if (jpeg_finish_decompress (&cinfo) != TRUE) { + php_gd_error("gd-jpeg: warning: jpeg_finish_decompress reports suspended data source"); + } + + jpeg_destroy_decompress (&cinfo); + gdFree (row); + + return im; error: - jpeg_destroy_decompress (&cinfo); - if (row) - gdFree (row); - if (im) - gdImageDestroy (im); - return 0; + jpeg_destroy_decompress (&cinfo); + if (row) { + gdFree (row); + } + if (im) { + gdImageDestroy (im); + } + return 0; } /* @@ -488,15 +371,13 @@ /* Expanded data source object for gdIOCtx input */ typedef struct - { - struct jpeg_source_mgr pub; /* public fields */ +{ + struct jpeg_source_mgr pub; /* public fields */ - gdIOCtx *infile; /* source stream */ - unsigned char *buffer; /* start of buffer */ - safeboolean start_of_file; /* have we gotten any data yet? */ - - } -my_source_mgr; + gdIOCtx *infile; /* source stream */ + unsigned char *buffer; /* start of buffer */ + safeboolean start_of_file; /* have we gotten any data yet? */ +} my_source_mgr; typedef my_source_mgr *my_src_ptr; @@ -510,13 +391,13 @@ void init_source (j_decompress_ptr cinfo) { - my_src_ptr src = (my_src_ptr) cinfo->src; + my_src_ptr src = (my_src_ptr) cinfo->src; - /* We reset the empty-input-file flag for each image, - * but we don't clear the input buffer. - * This is correct behavior for reading a series of images from one source. - */ - src->start_of_file = TRUE; + /* We reset the empty-input-file flag for each image, + * but we don't clear the input buffer. + * This is correct behavior for reading a series of images from one source. + */ + src->start_of_file = TRUE; } @@ -558,56 +439,42 @@ safeboolean fill_input_buffer (j_decompress_ptr cinfo) { - my_src_ptr src = (my_src_ptr) cinfo->src; - size_t nbytes = 0; + my_src_ptr src = (my_src_ptr) cinfo->src; + size_t nbytes = 0; - /* size_t got; */ - /* char *s; */ - memset (src->buffer, 0, INPUT_BUF_SIZE); + /* size_t got; */ + /* char *s; */ + memset (src->buffer, 0, INPUT_BUF_SIZE); - while (nbytes < INPUT_BUF_SIZE) - { - - int got = gdGetBuf (src->buffer + nbytes, - INPUT_BUF_SIZE - nbytes, - src->infile); + while (nbytes < INPUT_BUF_SIZE) { + int got = gdGetBuf (src->buffer + nbytes, INPUT_BUF_SIZE - nbytes, src->infile); - if ((got == EOF) || (got == 0)) - { - - /* EOF or error. If we got any data, don't worry about it. - If we didn't, then this is unexpected. */ - if (!nbytes) - { - - nbytes = -1; - - } - - break; - + if ((got == EOF) || (got == 0)) { + /* EOF or error. If we got any data, don't worry about it. If we didn't, then this is unexpected. */ + if (!nbytes) { + nbytes = -1; + } + break; + } + nbytes += got; } - - nbytes += got; - - } - if (nbytes <= 0) - { - if (src->start_of_file) /* Treat empty input file as fatal error */ - ERREXIT (cinfo, JERR_INPUT_EMPTY); - WARNMS (cinfo, JWRN_JPEG_EOF); - /* Insert a fake EOI marker */ - src->buffer[0] = (unsigned char) 0xFF; - src->buffer[1] = (unsigned char) JPEG_EOI; - nbytes = 2; - } - - src->pub.next_input_byte = src->buffer; - src->pub.bytes_in_buffer = nbytes; - src->start_of_file = FALSE; + if (nbytes <= 0) { + if (src->start_of_file) { /* Treat empty input file as fatal error */ + ERREXIT (cinfo, JERR_INPUT_EMPTY); + } + WARNMS (cinfo, JWRN_JPEG_EOF); + /* Insert a fake EOI marker */ + src->buffer[0] = (unsigned char) 0xFF; + src->buffer[1] = (unsigned char) JPEG_EOI; + nbytes = 2; + } + + src->pub.next_input_byte = src->buffer; + src->pub.bytes_in_buffer = nbytes; + src->start_of_file = FALSE; - return TRUE; + return TRUE; } @@ -626,24 +493,22 @@ void skip_input_data (j_decompress_ptr cinfo, long num_bytes) { - my_src_ptr src = (my_src_ptr) cinfo->src; + my_src_ptr src = (my_src_ptr) cinfo->src; - /* Just a dumb implementation for now. Not clear that being smart is worth - * any trouble anyway --- large skips are infrequent. - */ - if (num_bytes > 0) - { - while (num_bytes > (long) src->pub.bytes_in_buffer) - { - num_bytes -= (long) src->pub.bytes_in_buffer; - (void) fill_input_buffer (cinfo); - /* note we assume that fill_input_buffer will never return FALSE, - * so suspension need not be handled. - */ - } - src->pub.next_input_byte += (size_t) num_bytes; - src->pub.bytes_in_buffer -= (size_t) num_bytes; - } + /* Just a dumb implementation for now. Not clear that being smart is worth + * any trouble anyway --- large skips are infrequent. + */ + if (num_bytes > 0) { + while (num_bytes > (long) src->pub.bytes_in_buffer) { + num_bytes -= (long) src->pub.bytes_in_buffer; + (void) fill_input_buffer (cinfo); + /* note we assume that fill_input_buffer will never return FALSE, + * so suspension need not be handled. + */ + } + src->pub.next_input_byte += (size_t) num_bytes; + src->pub.bytes_in_buffer -= (size_t) num_bytes; + } } @@ -668,11 +533,9 @@ void term_source (j_decompress_ptr cinfo) { - #if 0 -/* never used */ - my_src_ptr src = (my_src_ptr) cinfo->src; - + * never used */ + my_src_ptr src = (my_src_ptr) cinfo->src; #endif } @@ -684,50 +547,44 @@ */ void -jpeg_gdIOCtx_src (j_decompress_ptr cinfo, - gdIOCtx * infile) +jpeg_gdIOCtx_src (j_decompress_ptr cinfo, gdIOCtx * infile) { - my_src_ptr src; + my_src_ptr src; - /* The source object and input buffer are made permanent so that a series - * of JPEG images can be read from the same file by calling jpeg_gdIOCtx_src - * only before the first one. (If we discarded the buffer at the end of - * one image, we'd likely lose the start of the next one.) - * This makes it unsafe to use this manager and a different source - * manager serially with the same JPEG object. Caveat programmer. - */ - if (cinfo->src == NULL) - { /* first time for this JPEG object? */ - cinfo->src = (struct jpeg_source_mgr *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, - sizeof (my_source_mgr)); - src = (my_src_ptr) cinfo->src; - src->buffer = (unsigned char *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, - INPUT_BUF_SIZE * sizeof (unsigned char)); + /* The source object and input buffer are made permanent so that a series + * of JPEG images can be read from the same file by calling jpeg_gdIOCtx_src + * only before the first one. (If we discarded the buffer at the end of + * one image, we'd likely lose the start of the next one.) + * This makes it unsafe to use this manager and a different source + * manager serially with the same JPEG object. Caveat programmer. + */ + if (cinfo->src == NULL) { /* first time for this JPEG object? */ + cinfo->src = (struct jpeg_source_mgr *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, sizeof (my_source_mgr)); + src = (my_src_ptr) cinfo->src; + src->buffer = (unsigned char *) (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, INPUT_BUF_SIZE * sizeof (unsigned char)); - } + } - src = (my_src_ptr) cinfo->src; - src->pub.init_source = init_source; - src->pub.fill_input_buffer = fill_input_buffer; - src->pub.skip_input_data = skip_input_data; - src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */ - src->pub.term_source = term_source; - src->infile = infile; - src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */ - src->pub.next_input_byte = NULL; /* until buffer loaded */ + src = (my_src_ptr) cinfo->src; + src->pub.init_source = init_source; + src->pub.fill_input_buffer = fill_input_buffer; + src->pub.skip_input_data = skip_input_data; + src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */ + src->pub.term_source = term_source; + src->infile = infile; + src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */ + src->pub.next_input_byte = NULL; /* until buffer loaded */ } /* Expanded data destination object for stdio output */ typedef struct { - struct jpeg_destination_mgr pub; /* public fields */ - gdIOCtx *outfile; /* target stream */ - unsigned char *buffer; /* start of buffer */ -} -my_destination_mgr; + struct jpeg_destination_mgr pub; /* public fields */ + gdIOCtx *outfile; /* target stream */ + unsigned char *buffer; /* start of buffer */ +} my_destination_mgr; typedef my_destination_mgr *my_dest_ptr; @@ -741,15 +598,13 @@ void init_destination (j_compress_ptr cinfo) { - my_dest_ptr dest = (my_dest_ptr) cinfo->dest; + my_dest_ptr dest = (my_dest_ptr) cinfo->dest; - /* Allocate the output buffer --- it will be released when done with image */ - dest->buffer = (unsigned char *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - OUTPUT_BUF_SIZE * sizeof (unsigned char)); + /* Allocate the output buffer --- it will be released when done with image */ + dest->buffer = (unsigned char *) (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, OUTPUT_BUF_SIZE * sizeof (unsigned char)); - dest->pub.next_output_byte = dest->buffer; - dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; + dest->pub.next_output_byte = dest->buffer; + dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; } @@ -779,16 +634,16 @@ safeboolean empty_output_buffer (j_compress_ptr cinfo) { - my_dest_ptr dest = (my_dest_ptr) cinfo->dest; + my_dest_ptr dest = (my_dest_ptr) cinfo->dest; - if (gdPutBuf (dest->buffer, OUTPUT_BUF_SIZE, dest->outfile) != - (size_t) OUTPUT_BUF_SIZE) - ERREXIT (cinfo, JERR_FILE_WRITE); + if (gdPutBuf (dest->buffer, OUTPUT_BUF_SIZE, dest->outfile) != (size_t) OUTPUT_BUF_SIZE) { + ERREXIT (cinfo, JERR_FILE_WRITE); + } - dest->pub.next_output_byte = dest->buffer; - dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; + dest->pub.next_output_byte = dest->buffer; + dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; - return TRUE; + return TRUE; } @@ -804,15 +659,13 @@ void term_destination (j_compress_ptr cinfo) { - my_dest_ptr dest = (my_dest_ptr) cinfo->dest; - size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer; + my_dest_ptr dest = (my_dest_ptr) cinfo->dest; + size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer; - /* Write any data remaining in the buffer */ - if (datacount > 0) - { - if ((size_t)gdPutBuf (dest->buffer, datacount, dest->outfile) != datacount) - ERREXIT (cinfo, JERR_FILE_WRITE); - } + /* Write any data remaining in the buffer */ + if (datacount > 0 && ((size_t)gdPutBuf (dest->buffer, datacount, dest->outfile) != datacount)) { + ERREXIT (cinfo, JERR_FILE_WRITE); + } } @@ -825,26 +678,23 @@ void jpeg_gdIOCtx_dest (j_compress_ptr cinfo, gdIOCtx * outfile) { - my_dest_ptr dest; + my_dest_ptr dest; + + /* The destination object is made permanent so that multiple JPEG images + * can be written to the same file without re-executing jpeg_stdio_dest. + * This makes it dangerous to use this manager and a different destination + * manager serially with the same JPEG object, because their private object + * sizes may be different. Caveat programmer. + */ + if (cinfo->dest == NULL) { /* first time for this JPEG object? */ + cinfo->dest = (struct jpeg_destination_mgr *) (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, sizeof (my_destination_mgr)); + } - /* The destination object is made permanent so that multiple JPEG images - * can be written to the same file without re-executing jpeg_stdio_dest. - * This makes it dangerous to use this manager and a different destination - * manager serially with the same JPEG object, because their private object - * sizes may be different. Caveat programmer. - */ - if (cinfo->dest == NULL) - { /* first time for this JPEG object? */ - cinfo->dest = (struct jpeg_destination_mgr *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, - sizeof (my_destination_mgr)); - } - - dest = (my_dest_ptr) cinfo->dest; - dest->pub.init_destination = init_destination; - dest->pub.empty_output_buffer = empty_output_buffer; - dest->pub.term_destination = term_destination; - dest->outfile = outfile; + dest = (my_dest_ptr) cinfo->dest; + dest->pub.init_destination = init_destination; + dest->pub.empty_output_buffer = empty_output_buffer; + dest->pub.term_destination = term_destination; + dest->outfile = outfile; } #endif /* HAVE_JPEG */