Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add LCMS2 flags to ImageCms #7676

Merged
merged 5 commits into from
Jan 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions Tests/test_imagecms.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,16 @@ def test_sanity():
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():
skip_missing()
# get profile information for file
Expand Down
4 changes: 2 additions & 2 deletions docs/deprecations.rst
Original file line number Diff line number Diff line change
Expand Up @@ -338,8 +338,8 @@ ImageCms.CmsProfile attributes
.. deprecated:: 3.2.0
.. versionremoved:: 8.0.0

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

======================== ===================================================
Removed Use instead
Expand Down
26 changes: 25 additions & 1 deletion docs/reference/ImageCms.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,31 @@ The :py:mod:`~PIL.ImageCms` module provides color profile management
support using the LittleCMS2 color management engine, based on Kevin
Cazabon's PyCMS library.

.. autoclass:: ImageCmsProfile
:members:
:special-members: __init__
.. autoclass:: ImageCmsTransform
:members:
:undoc-members:
nulano marked this conversation as resolved.
Show resolved Hide resolved
:show-inheritance:
.. 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
---------

Expand All @@ -37,13 +59,15 @@ CmsProfile
----------

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.

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

.. py:currentmodule:: PIL.ImageCms.core
.. py:class:: CmsProfile
:canonical: PIL._imagingcms.CmsProfile

.. py:attribute:: creation_date
:type: Optional[datetime.datetime]
Expand Down
2 changes: 1 addition & 1 deletion docs/releasenotes/8.0.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ Image.fromstring, im.fromstring and im.tostring
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
Expand Down
84 changes: 72 additions & 12 deletions src/PIL/ImageCms.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@
# below for the original description.
from __future__ import annotations

import operator
import sys
from enum import IntEnum
from enum import IntEnum, IntFlag
from functools import reduce

from . import Image

Expand Down Expand Up @@ -119,6 +121,69 @@
#
# 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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The purpose of these _GRIDPOINTS_ flags is not for independent use, but rather so that when you look at _MAX_FLAG or the returned values of GRIDPOINTS(), you see the numbers expressed as flags, not just integers, yes?


@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 = {
"MATRIXINPUT": 1,
"MATRIXOUTPUT": 2,
Expand All @@ -142,11 +207,6 @@
"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
Expand Down Expand Up @@ -218,7 +278,7 @@
intent=Intent.PERCEPTUAL,
proof=None,
proof_intent=Intent.ABSOLUTE_COLORIMETRIC,
flags=0,
flags=Flags.NONE,
):
if proof is None:
self.transform = core.buildTransform(
Expand Down Expand Up @@ -303,7 +363,7 @@
renderingIntent=Intent.PERCEPTUAL,
outputMode=None,
inPlace=False,
flags=0,
flags=Flags.NONE,
):
"""
(pyCMS) Applies an ICC transformation to a given image, mapping from
Expand Down Expand Up @@ -420,7 +480,7 @@
inMode,
outMode,
renderingIntent=Intent.PERCEPTUAL,
flags=0,
flags=Flags.NONE,
):
"""
(pyCMS) Builds an ICC transform mapping from the ``inputProfile`` to the
Expand Down Expand Up @@ -482,7 +542,7 @@
raise PyCMSError(msg)

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}"

Check warning on line 545 in src/PIL/ImageCms.py

View check run for this annotation

Codecov / codecov/patch

src/PIL/ImageCms.py#L545

Added line #L545 was not covered by tests
raise PyCMSError(msg)

try:
Expand All @@ -505,7 +565,7 @@
outMode,
renderingIntent=Intent.PERCEPTUAL,
proofRenderingIntent=Intent.ABSOLUTE_COLORIMETRIC,
flags=FLAGS["SOFTPROOFING"],
flags=Flags.SOFTPROOFING,
):
"""
(pyCMS) Builds an ICC transform mapping from the ``inputProfile`` to the
Expand Down Expand Up @@ -586,7 +646,7 @@
raise PyCMSError(msg)

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}"

Check warning on line 649 in src/PIL/ImageCms.py

View check run for this annotation

Codecov / codecov/patch

src/PIL/ImageCms.py#L649

Added line #L649 was not covered by tests
raise PyCMSError(msg)

try:
Expand Down
Loading