18 |
18 |
19 from .ExporterBase import ExporterBase |
19 from .ExporterBase import ExporterBase |
20 |
20 |
21 import Preferences |
21 import Preferences |
22 |
22 |
23 PDF_FONT_DEFAULT = 1 # Helvetica |
23 PDF_FONT_DEFAULT = 1 # Helvetica |
24 PDF_FONTSIZE_DEFAULT = 10 |
24 PDF_FONTSIZE_DEFAULT = 10 |
25 PDF_SPACING_DEFAULT = 1.2 |
25 PDF_SPACING_DEFAULT = 1.2 |
26 PDF_MARGIN_DEFAULT = 72 # 1.0" |
26 PDF_MARGIN_DEFAULT = 72 # 1.0" |
27 PDF_ENCODING = "WinAnsiEncoding" |
27 PDF_ENCODING = "WinAnsiEncoding" |
28 |
28 |
29 PDFfontNames = [ |
29 PDFfontNames = [ |
30 "Courier", "Courier-Bold", "Courier-Oblique", "Courier-BoldOblique", |
30 "Courier", |
31 "Helvetica", "Helvetica-Bold", "Helvetica-Oblique", |
31 "Courier-Bold", |
32 "Helvetica-BoldOblique", "Times-Roman", "Times-Bold", "Times-Italic", |
32 "Courier-Oblique", |
33 "Times-BoldItalic" |
33 "Courier-BoldOblique", |
|
34 "Helvetica", |
|
35 "Helvetica-Bold", |
|
36 "Helvetica-Oblique", |
|
37 "Helvetica-BoldOblique", |
|
38 "Times-Roman", |
|
39 "Times-Bold", |
|
40 "Times-Italic", |
|
41 "Times-BoldItalic", |
34 ] |
42 ] |
35 PDFfontAscenders = [629, 718, 699] |
43 PDFfontAscenders = [629, 718, 699] |
36 PDFfontDescenders = [157, 207, 217] |
44 PDFfontDescenders = [157, 207, 217] |
37 PDFfontWidths = [600, 0, 0] |
45 PDFfontWidths = [600, 0, 0] |
38 |
46 |
39 PDFpageSizes = { |
47 PDFpageSizes = { |
40 #- name : (height, width) |
48 # - name : (height, width) |
41 "Letter": (792, 612), |
49 "Letter": (792, 612), |
42 "A4": (842, 595), |
50 "A4": (842, 595), |
43 } |
51 } |
44 |
52 |
45 |
53 |
46 class PDFStyle: |
54 class PDFStyle: |
47 """ |
55 """ |
48 Simple class to store the values of a PDF style. |
56 Simple class to store the values of a PDF style. |
49 """ |
57 """ |
|
58 |
50 def __init__(self): |
59 def __init__(self): |
51 """ |
60 """ |
52 Constructor |
61 Constructor |
53 """ |
62 """ |
54 self.fore = "" |
63 self.fore = "" |
57 |
66 |
58 class PDFObjectTracker: |
67 class PDFObjectTracker: |
59 """ |
68 """ |
60 Class to conveniently handle the tracking of PDF objects so that the |
69 Class to conveniently handle the tracking of PDF objects so that the |
61 cross-reference table can be built (PDF1.4Ref(p39)). |
70 cross-reference table can be built (PDF1.4Ref(p39)). |
62 |
71 |
63 All writes to the file are passed through a PDFObjectTracker object. |
72 All writes to the file are passed through a PDFObjectTracker object. |
64 """ |
73 """ |
|
74 |
65 def __init__(self, file): |
75 def __init__(self, file): |
66 """ |
76 """ |
67 Constructor |
77 Constructor |
68 |
78 |
69 @param file file object open for writing (file) |
79 @param file file object open for writing (file) |
70 """ |
80 """ |
71 self.file = file |
81 self.file = file |
72 self.offsetList = [] |
82 self.offsetList = [] |
73 self.index = 1 |
83 self.index = 1 |
74 |
84 |
75 def write(self, objectData): |
85 def write(self, objectData): |
76 """ |
86 """ |
77 Public method to write the data to the file. |
87 Public method to write the data to the file. |
78 |
88 |
79 @param objectData data to be written (integer or string) |
89 @param objectData data to be written (integer or string) |
80 """ |
90 """ |
81 if isinstance(objectData, int): |
91 if isinstance(objectData, int): |
82 self.file.write("{0:d}".format(objectData)) |
92 self.file.write("{0:d}".format(objectData)) |
83 else: |
93 else: |
84 self.file.write(objectData) |
94 self.file.write(objectData) |
85 |
95 |
86 def add(self, objectData): |
96 def add(self, objectData): |
87 """ |
97 """ |
88 Public method to add a new object. |
98 Public method to add a new object. |
89 |
99 |
90 @param objectData data to be added (integer or string) |
100 @param objectData data to be added (integer or string) |
91 @return object number assigned to the supplied data (integer) |
101 @return object number assigned to the supplied data (integer) |
92 """ |
102 """ |
93 self.offsetList.append(self.file.tell()) |
103 self.offsetList.append(self.file.tell()) |
94 self.write(self.index) |
104 self.write(self.index) |
150 self.pageContentStart = 0 |
161 self.pageContentStart = 0 |
151 self.xPos = 0.0 |
162 self.xPos = 0.0 |
152 self.yPos = 0.0 |
163 self.yPos = 0.0 |
153 self.justWhiteSpace = False |
164 self.justWhiteSpace = False |
154 self.oT = None |
165 self.oT = None |
155 |
166 |
156 def fontToPoints(self, thousandths): |
167 def fontToPoints(self, thousandths): |
157 """ |
168 """ |
158 Public method to convert the font size to points. |
169 Public method to convert the font size to points. |
159 |
170 |
160 @param thousandths font size (integer) |
171 @param thousandths font size (integer) |
161 @return point size of the font (integer) |
172 @return point size of the font (integer) |
162 """ |
173 """ |
163 return self.fontSize * thousandths / 1000.0 |
174 return self.fontSize * thousandths / 1000.0 |
164 |
175 |
165 def setStyle(self, style_): |
176 def setStyle(self, style_): |
166 """ |
177 """ |
167 Public method to set a style. |
178 Public method to set a style. |
168 |
179 |
169 @param style_ style to be set (integer) |
180 @param style_ style to be set (integer) |
170 @return the PDF string to set the given style (string) |
181 @return the PDF string to set the given style (string) |
171 """ |
182 """ |
172 styleNext = style_ |
183 styleNext = style_ |
173 if style_ == -1: |
184 if style_ == -1: |
174 styleNext = self.styleCurrent |
185 styleNext = self.styleCurrent |
175 |
186 |
176 buf = "" |
187 buf = "" |
177 if styleNext != self.styleCurrent or style_ == -1: |
188 if styleNext != self.styleCurrent or style_ == -1: |
178 if ( |
189 if ( |
179 (self.style[self.styleCurrent].font != |
190 self.style[self.styleCurrent].font != self.style[styleNext].font |
180 self.style[styleNext].font) or |
191 ) or style_ == -1: |
181 style_ == -1 |
|
182 ): |
|
183 buf += "/F{0:d} {1:d} Tf ".format( |
192 buf += "/F{0:d} {1:d} Tf ".format( |
184 self.style[styleNext].font + 1, self.fontSize) |
193 self.style[styleNext].font + 1, self.fontSize |
|
194 ) |
185 if ( |
195 if ( |
186 (self.style[self.styleCurrent].fore != |
196 self.style[self.styleCurrent].fore != self.style[styleNext].fore |
187 self.style[styleNext].fore) or |
197 ) or style_ == -1: |
188 style_ == -1 |
|
189 ): |
|
190 buf += "{0}rg ".format(self.style[styleNext].fore) |
198 buf += "{0}rg ".format(self.style[styleNext].fore) |
191 return buf |
199 return buf |
192 |
200 |
193 def startPDF(self): |
201 def startPDF(self): |
194 """ |
202 """ |
195 Public method to start the PDF document. |
203 Public method to start the PDF document. |
196 """ |
204 """ |
197 if self.fontSize <= 0: |
205 if self.fontSize <= 0: |
198 self.fontSize = PDF_FONTSIZE_DEFAULT |
206 self.fontSize = PDF_FONTSIZE_DEFAULT |
199 |
207 |
200 # leading is the term for distance between lines |
208 # leading is the term for distance between lines |
201 self.leading = self.fontSize * PDF_SPACING_DEFAULT |
209 self.leading = self.fontSize * PDF_SPACING_DEFAULT |
202 |
210 |
203 # sanity check for page size and margins |
211 # sanity check for page size and margins |
204 pageWidthMin = ( |
212 pageWidthMin = ( |
205 int(self.leading) + |
213 int(self.leading) + self.pageMargins["left"] + self.pageMargins["right"] |
206 self.pageMargins["left"] + |
|
207 self.pageMargins["right"] |
|
208 ) |
214 ) |
209 if self.pageWidth < pageWidthMin: |
215 if self.pageWidth < pageWidthMin: |
210 self.pageWidth = pageWidthMin |
216 self.pageWidth = pageWidthMin |
211 pageHeightMin = ( |
217 pageHeightMin = ( |
212 int(self.leading) + |
218 int(self.leading) + self.pageMargins["top"] + self.pageMargins["bottom"] |
213 self.pageMargins["top"] + |
|
214 self.pageMargins["bottom"] |
|
215 ) |
219 ) |
216 if self.pageHeight < pageHeightMin: |
220 if self.pageHeight < pageHeightMin: |
217 self.pageHeight = pageHeightMin |
221 self.pageHeight = pageHeightMin |
218 |
222 |
219 # start to write PDF file here (PDF1.4Ref(p63)) |
223 # start to write PDF file here (PDF1.4Ref(p63)) |
220 # ASCII>127 characters to indicate binary-possible stream |
224 # ASCII>127 characters to indicate binary-possible stream |
221 self.oT.write("%PDF-1.3\n%�쏢\n") |
225 self.oT.write("%PDF-1.3\n%�쏢\n") |
222 self.styleCurrent = QsciScintilla.STYLE_DEFAULT |
226 self.styleCurrent = QsciScintilla.STYLE_DEFAULT |
223 |
227 |
224 # build objects for font resources; note that font objects are |
228 # build objects for font resources; note that font objects are |
225 # *expected* to start from index 1 since they are the first objects |
229 # *expected* to start from index 1 since they are the first objects |
226 # to be inserted (PDF1.4Ref(p317)) |
230 # to be inserted (PDF1.4Ref(p317)) |
227 for i in range(4): |
231 for i in range(4): |
228 buffer = ( |
232 buffer = ( |
229 "<</Type/Font/Subtype/Type1/Name/F{0:d}/BaseFont/{1}/" |
233 "<</Type/Font/Subtype/Type1/Name/F{0:d}/BaseFont/{1}/" |
230 "Encoding/{2}>>\n" |
234 "Encoding/{2}>>\n" |
231 ).format( |
235 ).format(i + 1, PDFfontNames[self.fontSet * 4 + i], PDF_ENCODING) |
232 i + 1, PDFfontNames[self.fontSet * 4 + i], PDF_ENCODING |
|
233 ) |
|
234 self.oT.add(buffer) |
236 self.oT.add(buffer) |
235 |
237 |
236 self.pageContentStart = self.oT.index |
238 self.pageContentStart = self.oT.index |
237 |
239 |
238 def endPDF(self): |
240 def endPDF(self): |
239 """ |
241 """ |
240 Public method to end the PDF document. |
242 Public method to end the PDF document. |
241 """ |
243 """ |
242 if self.pageStarted: |
244 if self.pageStarted: |
243 # flush buffers |
245 # flush buffers |
244 self.endPage() |
246 self.endPage() |
245 |
247 |
246 # refer to all used or unused fonts for simplicity |
248 # refer to all used or unused fonts for simplicity |
247 resourceRef = self.oT.add( |
249 resourceRef = self.oT.add( |
248 "<</ProcSet[/PDF/Text]\n/Font<</F1 1 0 R/F2 2 0 R/F3 3 0 R/" |
250 "<</ProcSet[/PDF/Text]\n/Font<</F1 1 0 R/F2 2 0 R/F3 3 0 R/" |
249 "F4 4 0 R>> >>\n") |
251 "F4 4 0 R>> >>\n" |
250 |
252 ) |
|
253 |
251 # create all the page objects (PDF1.4Ref(p88)) |
254 # create all the page objects (PDF1.4Ref(p88)) |
252 # forward reference pages object; calculate its object number |
255 # forward reference pages object; calculate its object number |
253 pageObjectStart = self.oT.index |
256 pageObjectStart = self.oT.index |
254 pagesRef = pageObjectStart + self.pageCount |
257 pagesRef = pageObjectStart + self.pageCount |
255 for i in range(self.pageCount): |
258 for i in range(self.pageCount): |
257 "<</Type/Page/Parent {0:d} 0 R\n" |
260 "<</Type/Page/Parent {0:d} 0 R\n" |
258 "/MediaBox[ 0 0 {1:d} {2:d}]\n" |
261 "/MediaBox[ 0 0 {1:d} {2:d}]\n" |
259 "/Contents {3:d} 0 R\n" |
262 "/Contents {3:d} 0 R\n" |
260 "/Resources {4:d} 0 R\n>>\n" |
263 "/Resources {4:d} 0 R\n>>\n" |
261 ).format( |
264 ).format( |
262 pagesRef, self.pageWidth, self.pageHeight, |
265 pagesRef, |
263 self.pageContentStart + i, resourceRef |
266 self.pageWidth, |
|
267 self.pageHeight, |
|
268 self.pageContentStart + i, |
|
269 resourceRef, |
264 ) |
270 ) |
265 self.oT.add(buffer) |
271 self.oT.add(buffer) |
266 |
272 |
267 # create page tree object (PDF1.4Ref(p86)) |
273 # create page tree object (PDF1.4Ref(p86)) |
268 self.pageData = "<</Type/Pages/Kids[\n" |
274 self.pageData = "<</Type/Pages/Kids[\n" |
269 for i in range(self.pageCount): |
275 for i in range(self.pageCount): |
270 self.pageData += "{0:d} 0 R\n".format(pageObjectStart + i) |
276 self.pageData += "{0:d} 0 R\n".format(pageObjectStart + i) |
271 self.pageData += "]/Count {0:d}\n>>\n".format(self.pageCount) |
277 self.pageData += "]/Count {0:d}\n>>\n".format(self.pageCount) |
272 self.oT.add(self.pageData) |
278 self.oT.add(self.pageData) |
273 |
279 |
274 # create catalog object (PDF1.4Ref(p83)) |
280 # create catalog object (PDF1.4Ref(p83)) |
275 buffer = "<</Type/Catalog/Pages {0:d} 0 R >>\n".format(pagesRef) |
281 buffer = "<</Type/Catalog/Pages {0:d} 0 R >>\n".format(pagesRef) |
276 catalogRef = self.oT.add(buffer) |
282 catalogRef = self.oT.add(buffer) |
277 |
283 |
278 # append the cross reference table (PDF1.4Ref(p64)) |
284 # append the cross reference table (PDF1.4Ref(p64)) |
279 xref = self.oT.xref() |
285 xref = self.oT.xref() |
280 |
286 |
281 # end the file with the trailer (PDF1.4Ref(p67)) |
287 # end the file with the trailer (PDF1.4Ref(p67)) |
282 buffer = ( |
288 buffer = ( |
283 "trailer\n<< /Size {0:d} /Root {1:d} 0 R\n>>\nstartxref\n{2:d}\n" |
289 "trailer\n<< /Size {0:d} /Root {1:d} 0 R\n>>\nstartxref\n{2:d}\n" "%%EOF\n" |
284 "%%EOF\n" |
|
285 ).format(self.oT.index, catalogRef, xref) |
290 ).format(self.oT.index, catalogRef, xref) |
286 self.oT.write(buffer) |
291 self.oT.write(buffer) |
287 |
292 |
288 def add(self, ch, style_): |
293 def add(self, ch, style_): |
289 """ |
294 """ |
290 Public method to add a character to the page. |
295 Public method to add a character to the page. |
291 |
296 |
292 @param ch character to add (string) |
297 @param ch character to add (string) |
293 @param style_ number of the style of the character (integer) |
298 @param style_ number of the style of the character (integer) |
294 """ |
299 """ |
295 if not self.pageStarted: |
300 if not self.pageStarted: |
296 self.startPage() |
301 self.startPage() |
297 |
302 |
298 # get glyph width (TODO future non-monospace handling) |
303 # get glyph width (TODO future non-monospace handling) |
299 glyphWidth = self.fontToPoints(PDFfontWidths[self.fontSet]) |
304 glyphWidth = self.fontToPoints(PDFfontWidths[self.fontSet]) |
300 self.xPos += glyphWidth |
305 self.xPos += glyphWidth |
301 |
306 |
302 # if cannot fit into a line, flush, wrap to next line |
307 # if cannot fit into a line, flush, wrap to next line |
303 if self.xPos > self.pageWidth - self.pageMargins["right"]: |
308 if self.xPos > self.pageWidth - self.pageMargins["right"]: |
304 self.nextLine() |
309 self.nextLine() |
305 self.xPos += glyphWidth |
310 self.xPos += glyphWidth |
306 |
311 |
307 # if different style, then change to style |
312 # if different style, then change to style |
308 if style_ != self.styleCurrent: |
313 if style_ != self.styleCurrent: |
309 self.flushSegment() |
314 self.flushSegment() |
310 # output code (if needed) for new style |
315 # output code (if needed) for new style |
311 self.segStyle = self.setStyle(style_) |
316 self.segStyle = self.setStyle(style_) |
312 self.stylePrev = self.styleCurrent |
317 self.stylePrev = self.styleCurrent |
313 self.styleCurrent = style_ |
318 self.styleCurrent = style_ |
314 |
319 |
315 # escape these characters |
320 # escape these characters |
316 if ch in (')', '(', '\\'): |
321 if ch in (")", "(", "\\"): |
317 self.segment += '\\' |
322 self.segment += "\\" |
318 if ch != ' ': |
323 if ch != " ": |
319 self.justWhiteSpace = False |
324 self.justWhiteSpace = False |
320 self.segment += ch # add to segment data |
325 self.segment += ch # add to segment data |
321 |
326 |
322 def flushSegment(self): |
327 def flushSegment(self): |
323 """ |
328 """ |
324 Public method to flush a segment of data. |
329 Public method to flush a segment of data. |
325 """ |
330 """ |
326 if len(self.segment) > 0: |
331 if len(self.segment) > 0: |
327 if self.justWhiteSpace: # optimise |
332 if self.justWhiteSpace: # optimise |
328 self.styleCurrent = self.stylePrev |
333 self.styleCurrent = self.stylePrev |
329 else: |
334 else: |
330 self.pageData += self.segStyle |
335 self.pageData += self.segStyle |
331 self.pageData += "({0})Tj\n".format(self.segment) |
336 self.pageData += "({0})Tj\n".format(self.segment) |
332 self.segment = "" |
337 self.segment = "" |
333 self.segStyle = "" |
338 self.segStyle = "" |
334 self.justWhiteSpace = True |
339 self.justWhiteSpace = True |
335 |
340 |
336 def startPage(self): |
341 def startPage(self): |
337 """ |
342 """ |
338 Public method to start a new page. |
343 Public method to start a new page. |
339 """ |
344 """ |
340 self.pageStarted = True |
345 self.pageStarted = True |
341 self.firstLine = True |
346 self.firstLine = True |
342 self.pageCount += 1 |
347 self.pageCount += 1 |
343 fontAscender = self.fontToPoints(PDFfontAscenders[self.fontSet]) |
348 fontAscender = self.fontToPoints(PDFfontAscenders[self.fontSet]) |
344 self.yPos = self.pageHeight - self.pageMargins["top"] - fontAscender |
349 self.yPos = self.pageHeight - self.pageMargins["top"] - fontAscender |
345 |
350 |
346 # start a new page |
351 # start a new page |
347 buffer = "BT 1 0 0 1 {0:d} {1:d} Tm\n".format( |
352 buffer = "BT 1 0 0 1 {0:d} {1:d} Tm\n".format( |
348 self.pageMargins["left"], int(self.yPos)) |
353 self.pageMargins["left"], int(self.yPos) |
349 |
354 ) |
|
355 |
350 # force setting of initial font, colour |
356 # force setting of initial font, colour |
351 self.segStyle = self.setStyle(-1) |
357 self.segStyle = self.setStyle(-1) |
352 buffer += self.segStyle |
358 buffer += self.segStyle |
353 self.pageData = buffer |
359 self.pageData = buffer |
354 self.xPos = self.pageMargins["left"] |
360 self.xPos = self.pageMargins["left"] |
355 self.segment = "" |
361 self.segment = "" |
356 self.flushSegment() |
362 self.flushSegment() |
357 |
363 |
358 def endPage(self): |
364 def endPage(self): |
359 """ |
365 """ |
360 Public method to end a page. |
366 Public method to end a page. |
361 """ |
367 """ |
362 self.pageStarted = False |
368 self.pageStarted = False |
363 self.flushSegment() |
369 self.flushSegment() |
364 |
370 |
365 # build actual text object; +3 is for "ET\n" |
371 # build actual text object; +3 is for "ET\n" |
366 # PDF1.4Ref(p38) EOL marker preceding endstream not counted |
372 # PDF1.4Ref(p38) EOL marker preceding endstream not counted |
367 textObj = "<</Length {0:d}>>\nstream\n{1}ET\nendstream\n".format( |
373 textObj = "<</Length {0:d}>>\nstream\n{1}ET\nendstream\n".format( |
368 len(self.pageData) - 1 + 3, self.pageData) |
374 len(self.pageData) - 1 + 3, self.pageData |
|
375 ) |
369 self.oT.add(textObj) |
376 self.oT.add(textObj) |
370 |
377 |
371 def nextLine(self): |
378 def nextLine(self): |
372 """ |
379 """ |
373 Public method to start a new line. |
380 Public method to start a new line. |
374 """ |
381 """ |
375 if not self.pageStarted: |
382 if not self.pageStarted: |
376 self.startPage() |
383 self.startPage() |
377 |
384 |
378 self.xPos = self.pageMargins["left"] |
385 self.xPos = self.pageMargins["left"] |
379 self.flushSegment() |
386 self.flushSegment() |
380 |
387 |
381 # PDF follows cartesian coords, subtract -> down |
388 # PDF follows cartesian coords, subtract -> down |
382 self.yPos -= self.leading |
389 self.yPos -= self.leading |
383 fontDescender = self.fontToPoints(PDFfontDescenders[self.fontSet]) |
390 fontDescender = self.fontToPoints(PDFfontDescenders[self.fontSet]) |
384 if self.yPos < self.pageMargins["bottom"] + fontDescender: |
391 if self.yPos < self.pageMargins["bottom"] + fontDescender: |
385 self.endPage() |
392 self.endPage() |
386 self.startPage() |
393 self.startPage() |
387 return |
394 return |
388 |
395 |
389 if self.firstLine: |
396 if self.firstLine: |
390 # avoid breakage due to locale setting |
397 # avoid breakage due to locale setting |
391 f = int(self.leading * 10 + 0.5) |
398 f = int(self.leading * 10 + 0.5) |
392 buffer = "0 -{0:d}.{1:d} TD\n".format(f // 10, f % 10) |
399 buffer = "0 -{0:d}.{1:d} TD\n".format(f // 10, f % 10) |
393 self.firstLine = False |
400 self.firstLine = False |
422 if c in (0, 1000): |
430 if c in (0, 1000): |
423 pdfColor += "{0:d} ".format(c // 1000) |
431 pdfColor += "{0:d} ".format(c // 1000) |
424 else: |
432 else: |
425 pdfColor += "0.{0:03d} ".format(c) |
433 pdfColor += "0.{0:03d} ".format(c) |
426 return pdfColor |
434 return pdfColor |
427 |
435 |
428 def exportSource(self): |
436 def exportSource(self): |
429 """ |
437 """ |
430 Public method performing the export. |
438 Public method performing the export. |
431 """ |
439 """ |
432 self.pr = PDFRender() |
440 self.pr = PDFRender() |
433 |
441 |
434 filename = self._getFileName(self.tr("PDF Files (*.pdf)")) |
442 filename = self._getFileName(self.tr("PDF Files (*.pdf)")) |
435 if not filename: |
443 if not filename: |
436 return |
444 return |
437 |
445 |
438 self.editor.recolor(0, -1) |
446 self.editor.recolor(0, -1) |
439 lex = self.editor.getLexer() |
447 lex = self.editor.getLexer() |
440 |
448 |
441 tabSize = self.editor.getEditorConfig("TabWidth") |
449 tabSize = self.editor.getEditorConfig("TabWidth") |
442 if tabSize == 0: |
450 if tabSize == 0: |
443 tabSize = 4 |
451 tabSize = 4 |
444 |
452 |
445 # get magnification value to add to default screen font size |
453 # get magnification value to add to default screen font size |
446 self.pr.fontSize = Preferences.getEditorExporter( |
454 self.pr.fontSize = Preferences.getEditorExporter("PDF/Magnification") |
447 "PDF/Magnification") |
455 |
448 |
|
449 # set font family according to face name |
456 # set font family according to face name |
450 fontName = Preferences.getEditorExporter("PDF/Font") |
457 fontName = Preferences.getEditorExporter("PDF/Font") |
451 self.pr.fontSet = PDF_FONT_DEFAULT |
458 self.pr.fontSet = PDF_FONT_DEFAULT |
452 if fontName == "Courier": |
459 if fontName == "Courier": |
453 self.pr.fontSet = 0 |
460 self.pr.fontSet = 0 |
454 elif fontName == "Helvetica": |
461 elif fontName == "Helvetica": |
455 self.pr.fontSet = 1 |
462 self.pr.fontSet = 1 |
456 elif fontName == "Times": |
463 elif fontName == "Times": |
457 self.pr.fontSet = 2 |
464 self.pr.fontSet = 2 |
458 |
465 |
459 # page size: height, width, |
466 # page size: height, width, |
460 pageSize = Preferences.getEditorExporter("PDF/PageSize") |
467 pageSize = Preferences.getEditorExporter("PDF/PageSize") |
461 try: |
468 try: |
462 pageDimensions = PDFpageSizes[pageSize] |
469 pageDimensions = PDFpageSizes[pageSize] |
463 except KeyError: |
470 except KeyError: |
464 pageDimensions = PDFpageSizes["A4"] |
471 pageDimensions = PDFpageSizes["A4"] |
465 self.pr.pageHeight = pageDimensions[0] |
472 self.pr.pageHeight = pageDimensions[0] |
466 self.pr.pageWidth = pageDimensions[1] |
473 self.pr.pageWidth = pageDimensions[1] |
467 |
474 |
468 # page margins: left, right, top, bottom |
475 # page margins: left, right, top, bottom |
469 # < 0 to use PDF default values |
476 # < 0 to use PDF default values |
470 val = Preferences.getEditorExporter("PDF/MarginLeft") |
477 val = Preferences.getEditorExporter("PDF/MarginLeft") |
471 if val < 0: |
478 if val < 0: |
472 self.pr.pageMargins["left"] = PDF_MARGIN_DEFAULT |
479 self.pr.pageMargins["left"] = PDF_MARGIN_DEFAULT |
485 val = Preferences.getEditorExporter("PDF/MarginBottom") |
492 val = Preferences.getEditorExporter("PDF/MarginBottom") |
486 if val < 0: |
493 if val < 0: |
487 self.pr.pageMargins["bottom"] = PDF_MARGIN_DEFAULT |
494 self.pr.pageMargins["bottom"] = PDF_MARGIN_DEFAULT |
488 else: |
495 else: |
489 self.pr.pageMargins["bottom"] = val |
496 self.pr.pageMargins["bottom"] = val |
490 |
497 |
491 # collect all styles available for that 'language' |
498 # collect all styles available for that 'language' |
492 # or the default style if no language is available... |
499 # or the default style if no language is available... |
493 if lex: |
500 if lex: |
494 istyle = 0 |
501 istyle = 0 |
495 while istyle <= QsciScintilla.STYLE_MAX: |
502 while istyle <= QsciScintilla.STYLE_MAX: |
496 if (istyle <= QsciScintilla.STYLE_DEFAULT or |
503 if ( |
497 istyle > QsciScintilla.STYLE_LASTPREDEFINED): |
504 istyle <= QsciScintilla.STYLE_DEFAULT |
498 if ( |
505 or istyle > QsciScintilla.STYLE_LASTPREDEFINED |
499 lex.description(istyle) or |
506 ): |
500 istyle == QsciScintilla.STYLE_DEFAULT |
507 if lex.description(istyle) or istyle == QsciScintilla.STYLE_DEFAULT: |
501 ): |
|
502 style = PDFStyle() |
508 style = PDFStyle() |
503 |
509 |
504 font = lex.font(istyle) |
510 font = lex.font(istyle) |
505 if font.italic(): |
511 if font.italic(): |
506 style.font |= 2 |
512 style.font |= 2 |
507 if font.bold(): |
513 if font.bold(): |
508 style.font |= 1 |
514 style.font |= 1 |
509 |
515 |
510 colour = lex.color(istyle) |
516 colour = lex.color(istyle) |
511 style.fore = self.__getPDFRGB(colour) |
517 style.fore = self.__getPDFRGB(colour) |
512 self.pr.style[istyle] = style |
518 self.pr.style[istyle] = style |
513 |
519 |
514 # get substyles |
520 # get substyles |
515 subs_start, subs_count = self.editor.getSubStyleRange( |
521 subs_start, subs_count = self.editor.getSubStyleRange(istyle) |
516 istyle) |
|
517 for subs_idx in range(subs_count): |
522 for subs_idx in range(subs_count): |
518 style = PDFStyle() |
523 style = PDFStyle() |
519 font = lex.font(subs_start + subs_idx) |
524 font = lex.font(subs_start + subs_idx) |
520 if font.italic(): |
525 if font.italic(): |
521 style.font |= 2 |
526 style.font |= 2 |
522 if font.bold(): |
527 if font.bold(): |
523 style.font |= 1 |
528 style.font |= 1 |
524 |
529 |
525 colour = lex.color(subs_start + subs_idx) |
530 colour = lex.color(subs_start + subs_idx) |
526 style.fore = self.__getPDFRGB(colour) |
531 style.fore = self.__getPDFRGB(colour) |
527 # styleAt returns negative numbers for substyles |
532 # styleAt returns negative numbers for substyles |
528 self.pr.style[subs_idx - subs_start] = style |
533 self.pr.style[subs_idx - subs_start] = style |
529 |
534 |
532 fontSize = QFontInfo(font).pointSize() |
537 fontSize = QFontInfo(font).pointSize() |
533 if fontSize > 0: |
538 if fontSize > 0: |
534 self.pr.fontSize += fontSize |
539 self.pr.fontSize += fontSize |
535 else: |
540 else: |
536 self.pr.fontSize = PDF_FONTSIZE_DEFAULT |
541 self.pr.fontSize = PDF_FONTSIZE_DEFAULT |
537 |
542 |
538 istyle += 1 |
543 istyle += 1 |
539 else: |
544 else: |
540 style = PDFStyle() |
545 style = PDFStyle() |
541 |
546 |
542 font = Preferences.getEditorOtherFonts("DefaultFont") |
547 font = Preferences.getEditorOtherFonts("DefaultFont") |
543 if font.italic(): |
548 if font.italic(): |
544 style.font |= 2 |
549 style.font |= 2 |
545 if font.bold(): |
550 if font.bold(): |
546 style.font |= 1 |
551 style.font |= 1 |
547 |
552 |
548 colour = self.editor.color() |
553 colour = self.editor.color() |
549 style.fore = self.__getPDFRGB(colour) |
554 style.fore = self.__getPDFRGB(colour) |
550 self.pr.style[0] = style |
555 self.pr.style[0] = style |
551 self.pr.style[QsciScintilla.STYLE_DEFAULT] = style |
556 self.pr.style[QsciScintilla.STYLE_DEFAULT] = style |
552 |
557 |
553 fontSize = QFontInfo(font).pointSize() |
558 fontSize = QFontInfo(font).pointSize() |
554 if fontSize > 0: |
559 if fontSize > 0: |
555 self.pr.fontSize += fontSize |
560 self.pr.fontSize += fontSize |
556 else: |
561 else: |
557 self.pr.fontSize = PDF_FONTSIZE_DEFAULT |
562 self.pr.fontSize = PDF_FONTSIZE_DEFAULT |
558 |
563 |
559 with EricOverrideCursor(), open(filename, "w", encoding="cp1250", |
564 with EricOverrideCursor(), open( |
560 errors="backslashreplace") as f: |
565 filename, "w", encoding="cp1250", errors="backslashreplace" |
|
566 ) as f: |
561 # save file in win ansi using cp1250 |
567 # save file in win ansi using cp1250 |
562 try: |
568 try: |
563 # initialise PDF rendering |
569 # initialise PDF rendering |
564 ot = PDFObjectTracker(f) |
570 ot = PDFObjectTracker(f) |
565 self.pr.oT = ot |
571 self.pr.oT = ot |
566 self.pr.startPDF() |
572 self.pr.startPDF() |
567 |
573 |
568 # do here all the writing |
574 # do here all the writing |
569 lengthDoc = self.editor.length() |
575 lengthDoc = self.editor.length() |
570 |
576 |
571 if lengthDoc == 0: |
577 if lengthDoc == 0: |
572 self.pr.nextLine() # enable zero length docs |
578 self.pr.nextLine() # enable zero length docs |
573 else: |
579 else: |
574 pos = 0 |
580 pos = 0 |
575 column = 0 |
581 column = 0 |
576 utf8 = self.editor.isUtf8() |
582 utf8 = self.editor.isUtf8() |
577 utf8Ch = b"" |
583 utf8Ch = b"" |
578 utf8Len = 0 |
584 utf8Len = 0 |
579 |
585 |
580 while pos < lengthDoc: |
586 while pos < lengthDoc: |
581 ch = self.editor.byteAt(pos) |
587 ch = self.editor.byteAt(pos) |
582 style = self.editor.styleAt(pos) |
588 style = self.editor.styleAt(pos) |
583 |
589 |
584 if ch == b'\t': |
590 if ch == b"\t": |
585 # expand tabs |
591 # expand tabs |
586 ts = tabSize - (column % tabSize) |
592 ts = tabSize - (column % tabSize) |
587 column += ts |
593 column += ts |
588 self.pr.add(' ' * ts, style) |
594 self.pr.add(" " * ts, style) |
589 elif ch in (b'\r', b'\n'): |
595 elif ch in (b"\r", b"\n"): |
590 if ( |
596 if ch == b"\r" and self.editor.byteAt(pos + 1) == b"\n": |
591 ch == b'\r' and |
|
592 self.editor.byteAt(pos + 1) == b'\n' |
|
593 ): |
|
594 pos += 1 |
597 pos += 1 |
595 # close and begin a newline... |
598 # close and begin a newline... |
596 self.pr.nextLine() |
599 self.pr.nextLine() |
597 column = 0 |
600 column = 0 |
598 else: |
601 else: |