From e4db4e9e8e129daa2b4b55741cd825bc6fd3c454 Mon Sep 17 00:00:00 2001 From: Erik Jensen Date: Sun, 15 Feb 2015 00:03:16 -0800 Subject: [PATCH] Enable support for CMYK images CMYK TIFFs and JPEGs both work. CMYK JPEG2000 images have not been tested. Adobe Photoshop and some other software generate inverted CMYK JPEGs. The image is assumed to be inverted if the "Adobe" (APP14) tag is present. Images can be forced inverted with `-C "CMYK;I"`, and forced not inverted with `-C CMYK`. --- src/img2pdf.py | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/src/img2pdf.py b/src/img2pdf.py index 45601b4..f923e8b 100755 --- a/src/img2pdf.py +++ b/src/img2pdf.py @@ -121,9 +121,11 @@ class pdfdoc(object): def addimage(self, color, width, height, imgformat, imgdata, pdf_x, pdf_y): if color == 'L': - color = "/DeviceGray" + colorspace = "/DeviceGray" elif color == 'RGB': - color = "/DeviceRGB" + colorspace = "/DeviceRGB" + elif color == 'CMYK' or color == 'CMYK;I': + colorspace = "/DeviceCMYK" else: error_out("unsupported color space: %s"%color) exit(1) @@ -145,12 +147,16 @@ class pdfdoc(object): "/Filter": ofilter, "/Width": width, "/Height": height, - "/ColorSpace": color, + "/ColorSpace": colorspace, # hardcoded as PIL doesnt provide bits for non-jpeg formats "/BitsPerComponent": 8, "/Length": len(imgdata) }, imgdata) + if color == 'CMYK;I': + # Inverts all four channels + image.content['/Decode'] = [1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0] + text = ("q\n%f 0 0 %f 0 0 cm\n/Im0 Do\nQ"%(pdf_x, pdf_y)).encode('utf8') content = obj({ @@ -252,6 +258,16 @@ def convert(images, dpi, x, y, title=None, author=None, creator=None, producer=N debug_out("input colorspace (forced) = %s"%(color), verbose) else: color = imgdata.mode + if color == "CMYK" and imgformat == "JPEG": + # Adobe inverts CMYK JPEGs for some reason, and others + # have followed suit as well. Some software assumes the + # JPEG is inverted if the Adobe tag (APP14), while other + # software assumes all CMYK JPEGs are inverted. I don't + # have enough experience with these to know which is + # better for images currently in the wild, so I'm going + # with the first approach for now. + if "adobe" in imgdata.info: + color = "CMYK;I" debug_out("input colorspace = %s"%(color), verbose) debug_out("width x height = %d x %d"%(width,height), verbose) @@ -270,7 +286,7 @@ def convert(images, dpi, x, y, title=None, author=None, creator=None, producer=N debug_out("Converting colorspace 1 to L", verbose) imgdata = imgdata.convert('L') color = 'L' - elif color in ("RGB", "L"): + elif color in ("RGB", "L", "CMYK", "CMYK;I"): debug_out("Colorspace is OK: %s"%color, verbose) else: debug_out("Converting colorspace %s to RGB"%color, verbose) @@ -347,7 +363,7 @@ parser.add_argument( help='keywords for metadata') parser.add_argument( '-C', '--colorspace', metavar='colorspace', type=str, - help='force PIL colorspace (one of: RGB, L, 1)') + help='force PIL colorspace (one of: RGB, L, 1, CMYK, CMYK;I)') parser.add_argument( '-D', '--nodate', help='do not add timestamps', action="store_true") parser.add_argument(