reportlab: added preliminary support for enforcing color spaces
authorrgbecker
Wed, 15 Sep 2010 15:15:46 +0000
changeset 3443 64d1fba94908
parent 3442 04096d41cb18
child 3444 bea839deb0c1
reportlab: added preliminary support for enforcing color spaces
src/reportlab/pdfgen/canvas.py
src/reportlab/pdfgen/pycanvas.py
src/reportlab/pdfgen/textobject.py
src/reportlab/platypus/doctemplate.py
--- a/src/reportlab/pdfgen/canvas.py	Wed Sep 15 15:13:54 2010 +0000
+++ b/src/reportlab/pdfgen/canvas.py	Wed Sep 15 15:15:46 2010 +0000
@@ -177,6 +177,7 @@
                  encrypt=None,
                  cropMarks=None,
                  pdfVersion=None,
+                 enforceColorSpace=None,
                  ):
         """Create a canvas of a given size. etc.
 
@@ -188,6 +189,9 @@
         as the preferred interface.  Default page size is A4.
         cropMarks may be True/False or an object with parameters borderWidth, markColor, markWidth
         and markLength
+    
+        if enforceColorSpace is in ('cmyk', 'rgb') then one of the standard _PDFColorSetter callables
+        will be used to enforce appropriate color settings. If it is a callable then that will be used.
         """
         if pagesize is None: pagesize = rl_config.defaultPageSize
         if invariant is None: invariant = rl_config.invariant
@@ -198,6 +202,19 @@
                                        pdfVersion=pdfVersion or pdfdoc.PDF_VERSION_DEFAULT,
                                        )
 
+
+        if enforceColorSpace is not None:
+            if enforceColorSpace=='cmyk':
+                self._enforceColorSpace = self._enforceCMYK
+            elif enforceColorSpace=='rgb':
+                self._enforceColorSpace = self._enforceRGB
+            elif enforceColorSpace=='sep':
+                self._enforceColorSpace = self._enforceSEP
+            elif callable(enforceColorSpace):
+                self._enforceColorSpace = enforceColorSpace
+            else:
+                raise ValueError('Invalid value for Canvas argument enforceColorSpace=%r' % enforceColorSpace)
+
         #this only controls whether it prints 'saved ...' - 0 disables
         self._verbosity = verbosity
 
--- a/src/reportlab/pdfgen/pycanvas.py	Wed Sep 15 15:13:54 2010 +0000
+++ b/src/reportlab/pdfgen/pycanvas.py	Wed Sep 15 15:15:46 2010 +0000
@@ -273,6 +273,7 @@
         self._formnumber = 0
         self._footerpresent = 0
         self._object = canvas.Canvas(*args,**kwargs)
+        self._enforceColorSpace = self._object._enforceColorSpace
         self._pyfile = cStringIO.StringIO()
         self._PyWrite(PyHeader)
         try :
