From 95d2f0feabec15ac4552c199b5679653fa736085 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 1 Nov 2013 22:11:46 +0530 Subject: [PATCH] EPUB Output: Add a warning about images in the CMYK colorspace --- .../ebooks/conversion/plugins/epub_output.py | 2 +- src/calibre/ebooks/oeb/transforms/rescale.py | 17 +++++++- src/calibre/utils/magick/__init__.py | 12 ++++++ src/calibre/utils/magick/magick.c | 39 +++++++++++++++++++ 4 files changed, 68 insertions(+), 2 deletions(-) diff --git a/src/calibre/ebooks/conversion/plugins/epub_output.py b/src/calibre/ebooks/conversion/plugins/epub_output.py index 57f06e17ba..254c50dbe6 100644 --- a/src/calibre/ebooks/conversion/plugins/epub_output.py +++ b/src/calibre/ebooks/conversion/plugins/epub_output.py @@ -190,7 +190,7 @@ class EPUBOutput(OutputFormatPlugin): self.workaround_webkit_quirks() self.upshift_markup() from calibre.ebooks.oeb.transforms.rescale import RescaleImages - RescaleImages()(oeb, opts) + RescaleImages(check_colorspaces=True)(oeb, opts) from calibre.ebooks.oeb.transforms.split import Split split = Split(not self.opts.dont_split_on_page_breaks, diff --git a/src/calibre/ebooks/oeb/transforms/rescale.py b/src/calibre/ebooks/oeb/transforms/rescale.py index f9f14b1cb9..bc56280f7d 100644 --- a/src/calibre/ebooks/oeb/transforms/rescale.py +++ b/src/calibre/ebooks/oeb/transforms/rescale.py @@ -9,8 +9,12 @@ __docformat__ = 'restructuredtext en' from calibre import fit_image class RescaleImages(object): + 'Rescale all images to fit inside given screen size' + def __init__(self, check_colorspaces=False): + self.check_colorspaces = check_colorspaces + def __call__(self, oeb, opts): self.oeb, self.opts, self.log = oeb, opts, oeb.log from calibre.gui2 import is_ok_to_use_qt @@ -31,7 +35,8 @@ class RescaleImages(object): for item in self.oeb.manifest: if item.media_type.startswith('image'): ext = item.media_type.split('/')[-1].upper() - if ext == 'JPG': ext = 'JPEG' + if ext == 'JPG': + ext = 'JPEG' if ext not in ('PNG', 'JPEG', 'GIF'): ext = 'JPEG' @@ -46,6 +51,16 @@ class RescaleImages(object): continue width, height = img.size + try: + if self.check_colorspaces and img.colorspace == 'CMYKColorspace': + # We cannot do an automatic conversion of CMYK to RGB as + # ImageMagick inverts colors if you just set the colorspace + # to rgb. See for example: https://bugs.launchpad.net/bugs/1246710 + self.log.warn( + 'The image %s is in the CMYK colorspace, you should convert' + ' it to sRGB as Adobe Digital Editions cannot render CMYK' % item.href) + except Exception: + pass scaled, new_width, new_height = fit_image(width, height, page_width, page_height) diff --git a/src/calibre/utils/magick/__init__.py b/src/calibre/utils/magick/__init__.py index 0c1315eb71..b8ebabe0c1 100644 --- a/src/calibre/utils/magick/__init__.py +++ b/src/calibre/utils/magick/__init__.py @@ -20,6 +20,9 @@ _gravity_map = dict([(getattr(_magick, x), x) for x in dir(_magick) if _type_map = dict([(getattr(_magick, x), x) for x in dir(_magick) if x.endswith('Type')]) +_colorspace_map = dict([(getattr(_magick, x), x) for x in dir(_magick) if + x.endswith('Colorspace')]) + # Font metrics {{{ class Rect(object): @@ -165,6 +168,15 @@ class Image(_magick.Image): # {{{ self.type_ = val return property(fget=fget, fset=fset, doc=_magick.Image.type_.__doc__) + @dynamic_property + def colorspace(self): + def fget(self): + return _colorspace_map[self.colorspace_] + def fset(self, val): + val = getattr(_magick, str(val)) + self.colorspace_ = val + return property(fget=fget, fset=fset, doc=_magick.Image.type_.__doc__) + @dynamic_property def size(self): def fget(self): diff --git a/src/calibre/utils/magick/magick.c b/src/calibre/utils/magick/magick.c index e306ad9065..2c7d47a3b7 100644 --- a/src/calibre/utils/magick/magick.c +++ b/src/calibre/utils/magick/magick.c @@ -1252,6 +1252,41 @@ magick_Image_set_opacity(magick_Image *self, PyObject *args) { } // }}} +// Image.colorspace {{{ +static PyObject * +magick_Image_colorspace_getter(magick_Image *self, void *closure) { + NULL_CHECK(NULL) + + return Py_BuildValue("i", MagickGetImageColorspace(self->wand)); +} + +static int +magick_Image_colorspace_setter(magick_Image *self, PyObject *val, void *closure) { + int cs = RGBColorspace; + + NULL_CHECK(-1) + + if (val == NULL) { + PyErr_SetString(PyExc_TypeError, "Cannot delete image colorspace"); + return -1; + } + + if (!PyInt_Check(val)) { + PyErr_SetString(PyExc_TypeError, "Colorspace must be an integer"); + return -1; + } + + cs = (int)PyInt_AS_LONG(val); + if (!MagickSetImageColorspace(self->wand, cs)) { + PyErr_Format(PyExc_ValueError, "Could not set image colorspace to %d", cs); + return -1; + } + + return 0; +} + +// }}} + // Image attr list {{{ static PyMethodDef magick_Image_methods[] = { {"destroy", (PyCFunction)magick_Image_destroy, METH_VARARGS, @@ -1395,6 +1430,10 @@ static PyGetSetDef magick_Image_getsetters[] = { (char *)"the image depth.", NULL}, + {(char *)"colorspace_", + (getter)magick_Image_colorspace_getter, (setter)magick_Image_colorspace_setter, + (char *)"the image colorspace.", + NULL}, {NULL} /* Sentinel */ };