[patch] gdk-pixbuf loaders crash on CMYK JPEGs
- From: Michael Natterer <mitch gimp org>
- To: gtk-devel-list gnome org
- Subject: [patch] gdk-pixbuf loaders crash on CMYK JPEGs
- Date: 29 Jul 2002 13:04:04 +0200
Hi all,
currently io-jpeg.c simply crashes on CMYK JPEGs (or any JPEG with
n_components != 1 or 3). The attached patch does the following:
- removes GREY->RGB conversion routine
- uses the libjpeg built-in ability to promote everything to either
RGB or CMYK
- adds CMYK->RGB conversion.
- refuses to load files with unknown colorspace.
I guess it should be comitted to both branches.
OK to commit or is it too much of a change and should go to
Bugzilla first?
ciao,
--mitch
Index: gdk-pixbuf/io-jpeg.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk-pixbuf/io-jpeg.c,v
retrieving revision 1.43
diff -u -p -r1.43 io-jpeg.c
--- gdk-pixbuf/io-jpeg.c 11 Apr 2002 21:18:40 -0000 1.43
+++ gdk-pixbuf/io-jpeg.c 29 Jul 2002 10:59:01 -0000
@@ -86,6 +86,8 @@ typedef struct {
GdkPixbuf *pixbuf;
guchar *dptr; /* current position in pixbuf */
+ guchar *cmyk_buf; /* buffer for CMYK data */
+
gboolean did_prescan; /* are we in image data yet? */
gboolean got_header; /* have we loaded jpeg header? */
gboolean src_initialized;/* TRUE when jpeg lib initialized */
@@ -140,32 +142,35 @@ output_message_handler (j_common_ptr cin
/* do nothing */
}
-/* explode gray image data from jpeg library into rgb components in pixbuf */
+/* implode CMYK image data from jpeg library into rgb components in pixbuf */
static void
-explode_gray_into_buf (struct jpeg_decompress_struct *cinfo,
- guchar **lines)
+convert_cmyk_lines (struct jpeg_decompress_struct *cinfo,
+ guchar **cmyk_lines,
+ guchar **lines)
{
gint i, j;
- guint w;
+ gint w;
g_return_if_fail (cinfo != NULL);
- g_return_if_fail (cinfo->output_components == 1);
+ g_return_if_fail (cinfo->out_color_space == JCS_CMYK);
- /* Expand grey->colour. Expand from the end of the
- * memory down, so we can use the same buffer.
- */
w = cinfo->image_width;
- for (i = cinfo->rec_outbuf_height - 1; i >= 0; i--) {
+ for (i = 0; i < cinfo->rec_outbuf_height; i++) {
guchar *from, *to;
- from = lines[i] + w - 1;
- to = lines[i] + (w - 1) * 3;
- for (j = w - 1; j >= 0; j--) {
- to[0] = from[0];
- to[1] = from[0];
- to[2] = from[0];
- to -= 3;
- from--;
+ from = cmyk_lines[i];
+ to = lines[i];
+ for (j = 0; j < w; j++) {
+ guint r_c, g_m, b_y, k;
+
+ r_c = *from++;
+ g_m = *from++;
+ b_y = *from++;
+ k = *from++;
+
+ *to++ = (r_c * k) / 255;
+ *to++ = (g_m * k) / 255;
+ *to++ = (b_y * k) / 255;
}
}
}
@@ -240,6 +245,7 @@ gdk_pixbuf__jpeg_image_load (FILE *f, GE
{
gint i;
GdkPixbuf * volatile pixbuf = NULL;
+ guchar * volatile cmyk_buf = NULL;
guchar *dptr;
guchar *lines[4]; /* Used to expand rows, via rec_outbuf_height,
* from the header file:
@@ -263,6 +269,9 @@ gdk_pixbuf__jpeg_image_load (FILE *f, GE
if (pixbuf)
g_object_unref (pixbuf);
+ if (cmyk_buf)
+ g_free (cmyk_buf);
+
jpeg_destroy_decompress (&cinfo);
return NULL;
}
@@ -292,11 +301,37 @@ gdk_pixbuf__jpeg_image_load (FILE *f, GE
cinfo.do_fancy_upsampling = FALSE;
cinfo.do_block_smoothing = FALSE;
+ switch (cinfo.out_color_space) {
+ case JCS_UNKNOWN:
+ g_set_error (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_UNSUPPORTED_OPERATION,
+ _("JPEG file has unknown colorspace"));
+ return NULL;
+
+ case JCS_GRAYSCALE:
+ case JCS_RGB:
+ case JCS_YCbCr:
+ cinfo.out_color_space = JCS_RGB;
+ break;
+
+ case JCS_CMYK:
+ case JCS_YCCK:
+ cinfo.out_color_space = JCS_CMYK;
+ cmyk_buf = g_new (guchar, (cinfo.output_width *
+ cinfo.output_components *
+ cinfo.rec_outbuf_height));
+ break;
+ }
+
pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, cinfo.output_width, cinfo.output_height);
if (!pixbuf) {
jpeg_destroy_decompress (&cinfo);
+ if (cmyk_buf)
+ g_free (cmyk_buf);
+
/* broken check for *error == NULL for robustness against
* crappy JPEG library
*/
@@ -321,15 +356,32 @@ gdk_pixbuf__jpeg_image_load (FILE *f, GE
dptr += pixbuf->rowstride;
}
- jpeg_read_scanlines (&cinfo, lines, cinfo.rec_outbuf_height);
+ if (cinfo.out_color_space == JCS_CMYK) {
+ guchar *cmyk_lines[4];
+
+ for (i = 0; i < cinfo.rec_outbuf_height; i++) {
+ cmyk_lines[i] = (cmyk_buf +
+ i * (cinfo.output_width *
+ cinfo.output_components));
+ }
+
+ jpeg_read_scanlines (&cinfo, cmyk_lines,
+ cinfo.rec_outbuf_height);
+
+ convert_cmyk_lines (&cinfo, cmyk_lines, lines);
+ } else {
+ jpeg_read_scanlines (&cinfo, lines,
+ cinfo.rec_outbuf_height);
- if (cinfo.output_components == 1)
- explode_gray_into_buf (&cinfo, lines);
+ }
}
jpeg_finish_decompress (&cinfo);
jpeg_destroy_decompress (&cinfo);
+ if (cmyk_buf)
+ g_free (cmyk_buf);
+
return pixbuf;
}
@@ -459,6 +511,9 @@ gdk_pixbuf__jpeg_image_stop_load (gpoint
if (context->pixbuf)
g_object_unref (context->pixbuf);
+ if (context->cmyk_buf)
+ g_free (context->cmyk_buf);
+
/* if we have an error? */
if (sigsetjmp (context->jerr.setjmp_buffer, 1)) {
jpeg_destroy_decompress (&context->cinfo);
@@ -618,6 +673,29 @@ gdk_pixbuf__jpeg_image_load_increment (g
cinfo->do_fancy_upsampling = FALSE;
cinfo->do_block_smoothing = FALSE;
+ switch (cinfo->out_color_space) {
+ case JCS_UNKNOWN:
+ g_set_error (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_UNSUPPORTED_OPERATION,
+ _("JPEG file has unknown colorspace"));
+ return FALSE;
+
+ case JCS_GRAYSCALE:
+ case JCS_RGB:
+ case JCS_YCbCr:
+ cinfo->out_color_space = JCS_RGB;
+ break;
+
+ case JCS_CMYK:
+ case JCS_YCCK:
+ cinfo->out_color_space = JCS_CMYK;
+ context->cmyk_buf = g_new (guchar, (cinfo->output_width *
+ cinfo->output_components *
+ cinfo->rec_outbuf_height));
+ break;
+ }
+
if (rc == JPEG_SUSPENDED)
continue;
@@ -647,16 +725,29 @@ gdk_pixbuf__jpeg_image_load_increment (g
*lptr++ = rowptr;
rowptr += context->pixbuf->rowstride;
}
-
- nlines = jpeg_read_scanlines (cinfo, lines,
- cinfo->rec_outbuf_height);
+
+ if (cinfo->out_color_space == JCS_CMYK) {
+ guchar *cmyk_lines[4];
+
+ for (i = 0; i < cinfo->rec_outbuf_height; i++) {
+ cmyk_lines[i] = (context->cmyk_buf +
+ i * (cinfo->output_width *
+ cinfo->output_components));
+ }
+
+ nlines = jpeg_read_scanlines (cinfo, cmyk_lines,
+ cinfo->rec_outbuf_height);
+
+ if (nlines > 0)
+ convert_cmyk_lines (cinfo, cmyk_lines, lines);
+ } else {
+ nlines = jpeg_read_scanlines (cinfo, lines,
+ cinfo->rec_outbuf_height);
+ }
+
if (nlines == 0)
break;
- /* handle gray */
- if (cinfo->output_components == 1)
- explode_gray_into_buf (cinfo, lines);
-
context->dptr += nlines * context->pixbuf->rowstride;
/* send updated signal */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]