Merge pull request #7676 from nulano/lcms2-flags

This commit is contained in:
Hugo van Kemenade 2024-01-06 16:43:20 +02:00 committed by GitHub
commit fcaed26ab1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 110 additions and 16 deletions

View File

@ -90,6 +90,16 @@ def test_sanity():
hopper().point(t) hopper().point(t)
def test_flags():
assert ImageCms.Flags.NONE == 0
assert ImageCms.Flags.GRIDPOINTS(0) == ImageCms.Flags.NONE
assert ImageCms.Flags.GRIDPOINTS(256) == ImageCms.Flags.NONE
assert ImageCms.Flags.GRIDPOINTS(255) == (255 << 16)
assert ImageCms.Flags.GRIDPOINTS(-1) == ImageCms.Flags.GRIDPOINTS(255)
assert ImageCms.Flags.GRIDPOINTS(511) == ImageCms.Flags.GRIDPOINTS(255)
def test_name(): def test_name():
skip_missing() skip_missing()
# get profile information for file # get profile information for file

View File

@ -338,8 +338,8 @@ ImageCms.CmsProfile attributes
.. deprecated:: 3.2.0 .. deprecated:: 3.2.0
.. versionremoved:: 8.0.0 .. versionremoved:: 8.0.0
Some attributes in :py:class:`PIL.ImageCms.CmsProfile` have been removed. From 6.0.0, Some attributes in :py:class:`PIL.ImageCms.core.CmsProfile` have been removed.
they issued a :py:exc:`DeprecationWarning`: From 6.0.0, they issued a :py:exc:`DeprecationWarning`:
======================== =================================================== ======================== ===================================================
Removed Use instead Removed Use instead

View File

@ -8,9 +8,31 @@ The :py:mod:`~PIL.ImageCms` module provides color profile management
support using the LittleCMS2 color management engine, based on Kevin support using the LittleCMS2 color management engine, based on Kevin
Cazabon's PyCMS library. Cazabon's PyCMS library.
.. autoclass:: ImageCmsProfile
:members:
:special-members: __init__
.. autoclass:: ImageCmsTransform .. autoclass:: ImageCmsTransform
:members:
:undoc-members:
:show-inheritance:
.. autoexception:: PyCMSError .. autoexception:: PyCMSError
Constants
---------
.. autoclass:: Intent
:members:
:member-order: bysource
:undoc-members:
.. autoclass:: Direction
:members:
:member-order: bysource
:undoc-members:
.. autoclass:: Flags
:members:
:member-order: bysource
:undoc-members:
Functions Functions
--------- ---------
@ -37,13 +59,15 @@ CmsProfile
---------- ----------
The ICC color profiles are wrapped in an instance of the class The ICC color profiles are wrapped in an instance of the class
:py:class:`CmsProfile`. The specification ICC.1:2010 contains more :py:class:`~core.CmsProfile`. The specification ICC.1:2010 contains more
information about the meaning of the values in ICC profiles. information about the meaning of the values in ICC profiles.
For convenience, all XYZ-values are also given as xyY-values (so they For convenience, all XYZ-values are also given as xyY-values (so they
can be easily displayed in a chromaticity diagram, for example). can be easily displayed in a chromaticity diagram, for example).
.. py:currentmodule:: PIL.ImageCms.core
.. py:class:: CmsProfile .. py:class:: CmsProfile
:canonical: PIL._imagingcms.CmsProfile
.. py:attribute:: creation_date .. py:attribute:: creation_date
:type: Optional[datetime.datetime] :type: Optional[datetime.datetime]

View File

@ -30,7 +30,7 @@ Image.fromstring, im.fromstring and im.tostring
ImageCms.CmsProfile attributes ImageCms.CmsProfile attributes
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Some attributes in :py:class:`PIL.ImageCms.CmsProfile` have been removed: Some attributes in :py:class:`PIL.ImageCms.core.CmsProfile` have been removed:
======================== =================================================== ======================== ===================================================
Removed Use instead Removed Use instead

View File

