Correctly decode Adobe CMYK JPEGs in PDF export From: Peter TB Brett Adobe PhotoShop generates CMYK JPEG files with inverted CMYK. When a JPEG file with this format is included in a PDF file, a `/Decode` array must be included to convert to "normal" CMYK. These JPEG files can be detected via the presence of the APP14 "Adobe" marker. However, PDF viewers are not required to detect and handle this private marker, so it must be detected and handled (by adding a `/Decode`) by the PDF generator. Signed-Off-By: Peter TB Brett --- src/cairo-image-info-private.h | 1 + src/cairo-image-info.c | 21 +++++++++++++++++++++ src/cairo-pdf-surface.c | 2 ++ 3 files changed, 24 insertions(+) diff --git a/src/cairo-image-info-private.h b/src/cairo-image-info-private.h index e64928e..99cbbcc 100644 --- a/src/cairo-image-info-private.h +++ b/src/cairo-image-info-private.h @@ -43,6 +43,7 @@ typedef struct _cairo_image_info { int height; int num_components; int bits_per_component; + int is_adobe_jpeg; } cairo_image_info_t; cairo_private cairo_int_status_t diff --git a/src/cairo-image-info.c b/src/cairo-image-info.c index 26e7ae5..2ecce95 100644 --- a/src/cairo-image-info.c +++ b/src/cairo-image-info.c @@ -67,6 +67,9 @@ #define SOF14 0xce #define SOF15 0xcf +/* Start of tag markers */ +#define APP14 0xee /* Adobe */ + static const unsigned char * _jpeg_skip_segment (const unsigned char *p) { @@ -94,6 +97,8 @@ _cairo_image_info_get_jpeg_info (cairo_image_info_t *info, { const unsigned char *p = data; + info->is_adobe_jpeg = FALSE; + while (p + 1 < data + length) { if (*p != 0xff) return CAIRO_INT_STATUS_UNSUPPORTED; @@ -131,6 +136,18 @@ _cairo_image_info_get_jpeg_info (cairo_image_info_t *info, _jpeg_extract_info (info, p); return CAIRO_STATUS_SUCCESS; + case APP14: + /* "Adobe" tags segment indicates inverted CMYK (in + * CMYK images). */ + if (p + 12 > data + length) + return CAIRO_INT_STATUS_UNSUPPORTED; + + info->is_adobe_jpeg = + (0 == strncmp((const char *)(p + 3), "Adobe", 5)); + + p = _jpeg_skip_segment(p); + break; + default: if (*p >= RST_begin && *p <= RST_end) { p++; @@ -206,6 +223,7 @@ _jpx_extract_info (const unsigned char *p, cairo_image_info_t *info) info->width = get_unaligned_be32 (p + 4); info->num_components = (p[8] << 8) + p[9]; info->bits_per_component = p[10]; + info->is_adobe_jpeg = FALSE; } cairo_int_status_t @@ -283,6 +301,8 @@ _cairo_image_info_get_png_info (cairo_image_info_t *info, p += 4; info->height = get_unaligned_be32 (p); + info->is_adobe_jpeg = FALSE; + return CAIRO_STATUS_SUCCESS; } @@ -395,6 +415,7 @@ _jbig2_extract_info (cairo_image_info_t *info, const unsigned char *p) info->height = get_unaligned_be32 (p + 4); info->num_components = 1; info->bits_per_component = 1; + info->is_adobe_jpeg = FALSE; } cairo_int_status_t diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c index 09094ff..944e9d6 100644 --- a/src/cairo-pdf-surface.c +++ b/src/cairo-pdf-surface.c @@ -2959,6 +2959,7 @@ _cairo_pdf_surface_emit_jpeg_image (cairo_pdf_surface_t *surface, " /Height %d\n" " /ColorSpace %s\n" " /Interpolate %s\n" + "%s" " /BitsPerComponent %d\n" "%s" " /Filter /DCTDecode\n", @@ -2966,6 +2967,7 @@ _cairo_pdf_surface_emit_jpeg_image (cairo_pdf_surface_t *surface, info.height, colorspace, surface_entry->interpolate ? "true" : "false", + info.is_adobe_jpeg && info.num_components == 4 ? " /Decode [ 1 0 1 0 1 0 1 0 ]\n" : "", info.bits_per_component, smask_buf); }