Very nice - it just needs LCMS flags support so we can use black point
compensation and softproofing :) See attached patches. They also fix a
naming issue which could cause confusion - display profile (ImageCms
wording) actually means proof profile (lcms wording), so I changed
variable names and docstrings where applicable. Patches are tested under
Python 2.6.

Regards,

Florian Höch

Fredrik Lundh schrieb:
Kevin Cazabon has graciously donated his PyCMS library to PIL, and it
landed in the "raclette" tree yesterday.  The library will
automatically be built if you have LittleCMS on the machine
(www.littlecms.com).  The Python binding is now in PIL.ImageCms.

I'm still working on a tighter integration, but the module provides
the procedural PyCMS API (with a few enhancements; you can e.g. read
profiles from memory by passing in file objects instead of filenames).
 In other words, code written for pyCMS "should" still work if you
just change "import pyCMS" to

    import PIL.ImageCms as pyCMS

The internals are reworked, though, so code that rely on
implementation details, the exact phrasing of error messages (the PIL
version is less informative), or access to the pyCMSdll layer won't
work.

If you want to help out testing the integration, you can pull the
current snapshot from

    http://bitbucket.org/effbot/pil-2009-raclette/overview/

(either as a zip/tarball via the download link, or using "hg clone").

Cheers /F
_______________________________________________
Image-SIG maillist  -  Image-SIG@python.org
http://mail.python.org/mailman/listinfo/image-sig

--- _imagingcms.c.bak   Tue Mar 10 08:46:49 2009
+++ _imagingcms.c       Tue Mar 10 11:57:38 2009
@@ -260,7 +260,7 @@
 }
 
 static cmsHTRANSFORM
-_buildTransform(cmsHPROFILE hInputProfile, cmsHPROFILE hOutputProfile, char 
*sInMode, char *sOutMode, int iRenderingIntent)
+_buildTransform(cmsHPROFILE hInputProfile, cmsHPROFILE hOutputProfile, char 
*sInMode, char *sOutMode, int iRenderingIntent, DWORD cmsFLAGS)
 {
   cmsHTRANSFORM hTransform;
 
@@ -273,7 +273,7 @@
                                  findLCMStype(sInMode),
                                  hOutputProfile,
                                  findLCMStype(sOutMode),
-                                 iRenderingIntent, 0);
+                                 iRenderingIntent, cmsFLAGS);
 
   Py_END_ALLOW_THREADS
 
@@ -284,7 +284,7 @@
 }
 
 static cmsHTRANSFORM
-_buildProofTransform(cmsHPROFILE hInputProfile, cmsHPROFILE hOutputProfile, 
cmsHPROFILE hDisplayProfile, char *sInMode, char *sOutMode, int 
iRenderingIntent, int iDisplayIntent)
+_buildProofTransform(cmsHPROFILE hInputProfile, cmsHPROFILE hOutputProfile, 
cmsHPROFILE hProofProfile, char *sInMode, char *sOutMode, int iRenderingIntent, 
int iProofIntent, DWORD cmsFLAGS)
 {
   cmsHTRANSFORM hTransform;
 
@@ -297,10 +297,10 @@
                           findLCMStype(sInMode),
                           hOutputProfile,
                           findLCMStype(sOutMode),
-                          hDisplayProfile,
+                          hProofProfile,
                           iRenderingIntent,
-                          iDisplayIntent,
-                          0);
+                          iProofIntent,
+                          cmsFLAGS);
 
   Py_END_ALLOW_THREADS
 
@@ -326,15 +326,16 @@
   char *sInMode;
   char *sOutMode;
   int iRenderingIntent = 0;
+  int cmsFLAGS = 0;
 
   cmsHTRANSFORM transform = NULL;
 
-  if (!PyArg_ParseTuple(args, "O!O!ss|i:buildTransform", &CmsProfile_Type, 
&pInputProfile, &CmsProfile_Type, &pOutputProfile, &sInMode, &sOutMode, 
&iRenderingIntent))
+  if (!PyArg_ParseTuple(args, "O!O!ss|ii:buildTransform", &CmsProfile_Type, 
&pInputProfile, &CmsProfile_Type, &pOutputProfile, &sInMode, &sOutMode, 
&iRenderingIntent, &cmsFLAGS))
     return NULL;
 
   cmsErrorAction(LCMS_ERROR_IGNORE);
 
