Skip to content

Commit 6a12163

Browse files
committed
Default to default rendering intent from slide ICC profile
ICC profiles don't necessarily support all rendering intents, and aren't necessarily optimized for all the intents they do support. They can also be queried for the rendering intent recommended by the profile creator. Use that by default, instead of absolute colorimetric. Signed-off-by: Benjamin Gilbert <[email protected]>
1 parent 524e121 commit 6a12163

File tree

4 files changed

+31
-25
lines changed

4 files changed

+31
-25
lines changed

doc/index.rst

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -213,22 +213,21 @@ To include the profile in an image file when saving the image to disk::
213213
image.save(filename, icc_profile=image.info.get('icc_profile'))
214214

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

219220
from io import BytesIO
220221
from PIL import ImageCms
221222

222223
fromProfile = ImageCms.getOpenProfile(BytesIO(image.info['icc_profile']))
223224
toProfile = ImageCms.createProfile('sRGB')
225+
intent = ImageCms.getDefaultIntent(fromProfile)
224226
ImageCms.profileToProfile(
225-
image, fromProfile, toProfile,
226-
ImageCms.Intent.ABSOLUTE_COLORIMETRIC, 'RGBA', True, 0
227+
image, fromProfile, toProfile, intent, 'RGBA', True, 0
227228
)
228229

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

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

240239
toProfile = ImageCms.createProfile('sRGB')
240+
intent = ImageCms.getDefaultIntent(slide.color_profile)
241241
transform = ImageCms.buildTransform(
242-
slide.color_profile, toProfile, 'RGBA', 'RGBA',
243-
ImageCms.Intent.ABSOLUTE_COLORIMETRIC, 0
242+
slide.color_profile, toProfile, 'RGBA', 'RGBA', intent, 0
244243
)
245244
# for each region image:
246245
ImageCms.applyTransform(image, transform, True)
247246

248-
.. _maximizes the comparability: https://www.ncbi.nlm.nih.gov/pmc/articles/PMC4478790/
249-
250247

251248
Caching
252249
-------

examples/deepzoom/deepzoom_multiserver.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ def create_app(config=None, config_file=None):
7373
DEEPZOOM_OVERLAP=1,
7474
DEEPZOOM_LIMIT_BOUNDS=True,
7575
DEEPZOOM_TILE_QUALITY=75,
76-
DEEPZOOM_COLOR_MODE='absolute-colorimetric',
76+
DEEPZOOM_COLOR_MODE='default',
7777
)
7878
app.config.from_envvar('DEEPZOOM_MULTISERVER_SETTINGS', silent=True)
7979
if config_file is not None:
@@ -212,6 +212,8 @@ def _get_transform(self, image):
212212
elif mode == 'embed':
213213
# embed ICC profile in tiles
214214
return lambda img: None
215+
elif mode == 'default':
216+
intent = ImageCms.getDefaultIntent(image.color_profile)
215217
elif mode == 'absolute-colorimetric':
216218
intent = ImageCms.Intent.ABSOLUTE_COLORIMETRIC
217219
elif mode == 'relative-colorimetric':
@@ -276,18 +278,19 @@ def __init__(self, relpath):
276278
'--color-mode',
277279
dest='DEEPZOOM_COLOR_MODE',
278280
choices=[
281+
'default',
279282
'absolute-colorimetric',
280283
'perceptual',
281284
'relative-colorimetric',
282285
'saturation',
283286
'embed',
284287
'ignore',
285288
],
286-
default='absolute-colorimetric',
289+
default='default',
287290
help=(
288-
'convert tiles to sRGB using specified rendering intent, or '
289-
'embed original ICC profile, or ignore ICC profile (compat) '
290-
'[absolute-colorimetric]'
291+
'convert tiles to sRGB using default rendering intent of ICC '
292+
'profile, or specified rendering intent; or embed original '
293+
'ICC profile; or ignore ICC profile (compat) [default]'
291294
),
292295
)
293296
parser.add_argument(

examples/deepzoom/deepzoom_server.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ def create_app(config=None, config_file=None):
7373
DEEPZOOM_OVERLAP=1,
7474
DEEPZOOM_LIMIT_BOUNDS=True,
7575
DEEPZOOM_TILE_QUALITY=75,
76-
DEEPZOOM_COLOR_MODE='absolute-colorimetric',
76+
DEEPZOOM_COLOR_MODE='default',
7777
)
7878
app.config.from_envvar('DEEPZOOM_TILER_SETTINGS', silent=True)
7979
if config_file is not None:
@@ -182,6 +182,8 @@ def get_transform(image, mode):
182182
elif mode == 'embed':
183183
# embed ICC profile in tiles
184184
return lambda img: None
185+
elif mode == 'default':
186+
intent = ImageCms.getDefaultIntent(image.color_profile)
185187
elif mode == 'absolute-colorimetric':
186188
intent = ImageCms.Intent.ABSOLUTE_COLORIMETRIC
187189
elif mode == 'relative-colorimetric':
@@ -224,18 +226,19 @@ def xfrm(img):
224226
'--color-mode',
225227
dest='DEEPZOOM_COLOR_MODE',
226228
choices=[
229+
'default',
227230
'absolute-colorimetric',
228231
'perceptual',
229232
'relative-colorimetric',
230233
'saturation',
231234
'embed',
232235
'ignore',
233236
],
234-
default='absolute-colorimetric',
237+
default='default',
235238
help=(
236-
'convert tiles to sRGB using specified rendering intent, or '
237-
'embed original ICC profile, or ignore ICC profile (compat) '
238-
'[absolute-colorimetric]'
239+
'convert tiles to sRGB using default rendering intent of ICC '
240+
'profile, or specified rendering intent; or embed original '
241+
'ICC profile; or ignore ICC profile (compat) [default]'
239242
),
240243
)
241244
parser.add_argument(

examples/deepzoom/deepzoom_tile.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,8 @@ def _get_transform(self, image):
125125
elif mode == 'embed':
126126
# embed ICC profile in tiles
127127
return lambda img: None
128+
elif mode == 'default':
129+
intent = ImageCms.getDefaultIntent(image.color_profile)
128130
elif mode == 'absolute-colorimetric':
129131
intent = ImageCms.Intent.ABSOLUTE_COLORIMETRIC
130132
elif mode == 'relative-colorimetric':
@@ -356,18 +358,19 @@ def _shutdown(self):
356358
'--color-mode',
357359
dest='color_mode',
358360
choices=[
361+
'default',
359362
'absolute-colorimetric',
360363
'perceptual',
361364
'relative-colorimetric',
362365
'saturation',
363366
'embed',
364367
'ignore',
365368
],
366-
default='absolute-colorimetric',
369+
default='default',
367370
help=(
368-
'convert tiles to sRGB using specified rendering intent, or '
369-
'embed original ICC profile, or ignore ICC profile (compat) '
370-
'[absolute-colorimetric]'
371+
'convert tiles to sRGB using default rendering intent of ICC '
372+
'profile, or specified rendering intent; or embed original '
373+
'ICC profile; or ignore ICC profile (compat) [default]'
371374
),
372375
)
373376
parser.add_argument(

0 commit comments

Comments
 (0)