@ -16,8 +16,10 @@
# below for the original description. # below for the original description.
from __future__ import annotations from __future__ import annotations
import operator
import sys import sys
from enum import IntEnum from enum import IntEnum, IntFlag
from functools import reduce
from . import Image from . import Image
@ -119,6 +121,69 @@ class Direction(IntEnum):
# #
# flags # flags
class Flags(IntFlag):
"""Flags and documentation are taken from ``lcms2.h``."""
NONE = 0
NOCACHE = 0x0040
"""Inhibit 1-pixel cache"""
NOOPTIMIZE = 0x0100
"""Inhibit optimizations"""
NULLTRANSFORM = 0x0200
"""Don't transform anyway"""
GAMUTCHECK = 0x1000
"""Out of Gamut alarm"""
SOFTPROOFING = 0x4000
"""Do softproofing"""
BLACKPOINTCOMPENSATION = 0x2000
NOWHITEONWHITEFIXUP = 0x0004
"""Don't fix scum dot"""
HIGHRESPRECALC = 0x0400
"""Use more memory to give better accuracy"""
LOWRESPRECALC = 0x0800
"""Use less memory to minimize resources"""
# this should be 8BITS_DEVICELINK, but that is not a valid name in Python:
USE_8BITS_DEVICELINK = 0x0008
"""Create 8 bits devicelinks"""
GUESSDEVICECLASS = 0x0020
"""Guess device class (for ``transform2devicelink``)"""
KEEP_SEQUENCE = 0x0080
"""Keep profile sequence for devicelink creation"""
FORCE_CLUT = 0x0002
"""Force CLUT optimization"""
CLUT_POST_LINEARIZATION = 0x0001
"""create postlinearization tables if possible"""
CLUT_PRE_LINEARIZATION = 0x0010
"""create prelinearization tables if possible"""
NONEGATIVES = 0x8000
"""Prevent negative numbers in floating point transforms"""
COPY_ALPHA = 0x04000000
"""Alpha channels are copied on ``cmsDoTransform()``"""
NODEFAULTRESOURCEDEF = 0x01000000
_GRIDPOINTS_1 = 1 << 16
_GRIDPOINTS_2 = 2 << 16
_GRIDPOINTS_4 = 4 << 16
_GRIDPOINTS_8 = 8 << 16
_GRIDPOINTS_16 = 16 << 16
_GRIDPOINTS_32 = 32 << 16
_GRIDPOINTS_64 = 64 << 16
_GRIDPOINTS_128 = 128 << 16
@staticmethod
def GRIDPOINTS(n: int) -> Flags:
"""
Fine-tune control over number of gridpoints
:param n: :py:class:`int` in range ``0 <= n <= 255``
"""
return Flags.NONE | ((n & 0xFF) << 16)
_MAX_FLAG = reduce(operator.or_, Flags)
FLAGS = { FLAGS = {
"MATRIXINPUT": 1, "MATRIXINPUT": 1,
"MATRIXOUTPUT": 2, "MATRIXOUTPUT": 2,
@ -142,11 +207,6 @@ FLAGS = {
"GRIDPOINTS": lambda n: (n & 0xFF) << 16, # Gridpoints "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 # Experimental PIL-level API
@ -218,7 +278,7 @@ class ImageCmsTransform(Image.ImagePointHandler):
intent=Intent.PERCEPTUAL, intent=Intent.PERCEPTUAL,
proof=None, proof=None,
proof_intent=Intent.ABSOLUTE_COLORIMETRIC, proof_intent=Intent.ABSOLUTE_COLORIMETRIC,
flags=0, flags=Flags.NONE,
): ):
if proof is None: if proof is None:
self.transform = core.buildTransform( self.transform = core.buildTransform(
@ -303,7 +363,7 @@ def profileToProfile(
renderingIntent=Intent.PERCEPTUAL, renderingIntent=Intent.PERCEPTUAL,
outputMode=None, outputMode=None,
inPlace=False, inPlace=False,
flags=0, flags=Flags.NONE,
): ):
""" """
(pyCMS) Applies an ICC transformation to a given image, mapping from (pyCMS) Applies an ICC transformation to a given image, mapping from
@ -420,7 +480,7 @@ def buildTransform(
inMode, inMode,
outMode, outMode,
renderingIntent=Intent.PERCEPTUAL, renderingIntent=Intent.PERCEPTUAL,
flags=0, flags=Flags.NONE,
): ):
""" """
(pyCMS) Builds an ICC transform mapping from the ``inputProfile`` to the (pyCMS) Builds an ICC transform mapping from the ``inputProfile`` to the
@ -482,7 +542,7 @@ def buildTransform(
raise PyCMSError(msg) raise PyCMSError(msg)
if not isinstance(flags, int) or not (0 <= flags <= _MAX_FLAG): if not isinstance(flags, int) or not (0 <= flags <= _MAX_FLAG):
msg = "flags must be an integer between 0 and %s" + _MAX_FLAG msg = f"flags must be an integer between 0 and {_MAX_FLAG}"
raise PyCMSError(msg) raise PyCMSError(msg)
try: try:
@ -505,7 +565,7 @@ def buildProofTransform(
outMode, outMode,
renderingIntent=Intent.PERCEPTUAL, renderingIntent=Intent.PERCEPTUAL,
proofRenderingIntent=Intent.ABSOLUTE_COLORIMETRIC, proofRenderingIntent=Intent.ABSOLUTE_COLORIMETRIC,
flags=FLAGS["SOFTPROOFING"], flags=Flags.SOFTPROOFING,
): ):
""" """
(pyCMS) Builds an ICC transform mapping from the ``inputProfile`` to the (pyCMS) Builds an ICC transform mapping from the ``inputProfile`` to the
@ -586,7 +646,7 @@ def buildProofTransform(
raise PyCMSError(msg) raise PyCMSError(msg)
if not isinstance(flags, int) or not (0 <= flags <= _MAX_FLAG): if not isinstance(flags, int) or not (0 <= flags <= _MAX_FLAG):
msg = "flags must be an integer between 0 and %s" + _MAX_FLAG msg = f"flags must be an integer between 0 and {_MAX_FLAG}"
raise PyCMSError(msg) raise PyCMSError(msg)
try: try: