QScintilla/Exporters/ExporterPDF.py

changeset 945
8cd4d08fa9f6
parent 791
9ec2ac20e54e
child 1112
8a7d1b9d18db
equal deleted inserted replaced
944:1b59c4ba121e 945:8cd4d08fa9f6
22 import Preferences 22 import Preferences
23 23
24 PDF_FONT_DEFAULT = 1 # Helvetica 24 PDF_FONT_DEFAULT = 1 # Helvetica
25 PDF_FONTSIZE_DEFAULT = 10 25 PDF_FONTSIZE_DEFAULT = 10
26 PDF_SPACING_DEFAULT = 1.2 26 PDF_SPACING_DEFAULT = 1.2
27 PDF_MARGIN_DEFAULT = 72 # 1.0" 27 PDF_MARGIN_DEFAULT = 72 # 1.0"
28 PDF_ENCODING = "WinAnsiEncoding" 28 PDF_ENCODING = "WinAnsiEncoding"
29 29
30 PDFfontNames = [ 30 PDFfontNames = [
31 "Courier", "Courier-Bold", "Courier-Oblique", "Courier-BoldOblique", 31 "Courier", "Courier-Bold", "Courier-Oblique", "Courier-BoldOblique",
32 "Helvetica", "Helvetica-Bold", "Helvetica-Oblique", "Helvetica-BoldOblique", 32 "Helvetica", "Helvetica-Bold", "Helvetica-Oblique", "Helvetica-BoldOblique",
33 "Times-Roman", "Times-Bold", "Times-Italic", "Times-BoldItalic" 33 "Times-Roman", "Times-Bold", "Times-Italic", "Times-BoldItalic"
34 ] 34 ]
35 PDFfontAscenders = [629, 718, 699] 35 PDFfontAscenders = [629, 718, 699]
36 PDFfontDescenders = [157, 207, 217] 36 PDFfontDescenders = [157, 207, 217]
37 PDFfontWidths = [600, 0, 0] 37 PDFfontWidths = [600, 0, 0]
38 38
39 PDFpageSizes = { 39 PDFpageSizes = {
40 # name : (height, width) 40 # name : (height, width)
41 "Letter" : (792, 612), 41 "Letter": (792, 612),
42 "A4" : (842, 595), 42 "A4": (842, 595),
43 } 43 }
44
44 45
45 class PDFStyle(object): 46 class PDFStyle(object):
46 """ 47 """
47 Simple class to store the values of a PDF style. 48 Simple class to store the values of a PDF style.
48 """ 49 """
50 """ 51 """
51 Constructor 52 Constructor
52 """ 53 """
53 self.fore = "" 54 self.fore = ""
54 self.font = 0 55 self.font = 0
56
55 57
56 class PDFObjectTracker(object): 58 class PDFObjectTracker(object):
57 """ 59 """
58 Class to conveniently handle the tracking of PDF objects 60 Class to conveniently handle the tracking of PDF objects
59 so that the cross-reference table can be built (PDF1.4Ref(p39)) 61 so that the cross-reference table can be built (PDF1.4Ref(p39))
112 while ind < len(self.offsetList): 114 while ind < len(self.offsetList):
113 self.write("{0:010d} 00000 n \n".format(self.offsetList[ind])) 115 self.write("{0:010d} 00000 n \n".format(self.offsetList[ind]))
114 ind += 1 116 ind += 1
115 return xrefStart 117 return xrefStart
116 118
119
117 class PDFRender(object): 120 class PDFRender(object):
118 """ 121 """
119 Class to manage line and page rendering. 122 Class to manage line and page rendering.
120 123
121 Apart from startPDF, endPDF everything goes in via add() and nextLine() 124 Apart from startPDF, endPDF everything goes in via add() and nextLine()
122 so that line formatting and pagination can be done properly. 125 so that line formatting and pagination can be done properly.
123 """ 126 """
124 def __init__(self): 127 def __init__(self):
131 self.pageData = "" 134 self.pageData = ""
132 self.style = {} 135 self.style = {}
133 self.segStyle = "" 136 self.segStyle = ""
134 self.segment = "" 137 self.segment = ""
135 self.pageMargins = { 138 self.pageMargins = {
136 "left" : 72, 139 "left": 72,
137 "right" : 72, 140 "right": 72,
138 "top" : 72, 141 "top": 72,
139 "bottom" : 72, 142 "bottom": 72,
140 } 143 }
141 self.fontSize = 0 144 self.fontSize = 0
142 self.fontSet = 0 145 self.fontSet = 0
143 self.leading = 0.0 146 self.leading = 0.0
144 self.pageWidth = 0 147 self.pageWidth = 0
170 173
171 buf = "" 174 buf = ""
172 if styleNext != self.styleCurrent or style_ == -1: 175 if styleNext != self.styleCurrent or style_ == -1:
173 if self.style[self.styleCurrent].font != self.style[styleNext].font or \ 176 if self.style[self.styleCurrent].font != self.style[styleNext].font or \
174 style_ == -1: 177 style_ == -1:
175 buf += "/F{0:d} {1:d} Tf ".format(self.style[styleNext].font + 1, 178 buf += "/F{0:d} {1:d} Tf ".format(self.style[styleNext].font + 1,
176 self.fontSize) 179 self.fontSize)
177 if self.style[self.styleCurrent].fore != self.style[styleNext].fore or \ 180 if self.style[self.styleCurrent].fore != self.style[styleNext].fore or \
178 style_ == -1: 181 style_ == -1:
179 buf += "{0}rg ".format(self.style[styleNext].fore) 182 buf += "{0}rg ".format(self.style[styleNext].fore)
180 return buf 183 return buf
234 for i in range(self.pageCount): 237 for i in range(self.pageCount):
235 buffer = "<</Type/Page/Parent {0:d} 0 R\n" \ 238 buffer = "<</Type/Page/Parent {0:d} 0 R\n" \
236 "/MediaBox[ 0 0 {1:d} {2:d}]\n" \ 239 "/MediaBox[ 0 0 {1:d} {2:d}]\n" \
237 "/Contents {3:d} 0 R\n" \ 240 "/Contents {3:d} 0 R\n" \
238 "/Resources {4:d} 0 R\n>>\n".format( 241 "/Resources {4:d} 0 R\n>>\n".format(
239 pagesRef, self.pageWidth, self.pageHeight, 242 pagesRef, self.pageWidth, self.pageHeight,
240 self.pageContentStart + i, resourceRef) 243 self.pageContentStart + i, resourceRef)
241 self.oT.add(buffer) 244 self.oT.add(buffer)
242 245
243 # create page tree object (PDF1.4Ref(p86)) 246 # create page tree object (PDF1.4Ref(p86))
244 self.pageData = "<</Type/Pages/Kids[\n" 247 self.pageData = "<</Type/Pages/Kids[\n"
289 # escape these characters 292 # escape these characters
290 if ch == ')' or ch == '(' or ch == '\\': 293 if ch == ')' or ch == '(' or ch == '\\':
291 self.segment += '\\' 294 self.segment += '\\'
292 if ch != ' ': 295 if ch != ' ':
293 self.justWhiteSpace = False 296 self.justWhiteSpace = False
294 self.segment += ch # add to segment data 297 self.segment += ch # add to segment data
295 298
296 def flushSegment(self): 299 def flushSegment(self):
297 """ 300 """
298 Public method to flush a segment of data. 301 Public method to flush a segment of data.
299 """ 302 """
367 self.firstLine = False 370 self.firstLine = False
368 else: 371 else:
369 buffer = "T*\n" 372 buffer = "T*\n"
370 self.pageData += buffer 373 self.pageData += buffer
371 374
375
372 class ExporterPDF(ExporterBase): 376 class ExporterPDF(ExporterBase):
373 """ 377 """
374 Class implementing an exporter for PDF. 378 Class implementing an exporter for PDF.
375 """ 379 """
376 def __init__(self, editor, parent = None): 380 def __init__(self, editor, parent=None):
377 """ 381 """
378 Constructor 382 Constructor
379 383
380 @param editor reference to the editor object (QScintilla.Editor.Editor) 384 @param editor reference to the editor object (QScintilla.Editor.Editor)
381 @param parent parent object of the exporter (QObject) 385 @param parent parent object of the exporter (QObject)
430 elif fontName == "Helvetica": 434 elif fontName == "Helvetica":
431 self.pr.fontSet = 1 435 self.pr.fontSet = 1
432 elif fontName == "Times": 436 elif fontName == "Times":
433 self.pr.fontSet = 2 437 self.pr.fontSet = 2
434 438
435 # page size: height, width, 439 # page size: height, width,
436 pageSize = Preferences.getEditorExporter("PDF/PageSize") 440 pageSize = Preferences.getEditorExporter("PDF/PageSize")
437 try: 441 try:
438 pageDimensions = PDFpageSizes[pageSize] 442 pageDimensions = PDFpageSizes[pageSize]
439 except KeyError: 443 except KeyError:
440 pageDimensions = PDFpageSizes["A4"] 444 pageDimensions = PDFpageSizes["A4"]
514 else: 518 else:
515 self.pr.fontSize = PDF_FONTSIZE_DEFAULT 519 self.pr.fontSize = PDF_FONTSIZE_DEFAULT
516 520
517 try: 521 try:
518 # save file in win ansi using cp1250 522 # save file in win ansi using cp1250
519 f = open(filename, "w", encoding = "cp1250", errors = "backslashreplace") 523 f = open(filename, "w", encoding="cp1250", errors="backslashreplace")
520 524
521 # initialise PDF rendering 525 # initialise PDF rendering
522 ot = PDFObjectTracker(f) 526 ot = PDFObjectTracker(f)
523 self.pr.oT = ot 527 self.pr.oT = ot
524 self.pr.startPDF() 528 self.pr.startPDF()
525 529
526 # do here all the writing 530 # do here all the writing
527 lengthDoc = self.editor.length() 531 lengthDoc = self.editor.length()
528 532
529 if lengthDoc == 0: 533 if lengthDoc == 0:
530 self.pr.nextLine() # enable zero length docs 534 self.pr.nextLine() # enable zero length docs
531 else: 535 else:
532 pos = 0 536 pos = 0
533 column = 0 537 column = 0
534 utf8 = self.editor.isUtf8() 538 utf8 = self.editor.isUtf8()
535 utf8Ch = b"" 539 utf8Ch = b""
559 utf8Len = 4 563 utf8Len = 4
560 elif (utf8Ch[0] & 0xE0) == 0xE0: 564 elif (utf8Ch[0] & 0xE0) == 0xE0:
561 utf8Len = 3 565 utf8Len = 3
562 elif (utf8Ch[0] & 0xC0) == 0xC0: 566 elif (utf8Ch[0] & 0xC0) == 0xC0:
563 utf8Len = 2 567 utf8Len = 2
564 column -= 1 # will be incremented again later 568 column -= 1 # will be incremented again later
565 elif len(utf8Ch) == utf8Len: 569 elif len(utf8Ch) == utf8Len:
566 ch = utf8Ch.decode('utf8') 570 ch = utf8Ch.decode('utf8')
567 self.pr.add(ch, style) 571 self.pr.add(ch, style)
568 utf8Ch = b"" 572 utf8Ch = b""
569 utf8Len = 0 573 utf8Len = 0
570 else: 574 else:
571 column -= 1 # will be incremented again later 575 column -= 1 # will be incremented again later
572 else: 576 else:
573 self.pr.add(ch.decode(), style) 577 self.pr.add(ch.decode(), style)
574 column += 1 578 column += 1
575 579
576 pos += 1 580 pos += 1

eric ide

mercurial