~openerp-groupes/openobject-server/6.0-fix-setup-windows

« back to all changes in this revision

Viewing changes to bin/reportlab/platypus/figures.py

  • Committer: pinky
  • Date: 2006-12-07 13:41:40 UTC
  • Revision ID: pinky-3f10ee12cea3c4c75cef44ab04ad33ef47432907
New trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#Copyright ReportLab Europe Ltd. 2000-2004
 
2
#see license.txt for license details
 
3
#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/platypus/figures.py
 
4
"""This includes some demos of platypus for use in the API proposal"""
 
5
__version__=''' $Id$ '''
 
6
 
 
7
import os
 
8
 
 
9
from reportlab.lib import colors
 
10
from reportlab.pdfgen.canvas import Canvas
 
11
from reportlab.lib.styles import ParagraphStyle
 
12
from reportlab.lib.utils import recursiveImport
 
13
from reportlab.platypus import Frame
 
14
from reportlab.platypus import Flowable
 
15
from reportlab.platypus import Paragraph
 
16
from reportlab.lib.units import inch
 
17
from reportlab.lib.enums import TA_LEFT, TA_RIGHT, TA_CENTER
 
18
from reportlab.lib.validators import isColor
 
19
from reportlab.lib.colors import toColor
 
20
 
 
21
captionStyle = ParagraphStyle('Caption', fontName='Times-Italic', fontSize=10, alignment=TA_CENTER)
 
22
 
 
23
class Figure(Flowable):
 
24
    def __init__(self, width, height, caption="",
 
25
                 captionFont="Times-Italic", captionSize=12,
 
26
                 background=None,
 
27
                 captionTextColor=toColor('black'),
 
28
                 captionBackColor=None,
 
29
                 border=1):
 
30
        Flowable.__init__(self)
 
31
        self.width = width
 
32
        self.figureHeight = height
 
33
        self.caption = caption
 
34
        self.captionFont = captionFont
 
35
        self.captionSize = captionSize
 
36
        self.captionTextColor = captionTextColor
 
37
        self.captionBackColor = captionBackColor
 
38
        self._captionData = None
 
39
        self.captionHeight = 0  # work out later
 
40
        self.background = background
 
41
        self.border = border
 
42
        self.spaceBefore = 12
 
43
        self.spaceAfter = 12
 
44
 
 
45
    def _getCaptionPara(self):
 
46
        caption = self.caption
 
47
        captionFont = self.captionFont
 
48
        captionSize = self.captionSize
 
49
        captionTextColor = self.captionTextColor
 
50
        captionBackColor = self.captionBackColor
 
51
        if self._captionData!=(caption,captionFont,captionSize,captionTextColor,captionBackColor):
 
52
            self._captionData = (caption,captionFont,captionSize,captionTextColor,captionBackColor)
 
53
            self.captionStyle = ParagraphStyle(
 
54
                'Caption',
 
55
                fontName=captionFont,
 
56
                fontSize=captionSize,
 
57
                leading=1.2*captionSize,
 
58
                textColor = captionTextColor,
 
59
                backColor = captionBackColor,
 
60
                spaceBefore=captionSize * 0.5,
 
61
                alignment=TA_CENTER)
 
62
            #must build paragraph now to get sequencing in synch with rest of story
 
63
            self.captionPara = Paragraph(self.caption, self.captionStyle)
 
64
 
 
65
    def wrap(self, availWidth, availHeight):
 
66
        # try to get the caption aligned
 
67
        if self.caption:
 
68
            self._getCaptionPara()
 
69
            (w, h) = self.captionPara.wrap(self.width, availHeight - self.figureHeight)
 
70
            self.captionHeight = h
 
71
            self.height = self.captionHeight + self.figureHeight
 
72
            if w>self.width: self.width = w
 
73
        else:
 
74
            self.height = self.figureHeight
 
75
        self.dx = 0.5 * (availWidth - self.width)
 
76
        return (self.width, self.height)
 
77
 
 
78
    def draw(self):
 
79
        self.canv.translate(self.dx, 0)
 
80
        if self.caption:
 
81
            self._getCaptionPara()
 
82
            self.drawCaption()
 
83
            self.canv.translate(0, self.captionHeight)
 
84
        if self.background:
 
85
            self.drawBackground()
 
86
        if self.border:
 
87
            self.drawBorder()
 
88
        self.drawFigure()
 
89
 
 
90
    def drawBorder(self):
 
91
        self.canv.rect(0, 0, self.width, self.figureHeight)
 
92
 
 
93
    def _doBackground(self, color):
 
94
        self.canv.saveState()
 
95
        self.canv.setFillColor(self.background)
 
96
        self.canv.rect(0, 0, self.width, self.figureHeight, fill=1)
 
97
        self.canv.restoreState()
 
98
 
 
99
    def drawBackground(self):
 
100
        """For use when using a figure on a differently coloured background.
 
101
        Allows you to specify a colour to be used as a background for the figure."""
 
102
        if isColor(self.background):
 
103
            self._doBackground(self.background)
 
104
        else:
 
105
            try:
 
106
                c = toColor(self.background)
 
107
                self._doBackground(c)
 
108
            except:
 
109
                pass
 
110
 
 
111
    def drawCaption(self):
 
112
        self.captionPara.drawOn(self.canv, 0, 0)
 
113
 
 
114
    def drawFigure(self):
 
115
        pass
 
116
 
 
117
def drawPage(canvas,x, y, width, height):
 
118
    #draws something which looks like a page
 
119
    pth = canvas.beginPath()
 
120
    corner = 0.05*width
 
121
 
 
122
    # shaded backdrop offset a little
 
123
    canvas.setFillColorRGB(0.5,0.5,0.5)
 
124
    canvas.rect(x + corner, y - corner, width, height, stroke=0, fill=1)
 
125
 
 
126
    #'sheet of paper' in light yellow
 
127
    canvas.setFillColorRGB(1,1,0.9)
 
128
    canvas.setLineWidth(0)
 
129
    canvas.rect(x, y, width, height, stroke=1, fill=1)
 
130
 
 
131
    #reset
 
132
    canvas.setFillColorRGB(0,0,0)
 
133
    canvas.setStrokeColorRGB(0,0,0)
 
134
 
 
135
class PageFigure(Figure):
 
136
    """Shows a blank page in a frame, and draws on that.  Used in
 
137
    illustrations of how PLATYPUS works."""
 
138
    def __init__(self, background=None):
 
139
        Figure.__init__(self, 3*inch, 3*inch)
 
140
        self.caption = 'Figure 1 - a blank page'
 
141
        self.captionStyle = captionStyle
 
142
        self.background = background
 
143
 
 
144
    def drawVirtualPage(self):
 
145
        pass
 
146
 
 
147
    def drawFigure(self):
 
148
        drawPage(self.canv, 0.625*inch, 0.25*inch, 1.75*inch, 2.5*inch)
 
149
        self.canv.translate(0.625*inch, 0.25*inch)
 
150
        self.canv.scale(1.75/8.27, 2.5/11.69)
 
151
        self.drawVirtualPage()
 
152
 
 
153
class PlatPropFigure1(PageFigure):
 
154
    """This shows a page with a frame on it"""
 
155
    def __init__(self):
 
156
        PageFigure.__init__(self)
 
157
        self.caption = "Figure 1 - a page with a simple frame"
 
158
    def drawVirtualPage(self):
 
159
        demo1(self.canv)
 
160
 
 
161
class FlexFigure(Figure):
 
162
    """Base for a figure class with a caption. Can grow or shrink in proportion"""
 
163
    def __init__(self, width, height, caption, background=None):
 
164
        Figure.__init__(self, width, height, caption,
 
165
                        captionFont="Helvetica-Oblique", captionSize=8,
 
166
                        background=None)
 
167
        self.shrinkToFit = 1 #if set and wrap is too tight, shrinks
 
168
        self.growToFit = 1 #if set and wrap is too tight, shrinks
 
169
        self.scaleFactor = None
 
170
        self.captionStyle = ParagraphStyle(
 
171
            'Caption',
 
172
            fontName='Times', #'Helvetica-Oblique',
 
173
            fontSize=4, #8,
 
174
            spaceBefore=9, #3,
 
175
            alignment=TA_CENTER
 
176
            )
 
177
        self._scaleFactor = None
 
178
        self.background = background
 
179
 
 
180
    def _scale(self,availWidth,availHeight):
 
181
        "Rescale to fit according to the rules, but only once"
 
182
        if self._scaleFactor is None or self.width>availWidth or self.height>availHeight:
 
183
            w, h = Figure.wrap(self, availWidth, availHeight)
 
184
            captionHeight = h - self.figureHeight
 
185
            if self.scaleFactor is None:
 
186
                #scale factor None means auto
 
187
                self._scaleFactor = min(availWidth/self.width,(availHeight-captionHeight)/self.figureHeight)
 
188
            else: #they provided a factor
 
189
                self._scaleFactor = self.scaleFactor
 
190
            if self._scaleFactor<1 and self.shrinkToFit:
 
191
                self.width = self.width * self._scaleFactor - 0.0001
 
192
                self.figureHeight = self.figureHeight * self._scaleFactor
 
193
            elif self._scaleFactor>1 and self.growToFit:
 
194
                self.width = self.width*self._scaleFactor - 0.0001
 
195
                self.figureHeight = self.figureHeight * self._scaleFactor
 
196
 
 
197
    def wrap(self, availWidth, availHeight):
 
198
        self._scale(availWidth,availHeight)
 
199
        return Figure.wrap(self, availWidth, availHeight)
 
200
 
 
201
    def split(self, availWidth, availHeight):
 
202
        self._scale(availWidth,availHeight)
 
203
        return Figure.split(self, availWidth, availHeight)
 
204
 
 
205
class ImageFigure(FlexFigure):
 
206
    """Image with a caption below it"""
 
207
    def __init__(self, filename, caption, background=None):
 
208
        assert os.path.isfile(filename), 'image file %s not found' % filename
 
209
        from reportlab.lib.utils import ImageReader
 
210
        w, h = ImageReader(filename).getSize()
 
211
        self.filename = filename
 
212
        FlexFigure.__init__(self, w, h, caption, background)
 
213
 
 
214
    def drawFigure(self):
 
215
        self.canv.drawInlineImage(self.filename,
 
216
                                  0, 0,self.width, self.figureHeight)
 
217
 
 
218
class DrawingFigure(FlexFigure):
 
219
    """Drawing with a caption below it.  Clunky, scaling fails."""
 
220
    def __init__(self, modulename, classname, caption, baseDir=None, background=None):
 
221
        module = recursiveImport(modulename, baseDir)
 
222
        klass = getattr(module, classname)
 
223
        self.drawing = klass()
 
224
        FlexFigure.__init__(self,
 
225
                            self.drawing.width,
 
226
                            self.drawing.height,
 
227
                            caption,
 
228
                            background)
 
229
        self.growToFit = 1
 
230
 
 
231
    def drawFigure(self):
 
232
        self.canv.scale(self._scaleFactor, self._scaleFactor)
 
233
        self.drawing.drawOn(self.canv, 0, 0)
 
234
 
 
235
 
 
236
try:
 
237
    from rlextra.pageCatcher.pageCatcher import restoreForms, storeForms, storeFormsInMemory, restoreFormsInMemory
 
238
    _hasPageCatcher = 1
 
239
except ImportError:
 
240
    _hasPageCatcher = 0
 
241
if _hasPageCatcher:
 
242
    ####################################################################
 
243
    #
 
244
    #    PageCatcher plugins
 
245
    # These let you use our PageCatcher product to add figures
 
246
    # to other documents easily.
 
247
    ####################################################################
 
248
    class PageCatcherCachingMixIn:
 
249
        "Helper functions to cache pages for figures"
 
250
 
 
251
        def getFormName(self, pdfFileName, pageNo):
 
252
            #naming scheme works within a directory only
 
253
            dirname, filename = os.path.split(pdfFileName)
 
254
            root, ext = os.path.splitext(filename)
 
255
            return '%s_page%d' % (root, pageNo)
 
256
 
 
257
 
 
258
        def needsProcessing(self, pdfFileName, pageNo):
 
259
            "returns 1 if no forms or form is older"
 
260
            formName = self.getFormName(pdfFileName, pageNo)
 
261
            if os.path.exists(formName + '.frm'):
 
262
                formModTime = os.stat(formName + '.frm')[8]
 
263
                pdfModTime = os.stat(pdfFileName)[8]
 
264
                return (pdfModTime > formModTime)
 
265
            else:
 
266
                return 1
 
267
 
 
268
        def processPDF(self, pdfFileName, pageNo):
 
269
            formName = self.getFormName(pdfFileName, pageNo)
 
270
            storeForms(pdfFileName, formName + '.frm',
 
271
                                    prefix= formName + '_',
 
272
                                    pagenumbers=[pageNo])
 
273
            #print 'stored %s.frm' % formName
 
274
            return formName + '.frm'
 
275
 
 
276
    class cachePageCatcherFigureNonA4(FlexFigure, PageCatcherCachingMixIn):
 
277
        """PageCatcher page with a caption below it.  Size to be supplied."""
 
278
        # This should merge with PageFigure into one class that reuses
 
279
        # form information to determine the page orientation...
 
280
        def __init__(self, filename, pageNo, caption, width, height, background=None):
 
281
            self.dirname, self.filename = os.path.split(filename)
 
282
            if self.dirname == '':
 
283
                self.dirname = os.curdir
 
284
            self.pageNo = pageNo
 
285
            self.formName = self.getFormName(self.filename, self.pageNo) + '_' + str(pageNo)
 
286
            FlexFigure.__init__(self, width, height, caption, background)
 
287
 
 
288
        def drawFigure(self):
 
289
            self.canv.saveState()
 
290
            if not self.canv.hasForm(self.formName):
 
