Skip to content

Commit fcaed26

Browse files
authored
Merge pull request #7676 from nulano/lcms2-flags
2 parents f162d65 + d9ec2fd commit fcaed26

File tree

5 files changed

+110
-16
lines changed

5 files changed

+110
-16
lines changed

Tests/test_imagecms.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,16 @@ def test_sanity():
9090
hopper().point(t)
9191

9292

93+
def test_flags():
94+
assert ImageCms.Flags.NONE == 0
95+
assert ImageCms.Flags.GRIDPOINTS(0) == ImageCms.Flags.NONE
96+
assert ImageCms.Flags.GRIDPOINTS(256) == ImageCms.Flags.NONE
97+
98+
assert ImageCms.Flags.GRIDPOINTS(255) == (255 << 16)
99+
assert ImageCms.Flags.GRIDPOINTS(-1) == ImageCms.Flags.GRIDPOINTS(255)
100+
assert ImageCms.Flags.GRIDPOINTS(511) == ImageCms.Flags.GRIDPOINTS(255)
101+
102+
93103
def test_name():
94104
skip_missing()
95105
# get profile information for file

docs/deprecations.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -338,8 +338,8 @@ ImageCms.CmsProfile attributes
338338
.. deprecated:: 3.2.0
339339
.. versionremoved:: 8.0.0
340340

341-
Some attributes in :py:class:`PIL.ImageCms.CmsProfile` have been removed. From 6.0.0,
342-
they issued a :py:exc:`DeprecationWarning`:
341+
Some attributes in :py:class:`PIL.ImageCms.core.CmsProfile` have been removed.
342+
From 6.0.0, they issued a :py:exc:`DeprecationWarning`:
343343

344344
======================== ===================================================
345345
Removed Use instead

docs/reference/ImageCms.rst

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,31 @@ The :py:mod:`~PIL.ImageCms` module provides color profile management
88
support using the LittleCMS2 color management engine, based on Kevin
99
Cazabon's PyCMS library.
1010

11+
.. autoclass:: ImageCmsProfile
12+
:members:
13+
:special-members: __init__
1114
.. autoclass:: ImageCmsTransform
15+
:members:
16+
:undoc-members:
17+
:show-inheritance:
1218
.. autoexception:: PyCMSError
1319

20+
Constants
21+
---------
22+
23+
.. autoclass:: Intent
24+
:members:
25+
:member-order: bysource
26+
:undoc-members:
27+
.. autoclass:: Direction
28+
:members:
29+
:member-order: bysource
30+
:undoc-members:
31+
.. autoclass:: Flags
32+
:members:
33+
:member-order: bysource
34+
:undoc-members:
35+
1436
Functions
1537
---------
1638

@@ -37,13 +59,15 @@ CmsProfile
3759
----------
3860

3961
The ICC color profiles are wrapped in an instance of the class
40-
:py:class:`CmsProfile`. The specification ICC.1:2010 contains more
62+
:py:class:`~core.CmsProfile`. The specification ICC.1:2010 contains more
4163
information about the meaning of the values in ICC profiles.
4264

4365
For convenience, all XYZ-values are also given as xyY-values (so they
4466
can be easily displayed in a chromaticity diagram, for example).
4567

68+
.. py:currentmodule:: PIL.ImageCms.core
4669
.. py:class:: CmsProfile
70+
:canonical: PIL._imagingcms.CmsProfile
4771

4872
.. py:attribute:: creation_date
4973
:type: Optional[datetime.datetime]

docs/releasenotes/8.0.0.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ Image.fromstring, im.fromstring and im.tostring
3030
ImageCms.CmsProfile attributes
3131
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
3232

33-
Some attributes in :py:class:`PIL.ImageCms.CmsProfile` have been removed:
33+
Some attributes in :py:class:`PIL.ImageCms.core.CmsProfile` have been removed:
3434

3535
======================== ===================================================
3636
Removed Use instead

src/PIL/ImageCms.py

Lines changed: 72 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@
1616
# below for the original description.
1717
from __future__ import annotations
1818

19+
import operator
1920
import sys
20-
from enum import IntEnum
21+
from enum import IntEnum, IntFlag
22+
from functools import reduce
2123

2224
from . import Image
2325

@@ -119,6 +121,69 @@ class Direction(IntEnum):
119121
#
120122
# flags
121123

