Skip to content

Commit bd74845

Browse files
authored
Merge pull request #227 from bgilbert/default-intent
Default to default rendering intent from slide ICC profile
2 parents 524e121 + 6a12163 commit bd74845

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)