Learn more  » Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Bower components Debian packages RPM packages NuGet packages

squarecapadmin / Pillow   python

Repository URL to install this package:

/ src / PIL / ImageCms.py

# The Python Imaging Library.
# $Id$

# Optional color management support, based on Kevin Cazabon's PyCMS
# library.

# History:

# 2009-03-08 fl   Added to PIL.

# Copyright (C) 2002-2003 Kevin Cazabon
# Copyright (c) 2009 by Fredrik Lundh
# Copyright (c) 2013 by Eric Soroos

# See the README file for information on usage and redistribution.  See
# below for the original description.

from __future__ import print_function
import sys

from PIL import Image
try:
    from PIL import _imagingcms
except ImportError as ex:
    # Allow error import for doc purposes, but error out when accessing
    # anything in core.
    from _util import deferred_error
    _imagingcms = deferred_error(ex)
from PIL._util import isStringType

DESCRIPTION = """
pyCMS

    a Python / PIL interface to the littleCMS ICC Color Management System
    Copyright (C) 2002-2003 Kevin Cazabon
    kevin@cazabon.com
    http://www.cazabon.com

    pyCMS home page:  http://www.cazabon.com/pyCMS
    littleCMS home page:  http://www.littlecms.com
    (littleCMS is Copyright (C) 1998-2001 Marti Maria)

    Originally released under LGPL.  Graciously donated to PIL in
    March 2009, for distribution under the standard PIL license

    The pyCMS.py module provides a "clean" interface between Python/PIL and
    pyCMSdll, taking care of some of the more complex handling of the direct
    pyCMSdll functions, as well as error-checking and making sure that all
    relevant data is kept together.

    While it is possible to call pyCMSdll functions directly, it's not highly
    recommended.

    Version History:

        1.0.0 pil       Oct 2013 Port to LCMS 2.

        0.1.0 pil mod   March 10, 2009

                        Renamed display profile to proof profile. The proof
                        profile is the profile of the device that is being
                        simulated, not the profile of the device which is
                        actually used to display/print the final simulation
                        (that'd be the output profile) - also see LCMSAPI.txt
                        input colorspace -> using 'renderingIntent' -> proof
                        colorspace -> using 'proofRenderingIntent' -> output
                        colorspace

                        Added LCMS FLAGS support.
                        Added FLAGS["SOFTPROOFING"] as default flag for
                        buildProofTransform (otherwise the proof profile/intent
                        would be ignored).

        0.1.0 pil       March 2009 - added to PIL, as PIL.ImageCms

        0.0.2 alpha     Jan 6, 2002

                        Added try/except statements around type() checks of
                        potential CObjects... Python won't let you use type()
                        on them, and raises a TypeError (stupid, if you ask
                        me!)

                        Added buildProofTransformFromOpenProfiles() function.
                        Additional fixes in DLL, see DLL code for details.

        0.0.1 alpha     first public release, Dec. 26, 2002

    Known to-do list with current version (of Python interface, not pyCMSdll):

        none

"""

VERSION = "1.0.0 pil"

# --------------------------------------------------------------------.

core = _imagingcms

#
# intent/direction values

INTENT_PERCEPTUAL = 0
INTENT_RELATIVE_COLORIMETRIC = 1
INTENT_SATURATION = 2
INTENT_ABSOLUTE_COLORIMETRIC = 3

DIRECTION_INPUT = 0
DIRECTION_OUTPUT = 1
DIRECTION_PROOF = 2

#
# flags

