add support for crop/art/trim/bleed boxes; version --> 3.2.2
authorrobin
Wed, 24 Jun 2015 14:13:27 +0100
changeset 4212 c903815560d1
parent 4211 464df39467fc
child 4213 577178727e17
add support for crop/art/trim/bleed boxes; version --> 3.2.2
src/reportlab/__init__.py
src/reportlab/pdfgen/canvas.py
src/reportlab/platypus/doctemplate.py
tests/test_pdfgen_general.py
--- a/src/reportlab/__init__.py	Fri Jun 19 14:09:51 2015 +0100
+++ b/src/reportlab/__init__.py	Wed Jun 24 14:13:27 2015 +0100
@@ -1,7 +1,7 @@
 #Copyright ReportLab Europe Ltd. 2000-2015
 #see license.txt for license details
 __doc__="""The Reportlab PDF generation library."""
-Version = "3.2.1"
+Version = "3.2.2"
 __version__=Version
 
 import sys, os, imp
--- a/src/reportlab/pdfgen/canvas.py	Fri Jun 19 14:09:51 2015 +0100
+++ b/src/reportlab/pdfgen/canvas.py	Wed Jun 24 14:13:27 2015 +0100
@@ -240,6 +240,10 @@
                  initialFontName=None,
                  initialFontSize=None,
                  initialLeading=None,
+                 cropBox=None,
+                 artBox=None,
+                 trimBox=None,
+                 bleedBox=None,
                  ):
         """Create a canvas of a given size. etc.
 
@@ -305,6 +309,12 @@
         #drawing coordinates.
         self.bottomup = bottomup
         self.imageCaching = rl_config.defaultImageCaching
+
+        self._cropBox = cropBox     #we don't do semantics for these at all
+        self._artBox = artBox
+        self._trimBox = trimBox
+        self._bleedBox = bleedBox
+
         self.init_graphics_state()
         self._make_preamble()
         self.state_stack = []
@@ -638,6 +648,10 @@
         page.hasImages = self._currentPageHasImages
         page.setPageTransition(self._pageTransition)
         page.setCompression(self._pageCompression)
+        for box in ('crop','art','bleed','trim'):
+            size = getattr(self,'_%sBox'%box,None)
+            if size:
+                setattr(page,box.capitalize()+'Box',pdfdoc.PDFArray(size))
         if self._pageDuration is not None:
             page.Dur = self._pageDuration
 
@@ -1238,6 +1252,23 @@
         self._pagesize = size
         self._make_preamble()
 
+    def setCropBox(self, size, name='crop'):
+        """accepts a 2-tuple in points for name+'Box' size for this and subsequent pages"""
+        name = name.lower()
+        if name.endswith('box'): name = name[:-3]
+        if name not in ('crop','art','trim','bleed'):
+            raise ValueError('unknown box name: %r' % name)
+        setattr(self,'_%sBox' % name, size)
+
+    def setTrimBox(self,size):
+        self.setCropBox(size,name='trim')
+
+    def setArtBox(self,size):
+        self.setCropBox(size,name='art')
+
+    def setBleedBox(self,size):
+        self.setCropBox(size,name='bleed')
+
     def setPageRotation(self, rot):
         """Instruct display device that this page is to be rotated"""
         assert rot % 90.0 == 0.0, "Rotation must be a multiple of 90 degrees"
--- a/src/reportlab/platypus/doctemplate.py	Fri Jun 19 14:09:51 2015 +0100
+++ b/src/reportlab/platypus/doctemplate.py	Wed Jun 24 14:13:27 2015 +0100
@@ -251,7 +251,12 @@
     derived classes can also implement beforeDrawPage and afterDrawPage if they want
     """
     def __init__(self,id=None,frames=[],onPage=_doNothing, onPageEnd=_doNothing,
-                 pagesize=None, autoNextPageTemplate=None):
+                 pagesize=None, autoNextPageTemplate=None,
+                 cropBox=None,
+                 artBox=None,
+                 trimBox=None,
+                 bleedBox=None,
+                 ):
         frames = frames or []
         if not isSeq(frames): frames = [frames]
         assert [x for x in frames if not isinstance(x,Frame)]==[], "frames argument error"
@@ -261,6 +266,10 @@
         self.onPageEnd = onPageEnd
         self.pagesize = pagesize
         self.autoNextPageTemplate = autoNextPageTemplate
+        self.cropBox = cropBox
+        self.artBox = artBox
+        self.trimBox = trimBox
+        self.bleedBox = bleedBox
 
     def beforeDrawPage(self,canv,doc):
         """Override this if you want additional functionality or prefer
@@ -288,6 +297,10 @@
                 canv.setPageSize(self.pagesize)
             elif cp!=dp:
                 canv.setPageSize(doc.pagesize)
+        for box in 'crop','art','trim','bleed':
+            size = getattr(self,box+'Box',None)
+            if size:
+                canv.setCropBox(size,name=box)
 
     def afterDrawPage(self, canv, doc):
         """This is called after the last flowable for the page has
@@ -456,6 +469,10 @@
                     'initialFontName': None,
                     'initialFontSize': None,
                     'initialLeading': None,
+                    'cropBox': None,
+                    'artBox': None,
+                    'trimBox': None,
+                    'bleedBox': None,
                     }
     _invalidInitArgs = ()
     _firstPageTemplateIndex = 0
