diff options
Diffstat (limited to 'ext/gd/libgd/gd_jpeg.c')
-rw-r--r-- | ext/gd/libgd/gd_jpeg.c | 104 |
1 files changed, 87 insertions, 17 deletions
diff --git a/ext/gd/libgd/gd_jpeg.c b/ext/gd/libgd/gd_jpeg.c index e043af62d7..26332279ae 100644 --- a/ext/gd/libgd/gd_jpeg.c +++ b/ext/gd/libgd/gd_jpeg.c @@ -217,8 +217,20 @@ gdImagePtr gdImageCreateFromJpeg (FILE * inFile) return im; } +gdImagePtr gdImageCreateFromJpegPtr (int size, void *data) +{ + gdImagePtr im; + gdIOCtx *in = gdNewDynamicCtxEx(size, data, 0); + im = gdImageCreateFromJpegCtx(in); + in->gd_free(in); + + return im; +} + void jpeg_gdIOCtx_src (j_decompress_ptr cinfo, gdIOCtx * infile); +static int CMYKToRGB(int c, int m, int y, int k, int inverted); + /* * Create a gd-format image from the JPEG-format INFILE. Returns the * image, or NULL upon error. @@ -235,6 +247,8 @@ gdImagePtr gdImageCreateFromJpegCtx (gdIOCtx * infile) unsigned int i, j; int retval; JDIMENSION nrows; + int channels = 3; + int inverted = 0; memset (&cinfo, 0, sizeof (cinfo)); memset (&jerr, 0, sizeof (jerr)); @@ -258,6 +272,9 @@ gdImagePtr gdImageCreateFromJpegCtx (gdIOCtx * infile) jpeg_gdIOCtx_src (&cinfo, infile); + /* 2.0.22: save the APP14 marker to check for Adobe Photoshop CMYK files with inverted components. */ + jpeg_save_markers(&cinfo, JPEG_APP0 + 14, 256); + 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); @@ -277,8 +294,14 @@ gdImagePtr gdImageCreateFromJpegCtx (gdIOCtx * infile) 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; + /* 2.0.22: very basic support for reading CMYK colorspace files. Nice for + * thumbnails but there's no support for fussy adjustment of the + * assumed properties of inks and paper. */ + if ((cinfo.jpeg_color_space == JCS_CMYK) || (cinfo.jpeg_color_space == JCS_YCCK)) { + cinfo.out_color_space = JCS_CMYK; + } else { + 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"); @@ -297,8 +320,29 @@ gdImagePtr gdImageCreateFromJpegCtx (gdIOCtx * infile) 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)", cinfo.output_components); + if (cinfo.out_color_space == JCS_RGB) { + 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 for RGB)", cinfo.output_components); + goto error; + } + channels = 3; + } else if (cinfo.out_color_space == JCS_CMYK) { + jpeg_saved_marker_ptr marker; + if (cinfo.output_components != 4) { + php_gd_error_ex(E_WARNING, "gd-jpeg: error: JPEG color quantization request resulted in output_components == %d (expected 4 for CMYK)", cinfo.output_components); + goto error; + } + channels = 4; + marker = cinfo.marker_list; + while (marker) { + if ((marker->marker == (JPEG_APP0 + 14)) && (marker->data_length >= 12) && (!strncmp((const char *) marker->data, "Adobe", 5))) { + inverted = 1; + break; + } + marker = marker->next; + } + } else { + php_gd_error_ex(E_WARNING, "gd-jpeg: error: unexpected colorspace."); goto error; } @@ -307,22 +351,37 @@ gdImagePtr gdImageCreateFromJpegCtx (gdIOCtx * infile) goto error; #endif /* BITS_IN_JSAMPLE == 12 */ - row = safe_emalloc(cinfo.output_width * 3, sizeof(JSAMPLE), 0); - memset(row, 0, cinfo.output_width * 3 * sizeof(JSAMPLE)); + row = safe_emalloc(cinfo.output_width * channels, sizeof(JSAMPLE), 0); + memset(row, 0, cinfo.output_width * channels * 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; + if (cinfo.out_color_space == JCS_CMYK) { + 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 += 4, tpix++) { + *tpix = CMYKToRGB (currow[0], currow[1], currow[2], currow[3], inverted); + } } - for (j = 0; j < cinfo.output_width; j++, currow += 3, tpix++) { - *tpix = gdTrueColor (currow[0], currow[1], currow[2]); + } else { + 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"); @@ -349,8 +408,19 @@ error: return 0; } -/* +/* A very basic conversion approach, TBB */ +static int CMYKToRGB(int c, int m, int y, int k, int inverted) +{ + if (inverted) { + c = 255 - c; + m = 255 - m; + y = 255 - y; + k = 255 - k; + } + return gdTrueColor((255 - c) * (255 - k) / 255, (255 - m) * (255 - k) / 255, (255 - y) * (255 - k) / 255); +} +/* * gdIOCtx JPEG data sources and sinks, T. Boutell * almost a simple global replace from T. Lane's stdio versions. * |