FLAGS = {
    "MATRIXINPUT": 1,
    "MATRIXOUTPUT": 2,
    "MATRIXONLY": (1 | 2),
    "NOWHITEONWHITEFIXUP": 4,  # Don't hot fix scum dot
    # Don't create prelinearization tables on precalculated transforms
    # (internal use):
    "NOPRELINEARIZATION": 16,
    "GUESSDEVICECLASS": 32,  # Guess device class (for transform2devicelink)
    "NOTCACHE": 64,  # Inhibit 1-pixel cache
    "NOTPRECALC": 256,
    "NULLTRANSFORM": 512,  # Don't transform anyway
    "HIGHRESPRECALC": 1024,  # Use more memory to give better accuracy
    "LOWRESPRECALC": 2048,  # Use less memory to minimize resources
    "WHITEBLACKCOMPENSATION": 8192,
    "BLACKPOINTCOMPENSATION": 8192,
    "GAMUTCHECK": 4096,  # Out of Gamut alarm
    "SOFTPROOFING": 16384,  # Do softproofing
    "PRESERVEBLACK": 32768,  # Black preservation
    "NODEFAULTRESOURCEDEF": 16777216,  # CRD special
    "GRIDPOINTS": lambda n: ((n) & 0xFF) << 16  # Gridpoints
}

_MAX_FLAG = 0
for flag in FLAGS.values():
    if isinstance(flag, int):
        _MAX_FLAG = _MAX_FLAG | flag


# --------------------------------------------------------------------.
# Experimental PIL-level API
# --------------------------------------------------------------------.

##
# Profile.

class ImageCmsProfile(object):

    def __init__(self, profile):
        """
        :param profile: Either a string representing a filename,
            a file like object containing a profile or a
            low-level profile object

        """

        if isStringType(profile):
            self._set(core.profile_open(profile), profile)
        elif hasattr(profile, "read"):
            self._set(core.profile_frombytes(profile.read()))
        elif isinstance(profile, _imagingcms.CmsProfile):
            self._set(profile)
        else:
            raise TypeError("Invalid type for Profile")

    def _set(self, profile, filename=None):
        self.profile = profile
        self.filename = filename
        if profile:
            self.product_name = None  # profile.product_name
            self.product_info = None  # profile.product_info
        else:
            self.product_name = None
            self.product_info = None

    def tobytes(self):
        """
        Returns the profile in a format suitable for embedding in
        saved images.

        :returns: a bytes object containing the ICC profile.
        """

        return core.profile_tobytes(self.profile)


class ImageCmsTransform(Image.ImagePointHandler):

    """
    Transform.  This can be used with the procedural API, or with the standard
    Image.point() method.

    Will return the output profile in the output.info['icc_profile'].
    """

    def __init__(self, input, output, input_mode, output_mode,
                 intent=INTENT_PERCEPTUAL, proof=None,
                 proof_intent=INTENT_ABSOLUTE_COLORIMETRIC, flags=0):
        if proof is None:
            self.transform = core.buildTransform(
                input.profile, output.profile,
                input_mode, output_mode,
                intent,
                flags
            )
        else:
            self.transform = core.buildProofTransform(
                input.profile, output.profile, proof.profile,
                input_mode, output_mode,
                intent, proof_intent,
                flags
            )
        # Note: inputMode and outputMode are for pyCMS compatibility only
        self.input_mode = self.inputMode = input_mode
        self.output_mode = self.outputMode = output_mode

        self.output_profile = output

    def point(self, im):
        return self.apply(im)

    def apply(self, im, imOut=None):
        im.load()
        if imOut is None:
            imOut = Image.new(self.output_mode, im.size, None)
        self.transform.apply(im.im.id, imOut.im.id)
        imOut.info['icc_profile'] = self.output_profile.tobytes()
        return imOut

    def apply_in_place(self, im):
        im.load()
        if im.mode != self.output_mode:
            raise ValueError("mode mismatch")  # wrong output mode
        self.transform.apply(im.im.id, im.im.id)
        im.info['icc_profile'] = self.output_profile.tobytes()
        return im


def get_display_profile(handle=None):
    """ (experimental) Fetches the profile for the current display device.
    :returns: None if the profile is not known.
    """

    if sys.platform == "win32":
        from PIL import ImageWin
        if isinstance(handle, ImageWin.HDC):
            profile = core.get_display_profile_win32(handle, 1)
        else:
            profile = core.get_display_profile_win32(handle or 0)
    else:
        try:
            get = _imagingcms.get_display_profile
        except AttributeError:
            return None
        else:
            profile = get()
    return ImageCmsProfile(profile)


