ImageCms.py 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991
  1. # The Python Imaging Library.
  2. # $Id$
  3. # Optional color management support, based on Kevin Cazabon's PyCMS
  4. # library.
  5. # History:
  6. # 2009-03-08 fl Added to PIL.
  7. # Copyright (C) 2002-2003 Kevin Cazabon
  8. # Copyright (c) 2009 by Fredrik Lundh
  9. # Copyright (c) 2013 by Eric Soroos
  10. # See the README file for information on usage and redistribution. See
  11. # below for the original description.
  12. from __future__ import print_function
  13. import sys
  14. from PIL import Image
  15. from PIL._util import isStringType
  16. try:
  17. from PIL import _imagingcms
  18. except ImportError as ex:
  19. # Allow error import for doc purposes, but error out when accessing
  20. # anything in core.
  21. from ._util import deferred_error
  22. _imagingcms = deferred_error(ex)
  23. DESCRIPTION = """
  24. pyCMS
  25. a Python / PIL interface to the littleCMS ICC Color Management System
  26. Copyright (C) 2002-2003 Kevin Cazabon
  27. kevin@cazabon.com
  28. http://www.cazabon.com
  29. pyCMS home page: http://www.cazabon.com/pyCMS
  30. littleCMS home page: http://www.littlecms.com
  31. (littleCMS is Copyright (C) 1998-2001 Marti Maria)
  32. Originally released under LGPL. Graciously donated to PIL in
  33. March 2009, for distribution under the standard PIL license
  34. The pyCMS.py module provides a "clean" interface between Python/PIL and
  35. pyCMSdll, taking care of some of the more complex handling of the direct
  36. pyCMSdll functions, as well as error-checking and making sure that all
  37. relevant data is kept together.
  38. While it is possible to call pyCMSdll functions directly, it's not highly
  39. recommended.
  40. Version History:
  41. 1.0.0 pil Oct 2013 Port to LCMS 2.
  42. 0.1.0 pil mod March 10, 2009
  43. Renamed display profile to proof profile. The proof
  44. profile is the profile of the device that is being
  45. simulated, not the profile of the device which is
  46. actually used to display/print the final simulation
  47. (that'd be the output profile) - also see LCMSAPI.txt
  48. input colorspace -> using 'renderingIntent' -> proof
  49. colorspace -> using 'proofRenderingIntent' -> output
  50. colorspace
  51. Added LCMS FLAGS support.
  52. Added FLAGS["SOFTPROOFING"] as default flag for
  53. buildProofTransform (otherwise the proof profile/intent
  54. would be ignored).
  55. 0.1.0 pil March 2009 - added to PIL, as PIL.ImageCms
  56. 0.0.2 alpha Jan 6, 2002
  57. Added try/except statements around type() checks of
  58. potential CObjects... Python won't let you use type()
  59. on them, and raises a TypeError (stupid, if you ask
  60. me!)
  61. Added buildProofTransformFromOpenProfiles() function.
  62. Additional fixes in DLL, see DLL code for details.
  63. 0.0.1 alpha first public release, Dec. 26, 2002
  64. Known to-do list with current version (of Python interface, not pyCMSdll):
  65. none
  66. """
  67. VERSION = "1.0.0 pil"
  68. # --------------------------------------------------------------------.
  69. core = _imagingcms
  70. #
  71. # intent/direction values
  72. INTENT_PERCEPTUAL = 0
  73. INTENT_RELATIVE_COLORIMETRIC = 1
  74. INTENT_SATURATION = 2
  75. INTENT_ABSOLUTE_COLORIMETRIC = 3
  76. DIRECTION_INPUT = 0
  77. DIRECTION_OUTPUT = 1
  78. DIRECTION_PROOF = 2
  79. #
  80. # flags
  81. FLAGS = {
  82. "MATRIXINPUT": 1,
  83. "MATRIXOUTPUT": 2,
  84. "MATRIXONLY": (1 | 2),
  85. "NOWHITEONWHITEFIXUP": 4, # Don't hot fix scum dot
  86. # Don't create prelinearization tables on precalculated transforms
  87. # (internal use):
  88. "NOPRELINEARIZATION": 16,
  89. "GUESSDEVICECLASS": 32, # Guess device class (for transform2devicelink)
  90. "NOTCACHE": 64, # Inhibit 1-pixel cache
  91. "NOTPRECALC": 256,
  92. "NULLTRANSFORM": 512, # Don't transform anyway
  93. "HIGHRESPRECALC": 1024, # Use more memory to give better accuracy
  94. "LOWRESPRECALC": 2048, # Use less memory to minimize resources
  95. "WHITEBLACKCOMPENSATION": 8192,
  96. "BLACKPOINTCOMPENSATION": 8192,
  97. "GAMUTCHECK": 4096, # Out of Gamut alarm
  98. "SOFTPROOFING": 16384, # Do softproofing
  99. "PRESERVEBLACK": 32768, # Black preservation
  100. "NODEFAULTRESOURCEDEF": 16777216, # CRD special
  101. "GRIDPOINTS": lambda n: ((n) & 0xFF) << 16, # Gridpoints
  102. }
  103. _MAX_FLAG = 0
  104. for flag in FLAGS.values():
  105. if isinstance(flag, int):
  106. _MAX_FLAG = _MAX_FLAG | flag
  107. # --------------------------------------------------------------------.
  108. # Experimental PIL-level API
  109. # --------------------------------------------------------------------.
  110. ##
  111. # Profile.
  112. class ImageCmsProfile(object):
  113. def __init__(self, profile):
  114. """
  115. :param profile: Either a string representing a filename,
  116. a file like object containing a profile or a
  117. low-level profile object
  118. """
  119. if isStringType(profile):
  120. self._set(core.profile_open(profile), profile)
  121. elif hasattr(profile, "read"):
  122. self._set(core.profile_frombytes(profile.read()))
  123. elif isinstance(profile, _imagingcms.CmsProfile):
  124. self._set(profile)
  125. else:
  126. raise TypeError("Invalid type for Profile")
  127. def _set(self, profile, filename=None):
  128. self.profile = profile
  129. self.filename = filename
  130. if profile:
  131. self.product_name = None # profile.product_name
  132. self.product_info = None # profile.product_info
  133. else:
  134. self.product_name = None
  135. self.product_info = None
  136. def tobytes(self):
  137. """
  138. Returns the profile in a format suitable for embedding in
  139. saved images.
  140. :returns: a bytes object containing the ICC profile.
  141. """
  142. return core.profile_tobytes(self.profile)
  143. class ImageCmsTransform(Image.ImagePointHandler):
  144. """
  145. Transform. This can be used with the procedural API, or with the standard
  146. Image.point() method.
  147. Will return the output profile in the output.info['icc_profile'].
  148. """
  149. def __init__(
  150. self,
  151. input,
  152. output,
  153. input_mode,
  154. output_mode,
  155. intent=INTENT_PERCEPTUAL,
  156. proof=None,
  157. proof_intent=INTENT_ABSOLUTE_COLORIMETRIC,
  158. flags=0,
  159. ):
  160. if proof is None:
  161. self.transform = core.buildTransform(
  162. input.profile, output.profile, input_mode, output_mode, intent, flags
  163. )
  164. else:
  165. self.transform = core.buildProofTransform(
  166. input.profile,
  167. output.profile,
  168. proof.profile,
  169. input_mode,
  170. output_mode,
  171. intent,
  172. proof_intent,
  173. flags,
  174. )
  175. # Note: inputMode and outputMode are for pyCMS compatibility only
  176. self.input_mode = self.inputMode = input_mode
  177. self.output_mode = self.outputMode = output_mode
  178. self.output_profile = output
  179. def point(self, im):
  180. return self.apply(im)
  181. def apply(self, im, imOut=None):
  182. im.load()
  183. if imOut is None:
  184. imOut = Image.new(self.output_mode, im.size, None)
  185. self.transform.apply(im.im.id, imOut.im.id)
  186. imOut.info["icc_profile"] = self.output_profile.tobytes()
  187. return imOut
  188. def apply_in_place(self, im):
  189. im.load()
  190. if im.mode != self.output_mode:
  191. raise ValueError("mode mismatch") # wrong output mode
  192. self.transform.apply(im.im.id, im.im.id)
  193. im.info["icc_profile"] = self.output_profile.tobytes()
  194. return im
  195. def get_display_profile(handle=None):
  196. """ (experimental) Fetches the profile for the current display device.
  197. :returns: None if the profile is not known.
  198. """
  199. if sys.platform == "win32":
  200. from PIL import ImageWin
  201. if isinstance(handle, ImageWin.HDC):
  202. profile = core.get_display_profile_win32(handle, 1)
  203. else:
  204. profile = core.get_display_profile_win32(handle or 0)
  205. else:
  206. try:
  207. get = _imagingcms.get_display_profile
  208. except AttributeError:
  209. return None
  210. else:
  211. profile = get()
  212. return ImageCmsProfile(profile)
  213. # --------------------------------------------------------------------.
  214. # pyCMS compatible layer
  215. # --------------------------------------------------------------------.
  216. class PyCMSError(Exception):
  217. """ (pyCMS) Exception class.
  218. This is used for all errors in the pyCMS API. """
  219. pass
  220. def profileToProfile(
  221. im,
  222. inputProfile,
  223. outputProfile,
  224. renderingIntent=INTENT_PERCEPTUAL,
  225. outputMode=None,
  226. inPlace=False,
  227. flags=0,
  228. ):
  229. """
  230. (pyCMS) Applies an ICC transformation to a given image, mapping from
  231. inputProfile to outputProfile.
  232. If the input or output profiles specified are not valid filenames, a
  233. PyCMSError will be raised. If inPlace is True and outputMode != im.mode,
  234. a PyCMSError will be raised. If an error occurs during application of
  235. the profiles, a PyCMSError will be raised. If outputMode is not a mode
  236. supported by the outputProfile (or by pyCMS), a PyCMSError will be
  237. raised.
  238. This function applies an ICC transformation to im from inputProfile's
  239. color space to outputProfile's color space using the specified rendering
  240. intent to decide how to handle out-of-gamut colors.
  241. OutputMode can be used to specify that a color mode conversion is to
  242. be done using these profiles, but the specified profiles must be able
  243. to handle that mode. I.e., if converting im from RGB to CMYK using
  244. profiles, the input profile must handle RGB data, and the output
  245. profile must handle CMYK data.
  246. :param im: An open PIL image object (i.e. Image.new(...) or
  247. Image.open(...), etc.)
  248. :param inputProfile: String, as a valid filename path to the ICC input
  249. profile you wish to use for this image, or a profile object
  250. :param outputProfile: String, as a valid filename path to the ICC output
  251. profile you wish to use for this image, or a profile object
  252. :param renderingIntent: Integer (0-3) specifying the rendering intent you
  253. wish to use for the transform
  254. ImageCms.INTENT_PERCEPTUAL = 0 (DEFAULT)
  255. ImageCms.INTENT_RELATIVE_COLORIMETRIC = 1
  256. ImageCms.INTENT_SATURATION = 2
  257. ImageCms.INTENT_ABSOLUTE_COLORIMETRIC = 3
  258. see the pyCMS documentation for details on rendering intents and what
  259. they do.
  260. :param outputMode: A valid PIL mode for the output image (i.e. "RGB",
  261. "CMYK", etc.). Note: if rendering the image "inPlace", outputMode
  262. MUST be the same mode as the input, or omitted completely. If
  263. omitted, the outputMode will be the same as the mode of the input
  264. image (im.mode)
  265. :param inPlace: Boolean. If True, the original image is modified in-place,
  266. and None is returned. If False (default), a new Image object is
  267. returned with the transform applied.
  268. :param flags: Integer (0-...) specifying additional flags
  269. :returns: Either None or a new PIL image object, depending on value of
  270. inPlace
  271. :exception PyCMSError:
  272. """
  273. if outputMode is None:
  274. outputMode = im.mode
  275. if not isinstance(renderingIntent, int) or not (0 <= renderingIntent <= 3):
  276. raise PyCMSError("renderingIntent must be an integer between 0 and 3")
  277. if not isinstance(flags, int) or not (0 <= flags <= _MAX_FLAG):
  278. raise PyCMSError("flags must be an integer between 0 and %s" + _MAX_FLAG)
  279. try:
  280. if not isinstance(inputProfile, ImageCmsProfile):
  281. inputProfile = ImageCmsProfile(inputProfile)
  282. if not isinstance(outputProfile, ImageCmsProfile):
  283. outputProfile = ImageCmsProfile(outputProfile)
  284. transform = ImageCmsTransform(
  285. inputProfile,
  286. outputProfile,
  287. im.mode,
  288. outputMode,
  289. renderingIntent,
  290. flags=flags,
  291. )
  292. if inPlace:
  293. transform.apply_in_place(im)
  294. imOut = None
  295. else:
  296. imOut = transform.apply(im)
  297. except (IOError, TypeError, ValueError) as v:
  298. raise PyCMSError(v)
  299. return imOut
  300. def getOpenProfile(profileFilename):
  301. """
  302. (pyCMS) Opens an ICC profile file.
  303. The PyCMSProfile object can be passed back into pyCMS for use in creating
  304. transforms and such (as in ImageCms.buildTransformFromOpenProfiles()).
  305. If profileFilename is not a valid filename for an ICC profile, a PyCMSError
  306. will be raised.
  307. :param profileFilename: String, as a valid filename path to the ICC profile
  308. you wish to open, or a file-like object.
  309. :returns: A CmsProfile class object.
  310. :exception PyCMSError:
  311. """
  312. try:
  313. return ImageCmsProfile(profileFilename)
  314. except (IOError, TypeError, ValueError) as v:
  315. raise PyCMSError(v)
  316. def buildTransform(
  317. inputProfile,
  318. outputProfile,
  319. inMode,
  320. outMode,
  321. renderingIntent=INTENT_PERCEPTUAL,
  322. flags=0,
  323. ):
  324. """
  325. (pyCMS) Builds an ICC transform mapping from the inputProfile to the
  326. outputProfile. Use applyTransform to apply the transform to a given
  327. image.
  328. If the input or output profiles specified are not valid filenames, a
  329. PyCMSError will be raised. If an error occurs during creation of the
  330. transform, a PyCMSError will be raised.
  331. If inMode or outMode are not a mode supported by the outputProfile (or
  332. by pyCMS), a PyCMSError will be raised.
  333. This function builds and returns an ICC transform from the inputProfile
  334. to the outputProfile using the renderingIntent to determine what to do
  335. with out-of-gamut colors. It will ONLY work for converting images that
  336. are in inMode to images that are in outMode color format (PIL mode,
  337. i.e. "RGB", "RGBA", "CMYK", etc.).
  338. Building the transform is a fair part of the overhead in
  339. ImageCms.profileToProfile(), so if you're planning on converting multiple
  340. images using the same input/output settings, this can save you time.
  341. Once you have a transform object, it can be used with
  342. ImageCms.applyProfile() to convert images without the need to re-compute
  343. the lookup table for the transform.
  344. The reason pyCMS returns a class object rather than a handle directly
  345. to the transform is that it needs to keep track of the PIL input/output
  346. modes that the transform is meant for. These attributes are stored in
  347. the "inMode" and "outMode" attributes of the object (which can be
  348. manually overridden if you really want to, but I don't know of any
  349. time that would be of use, or would even work).
  350. :param inputProfile: String, as a valid filename path to the ICC input
  351. profile you wish to use for this transform, or a profile object
  352. :param outputProfile: String, as a valid filename path to the ICC output
  353. profile you wish to use for this transform, or a profile object
  354. :param inMode: String, as a valid PIL mode that the appropriate profile
  355. also supports (i.e. "RGB", "RGBA", "CMYK", etc.)
  356. :param outMode: String, as a valid PIL mode that the appropriate profile
  357. also supports (i.e. "RGB", "RGBA", "CMYK", etc.)
  358. :param renderingIntent: Integer (0-3) specifying the rendering intent you
  359. wish to use for the transform
  360. ImageCms.INTENT_PERCEPTUAL = 0 (DEFAULT)
  361. ImageCms.INTENT_RELATIVE_COLORIMETRIC = 1
  362. ImageCms.INTENT_SATURATION = 2
  363. ImageCms.INTENT_ABSOLUTE_COLORIMETRIC = 3
  364. see the pyCMS documentation for details on rendering intents and what
  365. they do.
  366. :param flags: Integer (0-...) specifying additional flags
  367. :returns: A CmsTransform class object.
  368. :exception PyCMSError:
  369. """
  370. if not isinstance(renderingIntent, int) or not (0 <= renderingIntent <= 3):
  371. raise PyCMSError("renderingIntent must be an integer between 0 and 3")
  372. if not isinstance(flags, int) or not (0 <= flags <= _MAX_FLAG):
  373. raise PyCMSError("flags must be an integer between 0 and %s" + _MAX_FLAG)
  374. try:
  375. if not isinstance(inputProfile, ImageCmsProfile):
  376. inputProfile = ImageCmsProfile(inputProfile)
  377. if not isinstance(outputProfile, ImageCmsProfile):
  378. outputProfile = ImageCmsProfile(outputProfile)
  379. return ImageCmsTransform(
  380. inputProfile, outputProfile, inMode, outMode, renderingIntent, flags=flags
  381. )
  382. except (IOError, TypeError, ValueError) as v:
  383. raise PyCMSError(v)
  384. def buildProofTransform(
  385. inputProfile,
  386. outputProfile,
  387. proofProfile,
  388. inMode,
  389. outMode,
  390. renderingIntent=INTENT_PERCEPTUAL,
  391. proofRenderingIntent=INTENT_ABSOLUTE_COLORIMETRIC,
  392. flags=FLAGS["SOFTPROOFING"],
  393. ):
  394. """
  395. (pyCMS) Builds an ICC transform mapping from the inputProfile to the
  396. outputProfile, but tries to simulate the result that would be
  397. obtained on the proofProfile device.
  398. If the input, output, or proof profiles specified are not valid
  399. filenames, a PyCMSError will be raised.
  400. If an error occurs during creation of the transform, a PyCMSError will
  401. be raised.
  402. If inMode or outMode are not a mode supported by the outputProfile
  403. (or by pyCMS), a PyCMSError will be raised.
  404. This function builds and returns an ICC transform from the inputProfile
  405. to the outputProfile, but tries to simulate the result that would be
  406. obtained on the proofProfile device using renderingIntent and
  407. proofRenderingIntent to determine what to do with out-of-gamut
  408. colors. This is known as "soft-proofing". It will ONLY work for
  409. converting images that are in inMode to images that are in outMode
  410. color format (PIL mode, i.e. "RGB", "RGBA", "CMYK", etc.).
  411. Usage of the resulting transform object is exactly the same as with
  412. ImageCms.buildTransform().
  413. Proof profiling is generally used when using an output device to get a
  414. good idea of what the final printed/displayed image would look like on
  415. the proofProfile device when it's quicker and easier to use the
  416. output device for judging color. Generally, this means that the
  417. output device is a monitor, or a dye-sub printer (etc.), and the simulated
  418. device is something more expensive, complicated, or time consuming
  419. (making it difficult to make a real print for color judgement purposes).
  420. Soft-proofing basically functions by adjusting the colors on the
  421. output device to match the colors of the device being simulated. However,
  422. when the simulated device has a much wider gamut than the output
  423. device, you may obtain marginal results.
  424. :param inputProfile: String, as a valid filename path to the ICC input
  425. profile you wish to use for this transform, or a profile object
  426. :param outputProfile: String, as a valid filename path to the ICC output
  427. (monitor, usually) profile you wish to use for this transform, or a
  428. profile object
  429. :param proofProfile: String, as a valid filename path to the ICC proof
  430. profile you wish to use for this transform, or a profile object
  431. :param inMode: String, as a valid PIL mode that the appropriate profile
  432. also supports (i.e. "RGB", "RGBA", "CMYK", etc.)
  433. :param outMode: String, as a valid PIL mode that the appropriate profile
  434. also supports (i.e. "RGB", "RGBA", "CMYK", etc.)
  435. :param renderingIntent: Integer (0-3) specifying the rendering intent you
  436. wish to use for the input->proof (simulated) transform
  437. ImageCms.INTENT_PERCEPTUAL = 0 (DEFAULT)
  438. ImageCms.INTENT_RELATIVE_COLORIMETRIC = 1
  439. ImageCms.INTENT_SATURATION = 2
  440. ImageCms.INTENT_ABSOLUTE_COLORIMETRIC = 3
  441. see the pyCMS documentation for details on rendering intents and what
  442. they do.
  443. :param proofRenderingIntent: Integer (0-3) specifying the rendering intent
  444. you wish to use for proof->output transform
  445. ImageCms.INTENT_PERCEPTUAL = 0 (DEFAULT)
  446. ImageCms.INTENT_RELATIVE_COLORIMETRIC = 1
  447. ImageCms.INTENT_SATURATION = 2
  448. ImageCms.INTENT_ABSOLUTE_COLORIMETRIC = 3
  449. see the pyCMS documentation for details on rendering intents and what
  450. they do.
  451. :param flags: Integer (0-...) specifying additional flags
  452. :returns: A CmsTransform class object.
  453. :exception PyCMSError:
  454. """
  455. if not isinstance(renderingIntent, int) or not (0 <= renderingIntent <= 3):
  456. raise PyCMSError("renderingIntent must be an integer between 0 and 3")
  457. if not isinstance(flags, int) or not (0 <= flags <= _MAX_FLAG):
  458. raise PyCMSError("flags must be an integer between 0 and %s" + _MAX_FLAG)
  459. try:
  460. if not isinstance(inputProfile, ImageCmsProfile):
  461. inputProfile = ImageCmsProfile(inputProfile)
  462. if not isinstance(outputProfile, ImageCmsProfile):
  463. outputProfile = ImageCmsProfile(outputProfile)
  464. if not isinstance(proofProfile, ImageCmsProfile):
  465. proofProfile = ImageCmsProfile(proofProfile)
  466. return ImageCmsTransform(
  467. inputProfile,
  468. outputProfile,
  469. inMode,
  470. outMode,
  471. renderingIntent,
  472. proofProfile,
  473. proofRenderingIntent,
  474. flags,
  475. )
  476. except (IOError, TypeError, ValueError) as v:
  477. raise PyCMSError(v)
  478. buildTransformFromOpenProfiles = buildTransform
  479. buildProofTransformFromOpenProfiles = buildProofTransform
  480. def applyTransform(im, transform, inPlace=False):
  481. """
  482. (pyCMS) Applies a transform to a given image.
  483. If im.mode != transform.inMode, a PyCMSError is raised.
  484. If inPlace is True and transform.inMode != transform.outMode, a
  485. PyCMSError is raised.
  486. If im.mode, transform.inMode, or transform.outMode is not supported by
  487. pyCMSdll or the profiles you used for the transform, a PyCMSError is
  488. raised.
  489. If an error occurs while the transform is being applied, a PyCMSError
  490. is raised.
  491. This function applies a pre-calculated transform (from
  492. ImageCms.buildTransform() or ImageCms.buildTransformFromOpenProfiles())
  493. to an image. The transform can be used for multiple images, saving
  494. considerable calculation time if doing the same conversion multiple times.
  495. If you want to modify im in-place instead of receiving a new image as
  496. the return value, set inPlace to True. This can only be done if
  497. transform.inMode and transform.outMode are the same, because we can't
  498. change the mode in-place (the buffer sizes for some modes are
  499. different). The default behavior is to return a new Image object of
  500. the same dimensions in mode transform.outMode.
  501. :param im: A PIL Image object, and im.mode must be the same as the inMode
  502. supported by the transform.
  503. :param transform: A valid CmsTransform class object
  504. :param inPlace: Bool. If True, im is modified in place and None is
  505. returned, if False, a new Image object with the transform applied is
  506. returned (and im is not changed). The default is False.
  507. :returns: Either None, or a new PIL Image object, depending on the value of
  508. inPlace. The profile will be returned in the image's
  509. info['icc_profile'].
  510. :exception PyCMSError:
  511. """
  512. try:
  513. if inPlace:
  514. transform.apply_in_place(im)
  515. imOut = None
  516. else:
  517. imOut = transform.apply(im)
  518. except (TypeError, ValueError) as v:
  519. raise PyCMSError(v)
  520. return imOut
  521. def createProfile(colorSpace, colorTemp=-1):
  522. """
  523. (pyCMS) Creates a profile.
  524. If colorSpace not in ["LAB", "XYZ", "sRGB"], a PyCMSError is raised
  525. If using LAB and colorTemp != a positive integer, a PyCMSError is raised.
  526. If an error occurs while creating the profile, a PyCMSError is raised.
  527. Use this function to create common profiles on-the-fly instead of
  528. having to supply a profile on disk and knowing the path to it. It
  529. returns a normal CmsProfile object that can be passed to
  530. ImageCms.buildTransformFromOpenProfiles() to create a transform to apply
  531. to images.
  532. :param colorSpace: String, the color space of the profile you wish to
  533. create.
  534. Currently only "LAB", "XYZ", and "sRGB" are supported.
  535. :param colorTemp: Positive integer for the white point for the profile, in
  536. degrees Kelvin (i.e. 5000, 6500, 9600, etc.). The default is for D50
  537. illuminant if omitted (5000k). colorTemp is ONLY applied to LAB
  538. profiles, and is ignored for XYZ and sRGB.
  539. :returns: A CmsProfile class object
  540. :exception PyCMSError:
  541. """
  542. if colorSpace not in ["LAB", "XYZ", "sRGB"]:
  543. raise PyCMSError(
  544. "Color space not supported for on-the-fly profile creation (%s)"
  545. % colorSpace
  546. )
  547. if colorSpace == "LAB":
  548. try:
  549. colorTemp = float(colorTemp)
  550. except (TypeError, ValueError):
  551. raise PyCMSError(
  552. 'Color temperature must be numeric, "%s" not valid' % colorTemp
  553. )
  554. try:
  555. return core.createProfile(colorSpace, colorTemp)
  556. except (TypeError, ValueError) as v:
  557. raise PyCMSError(v)
  558. def getProfileName(profile):
  559. """
  560. (pyCMS) Gets the internal product name for the given profile.
  561. If profile isn't a valid CmsProfile object or filename to a profile,
  562. a PyCMSError is raised If an error occurs while trying to obtain the
  563. name tag, a PyCMSError is raised.
  564. Use this function to obtain the INTERNAL name of the profile (stored
  565. in an ICC tag in the profile itself), usually the one used when the
  566. profile was originally created. Sometimes this tag also contains
  567. additional information supplied by the creator.
  568. :param profile: EITHER a valid CmsProfile object, OR a string of the
  569. filename of an ICC profile.
  570. :returns: A string containing the internal name of the profile as stored
  571. in an ICC tag.
  572. :exception PyCMSError:
  573. """
  574. try:
  575. # add an extra newline to preserve pyCMS compatibility
  576. if not isinstance(profile, ImageCmsProfile):
  577. profile = ImageCmsProfile(profile)
  578. # do it in python, not c.
  579. # // name was "%s - %s" (model, manufacturer) || Description ,
  580. # // but if the Model and Manufacturer were the same or the model
  581. # // was long, Just the model, in 1.x
  582. model = profile.profile.model
  583. manufacturer = profile.profile.manufacturer
  584. if not (model or manufacturer):
  585. return (profile.profile.profile_description or "") + "\n"
  586. if not manufacturer or len(model) > 30:
  587. return model + "\n"
  588. return "%s - %s\n" % (model, manufacturer)
  589. except (AttributeError, IOError, TypeError, ValueError) as v:
  590. raise PyCMSError(v)
  591. def getProfileInfo(profile):
  592. """
  593. (pyCMS) Gets the internal product information for the given profile.
  594. If profile isn't a valid CmsProfile object or filename to a profile,
  595. a PyCMSError is raised.
  596. If an error occurs while trying to obtain the info tag, a PyCMSError
  597. is raised
  598. Use this function to obtain the information stored in the profile's
  599. info tag. This often contains details about the profile, and how it
  600. was created, as supplied by the creator.
  601. :param profile: EITHER a valid CmsProfile object, OR a string of the
  602. filename of an ICC profile.
  603. :returns: A string containing the internal profile information stored in
  604. an ICC tag.
  605. :exception PyCMSError:
  606. """
  607. try:
  608. if not isinstance(profile, ImageCmsProfile):
  609. profile = ImageCmsProfile(profile)
  610. # add an extra newline to preserve pyCMS compatibility
  611. # Python, not C. the white point bits weren't working well,
  612. # so skipping.
  613. # info was description \r\n\r\n copyright \r\n\r\n K007 tag \r\n\r\n whitepoint
  614. description = profile.profile.profile_description
  615. cpright = profile.profile.copyright
  616. arr = []
  617. for elt in (description, cpright):
  618. if elt:
  619. arr.append(elt)
  620. return "\r\n\r\n".join(arr) + "\r\n\r\n"
  621. except (AttributeError, IOError, TypeError, ValueError) as v:
  622. raise PyCMSError(v)
  623. def getProfileCopyright(profile):
  624. """
  625. (pyCMS) Gets the copyright for the given profile.
  626. If profile isn't a valid CmsProfile object or filename to a profile,
  627. a PyCMSError is raised.
  628. If an error occurs while trying to obtain the copyright tag, a PyCMSError
  629. is raised
  630. Use this function to obtain the information stored in the profile's
  631. copyright tag.
  632. :param profile: EITHER a valid CmsProfile object, OR a string of the
  633. filename of an ICC profile.
  634. :returns: A string containing the internal profile information stored in
  635. an ICC tag.
  636. :exception PyCMSError:
  637. """
  638. try:
  639. # add an extra newline to preserve pyCMS compatibility
  640. if not isinstance(profile, ImageCmsProfile):
  641. profile = ImageCmsProfile(profile)
  642. return (profile.profile.copyright or "") + "\n"
  643. except (AttributeError, IOError, TypeError, ValueError) as v:
  644. raise PyCMSError(v)
  645. def getProfileManufacturer(profile):
  646. """
  647. (pyCMS) Gets the manufacturer for the given profile.
  648. If profile isn't a valid CmsProfile object or filename to a profile,
  649. a PyCMSError is raised.
  650. If an error occurs while trying to obtain the manufacturer tag, a
  651. PyCMSError is raised
  652. Use this function to obtain the information stored in the profile's
  653. manufacturer tag.
  654. :param profile: EITHER a valid CmsProfile object, OR a string of the
  655. filename of an ICC profile.
  656. :returns: A string containing the internal profile information stored in
  657. an ICC tag.
  658. :exception PyCMSError:
  659. """
  660. try:
  661. # add an extra newline to preserve pyCMS compatibility
  662. if not isinstance(profile, ImageCmsProfile):
  663. profile = ImageCmsProfile(profile)
  664. return (profile.profile.manufacturer or "") + "\n"
  665. except (AttributeError, IOError, TypeError, ValueError) as v:
  666. raise PyCMSError(v)
  667. def getProfileModel(profile):
  668. """
  669. (pyCMS) Gets the model for the given profile.
  670. If profile isn't a valid CmsProfile object or filename to a profile,
  671. a PyCMSError is raised.
  672. If an error occurs while trying to obtain the model tag, a PyCMSError
  673. is raised
  674. Use this function to obtain the information stored in the profile's
  675. model tag.
  676. :param profile: EITHER a valid CmsProfile object, OR a string of the
  677. filename of an ICC profile.
  678. :returns: A string containing the internal profile information stored in
  679. an ICC tag.
  680. :exception PyCMSError:
  681. """
  682. try:
  683. # add an extra newline to preserve pyCMS compatibility
  684. if not isinstance(profile, ImageCmsProfile):
  685. profile = ImageCmsProfile(profile)
  686. return (profile.profile.model or "") + "\n"
  687. except (AttributeError, IOError, TypeError, ValueError) as v:
  688. raise PyCMSError(v)
  689. def getProfileDescription(profile):
  690. """
  691. (pyCMS) Gets the description for the given profile.
  692. If profile isn't a valid CmsProfile object or filename to a profile,
  693. a PyCMSError is raised.
  694. If an error occurs while trying to obtain the description tag, a PyCMSError
  695. is raised
  696. Use this function to obtain the information stored in the profile's
  697. description tag.
  698. :param profile: EITHER a valid CmsProfile object, OR a string of the
  699. filename of an ICC profile.
  700. :returns: A string containing the internal profile information stored in an
  701. ICC tag.
  702. :exception PyCMSError:
  703. """
  704. try:
  705. # add an extra newline to preserve pyCMS compatibility
  706. if not isinstance(profile, ImageCmsProfile):
  707. profile = ImageCmsProfile(profile)
  708. return (profile.profile.profile_description or "") + "\n"
  709. except (AttributeError, IOError, TypeError, ValueError) as v:
  710. raise PyCMSError(v)
  711. def getDefaultIntent(profile):
  712. """
  713. (pyCMS) Gets the default intent name for the given profile.
  714. If profile isn't a valid CmsProfile object or filename to a profile,
  715. a PyCMSError is raised.
  716. If an error occurs while trying to obtain the default intent, a
  717. PyCMSError is raised.
  718. Use this function to determine the default (and usually best optimized)
  719. rendering intent for this profile. Most profiles support multiple
  720. rendering intents, but are intended mostly for one type of conversion.
  721. If you wish to use a different intent than returned, use
  722. ImageCms.isIntentSupported() to verify it will work first.
  723. :param profile: EITHER a valid CmsProfile object, OR a string of the
  724. filename of an ICC profile.
  725. :returns: Integer 0-3 specifying the default rendering intent for this
  726. profile.
  727. ImageCms.INTENT_PERCEPTUAL = 0 (DEFAULT)
  728. ImageCms.INTENT_RELATIVE_COLORIMETRIC = 1
  729. ImageCms.INTENT_SATURATION = 2
  730. ImageCms.INTENT_ABSOLUTE_COLORIMETRIC = 3
  731. see the pyCMS documentation for details on rendering intents and what
  732. they do.
  733. :exception PyCMSError:
  734. """
  735. try:
  736. if not isinstance(profile, ImageCmsProfile):
  737. profile = ImageCmsProfile(profile)
  738. return profile.profile.rendering_intent
  739. except (AttributeError, IOError, TypeError, ValueError) as v:
  740. raise PyCMSError(v)
  741. def isIntentSupported(profile, intent, direction):
  742. """
  743. (pyCMS) Checks if a given intent is supported.
  744. Use this function to verify that you can use your desired
  745. renderingIntent with profile, and that profile can be used for the
  746. input/output/proof profile as you desire.
  747. Some profiles are created specifically for one "direction", can cannot
  748. be used for others. Some profiles can only be used for certain
  749. rendering intents... so it's best to either verify this before trying
  750. to create a transform with them (using this function), or catch the
  751. potential PyCMSError that will occur if they don't support the modes
  752. you select.
  753. :param profile: EITHER a valid CmsProfile object, OR a string of the
  754. filename of an ICC profile.
  755. :param intent: Integer (0-3) specifying the rendering intent you wish to
  756. use with this profile
  757. ImageCms.INTENT_PERCEPTUAL = 0 (DEFAULT)
  758. ImageCms.INTENT_RELATIVE_COLORIMETRIC = 1
  759. ImageCms.INTENT_SATURATION = 2
  760. ImageCms.INTENT_ABSOLUTE_COLORIMETRIC = 3
  761. see the pyCMS documentation for details on rendering intents and what
  762. they do.
  763. :param direction: Integer specifying if the profile is to be used for
  764. input, output, or proof
  765. INPUT = 0 (or use ImageCms.DIRECTION_INPUT)
  766. OUTPUT = 1 (or use ImageCms.DIRECTION_OUTPUT)
  767. PROOF = 2 (or use ImageCms.DIRECTION_PROOF)
  768. :returns: 1 if the intent/direction are supported, -1 if they are not.
  769. :exception PyCMSError:
  770. """
  771. try:
  772. if not isinstance(profile, ImageCmsProfile):
  773. profile = ImageCmsProfile(profile)
  774. # FIXME: I get different results for the same data w. different
  775. # compilers. Bug in LittleCMS or in the binding?
  776. if profile.profile.is_intent_supported(intent, direction):
  777. return 1
  778. else:
  779. return -1
  780. except (AttributeError, IOError, TypeError, ValueError) as v:
  781. raise PyCMSError(v)
  782. def versions():
  783. """
  784. (pyCMS) Fetches versions.
  785. """
  786. return (VERSION, core.littlecms_version, sys.version.split()[0], Image.__version__)