--- a/src/reportlab/pdfgen/textobject.py	Wed Sep 15 15:13:54 2010 +0000
+++ b/src/reportlab/pdfgen/textobject.py	Wed Sep 15 15:15:46 2010 +0000
@@ -11,14 +11,13 @@
 """
 import string
 from types import *
-from reportlab.lib.colors import Color, CMYKColor, CMYKColorSep, toColor
+from reportlab.lib.colors import Color, CMYKColor, CMYKColorSep, toColor, black, white, _CMYK_black, _CMYK_white
 from reportlab.lib.utils import fp_str
 from reportlab.pdfbase import pdfmetrics
 
 class _PDFColorSetter:
     '''Abstracts the color setting operations; used in Canvas and Textobject
     asseumes we have a _code object'''
-
     def _checkSeparation(self,cmyk):
         if isinstance(cmyk,CMYKColorSep):
             name,sname = self._doc.addColor(cmyk)
@@ -26,42 +25,74 @@
                 self._colorsUsed[name] = sname
             return name
 
+    def _enforceSEP(c):
+        tc = toColor(c)
+        if not isinstance(tc,CMYKColorSep):
+            raise ValueError('Non separating color %r' % c)
+        return c
+    _enforceSEP = staticmethod(_enforceSEP)
+
+    def _enforceCMYK(c):
+        tc = toColor(c)
+        if not isinstance(tc,CMYKColor):
+            if tc==black:
+                c = _CMYK_black
+            elif tc==white:
+                c = _CMYK_white
+            else:
+                if isinstance(tc,Color) and tc.red==tc.blue==tc.green: #ahahahah it's grey
+                    c = _CMYK_black.clone(density=1-tc.red)
+                else:
+                    raise ValueError('Non CMYK color %r' % c)
+        return c
+    _enforceCMYK = staticmethod(_enforceCMYK)
+
+    def _enforceRGB(c):
+        tc = toColor(c)
+        if not isinstance(tc,Color):
+            if tc==_CMYK_black:
+                c = black
+            elif tc==_CMYK_white:
+                c = white
+            else:
+                if isinstance(tc,CMYKColor) and tc.cyan==tc.magenta==tc.yellow==0: #ahahahah it's grey
+                    c = black.clone()
+                    c.red = c.green = c.blue = 1-tc.black
+                else:
+                    raise ValueError('Non RGB color %r' % c)
+        return c
+    _enforceRGB = staticmethod(_enforceRGB)
+
+    #if this is set to a callable(color) --> color it can be used to check color setting
+    #see eg _enforceCMYK/_enforceRGB
+    _enforceColorSpace = None
+
     def setFillColorCMYK(self, c, m, y, k, alpha=None):
          """set the fill color useing negative color values
          (cyan, magenta, yellow and darkness value).
          Takes 4 arguments between 0.0 and 1.0"""
-         self._fillColorObj = (c, m, y, k)
-         self._code.append('%s k' % fp_str(c, m, y, k))
-         if alpha is not None:
-             self.setFillAlpha(alpha)
+         self.setFillColor((c,m,y,k),alpha=alpha)
 
     def setStrokeColorCMYK(self, c, m, y, k, alpha=None):
          """set the stroke color useing negative color values
             (cyan, magenta, yellow and darkness value).
             Takes 4 arguments between 0.0 and 1.0"""
-         self._strokeColorObj = (c, m, y, k)
-         self._code.append('%s K' % fp_str(c, m, y, k))
-         if alpha is not None:
-             self.setStrokeAlpha(alpha)
+         self.setStrokeColor((c,m,y,k),alpha=alpha)
 
     def setFillColorRGB(self, r, g, b, alpha=None):
         """Set the fill color using positive color description
            (Red,Green,Blue).  Takes 3 arguments between 0.0 and 1.0"""
-        self._fillColorObj = (r, g, b)
-        self._code.append('%s rg' % fp_str(r,g,b))
-        if alpha is not None:
-            self.setFillAlpha(alpha)
+        self.setFillColor((r,g,b),alpha=alpha)
 
     def setStrokeColorRGB(self, r, g, b, alpha=None):
         """Set the stroke color using positive color description
            (Red,Green,Blue).  Takes 3 arguments between 0.0 and 1.0"""
-        self._strokeColorObj = (r, g, b)
-        self._code.append('%s RG' % fp_str(r,g,b))
-        if alpha is not None:
-            self.setStrokeAlpha(alpha)
+        self.setStrokeColor((r,g,b),alpha=alpha)
 
     def setFillColor(self, aColor, alpha=None):
         """Takes a color object, allowing colors to be referred to by name"""
+        if self._enforceColorSpace:
+            aColor = self._enforceColorSpace(aColor)
         if isinstance(aColor, CMYKColor):
             d = aColor.density
             c,m,y,k = (d*aColor.cyan, d*aColor.magenta, d*aColor.yellow, d*aColor.black)
@@ -81,7 +112,8 @@
                 self._fillColorObj = aColor
                 self._code.append('%s rg' % fp_str(aColor) )
             elif l==4:
-                self.setFillColorCMYK(aColor[0], aColor[1], aColor[2], aColor[3])
+                self._fillColorObj = aColor
+                self._code.append('%s k' % fp_str(aColor))
             else:
                 raise ValueError('Unknown color %r' % aColor)
         elif isinstance(aColor,basestring):
@@ -95,6 +127,8 @@
 
     def setStrokeColor(self, aColor, alpha=None):
         """Takes a color object, allowing colors to be referred to by name"""
+        if self._enforceColorSpace:
+            aColor = self._enforceColorSpace(aColor)
         if isinstance(aColor, CMYKColor):
             d = aColor.density
             c,m,y,k = (d*aColor.cyan, d*aColor.magenta, d*aColor.yellow, d*aColor.black)
@@ -114,7 +148,8 @@
                 self._strokeColorObj = aColor
                 self._code.append('%s RG' % fp_str(aColor) )
             elif l==4:
-                self.setStrokeColorCMYK(aColor[0], aColor[1], aColor[2], aColor[3])
+                self._fillColorObj = aColor
+                self._code.append('%s K' % fp_str(aColor))
             else:
                 raise ValueError('Unknown color %r' % aColor)
         elif isinstance(aColor,basestring):
@@ -178,6 +213,7 @@
         self._leading = self._canvas._leading
         self._doc = self._canvas._doc
         self._colorsUsed = self._canvas._colorsUsed
+        self._enforceColorSpace = getattr(canvas,'_enforceColorSpace',None)
         font = pdfmetrics.getFont(self._fontname)
         self._curSubset = -1
         self.setTextOrigin(x, y)
--- a/src/reportlab/platypus/doctemplate.py	Wed Sep 15 15:13:54 2010 +0000
+++ b/src/reportlab/platypus/doctemplate.py	Wed Sep 15 15:15:46 2010 +0000
@@ -441,6 +441,7 @@
                     '_debug':0,
                     'encrypt': None,
                     'cropMarks': None,
+                    'enforceColorSpace': None,
                     }
     _invalidInitArgs = ()
     _firstPageTemplateIndex = 0
@@ -817,7 +818,9 @@
         self.canv = canvasmaker(filename or self.filename,
                                 pagesize=self.pagesize,
                                 invariant=self.invariant,
-                                pageCompression=self.pageCompression)
+                                pageCompression=self.pageCompression,
+                                enforceColorSpace=self.enforceColorSpace,
+                                )
  
         getattr(self.canv,'setEncrypt',lambda x: None)(self.encrypt)