# --------------------------------------------------------------------.
# pyCMS compatible layer
# --------------------------------------------------------------------.

class PyCMSError(Exception):

    """ (pyCMS) Exception class.
    This is used for all errors in the pyCMS API. """
    pass


def profileToProfile(
        im, inputProfile, outputProfile, renderingIntent=INTENT_PERCEPTUAL,
        outputMode=None, inPlace=0, flags=0):
    """
    (pyCMS) Applies an ICC transformation to a given image, mapping from
    inputProfile to outputProfile.

    If the input or output profiles specified are not valid filenames, a
    PyCMSError will be raised.  If inPlace == TRUE and outputMode != im.mode,
    a PyCMSError will be raised.  If an error occurs during application of
    the profiles, a PyCMSError will be raised.  If outputMode is not a mode
    supported by the outputProfile (or by pyCMS), a PyCMSError will be
    raised.

    This function applies an ICC transformation to im from inputProfile's
    color space to outputProfile's color space using the specified rendering
    intent to decide how to handle out-of-gamut colors.

    OutputMode can be used to specify that a color mode conversion is to
    be done using these profiles, but the specified profiles must be able
    to handle that mode.  I.e., if converting im from RGB to CMYK using
    profiles, the input profile must handle RGB data, and the output
    profile must handle CMYK data.

    :param im: An open PIL image object (i.e. Image.new(...) or
        Image.open(...), etc.)
    :param inputProfile: String, as a valid filename path to the ICC input
        profile you wish to use for this image, or a profile object
    :param outputProfile: String, as a valid filename path to the ICC output
        profile you wish to use for this image, or a profile object
    :param renderingIntent: Integer (0-3) specifying the rendering intent you
        wish to use for the transform

            INTENT_PERCEPTUAL            = 0 (DEFAULT) (ImageCms.INTENT_PERCEPTUAL)
            INTENT_RELATIVE_COLORIMETRIC = 1 (ImageCms.INTENT_RELATIVE_COLORIMETRIC)
            INTENT_SATURATION            = 2 (ImageCms.INTENT_SATURATION)
            INTENT_ABSOLUTE_COLORIMETRIC = 3 (ImageCms.INTENT_ABSOLUTE_COLORIMETRIC)

        see the pyCMS documentation for details on rendering intents and what
        they do.
    :param outputMode: A valid PIL mode for the output image (i.e. "RGB",
        "CMYK", etc.).  Note: if rendering the image "inPlace", outputMode
        MUST be the same mode as the input, or omitted completely.  If
        omitted, the outputMode will be the same as the mode of the input
        image (im.mode)
    :param inPlace: Boolean (1 = True, None or 0 = False).  If True, the
        original image is modified in-place, and None is returned.  If False
        (default), a new Image object is returned with the transform applied.
    :param flags: Integer (0-...) specifying additional flags
    :returns: Either None or a new PIL image object, depending on value of
        inPlace
    :exception PyCMSError:
    """

    if outputMode is None:
        outputMode = im.mode

    if not isinstance(renderingIntent, int) or not (0 <= renderingIntent <= 3):
        raise PyCMSError("renderingIntent must be an integer between 0 and 3")

    if not isinstance(flags, int) or not (0 <= flags <= _MAX_FLAG):
        raise PyCMSError(
            "flags must be an integer between 0 and %s" + _MAX_FLAG)

    try:
        if not isinstance(inputProfile, ImageCmsProfile):
            inputProfile = ImageCmsProfile(inputProfile)
        if not isinstance(outputProfile, ImageCmsProfile):
            outputProfile = ImageCmsProfile(outputProfile)
        transform = ImageCmsTransform(
            inputProfile, outputProfile, im.mode, outputMode,
Loading ...