QScintilla/Exporters/ExporterPDF.py

branch
Py2 comp.
changeset 3057
10516539f238
parent 2525
8b507a9a2d40
parent 3011
18292228c724
child 3060
5883ce99ee12
equal deleted inserted replaced
3056:9986ec0e559a 3057:10516539f238
28 PDF_MARGIN_DEFAULT = 72 # 1.0" 28 PDF_MARGIN_DEFAULT = 72 # 1.0"
29 PDF_ENCODING = "WinAnsiEncoding" 29 PDF_ENCODING = "WinAnsiEncoding"
30 30
31 PDFfontNames = [ 31 PDFfontNames = [
32 "Courier", "Courier-Bold", "Courier-Oblique", "Courier-BoldOblique", 32 "Courier", "Courier-Bold", "Courier-Oblique", "Courier-BoldOblique",
33 "Helvetica", "Helvetica-Bold", "Helvetica-Oblique", "Helvetica-BoldOblique", 33 "Helvetica", "Helvetica-Bold", "Helvetica-Oblique",
34 "Times-Roman", "Times-Bold", "Times-Italic", "Times-BoldItalic" 34 "Helvetica-BoldOblique", "Times-Roman", "Times-Bold", "Times-Italic",
35 "Times-BoldItalic"
35 ] 36 ]
36 PDFfontAscenders = [629, 718, 699] 37 PDFfontAscenders = [629, 718, 699]
37 PDFfontDescenders = [157, 207, 217] 38 PDFfontDescenders = [157, 207, 217]
38 PDFfontWidths = [600, 0, 0] 39 PDFfontWidths = [600, 0, 0]
39 40
56 self.font = 0 57 self.font = 0
57 58
58 59
59 class PDFObjectTracker(object): 60 class PDFObjectTracker(object):
60 """ 61 """
61 Class to conveniently handle the tracking of PDF objects 62 Class to conveniently handle the tracking of PDF objects so that the
62 so that the cross-reference table can be built (PDF1.4Ref(p39)) 63 cross-reference table can be built (PDF1.4Ref(p39)).
64
63 All writes to the file are passed through a PDFObjectTracker object. 65 All writes to the file are passed through a PDFObjectTracker object.
64 """ 66 """
65 def __init__(self, file): 67 def __init__(self, file):
66 """ 68 """
67 Constructor 69 Constructor
155 157
156 def fontToPoints(self, thousandths): 158 def fontToPoints(self, thousandths):
157 """ 159 """
158 Public method to convert the font size to points. 160 Public method to convert the font size to points.
159 161
162 @param thousandths font size (integer)
160 @return point size of the font (integer) 163 @return point size of the font (integer)
161 """ 164 """
162 return self.fontSize * thousandths / 1000.0 165 return self.fontSize * thousandths / 1000.0
163 166
164 def setStyle(self, style_): 167 def setStyle(self, style_):
172 if style_ == -1: 175 if style_ == -1:
173 styleNext = self.styleCurrent 176 styleNext = self.styleCurrent
174 177
175 buf = "" 178 buf = ""
176 if styleNext != self.styleCurrent or style_ == -1: 179 if styleNext != self.styleCurrent or style_ == -1:
177 if self.style[self.styleCurrent].font != self.style[styleNext].font or \ 180 if self.style[self.styleCurrent].font != \
178 style_ == -1: 181 self.style[styleNext].font or style_ == -1:
179 buf += "/F{0:d} {1:d} Tf ".format(self.style[styleNext].font + 1, 182 buf += "/F{0:d} {1:d} Tf ".format(
180 self.fontSize) 183 self.style[styleNext].font + 1, self.fontSize)
181 if self.style[self.styleCurrent].fore != self.style[styleNext].fore or \ 184 if self.style[self.styleCurrent].fore != \
182 style_ == -1: 185 self.style[styleNext].fore or style_ == -1:
183 buf += "{0}rg ".format(self.style[styleNext].fore) 186 buf += "{0}rg ".format(self.style[styleNext].fore)
184 return buf 187 return buf
185 188
186 def startPDF(self): 189 def startPDF(self):
187 """ 190 """
211 # build objects for font resources; note that font objects are 214 # build objects for font resources; note that font objects are
212 # *expected* to start from index 1 since they are the first objects 215 # *expected* to start from index 1 since they are the first objects
213 # to be inserted (PDF1.4Ref(p317)) 216 # to be inserted (PDF1.4Ref(p317))
214 for i in range(4): 217 for i in range(4):
215 buffer = \ 218 buffer = \
216 "<</Type/Font/Subtype/Type1/Name/F{0:d}/BaseFont/{1}/Encoding/{2}>>\n"\ 219 "<</Type/Font/Subtype/Type1/Name/F{0:d}/BaseFont/{1}/" \
217 .format(i + 1, PDFfontNames[self.fontSet * 4 + i], PDF_ENCODING) 220 "Encoding/{2}>>\n".format(
221 i + 1, PDFfontNames[self.fontSet * 4 + i], PDF_ENCODING)
218 self.oT.add(buffer) 222 self.oT.add(buffer)
219 223
220 self.pageContentStart = self.oT.index 224 self.pageContentStart = self.oT.index
221 225
222 def endPDF(self): 226 def endPDF(self):
227 # flush buffers 231 # flush buffers
228 self.endPage() 232 self.endPage()
229 233
230 # refer to all used or unused fonts for simplicity 234 # refer to all used or unused fonts for simplicity
231 resourceRef = self.oT.add( 235 resourceRef = self.oT.add(
232 "<</ProcSet[/PDF/Text]\n/Font<</F1 1 0 R/F2 2 0 R/F3 3 0 R/F4 4 0 R>> >>\n") 236 "<</ProcSet[/PDF/Text]\n/Font<</F1 1 0 R/F2 2 0 R/F3 3 0 R/"
237 "F4 4 0 R>> >>\n")
233 238
234 # create all the page objects (PDF1.4Ref(p88)) 239 # create all the page objects (PDF1.4Ref(p88))
235 # forward reference pages object; calculate its object number 240 # forward reference pages object; calculate its object number
236 pageObjectStart = self.oT.index 241 pageObjectStart = self.oT.index
237 pagesRef = pageObjectStart + self.pageCount 242 pagesRef = pageObjectStart + self.pageCount
257 262
258 # append the cross reference table (PDF1.4Ref(p64)) 263 # append the cross reference table (PDF1.4Ref(p64))
259 xref = self.oT.xref() 264 xref = self.oT.xref()
260 265
261 # end the file with the trailer (PDF1.4Ref(p67)) 266 # end the file with the trailer (PDF1.4Ref(p67))
262 buffer = "trailer\n<< /Size {0:d} /Root {1:d} 0 R\n>>\nstartxref\n{2:d}\n%%EOF\n"\ 267 buffer = \
263 .format(self.oT.index, catalogRef, xref) 268 "trailer\n<< /Size {0:d} /Root {1:d} 0 R\n>>\nstartxref\n{2:d}\n" \
269 "%%EOF\n".format(self.oT.index, catalogRef, xref)
264 self.oT.write(buffer) 270 self.oT.write(buffer)
265 271
266 def add(self, ch, style_): 272 def add(self, ch, style_):
267 """ 273 """
268 Public method to add a character to the page. 274 Public method to add a character to the page.
423 tabSize = Preferences.getEditor("TabWidth") 429 tabSize = Preferences.getEditor("TabWidth")
424 if tabSize == 0: 430 if tabSize == 0:
425 tabSize = 4 431 tabSize = 4
426 432
427 # get magnification value to add to default screen font size 433 # get magnification value to add to default screen font size
428 self.pr.fontSize = Preferences.getEditorExporter("PDF/Magnification") 434 self.pr.fontSize = Preferences.getEditorExporter(
435 "PDF/Magnification")
429 436
430 # set font family according to face name 437 # set font family according to face name
431 fontName = Preferences.getEditorExporter("PDF/Font") 438 fontName = Preferences.getEditorExporter("PDF/Font")
432 self.pr.fontSet = PDF_FONT_DEFAULT 439 self.pr.fontSet = PDF_FONT_DEFAULT
433 if fontName == "Courier": 440 if fontName == "Courier":
519 else: 526 else:
520 self.pr.fontSize = PDF_FONTSIZE_DEFAULT 527 self.pr.fontSize = PDF_FONTSIZE_DEFAULT
521 528
522 try: 529 try:
523 # save file in win ansi using cp1250 530 # save file in win ansi using cp1250
524 f = open(filename, "w", encoding="cp1250", errors="backslashreplace") 531 f = open(filename, "w", encoding="cp1250",
532 errors="backslashreplace")
525 533
526 # initialise PDF rendering 534 # initialise PDF rendering
527 ot = PDFObjectTracker(f) 535 ot = PDFObjectTracker(f)
528 self.pr.oT = ot 536 self.pr.oT = ot
529 self.pr.startPDF() 537 self.pr.startPDF()
548 # expand tabs 556 # expand tabs
549 ts = tabSize - (column % tabSize) 557 ts = tabSize - (column % tabSize)
550 column += ts 558 column += ts
551 self.pr.add(' ' * ts, style) 559 self.pr.add(' ' * ts, style)
552 elif ch == b'\r' or ch == b'\n': 560 elif ch == b'\r' or ch == b'\n':
553 if ch == b'\r' and self.editor.byteAt(pos + 1) == b'\n': 561 if ch == b'\r' and \
562 self.editor.byteAt(pos + 1) == b'\n':
554 pos += 1 563 pos += 1
555 # close and begin a newline... 564 # close and begin a newline...
556 self.pr.nextLine() 565 self.pr.nextLine()
557 column = 0 566 column = 0
558 else: 567 else:
564 utf8Len = 4 573 utf8Len = 4
565 elif (utf8Ch[0] & 0xE0) == 0xE0: 574 elif (utf8Ch[0] & 0xE0) == 0xE0:
566 utf8Len = 3 575 utf8Len = 3
567 elif (utf8Ch[0] & 0xC0) == 0xC0: 576 elif (utf8Ch[0] & 0xC0) == 0xC0:
568 utf8Len = 2 577 utf8Len = 2
569 column -= 1 # will be incremented again later 578 column -= 1 # will be incremented
579 # again later
570 elif len(utf8Ch) == utf8Len: 580 elif len(utf8Ch) == utf8Len:
571 ch = utf8Ch.decode('utf8') 581 ch = utf8Ch.decode('utf8')
572 self.pr.add(ch, style) 582 self.pr.add(ch, style)
573 utf8Ch = b"" 583 utf8Ch = b""
574 utf8Len = 0 584 utf8Len = 0
575 else: 585 else:
576 column -= 1 # will be incremented again later 586 column -= 1 # will be incremented
587 # again later
577 else: 588 else:
578 self.pr.add(ch.decode(), style) 589 self.pr.add(ch.decode(), style)
579 column += 1 590 column += 1
580 591
581 pos += 1 592 pos += 1
583 # write required stuff and close the PDF file 594 # write required stuff and close the PDF file
584 self.pr.endPDF() 595 self.pr.endPDF()
585 f.close() 596 f.close()
586 except IOError as err: 597 except IOError as err:
587 QApplication.restoreOverrideCursor() 598 QApplication.restoreOverrideCursor()
588 E5MessageBox.critical(self.editor, 599 E5MessageBox.critical(
600 self.editor,
589 self.trUtf8("Export source"), 601 self.trUtf8("Export source"),
590 self.trUtf8( 602 self.trUtf8(
591 """<p>The source could not be exported to <b>{0}</b>.</p>""" 603 """<p>The source could not be exported to"""
592 """<p>Reason: {1}</p>""")\ 604 """ <b>{0}</b>.</p><p>Reason: {1}</p>""")\
593 .format(filename, str(err))) 605 .format(filename, str(err)))
594 finally: 606 finally:
595 QApplication.restoreOverrideCursor() 607 QApplication.restoreOverrideCursor()

eric ide

mercurial