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 ([EMAIL PROTECTED]) + * + * 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 */
-- PHP CVS Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php