@@ -863,6 +880,10 @@
                                 initialFontName = self.initialFontName,
                                 initialFontSize = self.initialFontSize,
                                 initialLeading = self.initialLeading,
+                                cropBox = self.cropBox,
+                                artBox = self.artBox,
+                                trimBox = self.trimBox,
+                                bleedBox = self.bleedBox,
                                 )
 
         getattr(self.canv,'setEncrypt',lambda x: None)(self.encrypt)
--- a/tests/test_pdfgen_general.py	Fri Jun 19 14:09:51 2015 +0100
+++ b/tests/test_pdfgen_general.py	Wed Jun 24 14:13:27 2015 +0100
@@ -209,7 +209,7 @@
     c.drawString(100, 100, msg_uni)
     c.drawString(100, 80, msg_utf8)
 
-    
+
 
 
     t = c.beginText(inch, 10*inch)
@@ -546,7 +546,7 @@
         if anchor=='end':
             x -= width
         elif anchor in ('centre','center'):
-            x = 0.5*width 
+            x = 0.5*width
         c.saveState()
         c.setDash(2,2)
         c.setStrokeColor(color)
@@ -824,33 +824,33 @@
         #preserveAspectRatio test
         c.drawString(inch, 8.8*inch, 'Both of these should appear within the boxes, vertically centered')
 
-    
+
         x, y, w, h = inch, 6.75* inch, 2*inch, 2*inch
         c.rect(x, y, w, h)
         (w2, h2) = c.drawImage(gif,  #anchor southwest, drawImage
-                    x, y, width=w, height=h, 
-                    preserveAspectRatio=True, 
+                    x, y, width=w, height=h,
+                    preserveAspectRatio=True,
                     anchor='c'
                     )
-                    
-        #now test drawInlineImage across the page            
+
+        #now test drawInlineImage across the page
         x = 5 * inch
         c.rect(x, y, w, h)
         (w2, h2) = c.drawInlineImage(gif,  #anchor southwest, drawInlineImage
-                    x, y, width=w, height=h, 
+                    x, y, width=w, height=h,
                     preserveAspectRatio=True,
                     anchor='c'
                     )
-                    
-        c.drawString(inch, 5.75*inch, 
+
+        c.drawString(inch, 5.75*inch,
         'anchored by respective corners - use both a wide and a tall one as tests')
         x = 0.25 * inch
         for anchor in ['nw','n','ne','w','c','e','sw','s','se']:
             x += 0.75*inch
             c.rect(x, 5*inch, 0.6*inch, 0.6*inch)
             c.drawImage(
-                    gif, x, 5*inch, 
-                    width=0.6*inch, height=0.6*inch, 
+                    gif, x, 5*inch,
+                    width=0.6*inch, height=0.6*inch,
                     preserveAspectRatio=True,
                     anchor=anchor
                     )
@@ -862,8 +862,8 @@
             x += 0.75*inch
             c.rect(x, 4*inch, 0.6*inch, 0.6*inch)
             c.drawImage(
-                    tall_red, x, 4*inch, 
-                    width=0.6*inch, height=0.6*inch, 
+                    tall_red, x, 4*inch,
+                    width=0.6*inch, height=0.6*inch,
                     preserveAspectRatio=True,
                     anchor=anchor
                     )
@@ -1034,7 +1034,7 @@
             c.showPage()
 
         # Output the PDF
-        c.save()    
+        c.save()
 
     def test2(self):
         c=canvas.Canvas('test_pdfgen_autocropmarks.pdf',cropMarks=True)
@@ -1112,7 +1112,7 @@
         self.assertRaises(ValueError,trySomeColors,rgb+cmyk+seps,'rgb')
         self.assertRaises(ValueError,trySomeColors,rgb+cmyk,'rgb')
         self.assertRaises(ValueError,trySomeColors,rgb+seps,'rgb')
-        trySomeColors(rgb+sepb,'rgb')   #should work because blacks are convertible 
+        trySomeColors(rgb+sepb,'rgb')   #should work because blacks are convertible
         trySomeColors(rgb+cmykb,'rgb')
         self.assertRaises(ValueError,trySomeColors,cmyk+rgb+seps,'cmyk')
         trySomeColors(cmyk+['black']+seps,'cmyk')   #OK because black & seps are convertible
@@ -1167,8 +1167,18 @@
         # Output the PDF
         stuff = c.getpdfdata()
         #multiple calls to save / getpdfdata used to cause errors
-        stuff = c.getpdfdata()    
+        stuff = c.getpdfdata()
 
+    def testBoxes(self):
+        c=canvas.Canvas(outputfile('test_pdfgen_boxes.pdf'))
+        w,h = c._pagesize
+        c.setCropBox((0.1,0.1,w-0.2,h-0.2))
+        c.setBleedBox((-0.1,-0.1,w+0.2,h+0.2))
+        c.setArtBox((0.2,0.2,w-0.4,h-0.4))
+        c.setTrimBox((0.01,0.01,w-0.02,h-0.02))
+        c.drawString(100, 700, 'Hello World!')
+        c.showPage()
+        c.save()
 
 def trySomeColors(C,enforceColorSpace=None):
     from reportlab.lib.utils import getBytesIO