291
                restorePath = self.dirname + os.sep + self.filename
 
292
                #does the form file exist?  if not, generate it.
 
293
                formFileName = self.getFormName(restorePath, self.pageNo) + '.frm'
 
294
                if self.needsProcessing(restorePath, self.pageNo):
 
295
                    #print 'preprocessing PDF %s page %s' % (restorePath, self.pageNo)
 
296
                    self.processPDF(restorePath, self.pageNo)
 
297
                names = restoreForms(formFileName, self.canv)
 
298
            self.canv.scale(self._scaleFactor, self._scaleFactor)
 
299
            self.canv.doForm(self.formName)
 
300
            self.canv.restoreState()
 
301
 
 
302
    class cachePageCatcherFigure(cachePageCatcherFigureNonA4):
 
303
        """PageCatcher page with a caption below it.  Presumes A4, Portrait.
 
304
        This needs our commercial PageCatcher product, or you'll get a blank."""
 
305
        def __init__(self, filename, pageNo, caption, width=595, height=842, background=None):
 
306
            cachePageCatcherFigureNonA4.__init__(self, filename, pageNo, caption, width, height, background=background)
 
307
 
 
308
    class PageCatcherFigureNonA4(FlexFigure):
 
309
        """PageCatcher page with a caption below it.  Size to be supplied."""
 
310
        # This should merge with PageFigure into one class that reuses
 
311
        # form information to determine the page orientation...
 
312
        _cache = {}
 
313
        def __init__(self, filename, pageNo, caption, width, height, background=None, caching=None):
 
314
            fn = self.filename = filename
 
315
            self.pageNo = pageNo
 
316
            fn = fn.replace(os.sep,'_').replace('/','_').replace('\\','_').replace('-','_').replace(':','_')
 
317
            self.prefix = fn.replace('.','_')+'_'+str(pageNo)+'_'
 
318
            self.formName = self.prefix + str(pageNo)
 
319
            self.caching = caching
 
320
            FlexFigure.__init__(self, width, height, caption, background)
 
321
 
 
322
        def drawFigure(self):
 
323
            if not self.canv.hasForm(self.formName):
 
324
                if self.filename in self._cache:
 
325
                    f,data = self._cache[self.filename]
 
326
                else:
 
327
                    f = open(self.filename,'rb')
 
328
                    pdf = f.read()
 
329
                    f.close()
 
330
                    f, data = storeFormsInMemory(pdf, pagenumbers=[self.pageNo], prefix=self.prefix)
 
331
                    if self.caching=='memory':
 
332
                        self._cache[self.filename] = f, data
 
333
                f = restoreFormsInMemory(data, self.canv)
 
334
            self.canv.saveState()
 
335
            self.canv.scale(self._scaleFactor, self._scaleFactor)
 
336
            self.canv.doForm(self.formName)
 
337
            self.canv.restoreState()
 
338
 
 
339
    class PageCatcherFigure(PageCatcherFigureNonA4):
 
340
        """PageCatcher page with a caption below it.  Presumes A4, Portrait.
 
341
        This needs our commercial PageCatcher product, or you'll get a blank."""
 
342
        def __init__(self, filename, pageNo, caption, width=595, height=842, background=None, caching=None):
 
343
            PageCatcherFigureNonA4.__init__(self, filename, pageNo, caption, width, height, background=background, caching=caching)
 
344
 
 
345
def demo1(canvas):
 
346
    frame = Frame(
 
347
                    2*inch,     # x
 
348
                    4*inch,     # y at bottom
 
349
                    4*inch,     # width
 
350
                    5*inch,     # height
 
351
                    showBoundary = 1  # helps us see what's going on
 
352
                    )
 
353
    bodyStyle = ParagraphStyle('Body', fontName='Times-Roman', fontSize=24, leading=28, spaceBefore=6)
 
354
    para1 = Paragraph('Spam spam spam spam. ' * 5, bodyStyle)
 
355
    para2 = Paragraph('Eggs eggs eggs. ' * 5, bodyStyle)
 
356
    mydata = [para1, para2]
 
357
 
 
358
    #this does the packing and drawing.  The frame will consume
 
359
    #items from the front of the list as it prints them
 
360
    frame.addFromList(mydata,canvas)
 
361
 
 
362
def test1():
 
363
    c  = Canvas('figures.pdf')
 
364
    f = Frame(inch, inch, 6*inch, 9*inch, showBoundary=1)
 
365
    v = PlatPropFigure1()
 
366
    v.captionTextColor = toColor('blue')
 
367
    v.captionBackColor = toColor('lightyellow')
 
368
    f.addFromList([v],c)
 
369
    c.save()
 
370
 
 
371
if __name__ == '__main__':
 
372
    test1()