You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

955 lines
35 KiB

4 years ago
  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. try:
  16. from PIL import _imagingcms
  17. except ImportError as ex:
  18. # Allow error import for doc purposes, but error out when accessing
  19. # anything in core.
  20. from _util import deferred_error
  21. _imagingcms = deferred_error(ex)
  22. from PIL._util import isStringType
  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__(self, input, output, input_mode, output_mode,
  150. intent=INTENT_PERCEPTUAL, proof=None,
  151. proof_intent=INTENT_ABSOLUTE_COLORIMETRIC, flags=0):
  152. if proof is None:
  153. self.transform = core.buildTransform(
  154. input.profile, output.profile,
  155. input_mode, output_mode,
  156. intent,
  157. flags
  158. )
  159. else:
  160. self.transform = core.buildProofTransform(
  161. input.profile, output.profile, proof.profile,
  162. input_mode, output_mode,
  163. intent, proof_intent,
  164. flags
  165. )
  166. # Note: inputMode and outputMode are for pyCMS compatibility only
  167. self.input_mode = self.inputMode = input_mode
  168. self.output_mode = self.outputMode = output_mode
  169. self.output_profile = output
  170. def point(self, im):
  171. return self.apply(im)
  172. def apply(self, im, imOut=None):
  173. im.load()
  174. if imOut is None:
  175. imOut = Image.new(self.output_mode, im.size, None)
  176. self.transform.apply(im.im.id, imOut.im.id)
  177. imOut.info['icc_profile'] = self.output_profile.tobytes()
  178. return imOut
  179. def apply_in_place(self, im):
  180. im.load()
  181. if im.mode != self.output_mode:
  182. raise ValueError("mode mismatch") # wrong output mode
  183. self.transform.apply(im.im.id, im.im.id)
  184. im.info['icc_profile'] = self.output_profile.tobytes()
  185. return im
  186. def get_display_profile(handle=None):
  187. """ (experimental) Fetches the profile for the current display device.
  188. :returns: None if the profile is not known.
  189. """
  190. if sys.platform == "win32":
  191. from PIL import ImageWin
  192. if isinstance(handle, ImageWin.HDC):
  193. profile = core.get_display_profile_win32(handle, 1)
  194. else:
  195. profile = core.get_display_profile_win32(handle or 0)
  196. else:
  197. try:
  198. get = _imagingcms.get_display_profile
  199. except AttributeError:
  200. return None
  201. else:
  202. profile = get()
  203. return ImageCmsProfile(profile)
  204. # --------------------------------------------------------------------.
  205. # pyCMS compatible layer
  206. # --------------------------------------------------------------------.
  207. class PyCMSError(Exception):
  208. """ (pyCMS) Exception class.
  209. This is used for all errors in the pyCMS API. """
  210. pass
  211. def profileToProfile(
  212. im, inputProfile, outputProfile, renderingIntent=INTENT_PERCEPTUAL,
  213. outputMode=None, inPlace=0, flags=0):
  214. """
  215. (pyCMS) Applies an ICC transformation to a given image, mapping from
  216. inputProfile to outputProfile.
  217. If the input or output profiles specified are not valid filenames, a
  218. PyCMSError will be raised. If inPlace == TRUE and outputMode != im.mode,
  219. a PyCMSError will be raised. If an error occurs during application of
  220. the profiles, a PyCMSError will be raised. If outputMode is not a mode
  221. supported by the outputProfile (or by pyCMS), a PyCMSError will be
  222. raised.
  223. This function applies an ICC transformation to im from inputProfile's
  224. color space to outputProfile's color space using the specified rendering
  225. intent to decide how to handle out-of-gamut colors.
  226. OutputMode can be used to specify that a color mode conversion is to
  227. be done using these profiles, but the specified profiles must be able
  228. to handle that mode. I.e., if converting im from RGB to CMYK using
  229. profiles, the input profile must handle RGB data, and the output
  230. profile must handle CMYK data.
  231. :param im: An open PIL image object (i.e. Image.new(...) or
  232. Image.open(...), etc.)
  233. :param inputProfile: String, as a valid filename path to the ICC input
  234. profile you wish to use for this image, or a profile object
  235. :param outputProfile: String, as a valid filename path to the ICC output
  236. profile you wish to use for this image, or a profile object
  237. :param renderingIntent: Integer (0-3) specifying the rendering intent you
  238. wish to use for the transform
  239. ImageCms.INTENT_PERCEPTUAL = 0 (DEFAULT)
  240. ImageCms.INTENT_RELATIVE_COLORIMETRIC = 1
  241. ImageCms.INTENT_SATURATION = 2
  242. ImageCms.INTENT_ABSOLUTE_COLORIMETRIC = 3
  243. see the pyCMS documentation for details on rendering intents and what
  244. they do.
  245. :param outputMode: A valid PIL mode for the output image (i.e. "RGB",
  246. "CMYK", etc.). Note: if rendering the image "inPlace", outputMode
  247. MUST be the same mode as the input, or omitted completely. If
  248. omitted, the outputMode will be the same as the mode of the input
  249. image (im.mode)
  250. :param inPlace: Boolean (1 = True, None or 0 = False). If True, the
  251. original image is modified in-place, and None is returned. If False
  252. (default), a new Image object is returned with the transform applied.
  253. :param flags: Integer (0-...) specifying additional flags
  254. :returns: Either None or a new PIL image object, depending on value of
  255. inPlace
  256. :exception PyCMSError:
  257. """
  258. if outputMode is None:
  259. outputMode = im.mode
  260. if not isinstance(renderingIntent, int) or not (0 <= renderingIntent <= 3):
  261. raise PyCMSError("renderingIntent must be an integer between 0 and 3")
  262. if not isinstance(flags, int) or not (0 <= flags <= _MAX_FLAG):
  263. raise PyCMSError(
  264. "flags must be an integer between 0 and %s" + _MAX_FLAG)
  265. try:
  266. if not isinstance(inputProfile, ImageCmsProfile):
  267. inputProfile = ImageCmsProfile(inputProfile)
  268. if not isinstance(outputProfile, ImageCmsProfile):
  269. outputProfile = ImageCmsProfile(outputProfile)
  270. transform = ImageCmsTransform(
  271. inputProfile, outputProfile, im.mode, outputMode,
  272. renderingIntent, flags=flags
  273. )
  274. if inPlace:
  275. transform.apply_in_place(im)
  276. imOut = None
  277. else:
  278. imOut = transform.apply(im)
  279. except (IOError, TypeError, ValueError) as v:
  280. raise PyCMSError(v)
  281. return imOut
  282. def getOpenProfile(profileFilename):
  283. """
  284. (pyCMS) Opens an ICC profile file.
  285. The PyCMSProfile object can be passed back into pyCMS for use in creating
  286. transforms and such (as in ImageCms.buildTransformFromOpenProfiles()).
  287. If profileFilename is not a valid filename for an ICC profile, a PyCMSError
  288. will be raised.
  289. :param profileFilename: String, as a valid filename path to the ICC profile
  290. you wish to open, or a file-like object.
  291. :returns: A CmsProfile class object.
  292. :exception PyCMSError:
  293. """
  294. try:
  295. return ImageCmsProfile(profileFilename)
  296. except (IOError, TypeError, ValueError) as v:
  297. raise PyCMSError(v)
  298. def buildTransform(
  299. inputProfile, outputProfile, inMode, outMode,
  300. renderingIntent=INTENT_PERCEPTUAL, flags=0):
  301. """
  302. (pyCMS) Builds an ICC transform mapping from the inputProfile to the
  303. outputProfile. Use applyTransform to apply the transform to a given
  304. image.
  305. If the input or output profiles specified are not valid filenames, a
  306. PyCMSError will be raised. If an error occurs during creation of the
  307. transform, a PyCMSError will be raised.
  308. If inMode or outMode are not a mode supported by the outputProfile (or
  309. by pyCMS), a PyCMSError will be raised.
  310. This function builds and returns an ICC transform from the inputProfile
  311. to the outputProfile using the renderingIntent to determine what to do
  312. with out-of-gamut colors. It will ONLY work for converting images that
  313. are in inMode to images that are in outMode color format (PIL mode,
  314. i.e. "RGB", "RGBA", "CMYK", etc.).
  315. Building the transform is a fair part of the overhead in
  316. ImageCms.profileToProfile(), so if you're planning on converting multiple
  317. images using the same input/output settings, this can save you time.
  318. Once you have a transform object, it can be used with
  319. ImageCms.applyProfile() to convert images without the need to re-compute
  320. the lookup table for the transform.
  321. The reason pyCMS returns a class object rather than a handle directly
  322. to the transform is that it needs to keep track of the PIL input/output
  323. modes that the transform is meant for. These attributes are stored in
  324. the "inMode" and "outMode" attributes of the object (which can be
  325. manually overridden if you really want to, but I don't know of any
  326. time that would be of use, or would even work).
  327. :param inputProfile: String, as a valid filename path to the ICC input
  328. profile you wish to use for this transform, or a profile object
  329. :param outputProfile: String, as a valid filename path to the ICC output
  330. profile you wish to use for this transform, or a profile object
  331. :param inMode: String, as a valid PIL mode that the appropriate profile
  332. also supports (i.e. "RGB", "RGBA", "CMYK", etc.)
  333. :param outMode: String, as a valid PIL mode that the appropriate profile
  334. also supports (i.e. "RGB", "RGBA", "CMYK", etc.)
  335. :param renderingIntent: Integer (0-3) specifying the rendering intent you
  336. wish to use for the transform
  337. ImageCms.INTENT_PERCEPTUAL = 0 (DEFAULT)
  338. ImageCms.INTENT_RELATIVE_COLORIMETRIC = 1
  339. ImageCms.INTENT_SATURATION = 2
  340. ImageCms.INTENT_ABSOLUTE_COLORIMETRIC = 3
  341. see the pyCMS documentation for details on rendering intents and what
  342. they do.
  343. :param flags: Integer (0-...) specifying additional flags
  344. :returns: A CmsTransform class object.
  345. :exception PyCMSError:
  346. """
  347. if not isinstance(renderingIntent, int) or not (0 <= renderingIntent <= 3):
  348. raise PyCMSError("renderingIntent must be an integer between 0 and 3")
  349. if not isinstance(flags, int) or not (0 <= flags <= _MAX_FLAG):
  350. raise PyCMSError(
  351. "flags must be an integer between 0 and %s" + _MAX_FLAG)
  352. try:
  353. if not isinstance(inputProfile, ImageCmsProfile):
  354. inputProfile = ImageCmsProfile(inputProfile)
  355. if not isinstance(outputProfile, ImageCmsProfile):
  356. outputProfile = ImageCmsProfile(outputProfile)
  357. return ImageCmsTransform(
  358. inputProfile, outputProfile, inMode, outMode,
  359. renderingIntent, flags=flags)
  360. except (IOError, TypeError, ValueError) as v:
  361. raise PyCMSError(v)
  362. def buildProofTransform(
  363. inputProfile, outputProfile, proofProfile, inMode, outMode,
  364. renderingIntent=INTENT_PERCEPTUAL,
  365. proofRenderingIntent=INTENT_ABSOLUTE_COLORIMETRIC,
  366. flags=FLAGS["SOFTPROOFING"]):
  367. """
  368. (pyCMS) Builds an ICC transform mapping from the inputProfile to the
  369. outputProfile, but tries to simulate the result that would be
  370. obtained on the proofProfile device.
  371. If the input, output, or proof profiles specified are not valid
  372. filenames, a PyCMSError will be raised.
  373. If an error occurs during creation of the transform, a PyCMSError will
  374. be raised.
  375. If inMode or outMode are not a mode supported by the outputProfile
  376. (or by pyCMS), a PyCMSError will be raised.
  377. This function builds and returns an ICC transform from the inputProfile
  378. to the outputProfile, but tries to simulate the result that would be
  379. obtained on the proofProfile device using renderingIntent and
  380. proofRenderingIntent to determine what to do with out-of-gamut
  381. colors. This is known as "soft-proofing". It will ONLY work for
  382. converting images that are in inMode to images that are in outMode
  383. color format (PIL mode, i.e. "RGB", "RGBA", "CMYK", etc.).
  384. Usage of the resulting transform object is exactly the same as with
  385. ImageCms.buildTransform().
  386. Proof profiling is generally used when using an output device to get a
  387. good idea of what the final printed/displayed image would look like on
  388. the proofProfile device when it's quicker and easier to use the
  389. output device for judging color. Generally, this means that the
  390. output device is a monitor, or a dye-sub printer (etc.), and the simulated
  391. device is something more expensive, complicated, or time consuming
  392. (making it difficult to make a real print for color judgement purposes).
  393. Soft-proofing basically functions by adjusting the colors on the
  394. output device to match the colors of the device being simulated. However,
  395. when the simulated device has a much wider gamut than the output
  396. device, you may obtain marginal results.
  397. :param inputProfile: String, as a valid filename path to the ICC input
  398. profile you wish to use for this transform, or a profile object
  399. :param outputProfile: String, as a valid filename path to the ICC output
  400. (monitor, usually) profile you wish to use for this transform, or a
  401. profile object
  402. :param proofProfile: String, as a valid filename path to the ICC proof
  403. profile you wish to use for this transform, or a profile object
  404. :param inMode: String, as a valid PIL mode that the appropriate profile
  405. also supports (i.e. "RGB", "RGBA", "CMYK", etc.)
  406. :param outMode: String, as a valid PIL mode that the appropriate profile
  407. also supports (i.e. "RGB", "RGBA", "CMYK", etc.)
  408. :param renderingIntent: Integer (0-3) specifying the rendering intent you
  409. wish to use for the input->proof (simulated) transform
  410. ImageCms.INTENT_PERCEPTUAL = 0 (DEFAULT)
  411. ImageCms.INTENT_RELATIVE_COLORIMETRIC = 1
  412. ImageCms.INTENT_SATURATION = 2
  413. ImageCms.INTENT_ABSOLUTE_COLORIMETRIC = 3
  414. see the pyCMS documentation for details on rendering intents and what
  415. they do.
  416. :param proofRenderingIntent: Integer (0-3) specifying the rendering intent
  417. you wish to use for proof->output transform
  418. ImageCms.INTENT_PERCEPTUAL = 0 (DEFAULT)
  419. ImageCms.INTENT_RELATIVE_COLORIMETRIC = 1
  420. ImageCms.INTENT_SATURATION = 2
  421. ImageCms.INTENT_ABSOLUTE_COLORIMETRIC = 3
  422. see the pyCMS documentation for details on rendering intents and what
  423. they do.
  424. :param flags: Integer (0-...) specifying additional flags
  425. :returns: A CmsTransform class object.
  426. :exception PyCMSError:
  427. """
  428. if not isinstance(renderingIntent, int) or not (0 <= renderingIntent <= 3):
  429. raise PyCMSError("renderingIntent must be an integer between 0 and 3")
  430. if not isinstance(flags, int) or not (0 <= flags <= _MAX_FLAG):
  431. raise PyCMSError(
  432. "flags must be an integer between 0 and %s" + _MAX_FLAG)
  433. try:
  434. if not isinstance(inputProfile, ImageCmsProfile):
  435. inputProfile = ImageCmsProfile(inputProfile)
  436. if not isinstance(outputProfile, ImageCmsProfile):
  437. outputProfile = ImageCmsProfile(outputProfile)
  438. if not isinstance(proofProfile, ImageCmsProfile):
  439. proofProfile = ImageCmsProfile(proofProfile)
  440. return ImageCmsTransform(
  441. inputProfile, outputProfile, inMode, outMode, renderingIntent,
  442. proofProfile, proofRenderingIntent, flags)
  443. except (IOError, TypeError, ValueError) as v:
  444. raise PyCMSError(v)
  445. buildTransformFromOpenProfiles = buildTransform
  446. buildProofTransformFromOpenProfiles = buildProofTransform
  447. def applyTransform(im, transform, inPlace=0):
  448. """
  449. (pyCMS) Applies a transform to a given image.
  450. If im.mode != transform.inMode, a PyCMSError is raised.
  451. If inPlace == TRUE and transform.inMode != transform.outMode, a
  452. PyCMSError is raised.
  453. If im.mode, transfer.inMode, or transfer.outMode is not supported by
  454. pyCMSdll or the profiles you used for the transform, a PyCMSError is
  455. raised.
  456. If an error occurs while the transform is being applied, a PyCMSError
  457. is raised.
  458. This function applies a pre-calculated transform (from
  459. ImageCms.buildTransform() or ImageCms.buildTransformFromOpenProfiles())
  460. to an image. The transform can be used for multiple images, saving
  461. considerable calculation time if doing the same conversion multiple times.
  462. If you want to modify im in-place instead of receiving a new image as
  463. the return value, set inPlace to TRUE. This can only be done if
  464. transform.inMode and transform.outMode are the same, because we can't
  465. change the mode in-place (the buffer sizes for some modes are
  466. different). The default behavior is to return a new Image object of
  467. the same dimensions in mode transform.outMode.
  468. :param im: A PIL Image object, and im.mode must be the same as the inMode
  469. supported by the transform.
  470. :param transform: A valid CmsTransform class object
  471. :param inPlace: Bool (1 == True, 0 or None == False). If True, im is
  472. modified in place and None is returned, if False, a new Image object
  473. with the transform applied is returned (and im is not changed). The
  474. default is False.
  475. :returns: Either None, or a new PIL Image object, depending on the value of
  476. inPlace. The profile will be returned in the image's
  477. info['icc_profile'].
  478. :exception PyCMSError:
  479. """
  480. try:
  481. if inPlace:
  482. transform.apply_in_place(im)
  483. imOut = None
  484. else:
  485. imOut = transform.apply(im)
  486. except (TypeError, ValueError) as v:
  487. raise PyCMSError(v)
  488. return imOut
  489. def createProfile(colorSpace, colorTemp=-1):
  490. """
  491. (pyCMS) Creates a profile.
  492. If colorSpace not in ["LAB", "XYZ", "sRGB"], a PyCMSError is raised
  493. If using LAB and colorTemp != a positive integer, a PyCMSError is raised.
  494. If an error occurs while creating the profile, a PyCMSError is raised.
  495. Use this function to create common profiles on-the-fly instead of
  496. having to supply a profile on disk and knowing the path to it. It
  497. returns a normal CmsProfile object that can be passed to
  498. ImageCms.buildTransformFromOpenProfiles() to create a transform to apply
  499. to images.
  500. :param colorSpace: String, the color space of the profile you wish to
  501. create.
  502. Currently only "LAB", "XYZ", and "sRGB" are supported.
  503. :param colorTemp: Positive integer for the white point for the profile, in
  504. degrees Kelvin (i.e. 5000, 6500, 9600, etc.). The default is for D50
  505. illuminant if omitted (5000k). colorTemp is ONLY applied to LAB
  506. profiles, and is ignored for XYZ and sRGB.
  507. :returns: A CmsProfile class object
  508. :exception PyCMSError:
  509. """
  510. if colorSpace not in ["LAB", "XYZ", "sRGB"]:
  511. raise PyCMSError(
  512. "Color space not supported for on-the-fly profile creation (%s)"
  513. % colorSpace)
  514. if colorSpace == "LAB":
  515. try:
  516. colorTemp = float(colorTemp)
  517. except:
  518. raise PyCMSError(
  519. "Color temperature must be numeric, \"%s\" not valid"
  520. % colorTemp)
  521. try:
  522. return core.createProfile(colorSpace, colorTemp)
  523. except (TypeError, ValueError) as v:
  524. raise PyCMSError(v)
  525. def getProfileName(profile):
  526. """
  527. (pyCMS) Gets the internal product name for the given profile.
  528. If profile isn't a valid CmsProfile object or filename to a profile,
  529. a PyCMSError is raised If an error occurs while trying to obtain the
  530. name tag, a PyCMSError is raised.
  531. Use this function to obtain the INTERNAL name of the profile (stored
  532. in an ICC tag in the profile itself), usually the one used when the
  533. profile was originally created. Sometimes this tag also contains
  534. additional information supplied by the creator.
  535. :param profile: EITHER a valid CmsProfile object, OR a string of the
  536. filename of an ICC profile.
  537. :returns: A string containing the internal name of the profile as stored
  538. in an ICC tag.
  539. :exception PyCMSError:
  540. """
  541. try:
  542. # add an extra newline to preserve pyCMS compatibility
  543. if not isinstance(profile, ImageCmsProfile):
  544. profile = ImageCmsProfile(profile)
  545. # do it in python, not c.
  546. # // name was "%s - %s" (model, manufacturer) || Description ,
  547. # // but if the Model and Manufacturer were the same or the model
  548. # // was long, Just the model, in 1.x
  549. model = profile.profile.product_model
  550. manufacturer = profile.profile.product_manufacturer
  551. if not (model or manufacturer):
  552. return profile.profile.product_description + "\n"
  553. if not manufacturer or len(model) > 30:
  554. return model + "\n"
  555. return "%s - %s\n" % (model, manufacturer)
  556. except (AttributeError, IOError, TypeError, ValueError) as v:
  557. raise PyCMSError(v)
  558. def getProfileInfo(profile):
  559. """
  560. (pyCMS) Gets the internal product information for the given profile.
  561. If profile isn't a valid CmsProfile object or filename to a profile,
  562. a PyCMSError is raised.
  563. If an error occurs while trying to obtain the info tag, a PyCMSError
  564. is raised
  565. Use this function to obtain the information stored in the profile's
  566. info tag. This often contains details about the profile, and how it
  567. was created, as 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 profile information stored in
  571. an ICC tag.
  572. :exception PyCMSError:
  573. """
  574. try:
  575. if not isinstance(profile, ImageCmsProfile):
  576. profile = ImageCmsProfile(profile)
  577. # add an extra newline to preserve pyCMS compatibility
  578. # Python, not C. the white point bits weren't working well,
  579. # so skipping.
  580. # // info was description \r\n\r\n copyright \r\n\r\n K007 tag \r\n\r\n whitepoint
  581. description = profile.profile.product_description
  582. cpright = profile.profile.product_copyright
  583. arr = []
  584. for elt in (description, cpright):
  585. if elt:
  586. arr.append(elt)
  587. return "\r\n\r\n".join(arr) + "\r\n\r\n"
  588. except (AttributeError, IOError, TypeError, ValueError) as v:
  589. raise PyCMSError(v)
  590. def getProfileCopyright(profile):
  591. """
  592. (pyCMS) Gets the copyright for the given profile.
  593. If profile isn't a valid CmsProfile object or filename to a profile,
  594. a PyCMSError is raised.
  595. If an error occurs while trying to obtain the copyright tag, a PyCMSError
  596. is raised
  597. Use this function to obtain the information stored in the profile's
  598. copyright tag.
  599. :param profile: EITHER a valid CmsProfile object, OR a string of the
  600. filename of an ICC profile.
  601. :returns: A string containing the internal profile information stored in
  602. an ICC tag.
  603. :exception PyCMSError:
  604. """
  605. try:
  606. # add an extra newline to preserve pyCMS compatibility
  607. if not isinstance(profile, ImageCmsProfile):
  608. profile = ImageCmsProfile(profile)
  609. return profile.profile.product_copyright + "\n"
  610. except (AttributeError, IOError, TypeError, ValueError) as v:
  611. raise PyCMSError(v)
  612. def getProfileManufacturer(profile):
  613. """
  614. (pyCMS) Gets the manufacturer for the given profile.
  615. If profile isn't a valid CmsProfile object or filename to a profile,
  616. a PyCMSError is raised.
  617. If an error occurs while trying to obtain the manufacturer tag, a
  618. PyCMSError is raised
  619. Use this function to obtain the information stored in the profile's
  620. manufacturer tag.
  621. :param profile: EITHER a valid CmsProfile object, OR a string of the
  622. filename of an ICC profile.
  623. :returns: A string containing the internal profile information stored in
  624. an ICC tag.
  625. :exception PyCMSError:
  626. """
  627. try:
  628. # add an extra newline to preserve pyCMS compatibility
  629. if not isinstance(profile, ImageCmsProfile):
  630. profile = ImageCmsProfile(profile)
  631. return profile.profile.product_manufacturer + "\n"
  632. except (AttributeError, IOError, TypeError, ValueError) as v:
  633. raise PyCMSError(v)
  634. def getProfileModel(profile):
  635. """
  636. (pyCMS) Gets the model for the given profile.
  637. If profile isn't a valid CmsProfile object or filename to a profile,
  638. a PyCMSError is raised.
  639. If an error occurs while trying to obtain the model tag, a PyCMSError
  640. is raised
  641. Use this function to obtain the information stored in the profile's
  642. model tag.
  643. :param profile: EITHER a valid CmsProfile object, OR a string of the
  644. filename of an ICC profile.
  645. :returns: A string containing the internal profile information stored in
  646. an ICC tag.
  647. :exception PyCMSError:
  648. """
  649. try:
  650. # add an extra newline to preserve pyCMS compatibility
  651. if not isinstance(profile, ImageCmsProfile):
  652. profile = ImageCmsProfile(profile)
  653. return profile.profile.product_model + "\n"
  654. except (AttributeError, IOError, TypeError, ValueError) as v:
  655. raise PyCMSError(v)
  656. def getProfileDescription(profile):
  657. """
  658. (pyCMS) Gets the description for the given profile.
  659. If profile isn't a valid CmsProfile object or filename to a profile,
  660. a PyCMSError is raised.
  661. If an error occurs while trying to obtain the description tag, a PyCMSError
  662. is raised
  663. Use this function to obtain the information stored in the profile's
  664. description tag.
  665. :param profile: EITHER a valid CmsProfile object, OR a string of the
  666. filename of an ICC profile.
  667. :returns: A string containing the internal profile information stored in an
  668. ICC tag.
  669. :exception PyCMSError:
  670. """
  671. try:
  672. # add an extra newline to preserve pyCMS compatibility
  673. if not isinstance(profile, ImageCmsProfile):
  674. profile = ImageCmsProfile(profile)
  675. return profile.profile.product_description + "\n"
  676. except (AttributeError, IOError, TypeError, ValueError) as v:
  677. raise PyCMSError(v)
  678. def getDefaultIntent(profile):
  679. """
  680. (pyCMS) Gets the default intent name for the given profile.
  681. If profile isn't a valid CmsProfile object or filename to a profile,
  682. a PyCMSError is raised.
  683. If an error occurs while trying to obtain the default intent, a
  684. PyCMSError is raised.
  685. Use this function to determine the default (and usually best optimized)
  686. rendering intent for this profile. Most profiles support multiple
  687. rendering intents, but are intended mostly for one type of conversion.
  688. If you wish to use a different intent than returned, use
  689. ImageCms.isIntentSupported() to verify it will work first.
  690. :param profile: EITHER a valid CmsProfile object, OR a string of the
  691. filename of an ICC profile.
  692. :returns: Integer 0-3 specifying the default rendering intent for this
  693. profile.
  694. ImageCms.INTENT_PERCEPTUAL = 0 (DEFAULT)
  695. ImageCms.INTENT_RELATIVE_COLORIMETRIC = 1
  696. ImageCms.INTENT_SATURATION = 2
  697. ImageCms.INTENT_ABSOLUTE_COLORIMETRIC = 3
  698. see the pyCMS documentation for details on rendering intents and what
  699. they do.
  700. :exception PyCMSError:
  701. """
  702. try:
  703. if not isinstance(profile, ImageCmsProfile):
  704. profile = ImageCmsProfile(profile)
  705. return profile.profile.rendering_intent
  706. except (AttributeError, IOError, TypeError, ValueError) as v:
  707. raise PyCMSError(v)
  708. def isIntentSupported(profile, intent, direction):
  709. """
  710. (pyCMS) Checks if a given intent is supported.
  711. Use this function to verify that you can use your desired
  712. renderingIntent with profile, and that profile can be used for the
  713. input/output/proof profile as you desire.
  714. Some profiles are created specifically for one "direction", can cannot
  715. be used for others. Some profiles can only be used for certain
  716. rendering intents... so it's best to either verify this before trying
  717. to create a transform with them (using this function), or catch the
  718. potential PyCMSError that will occur if they don't support the modes
  719. you select.
  720. :param profile: EITHER a valid CmsProfile object, OR a string of the
  721. filename of an ICC profile.
  722. :param intent: Integer (0-3) specifying the rendering intent you wish to
  723. use with this profile
  724. ImageCms.INTENT_PERCEPTUAL = 0 (DEFAULT)
  725. ImageCms.INTENT_RELATIVE_COLORIMETRIC = 1
  726. ImageCms.INTENT_SATURATION = 2
  727. ImageCms.INTENT_ABSOLUTE_COLORIMETRIC = 3
  728. see the pyCMS documentation for details on rendering intents and what
  729. they do.
  730. :param direction: Integer specifying if the profile is to be used for
  731. input, output, or proof
  732. INPUT = 0 (or use ImageCms.DIRECTION_INPUT)
  733. OUTPUT = 1 (or use ImageCms.DIRECTION_OUTPUT)
  734. PROOF = 2 (or use ImageCms.DIRECTION_PROOF)
  735. :returns: 1 if the intent/direction are supported, -1 if they are not.
  736. :exception PyCMSError:
  737. """
  738. try:
  739. if not isinstance(profile, ImageCmsProfile):
  740. profile = ImageCmsProfile(profile)
  741. # FIXME: I get different results for the same data w. different
  742. # compilers. Bug in LittleCMS or in the binding?
  743. if profile.profile.is_intent_supported(intent, direction):
  744. return 1
  745. else:
  746. return -1
  747. except (AttributeError, IOError, TypeError, ValueError) as v:
  748. raise PyCMSError(v)
  749. def versions():
  750. """
  751. (pyCMS) Fetches versions.
  752. """
  753. return (
  754. VERSION, core.littlecms_version,
  755. sys.version.split()[0], Image.VERSION
  756. )