-  transform = _buildTransform(pInputProfile->profile, pOutputProfile->profile, 
sInMode, sOutMode, iRenderingIntent);
+  transform = _buildTransform(pInputProfile->profile, pOutputProfile->profile, 
sInMode, sOutMode, iRenderingIntent, cmsFLAGS);
 
   if (!transform)
     return NULL;
@@ -347,20 +348,21 @@
 {
   CmsProfileObject *pInputProfile;
   CmsProfileObject *pOutputProfile;
-  CmsProfileObject *pDisplayProfile;
+  CmsProfileObject *pProofProfile;
   char *sInMode;
   char *sOutMode;
   int iRenderingIntent = 0;
-  int iDisplayIntent = 0;
+  int iProofIntent = 0;
+  int cmsFLAGS = 0;
 
   cmsHTRANSFORM transform = NULL;
 
-  if (!PyArg_ParseTuple(args, "O!O!O!ss|ii:buildProofTransform", 
&CmsProfile_Type, &pInputProfile, &CmsProfile_Type, &pOutputProfile, 
&CmsProfile_Type, &pDisplayProfile, &sInMode, &sOutMode, &iRenderingIntent, 
&iDisplayIntent))
+  if (!PyArg_ParseTuple(args, "O!O!O!ss|iii:buildProofTransform", 
&CmsProfile_Type, &pInputProfile, &CmsProfile_Type, &pOutputProfile, 
&CmsProfile_Type, &pProofProfile, &sInMode, &sOutMode, &iRenderingIntent, 
&iProofIntent, &cmsFLAGS))
     return NULL;
 
   cmsErrorAction(LCMS_ERROR_IGNORE);
 
-  transform = _buildProofTransform(pInputProfile->profile, 
pOutputProfile->profile, pDisplayProfile->profile, sInMode, sOutMode, 
iRenderingIntent, iDisplayIntent);
+  transform = _buildProofTransform(pInputProfile->profile, 
pOutputProfile->profile, pProofProfile->profile, sInMode, sOutMode, 
iRenderingIntent, iProofIntent, cmsFLAGS);
   
   if (!transform)
     return NULL;

--- PIL\ImageCms.py.bak Mon Mar 09 19:51:38 2009
+++ PIL\ImageCms.py     Tue Mar 10 12:50:24 2009
@@ -40,6 +40,22 @@
 
     Version History:
 
+        0.1.0 pil mod   March 10, 2009
+
+                        Renamed display profile to proof profile. The proof
+                        profile is the profile of the device that is being
+                        simulated, not the profile of the device which is
+                        actually used to display/print the final simulation
+                        (that'd be the output profile) - also see LCMSAPI.txt
+                        input colorspace -> using 'renderingIntent' -> proof
+                        colorspace -> using 'proofRenderingIntent' -> output
+                        colorspace
+                        
+                        Added LCMS FLAGS support.
+                        Added FLAGS["SOFTPROOFING"] as default flag for
+                        buildProofTransform (otherwise the proof profile/intent
+                        would be ignored).
+
         0.1.0 pil       March 2009 - added to PIL, as PIL.ImageCms
 
         0.0.2 alpha     Jan 6, 2002
@@ -80,6 +96,30 @@
 DIRECTION_OUTPUT = 1
 DIRECTION_PROOF = 2
 
+#
+# flags
+
+FLAGS = {
+    "MATRIXINPUT": 1,
+    "MATRIXOUTPUT": 2,
+    "MATRIXONLY": (1|2),
+    "NOWHITEONWHITEFIXUP": 4, # Don't hot fix scum dot   
+    "NOPRELINEARIZATION": 16, # Don't create prelinearization tables on 
precalculated transforms (internal use)
+    "GUESSDEVICECLASS": 32, # Guess device class (for transform2devicelink)
+    "NOTCACHE": 64, # Inhibit 1-pixel cache
+    "NOTPRECALC": 256,
+    "NULLTRANSFORM": 512, # Don't transform anyway
+    "HIGHRESPRECALC": 1024, # Use more memory to give better accurancy
+    "LOWRESPRECALC": 2048, # Use less memory to minimize resouces
+    "WHITEBLACKCOMPENSATION": 8192,
+    "BLACKPOINTCOMPENSATION": 8192,
+    "GAMUTCHECK": 4096, # Out of Gamut alarm
+    "SOFTPROOFING": 16384, # Do softproofing
+    "PRESERVEBLACK": 32768, # Black preservation
+    "NODEFAULTRESOURCEDEF": 16777216, # CRD special
+    "GRIDPOINTS": lambda n: ((n) & 0xFF) << 16 # Gridpoints
+}
+
 # --------------------------------------------------------------------.
 # Experimental PIL-level API
 # --------------------------------------------------------------------.
@@ -115,18 +155,20 @@
 
     def __init__(self, input, output, input_mode, output_mode,
                  intent=INTENT_PERCEPTUAL,
-                 display=None, display_intent=INTENT_PERCEPTUAL):
-        if display is None:
+                 proof=None, proof_intent=INTENT_ABSOLUTE_COLORIMETRIC, 
flags=0):
+        if proof is None:
             self.transform = cmscore.buildTransform(
                 input.profile, output.profile,
                 input_mode, output_mode,
-                intent
+                intent,
+                flags
                 )
         else:
             self.transform = cmscore.buildProofTransform(
-                input.profile, output.profile, display.profile,
+                input.profile, output.profile, proof.profile,
                 input_mode, output_mode,
-                intent, display_intent
+                intent, proof_intent,
+                flags
                 )
         # Note: inputMode and outputMode are for pyCMS compatibility only
         self.input_mode = self.inputMode = input_mode
@@ -160,7 +202,7 @@
 # (pyCMS) Applies an ICC transformation to a given image, mapping from
 # inputProfile to outputProfile.
 
-def profileToProfile(im, inputProfile, outputProfile, 
renderingIntent=INTENT_PERCEPTUAL, outputMode=None, inPlace=0):
+def profileToProfile(im, inputProfile, outputProfile, 
renderingIntent=INTENT_PERCEPTUAL, outputMode=None, inPlace=0, flags=0):
     """
     ImageCms.profileToProfile(im, inputProfile, outputProfile,
         [renderingIntent], [outputMode], [inPlace])
@@ -191,6 +233,7 @@
         image is modified in-place, and None is returned.  If FALSE
         (default), a new Image object is returned with the transform
         applied.
+    flags = integer (0-...) specifying additional flags
 
     If the input or output profiles specified are not valid filenames, a
     PyCMSError will be raised.  If inPlace == TRUE and outputMode != im.mode,
@@ -217,13 +260,17 @@
     if type(renderingIntent) != type(1) or not (0 <= renderingIntent <=3):
         raise PyCMSError("renderingIntent must be an integer between 0 and 3")
 
+    flagsum = sum([flag if type(flag) == type(1) else 0 for flag in 
FLAGS.values()])
+    if type(flags) != type(1) or not (0 <= flags <=flagsum):
+        raise PyCMSError("flags must be an integer between 0 and " + flagsum)
+
     try:
         if not isinstance(inputProfile, ImageCmsProfile):
             inputProfile = ImageCmsProfile(inputProfile)
         if not isinstance(outputProfile, ImageCmsProfile):
             outputProfile = ImageCmsProfile(outputProfile)
         transform = ImageCmsTransform(
-            inputProfile, outputProfile, im.mode, outputMode, renderingIntent
+            inputProfile, outputProfile, im.mode, outputMode, renderingIntent, 
flags=flags
             )
         if inPlace:
             transform.apply_in_place(im)
@@ -265,7 +312,7 @@
 # outputProfile.  Use applyTransform to apply the transform to a given
 # image.
 
-def buildTransform(inputProfile, outputProfile, inMode, outMode, 
renderingIntent=INTENT_PERCEPTUAL):
+def buildTransform(inputProfile, outputProfile, inMode, outMode, 
renderingIntent=INTENT_PERCEPTUAL, flags=0):
     """
     ImageCms.buildTransform(inputProfile, outputProfile, inMode, outMode,
         [renderingIntent])
@@ -288,6 +335,7 @@
         INTENT_ABSOLUTE_COLORIMETRIC =3 (ImageCms.INTENT_ABSOLUTE_COLORIMETRIC)
         see the pyCMS documentation for details on rendering intents and
         what they do.
+    flags = integer (0-...) specifying additional flags
 
     If the input or output profiles specified are not valid filenames, a
     PyCMSError will be raised.  If an error occurs during creation of the
@@ -321,56 +369,61 @@
     if type(renderingIntent) != type(1) or not (0 <= renderingIntent <=3):
         raise PyCMSError("renderingIntent must be an integer between 0 and 3")
 
+    flagsum = sum([flag if type(flag) == type(1) else 0 for flag in 
FLAGS.values()])
+    if type(flags) != type(1) or not (0 <= flags <=flagsum):
+        raise PyCMSError("flags must be an integer between 0 and " + flagsum)
+
     try:
         if not isinstance(inputProfile, ImageCmsProfile):
             inputProfile = ImageCmsProfile(inputProfile)
         if not isinstance(outputProfile, ImageCmsProfile):
             outputProfile = ImageCmsProfile(outputProfile)
-        return ImageCmsTransform(inputProfile, outputProfile, inMode, outMode, 
renderingIntent)
+        return ImageCmsTransform(inputProfile, outputProfile, inMode, outMode, 
renderingIntent, flags=flags)
     except (IOError, TypeError, ValueError), v:
         raise PyCMSError(v)
 
 ##
 # (pyCMS) Builds an ICC transform mapping from the inputProfile to the
-# displayProfile, but tries to simulate the result that would be
-# obtained on the outputProfile device.
+# outputProfile, but tries to simulate the result that would be
+# obtained on the proofProfile device.
 
-def buildProofTransform(inputProfile, outputProfile, displayProfile, inMode, 
outMode, renderingIntent=INTENT_PERCEPTUAL, 
displayRenderingIntent=INTENT_PERCEPTUAL):
+def buildProofTransform(inputProfile, outputProfile, proofProfile, inMode, 
outMode, renderingIntent=INTENT_PERCEPTUAL, 
proofRenderingIntent=INTENT_ABSOLUTE_COLORIMETRIC, flags=FLAGS["SOFTPROOFING"]):
     """
-    ImageCms.buildProofTransform(inputProfile, outputProfile, displayProfile,
-        inMode, outMode, [renderingIntent], [displayRenderingIntent])
+    ImageCms.buildProofTransform(inputProfile, outputProfile, proofProfile,
+        inMode, outMode, [renderingIntent], [proofRenderingIntent])
         
     Returns a CmsTransform class object.
     
     inputProfile = string, as a valid filename path to the ICC input
         profile you wish to use for this transform, or a profile object
     outputProfile = string, as a valid filename path to the ICC output
-        profile you wish to use for this transform, or a profile object
-    displayProfile = string, as a valid filename path to the ICC display
-        (monitor, usually) profile you wish to use for this transform,
+        (monitor, usually) profile you wish to use for this transform, 
         or a profile object
+    proofProfile = string, as a valid filename path to the ICC proof
+        profile you wish to use for this transform, or a profile object
     inMode = string, as a valid PIL mode that the appropriate profile also
         supports (i.e. "RGB", "RGBA", "CMYK", etc.)
     outMode = string, as a valid PIL mode that the appropriate profile also
         supports (i.e. "RGB", "RGBA", "CMYK", etc.)
     renderingIntent = integer (0-3) specifying the rendering intent you
-        wish to use for the input->output (simulated) transform
+        wish to use for the input->proof (simulated) transform
         INTENT_PERCEPTUAL =           0 (DEFAULT) (ImageCms.INTENT_PERCEPTUAL)
         INTENT_RELATIVE_COLORIMETRIC =1 (ImageCms.INTENT_RELATIVE_COLORIMETRIC)
         INTENT_SATURATION =           2 (ImageCms.INTENT_SATURATION)
         INTENT_ABSOLUTE_COLORIMETRIC =3 (ImageCms.INTENT_ABSOLUTE_COLORIMETRIC)
         see the pyCMS documentation for details on rendering intents and
         what they do.
-    displayRenderingIntent = integer (0-3) specifying the rendering intent
-        you wish to use for (input/output simulation)->display transform
+    proofRenderingIntent = integer (0-3) specifying the rendering intent
+        you wish to use for proof->output transform
         INTENT_PERCEPTUAL =           0 (DEFAULT) (ImageCms.INTENT_PERCEPTUAL)
         INTENT_RELATIVE_COLORIMETRIC =1 (ImageCms.INTENT_RELATIVE_COLORIMETRIC)
         INTENT_SATURATION =           2 (ImageCms.INTENT_SATURATION)
         INTENT_ABSOLUTE_COLORIMETRIC =3 (ImageCms.INTENT_ABSOLUTE_COLORIMETRIC)
         see the pyCMS documentation for details on rendering intents and
         what they do.
+    flags = integer (0-...) specifying additional flags
         
-    If the input, output, or display profiles specified are not valid
+    If the input, output, or proof profiles specified are not valid
     filenames, a PyCMSError will be raised.
     
     If an error occurs during creation of the transform, a PyCMSError will
@@ -380,9 +433,9 @@
     (or by pyCMS), a PyCMSError will be raised.
 
     This function builds and returns an ICC transform from the inputProfile
-    to the displayProfile, but tries to simulate the result that would be
-    obtained on the outputProfile device using renderingIntent and
-    displayRenderingIntent to determine what to do with out-of-gamut
+    to the outputProfile, but tries to simulate the result that would be
+    obtained on the proofProfile device using renderingIntent and
+    proofRenderingIntent to determine what to do with out-of-gamut
     colors.  This is known as "soft-proofing".  It will ONLY work for
     converting images that are in inMode to images that are in outMode
     color format (PIL mode, i.e. "RGB", "RGBA", "CMYK", etc.).
@@ -390,17 +443,17 @@
     Usage of the resulting transform object is exactly the same as with
     ImageCms.buildTransform().
 
-    Proof profiling is generally used when using a "proof" device to get a
+    Proof profiling is generally used when using an output device to get a
     good idea of what the final printed/displayed image would look like on
-    the outputProfile device when it's quicker and easier to use the
-    display device for judging color.  Generally, this means that
-    displayDevice is a monitor, or a dye-sub printer (etc.), and the output
+    the proofProfile device when it's quicker and easier to use the
+    output device for judging color.  Generally, this means that the
+    output device is a monitor, or a dye-sub printer (etc.), and the simulated
     device is something more expensive, complicated, or time consuming
     (making it difficult to make a real print for color judgement purposes).
 
-    Soft-proofing basically functions by limiting the color gamut on the
-    display device to the gamut availabile on the output device.  However,
-    when the final output device has a much wider gamut than the display
+    Soft-proofing basically functions by adjusting the colors on the
+    output device to match the colors of the device being simulated. However,
+    when the simulated device has a much wider gamut than the output
     device, you may obtain marginal results.
     
     """ 
@@ -408,14 +461,18 @@
     if type(renderingIntent) != type(1) or not (0 <= renderingIntent <=3):
         raise PyCMSError("renderingIntent must be an integer between 0 and 3")
 
+    flagsum = sum([flag if type(flag) == type(1) else 0 for flag in 
FLAGS.values()])
+    if type(flags) != type(1) or not (0 <= flags <=flagsum):
+        raise PyCMSError("flags must be an integer between 0 and " + flagsum)
+
     try:
         if not isinstance(inputProfile, ImageCmsProfile):
             inputProfile = ImageCmsProfile(inputProfile)
         if not isinstance(outputProfile, ImageCmsProfile):
             outputProfile = ImageCmsProfile(outputProfile)
-        if not isinstance(displayProfile, ImageCmsProfile):
-            displayProfile = ImageCmsProfile(displayProfile)
-        return ImageCmsTransform(inputProfile, outputProfile, inMode, outMode, 
renderingIntent, display=displayProfile, display_intent=displayRenderingIntent)
+        if not isinstance(proofProfile, ImageCmsProfile):
+            proofProfile = ImageCmsProfile(proofProfile)
+        return ImageCmsTransform(inputProfile, outputProfile, inMode, outMode, 
renderingIntent, proofProfile, proofRenderingIntent, flags)
     except (IOError, TypeError, ValueError), v:
         raise PyCMSError(v)
 
@@ -641,14 +698,14 @@
         see the pyCMS documentation for details on rendering intents and
         what they do.
     direction = integer specifing if the profile is to be used for input,
-        output, or display/proof
+        output, or proof
         INPUT =               0 (or use ImageCms.DIRECTION_INPUT)
         OUTPUT =              1 (or use ImageCms.DIRECTION_OUTPUT)
-        PROOF (or display) =  2 (or use ImageCms.DIRECTION_PROOF)
+        PROOF =               2 (or use ImageCms.DIRECTION_PROOF)
 
     Use this function to verify that you can use your desired
     renderingIntent with profile, and that profile can be used for the
-    input/output/display profile as you desire.
+    input/output/proof profile as you desire.
 
     Some profiles are created specifically for one "direction", can cannot
     be used for others.  Some profiles can only be used for certain

_______________________________________________
Image-SIG maillist  -  Image-SIG@python.org
http://mail.python.org/mailman/listinfo/image-sig

Reply via email to