mirror of
https://github.com/python-pillow/Pillow.git
synced 2024-12-25 01:16:16 +03:00
commit
841582fa26
|
@ -39,7 +39,7 @@ after_success:
|
|||
- coverage report
|
||||
- coveralls
|
||||
- pip install pep8 pyflakes
|
||||
- pep8 PIL/*.py
|
||||
- pyflakes PIL/*.py
|
||||
- pep8 Tests/*.py
|
||||
- pyflakes Tests/*.py
|
||||
- pep8 --statistics --count PIL/*.py
|
||||
- pep8 --statistics --count Tests/*.py
|
||||
- pyflakes PIL/*.py | tee >(wc -l)
|
||||
- pyflakes Tests/*.py | tee >(wc -l)
|
||||
|
|
351
PIL/ImageCms.py
351
PIL/ImageCms.py
|
@ -1,19 +1,19 @@
|
|||
#
|
||||
# The Python Imaging Library.
|
||||
# $Id$
|
||||
#
|
||||
# optional color managment 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
|
||||
#
|
||||
# See the README file for information on usage and redistribution. See
|
||||
# below for the original description.
|
||||
#
|
||||
"""
|
||||
The Python Imaging Library.
|
||||
$Id$
|
||||
|
||||
Optional color managment 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
|
||||
|
||||
See the README file for information on usage and redistribution. See
|
||||
below for the original description.
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
|
@ -66,7 +66,8 @@ pyCMS
|
|||
|
||||
Added try/except statements arount type() checks of
|
||||
potential CObjects... Python won't let you use type()
|
||||
on them, and raises a TypeError (stupid, if you ask me!)
|
||||
on them, and raises a TypeError (stupid, if you ask
|
||||
me!)
|
||||
|
||||
Added buildProofTransformFromOpenProfiles() function.
|
||||
Additional fixes in DLL, see DLL code for details.
|
||||
|
@ -89,8 +90,8 @@ try:
|
|||
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 _util import import_err
|
||||
_imagingcms = import_err(ex)
|
||||
from PIL._util import isStringType
|
||||
|
||||
core = _imagingcms
|
||||
|
@ -113,22 +114,24 @@ DIRECTION_PROOF = 2
|
|||
FLAGS = {
|
||||
"MATRIXINPUT": 1,
|
||||
"MATRIXOUTPUT": 2,
|
||||
"MATRIXONLY": (1|2),
|
||||
"NOWHITEONWHITEFIXUP": 4, # Don't hot fix scum dot
|
||||
"NOPRELINEARIZATION": 16, # Don't create prelinearization tables on precalculated transforms (internal use)
|
||||
"GUESSDEVICECLASS": 32, # Guess device class (for transform2devicelink)
|
||||
"NOTCACHE": 64, # Inhibit 1-pixel cache
|
||||
"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 accurancy
|
||||
"LOWRESPRECALC": 2048, # Use less memory to minimize resouces
|
||||
"NULLTRANSFORM": 512, # Don't transform anyway
|
||||
"HIGHRESPRECALC": 1024, # Use more memory to give better accurancy
|
||||
"LOWRESPRECALC": 2048, # Use less memory to minimize resouces
|
||||
"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
|
||||
"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
|
||||
|
@ -136,6 +139,7 @@ for flag in FLAGS.values():
|
|||
if isinstance(flag, int):
|
||||
_MAX_FLAG = _MAX_FLAG | flag
|
||||
|
||||
|
||||
# --------------------------------------------------------------------.
|
||||
# Experimental PIL-level API
|
||||
# --------------------------------------------------------------------.
|
||||
|
@ -153,40 +157,42 @@ class ImageCmsProfile:
|
|||
elif hasattr(profile, "read"):
|
||||
self._set(core.profile_frombytes(profile.read()))
|
||||
else:
|
||||
self._set(profile) # assume it's already a profile
|
||||
self._set(profile) # assume it's already a 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
|
||||
self.product_name = None # profile.product_name
|
||||
self.product_info = None # profile.product_info
|
||||
else:
|
||||
self.product_name = None
|
||||
self.product_info = None
|
||||
|
||||
|
||||
class ImageCmsTransform(Image.ImagePointHandler):
|
||||
|
||||
"""Transform. This can be used with the procedural API, or with the
|
||||
standard Image.point() method.
|
||||
"""
|
||||
|
||||
def __init__(self, input, output, input_mode, output_mode,
|
||||
intent=INTENT_PERCEPTUAL,
|
||||
proof=None, proof_intent=INTENT_ABSOLUTE_COLORIMETRIC, flags=0):
|
||||
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
|
||||
|
@ -198,16 +204,17 @@ class ImageCmsTransform(Image.ImagePointHandler):
|
|||
im.load()
|
||||
if imOut is None:
|
||||
imOut = Image.new(self.output_mode, im.size, None)
|
||||
result = self.transform.apply(im.im.id, imOut.im.id)
|
||||
self.transform.apply(im.im.id, imOut.im.id)
|
||||
return imOut
|
||||
|
||||
def apply_in_place(self, im):
|
||||
im.load()
|
||||
if im.mode != self.output_mode:
|
||||
raise ValueError("mode mismatch") # wrong output mode
|
||||
result = self.transform.apply(im.im.id, im.im.id)
|
||||
raise ValueError("mode mismatch") # wrong output mode
|
||||
self.transform.apply(im.im.id, im.im.id)
|
||||
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.
|
||||
|
@ -229,15 +236,21 @@ def get_display_profile(handle=None):
|
|||
profile = get()
|
||||
return ImageCmsProfile(profile)
|
||||
|
||||
|
||||
# --------------------------------------------------------------------.
|
||||
# pyCMS compatible layer
|
||||
# --------------------------------------------------------------------.
|
||||
|
||||
class PyCMSError(Exception):
|
||||
""" (pyCMS) Exception class. This is used for all errors in the pyCMS API. """
|
||||
|
||||
""" (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):
|
||||
|
||||
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.
|
||||
|
@ -259,40 +272,45 @@ def profileToProfile(im, inputProfile, outputProfile, renderingIntent=INTENT_PER
|
|||
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 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
|
||||
: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.
|
||||
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
|
||||
: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):
|
||||
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)
|
||||
raise PyCMSError(
|
||||
"flags must be an integer between 0 and %s" + _MAX_FLAG)
|
||||
|
||||
try:
|
||||
if not isinstance(inputProfile, ImageCmsProfile):
|
||||
|
@ -300,8 +318,9 @@ def profileToProfile(im, inputProfile, outputProfile, renderingIntent=INTENT_PER
|
|||
if not isinstance(outputProfile, ImageCmsProfile):
|
||||
outputProfile = ImageCmsProfile(outputProfile)
|
||||
transform = ImageCmsTransform(
|
||||
inputProfile, outputProfile, im.mode, outputMode, renderingIntent, flags=flags
|
||||
)
|
||||
inputProfile, outputProfile, im.mode, outputMode,
|
||||
renderingIntent, flags=flags
|
||||
)
|
||||
if inPlace:
|
||||
transform.apply_in_place(im)
|
||||
imOut = None
|
||||
|
@ -323,8 +342,8 @@ def getOpenProfile(profileFilename):
|
|||
If profileFilename is not a vaild filename for an ICC profile, a PyCMSError
|
||||
will be raised.
|
||||
|
||||
:param profileFilename: String, as a valid filename path to the ICC profile you
|
||||
wish to open, or a file-like object.
|
||||
:param profileFilename: String, as a valid filename path to the ICC profile
|
||||
you wish to open, or a file-like object.
|
||||
:returns: A CmsProfile class object.
|
||||
:exception PyCMSError:
|
||||
"""
|
||||
|
@ -334,7 +353,10 @@ def getOpenProfile(profileFilename):
|
|||
except (IOError, TypeError, ValueError) as v:
|
||||
raise PyCMSError(v)
|
||||
|
||||
def buildTransform(inputProfile, outputProfile, inMode, outMode, renderingIntent=INTENT_PERCEPTUAL, flags=0):
|
||||
|
||||
def buildTransform(
|
||||
inputProfile, outputProfile, inMode, outMode,
|
||||
renderingIntent=INTENT_PERCEPTUAL, flags=0):
|
||||
"""
|
||||
(pyCMS) Builds an ICC transform mapping from the inputProfile to the
|
||||
outputProfile. Use applyTransform to apply the transform to a given
|
||||
|
@ -367,14 +389,14 @@ def buildTransform(inputProfile, outputProfile, inMode, outMode, renderingIntent
|
|||
manually overridden if you really want to, but I don't know of any
|
||||
time that would be of use, or would even work).
|
||||
|
||||
:param inputProfile: String, as a valid filename path to the ICC input profile
|
||||
you wish to use for this transform, or a profile object
|
||||
:param inputProfile: String, as a valid filename path to the ICC input
|
||||
profile you wish to use for this transform, or a profile object
|
||||
:param outputProfile: String, as a valid filename path to the ICC output
|
||||
profile you wish to use for this transform, or a profile object
|
||||
:param inMode: String, as a valid PIL mode that the appropriate profile also
|
||||
supports (i.e. "RGB", "RGBA", "CMYK", etc.)
|
||||
:param outMode: String, as a valid PIL mode that the appropriate profile also
|
||||
supports (i.e. "RGB", "RGBA", "CMYK", etc.)
|
||||
:param inMode: String, as a valid PIL mode that the appropriate profile
|
||||
also supports (i.e. "RGB", "RGBA", "CMYK", etc.)
|
||||
:param outMode: String, as a valid PIL mode that the appropriate profile
|
||||
also supports (i.e. "RGB", "RGBA", "CMYK", etc.)
|
||||
:param renderingIntent: Integer (0-3) specifying the rendering intent you
|
||||
wish to use for the transform
|
||||
|
||||
|
@ -383,28 +405,37 @@ def buildTransform(inputProfile, outputProfile, inMode, outMode, renderingIntent
|
|||
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.
|
||||
see the pyCMS documentation for details on rendering intents and what
|
||||
they do.
|
||||
:param flags: Integer (0-...) specifying additional flags
|
||||
:returns: A CmsTransform class object.
|
||||
:exception PyCMSError:
|
||||
"""
|
||||
|
||||
if not isinstance(renderingIntent, int) or not (0 <= renderingIntent <=3):
|
||||
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)
|
||||
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)
|
||||
return ImageCmsTransform(inputProfile, outputProfile, inMode, outMode, renderingIntent, flags=flags)
|
||||
return ImageCmsTransform(
|
||||
inputProfile, outputProfile, inMode, outMode,
|
||||
renderingIntent, flags=flags)
|
||||
except (IOError, TypeError, ValueError) as v:
|
||||
raise PyCMSError(v)
|
||||
|
||||
def buildProofTransform(inputProfile, outputProfile, proofProfile, inMode, outMode, renderingIntent=INTENT_PERCEPTUAL, proofRenderingIntent=INTENT_ABSOLUTE_COLORIMETRIC, flags=FLAGS["SOFTPROOFING"]):
|
||||
|
||||
def buildProofTransform(
|
||||
inputProfile, outputProfile, proofProfile, inMode, outMode,
|
||||
renderingIntent=INTENT_PERCEPTUAL,
|
||||
proofRenderingIntent=INTENT_ABSOLUTE_COLORIMETRIC,
|
||||
flags=FLAGS["SOFTPROOFING"]):
|
||||
"""
|
||||
(pyCMS) Builds an ICC transform mapping from the inputProfile to the
|
||||
outputProfile, but tries to simulate the result that would be
|
||||
|
@ -443,17 +474,17 @@ def buildProofTransform(inputProfile, outputProfile, proofProfile, inMode, outMo
|
|||
when the simulated device has a much wider gamut than the output
|
||||
device, you may obtain marginal results.
|
||||
|
||||
:param inputProfile: String, as a valid filename path to the ICC input profile
|
||||
you wish to use for this transform, or a profile object
|
||||
:param inputProfile: String, as a valid filename path to the ICC input
|
||||
profile you wish to use for this transform, or a profile object
|
||||
:param outputProfile: String, as a valid filename path to the ICC output
|
||||
(monitor, usually) profile you wish to use for this transform, or a
|
||||
profile object
|
||||
:param proofProfile: String, as a valid filename path to the ICC proof profile
|
||||
you wish to use for this transform, or a profile object
|
||||
:param inMode: String, as a valid PIL mode that the appropriate profile also
|
||||
supports (i.e. "RGB", "RGBA", "CMYK", etc.)
|
||||
:param outMode: String, as a valid PIL mode that the appropriate profile also
|
||||
supports (i.e. "RGB", "RGBA", "CMYK", etc.)
|
||||
:param proofProfile: String, as a valid filename path to the ICC proof
|
||||
profile you wish to use for this transform, or a profile object
|
||||
:param inMode: String, as a valid PIL mode that the appropriate profile
|
||||
also supports (i.e. "RGB", "RGBA", "CMYK", etc.)
|
||||
:param outMode: String, as a valid PIL mode that the appropriate profile
|
||||
also supports (i.e. "RGB", "RGBA", "CMYK", etc.)
|
||||
:param renderingIntent: Integer (0-3) specifying the rendering intent you
|
||||
wish to use for the input->proof (simulated) transform
|
||||
|
||||
|
@ -462,7 +493,8 @@ def buildProofTransform(inputProfile, outputProfile, proofProfile, inMode, outMo
|
|||
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.
|
||||
see the pyCMS documentation for details on rendering intents and what
|
||||
they do.
|
||||
:param proofRenderingIntent: Integer (0-3) specifying the rendering intent you
|
||||
wish to use for proof->output transform
|
||||
|
||||
|
@ -471,17 +503,19 @@ def buildProofTransform(inputProfile, outputProfile, proofProfile, inMode, outMo
|
|||
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.
|
||||
see the pyCMS documentation for details on rendering intents and what
|
||||
they do.
|
||||
:param flags: Integer (0-...) specifying additional flags
|
||||
:returns: A CmsTransform class object.
|
||||
:exception PyCMSError:
|
||||
"""
|
||||
|
||||
if not isinstance(renderingIntent, int) or not (0 <= renderingIntent <=3):
|
||||
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)
|
||||
raise PyCMSError(
|
||||
"flags must be an integer between 0 and %s" + _MAX_FLAG)
|
||||
|
||||
try:
|
||||
if not isinstance(inputProfile, ImageCmsProfile):
|
||||
|
@ -490,13 +524,16 @@ def buildProofTransform(inputProfile, outputProfile, proofProfile, inMode, outMo
|
|||
outputProfile = ImageCmsProfile(outputProfile)
|
||||
if not isinstance(proofProfile, ImageCmsProfile):
|
||||
proofProfile = ImageCmsProfile(proofProfile)
|
||||
return ImageCmsTransform(inputProfile, outputProfile, inMode, outMode, renderingIntent, proofProfile, proofRenderingIntent, flags)
|
||||
return ImageCmsTransform(
|
||||
inputProfile, outputProfile, inMode, outMode, renderingIntent,
|
||||
proofProfile, proofRenderingIntent, flags)
|
||||
except (IOError, TypeError, ValueError) as v:
|
||||
raise PyCMSError(v)
|
||||
|
||||
buildTransformFromOpenProfiles = buildTransform
|
||||
buildProofTransformFromOpenProfiles = buildProofTransform
|
||||
|
||||
|
||||
def applyTransform(im, transform, inPlace=0):
|
||||
"""
|
||||
(pyCMS) Applies a transform to a given image.
|
||||
|
@ -514,8 +551,8 @@ def applyTransform(im, transform, inPlace=0):
|
|||
is raised.
|
||||
|
||||
This function applies a pre-calculated transform (from
|
||||
ImageCms.buildTransform() or ImageCms.buildTransformFromOpenProfiles()) to an
|
||||
image. The transform can be used for multiple images, saving
|
||||
ImageCms.buildTransform() or ImageCms.buildTransformFromOpenProfiles())
|
||||
to an image. The transform can be used for multiple images, saving
|
||||
considerable calcuation time if doing the same conversion multiple times.
|
||||
|
||||
If you want to modify im in-place instead of receiving a new image as
|
||||
|
@ -528,10 +565,12 @@ def applyTransform(im, transform, inPlace=0):
|
|||
:param im: A PIL Image object, and im.mode must be the same as the inMode
|
||||
supported by the transform.
|
||||
:param transform: A valid CmsTransform class object
|
||||
:param inPlace: Bool (1 == True, 0 or None == False). If True, im is modified
|
||||
in place and None is returned, if False, a new Image object with the
|
||||
transform applied is returned (and im is not changed). The default is False.
|
||||
:returns: Either None, or a new PIL Image object, depending on the value of inPlace
|
||||
:param inPlace: Bool (1 == True, 0 or None == False). If True, im is
|
||||
modified in place and None is returned, if False, a new Image object
|
||||
with the transform applied is returned (and im is not changed). The
|
||||
default is False.
|
||||
:returns: Either None, or a new PIL Image object, depending on the value of
|
||||
inPlace
|
||||
:exception PyCMSError:
|
||||
"""
|
||||
|
||||
|
@ -546,6 +585,7 @@ def applyTransform(im, transform, inPlace=0):
|
|||
|
||||
return imOut
|
||||
|
||||
|
||||
def createProfile(colorSpace, colorTemp=-1):
|
||||
"""
|
||||
(pyCMS) Creates a profile.
|
||||
|
@ -562,30 +602,36 @@ def createProfile(colorSpace, colorTemp=-1):
|
|||
ImageCms.buildTransformFromOpenProfiles() to create a transform to apply
|
||||
to images.
|
||||
|
||||
:param colorSpace: String, the color space of the profile you wish to create.
|
||||
:param colorSpace: String, the color space of the profile you wish to
|
||||
create.
|
||||
Currently only "LAB", "XYZ", and "sRGB" are supported.
|
||||
:param colorTemp: Positive integer for the white point for the profile, in
|
||||
degrees Kelvin (i.e. 5000, 6500, 9600, etc.). The default is for D50
|
||||
illuminant if omitted (5000k). colorTemp is ONLY applied to LAB profiles,
|
||||
and is ignored for XYZ and sRGB.
|
||||
illuminant if omitted (5000k). colorTemp is ONLY applied to LAB
|
||||
profiles, and is ignored for XYZ and sRGB.
|
||||
:returns: A CmsProfile class object
|
||||
:exception PyCMSError:
|
||||
"""
|
||||
|
||||
if colorSpace not in ["LAB", "XYZ", "sRGB"]:
|
||||
raise PyCMSError("Color space not supported for on-the-fly profile creation (%s)" % colorSpace)
|
||||
raise PyCMSError(
|
||||
"Color space not supported for on-the-fly profile creation (%s)"
|
||||
% colorSpace)
|
||||
|
||||
if colorSpace == "LAB":
|
||||
try:
|
||||
colorTemp = float(colorTemp)
|
||||
except:
|
||||
raise PyCMSError("Color temperature must be numeric, \"%s\" not valid" % colorTemp)
|
||||
raise PyCMSError(
|
||||
"Color temperature must be numeric, \"%s\" not valid"
|
||||
% colorTemp)
|
||||
|
||||
try:
|
||||
return core.createProfile(colorSpace, colorTemp)
|
||||
except (TypeError, ValueError) as v:
|
||||
raise PyCMSError(v)
|
||||
|
||||
|
||||
def getProfileName(profile):
|
||||
"""
|
||||
|
||||
|
@ -600,10 +646,10 @@ def getProfileName(profile):
|
|||
profile was originally created. Sometimes this tag also contains
|
||||
additional information supplied by the creator.
|
||||
|
||||
:param profile: EITHER a valid CmsProfile object, OR a string of the filename
|
||||
of an ICC profile.
|
||||
:returns: A string containing the internal name of the profile as stored in an
|
||||
ICC tag.
|
||||
:param profile: EITHER a valid CmsProfile object, OR a string of the
|
||||
filename of an ICC profile.
|
||||
:returns: A string containing the internal name of the profile as stored
|
||||
in an ICC tag.
|
||||
:exception PyCMSError:
|
||||
"""
|
||||
|
||||
|
@ -619,7 +665,7 @@ def getProfileName(profile):
|
|||
manufacturer = profile.profile.product_manufacturer
|
||||
|
||||
if not (model or manufacturer):
|
||||
return profile.profile.product_description+"\n"
|
||||
return profile.profile.product_description + "\n"
|
||||
if not manufacturer or len(model) > 30:
|
||||
return model + "\n"
|
||||
return "%s - %s\n" % (model, manufacturer)
|
||||
|
@ -627,6 +673,7 @@ def getProfileName(profile):
|
|||
except (AttributeError, IOError, TypeError, ValueError) as v:
|
||||
raise PyCMSError(v)
|
||||
|
||||
|
||||
def getProfileInfo(profile):
|
||||
"""
|
||||
(pyCMS) Gets the internal product information for the given profile.
|
||||
|
@ -641,10 +688,10 @@ def getProfileInfo(profile):
|
|||
info tag. This often contains details about the profile, and how it
|
||||
was created, as supplied by the creator.
|
||||
|
||||
:param profile: EITHER a valid CmsProfile object, OR a string of the filename
|
||||
of an ICC profile.
|
||||
:returns: A string containing the internal profile information stored in an ICC
|
||||
tag.
|
||||
:param profile: EITHER a valid CmsProfile object, OR a string of the
|
||||
filename of an ICC profile.
|
||||
:returns: A string containing the internal profile information stored in
|
||||
an ICC tag.
|
||||
:exception PyCMSError:
|
||||
"""
|
||||
|
||||
|
@ -652,7 +699,8 @@ def getProfileInfo(profile):
|
|||
if not isinstance(profile, ImageCmsProfile):
|
||||
profile = ImageCmsProfile(profile)
|
||||
# add an extra newline to preserve pyCMS compatibility
|
||||
# Python, not C. the white point bits weren't working well, so skipping.
|
||||
# Python, not C. the white point bits weren't working well,
|
||||
# so skipping.
|
||||
# // info was description \r\n\r\n copyright \r\n\r\n K007 tag \r\n\r\n whitepoint
|
||||
description = profile.profile.product_description
|
||||
cpright = profile.profile.product_copyright
|
||||
|
@ -660,7 +708,7 @@ def getProfileInfo(profile):
|
|||
for elt in (description, cpright):
|
||||
if elt:
|
||||
arr.append(elt)
|
||||
return "\r\n\r\n".join(arr)+"\r\n\r\n"
|
||||
return "\r\n\r\n".join(arr) + "\r\n\r\n"
|
||||
|
||||
except (AttributeError, IOError, TypeError, ValueError) as v:
|
||||
raise PyCMSError(v)
|
||||
|
@ -679,10 +727,10 @@ def getProfileCopyright(profile):
|
|||
Use this function to obtain the information stored in the profile's
|
||||
copyright tag.
|
||||
|
||||
:param profile: EITHER a valid CmsProfile object, OR a string of the filename
|
||||
of an ICC profile.
|
||||
:returns: A string containing the internal profile information stored in an ICC
|
||||
tag.
|
||||
:param profile: EITHER a valid CmsProfile object, OR a string of the
|
||||
filename of an ICC profile.
|
||||
:returns: A string containing the internal profile information stored in
|
||||
an ICC tag.
|
||||
:exception PyCMSError:
|
||||
"""
|
||||
try:
|
||||
|
@ -693,6 +741,7 @@ def getProfileCopyright(profile):
|
|||
except (AttributeError, IOError, TypeError, ValueError) as v:
|
||||
raise PyCMSError(v)
|
||||
|
||||
|
||||
def getProfileManufacturer(profile):
|
||||
"""
|
||||
(pyCMS) Gets the manufacturer for the given profile.
|
||||
|
@ -700,16 +749,16 @@ def getProfileManufacturer(profile):
|
|||
If profile isn't a valid CmsProfile object or filename to a profile,
|
||||
a PyCMSError is raised.
|
||||
|
||||
If an error occurs while trying to obtain the manufacturer tag, a PyCMSError
|
||||
is raised
|
||||
If an error occurs while trying to obtain the manufacturer tag, a
|
||||
PyCMSError is raised
|
||||
|
||||
Use this function to obtain the information stored in the profile's
|
||||
manufacturer tag.
|
||||
|
||||
:param profile: EITHER a valid CmsProfile object, OR a string of the filename
|
||||
of an ICC profile.
|
||||
:returns: A string containing the internal profile information stored in an ICC
|
||||
tag.
|
||||
:param profile: EITHER a valid CmsProfile object, OR a string of the
|
||||
filename of an ICC profile.
|
||||
:returns: A string containing the internal profile information stored in
|
||||
an ICC tag.
|
||||
:exception PyCMSError:
|
||||
"""
|
||||
try:
|
||||
|
@ -720,6 +769,7 @@ def getProfileManufacturer(profile):
|
|||
except (AttributeError, IOError, TypeError, ValueError) as v:
|
||||
raise PyCMSError(v)
|
||||
|
||||
|
||||
def getProfileModel(profile):
|
||||
"""
|
||||
(pyCMS) Gets the model for the given profile.
|
||||
|
@ -733,10 +783,10 @@ def getProfileModel(profile):
|
|||
Use this function to obtain the information stored in the profile's
|
||||
model tag.
|
||||
|
||||
:param profile: EITHER a valid CmsProfile object, OR a string of the filename
|
||||
of an ICC profile.
|
||||
:returns: A string containing the internal profile information stored in an ICC
|
||||
tag.
|
||||
:param profile: EITHER a valid CmsProfile object, OR a string of the
|
||||
filename of an ICC profile.
|
||||
:returns: A string containing the internal profile information stored in
|
||||
an ICC tag.
|
||||
:exception PyCMSError:
|
||||
"""
|
||||
|
||||
|
@ -748,6 +798,7 @@ def getProfileModel(profile):
|
|||
except (AttributeError, IOError, TypeError, ValueError) as v:
|
||||
raise PyCMSError(v)
|
||||
|
||||
|
||||
def getProfileDescription(profile):
|
||||
"""
|
||||
(pyCMS) Gets the description for the given profile.
|
||||
|
@ -761,10 +812,10 @@ def getProfileDescription(profile):
|
|||
Use this function to obtain the information stored in the profile's
|
||||
description tag.
|
||||
|
||||
:param profile: EITHER a valid CmsProfile object, OR a string of the filename
|
||||
of an ICC profile.
|
||||
:returns: A string containing the internal profile information stored in an ICC
|
||||
tag.
|
||||
:param profile: EITHER a valid CmsProfile object, OR a string of the
|
||||
filename of an ICC profile.
|
||||
:returns: A string containing the internal profile information stored in an
|
||||
ICC tag.
|
||||
:exception PyCMSError:
|
||||
"""
|
||||
|
||||
|
@ -793,16 +844,18 @@ def getDefaultIntent(profile):
|
|||
If you wish to use a different intent than returned, use
|
||||
ImageCms.isIntentSupported() to verify it will work first.
|
||||
|
||||
:param profile: EITHER a valid CmsProfile object, OR a string of the filename
|
||||
of an ICC profile.
|
||||
:returns: Integer 0-3 specifying the default rendering intent for this profile.
|
||||
:param profile: EITHER a valid CmsProfile object, OR a string of the
|
||||
filename of an ICC profile.
|
||||
:returns: Integer 0-3 specifying the default rendering intent for this
|
||||
profile.
|
||||
|
||||
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.
|
||||
see the pyCMS documentation for details on rendering intents and what
|
||||
they do.
|
||||
:exception PyCMSError:
|
||||
"""
|
||||
|
||||
|
@ -813,6 +866,7 @@ def getDefaultIntent(profile):
|
|||
except (AttributeError, IOError, TypeError, ValueError) as v:
|
||||
raise PyCMSError(v)
|
||||
|
||||
|
||||
def isIntentSupported(profile, intent, direction):
|
||||
"""
|
||||
(pyCMS) Checks if a given intent is supported.
|
||||
|
@ -828,17 +882,18 @@ def isIntentSupported(profile, intent, direction):
|
|||
potential PyCMSError that will occur if they don't support the modes
|
||||
you select.
|
||||
|
||||
:param profile: EITHER a valid CmsProfile object, OR a string of the filename
|
||||
of an ICC profile.
|
||||
:param intent: Integer (0-3) specifying the rendering intent you wish to use
|
||||
with this profile
|
||||
:param profile: EITHER a valid CmsProfile object, OR a string of the
|
||||
filename of an ICC profile.
|
||||
:param intent: Integer (0-3) specifying the rendering intent you wish to
|
||||
use with this profile
|
||||
|
||||
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.
|
||||
see the pyCMS documentation for details on rendering intents and what
|
||||
they do.
|
||||
:param direction: Integer specifing if the profile is to be used for input,
|
||||
output, or proof
|
||||
|
||||
|
@ -862,6 +917,7 @@ def isIntentSupported(profile, intent, direction):
|
|||
except (AttributeError, IOError, TypeError, ValueError) as v:
|
||||
raise PyCMSError(v)
|
||||
|
||||
|
||||
def versions():
|
||||
"""
|
||||
(pyCMS) Fetches versions.
|
||||
|
@ -869,8 +925,9 @@ def versions():
|
|||
|
||||
import sys
|
||||
return (
|
||||
VERSION, core.littlecms_version, sys.version.split()[0], Image.VERSION
|
||||
)
|
||||
VERSION, core.littlecms_version,
|
||||
sys.version.split()[0], Image.VERSION
|
||||
)
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
|
||||
|
@ -880,14 +937,16 @@ if __name__ == "__main__":
|
|||
from PIL import ImageCms
|
||||
print(__doc__)
|
||||
|
||||
for f in dir(pyCMS):
|
||||
print("="*80)
|
||||
print("%s" %f)
|
||||
|
||||
for f in dir(ImageCms):
|
||||
doc = None
|
||||
try:
|
||||
exec ("doc = ImageCms.%s.__doc__" %(f))
|
||||
exec("doc = %s.__doc__" % (f))
|
||||
if "pyCMS" in doc:
|
||||
# so we don't get the __doc__ string for imported modules
|
||||
print("=" * 80)
|
||||
print("%s" % f)
|
||||
print(doc)
|
||||
except AttributeError:
|
||||
except (AttributeError, TypeError):
|
||||
pass
|
||||
|
||||
# End of file
|
||||
|
|
|
@ -15,11 +15,12 @@
|
|||
|
||||
__version__ = "0.1"
|
||||
|
||||
from PIL import Image, ImageFile, _binary
|
||||
from PIL import Image, ImageFile
|
||||
import struct
|
||||
import os
|
||||
import io
|
||||
|
||||
|
||||
def _parse_codestream(fp):
|
||||
"""Parse the JPEG 2000 codestream to extract the size and component
|
||||
count from the SIZ marker segment, returning a PIL (size, mode) tuple."""
|
||||
|
@ -28,7 +29,7 @@ def _parse_codestream(fp):
|
|||
lsiz = struct.unpack('>H', hdr)[0]
|
||||
siz = hdr + fp.read(lsiz - 2)
|
||||
lsiz, rsiz, xsiz, ysiz, xosiz, yosiz, xtsiz, ytsiz, \
|
||||
xtosiz, ytosiz, csiz \
|
||||
xtosiz, ytosiz, csiz \
|
||||
= struct.unpack('>HHIIIIIIIIH', siz[:38])
|
||||
ssiz = [None]*csiz
|
||||
xrsiz = [None]*csiz
|
||||
|
@ -51,6 +52,7 @@ def _parse_codestream(fp):
|
|||
|
||||
return (size, mode)
|
||||
|
||||
|
||||
def _parse_jp2_header(fp):
|
||||
"""Parse the JP2 header box to extract size, component count and
|
||||
color space information, returning a PIL (size, mode) tuple."""
|
||||
|
@ -90,7 +92,7 @@ def _parse_jp2_header(fp):
|
|||
|
||||
if tbox == b'ihdr':
|
||||
height, width, nc, bpc, c, unkc, ipr \
|
||||
= struct.unpack('>IIHBBBB', content)
|
||||
= struct.unpack('>IIHBBBB', content)
|
||||
size = (width, height)
|
||||
if unkc:
|
||||
if nc == 1:
|
||||
|
@ -112,13 +114,13 @@ def _parse_jp2_header(fp):
|
|||
elif nc == 4:
|
||||
mode = 'RGBA'
|
||||
break
|
||||
elif cs == 17: # grayscale
|
||||
elif cs == 17: # grayscale
|
||||
if nc == 1:
|
||||
mode = 'L'
|
||||
elif nc == 2:
|
||||
mode = 'LA'
|
||||
break
|
||||
elif cs == 18: # sYCC
|
||||
elif cs == 18: # sYCC
|
||||
if nc == 3:
|
||||
mode = 'RGB'
|
||||
elif nc == 4:
|
||||
|
@ -127,6 +129,7 @@ def _parse_jp2_header(fp):
|
|||
|
||||
return (size, mode)
|
||||
|
||||
|
||||
##
|
||||
# Image plugin for JPEG2000 images.
|
||||
|
||||
|
@ -180,10 +183,12 @@ class Jpeg2KImageFile(ImageFile.ImageFile):
|
|||
|
||||
ImageFile.ImageFile.load(self)
|
||||
|
||||
|
||||
def _accept(prefix):
|
||||
return (prefix[:4] == b'\xff\x4f\xff\x51'
|
||||
or prefix[:12] == b'\x00\x00\x00\x0cjP \x0d\x0a\x87\x0a')
|
||||
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# Save support
|
||||
|
||||
|
@ -228,7 +233,7 @@ def _save(im, fp, filename):
|
|||
progression,
|
||||
cinema_mode,
|
||||
fd
|
||||
)
|
||||
)
|
||||
|
||||
ImageFile._save(im, fp, [('jpeg2k', (0, 0)+im.size, 0, kind)])
|
||||
|
||||
|
|
|
@ -9,12 +9,13 @@ except ImportError:
|
|||
|
||||
SRGB = "Tests/icc/sRGB.icm"
|
||||
|
||||
|
||||
def test_sanity():
|
||||
|
||||
# basic smoke test.
|
||||
# this mostly follows the cms_test outline.
|
||||
|
||||
v = ImageCms.versions() # should return four strings
|
||||
v = ImageCms.versions() # should return four strings
|
||||
assert_equal(v[0], '1.0.0 pil')
|
||||
assert_equal(list(map(type, v)), [str, str, str, str])
|
||||
|
||||
|
@ -24,10 +25,19 @@ def test_sanity():
|
|||
i = ImageCms.profileToProfile(lena(), SRGB, SRGB)
|
||||
assert_image(i, "RGB", (128, 128))
|
||||
|
||||
i = lena()
|
||||
ImageCms.profileToProfile(i, SRGB, SRGB, inPlace=True)
|
||||
assert_image(i, "RGB", (128, 128))
|
||||
|
||||
t = ImageCms.buildTransform(SRGB, SRGB, "RGB", "RGB")
|
||||
i = ImageCms.applyTransform(lena(), t)
|
||||
assert_image(i, "RGB", (128, 128))
|
||||
|
||||
i = lena()
|
||||
t = ImageCms.buildTransform(SRGB, SRGB, "RGB", "RGB")
|
||||
ImageCms.applyTransform(lena(), t, inPlace=True)
|
||||
assert_image(i, "RGB", (128, 128))
|
||||
|
||||
p = ImageCms.createProfile("sRGB")
|
||||
o = ImageCms.getOpenProfile(SRGB)
|
||||
t = ImageCms.buildTransformFromOpenProfiles(p, o, "RGB", "RGB")
|
||||
|
@ -41,24 +51,47 @@ def test_sanity():
|
|||
assert_image(i, "RGB", (128, 128))
|
||||
|
||||
# test PointTransform convenience API
|
||||
im = lena().point(t)
|
||||
lena().point(t)
|
||||
|
||||
|
||||
def test_name():
|
||||
# get profile information for file
|
||||
assert_equal(ImageCms.getProfileName(SRGB).strip(),
|
||||
'IEC 61966-2.1 Default RGB colour space - sRGB')
|
||||
def x_test_info():
|
||||
|
||||
|
||||
def test_info():
|
||||
assert_equal(ImageCms.getProfileInfo(SRGB).splitlines(),
|
||||
['sRGB IEC61966-2.1', '',
|
||||
'Copyright (c) 1998 Hewlett-Packard Company', '',
|
||||
'WhitePoint : D65 (daylight)', '',
|
||||
'Tests/icc/sRGB.icm'])
|
||||
'Copyright (c) 1998 Hewlett-Packard Company', ''])
|
||||
|
||||
|
||||
def test_copyright():
|
||||
assert_equal(ImageCms.getProfileCopyright(SRGB).strip(),
|
||||
'Copyright (c) 1998 Hewlett-Packard Company')
|
||||
|
||||
|
||||
def test_manufacturer():
|
||||
assert_equal(ImageCms.getProfileManufacturer(SRGB).strip(),
|
||||
'IEC http://www.iec.ch')
|
||||
|
||||
|
||||
def test_model():
|
||||
assert_equal(ImageCms.getProfileModel(SRGB).strip(),
|
||||
'IEC 61966-2.1 Default RGB colour space - sRGB')
|
||||
|
||||
|
||||
def test_description():
|
||||
assert_equal(ImageCms.getProfileDescription(SRGB).strip(),
|
||||
'sRGB IEC61966-2.1')
|
||||
|
||||
|
||||
def test_intent():
|
||||
assert_equal(ImageCms.getDefaultIntent(SRGB), 0)
|
||||
assert_equal(ImageCms.isIntentSupported(
|
||||
SRGB, ImageCms.INTENT_ABSOLUTE_COLORIMETRIC,
|
||||
ImageCms.DIRECTION_INPUT), 1)
|
||||
SRGB, ImageCms.INTENT_ABSOLUTE_COLORIMETRIC,
|
||||
ImageCms.DIRECTION_INPUT), 1)
|
||||
|
||||
|
||||
def test_profile_object():
|
||||
# same, using profile object
|
||||
|
@ -69,8 +102,9 @@ def test_profile_object():
|
|||
# ['sRGB built-in', '', 'WhitePoint : D65 (daylight)', '', ''])
|
||||
assert_equal(ImageCms.getDefaultIntent(p), 0)
|
||||
assert_equal(ImageCms.isIntentSupported(
|
||||
p, ImageCms.INTENT_ABSOLUTE_COLORIMETRIC,
|
||||
ImageCms.DIRECTION_INPUT), 1)
|
||||
p, ImageCms.INTENT_ABSOLUTE_COLORIMETRIC,
|
||||
ImageCms.DIRECTION_INPUT), 1)
|
||||
|
||||
|
||||
def test_extensions():
|
||||
# extensions
|
||||
|
@ -79,12 +113,21 @@ def test_extensions():
|
|||
assert_equal(ImageCms.getProfileName(p).strip(),
|
||||
'IEC 61966-2.1 Default RGB colour space - sRGB')
|
||||
|
||||
|
||||
def test_exceptions():
|
||||
# the procedural pyCMS API uses PyCMSError for all sorts of errors
|
||||
assert_exception(ImageCms.PyCMSError, lambda: ImageCms.profileToProfile(lena(), "foo", "bar"))
|
||||
assert_exception(ImageCms.PyCMSError, lambda: ImageCms.buildTransform("foo", "bar", "RGB", "RGB"))
|
||||
assert_exception(ImageCms.PyCMSError, lambda: ImageCms.getProfileName(None))
|
||||
assert_exception(ImageCms.PyCMSError, lambda: ImageCms.isIntentSupported(SRGB, None, None))
|
||||
assert_exception(
|
||||
ImageCms.PyCMSError,
|
||||
lambda: ImageCms.profileToProfile(lena(), "foo", "bar"))
|
||||
assert_exception(
|
||||
ImageCms.PyCMSError,
|
||||
lambda: ImageCms.buildTransform("foo", "bar", "RGB", "RGB"))
|
||||
assert_exception(
|
||||
ImageCms.PyCMSError,
|
||||
lambda: ImageCms.getProfileName(None))
|
||||
assert_exception(
|
||||
ImageCms.PyCMSError,
|
||||
lambda: ImageCms.isIntentSupported(SRGB, None, None))
|
||||
|
||||
|
||||
def test_display_profile():
|
||||
|
@ -93,37 +136,37 @@ def test_display_profile():
|
|||
|
||||
|
||||
def test_lab_color_profile():
|
||||
pLab = ImageCms.createProfile("LAB", 5000)
|
||||
pLab = ImageCms.createProfile("LAB", 6500)
|
||||
ImageCms.createProfile("LAB", 5000)
|
||||
ImageCms.createProfile("LAB", 6500)
|
||||
|
||||
|
||||
def test_simple_lab():
|
||||
i = Image.new('RGB', (10,10), (128,128,128))
|
||||
i = Image.new('RGB', (10, 10), (128, 128, 128))
|
||||
|
||||
pLab = ImageCms.createProfile("LAB")
|
||||
t = ImageCms.buildTransform(SRGB, pLab, "RGB", "LAB")
|
||||
|
||||
i_lab = ImageCms.applyTransform(i, t)
|
||||
|
||||
|
||||
assert_equal(i_lab.mode, 'LAB')
|
||||
|
||||
k = i_lab.getpixel((0,0))
|
||||
assert_equal(k, (137,128,128)) # not a linear luminance map. so L != 128
|
||||
k = i_lab.getpixel((0, 0))
|
||||
assert_equal(k, (137, 128, 128)) # not a linear luminance map. so L != 128
|
||||
|
||||
L = i_lab.getdata(0)
|
||||
L = i_lab.getdata(0)
|
||||
a = i_lab.getdata(1)
|
||||
b = i_lab.getdata(2)
|
||||
|
||||
assert_equal(list(L), [137]*100)
|
||||
assert_equal(list(a), [128]*100)
|
||||
assert_equal(list(b), [128]*100)
|
||||
assert_equal(list(L), [137] * 100)
|
||||
assert_equal(list(a), [128] * 100)
|
||||
assert_equal(list(b), [128] * 100)
|
||||
|
||||
|
||||
def test_lab_color():
|
||||
pLab = ImageCms.createProfile("LAB")
|
||||
t = ImageCms.buildTransform(SRGB, pLab, "RGB", "LAB")
|
||||
# need to add a type mapping for some PIL type to TYPE_Lab_8 in findLCMSType,
|
||||
# and have that mapping work back to a PIL mode. (likely RGB)
|
||||
# Need to add a type mapping for some PIL type to TYPE_Lab_8 in
|
||||
# findLCMSType, and have that mapping work back to a PIL mode (likely RGB).
|
||||
i = ImageCms.applyTransform(lena(), t)
|
||||
assert_image(i, "LAB", (128, 128))
|
||||
|
||||
|
@ -133,6 +176,7 @@ def test_lab_color():
|
|||
|
||||
assert_image_similar(i, target, 30)
|
||||
|
||||
|
||||
def test_lab_srgb():
|
||||
pLab = ImageCms.createProfile("LAB")
|
||||
t = ImageCms.buildTransform(pLab, SRGB, "LAB", "RGB")
|
||||
|
@ -145,6 +189,7 @@ def test_lab_srgb():
|
|||
|
||||
assert_image_similar(lena(), img_srgb, 30)
|
||||
|
||||
|
||||
def test_lab_roundtrip():
|
||||
# check to see if we're at least internally consistent.
|
||||
pLab = ImageCms.createProfile("LAB")
|
||||
|
@ -156,5 +201,3 @@ def test_lab_roundtrip():
|
|||
out = ImageCms.applyTransform(i, t2)
|
||||
|
||||
assert_image_similar(lena(), out, 2)
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user