Skip to content

Commit

Permalink
Merge pull request #227 from bgilbert/default-intent
Browse files Browse the repository at this point in the history
Default to default rendering intent from slide ICC profile
  • Loading branch information
bgilbert authored Oct 8, 2023
2 parents 524e121 + 6a12163 commit bd74845
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 25 deletions.
19 changes: 8 additions & 11 deletions doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -213,22 +213,21 @@ To include the profile in an image file when saving the image to disk::
image.save(filename, icc_profile=image.info.get('icc_profile'))

To perform color conversions using the profile, import it into
:mod:`ImageCms <PIL.ImageCms>`. For example, to convert an image in-place
to a synthesized sRGB profile, using absolute colorimetric rendering::
:mod:`ImageCms <PIL.ImageCms>`. For example, to synthesize an sRGB profile
and use it to transform an image for display, with the default rendering
intent of the image's profile::

from io import BytesIO
from PIL import ImageCms

fromProfile = ImageCms.getOpenProfile(BytesIO(image.info['icc_profile']))
toProfile = ImageCms.createProfile('sRGB')
intent = ImageCms.getDefaultIntent(fromProfile)
ImageCms.profileToProfile(
image, fromProfile, toProfile,
ImageCms.Intent.ABSOLUTE_COLORIMETRIC, 'RGBA', True, 0
image, fromProfile, toProfile, intent, 'RGBA', True, 0
)

Absolute colorimetric rendering `maximizes the comparability`_ of images
produced by different scanners. When converting Deep Zoom tiles, use
``'RGB'`` instead of ``'RGBA'``.
When converting Deep Zoom tiles, use ``'RGB'`` instead of ``'RGBA'``.

All pyramid regions in a slide have the same profile, but each associated
image can have its own profile. As a convenience, the former is also
Expand All @@ -238,15 +237,13 @@ by building an :class:`~PIL.ImageCms.ImageCmsTransform` for the slide and
reusing it for multiple slide regions::

toProfile = ImageCms.createProfile('sRGB')
intent = ImageCms.getDefaultIntent(slide.color_profile)
transform = ImageCms.buildTransform(
slide.color_profile, toProfile, 'RGBA', 'RGBA',
ImageCms.Intent.ABSOLUTE_COLORIMETRIC, 0
slide.color_profile, toProfile, 'RGBA', 'RGBA', intent, 0
)
# for each region image:
ImageCms.applyTransform(image, transform, True)

.. _maximizes the comparability: https://www.ncbi.nlm.nih.gov/pmc/articles/PMC4478790/


Caching
-------
Expand Down
13 changes: 8 additions & 5 deletions examples/deepzoom/deepzoom_multiserver.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ def create_app(config=None, config_file=None):
DEEPZOOM_OVERLAP=1,
DEEPZOOM_LIMIT_BOUNDS=True,
DEEPZOOM_TILE_QUALITY=75,
DEEPZOOM_COLOR_MODE='absolute-colorimetric',
DEEPZOOM_COLOR_MODE='default',
)
app.config.from_envvar('DEEPZOOM_MULTISERVER_SETTINGS', silent=True)
if config_file is not None:
Expand Down Expand Up @@ -212,6 +212,8 @@ def _get_transform(self, image):
elif mode == 'embed':
# embed ICC profile in tiles
return lambda img: None
elif mode == 'default':
intent = ImageCms.getDefaultIntent(image.color_profile)
elif mode == 'absolute-colorimetric':
intent = ImageCms.Intent.ABSOLUTE_COLORIMETRIC
elif mode == 'relative-colorimetric':
Expand Down Expand Up @@ -276,18 +278,19 @@ def __init__(self, relpath):
'--color-mode',
dest='DEEPZOOM_COLOR_MODE',
choices=[
'default',
'absolute-colorimetric',
'perceptual',
'relative-colorimetric',
'saturation',
'embed',
'ignore',
],
default='absolute-colorimetric',
default='default',
help=(
'convert tiles to sRGB using specified rendering intent, or '
'embed original ICC profile, or ignore ICC profile (compat) '
'[absolute-colorimetric]'
'convert tiles to sRGB using default rendering intent of ICC '
'profile, or specified rendering intent; or embed original '
'ICC profile; or ignore ICC profile (compat) [default]'
),
)
parser.add_argument(
Expand Down
13 changes: 8 additions & 5 deletions examples/deepzoom/deepzoom_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ def create_app(config=None, config_file=None):
DEEPZOOM_OVERLAP=1,
DEEPZOOM_LIMIT_BOUNDS=True,
DEEPZOOM_TILE_QUALITY=75,
DEEPZOOM_COLOR_MODE='absolute-colorimetric',
DEEPZOOM_COLOR_MODE='default',
)
app.config.from_envvar('DEEPZOOM_TILER_SETTINGS', silent=True)
if config_file is not None:
Expand Down Expand Up @@ -182,6 +182,8 @@ def get_transform(image, mode):
elif mode == 'embed':
# embed ICC profile in tiles
return lambda img: None
elif mode == 'default':
intent = ImageCms.getDefaultIntent(image.color_profile)
elif mode == 'absolute-colorimetric':
intent = ImageCms.Intent.ABSOLUTE_COLORIMETRIC
elif mode == 'relative-colorimetric':
Expand Down Expand Up @@ -224,18 +226,19 @@ def xfrm(img):
'--color-mode',
dest='DEEPZOOM_COLOR_MODE',
choices=[
'default',
'absolute-colorimetric',
'perceptual',
'relative-colorimetric',
'saturation',
'embed',
'ignore',
],
default='absolute-colorimetric',
default='default',
help=(
'convert tiles to sRGB using specified rendering intent, or '
'embed original ICC profile, or ignore ICC profile (compat) '
'[absolute-colorimetric]'
'convert tiles to sRGB using default rendering intent of ICC '
'profile, or specified rendering intent; or embed original '
'ICC profile; or ignore ICC profile (compat) [default]'
),
)
parser.add_argument(
Expand Down
11 changes: 7 additions & 4 deletions examples/deepzoom/deepzoom_tile.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ def _get_transform(self, image):
elif mode == 'embed':
# embed ICC profile in tiles
return lambda img: None
elif mode == 'default':
intent = ImageCms.getDefaultIntent(image.color_profile)
elif mode == 'absolute-colorimetric':
intent = ImageCms.Intent.ABSOLUTE_COLORIMETRIC
elif mode == 'relative-colorimetric':
Expand Down Expand Up @@ -356,18 +358,19 @@ def _shutdown(self):
'--color-mode',
dest='color_mode',
choices=[
'default',
'absolute-colorimetric',
'perceptual',
'relative-colorimetric',
'saturation',
'embed',
'ignore',
],
default='absolute-colorimetric',
default='default',
help=(
'convert tiles to sRGB using specified rendering intent, or '
'embed original ICC profile, or ignore ICC profile (compat) '
'[absolute-colorimetric]'
'convert tiles to sRGB using default rendering intent of ICC '
'profile, or specified rendering intent; or embed original '
'ICC profile; or ignore ICC profile (compat) [default]'
),
)
parser.add_argument(
Expand Down

0 comments on commit bd74845

Please sign in to comment.