~ubuntu-branches/debian/jessie/python-uniconvertor/jessie

« back to all changes in this revision

Viewing changes to src/app/plugins/Filters/pdfgensaver.py

  • Committer: Bazaar Package Importer
  • Author(s): Andreas Wenning
  • Date: 2008-11-21 14:32:49 UTC
  • mfrom: (2.1.2 jaunty)
  • Revision ID: james.westby@ubuntu.com-20081121143249-1fdezrq6kyov91kv
Tags: 1.1.3-4
Add 04_no_exit_on_import.dpatch to prevent uniconvertor from calling
sys.exit() on import exiting the python interpreter. (LP: #300141)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- coding: utf-8 -*-
 
2
 
 
3
# Copyright (C) 2007-2008 by Igor Novikov
 
4
# Copyright (C) 2000, 2001, 2002 by Bernhard Herzog
 
5
#
 
6
# This library is free software; you can redistribute it and/or
 
7
# modify it under the terms of the GNU Library General Public
 
8
# License as published by the Free Software Foundation; either
 
9
# version 2 of the License, or (at your option) any later version.
 
10
#
 
11
# This library is distributed in the hope that it will be useful,
 
12
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
14
# Library General Public License for more details.
 
15
#
 
16
# You should have received a copy of the GNU Library General Public
 
17
# License along with this library; if not, write to the Free Software
 
18
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
19
 
 
20
###Sketch Config
 
21
#type = Export
 
22
#tk_file_type = ("Portable Document Format (PDF)", '.pdf')
 
23
#extensions = '.pdf'
 
24
#format_name = 'PDF-Reportlab'
 
25
#unload = 1
 
26
###End
 
27
 
 
28
from math import atan2, pi
 
29
import PIL
 
30
from app import _,Bezier, EmptyPattern, Rotation, Translation, _sketch
 
31
from app.Graphics.curveop import arrow_trafos
 
32
import reportlab.pdfgen.canvas
 
33
import app
 
34
 
 
35
 
 
36
def make_pdf_path(pdfpath, paths):
 
37
        for path in paths:
 
38
                for i in range(path.len):
 
39
                        type, control, p, cont = path.Segment(i)
 
40
                        if type == Bezier:
 
41
                                p1, p2 = control
 
42
                                pdfpath.curveTo(p1.x, p1.y, p2.x, p2.y, p.x, p.y)
 
43
                        else:
 
44
                                if i > 0:
 
45
                                        pdfpath.lineTo(p.x, p.y)
 
46
                                else:
 
47
                                        pdfpath.moveTo(p.x, p.y)
 
48
                if path.closed:
 
49
                        pdfpath.close()
 
50
        return pdfpath
 
51
 
 
52
class PDFDevice:
 
53
 
 
54
        has_axial_gradient = 0
 
55
        has_radial_gradient = 0
 
56
        has_conical_gradient = 0
 
57
        gradient_steps = 100
 
58
 
 
59
        def __init__(self, pdf):
 
60
                self.pdf = pdf
 
61
 
 
62
        def PushTrafo(self):
 
63
                self.pdf.saveState()
 
64
 
 
65
        def Concat(self, trafo):
 
66
                apply(self.pdf.transform, trafo.coeff())
 
67
 
 
68
        def Translate(self, x, y = None):
 
69
                if y is None:
 
70
                        x, y = x
 
71
                self.pdf.translate(x, y)
 
72
 
 
73
        def Rotate(self, angle):
 
74
                self.pdf.rotate(angle)
 
75
 
 
76
        def Scale(self, scale):
 
77
                self.pdf.scale(scale, scale)
 
78
        
 
79
        def PopTrafo(self):
 
80
                self.pdf.restoreState()
 
81
 
 
82
        PushClip = PushTrafo
 
83
        PopClip = PopTrafo
 
84
 
 
85
        def SetFillColor(self, color):
 
86
                self.pdf.setFillColor(tuple(color))
 
87
 
 
88
        def SetLineColor(self, color):
 
89
                self.pdf.setStrokeColor(tuple(color))
 
90
 
 
91
        def SetLineAttributes(self, width, cap = 1, join = 0, dashes = ()):
 
92
                self.pdf.setLineWidth(width)
 
93
                self.pdf.setLineCap(cap - 1)
 
94
                self.pdf.setLineJoin(join)
 
95
                if dashes:
 
96
                        dashes = list(dashes)
 
97
                        w = width
 
98
                        if w < 1.0:
 
99
                                w = 1.0
 
100
                        for i in range(len(dashes)):
 
101
                                dashes[i] = w * dashes[i]
 
102
                self.pdf.setDash(dashes)
 
103
 
 
104
        def DrawLine(self, start, end):
 
105
                self.pdf.line(start.x, start.y, end.x, end.y)
 
106
 
 
107
        def DrawLineXY(self, x1, y1, x2, y2):
 
108
                self.pdf.line(x1, y1, x2, y2)
 
109
 
 
110
        def DrawRectangle(self, start, end):
 
111
                self.pdf.rectangle(start.x, start.y, end.x - start.x, end.y - start.y, 
 
112
                                                   1, 0)
 
113
 
 
114
        def FillRectangle(self, left, bottom, right, top):
 
115
                self.pdf.rect(left, bottom, right - left, top - bottom, 0, 1)
 
116
 
 
117
        def DrawCircle(self, center, radius):
 
118
                self.pdf.circle(center.x, center.y, radius, 1, 0)
 
119
 
 
120
        def FillCircle(self, center, radius):
 
121
                self.pdf.circle(center.x, center.y, radius, 0, 1)
 
122
 
 
123
        def FillPolygon(self, pts):
 
124
                path = self.pdf.beginPath()
 
125
                apply(path.moveTo, pts[0])
 
126
                for x, y in pts:
 
127
                        path.lineTo(x, y)
 
128
                path.close()
 
129
                self.pdf.drawPath(path, 0, 1)
 
130
 
 
131
        def DrawBezierPath(self, path, rect = None):
 
132
                self.pdf.drawPath(make_pdf_path(self.pdf.beginPath(), (path,)), 1, 0)
 
133
 
 
134
        def FillBezierPath(self, path, rect = None):
 
135
                self.pdf.drawPath(make_pdf_path(self.pdf.beginPath(), (path,)), 0, 1)
 
136
 
 
137
 
 
138
 
 
139
class PDFGenSaver:
 
140
 
 
141
        def __init__(self, file, filename, document, options):
 
142
                self.file = file
 
143
                self.filename = filename
 
144
                self.document = document
 
145
                self.options = options
 
146
 
 
147
                # if there's a pdfgen_canvas option assume it's an instance of
 
148
                # reportlab.pdfgen.canvas.Canvas that we should render on. This
 
149
                # allows multiple documents to be rendered into the same PDF
 
150
                # file or to have other python code outside of Sketch such as
 
151
                # reportlab itself (more precisely one of its other components
 
152
                # besides pdfgen) render into to too.
 
153
                #
 
154
                # The code here assumes that the canvas is already setup
 
155
                # properly.
 
156
                if options.has_key("pdfgen_canvas"):
 
157
                        self.pdf = options["pdfgen_canvas"]
 
158
                else:
 
159
                        self.pdf = reportlab.pdfgen.canvas.Canvas(file)
 
160
                        self.pdf.setPageSize(document.PageSize())
 
161
 
 
162
        def close(self):
 
163
                if not self.options.has_key("pdfgen_canvas"):
 
164
                        self.pdf.save()
 
165
 
 
166
        def set_properties(self, properties, bounding_rect = None):
 
167
                pattern = properties.line_pattern
 
168
                if not pattern.is_Empty:
 
169
                        if pattern.is_Solid:
 
170
                                c, m, y, k =pattern.Color().getCMYK()
 
171
                                self.pdf.setStrokeColorCMYK(c, m, y, k)
 
172
                        self.pdf.setLineWidth(properties.line_width)
 
173
                        self.pdf.setLineJoin(properties.line_join)
 
174
                        self.pdf.setLineCap(properties.line_cap - 1)
 
175
                        dashes = properties.line_dashes
 
176
                        if dashes:
 
177
                                dashes = list(dashes)
 
178
                                w = properties.line_width
 
179
                                if w < 1.0:
 
180
                                        w = 1.0
 
181
                                for i in range(len(dashes)):
 
182
                                        dashes[i] = w * dashes[i]
 
183
                        self.pdf.setDash(dashes)
 
184
                active_fill = None
 
185
                pattern = properties.fill_pattern
 
186
                if not pattern.is_Empty:
 
187
                        if pattern.is_Solid:
 
188
                                c, m, y, k =pattern.Color().getCMYK()
 
189
                                self.pdf.setFillColorCMYK(c, m, y, k)
 
190
                        elif pattern.is_Tiled:
 
191
                                pass
 
192
                        elif pattern.is_AxialGradient:
 
193
                                active_fill = self.axial_gradient
 
194
                        else:
 
195
                                active_fill = self.execute_pattern
 
196
                return active_fill
 
197
 
 
198
        def axial_gradient(self, properties, rect):
 
199
                pattern = properties.fill_pattern
 
200
                vx, vy = pattern.Direction()
 
201
                angle = atan2(vy, vx) - pi / 2
 
202
                center = rect.center()
 
203
                rot = Rotation(angle, center)
 
204
                left, bottom, right, top = rot(rect)
 
205
                trafo = rot(Translation(center))
 
206
                image = PIL.Image.new('RGB', (1, 200))
 
207
                border = int(round(100 * pattern.Border()))
 
208
                _sketch.fill_axial_gradient(image.im, pattern.Gradient().Colors(), 
 
209
                                                                        0, border, 0, 200 - border)
 
210
                self.pdf.saveState()
 
211
                apply(self.pdf.transform, trafo.coeff())
 
212
                self.pdf.drawInlineImage(image, (left - right) / 2, (bottom - top) / 2, 
 
213
                                                                 right - left, top - bottom)
 
214
                self.pdf.restoreState()
 
215
 
 
216
        def execute_pattern(self, properties, rect):
 
217
                device = PDFDevice(self.pdf)
 
218
                properties.fill_pattern.Execute(device, rect)
 
219
 
 
220
        def make_pdf_path(self, paths):
 
221
                return make_pdf_path(self.pdf.beginPath(), paths)
 
222
 
 
223
        def polybezier(self, paths, properties, bounding_rect, clip = 0):
 
224
                pdfpath = self.make_pdf_path(paths)
 
225
                active_fill = self.set_properties(properties, bounding_rect)
 
226
                if active_fill:
 
227
                        if not clip:
 
228
                                self.pdf.saveState()
 
229
                        self.pdf.clipPath(pdfpath, 0, 0)
 
230
                        active_fill(properties, bounding_rect)
 
231
                        if not clip:
 
232
                                self.pdf.restoreState()
 
233
                        if properties.HasLine():
 
234
                                self.pdf.drawPath(pdfpath, 1, 0)
 
235
                else:
 
236
                        if clip:
 
237
                                method = self.pdf.clipPath
 
238
                        else:
 
239
                                method = self.pdf.drawPath
 
240
                        method(self.make_pdf_path(paths), properties.HasLine(), 
 
241
                                   properties.HasFill())
 
242
                # draw the arrows
 
243
                if properties.HasLine():
 
244
                        # Set the pdf fill color to the line color to make sure that
 
245
                        # arrows that are filled are filled with the line color of
 
246
                        # the object. Since lines are always drawn last, this
 
247
                        # shouldn't interfere with the object's fill.
 
248
                        c, m, y, k = properties.line_pattern.Color().getCMYK()
 
249
                        self.pdf.setFillColorCMYK(c, m, y, k)
 
250
                        arrow1 = properties.line_arrow1
 
251
                        arrow2 = properties.line_arrow2
 
252
                        if arrow1 or arrow2:
 
253
                                for path in paths:
 
254
                                        t1, t2 = arrow_trafos(path, properties)
 
255
                                        if arrow1 and t1 is not None:
 
256
                                                self.draw_arrow(arrow1, t1)
 
257
                                        if arrow2 and t2 is not None:
 
258
                                                self.draw_arrow(arrow2, t2)
 
259
                                        
 
260
        def draw_arrow(self, arrow, trafo):
 
261
                path = arrow.Paths()[0].Duplicate()
 
262
                path.Transform(trafo)
 
263
                pdfpath = self.make_pdf_path((path,))
 
264
                if arrow.IsFilled():
 
265
                        self.pdf.drawPath(pdfpath, 0, 1)
 
266
                else:
 
267
                        self.pdf.drawPath(pdfpath, 1, 0)
 
268
 
 
269
        def mask_group(self, object):
 
270
                mask = object.Mask()
 
271
                if not mask.has_properties:
 
272
                        # XXX implement this case (raster images)
 
273
                        return
 
274
                if mask.is_curve:
 
275
                        self.pdf.saveState()
 
276
                        prop = mask.Properties().Duplicate()
 
277
                        prop.SetProperty(line_pattern = EmptyPattern)
 
278
                        self.polybezier(mask.Paths(), prop, mask.bounding_rect, clip = 1)
 
279
                        self.save_objects(object.MaskedObjects())
 
280
                        if mask.has_line and mask.Properties().HasLine():
 
281
                                prop = mask.Properties().Duplicate()
 
282
                                prop.SetProperty(fill_pattern = EmptyPattern)
 
283
                                self.polybezier(mask.Paths(), prop, mask.bounding_rect, 
 
284
                                                                clip = 1)
 
285
                        self.pdf.restoreState()
 
286
 
 
287
        def raster_image(self, object):
 
288
                self.pdf.saveState()
 
289
                apply(self.pdf.transform, object.Trafo().coeff())
 
290
                self.pdf.drawInlineImage(object.Data().Image(), 0, 0)
 
291
                self.pdf.restoreState()
 
292
 
 
293
        def simple_text(self, object, clip = 0):
 
294
                properties = object.Properties()
 
295
                active_fill = self.set_properties(properties, object.bounding_rect)
 
296
                fontname = properties.font.PostScriptName()
 
297
                if fontname not in self.pdf.getAvailableFonts():
 
298
                        fontname = 'Times-Roman'
 
299
 
 
300
                if active_fill and not clip:
 
301
                        self.pdf.saveState()
 
302
                pdftext = self.pdf.beginText()
 
303
                if active_fill:
 
304
                        pdftext.setTextRenderMode(7)
 
305
                elif clip:
 
306
                        pdftext.setTextRenderMode(4)
 
307
                pdftext.setFont(fontname, properties.font_size)
 
308
                apply(pdftext.setTextTransform, object.FullTrafo().coeff())
 
309
                pdftext.textOut(object.Text())
 
310
                self.pdf.drawText(pdftext)
 
311
                if active_fill:
 
312
                        active_fill(properties, object.bounding_rect)
 
313
                        if not clip:
 
314
                                self.pdf.restoreState()
 
315
 
 
316
        def path_text(self, object, clip = 0):
 
317
                properties = object.Properties()
 
318
                active_fill = self.set_properties(properties, object.bounding_rect)
 
319
                fontname = properties.font.PostScriptName()
 
320
                if fontname not in self.pdf.getAvailableFonts():
 
321
                        fontname = 'Times-Roman'
 
322
 
 
323
                if active_fill and not clip:
 
324
                        self.pdf.saveState()
 
325
                pdftext = self.pdf.beginText()
 
326
                if active_fill:
 
327
                        pdftext.setTextRenderMode(7)
 
328
                elif clip:
 
329
                        pdftext.setTextRenderMode(4)
 
330
                pdftext.setFont(fontname, properties.font_size)
 
331
                trafos = object.CharacterTransformations()
 
332
                text = object.Text()
 
333
                for i in range(len(trafos)):
 
334
                        apply(pdftext.setTextTransform, trafos[i].coeff())
 
335
                        pdftext.textOut(text[i])
 
336
                self.pdf.drawText(pdftext)
 
337
                if active_fill:
 
338
                        active_fill(properties, object.bounding_rect)
 
339
                        if not clip:
 
340
                                self.pdf.restoreState()
 
341
 
 
342
        def Save(self):
 
343
                self.document.updateActivePage()
 
344
                masters=self.document.getMasterLayers()
 
345
                count=0
 
346
                pagenum=len(self.document.pages)
 
347
                interval=int(97/pagenum)
 
348
                for page in self.document.pages:
 
349
                        count+=1
 
350
                        app.updateInfo(inf2=_('Composing page %u of %u')%(count,pagenum),inf3=count*interval)
 
351
                        layers=page+masters
 
352
                        for layer in layers:
 
353
                                if not layer.is_SpecialLayer and layer.Printable():
 
354
                                        self.save_objects(layer.GetObjects())
 
355
                        self.pdf.showPage()
 
356
 
 
357
        def save_objects(self, objects):
 
358
                for object in objects:
 
359
                        if object.is_Compound:
 
360
                                if object.is_MaskGroup:
 
361
                                        self.mask_group(object)
 
362
                                else:
 
363
                                        self.save_objects(object.GetObjects())
 
364
                        elif object.is_SimpleText:
 
365
#                               self.simple_text(object)
 
366
                                obj=object.AsBezier()
 
367
                                self.polybezier(obj.Paths(), obj.Properties(), obj.bounding_rect)
 
368
                        elif object.is_PathTextText:
 
369
                                self.path_text(object)                          
 
370
                        elif object.is_Image:
 
371
                                self.raster_image(object)
 
372
                        elif object.is_Bezier or object.is_Rectangle or object.is_Ellipse:
 
373
                                self.polybezier(object.Paths(), object.Properties(), object.bounding_rect)
 
374
 
 
375
 
 
376
 
 
377
def save(document, file, filename, options = {}):
 
378
        app.updateInfo(inf1=_('PDF generation.'),inf2=_('Start document composing'),inf3=3)
 
379
        saver = PDFGenSaver(file, filename, document, options)
 
380
        saver.Save()
 
381
        saver.close()
 
382
        app.updateInfo(inf2=_('Document generation is finished'),inf3=100)