124+
125+
class Flags(IntFlag):
126+
"""Flags and documentation are taken from ``lcms2.h``."""
127+
128+
NONE = 0
129+
NOCACHE = 0x0040
130+
"""Inhibit 1-pixel cache"""
131+
NOOPTIMIZE = 0x0100
132+
"""Inhibit optimizations"""
133+
NULLTRANSFORM = 0x0200
134+
"""Don't transform anyway"""
135+
GAMUTCHECK = 0x1000
136+
"""Out of Gamut alarm"""
137+
SOFTPROOFING = 0x4000
138+
"""Do softproofing"""
139+
BLACKPOINTCOMPENSATION = 0x2000
140+
NOWHITEONWHITEFIXUP = 0x0004
141+
"""Don't fix scum dot"""
142+
HIGHRESPRECALC = 0x0400
143+
"""Use more memory to give better accuracy"""
144+
LOWRESPRECALC = 0x0800
145+
"""Use less memory to minimize resources"""
146+
# this should be 8BITS_DEVICELINK, but that is not a valid name in Python:
147+
USE_8BITS_DEVICELINK = 0x0008
148+
"""Create 8 bits devicelinks"""
149+
GUESSDEVICECLASS = 0x0020
150+
"""Guess device class (for ``transform2devicelink``)"""
151+
KEEP_SEQUENCE = 0x0080
152+
"""Keep profile sequence for devicelink creation"""
153+
FORCE_CLUT = 0x0002
154+
"""Force CLUT optimization"""
155+
CLUT_POST_LINEARIZATION = 0x0001
156+
"""create postlinearization tables if possible"""
157+
CLUT_PRE_LINEARIZATION = 0x0010
158+
"""create prelinearization tables if possible"""
159+
NONEGATIVES = 0x8000
160+
"""Prevent negative numbers in floating point transforms"""
161+
COPY_ALPHA = 0x04000000
162+
"""Alpha channels are copied on ``cmsDoTransform()``"""
163+
NODEFAULTRESOURCEDEF = 0x01000000
164+
165+
_GRIDPOINTS_1 = 1 << 16
166+
_GRIDPOINTS_2 = 2 << 16
167+
_GRIDPOINTS_4 = 4 << 16
168+
_GRIDPOINTS_8 = 8 << 16
169+
_GRIDPOINTS_16 = 16 << 16
170+
_GRIDPOINTS_32 = 32 << 16
171+
_GRIDPOINTS_64 = 64 << 16
172+
_GRIDPOINTS_128 = 128 << 16
173+
174+
@staticmethod
175+
def GRIDPOINTS(n: int) -> Flags:
176+
"""
177+
Fine-tune control over number of gridpoints
178+
179+
:param n: :py:class:`int` in range ``0 <= n <= 255``
180+
"""
181+
return Flags.NONE | ((n & 0xFF) << 16)
182+
183+
184+
_MAX_FLAG = reduce(operator.or_, Flags)
185+
186+
122187
FLAGS = {
123188
"MATRIXINPUT": 1,
124189
"MATRIXOUTPUT": 2,
@@ -142,11 +207,6 @@ class Direction(IntEnum):
142207
"GRIDPOINTS": lambda n: (n & 0xFF) << 16, # Gridpoints
143208
}
144209

145-
_MAX_FLAG = 0
146-
for flag in FLAGS.values():
147-
if isinstance(flag, int):
148-
_MAX_FLAG = _MAX_FLAG | flag
149-
150210

151211
# --------------------------------------------------------------------.
152212
# Experimental PIL-level API
@@ -218,7 +278,7 @@ def __init__(
218278
intent=Intent.PERCEPTUAL,
219279
proof=None,
220280
proof_intent=Intent.ABSOLUTE_COLORIMETRIC,
221-
flags=0,
281+
flags=Flags.NONE,
222282
):
223283
if proof is None:
224284
self.transform = core.buildTransform(
@@ -303,7 +363,7 @@ def profileToProfile(
303363
renderingIntent=Intent.PERCEPTUAL,
304364
outputMode=None,
305365
inPlace=False,
306-
flags=0,
366+
flags=Flags.NONE,
307367
):
308368
"""
309369
(pyCMS) Applies an ICC transformation to a given image, mapping from
@@ -420,7 +480,7 @@ def buildTransform(
420480
inMode,
421481
outMode,
422482
renderingIntent=Intent.PERCEPTUAL,
423-
flags=0,
483+
flags=Flags.NONE,
424484
):
425485
"""
426486
(pyCMS) Builds an ICC transform mapping from the ``inputProfile`` to the
@@ -482,7 +542,7 @@ def buildTransform(
482542
raise PyCMSError(msg)
483543

484544
if not isinstance(flags, int) or not (0 <= flags <= _MAX_FLAG):
485-
msg = "flags must be an integer between 0 and %s" + _MAX_FLAG
545+
msg = f"flags must be an integer between 0 and {_MAX_FLAG}"
486546
raise PyCMSError(msg)
487547

488548
try:
@@ -505,7 +565,7 @@ def buildProofTransform(
505565
outMode,
506566
renderingIntent=Intent.PERCEPTUAL,
507567
proofRenderingIntent=Intent.ABSOLUTE_COLORIMETRIC,
508-
flags=FLAGS["SOFTPROOFING"],
568+
flags=Flags.SOFTPROOFING,
509569
):
510570
"""
511571
(pyCMS) Builds an ICC transform mapping from the ``inputProfile`` to the
@@ -586,7 +646,7 @@ def buildProofTransform(
586646
raise PyCMSError(msg)
587647

588648
if not isinstance(flags, int) or not (0 <= flags <= _MAX_FLAG):
589-
msg = "flags must be an integer between 0 and %s" + _MAX_FLAG
649+
msg = f"flags must be an integer between 0 and {_MAX_FLAG}"
590650
raise PyCMSError(msg)
591651

592652
try:

0 commit comments

Comments
 (0)