summaryrefslogtreecommitdiff
path: root/ext/gd/libgd/gd_jpeg.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/gd/libgd/gd_jpeg.c')
-rw-r--r--ext/gd/libgd/gd_jpeg.c104
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.
*