From 0a7419d7e3ca1223ca27b556bcc10c37c3404256 Mon Sep 17 00:00:00 2001 From: Tom Price Date: Sun, 7 Dec 2014 17:32:24 +0000 Subject: [PATCH] Added printing requirements --- PyRIGS/settings.py | 6 - reportlab.zip | Bin 1057220 -> 0 bytes reportlab/MANIFEST.in | 6 + reportlab/__init__.py | 48 + reportlab/fonts/00readme.txt | 8 + reportlab/fonts/DarkGarden-changelog.txt | 14 + reportlab/fonts/DarkGarden-copying-gpl.txt | 339 + reportlab/fonts/DarkGarden-copying.txt | 26 + reportlab/fonts/DarkGarden-readme.txt | 106 + reportlab/fonts/DarkGarden.sfd | 11067 ++++++++++++++++ reportlab/fonts/DarkGardenMK.afm | 429 + reportlab/fonts/DarkGardenMK.pfb | Bin 0 -> 79824 bytes reportlab/fonts/Vera.ttf | Bin 0 -> 65932 bytes reportlab/fonts/VeraBI.ttf | Bin 0 -> 63208 bytes reportlab/fonts/VeraBd.ttf | Bin 0 -> 58716 bytes reportlab/fonts/VeraIt.ttf | Bin 0 -> 63684 bytes reportlab/fonts/bitstream-vera-license.txt | 124 + reportlab/graphics/__init__.py | 6 + reportlab/graphics/barcode/README | 59 + reportlab/graphics/barcode/TODO | 24 + reportlab/graphics/barcode/VERSION | 1 + reportlab/graphics/barcode/__init__.py | 136 + reportlab/graphics/barcode/code128.py | 321 + reportlab/graphics/barcode/code39.py | 245 + reportlab/graphics/barcode/code93.py | 234 + reportlab/graphics/barcode/common.py | 749 ++ reportlab/graphics/barcode/eanbc.py | 350 + reportlab/graphics/barcode/fourstate.py | 81 + reportlab/graphics/barcode/lto.py | 196 + reportlab/graphics/barcode/qr.py | 209 + reportlab/graphics/barcode/qrencoder.py | 1130 ++ reportlab/graphics/barcode/test.py | 200 + reportlab/graphics/barcode/usps.py | 232 + reportlab/graphics/barcode/usps4s.py | 386 + reportlab/graphics/barcode/widgets.py | 307 + reportlab/graphics/charts/__init__.py | 5 + reportlab/graphics/charts/areas.py | 94 + reportlab/graphics/charts/axes.py | 2332 ++++ reportlab/graphics/charts/barcharts.py | 2298 ++++ reportlab/graphics/charts/dotbox.py | 165 + reportlab/graphics/charts/doughnut.py | 400 + reportlab/graphics/charts/legends.py | 716 + reportlab/graphics/charts/linecharts.py | 715 + reportlab/graphics/charts/lineplots.py | 1150 ++ reportlab/graphics/charts/markers.py | 82 + reportlab/graphics/charts/piecharts.py | 1660 +++ reportlab/graphics/charts/slidebox.py | 186 + reportlab/graphics/charts/spider.py | 408 + reportlab/graphics/charts/textlabels.py | 466 + reportlab/graphics/charts/utils.py | 390 + reportlab/graphics/charts/utils3d.py | 233 + reportlab/graphics/renderPDF.py | 404 + reportlab/graphics/renderPM.py | 761 ++ reportlab/graphics/renderPS.py | 930 ++ reportlab/graphics/renderSVG.py | 929 ++ reportlab/graphics/renderbase.py | 357 + reportlab/graphics/samples/__init__.py | 1 + reportlab/graphics/samples/bubble.py | 73 + reportlab/graphics/samples/clustered_bar.py | 84 + .../graphics/samples/clustered_column.py | 83 + reportlab/graphics/samples/excelcolors.py | 45 + reportlab/graphics/samples/exploded_pie.py | 65 + reportlab/graphics/samples/filled_radar.py | 54 + reportlab/graphics/samples/line_chart.py | 83 + .../samples/linechart_with_markers.py | 94 + reportlab/graphics/samples/radar.py | 66 + reportlab/graphics/samples/runall.py | 58 + reportlab/graphics/samples/scatter.py | 71 + reportlab/graphics/samples/scatter_lines.py | 82 + .../graphics/samples/scatter_lines_markers.py | 72 + reportlab/graphics/samples/simple_pie.py | 61 + reportlab/graphics/samples/stacked_bar.py | 85 + reportlab/graphics/samples/stacked_column.py | 84 + reportlab/graphics/shapes.py | 1467 ++ reportlab/graphics/testdrawings.py | 296 + reportlab/graphics/testshapes.py | 580 + reportlab/graphics/widgetbase.py | 529 + reportlab/graphics/widgets/__init__.py | 5 + reportlab/graphics/widgets/eventcal.py | 304 + reportlab/graphics/widgets/flags.py | 880 ++ reportlab/graphics/widgets/grids.py | 519 + reportlab/graphics/widgets/markers.py | 245 + reportlab/graphics/widgets/signsandsymbols.py | 933 ++ reportlab/graphics/widgets/table.py | 161 + reportlab/license.txt | 29 + reportlab/pdfbase/__init__.py | 6 + reportlab/pdfbase/_can_cmap_data.py | 60 + reportlab/pdfbase/_cidfontdata.py | 483 + reportlab/pdfbase/_fontdata.py | 255 + reportlab/pdfbase/_fontdata_enc_macexpert.py | 28 + reportlab/pdfbase/_fontdata_enc_macroman.py | 35 + reportlab/pdfbase/_fontdata_enc_pdfdoc.py | 22 + reportlab/pdfbase/_fontdata_enc_standard.py | 15 + reportlab/pdfbase/_fontdata_enc_symbol.py | 30 + reportlab/pdfbase/_fontdata_enc_winansi.py | 37 + .../pdfbase/_fontdata_enc_zapfdingbats.py | 20 + reportlab/pdfbase/_fontdata_widths_courier.py | 229 + .../pdfbase/_fontdata_widths_courierbold.py | 229 + .../_fontdata_widths_courierboldoblique.py | 229 + .../_fontdata_widths_courieroblique.py | 229 + .../pdfbase/_fontdata_widths_helvetica.py | 229 + .../pdfbase/_fontdata_widths_helveticabold.py | 229 + .../_fontdata_widths_helveticaboldoblique.py | 229 + .../_fontdata_widths_helveticaoblique.py | 229 + reportlab/pdfbase/_fontdata_widths_symbol.py | 190 + .../pdfbase/_fontdata_widths_timesbold.py | 229 + .../_fontdata_widths_timesbolditalic.py | 229 + .../pdfbase/_fontdata_widths_timesitalic.py | 229 + .../pdfbase/_fontdata_widths_timesroman.py | 229 + .../pdfbase/_fontdata_widths_zapfdingbats.py | 202 + reportlab/pdfbase/cidfonts.py | 520 + reportlab/pdfbase/pdfdoc.py | 2394 ++++ reportlab/pdfbase/pdfform.py | 634 + reportlab/pdfbase/pdfmetrics.py | 799 ++ reportlab/pdfbase/pdfpattern.py | 93 + reportlab/pdfbase/pdfutils.py | 284 + reportlab/pdfbase/rl_codecs.py | 1054 ++ reportlab/pdfbase/ttfonts.py | 1220 ++ reportlab/pdfgen/__init__.py | 5 + reportlab/pdfgen/canvas.py | 1837 +++ reportlab/pdfgen/pathobject.py | 127 + reportlab/pdfgen/pdfgeom.py | 77 + reportlab/pdfgen/pdfimages.py | 217 + reportlab/pdfgen/textobject.py | 465 + reportlab/platypus/__init__.py | 17 + reportlab/platypus/doctemplate.py | 1250 ++ reportlab/platypus/figures.py | 433 + reportlab/platypus/flowables.py | 1979 +++ reportlab/platypus/frames.py | 282 + reportlab/platypus/para.py | 2366 ++++ reportlab/platypus/paragraph.py | 1957 +++ reportlab/platypus/paraparser.py | 1349 ++ reportlab/platypus/tableofcontents.py | 553 + reportlab/platypus/tables.py | 1612 +++ reportlab/platypus/xpreformatted.py | 338 + reportlab/rl_config.py | 131 + reportlab/rl_settings.py | 209 + z3c.zip | Bin 1834087 -> 0 bytes z3c/__init__.py | 8 + z3c/rml/README.txt | 18 + z3c/rml/__init__.py | 7 + z3c/rml/attr.py | 607 + z3c/rml/canvas.py | 1012 ++ z3c/rml/chart.py | 1662 +++ z3c/rml/directive.py | 123 + z3c/rml/doclogic.py | 169 + z3c/rml/document.py | 757 ++ z3c/rml/dtd.py | 76 + z3c/rml/flowable.py | 1611 +++ z3c/rml/form.py | 356 + z3c/rml/interfaces.py | 148 + z3c/rml/list.py | 181 + z3c/rml/occurence.py | 113 + z3c/rml/page.py | 115 + z3c/rml/pagetemplate.py | 45 + z3c/rml/pagetemplate.txt | 54 + z3c/rml/paraparser.py | 181 + z3c/rml/pdfinclude.py | 149 + z3c/rml/platypus.py | 135 + z3c/rml/reference.pt | 294 + z3c/rml/reference.py | 242 + z3c/rml/rlfix.py | 50 + z3c/rml/rml-reference.pdf | 5978 +++++++++ z3c/rml/rml.dtd | 2236 ++++ z3c/rml/rml2pdf.py | 70 + z3c/rml/rml2pdfscript.py | 116 + z3c/rml/special.py | 114 + z3c/rml/storyplace.py | 112 + z3c/rml/stylesheet.py | 687 + z3c/rml/template.py | 276 + z3c/rml/tests/__init__.py | 1 + .../tests/expected/encoding-test-latin1.pdf | 107 + z3c/rml/tests/expected/encoding-test-utf8.pdf | 107 + z3c/rml/tests/expected/printScaling.pdf | 102 + .../expected/rml-examples-000-simple.pdf | 127 + .../tests/expected/rml-examples-001-cmbox.pdf | 150 + .../tests/expected/rml-examples-001-hello.pdf | 136 + .../tests/expected/rml-examples-002-paras.pdf | 322 + .../expected/rml-examples-003-frames.pdf | 118 + .../rml-examples-004-fpt-templates.pdf | 149 + .../expected/rml-examples-004-templates.pdf | 149 + .../tests/expected/rml-examples-005-fonts.pdf | Bin 0 -> 105573 bytes .../expected/rml-examples-006-barcodes.pdf | 118 + .../expected/rml-examples-008-tables.pdf | 549 + .../expected/rml-examples-009-splitting.pdf | 222 + .../expected/rml-examples-010-linkURL.pdf | 124 + .../rml-examples-011-keepwithnext.pdf | 318 + .../expected/rml-examples-017-outlines.pdf | 263 + .../expected/rml-examples-022-paras-oas.pdf | 244 + .../expected/rml-examples-029-keepinframe.pdf | 90 + .../expected/rml-examples-031-japanese.pdf | 408 + .../expected/rml-examples-032-images.pdf | 86 + .../tests/expected/rml-examples-034-cmyk.pdf | 118 + .../expected/rml-examples-035-numbering.pdf | 150 + .../rml-examples-036-numbering-contd.pdf | 150 + .../rml-examples-037-plugingraphic.pdf | 150 + .../expected/rml-examples-038-rect-href.pdf | 375 + .../rml-examples-039-doc-programming.pdf | 359 + .../expected/rml-examples-040-colors.pdf | 139 + .../expected/rml-examples-041-masking.pdf | 155 + .../expected/rml-examples-042-longdoc.pdf | 445 + .../expected/rml-examples-043-headings.pdf | 161 + .../rml-examples-044-codesnippets.pdf | 150 + .../tests/expected/rml-examples-045-cmyk.pdf | 150 + .../tests/expected/rml-examples-046-lists.pdf | 82 + .../rml-examples-047-condPageBreak.pdf | 502 + ...l-examples-048-paragraph-flow-controls.pdf | 359 + .../tests/expected/rml-examples-049-pre.pdf | 172 + .../tests/expected/rml-guide-example-01.pdf | 96 + .../tests/expected/rml-guide-example-02.pdf | 96 + .../tests/expected/rml-guide-example-03.pdf | 96 + .../tests/expected/rml-guide-example-04.pdf | 96 + .../tests/expected/rml-guide-example-05.pdf | 118 + .../tests/expected/rml-guide-example-06.pdf | 118 + .../tests/expected/rml-guide-example-07.pdf | 96 + .../tests/expected/rml-guide-example-08.pdf | 96 + .../tests/expected/rml-guide-example-09.pdf | 151 + .../tests/expected/rml-guide-example-10.pdf | 129 + .../tests/expected/rml-guide-example-11.pdf | 140 + .../tests/expected/rml-guide-example-12.pdf | 134 + .../expected/sample-shipment-chinese.pdf | 891 ++ z3c/rml/tests/expected/simple-layout.pdf | 107 + z3c/rml/tests/expected/special-text.pdf | 127 + z3c/rml/tests/expected/symbols-set.pdf | 118 + z3c/rml/tests/expected/tag-addMapping.pdf | 107 + z3c/rml/tests/expected/tag-alias.pdf | 118 + z3c/rml/tests/expected/tag-barChart.pdf | 118 + z3c/rml/tests/expected/tag-barChart3d.pdf | 118 + .../tests/expected/tag-barCodeFlowable.pdf | 149 + z3c/rml/tests/expected/tag-barcode.pdf | 107 + z3c/rml/tests/expected/tag-blockTable-1.pdf | 118 + z3c/rml/tests/expected/tag-blockTable-10.pdf | 183 + z3c/rml/tests/expected/tag-blockTable-2.pdf | 140 + z3c/rml/tests/expected/tag-blockTable-3.pdf | 140 + z3c/rml/tests/expected/tag-blockTable-4.pdf | 118 + z3c/rml/tests/expected/tag-blockTable-5.pdf | 118 + z3c/rml/tests/expected/tag-blockTable-6.pdf | 118 + z3c/rml/tests/expected/tag-blockTable-7.pdf | 118 + z3c/rml/tests/expected/tag-blockTable-8.pdf | 129 + z3c/rml/tests/expected/tag-blockTable-9.pdf | 118 + .../expected/tag-blockTable-bulkData.pdf | 118 + .../tests/expected/tag-blockTableStyle-2.pdf | 118 + .../tests/expected/tag-blockTableStyle-3.pdf | 107 + .../tests/expected/tag-blockTableStyle.pdf | 129 + z3c/rml/tests/expected/tag-bookmark.pdf | 240 + z3c/rml/tests/expected/tag-buttonField.pdf | 96 + z3c/rml/tests/expected/tag-circle.pdf | 96 + z3c/rml/tests/expected/tag-codesnippet.pdf | 107 + z3c/rml/tests/expected/tag-color.pdf | 96 + z3c/rml/tests/expected/tag-condPageBreak.pdf | 138 + z3c/rml/tests/expected/tag-cropMarks.pdf | 107 + z3c/rml/tests/expected/tag-curves.pdf | 96 + z3c/rml/tests/expected/tag-doc.pdf | 118 + .../expected/tag-docinit-viewer-options.pdf | 125 + .../expected/tag-document-annotations.pdf | 107 + .../expected/tag-document-pageDrawing.pdf | 96 + z3c/rml/tests/expected/tag-document-story.pdf | 107 + .../tests/expected/tag-drawAlignedString.pdf | 96 + .../tests/expected/tag-drawCenteredString.pdf | 96 + .../tests/expected/tag-drawRightString.pdf | 96 + z3c/rml/tests/expected/tag-drawString.pdf | 96 + z3c/rml/tests/expected/tag-ellipse.pdf | 96 + z3c/rml/tests/expected/tag-fill.pdf | 96 + z3c/rml/tests/expected/tag-fixedSize.pdf | 57 + z3c/rml/tests/expected/tag-grid.pdf | 96 + z3c/rml/tests/expected/tag-hr.pdf | 96 + z3c/rml/tests/expected/tag-illustration.pdf | 118 + z3c/rml/tests/expected/tag-image-1.pdf | 112 + z3c/rml/tests/expected/tag-image-svg.pdf | 208 + z3c/rml/tests/expected/tag-image.pdf | 112 + .../expected/tag-imageAndFlowables-svg.pdf | 140 + .../tests/expected/tag-imageAndFlowables.pdf | 140 + z3c/rml/tests/expected/tag-img.pdf | 134 + .../tests/expected/tag-includePdfPages.pdf | Bin 0 -> 109091 bytes z3c/rml/tests/expected/tag-indent.pdf | 118 + z3c/rml/tests/expected/tag-index.pdf | 260 + z3c/rml/tests/expected/tag-keepInFrame.pdf | 68 + z3c/rml/tests/expected/tag-keepTogether.pdf | 158 + z3c/rml/tests/expected/tag-lineMode.pdf | 96 + z3c/rml/tests/expected/tag-linePlot.pdf | 118 + z3c/rml/tests/expected/tag-linePlot3D.pdf | 118 + z3c/rml/tests/expected/tag-lines.pdf | 96 + z3c/rml/tests/expected/tag-log.pdf | 107 + z3c/rml/tests/expected/tag-mergePage.pdf | 1334 ++ z3c/rml/tests/expected/tag-name.pdf | 107 + z3c/rml/tests/expected/tag-nextFrame.pdf | 107 + z3c/rml/tests/expected/tag-nextPage.pdf | 138 + z3c/rml/tests/expected/tag-outlineAdd.pdf | 138 + z3c/rml/tests/expected/tag-pageGraphics.pdf | 118 + z3c/rml/tests/expected/tag-pageInfo-2.pdf | 96 + z3c/rml/tests/expected/tag-pageInfo.pdf | 96 + z3c/rml/tests/expected/tag-para-border.pdf | 107 + z3c/rml/tests/expected/tag-para-wordWrap.pdf | 96 + z3c/rml/tests/expected/tag-para.pdf | 65 + z3c/rml/tests/expected/tag-path.pdf | 96 + z3c/rml/tests/expected/tag-pieChart.pdf | 118 + z3c/rml/tests/expected/tag-pieChart3d.pdf | 118 + z3c/rml/tests/expected/tag-place.pdf | 118 + z3c/rml/tests/expected/tag-plugInFlowable.pdf | 118 + z3c/rml/tests/expected/tag-plugInGraphic.pdf | 107 + z3c/rml/tests/expected/tag-pre.pdf | 140 + z3c/rml/tests/expected/tag-pto.pdf | 149 + z3c/rml/tests/expected/tag-rectange.pdf | 96 + .../tests/expected/tag-registerCidFont.pdf | 344 + z3c/rml/tests/expected/tag-registerTTFont.pdf | Bin 0 -> 29086 bytes .../tests/expected/tag-registerType1Face.pdf | Bin 0 -> 83755 bytes z3c/rml/tests/expected/tag-rotate.pdf | 96 + .../expected/tag-saveState-restoreState.pdf | 107 + z3c/rml/tests/expected/tag-scale.pdf | 96 + z3c/rml/tests/expected/tag-selectField.pdf | 0 z3c/rml/tests/expected/tag-setFont.pdf | 96 + z3c/rml/tests/expected/tag-setFontSize.pdf | 96 + z3c/rml/tests/expected/tag-setNextFrame.pdf | 107 + .../tests/expected/tag-setNextTemplate.pdf | 169 + z3c/rml/tests/expected/tag-skew.pdf | 96 + z3c/rml/tests/expected/tag-spacer.pdf | 118 + z3c/rml/tests/expected/tag-spiderChart.pdf | 118 + z3c/rml/tests/expected/tag-storyPlace.pdf | 96 + z3c/rml/tests/expected/tag-stroke.pdf | 96 + z3c/rml/tests/expected/tag-textAnnotation.pdf | 114 + z3c/rml/tests/expected/tag-textField.pdf | 268 + z3c/rml/tests/expected/tag-transform.pdf | 96 + z3c/rml/tests/expected/tag-translate.pdf | 96 + z3c/rml/tests/expected/tag-ul-ol-li.pdf | 61 + z3c/rml/tests/expected/tag-xpre.pdf | 140 + z3c/rml/tests/flowable.py | 31 + z3c/rml/tests/input/400x200.gif | Bin 0 -> 3519 bytes z3c/rml/tests/input/VeraMono.ttf | Bin 0 -> 7892 bytes z3c/rml/tests/input/data/fw2.pdf | Bin 0 -> 306050 bytes .../tests/input/data/include-bookmarks1.pdf | Bin 0 -> 24160 bytes .../tests/input/data/include-bookmarks2.pdf | Bin 0 -> 18217 bytes z3c/rml/tests/input/data/include1.pdf | Bin 0 -> 10795 bytes z3c/rml/tests/input/data/include2.pdf | Bin 0 -> 28946 bytes z3c/rml/tests/input/encoding-test-latin1.rml | 26 + z3c/rml/tests/input/encoding-test-utf8.rml | 23 + z3c/rml/tests/input/images/cylinder.eps | 187 + z3c/rml/tests/input/images/cylinder.svg | 2 + z3c/rml/tests/input/images/cylinder.svgz | Bin 0 -> 2920 bytes z3c/rml/tests/input/images/replogo.gif | Bin 0 -> 2269 bytes z3c/rml/tests/input/logo_no_bar.png | Bin 0 -> 6150 bytes z3c/rml/tests/input/printScaling.rml | 19 + .../tests/input/rml-examples-000-simple.rml | 16 + .../tests/input/rml-examples-001-cmbox.rml | 55 + .../tests/input/rml-examples-001-hello.rml | 57 + .../tests/input/rml-examples-002-paras.rml | 395 + .../tests/input/rml-examples-003-frames.rml | 111 + .../input/rml-examples-004-fpt-templates.rml | 114 + .../input/rml-examples-004-templates.rml | 116 + .../tests/input/rml-examples-005-fonts.rml | 58 + .../tests/input/rml-examples-006-barcodes.rml | 55 + .../tests/input/rml-examples-008-tables.rml | 994 ++ .../input/rml-examples-009-splitting.rml | 117 + .../tests/input/rml-examples-010-linkURL.rml | 29 + .../input/rml-examples-011-keepwithnext.rml | 190 + .../tests/input/rml-examples-017-outlines.rml | 46 + .../input/rml-examples-022-paras-oas.rml | 316 + .../input/rml-examples-029-keepinframe.rml | 577 + .../tests/input/rml-examples-031-japanese.rml | 130 + .../tests/input/rml-examples-032-images.rml | 106 + z3c/rml/tests/input/rml-examples-034-cmyk.rml | 80 + .../input/rml-examples-035-numbering.rml | 103 + .../rml-examples-036-numbering-contd.rml | 95 + .../input/rml-examples-037-plugingraphic.rml | 16 + .../input/rml-examples-038-rect-href.rml | 99 + .../rml-examples-039-doc-programming.rml | 149 + .../tests/input/rml-examples-040-colors.rml | 44 + .../tests/input/rml-examples-041-masking.rml | 67 + .../tests/input/rml-examples-042-longdoc.rml | 171 + .../tests/input/rml-examples-043-headings.rml | 64 + .../input/rml-examples-044-codesnippets.rml | 108 + z3c/rml/tests/input/rml-examples-045-cmyk.rml | 105 + .../tests/input/rml-examples-046-lists.rml | 160 + .../input/rml-examples-047-condPageBreak.rml | 319 + ...l-examples-048-paragraph-flow-controls.rml | 209 + z3c/rml/tests/input/rml-examples-049-pre.rml | 98 + z3c/rml/tests/input/rml-guide-example-01.rml | 10 + z3c/rml/tests/input/rml-guide-example-02.rml | 21 + z3c/rml/tests/input/rml-guide-example-03.rml | 109 + z3c/rml/tests/input/rml-guide-example-04.rml | 229 + z3c/rml/tests/input/rml-guide-example-05.rml | 141 + z3c/rml/tests/input/rml-guide-example-06.rml | 131 + z3c/rml/tests/input/rml-guide-example-07.rml | 50 + z3c/rml/tests/input/rml-guide-example-08.rml | 35 + z3c/rml/tests/input/rml-guide-example-09.rml | 83 + z3c/rml/tests/input/rml-guide-example-10.rml | 89 + z3c/rml/tests/input/rml-guide-example-11.rml | 104 + z3c/rml/tests/input/rml-guide-example-12.rml | 238 + z3c/rml/tests/input/simple-layout.rml | 39 + z3c/rml/tests/input/special-text.rml | 41 + z3c/rml/tests/input/strapline.png | Bin 0 -> 7241 bytes z3c/rml/tests/input/symbols-set.rml | 523 + z3c/rml/tests/input/tag-addMapping.rml | 38 + z3c/rml/tests/input/tag-alias.rml | 25 + z3c/rml/tests/input/tag-barChart.rml | 74 + z3c/rml/tests/input/tag-barChart3d.rml | 71 + z3c/rml/tests/input/tag-barCodeFlowable.rml | 192 + z3c/rml/tests/input/tag-barcode.rml | 33 + z3c/rml/tests/input/tag-blockTable-1.rml | 29 + z3c/rml/tests/input/tag-blockTable-10.rml | 34 + z3c/rml/tests/input/tag-blockTable-2.rml | 47 + z3c/rml/tests/input/tag-blockTable-3.rml | 48 + z3c/rml/tests/input/tag-blockTable-4.rml | 52 + z3c/rml/tests/input/tag-blockTable-5.rml | 66 + z3c/rml/tests/input/tag-blockTable-6.rml | 65 + z3c/rml/tests/input/tag-blockTable-7.rml | 58 + z3c/rml/tests/input/tag-blockTable-8.rml | 52 + z3c/rml/tests/input/tag-blockTable-9.rml | 90 + .../tests/input/tag-blockTable-bulkData.rml | 27 + z3c/rml/tests/input/tag-blockTableStyle-2.rml | 99 + z3c/rml/tests/input/tag-blockTableStyle-3.rml | 35 + z3c/rml/tests/input/tag-blockTableStyle.rml | 197 + z3c/rml/tests/input/tag-bookmark.rml | 50 + z3c/rml/tests/input/tag-buttonField.rml | 21 + z3c/rml/tests/input/tag-circle.rml | 22 + z3c/rml/tests/input/tag-codesnippet.rml | 46 + z3c/rml/tests/input/tag-color.rml | 31 + z3c/rml/tests/input/tag-condPageBreak.rml | 21 + z3c/rml/tests/input/tag-cropMarks.rml | 23 + z3c/rml/tests/input/tag-curves.rml | 16 + z3c/rml/tests/input/tag-doc.rml | 41 + .../input/tag-docinit-viewer-options.rml | 35 + .../tests/input/tag-document-annotations.rml | 21 + .../tests/input/tag-document-pageDrawing.rml | 11 + z3c/rml/tests/input/tag-document-story.rml | 17 + z3c/rml/tests/input/tag-drawAlignedString.rml | 58 + .../tests/input/tag-drawCenteredString.rml | 14 + z3c/rml/tests/input/tag-drawRightString.rml | 15 + z3c/rml/tests/input/tag-drawString.rml | 12 + z3c/rml/tests/input/tag-ellipse.rml | 22 + z3c/rml/tests/input/tag-fill.rml | 11 + z3c/rml/tests/input/tag-fixedSize.rml | 48 + z3c/rml/tests/input/tag-grid.rml | 16 + z3c/rml/tests/input/tag-hr.rml | 19 + z3c/rml/tests/input/tag-illustration.rml | 36 + z3c/rml/tests/input/tag-image-1.rml | 23 + z3c/rml/tests/input/tag-image-svg.rml | 31 + z3c/rml/tests/input/tag-image.rml | 23 + .../tests/input/tag-imageAndFlowables-svg.rml | 58 + z3c/rml/tests/input/tag-imageAndFlowables.rml | 57 + z3c/rml/tests/input/tag-img.rml | 40 + z3c/rml/tests/input/tag-includePdfPages.rml | 39 + z3c/rml/tests/input/tag-indent.rml | 54 + z3c/rml/tests/input/tag-index.rml | 44 + z3c/rml/tests/input/tag-keepInFrame.rml | 54 + z3c/rml/tests/input/tag-keepTogether.rml | 68 + z3c/rml/tests/input/tag-lineMode.rml | 11 + z3c/rml/tests/input/tag-linePlot.rml | 95 + z3c/rml/tests/input/tag-linePlot3D.rml | 95 + z3c/rml/tests/input/tag-lines.rml | 16 + z3c/rml/tests/input/tag-log.rml | 39 + z3c/rml/tests/input/tag-mergePage.rml | 84 + z3c/rml/tests/input/tag-name.rml | 28 + z3c/rml/tests/input/tag-nextFrame.rml | 19 + z3c/rml/tests/input/tag-nextPage.rml | 19 + z3c/rml/tests/input/tag-outlineAdd.rml | 19 + z3c/rml/tests/input/tag-pageGraphics.rml | 20 + z3c/rml/tests/input/tag-pageInfo-2.rml | 13 + z3c/rml/tests/input/tag-pageInfo.rml | 13 + z3c/rml/tests/input/tag-para-border.rml | 30 + z3c/rml/tests/input/tag-para-wordWrap.rml | 40 + z3c/rml/tests/input/tag-para.rml | 39 + z3c/rml/tests/input/tag-path.rml | 57 + z3c/rml/tests/input/tag-pieChart.rml | 87 + z3c/rml/tests/input/tag-pieChart3d.rml | 73 + z3c/rml/tests/input/tag-place.rml | 57 + z3c/rml/tests/input/tag-plugInFlowable.rml | 27 + z3c/rml/tests/input/tag-plugInGraphic.rml | 14 + z3c/rml/tests/input/tag-pre.rml | 24 + z3c/rml/tests/input/tag-pto.rml | 86 + z3c/rml/tests/input/tag-rectange.rml | 18 + z3c/rml/tests/input/tag-registerCidFont.rml | 25 + z3c/rml/tests/input/tag-registerTTFont.rml | 27 + z3c/rml/tests/input/tag-registerType1Face.rml | 24 + z3c/rml/tests/input/tag-rotate.rml | 19 + .../input/tag-saveState-restoreState.rml | 18 + z3c/rml/tests/input/tag-scale.rml | 19 + z3c/rml/tests/input/tag-selectField.rml | 37 + z3c/rml/tests/input/tag-setFont.rml | 13 + z3c/rml/tests/input/tag-setFontSize.rml | 15 + z3c/rml/tests/input/tag-setNextFrame.rml | 29 + z3c/rml/tests/input/tag-setNextTemplate.rml | 33 + z3c/rml/tests/input/tag-skew.rml | 19 + z3c/rml/tests/input/tag-spacer.rml | 32 + z3c/rml/tests/input/tag-spiderChart.rml | 76 + z3c/rml/tests/input/tag-storyPlace.rml | 32 + z3c/rml/tests/input/tag-stroke.rml | 11 + z3c/rml/tests/input/tag-textAnnotation.rml | 17 + z3c/rml/tests/input/tag-textField.rml | 31 + z3c/rml/tests/input/tag-transform.rml | 23 + z3c/rml/tests/input/tag-translate.rml | 19 + z3c/rml/tests/input/tag-ul-ol-li.rml | 88 + z3c/rml/tests/input/tag-xpre.rml | 34 + z3c/rml/tests/input/zope3logo.gif | Bin 0 -> 1506 bytes z3c/rml/tests/module.py | 78 + z3c/rml/tests/output/README.txt | 1 + z3c/rml/tests/test_directive.py | 52 + z3c/rml/tests/test_dtd.py | 31 + z3c/rml/tests/test_pagetemplate.py | 25 + z3c/rml/tests/test_reference.py | 31 + z3c/rml/tests/test_rml.py | 172 + z3c/rml/tests/test_subprocess.py | 57 + zope/__init__.py | 1 + zope/event/__init__.py | 31 + zope/event/tests.py | 48 + zope/interface/__init__.py | 89 + zope/interface/_compat.py | 69 + zope/interface/_flatten.py | 35 + .../_zope_interface_coptimizations.c | 1688 +++ zope/interface/adapter.py | 704 + zope/interface/advice.py | 206 + zope/interface/common/__init__.py | 2 + zope/interface/common/idatetime.py | 575 + zope/interface/common/interfaces.py | 102 + zope/interface/common/mapping.py | 125 + zope/interface/common/sequence.py | 160 + zope/interface/common/tests/__init__.py | 2 + zope/interface/common/tests/basemapping.py | 107 + zope/interface/common/tests/test_idatetime.py | 47 + .../common/tests/test_import_interfaces.py | 29 + zope/interface/declarations.py | 848 ++ zope/interface/document.py | 104 + zope/interface/exceptions.py | 67 + zope/interface/interface.py | 712 + zope/interface/interfaces.py | 1288 ++ zope/interface/registry.py | 530 + zope/interface/ro.py | 69 + zope/interface/tests/__init__.py | 13 + zope/interface/tests/advisory_testing.py | 42 + zope/interface/tests/dummy.py | 23 + zope/interface/tests/idummy.py | 23 + zope/interface/tests/ifoo.py | 26 + zope/interface/tests/ifoo_other.py | 26 + zope/interface/tests/m1.py | 21 + zope/interface/tests/m2.py | 15 + zope/interface/tests/odd.py | 129 + zope/interface/tests/test_adapter.py | 1285 ++ zope/interface/tests/test_advice.py | 397 + zope/interface/tests/test_declarations.py | 1576 +++ zope/interface/tests/test_document.py | 286 + zope/interface/tests/test_element.py | 41 + zope/interface/tests/test_exceptions.py | 75 + zope/interface/tests/test_interface.py | 2089 +++ zope/interface/tests/test_interfaces.py | 115 + zope/interface/tests/test_odd_declarations.py | 227 + zope/interface/tests/test_registry.py | 2454 ++++ zope/interface/tests/test_sorting.py | 55 + zope/interface/tests/test_verify.py | 571 + zope/interface/verify.py | 120 + zope/schema/__init__.py | 77 + zope/schema/_bootstrapfields.py | 441 + zope/schema/_bootstrapinterfaces.py | 120 + zope/schema/_compat.py | 58 + zope/schema/_field.py | 701 + zope/schema/_messageid.py | 20 + zope/schema/_schema.py | 90 + zope/schema/accessors.py | 120 + zope/schema/fieldproperty.py | 150 + zope/schema/interfaces.py | 764 ++ zope/schema/tests/__init__.py | 49 + zope/schema/tests/states.py | 130 + zope/schema/tests/test__bootstrapfields.py | 822 ++ .../schema/tests/test__bootstrapinterfaces.py | 68 + zope/schema/tests/test__field.py | 2122 +++ zope/schema/tests/test_accessors.py | 315 + zope/schema/tests/test_equality.py | 41 + zope/schema/tests/test_fieldproperty.py | 669 + zope/schema/tests/test_interfaces.py | 99 + zope/schema/tests/test_schema.py | 276 + zope/schema/tests/test_states.py | 106 + zope/schema/tests/test_vocabulary.py | 642 + zope/schema/vocabulary.py | 409 + 571 files changed, 143368 insertions(+), 6 deletions(-) delete mode 100644 reportlab.zip create mode 100644 reportlab/MANIFEST.in create mode 100644 reportlab/__init__.py create mode 100644 reportlab/fonts/00readme.txt create mode 100644 reportlab/fonts/DarkGarden-changelog.txt create mode 100644 reportlab/fonts/DarkGarden-copying-gpl.txt create mode 100644 reportlab/fonts/DarkGarden-copying.txt create mode 100644 reportlab/fonts/DarkGarden-readme.txt create mode 100644 reportlab/fonts/DarkGarden.sfd create mode 100644 reportlab/fonts/DarkGardenMK.afm create mode 100644 reportlab/fonts/DarkGardenMK.pfb create mode 100644 reportlab/fonts/Vera.ttf create mode 100644 reportlab/fonts/VeraBI.ttf create mode 100644 reportlab/fonts/VeraBd.ttf create mode 100644 reportlab/fonts/VeraIt.ttf create mode 100644 reportlab/fonts/bitstream-vera-license.txt create mode 100644 reportlab/graphics/__init__.py create mode 100644 reportlab/graphics/barcode/README create mode 100644 reportlab/graphics/barcode/TODO create mode 100644 reportlab/graphics/barcode/VERSION create mode 100644 reportlab/graphics/barcode/__init__.py create mode 100644 reportlab/graphics/barcode/code128.py create mode 100644 reportlab/graphics/barcode/code39.py create mode 100644 reportlab/graphics/barcode/code93.py create mode 100644 reportlab/graphics/barcode/common.py create mode 100644 reportlab/graphics/barcode/eanbc.py create mode 100644 reportlab/graphics/barcode/fourstate.py create mode 100644 reportlab/graphics/barcode/lto.py create mode 100644 reportlab/graphics/barcode/qr.py create mode 100644 reportlab/graphics/barcode/qrencoder.py create mode 100644 reportlab/graphics/barcode/test.py create mode 100644 reportlab/graphics/barcode/usps.py create mode 100644 reportlab/graphics/barcode/usps4s.py create mode 100644 reportlab/graphics/barcode/widgets.py create mode 100644 reportlab/graphics/charts/__init__.py create mode 100644 reportlab/graphics/charts/areas.py create mode 100644 reportlab/graphics/charts/axes.py create mode 100644 reportlab/graphics/charts/barcharts.py create mode 100644 reportlab/graphics/charts/dotbox.py create mode 100644 reportlab/graphics/charts/doughnut.py create mode 100644 reportlab/graphics/charts/legends.py create mode 100644 reportlab/graphics/charts/linecharts.py create mode 100644 reportlab/graphics/charts/lineplots.py create mode 100644 reportlab/graphics/charts/markers.py create mode 100644 reportlab/graphics/charts/piecharts.py create mode 100644 reportlab/graphics/charts/slidebox.py create mode 100644 reportlab/graphics/charts/spider.py create mode 100644 reportlab/graphics/charts/textlabels.py create mode 100644 reportlab/graphics/charts/utils.py create mode 100644 reportlab/graphics/charts/utils3d.py create mode 100644 reportlab/graphics/renderPDF.py create mode 100644 reportlab/graphics/renderPM.py create mode 100644 reportlab/graphics/renderPS.py create mode 100644 reportlab/graphics/renderSVG.py create mode 100644 reportlab/graphics/renderbase.py create mode 100644 reportlab/graphics/samples/__init__.py create mode 100644 reportlab/graphics/samples/bubble.py create mode 100644 reportlab/graphics/samples/clustered_bar.py create mode 100644 reportlab/graphics/samples/clustered_column.py create mode 100644 reportlab/graphics/samples/excelcolors.py create mode 100644 reportlab/graphics/samples/exploded_pie.py create mode 100644 reportlab/graphics/samples/filled_radar.py create mode 100644 reportlab/graphics/samples/line_chart.py create mode 100644 reportlab/graphics/samples/linechart_with_markers.py create mode 100644 reportlab/graphics/samples/radar.py create mode 100644 reportlab/graphics/samples/runall.py create mode 100644 reportlab/graphics/samples/scatter.py create mode 100644 reportlab/graphics/samples/scatter_lines.py create mode 100644 reportlab/graphics/samples/scatter_lines_markers.py create mode 100644 reportlab/graphics/samples/simple_pie.py create mode 100644 reportlab/graphics/samples/stacked_bar.py create mode 100644 reportlab/graphics/samples/stacked_column.py create mode 100644 reportlab/graphics/shapes.py create mode 100644 reportlab/graphics/testdrawings.py create mode 100644 reportlab/graphics/testshapes.py create mode 100644 reportlab/graphics/widgetbase.py create mode 100644 reportlab/graphics/widgets/__init__.py create mode 100644 reportlab/graphics/widgets/eventcal.py create mode 100644 reportlab/graphics/widgets/flags.py create mode 100644 reportlab/graphics/widgets/grids.py create mode 100644 reportlab/graphics/widgets/markers.py create mode 100644 reportlab/graphics/widgets/signsandsymbols.py create mode 100644 reportlab/graphics/widgets/table.py create mode 100644 reportlab/license.txt create mode 100644 reportlab/pdfbase/__init__.py create mode 100644 reportlab/pdfbase/_can_cmap_data.py create mode 100644 reportlab/pdfbase/_cidfontdata.py create mode 100644 reportlab/pdfbase/_fontdata.py create mode 100644 reportlab/pdfbase/_fontdata_enc_macexpert.py create mode 100644 reportlab/pdfbase/_fontdata_enc_macroman.py create mode 100644 reportlab/pdfbase/_fontdata_enc_pdfdoc.py create mode 100644 reportlab/pdfbase/_fontdata_enc_standard.py create mode 100644 reportlab/pdfbase/_fontdata_enc_symbol.py create mode 100644 reportlab/pdfbase/_fontdata_enc_winansi.py create mode 100644 reportlab/pdfbase/_fontdata_enc_zapfdingbats.py create mode 100644 reportlab/pdfbase/_fontdata_widths_courier.py create mode 100644 reportlab/pdfbase/_fontdata_widths_courierbold.py create mode 100644 reportlab/pdfbase/_fontdata_widths_courierboldoblique.py create mode 100644 reportlab/pdfbase/_fontdata_widths_courieroblique.py create mode 100644 reportlab/pdfbase/_fontdata_widths_helvetica.py create mode 100644 reportlab/pdfbase/_fontdata_widths_helveticabold.py create mode 100644 reportlab/pdfbase/_fontdata_widths_helveticaboldoblique.py create mode 100644 reportlab/pdfbase/_fontdata_widths_helveticaoblique.py create mode 100644 reportlab/pdfbase/_fontdata_widths_symbol.py create mode 100644 reportlab/pdfbase/_fontdata_widths_timesbold.py create mode 100644 reportlab/pdfbase/_fontdata_widths_timesbolditalic.py create mode 100644 reportlab/pdfbase/_fontdata_widths_timesitalic.py create mode 100644 reportlab/pdfbase/_fontdata_widths_timesroman.py create mode 100644 reportlab/pdfbase/_fontdata_widths_zapfdingbats.py create mode 100644 reportlab/pdfbase/cidfonts.py create mode 100644 reportlab/pdfbase/pdfdoc.py create mode 100644 reportlab/pdfbase/pdfform.py create mode 100644 reportlab/pdfbase/pdfmetrics.py create mode 100644 reportlab/pdfbase/pdfpattern.py create mode 100644 reportlab/pdfbase/pdfutils.py create mode 100644 reportlab/pdfbase/rl_codecs.py create mode 100644 reportlab/pdfbase/ttfonts.py create mode 100644 reportlab/pdfgen/__init__.py create mode 100644 reportlab/pdfgen/canvas.py create mode 100644 reportlab/pdfgen/pathobject.py create mode 100644 reportlab/pdfgen/pdfgeom.py create mode 100644 reportlab/pdfgen/pdfimages.py create mode 100644 reportlab/pdfgen/textobject.py create mode 100644 reportlab/platypus/__init__.py create mode 100644 reportlab/platypus/doctemplate.py create mode 100644 reportlab/platypus/figures.py create mode 100644 reportlab/platypus/flowables.py create mode 100644 reportlab/platypus/frames.py create mode 100644 reportlab/platypus/para.py create mode 100644 reportlab/platypus/paragraph.py create mode 100644 reportlab/platypus/paraparser.py create mode 100644 reportlab/platypus/tableofcontents.py create mode 100644 reportlab/platypus/tables.py create mode 100644 reportlab/platypus/xpreformatted.py create mode 100644 reportlab/rl_config.py create mode 100644 reportlab/rl_settings.py delete mode 100644 z3c.zip create mode 100644 z3c/__init__.py create mode 100644 z3c/rml/README.txt create mode 100644 z3c/rml/__init__.py create mode 100644 z3c/rml/attr.py create mode 100644 z3c/rml/canvas.py create mode 100644 z3c/rml/chart.py create mode 100644 z3c/rml/directive.py create mode 100644 z3c/rml/doclogic.py create mode 100644 z3c/rml/document.py create mode 100644 z3c/rml/dtd.py create mode 100644 z3c/rml/flowable.py create mode 100644 z3c/rml/form.py create mode 100644 z3c/rml/interfaces.py create mode 100644 z3c/rml/list.py create mode 100644 z3c/rml/occurence.py create mode 100644 z3c/rml/page.py create mode 100644 z3c/rml/pagetemplate.py create mode 100644 z3c/rml/pagetemplate.txt create mode 100644 z3c/rml/paraparser.py create mode 100644 z3c/rml/pdfinclude.py create mode 100644 z3c/rml/platypus.py create mode 100644 z3c/rml/reference.pt create mode 100644 z3c/rml/reference.py create mode 100644 z3c/rml/rlfix.py create mode 100644 z3c/rml/rml-reference.pdf create mode 100644 z3c/rml/rml.dtd create mode 100644 z3c/rml/rml2pdf.py create mode 100644 z3c/rml/rml2pdfscript.py create mode 100644 z3c/rml/special.py create mode 100644 z3c/rml/storyplace.py create mode 100644 z3c/rml/stylesheet.py create mode 100644 z3c/rml/template.py create mode 100644 z3c/rml/tests/__init__.py create mode 100644 z3c/rml/tests/expected/encoding-test-latin1.pdf create mode 100644 z3c/rml/tests/expected/encoding-test-utf8.pdf create mode 100644 z3c/rml/tests/expected/printScaling.pdf create mode 100644 z3c/rml/tests/expected/rml-examples-000-simple.pdf create mode 100644 z3c/rml/tests/expected/rml-examples-001-cmbox.pdf create mode 100644 z3c/rml/tests/expected/rml-examples-001-hello.pdf create mode 100644 z3c/rml/tests/expected/rml-examples-002-paras.pdf create mode 100644 z3c/rml/tests/expected/rml-examples-003-frames.pdf create mode 100644 z3c/rml/tests/expected/rml-examples-004-fpt-templates.pdf create mode 100644 z3c/rml/tests/expected/rml-examples-004-templates.pdf create mode 100644 z3c/rml/tests/expected/rml-examples-005-fonts.pdf create mode 100644 z3c/rml/tests/expected/rml-examples-006-barcodes.pdf create mode 100644 z3c/rml/tests/expected/rml-examples-008-tables.pdf create mode 100644 z3c/rml/tests/expected/rml-examples-009-splitting.pdf create mode 100644 z3c/rml/tests/expected/rml-examples-010-linkURL.pdf create mode 100644 z3c/rml/tests/expected/rml-examples-011-keepwithnext.pdf create mode 100644 z3c/rml/tests/expected/rml-examples-017-outlines.pdf create mode 100644 z3c/rml/tests/expected/rml-examples-022-paras-oas.pdf create mode 100644 z3c/rml/tests/expected/rml-examples-029-keepinframe.pdf create mode 100644 z3c/rml/tests/expected/rml-examples-031-japanese.pdf create mode 100644 z3c/rml/tests/expected/rml-examples-032-images.pdf create mode 100644 z3c/rml/tests/expected/rml-examples-034-cmyk.pdf create mode 100644 z3c/rml/tests/expected/rml-examples-035-numbering.pdf create mode 100644 z3c/rml/tests/expected/rml-examples-036-numbering-contd.pdf create mode 100644 z3c/rml/tests/expected/rml-examples-037-plugingraphic.pdf create mode 100644 z3c/rml/tests/expected/rml-examples-038-rect-href.pdf create mode 100644 z3c/rml/tests/expected/rml-examples-039-doc-programming.pdf create mode 100644 z3c/rml/tests/expected/rml-examples-040-colors.pdf create mode 100644 z3c/rml/tests/expected/rml-examples-041-masking.pdf create mode 100644 z3c/rml/tests/expected/rml-examples-042-longdoc.pdf create mode 100644 z3c/rml/tests/expected/rml-examples-043-headings.pdf create mode 100644 z3c/rml/tests/expected/rml-examples-044-codesnippets.pdf create mode 100644 z3c/rml/tests/expected/rml-examples-045-cmyk.pdf create mode 100644 z3c/rml/tests/expected/rml-examples-046-lists.pdf create mode 100644 z3c/rml/tests/expected/rml-examples-047-condPageBreak.pdf create mode 100644 z3c/rml/tests/expected/rml-examples-048-paragraph-flow-controls.pdf create mode 100644 z3c/rml/tests/expected/rml-examples-049-pre.pdf create mode 100644 z3c/rml/tests/expected/rml-guide-example-01.pdf create mode 100644 z3c/rml/tests/expected/rml-guide-example-02.pdf create mode 100644 z3c/rml/tests/expected/rml-guide-example-03.pdf create mode 100644 z3c/rml/tests/expected/rml-guide-example-04.pdf create mode 100644 z3c/rml/tests/expected/rml-guide-example-05.pdf create mode 100644 z3c/rml/tests/expected/rml-guide-example-06.pdf create mode 100644 z3c/rml/tests/expected/rml-guide-example-07.pdf create mode 100644 z3c/rml/tests/expected/rml-guide-example-08.pdf create mode 100644 z3c/rml/tests/expected/rml-guide-example-09.pdf create mode 100644 z3c/rml/tests/expected/rml-guide-example-10.pdf create mode 100644 z3c/rml/tests/expected/rml-guide-example-11.pdf create mode 100644 z3c/rml/tests/expected/rml-guide-example-12.pdf create mode 100644 z3c/rml/tests/expected/sample-shipment-chinese.pdf create mode 100644 z3c/rml/tests/expected/simple-layout.pdf create mode 100644 z3c/rml/tests/expected/special-text.pdf create mode 100644 z3c/rml/tests/expected/symbols-set.pdf create mode 100644 z3c/rml/tests/expected/tag-addMapping.pdf create mode 100644 z3c/rml/tests/expected/tag-alias.pdf create mode 100644 z3c/rml/tests/expected/tag-barChart.pdf create mode 100644 z3c/rml/tests/expected/tag-barChart3d.pdf create mode 100644 z3c/rml/tests/expected/tag-barCodeFlowable.pdf create mode 100644 z3c/rml/tests/expected/tag-barcode.pdf create mode 100644 z3c/rml/tests/expected/tag-blockTable-1.pdf create mode 100644 z3c/rml/tests/expected/tag-blockTable-10.pdf create mode 100644 z3c/rml/tests/expected/tag-blockTable-2.pdf create mode 100644 z3c/rml/tests/expected/tag-blockTable-3.pdf create mode 100644 z3c/rml/tests/expected/tag-blockTable-4.pdf create mode 100644 z3c/rml/tests/expected/tag-blockTable-5.pdf create mode 100644 z3c/rml/tests/expected/tag-blockTable-6.pdf create mode 100644 z3c/rml/tests/expected/tag-blockTable-7.pdf create mode 100644 z3c/rml/tests/expected/tag-blockTable-8.pdf create mode 100644 z3c/rml/tests/expected/tag-blockTable-9.pdf create mode 100644 z3c/rml/tests/expected/tag-blockTable-bulkData.pdf create mode 100644 z3c/rml/tests/expected/tag-blockTableStyle-2.pdf create mode 100644 z3c/rml/tests/expected/tag-blockTableStyle-3.pdf create mode 100644 z3c/rml/tests/expected/tag-blockTableStyle.pdf create mode 100644 z3c/rml/tests/expected/tag-bookmark.pdf create mode 100644 z3c/rml/tests/expected/tag-buttonField.pdf create mode 100644 z3c/rml/tests/expected/tag-circle.pdf create mode 100644 z3c/rml/tests/expected/tag-codesnippet.pdf create mode 100644 z3c/rml/tests/expected/tag-color.pdf create mode 100644 z3c/rml/tests/expected/tag-condPageBreak.pdf create mode 100644 z3c/rml/tests/expected/tag-cropMarks.pdf create mode 100644 z3c/rml/tests/expected/tag-curves.pdf create mode 100644 z3c/rml/tests/expected/tag-doc.pdf create mode 100644 z3c/rml/tests/expected/tag-docinit-viewer-options.pdf create mode 100644 z3c/rml/tests/expected/tag-document-annotations.pdf create mode 100644 z3c/rml/tests/expected/tag-document-pageDrawing.pdf create mode 100644 z3c/rml/tests/expected/tag-document-story.pdf create mode 100644 z3c/rml/tests/expected/tag-drawAlignedString.pdf create mode 100644 z3c/rml/tests/expected/tag-drawCenteredString.pdf create mode 100644 z3c/rml/tests/expected/tag-drawRightString.pdf create mode 100644 z3c/rml/tests/expected/tag-drawString.pdf create mode 100644 z3c/rml/tests/expected/tag-ellipse.pdf create mode 100644 z3c/rml/tests/expected/tag-fill.pdf create mode 100644 z3c/rml/tests/expected/tag-fixedSize.pdf create mode 100644 z3c/rml/tests/expected/tag-grid.pdf create mode 100644 z3c/rml/tests/expected/tag-hr.pdf create mode 100644 z3c/rml/tests/expected/tag-illustration.pdf create mode 100644 z3c/rml/tests/expected/tag-image-1.pdf create mode 100644 z3c/rml/tests/expected/tag-image-svg.pdf create mode 100644 z3c/rml/tests/expected/tag-image.pdf create mode 100644 z3c/rml/tests/expected/tag-imageAndFlowables-svg.pdf create mode 100644 z3c/rml/tests/expected/tag-imageAndFlowables.pdf create mode 100644 z3c/rml/tests/expected/tag-img.pdf create mode 100644 z3c/rml/tests/expected/tag-includePdfPages.pdf create mode 100644 z3c/rml/tests/expected/tag-indent.pdf create mode 100644 z3c/rml/tests/expected/tag-index.pdf create mode 100644 z3c/rml/tests/expected/tag-keepInFrame.pdf create mode 100644 z3c/rml/tests/expected/tag-keepTogether.pdf create mode 100644 z3c/rml/tests/expected/tag-lineMode.pdf create mode 100644 z3c/rml/tests/expected/tag-linePlot.pdf create mode 100644 z3c/rml/tests/expected/tag-linePlot3D.pdf create mode 100644 z3c/rml/tests/expected/tag-lines.pdf create mode 100644 z3c/rml/tests/expected/tag-log.pdf create mode 100644 z3c/rml/tests/expected/tag-mergePage.pdf create mode 100644 z3c/rml/tests/expected/tag-name.pdf create mode 100644 z3c/rml/tests/expected/tag-nextFrame.pdf create mode 100644 z3c/rml/tests/expected/tag-nextPage.pdf create mode 100644 z3c/rml/tests/expected/tag-outlineAdd.pdf create mode 100644 z3c/rml/tests/expected/tag-pageGraphics.pdf create mode 100644 z3c/rml/tests/expected/tag-pageInfo-2.pdf create mode 100644 z3c/rml/tests/expected/tag-pageInfo.pdf create mode 100644 z3c/rml/tests/expected/tag-para-border.pdf create mode 100644 z3c/rml/tests/expected/tag-para-wordWrap.pdf create mode 100644 z3c/rml/tests/expected/tag-para.pdf create mode 100644 z3c/rml/tests/expected/tag-path.pdf create mode 100644 z3c/rml/tests/expected/tag-pieChart.pdf create mode 100644 z3c/rml/tests/expected/tag-pieChart3d.pdf create mode 100644 z3c/rml/tests/expected/tag-place.pdf create mode 100644 z3c/rml/tests/expected/tag-plugInFlowable.pdf create mode 100644 z3c/rml/tests/expected/tag-plugInGraphic.pdf create mode 100644 z3c/rml/tests/expected/tag-pre.pdf create mode 100644 z3c/rml/tests/expected/tag-pto.pdf create mode 100644 z3c/rml/tests/expected/tag-rectange.pdf create mode 100644 z3c/rml/tests/expected/tag-registerCidFont.pdf create mode 100644 z3c/rml/tests/expected/tag-registerTTFont.pdf create mode 100644 z3c/rml/tests/expected/tag-registerType1Face.pdf create mode 100644 z3c/rml/tests/expected/tag-rotate.pdf create mode 100644 z3c/rml/tests/expected/tag-saveState-restoreState.pdf create mode 100644 z3c/rml/tests/expected/tag-scale.pdf create mode 100644 z3c/rml/tests/expected/tag-selectField.pdf create mode 100644 z3c/rml/tests/expected/tag-setFont.pdf create mode 100644 z3c/rml/tests/expected/tag-setFontSize.pdf create mode 100644 z3c/rml/tests/expected/tag-setNextFrame.pdf create mode 100644 z3c/rml/tests/expected/tag-setNextTemplate.pdf create mode 100644 z3c/rml/tests/expected/tag-skew.pdf create mode 100644 z3c/rml/tests/expected/tag-spacer.pdf create mode 100644 z3c/rml/tests/expected/tag-spiderChart.pdf create mode 100644 z3c/rml/tests/expected/tag-storyPlace.pdf create mode 100644 z3c/rml/tests/expected/tag-stroke.pdf create mode 100644 z3c/rml/tests/expected/tag-textAnnotation.pdf create mode 100644 z3c/rml/tests/expected/tag-textField.pdf create mode 100644 z3c/rml/tests/expected/tag-transform.pdf create mode 100644 z3c/rml/tests/expected/tag-translate.pdf create mode 100644 z3c/rml/tests/expected/tag-ul-ol-li.pdf create mode 100644 z3c/rml/tests/expected/tag-xpre.pdf create mode 100644 z3c/rml/tests/flowable.py create mode 100644 z3c/rml/tests/input/400x200.gif create mode 100644 z3c/rml/tests/input/VeraMono.ttf create mode 100644 z3c/rml/tests/input/data/fw2.pdf create mode 100644 z3c/rml/tests/input/data/include-bookmarks1.pdf create mode 100644 z3c/rml/tests/input/data/include-bookmarks2.pdf create mode 100644 z3c/rml/tests/input/data/include1.pdf create mode 100644 z3c/rml/tests/input/data/include2.pdf create mode 100644 z3c/rml/tests/input/encoding-test-latin1.rml create mode 100644 z3c/rml/tests/input/encoding-test-utf8.rml create mode 100644 z3c/rml/tests/input/images/cylinder.eps create mode 100644 z3c/rml/tests/input/images/cylinder.svg create mode 100644 z3c/rml/tests/input/images/cylinder.svgz create mode 100644 z3c/rml/tests/input/images/replogo.gif create mode 100644 z3c/rml/tests/input/logo_no_bar.png create mode 100644 z3c/rml/tests/input/printScaling.rml create mode 100644 z3c/rml/tests/input/rml-examples-000-simple.rml create mode 100644 z3c/rml/tests/input/rml-examples-001-cmbox.rml create mode 100644 z3c/rml/tests/input/rml-examples-001-hello.rml create mode 100644 z3c/rml/tests/input/rml-examples-002-paras.rml create mode 100644 z3c/rml/tests/input/rml-examples-003-frames.rml create mode 100644 z3c/rml/tests/input/rml-examples-004-fpt-templates.rml create mode 100644 z3c/rml/tests/input/rml-examples-004-templates.rml create mode 100644 z3c/rml/tests/input/rml-examples-005-fonts.rml create mode 100644 z3c/rml/tests/input/rml-examples-006-barcodes.rml create mode 100644 z3c/rml/tests/input/rml-examples-008-tables.rml create mode 100644 z3c/rml/tests/input/rml-examples-009-splitting.rml create mode 100644 z3c/rml/tests/input/rml-examples-010-linkURL.rml create mode 100644 z3c/rml/tests/input/rml-examples-011-keepwithnext.rml create mode 100644 z3c/rml/tests/input/rml-examples-017-outlines.rml create mode 100644 z3c/rml/tests/input/rml-examples-022-paras-oas.rml create mode 100644 z3c/rml/tests/input/rml-examples-029-keepinframe.rml create mode 100644 z3c/rml/tests/input/rml-examples-031-japanese.rml create mode 100644 z3c/rml/tests/input/rml-examples-032-images.rml create mode 100644 z3c/rml/tests/input/rml-examples-034-cmyk.rml create mode 100644 z3c/rml/tests/input/rml-examples-035-numbering.rml create mode 100644 z3c/rml/tests/input/rml-examples-036-numbering-contd.rml create mode 100644 z3c/rml/tests/input/rml-examples-037-plugingraphic.rml create mode 100644 z3c/rml/tests/input/rml-examples-038-rect-href.rml create mode 100644 z3c/rml/tests/input/rml-examples-039-doc-programming.rml create mode 100644 z3c/rml/tests/input/rml-examples-040-colors.rml create mode 100644 z3c/rml/tests/input/rml-examples-041-masking.rml create mode 100644 z3c/rml/tests/input/rml-examples-042-longdoc.rml create mode 100644 z3c/rml/tests/input/rml-examples-043-headings.rml create mode 100644 z3c/rml/tests/input/rml-examples-044-codesnippets.rml create mode 100644 z3c/rml/tests/input/rml-examples-045-cmyk.rml create mode 100644 z3c/rml/tests/input/rml-examples-046-lists.rml create mode 100644 z3c/rml/tests/input/rml-examples-047-condPageBreak.rml create mode 100644 z3c/rml/tests/input/rml-examples-048-paragraph-flow-controls.rml create mode 100644 z3c/rml/tests/input/rml-examples-049-pre.rml create mode 100644 z3c/rml/tests/input/rml-guide-example-01.rml create mode 100644 z3c/rml/tests/input/rml-guide-example-02.rml create mode 100644 z3c/rml/tests/input/rml-guide-example-03.rml create mode 100644 z3c/rml/tests/input/rml-guide-example-04.rml create mode 100644 z3c/rml/tests/input/rml-guide-example-05.rml create mode 100644 z3c/rml/tests/input/rml-guide-example-06.rml create mode 100644 z3c/rml/tests/input/rml-guide-example-07.rml create mode 100644 z3c/rml/tests/input/rml-guide-example-08.rml create mode 100644 z3c/rml/tests/input/rml-guide-example-09.rml create mode 100644 z3c/rml/tests/input/rml-guide-example-10.rml create mode 100644 z3c/rml/tests/input/rml-guide-example-11.rml create mode 100644 z3c/rml/tests/input/rml-guide-example-12.rml create mode 100644 z3c/rml/tests/input/simple-layout.rml create mode 100644 z3c/rml/tests/input/special-text.rml create mode 100644 z3c/rml/tests/input/strapline.png create mode 100644 z3c/rml/tests/input/symbols-set.rml create mode 100644 z3c/rml/tests/input/tag-addMapping.rml create mode 100644 z3c/rml/tests/input/tag-alias.rml create mode 100644 z3c/rml/tests/input/tag-barChart.rml create mode 100644 z3c/rml/tests/input/tag-barChart3d.rml create mode 100644 z3c/rml/tests/input/tag-barCodeFlowable.rml create mode 100644 z3c/rml/tests/input/tag-barcode.rml create mode 100644 z3c/rml/tests/input/tag-blockTable-1.rml create mode 100644 z3c/rml/tests/input/tag-blockTable-10.rml create mode 100644 z3c/rml/tests/input/tag-blockTable-2.rml create mode 100644 z3c/rml/tests/input/tag-blockTable-3.rml create mode 100644 z3c/rml/tests/input/tag-blockTable-4.rml create mode 100644 z3c/rml/tests/input/tag-blockTable-5.rml create mode 100644 z3c/rml/tests/input/tag-blockTable-6.rml create mode 100644 z3c/rml/tests/input/tag-blockTable-7.rml create mode 100644 z3c/rml/tests/input/tag-blockTable-8.rml create mode 100644 z3c/rml/tests/input/tag-blockTable-9.rml create mode 100644 z3c/rml/tests/input/tag-blockTable-bulkData.rml create mode 100644 z3c/rml/tests/input/tag-blockTableStyle-2.rml create mode 100644 z3c/rml/tests/input/tag-blockTableStyle-3.rml create mode 100644 z3c/rml/tests/input/tag-blockTableStyle.rml create mode 100644 z3c/rml/tests/input/tag-bookmark.rml create mode 100644 z3c/rml/tests/input/tag-buttonField.rml create mode 100644 z3c/rml/tests/input/tag-circle.rml create mode 100644 z3c/rml/tests/input/tag-codesnippet.rml create mode 100644 z3c/rml/tests/input/tag-color.rml create mode 100644 z3c/rml/tests/input/tag-condPageBreak.rml create mode 100644 z3c/rml/tests/input/tag-cropMarks.rml create mode 100644 z3c/rml/tests/input/tag-curves.rml create mode 100644 z3c/rml/tests/input/tag-doc.rml create mode 100644 z3c/rml/tests/input/tag-docinit-viewer-options.rml create mode 100644 z3c/rml/tests/input/tag-document-annotations.rml create mode 100644 z3c/rml/tests/input/tag-document-pageDrawing.rml create mode 100644 z3c/rml/tests/input/tag-document-story.rml create mode 100644 z3c/rml/tests/input/tag-drawAlignedString.rml create mode 100644 z3c/rml/tests/input/tag-drawCenteredString.rml create mode 100644 z3c/rml/tests/input/tag-drawRightString.rml create mode 100644 z3c/rml/tests/input/tag-drawString.rml create mode 100644 z3c/rml/tests/input/tag-ellipse.rml create mode 100644 z3c/rml/tests/input/tag-fill.rml create mode 100644 z3c/rml/tests/input/tag-fixedSize.rml create mode 100644 z3c/rml/tests/input/tag-grid.rml create mode 100644 z3c/rml/tests/input/tag-hr.rml create mode 100644 z3c/rml/tests/input/tag-illustration.rml create mode 100644 z3c/rml/tests/input/tag-image-1.rml create mode 100644 z3c/rml/tests/input/tag-image-svg.rml create mode 100644 z3c/rml/tests/input/tag-image.rml create mode 100644 z3c/rml/tests/input/tag-imageAndFlowables-svg.rml create mode 100644 z3c/rml/tests/input/tag-imageAndFlowables.rml create mode 100644 z3c/rml/tests/input/tag-img.rml create mode 100644 z3c/rml/tests/input/tag-includePdfPages.rml create mode 100644 z3c/rml/tests/input/tag-indent.rml create mode 100644 z3c/rml/tests/input/tag-index.rml create mode 100644 z3c/rml/tests/input/tag-keepInFrame.rml create mode 100644 z3c/rml/tests/input/tag-keepTogether.rml create mode 100644 z3c/rml/tests/input/tag-lineMode.rml create mode 100644 z3c/rml/tests/input/tag-linePlot.rml create mode 100644 z3c/rml/tests/input/tag-linePlot3D.rml create mode 100644 z3c/rml/tests/input/tag-lines.rml create mode 100644 z3c/rml/tests/input/tag-log.rml create mode 100644 z3c/rml/tests/input/tag-mergePage.rml create mode 100644 z3c/rml/tests/input/tag-name.rml create mode 100644 z3c/rml/tests/input/tag-nextFrame.rml create mode 100644 z3c/rml/tests/input/tag-nextPage.rml create mode 100644 z3c/rml/tests/input/tag-outlineAdd.rml create mode 100644 z3c/rml/tests/input/tag-pageGraphics.rml create mode 100644 z3c/rml/tests/input/tag-pageInfo-2.rml create mode 100644 z3c/rml/tests/input/tag-pageInfo.rml create mode 100644 z3c/rml/tests/input/tag-para-border.rml create mode 100644 z3c/rml/tests/input/tag-para-wordWrap.rml create mode 100644 z3c/rml/tests/input/tag-para.rml create mode 100644 z3c/rml/tests/input/tag-path.rml create mode 100644 z3c/rml/tests/input/tag-pieChart.rml create mode 100644 z3c/rml/tests/input/tag-pieChart3d.rml create mode 100644 z3c/rml/tests/input/tag-place.rml create mode 100644 z3c/rml/tests/input/tag-plugInFlowable.rml create mode 100644 z3c/rml/tests/input/tag-plugInGraphic.rml create mode 100644 z3c/rml/tests/input/tag-pre.rml create mode 100644 z3c/rml/tests/input/tag-pto.rml create mode 100644 z3c/rml/tests/input/tag-rectange.rml create mode 100644 z3c/rml/tests/input/tag-registerCidFont.rml create mode 100644 z3c/rml/tests/input/tag-registerTTFont.rml create mode 100644 z3c/rml/tests/input/tag-registerType1Face.rml create mode 100644 z3c/rml/tests/input/tag-rotate.rml create mode 100644 z3c/rml/tests/input/tag-saveState-restoreState.rml create mode 100644 z3c/rml/tests/input/tag-scale.rml create mode 100644 z3c/rml/tests/input/tag-selectField.rml create mode 100644 z3c/rml/tests/input/tag-setFont.rml create mode 100644 z3c/rml/tests/input/tag-setFontSize.rml create mode 100644 z3c/rml/tests/input/tag-setNextFrame.rml create mode 100644 z3c/rml/tests/input/tag-setNextTemplate.rml create mode 100644 z3c/rml/tests/input/tag-skew.rml create mode 100644 z3c/rml/tests/input/tag-spacer.rml create mode 100644 z3c/rml/tests/input/tag-spiderChart.rml create mode 100644 z3c/rml/tests/input/tag-storyPlace.rml create mode 100644 z3c/rml/tests/input/tag-stroke.rml create mode 100644 z3c/rml/tests/input/tag-textAnnotation.rml create mode 100644 z3c/rml/tests/input/tag-textField.rml create mode 100644 z3c/rml/tests/input/tag-transform.rml create mode 100644 z3c/rml/tests/input/tag-translate.rml create mode 100644 z3c/rml/tests/input/tag-ul-ol-li.rml create mode 100644 z3c/rml/tests/input/tag-xpre.rml create mode 100644 z3c/rml/tests/input/zope3logo.gif create mode 100644 z3c/rml/tests/module.py create mode 100644 z3c/rml/tests/output/README.txt create mode 100644 z3c/rml/tests/test_directive.py create mode 100644 z3c/rml/tests/test_dtd.py create mode 100644 z3c/rml/tests/test_pagetemplate.py create mode 100644 z3c/rml/tests/test_reference.py create mode 100644 z3c/rml/tests/test_rml.py create mode 100644 z3c/rml/tests/test_subprocess.py create mode 100644 zope/__init__.py create mode 100644 zope/event/__init__.py create mode 100644 zope/event/tests.py create mode 100644 zope/interface/__init__.py create mode 100644 zope/interface/_compat.py create mode 100644 zope/interface/_flatten.py create mode 100644 zope/interface/_zope_interface_coptimizations.c create mode 100644 zope/interface/adapter.py create mode 100644 zope/interface/advice.py create mode 100644 zope/interface/common/__init__.py create mode 100644 zope/interface/common/idatetime.py create mode 100644 zope/interface/common/interfaces.py create mode 100644 zope/interface/common/mapping.py create mode 100644 zope/interface/common/sequence.py create mode 100644 zope/interface/common/tests/__init__.py create mode 100644 zope/interface/common/tests/basemapping.py create mode 100644 zope/interface/common/tests/test_idatetime.py create mode 100644 zope/interface/common/tests/test_import_interfaces.py create mode 100644 zope/interface/declarations.py create mode 100644 zope/interface/document.py create mode 100644 zope/interface/exceptions.py create mode 100644 zope/interface/interface.py create mode 100644 zope/interface/interfaces.py create mode 100644 zope/interface/registry.py create mode 100644 zope/interface/ro.py create mode 100644 zope/interface/tests/__init__.py create mode 100644 zope/interface/tests/advisory_testing.py create mode 100644 zope/interface/tests/dummy.py create mode 100644 zope/interface/tests/idummy.py create mode 100644 zope/interface/tests/ifoo.py create mode 100644 zope/interface/tests/ifoo_other.py create mode 100644 zope/interface/tests/m1.py create mode 100644 zope/interface/tests/m2.py create mode 100644 zope/interface/tests/odd.py create mode 100644 zope/interface/tests/test_adapter.py create mode 100644 zope/interface/tests/test_advice.py create mode 100644 zope/interface/tests/test_declarations.py create mode 100644 zope/interface/tests/test_document.py create mode 100644 zope/interface/tests/test_element.py create mode 100644 zope/interface/tests/test_exceptions.py create mode 100644 zope/interface/tests/test_interface.py create mode 100644 zope/interface/tests/test_interfaces.py create mode 100644 zope/interface/tests/test_odd_declarations.py create mode 100644 zope/interface/tests/test_registry.py create mode 100644 zope/interface/tests/test_sorting.py create mode 100644 zope/interface/tests/test_verify.py create mode 100644 zope/interface/verify.py create mode 100644 zope/schema/__init__.py create mode 100644 zope/schema/_bootstrapfields.py create mode 100644 zope/schema/_bootstrapinterfaces.py create mode 100644 zope/schema/_compat.py create mode 100644 zope/schema/_field.py create mode 100644 zope/schema/_messageid.py create mode 100644 zope/schema/_schema.py create mode 100644 zope/schema/accessors.py create mode 100644 zope/schema/fieldproperty.py create mode 100644 zope/schema/interfaces.py create mode 100644 zope/schema/tests/__init__.py create mode 100644 zope/schema/tests/states.py create mode 100644 zope/schema/tests/test__bootstrapfields.py create mode 100644 zope/schema/tests/test__bootstrapinterfaces.py create mode 100644 zope/schema/tests/test__field.py create mode 100644 zope/schema/tests/test_accessors.py create mode 100644 zope/schema/tests/test_equality.py create mode 100644 zope/schema/tests/test_fieldproperty.py create mode 100644 zope/schema/tests/test_interfaces.py create mode 100644 zope/schema/tests/test_schema.py create mode 100644 zope/schema/tests/test_states.py create mode 100644 zope/schema/tests/test_vocabulary.py create mode 100644 zope/schema/vocabulary.py diff --git a/PyRIGS/settings.py b/PyRIGS/settings.py index 7b215ed2..3bd31598 100644 --- a/PyRIGS/settings.py +++ b/PyRIGS/settings.py @@ -12,12 +12,6 @@ https://docs.djangoproject.com/en/1.7/ref/settings/ import os BASE_DIR = os.path.dirname(os.path.dirname(__file__)) -# Add report lab things -import sys -sys.path.insert(0,'reportlab.zip') -sys.path.insert(0,'z3c.zip') - - # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/1.7/howto/deployment/checklist/ diff --git a/reportlab.zip b/reportlab.zip deleted file mode 100644 index 09121830b10fe0ac56a694d2d9219c106a51a42a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1057220 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

!#{JPIU>jw5%p!n|=7 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 z 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%0DUB>@I& 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 z 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 pDFs4MK3RG$?IamQ@?I~>mRB{X801ZuRkkF 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�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

% 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

',' (errors)') + html.append('') + html.extend(errs) + html.append(htmlBottom) + htmlFileName = os.path.join(outDir, 'pm-index.html') + open(htmlFileName, 'w').writelines(html) + if sys.platform=='mac': + from reportlab.lib.utils import markfilename + markfilename(htmlFileName,ext='HTML') + if shout or verbose>2: print('wrote %s' % htmlFileName) + +if __name__=='__main__': + test(shout=True) diff --git a/reportlab/graphics/renderPS.py b/reportlab/graphics/renderPS.py new file mode 100644 index 00000000..72d5b260 --- /dev/null +++ b/reportlab/graphics/renderPS.py @@ -0,0 +1,930 @@ +#Copyright ReportLab Europe Ltd. 2000-2012 +#see license.txt for license details +#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/graphics/renderPS.py +__version__=''' $Id$ ''' +__doc__="""Render drawing objects in Postscript""" + +from reportlab.pdfbase.pdfmetrics import getFont, stringWidth, unicode2T1 # for font info +from reportlab.lib.utils import getBytesIO, getStringIO, asBytes, char2int, rawBytes, asNative, isUnicode +from reportlab.lib.rl_accel import fp_str +from reportlab.lib.colors import black +from reportlab.graphics.renderbase import Renderer, StateTracker, getStateDelta, renderScaledDrawing +from reportlab.graphics.shapes import STATE_DEFAULTS +import math +from operator import getitem +from reportlab import rl_config +_ESCAPEDICT={} +for c in xrange(256): + if c<32 or c>=127: + _ESCAPEDICT[c]= '\\%03o' % c + elif c in (ord('\\'),ord('('),ord(')')): + _ESCAPEDICT[c] = '\\'+chr(c) + else: + _ESCAPEDICT[c] = chr(c) +del c + +def _escape_and_limit(s): + s = asBytes(s) + R = [] + aR = R.append + n = 0 + for c in s: + c = _ESCAPEDICT[char2int(c)] + aR(c) + n += len(c) + if n>=200: + n = 0 + aR('\\\n') + return ''.join(R) + +# we need to create encoding vectors for each font we use, or they will + # come out in Adobe's old StandardEncoding, which NOBODY uses. +PS_WinAnsiEncoding=""" +/RE { %def + findfont begin + currentdict dup length dict begin + { %forall + 1 index /FID ne { def } { pop pop } ifelse + } forall + /FontName exch def dup length 0 ne { %if + /Encoding Encoding 256 array copy def + 0 exch { %forall + dup type /nametype eq { %ifelse + Encoding 2 index 2 index put + pop 1 add + }{ %else + exch pop + } ifelse + } forall + } if pop + currentdict dup end end + /FontName get exch definefont pop +} bind def + +/WinAnsiEncoding [ + 39/quotesingle 96/grave 128/euro 130/quotesinglbase/florin/quotedblbase + /ellipsis/dagger/daggerdbl/circumflex/perthousand + /Scaron/guilsinglleft/OE 145/quoteleft/quoteright + /quotedblleft/quotedblright/bullet/endash/emdash + /tilde/trademark/scaron/guilsinglright/oe/dotlessi + 159/Ydieresis 164/currency 166/brokenbar 168/dieresis/copyright + /ordfeminine 172/logicalnot 174/registered/macron/ring + 177/plusminus/twosuperior/threesuperior/acute/mu + 183/periodcentered/cedilla/onesuperior/ordmasculine + 188/onequarter/onehalf/threequarters 192/Agrave/Aacute + /Acircumflex/Atilde/Adieresis/Aring/AE/Ccedilla + /Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute + /Icircumflex/Idieresis/Eth/Ntilde/Ograve/Oacute + /Ocircumflex/Otilde/Odieresis/multiply/Oslash + /Ugrave/Uacute/Ucircumflex/Udieresis/Yacute/Thorn + /germandbls/agrave/aacute/acircumflex/atilde/adieresis + /aring/ae/ccedilla/egrave/eacute/ecircumflex + /edieresis/igrave/iacute/icircumflex/idieresis + /eth/ntilde/ograve/oacute/ocircumflex/otilde + /odieresis/divide/oslash/ugrave/uacute/ucircumflex + /udieresis/yacute/thorn/ydieresis +] def +""" + +class PSCanvas: + def __init__(self,size=(300,300), PostScriptLevel=2): + self.width, self.height = size + xtraState = [] + self._xtraState_push = xtraState.append + self._xtraState_pop = xtraState.pop + self.comments = 0 + self.code = [] + self.code_append = self.code.append + self._sep = '\n' + self._strokeColor = self._fillColor = self._lineWidth = \ + self._font = self._fontSize = self._lineCap = \ + self._lineJoin = self._color = None + + self._fontsUsed = [] # track them as we go + self.setFont(STATE_DEFAULTS['fontName'],STATE_DEFAULTS['fontSize']) + self.setStrokeColor(STATE_DEFAULTS['strokeColor']) + self.setLineCap(2) + self.setLineJoin(0) + self.setLineWidth(1) + self.PostScriptLevel=PostScriptLevel + + def comment(self,msg): + if self.comments: self.code_append('%'+msg) + + def drawImage(self, image, x1,y1, x2=None,y2=None): # Postscript Level2 version + # select between postscript level 1 or level 2 + if self.PostScriptLevel==1: + self._drawImageLevel1(image, x1,y1, x2=None,y2=None) + elif self.PostScriptLevel==2: + self._drawImageLevel2(image, x1,y1, x2=None,y2=None) + else : + raise ValueError('Unsupported Postscript Level %s' % self.PostScriptLevel) + + def clear(self): + self.code_append('showpage') # ugh, this makes no sense oh well. + + def _t1_re_encode(self): + if not self._fontsUsed: return + # for each font used, reencode the vectors + C = [] + for fontName in self._fontsUsed: + fontObj = getFont(fontName) + if not fontObj._dynamicFont and fontObj.encName=='WinAnsiEncoding': + C.append('WinAnsiEncoding /%s /%s RE' % (fontName, fontName)) + if C: + C.insert(0,PS_WinAnsiEncoding) + self.code.insert(1, self._sep.join(C)) + + def save(self,f=None): + if not hasattr(f,'write'): + _f = open(f,'wb') + else: + _f = f + if self.code[-1]!='showpage': self.clear() + self.code.insert(0,'''\ +%%!PS-Adobe-3.0 EPSF-3.0 +%%%%BoundingBox: 0 0 %d %d +%%%% Initialization: +/m {moveto} bind def +/l {lineto} bind def +/c {curveto} bind def +''' % (self.width,self.height)) + + self._t1_re_encode() + _f.write(rawBytes(self._sep.join(self.code))) + if _f is not f: + _f.close() + from reportlab.lib.utils import markfilename + markfilename(f,creatorcode='XPR3',filetype='EPSF') + + def saveState(self): + self._xtraState_push((self._fontCodeLoc,)) + self.code_append('gsave') + + def restoreState(self): + self.code_append('grestore') + self._fontCodeLoc, = self._xtraState_pop() + + def stringWidth(self, s, font=None, fontSize=None): + """Return the logical width of the string if it were drawn + in the current font (defaults to self.font).""" + font = font or self._font + fontSize = fontSize or self._fontSize + return stringWidth(s, font, fontSize) + + def setLineCap(self,v): + if self._lineCap!=v: + self._lineCap = v + self.code_append('%d setlinecap'%v) + + def setLineJoin(self,v): + if self._lineJoin!=v: + self._lineJoin = v + self.code_append('%d setlinejoin'%v) + + def setDash(self, array=[], phase=0): + """Two notations. pass two numbers, or an array and phase""" + # copied and modified from reportlab.canvas + psoperation = "setdash" + if isinstance(array,(float,int)): + self.code_append('[%s %s] 0 %s' % (array, phase, psoperation)) + elif isinstance(array,(tuple,list)): + assert phase >= 0, "phase is a length in user space" + textarray = ' '.join(map(str, array)) + self.code_append('[%s] %s %s' % (textarray, phase, psoperation)) + + def setStrokeColor(self, color): + self._strokeColor = color + self.setColor(color) + + def setColor(self, color): + if self._color!=color: + self._color = color + if color: + if hasattr(color, "cyan"): + self.code_append('%s setcmykcolor' % fp_str(color.cyan, color.magenta, color.yellow, color.black)) + else: + self.code_append('%s setrgbcolor' % fp_str(color.red, color.green, color.blue)) + + def setFillColor(self, color): + self._fillColor = color + self.setColor(color) + + def setLineWidth(self, width): + if width != self._lineWidth: + self._lineWidth = width + self.code_append('%s setlinewidth' % width) + + def setFont(self,font,fontSize,leading=None): + if self._font!=font or self._fontSize!=fontSize: + self._fontCodeLoc = len(self.code) + self._font = font + self._fontSize = fontSize + self.code_append('') + + def line(self, x1, y1, x2, y2): + if self._strokeColor != None: + self.setColor(self._strokeColor) + self.code_append('%s m %s l stroke' % (fp_str(x1, y1), fp_str(x2, y2))) + + def _escape(self, s): + ''' + return a copy of string s with special characters in postscript strings + escaped with backslashes. + ''' + try: + return _escape_and_limit(s) + except: + raise ValueError("cannot escape %s" % ascii(s)) + + def _issueT1String(self,fontObj,x,y,s): + fc = fontObj + code_append = self.code_append + fontSize = self._fontSize + fontsUsed = self._fontsUsed + escape = self._escape + if not isUnicode(s): + try: + s = s.decode('utf8') + except UnicodeDecodeError as e: + i,j = e.args[2:4] + raise UnicodeDecodeError(*(e.args[:4]+('%s\n%s-->%s<--%s' % (e.args[4],s[i-10:i],s[i:j],s[j:j+10]),))) + + for f, t in unicode2T1(s,[fontObj]+fontObj.substitutionFonts): + if f!=fc: + psName = asNative(f.face.name) + code_append('(%s) findfont %s scalefont setfont' % (psName,fp_str(fontSize))) + if psName not in fontsUsed: + fontsUsed.append(psName) + fc = f + code_append('%s m (%s) show ' % (fp_str(x,y),escape(t))) + x += f.stringWidth(t.decode(f.encName),fontSize) + if fontObj!=fc: + self._font = None + self.setFont(fontObj.face.name,fontSize) + + def drawString(self, x, y, s, angle=0): + if self._fillColor != None: + fontObj = getFont(self._font) + if not self.code[self._fontCodeLoc]: + psName = asNative(fontObj.face.name) + self.code[self._fontCodeLoc]='(%s) findfont %s scalefont setfont' % (psName,fp_str(self._fontSize)) + if psName not in self._fontsUsed: + self._fontsUsed.append(psName) + self.setColor(self._fillColor) + if angle!=0: + self.code_append('gsave %s translate %s rotate' % (fp_str(x,y),fp_str(angle))) + x = y = 0 + if fontObj._dynamicFont: + s = self._escape(s) + self.code_append('%s m (%s) show ' % (fp_str(x,y),s)) + else: + self._issueT1String(fontObj,x,y,s) + if angle!=0: + self.code_append('grestore') + + def drawCentredString(self, x, y, text, text_anchor='middle'): + if self._fillColor is not None: + textLen = stringWidth(text, self._font,self._fontSize) + if text_anchor=='end': + x -= textLen + elif text_anchor=='middle': + x -= textLen/2. + elif text_anchor=='numeric': + x -= numericXShift(text_anchor,text,textLen,self._font,self._fontSize) + self.drawString(x,y,text) + + def drawRightString(self, text, x, y): + self.drawCentredString(text,x,y,text_anchor='end') + + def drawCurve(self, x1, y1, x2, y2, x3, y3, x4, y4, closed=0): + codeline = '%s m %s curveto' + data = (fp_str(x1, y1), fp_str(x2, y2, x3, y3, x4, y4)) + if self._fillColor != None: + self.setColor(self._fillColor) + self.code_append((codeline % data) + ' eofill') + if self._strokeColor != None: + self.setColor(self._strokeColor) + self.code_append((codeline % data) + + ((closed and ' closepath') or '') + + ' stroke') + + ######################################################################################## + + def rect(self, x1,y1, x2,y2, stroke=1, fill=1): + "Draw a rectangle between x1,y1, and x2,y2" + # Path is drawn in counter-clockwise direction" + + x1, x2 = min(x1,x2), max(x1, x2) # from piddle.py + y1, y2 = min(y1,y2), max(y1, y2) + self.polygon(((x1,y1),(x2,y1),(x2,y2),(x1,y2)), closed=1, stroke=stroke, fill = fill) + + def roundRect(self, x1,y1, x2,y2, rx=8, ry=8): + """Draw a rounded rectangle between x1,y1, and x2,y2, + with corners inset as ellipses with x radius rx and y radius ry. + These should have x10, and ry>0.""" + # Path is drawn in counter-clockwise direction + + x1, x2 = min(x1,x2), max(x1, x2) # from piddle.py + y1, y2 = min(y1,y2), max(y1, y2) + + # Note: arcto command draws a line from current point to beginning of arc + # save current matrix, translate to center of ellipse, scale by rx ry, and draw + # a circle of unit radius in counterclockwise dir, return to original matrix + # arguments are (cx, cy, rx, ry, startAngle, endAngle) + ellipsePath = 'matrix currentmatrix %s %s translate %s %s scale 0 0 1 %s %s arc setmatrix' + + # choice between newpath and moveTo beginning of arc + # go with newpath for precision, does this violate any assumptions in code??? + rr = ['newpath'] # Round Rect code path + a = rr.append + # upper left corner ellipse is first + a(ellipsePath % (x1+rx, y1+ry, rx, -ry, 90, 180)) + a(ellipsePath % (x1+rx, y2-ry, rx, -ry, 180, 270)) + a(ellipsePath % (x2-rx, y2-ry, rx, -ry, 270, 360)) + a(ellipsePath % (x2-rx, y1+ry, rx, -ry, 0, 90) ) + a('closepath') + + self._fillAndStroke(rr) + + def ellipse(self, x1,y1, x2,y2): + """Draw an orthogonal ellipse inscribed within the rectangle x1,y1,x2,y2. + These should have x1= 0: + arc='arc' + else: + arc='arcn' + data = (x,y, xScale, yScale, startAng, startAng+extent, arc) + + return codeline % data + + def polygon(self, p, closed=0, stroke=1, fill=1): + assert len(p) >= 2, 'Polygon must have 2 or more points' + + start = p[0] + p = p[1:] + + poly = [] + a = poly.append + a("%s m" % fp_str(start)) + for point in p: + a("%s l" % fp_str(point)) + if closed: + a("closepath") + + self._fillAndStroke(poly,stroke=stroke,fill=fill) + + def lines(self, lineList, color=None, width=None): + if self._strokeColor != None: + self._setColor(self._strokeColor) + codeline = '%s m %s l stroke' + for line in lineList: + self.code_append(codeline % (fp_str(line[0]),fp_str(line[1]))) + + def moveTo(self,x,y): + self.code_append('%s m' % fp_str(x, y)) + + def lineTo(self,x,y): + self.code_append('%s l' % fp_str(x, y)) + + def curveTo(self,x1,y1,x2,y2,x3,y3): + self.code_append('%s c' % fp_str(x1,y1,x2,y2,x3,y3)) + + def closePath(self): + self.code_append('closepath') + + def polyLine(self, p): + assert len(p) >= 1, 'Polyline must have 1 or more points' + if self._strokeColor != None: + self.setColor(self._strokeColor) + self.moveTo(p[0][0], p[0][1]) + for t in p[1:]: + self.lineTo(t[0], t[1]) + self.code_append('stroke') + + def drawFigure(self, partList, closed=0): + figureCode = [] + a = figureCode.append + first = 1 + + for part in partList: + op = part[0] + args = list(part[1:]) + + if op == figureLine: + if first: + first = 0 + a("%s m" % fp_str(args[:2])) + else: + a("%s l" % fp_str(args[:2])) + a("%s l" % fp_str(args[2:])) + + elif op == figureArc: + first = 0 + x1,y1,x2,y2,startAngle,extent = args[:6] + a(self._genArcCode(x1,y1,x2,y2,startAngle,extent)) + + elif op == figureCurve: + if first: + first = 0 + a("%s m" % fp_str(args[:2])) + else: + a("%s l" % fp_str(args[:2])) + a("%s curveto" % fp_str(args[2:])) + else: + raise TypeError("unknown figure operator: "+op) + + if closed: + a("closepath") + self._fillAndStroke(figureCode) + + def _fillAndStroke(self,code,clip=0,fill=1,stroke=1): + fill = self._fillColor and fill + stroke = self._strokeColor and stroke + if fill or stroke or clip: + self.code.extend(code) + if fill: + if stroke or clip: self.code_append("gsave") + self.setColor(self._fillColor) + self.code_append("eofill") + if stroke or clip: self.code_append("grestore") + if stroke: + if clip: self.code_append("gsave") + self.setColor(self._strokeColor) + self.code_append("stroke") + if clip: self.code_append("grestore") + if clip: + self.code_append("clip") + self.code_append("newpath") + + def translate(self,x,y): + self.code_append('%s translate' % fp_str(x,y)) + + def scale(self,x,y): + self.code_append('%s scale' % fp_str(x,y)) + + def transform(self,a,b,c,d,e,f): + self.code_append('[%s] concat' % fp_str(a,b,c,d,e,f)) + + def _drawTimeResize(self,w,h): + '''if this is used we're probably in the wrong world''' + self.width, self.height = w, h + + ############################################################################################ + # drawImage(self. image, x1, y1, x2=None, y2=None) is now defined by either _drawImageLevel1 + # ._drawImageLevel2, the choice is made in .__init__ depending on option + def _drawImageLevel1(self, image, x1, y1, x2=None,y2=None): + # Postscript Level1 version available for fallback mode when Level2 doesn't work + """drawImage(self,image,x1,y1,x2=None,y2=None) : If x2 and y2 are ommitted, they are + calculated from image size. (x1,y1) is upper left of image, (x2,y2) is lower right of + image in piddle coordinates.""" + # For now let's start with 24 bit RGB images (following piddlePDF again) + component_depth = 8 + myimage = image.convert('RGB') + imgwidth, imgheight = myimage.size + if not x2: + x2 = imgwidth + x1 + if not y2: + y2 = y1 + imgheight + drawwidth = x2 - x1 + drawheight = y2 - y1 + #print 'Image size (%d, %d); Draw size (%d, %d)' % (imgwidth, imgheight, drawwidth, drawheight) + # now I need to tell postscript how big image is + + # "image operators assume that they receive sample data from + # their data source in x-axis major index order. The coordinate + # of the lower-left corner of the first sample is (0,0), of the + # second (1,0) and so on" -PS2 ref manual p. 215 + # + # The ImageMatrix maps unit squre of user space to boundary of the source image + # + + # The CurrentTransformationMatrix (CTM) maps the unit square of + # user space to the rect...on the page that is to receive the + # image. A common ImageMatrix is [width 0 0 -height 0 height] + # (for a left to right, top to bottom image ) + + # first let's map the user coordinates start at offset x1,y1 on page + + self.code.extend([ + 'gsave', + '%s %s translate' % (x1,-y1 - drawheight), # need to start are lower left of image + '%s %s scale' % (drawwidth,drawheight), + '/scanline %d 3 mul string def' % imgwidth # scanline by multiples of image width + ]) + + # now push the dimensions and depth info onto the stack + # and push the ImageMatrix to map the source to the target rectangle (see above) + # finally specify source (PS2 pp. 225 ) and by exmample + self.code.extend([ + '%s %s %s' % (imgwidth, imgheight, component_depth), + '[%s %s %s %s %s %s]' % (imgwidth, 0, 0, -imgheight, 0, imgheight), + '{ currentfile scanline readhexstring pop } false 3', + 'colorimage ' + ]) + + # data source output--now we just need to deliver a hex encode + # series of lines of the right overall size can follow + # piddlePDF again + rawimage = (myimage.tobytes if hasattr(myimage,'tobytes') else myimage.tostring)() + hex_encoded = self._AsciiHexEncode(rawimage) + + # write in blocks of 78 chars per line + outstream = getStringIO(hex_encoded) + + dataline = outstream.read(78) + while dataline != "": + self.code_append(dataline) + dataline= outstream.read(78) + self.code_append('% end of image data') # for clarity + self.code_append('grestore') # return coordinates to normal + + # end of drawImage + def _AsciiHexEncode(self, input): # also based on piddlePDF + "Helper function used by images" + output = getStringIO() + for char in asBytes(input): + output.write('%02x' % char2int(char)) + return output.getvalue() + + def _drawImageLevel2(self, image, x1,y1, x2=None,y2=None): # Postscript Level2 version + '''At present we're handling only PIL''' + ### what sort of image are we to draw + if image.mode=='L' : + imBitsPerComponent = 8 + imNumComponents = 1 + myimage = image + elif image.mode == '1': + myimage = image.convert('L') + imNumComponents = 1 + myimage = image + else : + myimage = image.convert('RGB') + imNumComponents = 3 + imBitsPerComponent = 8 + + imwidth, imheight = myimage.size + if not x2: + x2 = imwidth + x1 + if not y2: + y2 = y1 + imheight + drawwidth = x2 - x1 + drawheight = y2 - y1 + self.code.extend([ + 'gsave', + '%s %s translate' % (x1,-y1 - drawheight), # need to start are lower left of image + '%s %s scale' % (drawwidth,drawheight)]) + + if imNumComponents == 3 : + self.code_append('/DeviceRGB setcolorspace') + elif imNumComponents == 1 : + self.code_append('/DeviceGray setcolorspace') + # create the image dictionary + self.code_append(""" +<< +/ImageType 1 +/Width %d /Height %d %% dimensions of source image +/BitsPerComponent %d""" % (imwidth, imheight, imBitsPerComponent) ) + + if imNumComponents == 1: + self.code_append('/Decode [0 1]') + if imNumComponents == 3: + self.code_append('/Decode [0 1 0 1 0 1] %% decode color values normally') + + self.code.extend([ '/ImageMatrix [%s 0 0 %s 0 %s]' % (imwidth, -imheight, imheight), + '/DataSource currentfile /ASCIIHexDecode filter', + '>> % End image dictionary', + 'image']) + # after image operator just need to dump image dat to file as hexstring + rawimage = (myimage.tobytes if hasattr(myimage,'tobytes') else myimage.tostring)() + hex_encoded = self._AsciiHexEncode(rawimage) + + # write in blocks of 78 chars per line + outstream = getStringIO(hex_encoded) + + dataline = outstream.read(78) + while dataline != "": + self.code_append(dataline) + dataline= outstream.read(78) + self.code_append('> % end of image data') # > is EOD for hex encoded filterfor clarity + self.code_append('grestore') # return coordinates to normal + +# renderpdf - draws them onto a canvas +"""Usage: + from reportlab.graphics import renderPS + renderPS.draw(drawing, canvas, x, y) +Execute the script to see some test drawings.""" +from reportlab.graphics.shapes import * + +# hack so we only get warnings once each +#warnOnce = WarnOnce() + +# the main entry point for users... +def draw(drawing, canvas, x=0, y=0, showBoundary=rl_config.showBoundary): + """As it says""" + R = _PSRenderer() + R.draw(renderScaledDrawing(drawing), canvas, x, y, showBoundary=showBoundary) + +def _pointsFromList(L): + ''' + given a list of coordinates [x0, y0, x1, y1....] + produce a list of points [(x0,y0), (y1,y0),....] + ''' + P=[] + a = P.append + for i in range(0,len(L),2): + a((L[i],L[i+1])) + return P + +class _PSRenderer(Renderer): + """This draws onto a EPS document. It needs to be a class + rather than a function, as some EPS-specific state tracking is + needed outside of the state info in the SVG model.""" + + def __init__(self): + self._tracker = StateTracker() + + def drawNode(self, node): + """This is the recursive method called for each node + in the tree""" + self._canvas.comment('begin node %r'%node) + color = self._canvas._color + if not (isinstance(node, Path) and node.isClipPath): + self._canvas.saveState() + + #apply state changes + deltas = getStateDelta(node) + self._tracker.push(deltas) + self.applyStateChanges(deltas, {}) + + #draw the object, or recurse + self.drawNodeDispatcher(node) + + rDeltas = self._tracker.pop() + if not (isinstance(node, Path) and node.isClipPath): + self._canvas.restoreState() + self._canvas.comment('end node %r'%node) + self._canvas._color = color + + #restore things we might have lost (without actually doing anything). + for k, v in rDeltas.items(): + if k in self._restores: + setattr(self._canvas,self._restores[k],v) + +## _restores = {'stroke':'_stroke','stroke_width': '_lineWidth','stroke_linecap':'_lineCap', +## 'stroke_linejoin':'_lineJoin','fill':'_fill','font_family':'_font', +## 'font_size':'_fontSize'} + _restores = {'strokeColor':'_strokeColor','strokeWidth': '_lineWidth','strokeLineCap':'_lineCap', + 'strokeLineJoin':'_lineJoin','fillColor':'_fillColor','fontName':'_font', + 'fontSize':'_fontSize'} + + def drawRect(self, rect): + if rect.rx == rect.ry == 0: + #plain old rectangle + self._canvas.rect( + rect.x, rect.y, + rect.x+rect.width, rect.y+rect.height) + else: + #cheat and assume ry = rx; better to generalize + #pdfgen roundRect function. TODO + self._canvas.roundRect( + rect.x, rect.y, + rect.x+rect.width, rect.y+rect.height, rect.rx, rect.ry + ) + + def drawLine(self, line): + if self._canvas._strokeColor: + self._canvas.line(line.x1, line.y1, line.x2, line.y2) + + def drawCircle(self, circle): + self._canvas.circle( circle.cx, circle.cy, circle.r) + + def drawWedge(self, wedge): + yradius, radius1, yradius1 = wedge._xtraRadii() + if (radius1==0 or radius1 is None) and (yradius1==0 or yradius1 is None) and not wedge.annular: + startangledegrees = wedge.startangledegrees + endangledegrees = wedge.endangledegrees + centerx= wedge.centerx + centery = wedge.centery + radius = wedge.radius + extent = endangledegrees - startangledegrees + self._canvas.drawArc(centerx-radius, centery-yradius, centerx+radius, centery+yradius, + startangledegrees, extent, fromcenter=1) + else: + P = wedge.asPolygon() + if isinstance(P,Path): + self.drawPath(P) + else: + self.drawPolygon(P) + + def drawPolyLine(self, p): + if self._canvas._strokeColor: + self._canvas.polyLine(_pointsFromList(p.points)) + + def drawEllipse(self, ellipse): + #need to convert to pdfgen's bounding box representation + x1 = ellipse.cx - ellipse.rx + x2 = ellipse.cx + ellipse.rx + y1 = ellipse.cy - ellipse.ry + y2 = ellipse.cy + ellipse.ry + self._canvas.ellipse(x1,y1,x2,y2) + + def drawPolygon(self, p): + self._canvas.polygon(_pointsFromList(p.points), closed=1) + + def drawString(self, stringObj): + if self._canvas._fillColor: + S = self._tracker.getState() + text_anchor, x, y, text = S['textAnchor'], stringObj.x,stringObj.y,stringObj.text + if not text_anchor in ['start','inherited']: + font, fontSize = S['fontName'], S['fontSize'] + textLen = stringWidth(text, font,fontSize) + if text_anchor=='end': + x -= textLen + elif text_anchor=='middle': + x -= textLen/2 + elif text_anchor=='numeric': + x -= numericXShift(text_anchor,text,textLen,font,fontSize,encoding='winansi') + else: + raise ValueError('bad value for text_anchor '+str(text_anchor)) + self._canvas.drawString(x,y,text) + + def drawPath(self, path): + from reportlab.graphics.shapes import _renderPath + c = self._canvas + drawFuncs = (c.moveTo, c.lineTo, c.curveTo, c.closePath) + isClosed = _renderPath(path, drawFuncs) + if not isClosed: + c._fillColor = None + c._fillAndStroke([], clip=path.isClipPath) + + def applyStateChanges(self, delta, newState): + """This takes a set of states, and outputs the operators + needed to set those properties""" + for key, value in delta.items(): + if key == 'transform': + self._canvas.transform(value[0], value[1], value[2], + value[3], value[4], value[5]) + elif key == 'strokeColor': + #this has different semantics in PDF to SVG; + #we always have a color, and either do or do + #not apply it; in SVG one can have a 'None' color + self._canvas.setStrokeColor(value) + elif key == 'strokeWidth': + self._canvas.setLineWidth(value) + elif key == 'strokeLineCap': #0,1,2 + self._canvas.setLineCap(value) + elif key == 'strokeLineJoin': + self._canvas.setLineJoin(value) + elif key == 'strokeDashArray': + if value: + if isinstance(value,(list,tuple)) and len(value)==2 and isinstance(value[1],(tuple,list)): + phase = value[0] + value = value[1] + else: + phase = 0 + self._canvas.setDash(value,phase) + else: + self._canvas.setDash() +## elif key == 'stroke_opacity': +## warnOnce('Stroke Opacity not supported yet') + elif key == 'fillColor': + #this has different semantics in PDF to SVG; + #we always have a color, and either do or do + #not apply it; in SVG one can have a 'None' color + self._canvas.setFillColor(value) +## elif key == 'fill_rule': +## warnOnce('Fill rules not done yet') +## elif key == 'fill_opacity': +## warnOnce('Fill opacity not done yet') + elif key in ['fontSize', 'fontName']: + # both need setting together in PDF + # one or both might be in the deltas, + # so need to get whichever is missing + fontname = delta.get('fontName', self._canvas._font) + fontsize = delta.get('fontSize', self._canvas._fontSize) + self._canvas.setFont(fontname, fontsize) + + def drawImage(self, image): + from reportlab.lib.utils import ImageReader + im = ImageReader(image.path) + x0 = image.x + y0 = image.y + x1 = image.width + if x1 is not None: x1 += x0 + y1 = image.height + if y1 is not None: y1 += y0 + self._canvas.drawImage(im._image,x0,y0,x1,y1) + +def drawToFile(d,fn, showBoundary=rl_config.showBoundary,**kwd): + d = renderScaledDrawing(d) + c = PSCanvas((d.width,d.height)) + draw(d, c, 0, 0, showBoundary=showBoundary) + c.save(fn) + +def drawToString(d, showBoundary=rl_config.showBoundary): + "Returns a PS as a string in memory, without touching the disk" + s = getBytesIO() + drawToFile(d, s, showBoundary=showBoundary) + return s.getvalue() + +######################################################### +# +# test code. First, defin a bunch of drawings. +# Routine to draw them comes at the end. +# +######################################################### +def test(outDir='epsout',shout=False): + from reportlab.graphics import testshapes + from reportlab.rl_config import verbose + OLDFONTS = testshapes._FONTS[:] + testshapes._FONTS[:] = ['Times-Roman','Times-Bold','Times-Italic', 'Times-BoldItalic','Courier'] + try: + import os + # save all drawings and their doc strings from the test file + if not os.path.isdir(outDir): + os.mkdir(outDir) + #grab all drawings from the test module + drawings = [] + + for funcname in dir(testshapes): + if funcname[0:10] == 'getDrawing': + drawing = eval('testshapes.' + funcname + '()') #execute it + docstring = eval('testshapes.' + funcname + '.__doc__') + drawings.append((drawing, docstring)) + + i = 0 + for (d, docstring) in drawings: + filename = outDir + os.sep + 'renderPS_%d.eps'%i + drawToFile(d,filename) + if shout or verbose>2: print('renderPS test saved %s' % ascii(filename)) + i += 1 + finally: + testshapes._FONTS[:] = OLDFONTS + +if __name__=='__main__': + import sys + if len(sys.argv)>1: + outdir = sys.argv[1] + else: + outdir = 'epsout' + test(outdir,shout=True) diff --git a/reportlab/graphics/renderSVG.py b/reportlab/graphics/renderSVG.py new file mode 100644 index 00000000..97ce3725 --- /dev/null +++ b/reportlab/graphics/renderSVG.py @@ -0,0 +1,929 @@ +__doc__="""An experimental SVG renderer for the ReportLab graphics framework. + +This will create SVG code from the ReportLab Graphics API (RLG). +To read existing SVG code and convert it into ReportLab graphics +objects download the svglib module here: + + http://python.net/~gherman/#svglib +""" + +import math, types, sys, os, codecs +from operator import getitem + +from reportlab.pdfbase.pdfmetrics import stringWidth # for font info +from reportlab.lib.rl_accel import fp_str +from reportlab.lib.colors import black +from reportlab.lib.utils import asNative +from reportlab.graphics.renderbase import StateTracker, getStateDelta, Renderer, renderScaledDrawing +from reportlab.graphics.shapes import STATE_DEFAULTS, Path, UserNode +from reportlab.graphics.shapes import * # (only for test0) +from reportlab import rl_config +from reportlab.lib.utils import getBytesIO, RLString, isPy3, isUnicode, isBytes + +from xml.dom import getDOMImplementation + +### some constants ### + +sin = math.sin +cos = math.cos +pi = math.pi + +AREA_STYLES = 'stroke-width stroke-linecap stroke stroke-opacity fill fill-opacity stroke-dasharray id'.split() +LINE_STYLES = 'stroke-width stroke-linecap stroke stroke-opacity stroke-dasharray id'.split() +TEXT_STYLES = 'font-family font-weight font-style font-variant font-size id'.split() + +### top-level user function ### +def drawToString(d, showBoundary=rl_config.showBoundary,**kwds): + "Returns a SVG as a string in memory, without touching the disk" + s = getBytesIO() + drawToFile(d, s, showBoundary=showBoundary,**kwds) + return s.getvalue() + +def drawToFile(d, fn, showBoundary=rl_config.showBoundary,**kwds): + d = renderScaledDrawing(d) + c = SVGCanvas((d.width, d.height),**kwds) + draw(d, c, 0, 0, showBoundary=showBoundary) + c.save(fn) + +def draw(drawing, canvas, x=0, y=0, showBoundary=rl_config.showBoundary): + """As it says.""" + r = _SVGRenderer() + r.draw(renderScaledDrawing(drawing), canvas, x, y, showBoundary=showBoundary) + +### helper functions ### +def _pointsFromList(L): + """ + given a list of coordinates [x0, y0, x1, y1....] + produce a list of points [(x0,y0), (y1,y0),....] + """ + + P=[] + for i in range(0,len(L), 2): + P.append((L[i], L[i+1])) + + return P + +def transformNode(doc, newTag, node=None, **attrDict): + """Transform a DOM node into new node and copy selected attributes. + + Creates a new DOM node with tag name 'newTag' for document 'doc' + and copies selected attributes from an existing 'node' as provided + in 'attrDict'. The source 'node' can be None. Attribute values will + be converted to strings. + + E.g. + + n = transformNode(doc, "node1", x="0", y="1") + -> DOM node for + + n = transformNode(doc, "node1", x=0, y=1+1) + -> DOM node for + + n = transformNode(doc, "node1", node0, x="x0", y="x0", zoo=bar()) + -> DOM node for + """ + + newNode = doc.createElement(newTag) + for newAttr, attr in attrDict.items(): + sattr = str(attr) + if not node: + newNode.setAttribute(newAttr, sattr) + else: + attrVal = node.getAttribute(sattr) + newNode.setAttribute(newAttr, attrVal or sattr) + + return newNode + +class EncodedWriter(list): + ''' + EncodedWriter(encoding) assumes .write will be called with + either unicode or utf8 encoded bytes. it will accumulate + unicode + ''' + BOMS = { + 'utf-32':codecs.BOM_UTF32, + 'utf-32-be':codecs.BOM_UTF32_BE, + 'utf-32-le':codecs.BOM_UTF32_LE, + 'utf-16':codecs.BOM_UTF16, + 'utf-16-be':codecs.BOM_UTF16_BE, + 'utf-16-le':codecs.BOM_UTF16_LE, + } + def __init__(self,encoding,bom=False): + list.__init__(self) + self.encoding = encoding = codecs.lookup(encoding).name + if bom and '16' in encoding or '32' in encoding: + self.write(self.BOMS[encoding]) + + def write(self,u): + if isBytes(u): + try: + u = u.decode('utf-8') + except: + et, ev, tb = sys.exc_info() + ev = str(ev) + del et, tb + raise ValueError("String %r not encoded as 'utf-8'\nerror=%s" % (u,ev)) + elif not isUnicode(u): + raise ValueError("EncodedWriter.write(%s) argument should be 'utf-8' bytes or str" % ascii(u)) + self.append(u) + + def getvalue(self): + r = ''.join(self) + del self[:] + return r + +### classes ### +class SVGCanvas: + def __init__(self, size=(300,300), encoding='utf-8', verbose=0, bom=False, **kwds): + ''' + verbose = 0 >0 means do verbose stuff + useClip = False True means don't use a clipPath definition put the global clip into the clip property + to get around an issue with safari + extraXmlDecl = '' use to add extra xml declarations + scaleGroupId = '' id of an extra group to add around the drawing to allow easy scaling + svgAttrs = {} dictionary of attributes to be applied to the svg tag itself + ''' + self.verbose = verbose + self.encoding = codecs.lookup(encoding).name + self.bom = bom + useClip = kwds.pop('useClip',False) + self.fontHacks = kwds.pop('fontHacks',{}) + self.extraXmlDecl = kwds.pop('extraXmlDecl','') + scaleGroupId = kwds.pop('scaleGroupId','') + + self.width, self.height = self.size = size + # self.height = size[1] + self.code = [] + self.style = {} + self.path = '' + self._strokeColor = self._fillColor = self._lineWidth = \ + self._font = self._fontSize = self._lineCap = \ + self._lineJoin = self._color = None + + implementation = getDOMImplementation('minidom') + #Based on official example here http://www.w3.org/TR/SVG10/linking.html want: + # + #Thus, + #doctype = implementation.createDocumentType("svg", + # "-//W3C//DTD SVG 20010904//EN", + # "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd") + # + #However, putting that example through http://validator.w3.org/ recommends: + # + #So we'll use that for our SVG 1.0 output. + doctype = implementation.createDocumentType("svg", + "-//W3C//DTD SVG 1.0//EN", + "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd") + self.doc = implementation.createDocument(None,"svg",doctype) + self.svg = self.doc.documentElement + svgAttrs = dict( + width = str(size[0]), + height=str(self.height), + preserveAspectRatio="xMinYMin meet", + viewBox="0 0 %d %d" % (self.width, self.height), + #baseProfile = "full", #disliked in V 1.0 + + #these suggested by Tim Roberts, as updated by peter@maubp.freeserve.co.uk + xmlns="http://www.w3.org/2000/svg", + version="1.0", + ) + svgAttrs["xmlns:xlink"] = "http://www.w3.org/1999/xlink" + svgAttrs.update(kwds.pop('svgAttrs',{})) + for k,v in svgAttrs.items(): + self.svg.setAttribute(k,v) + + title = self.doc.createElement('title') + text = self.doc.createTextNode('...') + title.appendChild(text) + self.svg.appendChild(title) + + desc = self.doc.createElement('desc') + text = self.doc.createTextNode('...') + desc.appendChild(text) + self.svg.appendChild(desc) + + self.setFont(STATE_DEFAULTS['fontName'], STATE_DEFAULTS['fontSize']) + self.setStrokeColor(STATE_DEFAULTS['strokeColor']) + self.setLineCap(2) + self.setLineJoin(0) + self.setLineWidth(1) + + if not useClip: + # Add a rectangular clipping path identical to view area. + clipPath = transformNode(self.doc, "clipPath", id="clip") + clipRect = transformNode(self.doc, "rect", x=0, y=0, + width=self.width, height=self.height) + clipPath.appendChild(clipRect) + self.svg.appendChild(clipPath) + gtkw = dict(style="clip-path: url(#clip)") + else: + gtkw = dict(clip="0 0 %d %d" % (self.width,self.height)) + + self.groupTree = transformNode(self.doc, "g", + id="group", + transform="scale(1,-1) translate(0,-%d)" % self.height, + **gtkw + ) + + if scaleGroupId: + self.scaleTree = transformNode(self.doc, "g", id=scaleGroupId, transform="scale(1,1)") + self.scaleTree.appendChild(self.groupTree) + self.svg.appendChild(self.scaleTree) + else: + self.svg.appendChild(self.groupTree) + self.currGroup = self.groupTree + + def save(self, fn=None): + writer = EncodedWriter(self.encoding,bom=self.bom) + self.doc.writexml(writer,addindent="\t",newl="\n",encoding=self.encoding) + + if hasattr(fn,'write'): + f = fn + else: + if isPy3: + f = open(fn, 'w',encoding=self.encoding) + else: + f = open(fn, 'w') + + svg = writer.getvalue() + exd = self.extraXmlDecl + if exd: + svg = svg.replace('?>','?>'+exd) + f.write(svg if isPy3 else svg.encode(self.encoding)) + if f is not fn: + f.close() + + ### helpers ### + def NOTUSED_stringWidth(self, s, font=None, fontSize=None): + """Return the logical width of the string if it were drawn + in the current font (defaults to self.font). + """ + + font = font or self._font + fontSize = fontSize or self._fontSize + + return stringWidth(s, font, fontSize) + + def _formatStyle(self, include=[], exclude='',**kwds): + style = self.style.copy() + style.update(kwds) + keys = list(style.keys()) + if include: + keys = [k for k in keys if k in include] + if exclude: + exclude = exclude.split() + items = [k+': '+str(style[k]) for k in keys if k not in exclude] + else: + items = [k+': '+str(style[k]) for k in keys] + return '; '.join(items) + ';' + + def _escape(self, s): + """ + return a copy of string s with special characters in postscript strings + escaped with backslashes. + Have not handled characters that are converted normally in python strings + i.e. \\n -> newline + """ + return s.replace(chr(0x5C), r'\\' ).replace('(', '\(' ).replace(')', '\)') + + def _genArcCode(self, x1, y1, x2, y2, startAng, extent): + """Calculate the path for an arc inscribed in rectangle defined + by (x1,y1),(x2,y2).""" + + return + + #calculate semi-minor and semi-major axes of ellipse + xScale = abs((x2-x1)/2.0) + yScale = abs((y2-y1)/2.0) + #calculate centre of ellipse + x, y = (x1+x2)/2.0, (y1+y2)/2.0 + + codeline = 'matrix currentmatrix %s %s translate %s %s scale 0 0 1 %s %s %s setmatrix' + + if extent >= 0: + arc='arc' + else: + arc='arcn' + data = (x,y, xScale, yScale, startAng, startAng+extent, arc) + + return codeline % data + + def _fillAndStroke(self, code, clip=0, link_info=None,styles=AREA_STYLES): + path = transformNode(self.doc, "path", + d=self.path, style=self._formatStyle(styles)) + if link_info : + path = self._add_link(path, link_info) + self.currGroup.appendChild(path) + self.path = '' + + + ### styles ### + def setLineCap(self, v): + vals = {0:'butt', 1:'round', 2:'square'} + if self._lineCap != v: + self._lineCap = v + self.style['stroke-linecap'] = vals[v] + + def setLineJoin(self, v): + vals = {0:'miter', 1:'round', 2:'bevel'} + if self._lineJoin != v: + self._lineJoin = v + self.style['stroke-linecap'] = vals[v] + + def setDash(self, array=[], phase=0): + """Two notations. Pass two numbers, or an array and phase.""" + + if isinstance(array,(float,int)): + self.style['stroke-dasharray'] = ', '.join(map(str, ([array, phase]))) + elif isinstance(array,(tuple,list)) and len(array) > 0: + assert phase >= 0, "phase is a length in user space" + self.style['stroke-dasharray'] = ', '.join(map(str, (array+[phase]))) + + def setStrokeColor(self, color): + self._strokeColor = color + self.setColor(color) + if color == None: + self.style['stroke'] = 'none' + else: + r, g, b = color.red, color.green, color.blue + self.style['stroke'] = 'rgb(%d%%,%d%%,%d%%)' % (r*100, g*100, b*100) + alpha = color.normalizedAlpha + if alpha!=1: + self.style['stroke-opacity'] = '%s' % alpha + elif 'stroke-opacity' in self.style: + del self.style['stroke-opacity'] + + def setColor(self, color): + if self._color != color: + self._color = color + + def setFillColor(self, color): + self._fillColor = color + self.setColor(color) + if color == None: + self.style['fill'] = 'none' + else: + r, g, b = color.red, color.green, color.blue + self.style['fill'] = 'rgb(%d%%,%d%%,%d%%)' % (r*100, g*100, b*100) + alpha = color.normalizedAlpha + if alpha!=1: + self.style['fill-opacity'] = '%s' % alpha + elif 'fill-opacity' in self.style: + del self.style['fill-opacity'] + + def setLineWidth(self, width): + if width != self._lineWidth: + self._lineWidth = width + self.style['stroke-width'] = width + + def setFont(self, font, fontSize): + if self._font != font or self._fontSize != fontSize: + self._font = font + self._fontSize = fontSize + style = self.style + for k in TEXT_STYLES: + if k in style: + del style[k] + svgAttrs = self.fontHacks[font] if font in self.fontHacks else {} + if isinstance(font,RLString): + svgAttrs.update(iter(font.svgAttrs.items())) + if svgAttrs: + for k,v in svgAttrs.items(): + a = 'font-'+k + if a in TEXT_STYLES: + style[a] = v + if 'font-family' not in style: + style['font-family'] = font + style['font-size'] = '%spx' % fontSize + + def _add_link(self, dom_object, link_info) : + assert isinstance(link_info, dict) + link = transformNode(self.doc, "a", **link_info) + link.appendChild(dom_object) + return link + + ### shapes ### + def rect(self, x1,y1, x2,y2, rx=8, ry=8, link_info=None, **_svgAttrs): + "Draw a rectangle between x1,y1 and x2,y2." + + if self.verbose: print("+++ SVGCanvas.rect") + + x = min(x1,x2) + y = min(y1,y2) + kwds = {} + rect = transformNode(self.doc, "rect", + x=x, y=y, width=max(x1,x2)-x, height=max(y1,y2)-y, + style=self._formatStyle(AREA_STYLES),**_svgAttrs) + + if link_info : + rect = self._add_link(rect, link_info) + + self.currGroup.appendChild(rect) + + def roundRect(self, x1,y1, x2,y2, rx=8, ry=8, link_info=None, **_svgAttrs): + """Draw a rounded rectangle between x1,y1 and x2,y2. + + Corners inset as ellipses with x-radius rx and y-radius ry. + These should have x10, and ry>0. + """ + + kwds = {} + rect = transformNode(self.doc, "rect", + x=x1, y=y1, width=x2-x1, height=y2-y1, rx=rx, ry=ry, + style=self._formatStyle(AREA_STYLES), **_svgAttrs) + + if link_info: + rect = self._add_link(rect, link_info) + + self.currGroup.appendChild(rect) + + def drawString(self, s, x, y, angle=0, link_info=None,**_svgAttrs): + s = asNative(s) + if self.verbose: print("+++ SVGCanvas.drawString") + + if self._fillColor != None: + self.setColor(self._fillColor) + s = self._escape(s) + st = self._formatStyle(TEXT_STYLES) + if angle != 0: + st = st + " rotate(%f %f %f);" % (angle, x, y) + st = st + " fill: %s;" % self.style['fill'] + text = transformNode(self.doc, "text", + x=x, y=y, style=st, + transform="translate(0,%d) scale(1,-1)" % (2*y), + **_svgAttrs + ) + content = self.doc.createTextNode(s) + text.appendChild(content) + + if link_info: + text = self._add_link(text, link_info) + + self.currGroup.appendChild(text) + + def drawCentredString(self, s, x, y, angle=0, text_anchor='middle', link_info=None): + if self.verbose: print("+++ SVGCanvas.drawCentredString") + + if self._fillColor != None: + if not text_anchor in ['start', 'inherited']: + textLen = stringWidth(s,self._font,self._fontSize) + if text_anchor=='end': + x -= textLen + elif text_anchor=='middle': + x -= textLen/2. + elif text_anchor=='numeric': + x -= numericXShift(text_anchor,s,textLen,self._font,self._fontSize) + else: + raise ValueError('bad value for text_anchor ' + str(text_anchor)) + self.drawString(x,y,text,angle=angle, link_info=link_info) + + def drawRightString(self, text, x, y, angle=0, link_info=None): + self.drawCentredString(text,x,y,angle=angle,text_anchor='end', link_info=link_info) + + def comment(self, data): + "Add a comment." + + comment = self.doc.createComment(data) + # self.currGroup.appendChild(comment) + + def drawImage(self, image, x1, y1, x2=None, y2=None): + pass + + def line(self, x1, y1, x2, y2): + if self._strokeColor != None: + if 0: # something is wrong with line in my SVG viewer... + line = transformNode(self.doc, "line", + x=x1, y=y1, x2=x2, y2=y2, + style=self._formatStyle(LINE_STYLES)) + self.currGroup.appendChild(line) + path = transformNode(self.doc, "path", + d="M %f,%f L %f,%f Z" % (x1,y1,x2,y2), + style=self._formatStyle(LINE_STYLES)) + self.currGroup.appendChild(path) + + def ellipse(self, x1, y1, x2, y2, link_info=None): + """Draw an orthogonal ellipse inscribed within the rectangle x1,y1,x2,y2. + + These should have x1=180, 0, mx, my) + else: + str = str + "M %f, %f A %f, %f %d %d %d %f, %f Z " % \ + (mx, my, rx, ry, 0, extent>=180, 0, mx, my) + + if fromcenter: + str = str + "L %f, %f Z " % (cx, cy) + + path = transformNode(self.doc, "path", + d=str, style=self._formatStyle()) + self.currGroup.appendChild(path) + + def polygon(self, points, closed=0, link_info=None): + assert len(points) >= 2, 'Polygon must have 2 or more points' + + if self._strokeColor != None: + self.setColor(self._strokeColor) + pairs = [] + for i in range(len(points)): + pairs.append("%f %f" % (points[i])) + pts = ', '.join(pairs) + polyline = transformNode(self.doc, "polygon", + points=pts, style=self._formatStyle(AREA_STYLES)) + + if link_info: + polyline = self._add_link(polyline, link_info) + + self.currGroup.appendChild(polyline) + + # self._fillAndStroke(polyCode) + + def lines(self, lineList, color=None, width=None): + # print "### lineList", lineList + return + + if self._strokeColor != None: + self._setColor(self._strokeColor) + codeline = '%s m %s l stroke' + for line in lineList: + self.code.append(codeline % (fp_str(line[0]), fp_str(line[1]))) + + def polyLine(self, points): + assert len(points) >= 1, 'Polyline must have 1 or more points' + + if self._strokeColor != None: + self.setColor(self._strokeColor) + pairs = [] + for i in range(len(points)): + pairs.append("%f %f" % (points[i])) + pts = ', '.join(pairs) + polyline = transformNode(self.doc, "polyline", + points=pts, style=self._formatStyle(AREA_STYLES,fill=None)) + self.currGroup.appendChild(polyline) + + ### groups ### + def startGroup(self): + if self.verbose: print("+++ begin SVGCanvas.startGroup") + currGroup, group = self.currGroup, transformNode(self.doc, "g", transform="") + currGroup.appendChild(group) + self.currGroup = group + if self.verbose: print("+++ end SVGCanvas.startGroup") + return currGroup + + def endGroup(self,currGroup): + if self.verbose: print("+++ begin SVGCanvas.endGroup") + self.currGroup = currGroup + if self.verbose: print("+++ end SVGCanvas.endGroup") + + def transform(self, a, b, c, d, e, f): + if self.verbose: print("!!! begin SVGCanvas.transform", a, b, c, d, e, f) + tr = self.currGroup.getAttribute("transform") + t = 'matrix(%f, %f, %f, %f, %f, %f)' % (a,b,c,d,e,f) + if (a, b, c, d, e, f) != (1, 0, 0, 1, 0, 0): + self.currGroup.setAttribute("transform", "%s %s" % (tr, t)) + + def translate(self, x, y): + # probably never used + print("!!! begin SVGCanvas.translate") + return + + tr = self.currGroup.getAttribute("transform") + t = 'translate(%f, %f)' % (x, y) + self.currGroup.setAttribute("transform", "%s %s" % (tr, t)) + + def scale(self, x, y): + # probably never used + print("!!! begin SVGCanvas.scale") + return + + tr = self.groups[-1].getAttribute("transform") + t = 'scale(%f, %f)' % (x, y) + self.currGroup.setAttribute("transform", "%s %s" % (tr, t)) + + ### paths ### + def moveTo(self, x, y): + self.path = self.path + 'M %f %f ' % (x, y) + + def lineTo(self, x, y): + self.path = self.path + 'L %f %f ' % (x, y) + + def curveTo(self, x1, y1, x2, y2, x3, y3): + self.path = self.path + 'C %f %f %f %f %f %f ' % (x1, y1, x2, y2, x3, y3) + + def closePath(self): + self.path = self.path + 'Z ' + + def saveState(self): + pass + + def restoreState(self): + pass + +class _SVGRenderer(Renderer): + """This draws onto an SVG document. + """ + + def __init__(self): + self._tracker = StateTracker() + self.verbose = 0 + + def drawNode(self, node): + """This is the recursive method called for each node in the tree. + """ + + if self.verbose: print("### begin _SVGRenderer.drawNode(%r)" % node) + + self._canvas.comment('begin node %r'%node) + color = self._canvas._color + style = self._canvas.style.copy() + if not (isinstance(node, Path) and node.isClipPath): + pass # self._canvas.saveState() + + #apply state changes + deltas = getStateDelta(node) + self._tracker.push(deltas) + self.applyStateChanges(deltas, {}) + + #draw the object, or recurse + self.drawNodeDispatcher(node) + + rDeltas = self._tracker.pop() + if not (isinstance(node, Path) and node.isClipPath): + pass #self._canvas.restoreState() + self._canvas.comment('end node %r'%node) + self._canvas._color = color + + #restore things we might have lost (without actually doing anything). + for k, v in rDeltas.items(): + if k in self._restores: + setattr(self._canvas,self._restores[k],v) + self._canvas.style = style + + if self.verbose: print("### end _SVGRenderer.drawNode(%r)" % node) + + _restores = {'strokeColor':'_strokeColor','strokeWidth': '_lineWidth','strokeLineCap':'_lineCap', + 'strokeLineJoin':'_lineJoin','fillColor':'_fillColor','fontName':'_font', + 'fontSize':'_fontSize'} + + def _get_link_info_dict(self, obj): + #We do not want None or False as the link, even if it is the + #attribute's value - use the empty string instead. + url = getattr(obj, "hrefURL", "") or "" + title = getattr(obj, "hrefTitle", "") or "" + if url : + #Is it valid to have a link with no href? The XML requires + #the xlink:href to be present, but you might just want a + #tool tip shown (via the xlink:title attribute). Note that + #giving an href of "" is equivalent to "the current page" + #(a relative link saying go nowhere). + return {"xlink:href":url, "xlink:title":title, "target":"_top"} + #Currently of all the mainstream browsers I have tested, only Safari/webkit + #will show SVG images embedded in HTML using a simple tag. + #However, the links don't work (Safari 3.2.1 on the Mac). + # + #Therefore I use the following, which also works for Firefox, Opera, and + #IE 6.0 with Adobe SVG Viewer 6 beta: + # + # + #Once displayed, Firefox and Safari treat the SVG like a frame, and + #by default clicking on links acts "in frame" and replaces the image. + #Opera does what I expect, and replaces the whole page with the link. + # + #Therefore I use target="_top" to force the links to replace the whole page. + #This now works as expected on Safari 3.2.1, Firefox 3.0.6, Opera 9.20. + #Perhaps the target attribute should be an option, perhaps defaulting to + #"_top" as used here? + else : + return None + + def drawGroup(self, group): + if self.verbose: print("### begin _SVGRenderer.drawGroup") + + currGroup = self._canvas.startGroup() + a, b, c, d, e, f = self._tracker.getState()['transform'] + for childNode in group.getContents(): + if isinstance(childNode, UserNode): + node2 = childNode.provideNode() + else: + node2 = childNode + self.drawNode(node2) + self._canvas.transform(a, b, c, d, e, f) + self._canvas.endGroup(currGroup) + + if self.verbose: print("### end _SVGRenderer.drawGroup") + + def drawRect(self, rect): + link_info = self._get_link_info_dict(rect) + svgAttrs = getattr(rect,'_svgAttrs',{}) + if rect.rx == rect.ry == 0: + #plain old rectangle + self._canvas.rect( + rect.x, rect.y, + rect.x+rect.width, rect.y+rect.height, link_info=link_info, **svgAttrs) + else: + #cheat and assume ry = rx; better to generalize + #pdfgen roundRect function. TODO + self._canvas.roundRect( + rect.x, rect.y, + rect.x+rect.width, rect.y+rect.height, + rect.rx, rect.ry, + link_info=link_info, **svgAttrs) + + def drawString(self, stringObj): + if self._canvas._fillColor: + S = self._tracker.getState() + text_anchor, x, y, text = S['textAnchor'], stringObj.x, stringObj.y, stringObj.text + if not text_anchor in ('start', 'inherited'): + font, fontSize = S['fontName'], S['fontSize'] + textLen = stringWidth(text, font,fontSize) + if text_anchor=='end': + x -= textLen + elif text_anchor=='middle': + x -= textLen/2 + elif text_anchor=='numeric': + x -= numericXShift(text_anchor,text,textLen,font,fontSize) + else: + raise ValueError('bad value for text_anchor ' + str(text_anchor)) + self._canvas.drawString(text,x,y,link_info=self._get_link_info_dict(stringObj),**getattr(stringObj,'_svgAttrs',{})) + + def drawLine(self, line): + if self._canvas._strokeColor: + self._canvas.line(line.x1, line.y1, line.x2, line.y2) + + def drawCircle(self, circle): + self._canvas.circle( circle.cx, circle.cy, circle.r, link_info=self._get_link_info_dict(circle)) + + def drawWedge(self, wedge): + yradius, radius1, yradius1 = wedge._xtraRadii() + if (radius1==0 or radius1 is None) and (yradius1==0 or yradius1 is None) and not wedge.annular: + centerx, centery, radius, startangledegrees, endangledegrees = \ + wedge.centerx, wedge.centery, wedge.radius, wedge.startangledegrees, wedge.endangledegrees + yradius = wedge.yradius or wedge.radius + (x1, y1) = (centerx-radius, centery-yradius) + (x2, y2) = (centerx+radius, centery+yradius) + extent = endangledegrees - startangledegrees + self._canvas.drawArc(x1, y1, x2, y2, startangledegrees, extent, fromcenter=1) + else: + P = wedge.asPolygon() + if isinstance(P,Path): + self.drawPath(P) + else: + self.drawPolygon(P) + + def drawPolyLine(self, p): + if self._canvas._strokeColor: + self._canvas.polyLine(_pointsFromList(p.points)) + + def drawEllipse(self, ellipse): + #need to convert to pdfgen's bounding box representation + x1 = ellipse.cx - ellipse.rx + x2 = ellipse.cx + ellipse.rx + y1 = ellipse.cy - ellipse.ry + y2 = ellipse.cy + ellipse.ry + self._canvas.ellipse(x1,y1,x2,y2, link_info=self._get_link_info_dict(ellipse)) + + def drawPolygon(self, p): + self._canvas.polygon(_pointsFromList(p.points), closed=1, link_info=self._get_link_info_dict(p)) + + def drawPath(self, path): + # print "### drawPath", path.points + from reportlab.graphics.shapes import _renderPath + c = self._canvas + drawFuncs = (c.moveTo, c.lineTo, c.curveTo, c.closePath) + isClosed = _renderPath(path, drawFuncs) + if isClosed: + #Only try and add links to closed paths... + link_info = self._get_link_info_dict(path) + else : + c._fillColor = None + link_info = None + c._fillAndStroke([], clip=path.isClipPath, link_info=link_info) + + def applyStateChanges(self, delta, newState): + """This takes a set of states, and outputs the operators + needed to set those properties""" + + for key, value in delta.items(): + if key == 'transform': + pass + #self._canvas.transform(value[0], value[1], value[2], value[3], value[4], value[5]) + elif key == 'strokeColor': + self._canvas.setStrokeColor(value) + elif key == 'strokeWidth': + self._canvas.setLineWidth(value) + elif key == 'strokeLineCap': #0,1,2 + self._canvas.setLineCap(value) + elif key == 'strokeLineJoin': + self._canvas.setLineJoin(value) + elif key == 'strokeDashArray': + if value: + if isinstance(value,(list,tuple)) and len(value)==2 and isinstance(value[1],(tuple,list)): + phase = value[0] + value = value[1] + else: + phase = 0 + self._canvas.setDash(value,phase) + else: + self._canvas.setDash() + elif key == 'fillColor': + self._canvas.setFillColor(value) + elif key in ['fontSize', 'fontName']: + fontname = delta.get('fontName', self._canvas._font) + fontsize = delta.get('fontSize', self._canvas._fontSize) + self._canvas.setFont(fontname, fontsize) + +def test(outDir='out-svg'): + # print all drawings and their doc strings from the test + # file + if not os.path.isdir(outDir): + os.mkdir(outDir) + #grab all drawings from the test module + from reportlab.graphics import testshapes + drawings = [] + + for funcname in dir(testshapes): + #if funcname[0:11] == 'getDrawing2': + # print 'hacked to only show drawing 2' + if funcname[0:10] == 'getDrawing': + drawing = eval('testshapes.' + funcname + '()') + docstring = eval('testshapes.' + funcname + '.__doc__') + drawings.append((drawing, docstring)) + + + i = 0 + for (d, docstring) in drawings: + filename = os.path.join(outDir,'renderSVG_%d.svg' % i) + drawToFile(d, filename) + i += 1 + + from reportlab.graphics.testshapes import getDrawing01 + d = getDrawing01() + drawToFile(d, os.path.join(outDir,"test.svg")) + + from reportlab.lib.corp import RL_CorpLogo + from reportlab.graphics.shapes import Drawing + + rl = RL_CorpLogo() + d = Drawing(rl.width,rl.height) + d.add(rl) + drawToFile(d, os.path.join(outDir,"corplogo.svg")) + +if __name__=='__main__': + test() diff --git a/reportlab/graphics/renderbase.py b/reportlab/graphics/renderbase.py new file mode 100644 index 00000000..64a64cc8 --- /dev/null +++ b/reportlab/graphics/renderbase.py @@ -0,0 +1,357 @@ +#Copyright ReportLab Europe Ltd. 2000-2012 +#see license.txt for license details +#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/graphics/renderbase.py + +__version__=''' $Id $ ''' +__doc__='''Superclass for renderers to factor out common functionality and default implementations.''' + +from reportlab.graphics.shapes import * +from reportlab.lib.validators import DerivedValue +from reportlab import rl_config + +def inverse(A): + "For A affine 2D represented as 6vec return 6vec version of A**(-1)" + # I checked this RGB + det = float(A[0]*A[3] - A[2]*A[1]) + R = [A[3]/det, -A[1]/det, -A[2]/det, A[0]/det] + return tuple(R+[-R[0]*A[4]-R[2]*A[5],-R[1]*A[4]-R[3]*A[5]]) + +def mmult(A, B): + "A postmultiplied by B" + # I checked this RGB + # [a0 a2 a4] [b0 b2 b4] + # [a1 a3 a5] * [b1 b3 b5] + # [ 1 ] [ 1 ] + # + return (A[0]*B[0] + A[2]*B[1], + A[1]*B[0] + A[3]*B[1], + A[0]*B[2] + A[2]*B[3], + A[1]*B[2] + A[3]*B[3], + A[0]*B[4] + A[2]*B[5] + A[4], + A[1]*B[4] + A[3]*B[5] + A[5]) + + +def getStateDelta(shape): + """Used to compute when we need to change the graphics state. + For example, if we have two adjacent red shapes we don't need + to set the pen color to red in between. Returns the effect + the given shape would have on the graphics state""" + delta = {} + for prop, value in shape.getProperties().items(): + if prop in STATE_DEFAULTS: + delta[prop] = value + return delta + + +class StateTracker: + """Keeps a stack of transforms and state + properties. It can contain any properties you + want, but the keys 'transform' and 'ctm' have + special meanings. The getCTM() + method returns the current transformation + matrix at any point, without needing to + invert matrixes when you pop.""" + def __init__(self, defaults=None): + # one stack to keep track of what changes... + self._deltas = [] + + # and another to keep track of cumulative effects. Last one in + # list is the current graphics state. We put one in to simplify + # loops below. + self._combined = [] + if defaults is None: + defaults = STATE_DEFAULTS.copy() + #ensure that if we have a transform, we have a CTM + if 'transform' in defaults: + defaults['ctm'] = defaults['transform'] + self._combined.append(defaults) + + def push(self,delta): + """Take a new state dictionary of changes and push it onto + the stack. After doing this, the combined state is accessible + through getState()""" + + newstate = self._combined[-1].copy() + for key, value in delta.items(): + if key == 'transform': #do cumulative matrix + newstate['transform'] = delta['transform'] + newstate['ctm'] = mmult(self._combined[-1]['ctm'], delta['transform']) + #print 'statetracker transform = (%0.2f, %0.2f, %0.2f, %0.2f, %0.2f, %0.2f)' % tuple(newstate['transform']) + #print 'statetracker ctm = (%0.2f, %0.2f, %0.2f, %0.2f, %0.2f, %0.2f)' % tuple(newstate['ctm']) + + else: #just overwrite it + newstate[key] = value + + self._combined.append(newstate) + self._deltas.append(delta) + + def pop(self): + """steps back one, and returns a state dictionary with the + deltas to reverse out of wherever you are. Depending + on your back end, you may not need the return value, + since you can get the complete state afterwards with getState()""" + del self._combined[-1] + newState = self._combined[-1] + lastDelta = self._deltas[-1] + del self._deltas[-1] + #need to diff this against the last one in the state + reverseDelta = {} + #print 'pop()...' + for key, curValue in lastDelta.items(): + #print ' key=%s, value=%s' % (key, curValue) + prevValue = newState[key] + if prevValue != curValue: + #print ' state popping "%s"="%s"' % (key, curValue) + if key == 'transform': + reverseDelta[key] = inverse(lastDelta['transform']) + else: #just return to previous state + reverseDelta[key] = prevValue + return reverseDelta + + def getState(self): + "returns the complete graphics state at this point" + return self._combined[-1] + + def getCTM(self): + "returns the current transformation matrix at this point""" + return self._combined[-1]['ctm'] + + def __getitem__(self,key): + "returns the complete graphics state value of key at this point" + return self._combined[-1][key] + + def __setitem__(self,key,value): + "sets the complete graphics state value of key to value" + self._combined[-1][key] = value + +def testStateTracker(): + print('Testing state tracker') + defaults = {'fillColor':None, 'strokeColor':None,'fontName':None, 'transform':[1,0,0,1,0,0]} + from reportlab.graphics.shapes import _baseGFontName + deltas = [ + {'fillColor':'red'}, + {'fillColor':'green', 'strokeColor':'blue','fontName':_baseGFontName}, + {'transform':[0.5,0,0,0.5,0,0]}, + {'transform':[0.5,0,0,0.5,2,3]}, + {'strokeColor':'red'} + ] + + st = StateTracker(defaults) + print('initial:', st.getState()) + print() + for delta in deltas: + print('pushing:', delta) + st.push(delta) + print('state: ',st.getState(),'\n') + + for delta in deltas: + print('popping:',st.pop()) + print('state: ',st.getState(),'\n') + + +def _expandUserNode(node,canvas): + if isinstance(node, UserNode): + try: + if hasattr(node,'_canvas'): + ocanvas = 1 + else: + node._canvas = canvas + ocanvas = None + onode = node + node = node.provideNode() + finally: + if not ocanvas: del onode._canvas + return node + +def renderScaledDrawing(d): + renderScale = d.renderScale + if renderScale!=1.0: + o = d + d = d.__class__(o.width*renderScale,o.height*renderScale) + d.__dict__ = o.__dict__.copy() + d.scale(renderScale,renderScale) + d.renderScale = 1.0 + return d + +class Renderer: + """Virtual superclass for graphics renderers.""" + + def __init__(self): + self._tracker = StateTracker() + self._nodeStack = [] #track nodes visited + + def undefined(self, operation): + raise ValueError("%s operation not defined at superclass class=%s" %(operation, self.__class__)) + + def draw(self, drawing, canvas, x=0, y=0, showBoundary=rl_config._unset_): + """This is the top level function, which draws the drawing at the given + location. The recursive part is handled by drawNode.""" + #stash references for ease of communication + if showBoundary is rl_config._unset_: showBoundary=rl_config.showBoundary + self._canvas = canvas + canvas.__dict__['_drawing'] = self._drawing = drawing + drawing._parent = None + try: + #bounding box + if showBoundary: canvas.rect(x, y, drawing.width, drawing.height) + canvas.saveState() + self.initState(x,y) #this is the push() + self.drawNode(drawing) + self.pop() + canvas.restoreState() + finally: + #remove any circular references + del self._canvas, self._drawing, canvas._drawing, drawing._parent + + def initState(self,x,y): + deltas = STATE_DEFAULTS.copy() + deltas['transform'] = [1,0,0,1,x,y] + self._tracker.push(deltas) + self.applyStateChanges(deltas, {}) + + def pop(self): + self._tracker.pop() + + def drawNode(self, node): + """This is the recursive method called for each node + in the tree""" + # Undefined here, but with closer analysis probably can be handled in superclass + self.undefined("drawNode") + + def getStateValue(self, key): + """Return current state parameter for given key""" + currentState = self._tracker._combined[-1] + return currentState[key] + + def fillDerivedValues(self, node): + """Examine a node for any values which are Derived, + and replace them with their calculated values. + Generally things may look at the drawing or their + parent. + + """ + for key, value in node.__dict__.items(): + if isinstance(value, DerivedValue): + #just replace with default for key? + #print ' fillDerivedValues(%s)' % key + newValue = value.getValue(self, key) + #print ' got value of %s' % newValue + node.__dict__[key] = newValue + + def drawNodeDispatcher(self, node): + """dispatch on the node's (super) class: shared code""" + + canvas = getattr(self,'_canvas',None) + # replace UserNode with its contents + + try: + node = _expandUserNode(node,canvas) + if not node: return + if hasattr(node,'_canvas'): + ocanvas = 1 + else: + node._canvas = canvas + ocanvas = None + + self.fillDerivedValues(node) + dtcb = getattr(node,'_drawTimeCallback',None) + if dtcb: + dtcb(node,canvas=canvas,renderer=self) + #draw the object, or recurse + if isinstance(node, Line): + self.drawLine(node) + elif isinstance(node, Image): + self.drawImage(node) + elif isinstance(node, Rect): + self.drawRect(node) + elif isinstance(node, Circle): + self.drawCircle(node) + elif isinstance(node, Ellipse): + self.drawEllipse(node) + elif isinstance(node, PolyLine): + self.drawPolyLine(node) + elif isinstance(node, Polygon): + self.drawPolygon(node) + elif isinstance(node, Path): + self.drawPath(node) + elif isinstance(node, String): + self.drawString(node) + elif isinstance(node, Group): + self.drawGroup(node) + elif isinstance(node, Wedge): + self.drawWedge(node) + else: + print('DrawingError','Unexpected element %s in drawing!' % str(node)) + finally: + if not ocanvas: del node._canvas + + _restores = {'stroke':'_stroke','stroke_width': '_lineWidth','stroke_linecap':'_lineCap', + 'stroke_linejoin':'_lineJoin','fill':'_fill','font_family':'_font', + 'font_size':'_fontSize'} + + def drawGroup(self, group): + # just do the contents. Some renderers might need to override this + # if they need a flipped transform + canvas = getattr(self,'_canvas',None) + for node in group.getContents(): + node = _expandUserNode(node,canvas) + if not node: continue + + #here is where we do derived values - this seems to get everything. Touch wood. + self.fillDerivedValues(node) + try: + if hasattr(node,'_canvas'): + ocanvas = 1 + else: + node._canvas = canvas + ocanvas = None + node._parent = group + self.drawNode(node) + finally: + del node._parent + if not ocanvas: del node._canvas + + def drawWedge(self, wedge): + # by default ask the wedge to make a polygon of itself and draw that! + #print "drawWedge" + P = wedge.asPolygon() + if isinstance(P,Path): + self.drawPath(P) + else: + self.drawPolygon(P) + + def drawPath(self, path): + polygons = path.asPolygons() + for polygon in polygons: + self.drawPolygon(polygon) + + def drawRect(self, rect): + # could be implemented in terms of polygon + self.undefined("drawRect") + + def drawLine(self, line): + self.undefined("drawLine") + + def drawCircle(self, circle): + self.undefined("drawCircle") + + def drawPolyLine(self, p): + self.undefined("drawPolyLine") + + def drawEllipse(self, ellipse): + self.undefined("drawEllipse") + + def drawPolygon(self, p): + self.undefined("drawPolygon") + + def drawString(self, stringObj): + self.undefined("drawString") + + def applyStateChanges(self, delta, newState): + """This takes a set of states, and outputs the operators + needed to set those properties""" + self.undefined("applyStateChanges") + +if __name__=='__main__': + print("this file has no script interpretation") + print(__doc__) diff --git a/reportlab/graphics/samples/__init__.py b/reportlab/graphics/samples/__init__.py new file mode 100644 index 00000000..c16b3b27 --- /dev/null +++ b/reportlab/graphics/samples/__init__.py @@ -0,0 +1 @@ +__doc__="""Example drawings to review, used in autogenerated docs""" diff --git a/reportlab/graphics/samples/bubble.py b/reportlab/graphics/samples/bubble.py new file mode 100644 index 00000000..b6bd6ac1 --- /dev/null +++ b/reportlab/graphics/samples/bubble.py @@ -0,0 +1,73 @@ +#Autogenerated by ReportLab guiedit do not edit +from reportlab.graphics.charts.legends import Legend +from reportlab.graphics.charts.lineplots import ScatterPlot +from reportlab.graphics.shapes import Drawing, _DrawingEditorMixin, String +from reportlab.graphics.charts.textlabels import Label +from reportlab.graphics.samples.excelcolors import * + +class Bubble(_DrawingEditorMixin,Drawing): + def __init__(self,width=200,height=150,*args,**kw): + Drawing.__init__(self,width,height,*args,**kw) + self._add(self,ScatterPlot(),name='chart',validate=None,desc="The main chart") + self.chart.width = 115 + self.chart.height = 80 + self.chart.x = 30 + self.chart.y = 40 + self.chart.lines[0].strokeColor = color01 + self.chart.lines[1].strokeColor = color02 + self.chart.lines[2].strokeColor = color03 + self.chart.lines[3].strokeColor = color04 + self.chart.lines[4].strokeColor = color05 + self.chart.lines[5].strokeColor = color06 + self.chart.lines[6].strokeColor = color07 + self.chart.lines[7].strokeColor = color08 + self.chart.lines[8].strokeColor = color09 + self.chart.lines[9].strokeColor = color10 + self.chart.lines.symbol.kind ='Circle' + self.chart.lines.symbol.size = 15 + self.chart.fillColor = backgroundGrey + self.chart.lineLabels.fontName = 'Helvetica' + self.chart.xValueAxis.labels.fontName = 'Helvetica' + self.chart.xValueAxis.labels.fontSize = 7 + self.chart.xValueAxis.forceZero = 0 + self.chart.data = [((100,100), (200,200), (250,210), (300,300), (350,450))] + self.chart.xValueAxis.avoidBoundFrac = 1 + self.chart.xValueAxis.gridEnd = 115 + self.chart.xValueAxis.tickDown = 3 + self.chart.xValueAxis.visibleGrid = 1 + self.chart.yValueAxis.tickLeft = 3 + self.chart.yValueAxis.labels.fontName = 'Helvetica' + self.chart.yValueAxis.labels.fontSize = 7 + self._add(self,Label(),name='Title',validate=None,desc="The title at the top of the chart") + self.Title.fontName = 'Helvetica-Bold' + self.Title.fontSize = 7 + self.Title.x = 100 + self.Title.y = 135 + self.Title._text = 'Chart Title' + self.Title.maxWidth = 180 + self.Title.height = 20 + self.Title.textAnchor ='middle' + self._add(self,Legend(),name='Legend',validate=None,desc="The legend or key for the chart") + self.Legend.colorNamePairs = [(color01, 'Widgets')] + self.Legend.fontName = 'Helvetica' + self.Legend.fontSize = 7 + self.Legend.x = 153 + self.Legend.y = 85 + self.Legend.dxTextSpace = 5 + self.Legend.dy = 5 + self.Legend.dx = 5 + self.Legend.deltay = 5 + self.Legend.alignment ='right' + self.chart.lineLabelFormat = None + self.chart.xLabel = 'X Axis' + self.chart.y = 30 + self.chart.yLabel = 'Y Axis' + self.chart.yValueAxis.labelTextFormat = '%d' + self.chart.yValueAxis.forceZero = 1 + self.chart.xValueAxis.forceZero = 1 + + + self._add(self,0,name='preview',validate=None,desc=None) + +if __name__=="__main__": #NORUNTESTS + Bubble().save(formats=['pdf'],outDir=None,fnRoot='bubble') diff --git a/reportlab/graphics/samples/clustered_bar.py b/reportlab/graphics/samples/clustered_bar.py new file mode 100644 index 00000000..11c7caac --- /dev/null +++ b/reportlab/graphics/samples/clustered_bar.py @@ -0,0 +1,84 @@ +#Autogenerated by ReportLab guiedit do not edit +from reportlab.graphics.charts.legends import Legend +from reportlab.graphics.samples.excelcolors import * +from reportlab.graphics.charts.barcharts import HorizontalBarChart +from reportlab.graphics.shapes import Drawing, _DrawingEditorMixin, String +from reportlab.graphics.charts.textlabels import Label + +class ClusteredBar(_DrawingEditorMixin,Drawing): + def __init__(self,width=200,height=150,*args,**kw): + Drawing.__init__(self,width,height,*args,**kw) + self._add(self,HorizontalBarChart(),name='chart',validate=None,desc="The main chart") + self.chart.width = 115 + self.chart.height = 80 + self.chart.x = 30 + self.chart.y = 40 + self.chart.bars[0].fillColor = color01 + self.chart.bars[1].fillColor = color02 + self.chart.bars[2].fillColor = color03 + self.chart.bars[3].fillColor = color04 + self.chart.bars[4].fillColor = color05 + self.chart.bars[5].fillColor = color06 + self.chart.bars[6].fillColor = color07 + self.chart.bars[7].fillColor = color08 + self.chart.bars[8].fillColor = color09 + self.chart.bars[9].fillColor = color10 + self.chart.fillColor = backgroundGrey + self.chart.barLabels.fontName = 'Helvetica' + self.chart.valueAxis.labels.fontName = 'Helvetica' + self.chart.valueAxis.labels.fontSize = 6 + self.chart.valueAxis.forceZero = 1 + self.chart.data = [(100, 150, 180), (125, 180, 200)] + self.chart.groupSpacing = 15 + self.chart.valueAxis.avoidBoundFrac = 1 + self.chart.valueAxis.gridEnd = 80 + self.chart.valueAxis.tickDown = 3 + self.chart.valueAxis.visibleGrid = 1 + self.chart.categoryAxis.categoryNames = ['North', 'South', 'Central'] + self.chart.categoryAxis.tickLeft = 3 + self.chart.categoryAxis.labels.fontName = 'Helvetica' + self.chart.categoryAxis.labels.fontSize = 6 + self.chart.categoryAxis.labels.dx = -3 + self._add(self,Label(),name='Title',validate=None,desc="The title at the top of the chart") + self.Title.fontName = 'Helvetica-Bold' + self.Title.fontSize = 7 + self.Title.x = 100 + self.Title.y = 135 + self.Title._text = 'Chart Title' + self.Title.maxWidth = 180 + self.Title.height = 20 + self.Title.textAnchor ='middle' + self._add(self,Legend(),name='Legend',validate=None,desc="The legend or key for the chart") + self.Legend.colorNamePairs = [(color01, 'Widgets'), (color02, 'Sprockets')] + self.Legend.fontName = 'Helvetica' + self.Legend.fontSize = 7 + self.Legend.x = 153 + self.Legend.y = 85 + self.Legend.dxTextSpace = 5 + self.Legend.dy = 5 + self.Legend.dx = 5 + self.Legend.deltay = 5 + self.Legend.alignment ='right' + self._add(self,Label(),name='XLabel',validate=None,desc="The label on the horizontal axis") + self.XLabel.fontName = 'Helvetica' + self.XLabel.fontSize = 7 + self.XLabel.x = 85 + self.XLabel.y = 10 + self.XLabel.textAnchor ='middle' + self.XLabel.maxWidth = 100 + self.XLabel.height = 20 + self.XLabel._text = "X Axis" + self._add(self,Label(),name='YLabel',validate=None,desc="The label on the vertical axis") + self.YLabel.fontName = 'Helvetica' + self.YLabel.fontSize = 7 + self.YLabel.x = 12 + self.YLabel.y = 80 + self.YLabel.angle = 90 + self.YLabel.textAnchor ='middle' + self.YLabel.maxWidth = 100 + self.YLabel.height = 20 + self.YLabel._text = "Y Axis" + self._add(self,0,name='preview',validate=None,desc=None) + +if __name__=="__main__": #NORUNTESTS + ClusteredBar().save(formats=['pdf'],outDir=None,fnRoot='clustered_bar') diff --git a/reportlab/graphics/samples/clustered_column.py b/reportlab/graphics/samples/clustered_column.py new file mode 100644 index 00000000..3aa95a42 --- /dev/null +++ b/reportlab/graphics/samples/clustered_column.py @@ -0,0 +1,83 @@ +#Autogenerated by ReportLab guiedit do not edit +from reportlab.graphics.charts.legends import Legend +from reportlab.graphics.samples.excelcolors import * +from reportlab.graphics.charts.barcharts import VerticalBarChart +from reportlab.graphics.shapes import Drawing, _DrawingEditorMixin, String +from reportlab.graphics.charts.textlabels import Label + +class ClusteredColumn(_DrawingEditorMixin,Drawing): + def __init__(self,width=200,height=150,*args,**kw): + Drawing.__init__(self,width,height,*args,**kw) + self._add(self,VerticalBarChart(),name='chart',validate=None,desc="The main chart") + self.chart.width = 115 + self.chart.height = 80 + self.chart.x = 30 + self.chart.y = 40 + self.chart.bars[0].fillColor = color01 + self.chart.bars[1].fillColor = color02 + self.chart.bars[2].fillColor = color03 + self.chart.bars[3].fillColor = color04 + self.chart.bars[4].fillColor = color05 + self.chart.bars[5].fillColor = color06 + self.chart.bars[6].fillColor = color07 + self.chart.bars[7].fillColor = color08 + self.chart.bars[8].fillColor = color09 + self.chart.bars[9].fillColor = color10 + self.chart.fillColor = backgroundGrey + self.chart.barLabels.fontName = 'Helvetica' + self.chart.valueAxis.labels.fontName = 'Helvetica' + self.chart.valueAxis.labels.fontSize = 7 + self.chart.valueAxis.forceZero = 1 + self.chart.data = [(100, 150, 180), (125, 180, 200)] + self.chart.groupSpacing = 15 + self.chart.valueAxis.avoidBoundFrac = 1 + self.chart.valueAxis.gridEnd = 115 + self.chart.valueAxis.tickLeft = 3 + self.chart.valueAxis.visibleGrid = 1 + self.chart.categoryAxis.categoryNames = ['North', 'South', 'Central'] + self.chart.categoryAxis.tickDown = 3 + self.chart.categoryAxis.labels.fontName = 'Helvetica' + self.chart.categoryAxis.labels.fontSize = 7 + self._add(self,Label(),name='Title',validate=None,desc="The title at the top of the chart") + self.Title.fontName = 'Helvetica-Bold' + self.Title.fontSize = 7 + self.Title.x = 100 + self.Title.y = 135 + self.Title._text = 'Chart Title' + self.Title.maxWidth = 180 + self.Title.height = 20 + self.Title.textAnchor ='middle' + self._add(self,Legend(),name='Legend',validate=None,desc="The legend or key for the chart") + self.Legend.colorNamePairs = [(color01, 'Widgets'), (color02, 'Sprockets')] + self.Legend.fontName = 'Helvetica' + self.Legend.fontSize = 7 + self.Legend.x = 153 + self.Legend.y = 85 + self.Legend.dxTextSpace = 5 + self.Legend.dy = 5 + self.Legend.dx = 5 + self.Legend.deltay = 5 + self.Legend.alignment ='right' + self._add(self,Label(),name='XLabel',validate=None,desc="The label on the horizontal axis") + self.XLabel.fontName = 'Helvetica' + self.XLabel.fontSize = 7 + self.XLabel.x = 85 + self.XLabel.y = 10 + self.XLabel.textAnchor ='middle' + self.XLabel.maxWidth = 100 + self.XLabel.height = 20 + self.XLabel._text = "X Axis" + self._add(self,Label(),name='YLabel',validate=None,desc="The label on the vertical axis") + self.YLabel.fontName = 'Helvetica' + self.YLabel.fontSize = 7 + self.YLabel.x = 12 + self.YLabel.y = 80 + self.YLabel.angle = 90 + self.YLabel.textAnchor ='middle' + self.YLabel.maxWidth = 100 + self.YLabel.height = 20 + self.YLabel._text = "Y Axis" + self._add(self,0,name='preview',validate=None,desc=None) + +if __name__=="__main__": #NORUNTESTS + ClusteredColumn().save(formats=['pdf'],outDir=None,fnRoot='clustered_column') diff --git a/reportlab/graphics/samples/excelcolors.py b/reportlab/graphics/samples/excelcolors.py new file mode 100644 index 00000000..f3f4f5b6 --- /dev/null +++ b/reportlab/graphics/samples/excelcolors.py @@ -0,0 +1,45 @@ +# define standard colors to mimic those used by Microsoft Excel +from reportlab.lib.colors import CMYKColor, PCMYKColor + +#colour names as comments at the end of each line are as a memory jogger ONLY +#NOT HTML named colours! + +#Main colours as used for bars etc +color01 = PCMYKColor(40,40,0,0) # Lavender +color02 = PCMYKColor(0,66,33,39) # Maroon +color03 = PCMYKColor(0,0,20,0) # Yellow +color04 = PCMYKColor(20,0,0,0) # Cyan +color05 = PCMYKColor(0,100,0,59) # Purple +color06 = PCMYKColor(0,49,49,0) # Salmon +color07 = PCMYKColor(100,49,0,19) # Blue +color08 = PCMYKColor(20,20,0,0) # PaleLavender +color09 = PCMYKColor(100,100,0,49) # NavyBlue +color10 = PCMYKColor(0,100,0,0) # Purple + +#Highlight colors - eg for the tops of bars +color01Light = PCMYKColor(39,39,0,25) # Light Lavender +color02Light = PCMYKColor(0,66,33,54) # Light Maroon +color03Light = PCMYKColor(0,0,19,25) # Light Yellow +color04Light = PCMYKColor(19,0,0,25) # Light Cyan +color05Light = PCMYKColor(0,100,0,69) # Light Purple +color06Light = PCMYKColor(0,49,49,25) # Light Salmon +color07Light = PCMYKColor(100,49,0,39) # Light Blue +color08Light = PCMYKColor(19,19,0,25) # Light PaleLavender +color09Light = PCMYKColor(100,100,0,62) # Light NavyBlue +color10Light = PCMYKColor(0,100,0,25) # Light Purple + +#Lowlight colors - eg for the sides of bars +color01Dark = PCMYKColor(39,39,0,49) # Dark Lavender +color02Dark = PCMYKColor(0,66,33,69) # Dark Maroon +color03Dark = PCMYKColor(0,0,20,49) # Dark Yellow +color04Dark = PCMYKColor(20,0,0,49) # Dark Cyan +color05Dark = PCMYKColor(0,100,0,80) # Dark Purple +color06Dark = PCMYKColor(0,50,50,49) # Dark Salmon +color07Dark = PCMYKColor(100,50,0,59) # Dark Blue +color08Dark = PCMYKColor(20,20,0,49) # Dark PaleLavender +color09Dark = PCMYKColor(100,100,0,79) # Dark NavyBlue +color10Dark = PCMYKColor(0,100,0,49) # Dark Purple + +#for standard grey backgrounds +backgroundGrey = PCMYKColor(0,0,0,24) + diff --git a/reportlab/graphics/samples/exploded_pie.py b/reportlab/graphics/samples/exploded_pie.py new file mode 100644 index 00000000..f4dc30a3 --- /dev/null +++ b/reportlab/graphics/samples/exploded_pie.py @@ -0,0 +1,65 @@ +#Autogenerated by ReportLab guiedit do not edit +from reportlab.graphics.charts.piecharts import Pie +from reportlab.graphics.samples.excelcolors import * +from reportlab.graphics.widgets.grids import ShadedRect +from reportlab.graphics.charts.legends import Legend +from reportlab.graphics.shapes import Drawing, _DrawingEditorMixin, String +from reportlab.graphics.charts.textlabels import Label + +class ExplodedPie(_DrawingEditorMixin,Drawing): + def __init__(self,width=200,height=150,*args,**kw): + Drawing.__init__(self,width,height,*args,**kw) + self._add(self,Pie(),name='chart',validate=None,desc="The main chart") + self.chart.width = 100 + self.chart.height = 100 + self.chart.x = 25 + self.chart.y = 25 + self.chart.slices[0].fillColor = color01 + self.chart.slices[1].fillColor = color02 + self.chart.slices[2].fillColor = color03 + self.chart.slices[3].fillColor = color04 + self.chart.slices[4].fillColor = color05 + self.chart.slices[5].fillColor = color06 + self.chart.slices[6].fillColor = color07 + self.chart.slices[7].fillColor = color08 + self.chart.slices[8].fillColor = color09 + self.chart.slices[9].fillColor = color10 + self.chart.data = (100, 150, 180) + self.chart.startAngle = -90 + self._add(self,Label(),name='Title',validate=None,desc="The title at the top of the chart") + self.Title.fontName = 'Helvetica-Bold' + self.Title.fontSize = 7 + self.Title.x = 100 + self.Title.y = 135 + self.Title._text = 'Chart Title' + self.Title.maxWidth = 180 + self.Title.height = 20 + self.Title.textAnchor ='middle' + self._add(self,Legend(),name='Legend',validate=None,desc="The legend or key for the chart") + self.Legend.colorNamePairs = [(color01, 'North'), (color02, 'South'), (color03, 'Central')] + self.Legend.fontName = 'Helvetica' + self.Legend.fontSize = 7 + self.Legend.x = 160 + self.Legend.y = 85 + self.Legend.dxTextSpace = 5 + self.Legend.dy = 5 + self.Legend.dx = 5 + self.Legend.deltay = 5 + self.Legend.alignment ='right' + self.Legend.columnMaximum = 10 + self.chart.slices.strokeWidth = 1 + self.chart.slices.fontName = 'Helvetica' + self.background = ShadedRect() + self.background.fillColorStart = backgroundGrey + self.background.fillColorEnd = backgroundGrey + self.background.numShades = 1 + self.background.strokeWidth = 0.5 + self.background.x = 20 + self.background.y = 20 + self.chart.slices.popout = 5 + self.background.height = 110 + self.background.width = 110 + self._add(self,0,name='preview',validate=None,desc=None) + +if __name__=="__main__": #NORUNTESTS + ExplodedPie().save(formats=['pdf'],outDir=None,fnRoot='exploded_pie') diff --git a/reportlab/graphics/samples/filled_radar.py b/reportlab/graphics/samples/filled_radar.py new file mode 100644 index 00000000..78d0d427 --- /dev/null +++ b/reportlab/graphics/samples/filled_radar.py @@ -0,0 +1,54 @@ +#Autogenerated by ReportLab guiedit do not edit +from reportlab.graphics.charts.legends import Legend +from reportlab.graphics.charts.spider import SpiderChart +from reportlab.graphics.shapes import Drawing, _DrawingEditorMixin, String +from reportlab.graphics.charts.textlabels import Label +from reportlab.graphics.samples.excelcolors import * + +class FilledRadarChart(_DrawingEditorMixin,Drawing): + def __init__(self,width=200,height=150,*args,**kw): + Drawing.__init__(self,width,height,*args,**kw) + self._add(self,SpiderChart(),name='chart',validate=None,desc="The main chart") + self.chart.width = 90 + self.chart.height = 90 + self.chart.x = 45 + self.chart.y = 25 + self.chart.strands[0].fillColor = color01 + self.chart.strands[1].fillColor = color02 + self.chart.strands[2].fillColor = color03 + self.chart.strands[3].fillColor = color04 + self.chart.strands[4].fillColor = color05 + self.chart.strands[5].fillColor = color06 + self.chart.strands[6].fillColor = color07 + self.chart.strands[7].fillColor = color08 + self.chart.strands[8].fillColor = color09 + self.chart.strands[9].fillColor = color10 + self.chart.strandLabels.fontName = 'Helvetica' + self.chart.strandLabels.fontSize = 6 + self.chart.fillColor = backgroundGrey + self.chart.data = [(125, 180, 200), (100, 150, 180)] + self.chart.labels = ['North', 'South', 'Central'] + self._add(self,Label(),name='Title',validate=None,desc="The title at the top of the chart") + self.Title.fontName = 'Helvetica-Bold' + self.Title.fontSize = 7 + self.Title.x = 100 + self.Title.y = 135 + self.Title._text = 'Chart Title' + self.Title.maxWidth = 180 + self.Title.height = 20 + self.Title.textAnchor ='middle' + self._add(self,Legend(),name='Legend',validate=None,desc="The legend or key for the chart") + self.Legend.colorNamePairs = [(color01, 'Widgets'), (color02, 'Sprockets')] + self.Legend.fontName = 'Helvetica' + self.Legend.fontSize = 7 + self.Legend.x = 153 + self.Legend.y = 85 + self.Legend.dxTextSpace = 5 + self.Legend.dy = 5 + self.Legend.dx = 5 + self.Legend.deltay = 5 + self.Legend.alignment ='right' + self._add(self,0,name='preview',validate=None,desc=None) + +if __name__=="__main__": #NORUNTESTS + FilledRadarChart().save(formats=['pdf'],outDir=None,fnRoot='filled_radar') diff --git a/reportlab/graphics/samples/line_chart.py b/reportlab/graphics/samples/line_chart.py new file mode 100644 index 00000000..6122bc81 --- /dev/null +++ b/reportlab/graphics/samples/line_chart.py @@ -0,0 +1,83 @@ +#Autogenerated by ReportLab guiedit do not edit +from reportlab.graphics.charts.legends import Legend +from reportlab.graphics.charts.lineplots import LinePlot +from reportlab.graphics.shapes import Drawing, _DrawingEditorMixin, String +from reportlab.graphics.charts.textlabels import Label +from reportlab.graphics.samples.excelcolors import * + +class LineChart(_DrawingEditorMixin,Drawing): + def __init__(self,width=200,height=150,*args,**kw): + Drawing.__init__(self,width,height,*args,**kw) + self._add(self,LinePlot(),name='chart',validate=None,desc="The main chart") + self.chart.width = 115 + self.chart.height = 80 + self.chart.x = 30 + self.chart.y = 40 + self.chart.lines[0].strokeColor = color01 + self.chart.lines[1].strokeColor = color02 + self.chart.lines[2].strokeColor = color03 + self.chart.lines[3].strokeColor = color04 + self.chart.lines[4].strokeColor = color05 + self.chart.lines[5].strokeColor = color06 + self.chart.lines[6].strokeColor = color07 + self.chart.lines[7].strokeColor = color08 + self.chart.lines[8].strokeColor = color09 + self.chart.lines[9].strokeColor = color10 + self.chart.fillColor = backgroundGrey + self.chart.lineLabels.fontName = 'Helvetica' + self.chart.xValueAxis.labels.fontName = 'Helvetica' + self.chart.xValueAxis.labels.fontSize = 7 + self.chart.xValueAxis.forceZero = 0 + self.chart.data = [((0, 50), (100,100), (200,200), (250,210), (300,300), (400,500)), ((0, 150), (100,200), (200,300), (250,200), (300,400), (400, 600))] + self.chart.xValueAxis.avoidBoundFrac = 1 + self.chart.xValueAxis.gridEnd = 115 + self.chart.xValueAxis.tickDown = 3 + self.chart.xValueAxis.visibleGrid = 1 + self.chart.yValueAxis.tickLeft = 3 + self.chart.yValueAxis.labels.fontName = 'Helvetica' + self.chart.yValueAxis.labels.fontSize = 7 + self._add(self,Label(),name='Title',validate=None,desc="The title at the top of the chart") + self.Title.fontName = 'Helvetica-Bold' + self.Title.fontSize = 7 + self.Title.x = 100 + self.Title.y = 135 + self.Title._text = 'Chart Title' + self.Title.maxWidth = 180 + self.Title.height = 20 + self.Title.textAnchor ='middle' + self._add(self,Legend(),name='Legend',validate=None,desc="The legend or key for the chart") + self.Legend.colorNamePairs = [(color01, 'Widgets'), (color02, 'Sprockets')] + self.Legend.fontName = 'Helvetica' + self.Legend.fontSize = 7 + self.Legend.x = 153 + self.Legend.y = 85 + self.Legend.dxTextSpace = 5 + self.Legend.dy = 5 + self.Legend.dx = 5 + self.Legend.deltay = 5 + self.Legend.alignment ='right' + self._add(self,Label(),name='XLabel',validate=None,desc="The label on the horizontal axis") + self.XLabel.fontName = 'Helvetica' + self.XLabel.fontSize = 7 + self.XLabel.x = 85 + self.XLabel.y = 10 + self.XLabel.textAnchor ='middle' + self.XLabel.maxWidth = 100 + self.XLabel.height = 20 + self.XLabel._text = "X Axis" + self._add(self,Label(),name='YLabel',validate=None,desc="The label on the vertical axis") + self.YLabel.fontName = 'Helvetica' + self.YLabel.fontSize = 7 + self.YLabel.x = 12 + self.YLabel.y = 80 + self.YLabel.angle = 90 + self.YLabel.textAnchor ='middle' + self.YLabel.maxWidth = 100 + self.YLabel.height = 20 + self.YLabel._text = "Y Axis" + self.chart.yValueAxis.forceZero = 1 + self.chart.xValueAxis.forceZero = 1 + self._add(self,0,name='preview',validate=None,desc=None) + +if __name__=="__main__": #NORUNTESTS + LineChart().save(formats=['pdf'],outDir=None,fnRoot='line_chart') diff --git a/reportlab/graphics/samples/linechart_with_markers.py b/reportlab/graphics/samples/linechart_with_markers.py new file mode 100644 index 00000000..56871b65 --- /dev/null +++ b/reportlab/graphics/samples/linechart_with_markers.py @@ -0,0 +1,94 @@ +#Autogenerated by ReportLab guiedit do not edit +from reportlab.graphics.charts.legends import Legend +from reportlab.graphics.charts.lineplots import LinePlot +from reportlab.graphics.shapes import Drawing, _DrawingEditorMixin, String +from reportlab.graphics.widgets.markers import makeMarker +from reportlab.graphics.charts.textlabels import Label +from reportlab.graphics.samples.excelcolors import * + +class LineChartWithMarkers(_DrawingEditorMixin,Drawing): + def __init__(self,width=200,height=150,*args,**kw): + Drawing.__init__(self,width,height,*args,**kw) + self._add(self,LinePlot(),name='chart',validate=None,desc="The main chart") + self.chart.width = 115 + self.chart.height = 80 + self.chart.x = 30 + self.chart.y = 40 + self.chart.lines[0].strokeColor = color01 + self.chart.lines[1].strokeColor = color02 + self.chart.lines[2].strokeColor = color03 + self.chart.lines[3].strokeColor = color04 + self.chart.lines[4].strokeColor = color05 + self.chart.lines[5].strokeColor = color06 + self.chart.lines[6].strokeColor = color07 + self.chart.lines[7].strokeColor = color08 + self.chart.lines[8].strokeColor = color09 + self.chart.lines[9].strokeColor = color10 + self.chart.lines[0].symbol = makeMarker('FilledSquare') + self.chart.lines[1].symbol = makeMarker('FilledDiamond') + self.chart.lines[2].symbol = makeMarker('FilledStarFive') + self.chart.lines[3].symbol = makeMarker('FilledTriangle') + self.chart.lines[4].symbol = makeMarker('FilledCircle') + self.chart.lines[5].symbol = makeMarker('FilledPentagon') + self.chart.lines[6].symbol = makeMarker('FilledStarSix') + self.chart.lines[7].symbol = makeMarker('FilledHeptagon') + self.chart.lines[8].symbol = makeMarker('FilledOctagon') + self.chart.lines[9].symbol = makeMarker('FilledCross') + self.chart.fillColor = backgroundGrey + self.chart.lineLabels.fontName = 'Helvetica' + self.chart.xValueAxis.labels.fontName = 'Helvetica' + self.chart.xValueAxis.labels.fontSize = 7 + self.chart.xValueAxis.forceZero = 0 + self.chart.data = [((0, 50), (100,100), (200,200), (250,210), (300,300), (400,500)), ((0, 150), (100,200), (200,300), (250,200), (300,400), (400, 600))] + self.chart.xValueAxis.avoidBoundFrac = 1 + self.chart.xValueAxis.gridEnd = 115 + self.chart.xValueAxis.tickDown = 3 + self.chart.xValueAxis.visibleGrid = 1 + self.chart.yValueAxis.tickLeft = 3 + self.chart.yValueAxis.labels.fontName = 'Helvetica' + self.chart.yValueAxis.labels.fontSize = 7 + self._add(self,Label(),name='Title',validate=None,desc="The title at the top of the chart") + self.Title.fontName = 'Helvetica-Bold' + self.Title.fontSize = 7 + self.Title.x = 100 + self.Title.y = 135 + self.Title._text = 'Chart Title' + self.Title.maxWidth = 180 + self.Title.height = 20 + self.Title.textAnchor ='middle' + self._add(self,Legend(),name='Legend',validate=None,desc="The legend or key for the chart") + self.Legend.colorNamePairs = [(color01, 'Widgets'), (color02, 'Sprockets')] + self.Legend.fontName = 'Helvetica' + self.Legend.fontSize = 7 + self.Legend.x = 153 + self.Legend.y = 85 + self.Legend.dxTextSpace = 5 + self.Legend.dy = 5 + self.Legend.dx = 5 + self.Legend.deltay = 5 + self.Legend.alignment ='right' + self._add(self,Label(),name='XLabel',validate=None,desc="The label on the horizontal axis") + self.XLabel.fontName = 'Helvetica' + self.XLabel.fontSize = 7 + self.XLabel.x = 85 + self.XLabel.y = 10 + self.XLabel.textAnchor ='middle' + self.XLabel.maxWidth = 100 + self.XLabel.height = 20 + self.XLabel._text = "X Axis" + self._add(self,Label(),name='YLabel',validate=None,desc="The label on the vertical axis") + self.YLabel.fontName = 'Helvetica' + self.YLabel.fontSize = 7 + self.YLabel.x = 12 + self.YLabel.y = 80 + self.YLabel.angle = 90 + self.YLabel.textAnchor ='middle' + self.YLabel.maxWidth = 100 + self.YLabel.height = 20 + self.YLabel._text = "Y Axis" + self.chart.yValueAxis.forceZero = 1 + self.chart.xValueAxis.forceZero = 1 + self._add(self,0,name='preview',validate=None,desc=None) + +if __name__=="__main__": #NORUNTESTS + LineChartWithMarkers().save(formats=['pdf'],outDir=None,fnRoot='linechart_with_markers') diff --git a/reportlab/graphics/samples/radar.py b/reportlab/graphics/samples/radar.py new file mode 100644 index 00000000..adbf8f9f --- /dev/null +++ b/reportlab/graphics/samples/radar.py @@ -0,0 +1,66 @@ +#Autogenerated by ReportLab guiedit do not edit +from reportlab.graphics.charts.legends import Legend +from reportlab.graphics.samples.excelcolors import * +from reportlab.graphics.charts.spider import SpiderChart +from reportlab.graphics.shapes import Drawing, _DrawingEditorMixin, String +from reportlab.graphics.charts.textlabels import Label + +class RadarChart(_DrawingEditorMixin,Drawing): + def __init__(self,width=200,height=150,*args,**kw): + Drawing.__init__(self,width,height,*args,**kw) + self._add(self,SpiderChart(),name='chart',validate=None,desc="The main chart") + self.chart.width = 90 + self.chart.height = 90 + self.chart.x = 45 + self.chart.y = 25 + self.chart.strands[0].strokeColor= color01 + self.chart.strands[1].strokeColor= color02 + self.chart.strands[2].strokeColor= color03 + self.chart.strands[3].strokeColor= color04 + self.chart.strands[4].strokeColor= color05 + self.chart.strands[5].strokeColor= color06 + self.chart.strands[6].strokeColor= color07 + self.chart.strands[7].strokeColor= color08 + self.chart.strands[8].strokeColor= color09 + self.chart.strands[9].strokeColor= color10 + self.chart.strands[0].fillColor = None + self.chart.strands[1].fillColor = None + self.chart.strands[2].fillColor = None + self.chart.strands[3].fillColor = None + self.chart.strands[4].fillColor = None + self.chart.strands[5].fillColor = None + self.chart.strands[6].fillColor = None + self.chart.strands[7].fillColor = None + self.chart.strands[8].fillColor = None + self.chart.strands[9].fillColor = None + self.chart.strands.strokeWidth = 1 + self.chart.strandLabels.fontName = 'Helvetica' + self.chart.strandLabels.fontSize = 6 + self.chart.fillColor = backgroundGrey + self.chart.data = [(125, 180, 200), (100, 150, 180)] + self.chart.labels = ['North', 'South', 'Central'] + self._add(self,Label(),name='Title',validate=None,desc="The title at the top of the chart") + self.Title.fontName = 'Helvetica-Bold' + self.Title.fontSize = 7 + self.Title.x = 100 + self.Title.y = 135 + self.Title._text = 'Chart Title' + self.Title.maxWidth = 180 + self.Title.height = 20 + self.Title.textAnchor ='middle' + self._add(self,Legend(),name='Legend',validate=None,desc="The legend or key for the chart") + self.Legend.colorNamePairs = [(color01, 'Widgets'), (color02, 'Sprockets')] + self.Legend.fontName = 'Helvetica' + self.Legend.fontSize = 7 + self.Legend.x = 153 + self.Legend.y = 85 + self.Legend.dxTextSpace = 5 + self.Legend.dy = 5 + self.Legend.dx = 5 + self.Legend.deltay = 5 + self.Legend.alignment ='right' + self.chart.strands.strokeWidth = 1 + self._add(self,0,name='preview',validate=None,desc=None) + +if __name__=="__main__": #NORUNTESTS + RadarChart().save(formats=['pdf'],outDir=None,fnRoot='radar') diff --git a/reportlab/graphics/samples/runall.py b/reportlab/graphics/samples/runall.py new file mode 100644 index 00000000..e305a37f --- /dev/null +++ b/reportlab/graphics/samples/runall.py @@ -0,0 +1,58 @@ +# runs all the GUIedit charts in this directory - +# makes a PDF sample for eaxh existing chart type +import sys +import glob +import inspect +import types + +def moduleClasses(mod): + def P(obj, m=mod.__name__, CT=type): + return (type(obj)==CT and obj.__module__==m) + try: + return inspect.getmembers(mod, P)[0][1] + except: + return None + +def getclass(f): + return moduleClasses(__import__(f)) + +def run(format, VERBOSE=0): + formats = format.split( ',') + for i in range(0, len(formats)): + formats[i] == formats[i].strip().lower() + allfiles = glob.glob('*.py') + allfiles.sort() + for fn in allfiles: + f = fn.split('.')[0] + c = getclass(f) + if c != None: + print(c.__name__) + try: + for fmt in formats: + if fmt: + c().save(formats=[fmt],outDir='.',fnRoot=c.__name__) + if VERBOSE: + print(" %s.%s" % (c.__name__, fmt)) + except: + print(" COULDN'T CREATE '%s.%s'!" % (c.__name__, format)) + +if __name__ == "__main__": + if len(sys.argv) == 1: + run('pdf,pict,png') + else: + try: + if sys.argv[1] == "-h": + print('usage: runall.py [FORMAT] [-h]') + print(' if format is supplied is should be one or more of pdf,gif,eps,png etc') + print(' if format is missing the following formats are assumed: pdf,pict,png') + print(' -h prints this message') + else: + t = sys.argv[1:] + for f in t: + run(f) + except: + print('usage: runall.py [FORMAT][-h]') + print(' if format is supplied is should be one or more of pdf,gif,eps,png etc') + print(' if format is missing the following formats are assumed: pdf,pict,png') + print(' -h prints this message') + raise diff --git a/reportlab/graphics/samples/scatter.py b/reportlab/graphics/samples/scatter.py new file mode 100644 index 00000000..1e227c1b --- /dev/null +++ b/reportlab/graphics/samples/scatter.py @@ -0,0 +1,71 @@ +#Autogenerated by ReportLab guiedit do not edit +from reportlab.graphics.charts.legends import Legend +from reportlab.graphics.charts.lineplots import ScatterPlot +from reportlab.graphics.shapes import Drawing, _DrawingEditorMixin, String +from reportlab.graphics.charts.textlabels import Label +from reportlab.graphics.samples.excelcolors import * + +class Scatter(_DrawingEditorMixin,Drawing): + def __init__(self,width=200,height=150,*args,**kw): + Drawing.__init__(self,width,height,*args,**kw) + self._add(self,ScatterPlot(),name='chart',validate=None,desc="The main chart") + self.chart.width = 115 + self.chart.height = 80 + self.chart.x = 30 + self.chart.y = 40 + self.chart.lines[0].strokeColor = color01 + self.chart.lines[1].strokeColor = color02 + self.chart.lines[2].strokeColor = color03 + self.chart.lines[3].strokeColor = color04 + self.chart.lines[4].strokeColor = color05 + self.chart.lines[5].strokeColor = color06 + self.chart.lines[6].strokeColor = color07 + self.chart.lines[7].strokeColor = color08 + self.chart.lines[8].strokeColor = color09 + self.chart.lines[9].strokeColor = color10 + self.chart.fillColor = backgroundGrey + self.chart.lineLabels.fontName = 'Helvetica' + self.chart.xValueAxis.labels.fontName = 'Helvetica' + self.chart.xValueAxis.labels.fontSize = 7 + self.chart.xValueAxis.forceZero = 0 + self.chart.data = [((100,100), (200,200), (250,210), (300,300), (400,500)), ((100,200), (200,300), (250,200), (300,400), (400, 600))] + self.chart.xValueAxis.avoidBoundFrac = 1 + self.chart.xValueAxis.gridEnd = 115 + self.chart.xValueAxis.tickDown = 3 + self.chart.xValueAxis.visibleGrid = 1 + self.chart.yValueAxis.tickLeft = 3 + self.chart.yValueAxis.labels.fontName = 'Helvetica' + self.chart.yValueAxis.labels.fontSize = 7 + self._add(self,Label(),name='Title',validate=None,desc="The title at the top of the chart") + self.Title.fontName = 'Helvetica-Bold' + self.Title.fontSize = 7 + self.Title.x = 100 + self.Title.y = 135 + self.Title._text = 'Chart Title' + self.Title.maxWidth = 180 + self.Title.height = 20 + self.Title.textAnchor ='middle' + self._add(self,Legend(),name='Legend',validate=None,desc="The legend or key for the chart") + self.Legend.colorNamePairs = [(color01, 'Widgets'), (color02, 'Sprockets')] + self.Legend.fontName = 'Helvetica' + self.Legend.fontSize = 7 + self.Legend.x = 153 + self.Legend.y = 85 + self.Legend.dxTextSpace = 5 + self.Legend.dy = 5 + self.Legend.dx = 5 + self.Legend.deltay = 5 + self.Legend.alignment ='right' + self.chart.lineLabelFormat = None + self.chart.xLabel = 'X Axis' + self.chart.y = 30 + self.chart.yLabel = 'Y Axis' + self.chart.yValueAxis.labelTextFormat = '%d' + self.chart.yValueAxis.forceZero = 1 + self.chart.xValueAxis.forceZero = 1 + + + self._add(self,0,name='preview',validate=None,desc=None) + +if __name__=="__main__": #NORUNTESTS + Scatter().save(formats=['pdf'],outDir=None,fnRoot='scatter') diff --git a/reportlab/graphics/samples/scatter_lines.py b/reportlab/graphics/samples/scatter_lines.py new file mode 100644 index 00000000..550b7931 --- /dev/null +++ b/reportlab/graphics/samples/scatter_lines.py @@ -0,0 +1,82 @@ +#Autogenerated by ReportLab guiedit do not edit +from reportlab.graphics.charts.legends import Legend +from reportlab.graphics.charts.lineplots import ScatterPlot +from reportlab.graphics.shapes import Drawing, _DrawingEditorMixin, String +from reportlab.graphics.charts.textlabels import Label +from reportlab.graphics.samples.excelcolors import * + +class ScatterLines(_DrawingEditorMixin,Drawing): + def __init__(self,width=200,height=150,*args,**kw): + Drawing.__init__(self,width,height,*args,**kw) + self._add(self,ScatterPlot(),name='chart',validate=None,desc="The main chart") + self.chart.width = 115 + self.chart.height = 80 + self.chart.x = 30 + self.chart.y = 40 + self.chart.lines[0].strokeColor = color01 + self.chart.lines[1].strokeColor = color02 + self.chart.lines[2].strokeColor = color03 + self.chart.lines[3].strokeColor = color04 + self.chart.lines[4].strokeColor = color05 + self.chart.lines[5].strokeColor = color06 + self.chart.lines[6].strokeColor = color07 + self.chart.lines[7].strokeColor = color08 + self.chart.lines[8].strokeColor = color09 + self.chart.lines[9].strokeColor = color10 + self.chart.lines[0].symbol = None + self.chart.lines[1].symbol = None + self.chart.lines[2].symbol = None + self.chart.lines[3].symbol = None + self.chart.lines[4].symbol = None + self.chart.lines[5].symbol = None + self.chart.lines[6].symbol = None + self.chart.lines[7].symbol = None + self.chart.lines[8].symbol = None + self.chart.lines[9].symbol = None + self.chart.fillColor = backgroundGrey + self.chart.lineLabels.fontName = 'Helvetica' + self.chart.xValueAxis.labels.fontName = 'Helvetica' + self.chart.xValueAxis.labels.fontSize = 7 + self.chart.xValueAxis.forceZero = 0 + self.chart.data = [((100,100), (200,200), (250,210), (300,300), (400,500)), ((100,200), (200,300), (250,200), (300,400), (400, 600))] + self.chart.xValueAxis.avoidBoundFrac = 1 + self.chart.xValueAxis.gridEnd = 115 + self.chart.xValueAxis.tickDown = 3 + self.chart.xValueAxis.visibleGrid = 1 + self.chart.yValueAxis.tickLeft = 3 + self.chart.yValueAxis.labels.fontName = 'Helvetica' + self.chart.yValueAxis.labels.fontSize = 7 + self._add(self,Label(),name='Title',validate=None,desc="The title at the top of the chart") + self.Title.fontName = 'Helvetica-Bold' + self.Title.fontSize = 7 + self.Title.x = 100 + self.Title.y = 135 + self.Title._text = 'Chart Title' + self.Title.maxWidth = 180 + self.Title.height = 20 + self.Title.textAnchor ='middle' + self._add(self,Legend(),name='Legend',validate=None,desc="The legend or key for the chart") + self.Legend.colorNamePairs = [(color01, 'Widgets'), (color02, 'Sprockets')] + self.Legend.fontName = 'Helvetica' + self.Legend.fontSize = 7 + self.Legend.x = 153 + self.Legend.y = 85 + self.Legend.dxTextSpace = 5 + self.Legend.dy = 5 + self.Legend.dx = 5 + self.Legend.deltay = 5 + self.Legend.alignment ='right' + self.chart.lineLabelFormat = None + self.chart.xLabel = 'X Axis' + self.chart.y = 30 + self.chart.yLabel = 'Y Axis' + self.chart.yValueAxis.gridEnd = 115 + self.chart.yValueAxis.visibleGrid = 1 + self.chart.yValueAxis.labelTextFormat = '%d' + self.chart.yValueAxis.forceZero = 1 + self.chart.xValueAxis.forceZero = 1 + self.chart.joinedLines = 1 + self._add(self,0,name='preview',validate=None,desc=None) + +if __name__=="__main__": #NORUNTESTS + ScatterLines().save(formats=['pdf'],outDir=None,fnRoot='scatter_lines') diff --git a/reportlab/graphics/samples/scatter_lines_markers.py b/reportlab/graphics/samples/scatter_lines_markers.py new file mode 100644 index 00000000..5686e4d8 --- /dev/null +++ b/reportlab/graphics/samples/scatter_lines_markers.py @@ -0,0 +1,72 @@ +#Autogenerated by ReportLab guiedit do not edit +from reportlab.graphics.charts.legends import Legend +from reportlab.graphics.charts.lineplots import ScatterPlot +from reportlab.graphics.shapes import Drawing, _DrawingEditorMixin, String +from reportlab.graphics.charts.textlabels import Label +from reportlab.graphics.samples.excelcolors import * + +class ScatterLinesMarkers(_DrawingEditorMixin,Drawing): + def __init__(self,width=200,height=150,*args,**kw): + Drawing.__init__(self,width,height,*args,**kw) + self._add(self,ScatterPlot(),name='chart',validate=None,desc="The main chart") + self.chart.width = 115 + self.chart.height = 80 + self.chart.x = 30 + self.chart.y = 40 + self.chart.lines[0].strokeColor = color01 + self.chart.lines[1].strokeColor = color02 + self.chart.lines[2].strokeColor = color03 + self.chart.lines[3].strokeColor = color04 + self.chart.lines[4].strokeColor = color05 + self.chart.lines[5].strokeColor = color06 + self.chart.lines[6].strokeColor = color07 + self.chart.lines[7].strokeColor = color08 + self.chart.lines[8].strokeColor = color09 + self.chart.lines[9].strokeColor = color10 + self.chart.fillColor = backgroundGrey + self.chart.lineLabels.fontName = 'Helvetica' + self.chart.xValueAxis.labels.fontName = 'Helvetica' + self.chart.xValueAxis.labels.fontSize = 7 + self.chart.xValueAxis.forceZero = 0 + self.chart.data = [((100,100), (200,200), (250,210), (300,300), (400,500)), ((100,200), (200,300), (250,200), (300,400), (400, 600))] + self.chart.xValueAxis.avoidBoundFrac = 1 + self.chart.xValueAxis.gridEnd = 115 + self.chart.xValueAxis.tickDown = 3 + self.chart.xValueAxis.visibleGrid = 1 + self.chart.yValueAxis.tickLeft = 3 + self.chart.yValueAxis.labels.fontName = 'Helvetica' + self.chart.yValueAxis.labels.fontSize = 7 + self._add(self,Label(),name='Title',validate=None,desc="The title at the top of the chart") + self.Title.fontName = 'Helvetica-Bold' + self.Title.fontSize = 7 + self.Title.x = 100 + self.Title.y = 135 + self.Title._text = 'Chart Title' + self.Title.maxWidth = 180 + self.Title.height = 20 + self.Title.textAnchor ='middle' + self._add(self,Legend(),name='Legend',validate=None,desc="The legend or key for the chart") + self.Legend.colorNamePairs = [(color01, 'Widgets'), (color02, 'Sprockets')] + self.Legend.fontName = 'Helvetica' + self.Legend.fontSize = 7 + self.Legend.x = 153 + self.Legend.y = 85 + self.Legend.dxTextSpace = 5 + self.Legend.dy = 5 + self.Legend.dx = 5 + self.Legend.deltay = 5 + self.Legend.alignment ='right' + self.chart.lineLabelFormat = None + self.chart.xLabel = 'X Axis' + self.chart.y = 30 + self.chart.yLabel = 'Y Axis' + self.chart.yValueAxis.gridEnd = 115 + self.chart.yValueAxis.visibleGrid = 1 + self.chart.yValueAxis.labelTextFormat = '%d' + self.chart.yValueAxis.forceZero = 1 + self.chart.xValueAxis.forceZero = 1 + self.chart.joinedLines = 1 + self._add(self,0,name='preview',validate=None,desc=None) + +if __name__=="__main__": #NORUNTESTS + ScatterLinesMarkers().save(formats=['pdf'],outDir=None,fnRoot='scatter_lines_markers') diff --git a/reportlab/graphics/samples/simple_pie.py b/reportlab/graphics/samples/simple_pie.py new file mode 100644 index 00000000..57f5ae74 --- /dev/null +++ b/reportlab/graphics/samples/simple_pie.py @@ -0,0 +1,61 @@ +#Autogenerated by ReportLab guiedit do not edit +from reportlab.graphics.charts.piecharts import Pie +from reportlab.graphics.widgets.grids import ShadedRect +from reportlab.graphics.charts.legends import Legend +from reportlab.graphics.shapes import Drawing, _DrawingEditorMixin, String +from reportlab.graphics.charts.textlabels import Label +from reportlab.graphics.samples.excelcolors import * + +class SimplePie(_DrawingEditorMixin,Drawing): + def __init__(self,width=200,height=150,*args,**kw): + Drawing.__init__(self,width,height,*args,**kw) + self._add(self,Pie(),name='chart',validate=None,desc="The main chart") + self.chart.width = 100 + self.chart.height = 100 + self.chart.x = 25 + self.chart.y = 25 + self.chart.slices[0].fillColor = color01 + self.chart.slices[1].fillColor = color02 + self.chart.slices[2].fillColor = color03 + self.chart.slices[3].fillColor = color04 + self.chart.slices[4].fillColor = color05 + self.chart.slices[5].fillColor = color06 + self.chart.slices[6].fillColor = color07 + self.chart.slices[7].fillColor = color08 + self.chart.slices[8].fillColor = color09 + self.chart.slices[9].fillColor = color10 + self.chart.data = (100, 150, 180) + self._add(self,Label(),name='Title',validate=None,desc="The title at the top of the chart") + self.Title.fontName = 'Helvetica-Bold' + self.Title.fontSize = 7 + self.Title.x = 100 + self.Title.y = 135 + self.Title._text = 'Chart Title' + self.Title.maxWidth = 180 + self.Title.height = 20 + self.Title.textAnchor ='middle' + self._add(self,Legend(),name='Legend',validate=None,desc="The legend or key for the chart") + self.Legend.colorNamePairs = [(color01, 'North'), (color02, 'South'),(color03, 'Central')] + self.Legend.fontName = 'Helvetica' + self.Legend.fontSize = 7 + self.Legend.x = 160 + self.Legend.y = 85 + self.Legend.dxTextSpace = 5 + self.Legend.dy = 5 + self.Legend.dx = 5 + self.Legend.deltay = 5 + self.Legend.alignment ='right' + self.chart.slices.strokeWidth = 1 + self.chart.slices.fontName = 'Helvetica' + self.background = ShadedRect() + self.background.fillColorStart = backgroundGrey + self.background.fillColorEnd = backgroundGrey + self.background.numShades = 1 + self.background.strokeWidth = 0.5 + self.background.x = 25 + self.background.y = 25 + self.Legend.columnMaximum = 10 + self._add(self,0,name='preview',validate=None,desc=None) + +if __name__=="__main__": #NORUNTESTS + SimplePie().save(formats=['pdf'],outDir=None,fnRoot=None) diff --git a/reportlab/graphics/samples/stacked_bar.py b/reportlab/graphics/samples/stacked_bar.py new file mode 100644 index 00000000..c5ec9c6a --- /dev/null +++ b/reportlab/graphics/samples/stacked_bar.py @@ -0,0 +1,85 @@ +#Autogenerated by ReportLab guiedit do not edit +from reportlab.graphics.charts.legends import Legend +from reportlab.graphics.charts.barcharts import HorizontalBarChart +from reportlab.graphics.shapes import Drawing, _DrawingEditorMixin, String +from reportlab.graphics.charts.textlabels import Label +from reportlab.graphics.samples.excelcolors import * + +class StackedBar(_DrawingEditorMixin,Drawing): + def __init__(self,width=200,height=150,*args,**kw): + Drawing.__init__(self,width,height,*args,**kw) + self._add(self,HorizontalBarChart(),name='chart',validate=None,desc="The main chart") + self.chart.width = 115 + self.chart.height = 80 + self.chart.x = 30 + self.chart.y = 40 + self.chart.bars[0].fillColor = color01 + self.chart.bars[1].fillColor = color02 + self.chart.bars[2].fillColor = color03 + self.chart.bars[3].fillColor = color04 + self.chart.bars[4].fillColor = color05 + self.chart.bars[5].fillColor = color06 + self.chart.bars[6].fillColor = color07 + self.chart.bars[7].fillColor = color08 + self.chart.bars[8].fillColor = color09 + self.chart.bars[9].fillColor = color10 + self.chart.fillColor = backgroundGrey + self.chart.barLabels.fontName = 'Helvetica' + self.chart.valueAxis.labels.fontName = 'Helvetica' + self.chart.valueAxis.labels.fontSize = 6 + self.chart.valueAxis.forceZero = 1 + self.chart.data = [(100, 150, 180), (125, 180, 200)] + self.chart.groupSpacing = 15 + self.chart.valueAxis.avoidBoundFrac = 1 + self.chart.valueAxis.gridEnd = 80 + self.chart.valueAxis.tickDown = 3 + self.chart.valueAxis.visibleGrid = 1 + self.chart.categoryAxis.categoryNames = ['North', 'South', 'Central'] + self.chart.categoryAxis.tickLeft = 3 + self.chart.categoryAxis.labels.fontName = 'Helvetica' + self.chart.categoryAxis.labels.fontSize = 6 + self.chart.categoryAxis.labels.dx = -3 + self._add(self,Label(),name='Title',validate=None,desc="The title at the top of the chart") + self.Title.fontName = 'Helvetica-Bold' + self.Title.fontSize = 7 + self.Title.x = 100 + self.Title.y = 135 + self.Title._text = 'Chart Title' + self.Title.maxWidth = 180 + self.Title.height = 20 + self.Title.textAnchor ='middle' + self._add(self,Legend(),name='Legend',validate=None,desc="The legend or key for the chart") + self.Legend.colorNamePairs = [(color01, 'Widgets'), (color02, 'Sprockets')] + self.Legend.fontName = 'Helvetica' + self.Legend.fontSize = 7 + self.Legend.x = 153 + self.Legend.y = 85 + self.Legend.dxTextSpace = 5 + self.Legend.dy = 5 + self.Legend.dx = 5 + self.Legend.deltay = 5 + self.Legend.alignment ='right' + self._add(self,Label(),name='XLabel',validate=None,desc="The label on the horizontal axis") + self.XLabel.fontName = 'Helvetica' + self.XLabel.fontSize = 7 + self.XLabel.x = 85 + self.XLabel.y = 10 + self.XLabel.textAnchor ='middle' + self.XLabel.maxWidth = 100 + self.XLabel.height = 20 + self.XLabel._text = "X Axis" + self._add(self,Label(),name='YLabel',validate=None,desc="The label on the vertical axis") + self.YLabel.fontName = 'Helvetica' + self.YLabel.fontSize = 7 + self.YLabel.x = 12 + self.YLabel.y = 80 + self.YLabel.angle = 90 + self.YLabel.textAnchor ='middle' + self.YLabel.maxWidth = 100 + self.YLabel.height = 20 + self.YLabel._text = "Y Axis" + self.chart.categoryAxis.style='stacked' + self._add(self,0,name='preview',validate=None,desc=None) + +if __name__=="__main__": #NORUNTESTS + StackedBar().save(formats=['pdf'],outDir=None,fnRoot='stacked_bar') diff --git a/reportlab/graphics/samples/stacked_column.py b/reportlab/graphics/samples/stacked_column.py new file mode 100644 index 00000000..f6028434 --- /dev/null +++ b/reportlab/graphics/samples/stacked_column.py @@ -0,0 +1,84 @@ +#Autogenerated by ReportLab guiedit do not edit +from reportlab.graphics.charts.legends import Legend +from reportlab.graphics.charts.barcharts import VerticalBarChart +from reportlab.graphics.shapes import Drawing, _DrawingEditorMixin, String +from reportlab.graphics.charts.textlabels import Label +from reportlab.graphics.samples.excelcolors import * + +class StackedColumn(_DrawingEditorMixin,Drawing): + def __init__(self,width=200,height=150,*args,**kw): + Drawing.__init__(self,width,height,*args,**kw) + self._add(self,VerticalBarChart(),name='chart',validate=None,desc="The main chart") + self.chart.width = 115 + self.chart.height = 80 + self.chart.x = 30 + self.chart.y = 40 + self.chart.bars[0].fillColor = color01 + self.chart.bars[1].fillColor = color02 + self.chart.bars[2].fillColor = color03 + self.chart.bars[3].fillColor = color04 + self.chart.bars[4].fillColor = color05 + self.chart.bars[5].fillColor = color06 + self.chart.bars[6].fillColor = color07 + self.chart.bars[7].fillColor = color08 + self.chart.bars[8].fillColor = color09 + self.chart.bars[9].fillColor = color10 + self.chart.fillColor = backgroundGrey + self.chart.barLabels.fontName = 'Helvetica' + self.chart.valueAxis.labels.fontName = 'Helvetica' + self.chart.valueAxis.labels.fontSize = 7 + self.chart.valueAxis.forceZero = 1 + self.chart.data = [(100, 150, 180), (125, 180, 200)] + self.chart.groupSpacing = 15 + self.chart.valueAxis.avoidBoundFrac = 1 + self.chart.valueAxis.gridEnd = 115 + self.chart.valueAxis.tickLeft = 3 + self.chart.valueAxis.visibleGrid = 1 + self.chart.categoryAxis.categoryNames = ['North', 'South', 'Central'] + self.chart.categoryAxis.tickDown = 3 + self.chart.categoryAxis.labels.fontName = 'Helvetica' + self.chart.categoryAxis.labels.fontSize = 7 + self._add(self,Label(),name='Title',validate=None,desc="The title at the top of the chart") + self.Title.fontName = 'Helvetica-Bold' + self.Title.fontSize = 7 + self.Title.x = 100 + self.Title.y = 135 + self.Title._text = 'Chart Title' + self.Title.maxWidth = 180 + self.Title.height = 20 + self.Title.textAnchor ='middle' + self._add(self,Legend(),name='Legend',validate=None,desc="The legend or key for the chart") + self.Legend.colorNamePairs = [(color01, 'Widgets'), (color02, 'Sprockets')] + self.Legend.fontName = 'Helvetica' + self.Legend.fontSize = 7 + self.Legend.x = 153 + self.Legend.y = 85 + self.Legend.dxTextSpace = 5 + self.Legend.dy = 5 + self.Legend.dx = 5 + self.Legend.deltay = 5 + self.Legend.alignment ='right' + self._add(self,Label(),name='XLabel',validate=None,desc="The label on the horizontal axis") + self.XLabel.fontName = 'Helvetica' + self.XLabel.fontSize = 7 + self.XLabel.x = 85 + self.XLabel.y = 10 + self.XLabel.textAnchor ='middle' + self.XLabel.maxWidth = 100 + self.XLabel.height = 20 + self.XLabel._text = "X Axis" + self._add(self,Label(),name='YLabel',validate=None,desc="The label on the vertical axis") + self.YLabel.fontName = 'Helvetica' + self.YLabel.fontSize = 7 + self.YLabel.x = 12 + self.YLabel.y = 80 + self.YLabel.angle = 90 + self.YLabel.textAnchor ='middle' + self.YLabel.maxWidth = 100 + self.YLabel.height = 20 + self.YLabel._text = "Y Axis" + self.chart.categoryAxis.style='stacked' + self._add(self,0,name='preview',validate=None,desc=None) + +if __name__=="__main__": #NORUNTESTS + StackedColumn().save(formats=['pdf'],outDir=None,fnRoot='stacked_column') diff --git a/reportlab/graphics/shapes.py b/reportlab/graphics/shapes.py new file mode 100644 index 00000000..dbdc3541 --- /dev/null +++ b/reportlab/graphics/shapes.py @@ -0,0 +1,1467 @@ +#Copyright ReportLab Europe Ltd. 2000-2012 +#see license.txt for license details +#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/graphics/shapes.py + +__version__=''' $Id$ ''' +__doc__='''Core of the graphics library - defines Drawing and Shapes''' + +import os, sys +from math import pi, cos, sin, tan, sqrt +from pprint import pprint + +from reportlab.platypus import Flowable +from reportlab.rl_config import shapeChecking, verbose, defaultGraphicsFontName as _baseGFontName, _unset_, decimalSymbol +from reportlab.lib import logger +from reportlab.lib import colors +from reportlab.lib.validators import * +from reportlab.lib.utils import isSeq, asBytes +isOpacity = NoneOr(isNumberInRange(0,1)) +from reportlab.lib.attrmap import * +from reportlab.lib.rl_accel import fp_str +from reportlab.pdfbase.pdfmetrics import stringWidth +from reportlab.lib.fonts import tt2ps +_baseGFontNameB = tt2ps(_baseGFontName,1,0) +_baseGFontNameI = tt2ps(_baseGFontName,0,1) +_baseGFontNameBI = tt2ps(_baseGFontName,1,1) + +class NotImplementedError(Exception): + pass + +# two constants for filling rules +NON_ZERO_WINDING = 'Non-Zero Winding' +EVEN_ODD = 'Even-Odd' + +## these can be overridden at module level before you start +#creating shapes. So, if using a special color model, +#this provides support for the rendering mechanism. +#you can change defaults globally before you start +#making shapes; one use is to substitute another +#color model cleanly throughout the drawing. + +STATE_DEFAULTS = { # sensible defaults for all + 'transform': (1,0,0,1,0,0), + + # styles follow SVG naming + 'strokeColor': colors.black, + 'strokeWidth': 1, + 'strokeLineCap': 0, + 'strokeLineJoin': 0, + 'strokeMiterLimit' : 10, # don't know yet so let bomb here + 'strokeDashArray': None, + 'strokeOpacity': None, #100% + 'fillOpacity': None, + 'fillOverprint': False, + 'strokeOverprint': False, + 'overprintMask': 0, + + 'fillColor': colors.black, #...or text will be invisible + #'fillRule': NON_ZERO_WINDING, - these can be done later + + 'fontSize': 10, + 'fontName': _baseGFontName, + 'textAnchor': 'start' # can be start, middle, end, inherited + } + + +#################################################################### +# math utilities. These could probably be moved into lib +# somewhere. +#################################################################### + +# constructors for matrices: +def nullTransform(): + return (1, 0, 0, 1, 0, 0) + +def translate(dx, dy): + return (1, 0, 0, 1, dx, dy) + +def scale(sx, sy): + return (sx, 0, 0, sy, 0, 0) + +def rotate(angle): + a = angle * pi/180 + return (cos(a), sin(a), -sin(a), cos(a), 0, 0) + +def skewX(angle): + a = angle * pi/180 + return (1, 0, tan(a), 1, 0, 0) + +def skewY(angle): + a = angle * pi/180 + return (1, tan(a), 0, 1, 0, 0) + +def mmult(A, B): + "A postmultiplied by B" + # I checked this RGB + # [a0 a2 a4] [b0 b2 b4] + # [a1 a3 a5] * [b1 b3 b5] + # [ 1 ] [ 1 ] + # + return (A[0]*B[0] + A[2]*B[1], + A[1]*B[0] + A[3]*B[1], + A[0]*B[2] + A[2]*B[3], + A[1]*B[2] + A[3]*B[3], + A[0]*B[4] + A[2]*B[5] + A[4], + A[1]*B[4] + A[3]*B[5] + A[5]) + +def inverse(A): + "For A affine 2D represented as 6vec return 6vec version of A**(-1)" + # I checked this RGB + det = float(A[0]*A[3] - A[2]*A[1]) + R = [A[3]/det, -A[1]/det, -A[2]/det, A[0]/det] + return tuple(R+[-R[0]*A[4]-R[2]*A[5],-R[1]*A[4]-R[3]*A[5]]) + +def zTransformPoint(A,v): + "Apply the homogenous part of atransformation a to vector v --> A*v" + return (A[0]*v[0]+A[2]*v[1],A[1]*v[0]+A[3]*v[1]) + +def transformPoint(A,v): + "Apply transformation a to vector v --> A*v" + return (A[0]*v[0]+A[2]*v[1]+A[4],A[1]*v[0]+A[3]*v[1]+A[5]) + +def transformPoints(matrix, V): + r = [transformPoint(matrix,v) for v in V] + if isinstance(V,tuple): r = tuple(r) + return r + +def zTransformPoints(matrix, V): + return list(map(lambda x,matrix=matrix: zTransformPoint(matrix,x), V)) + +def _textBoxLimits(text, font, fontSize, leading, textAnchor, boxAnchor): + w = 0 + for t in text: + w = max(w,stringWidth(t,font, fontSize)) + + h = len(text)*leading + yt = fontSize + if boxAnchor[0]=='s': + yb = -h + yt = yt - h + elif boxAnchor[0]=='n': + yb = 0 + else: + yb = -h/2.0 + yt = yt + yb + + if boxAnchor[-1]=='e': + xb = -w + if textAnchor=='end': xt = 0 + elif textAnchor=='start': xt = -w + else: xt = -w/2.0 + elif boxAnchor[-1]=='w': + xb = 0 + if textAnchor=='end': xt = w + elif textAnchor=='start': xt = 0 + else: xt = w/2.0 + else: + xb = -w/2.0 + if textAnchor=='end': xt = -xb + elif textAnchor=='start': xt = xb + else: xt = 0 + + return xb, yb, w, h, xt, yt + +def _rotatedBoxLimits( x, y, w, h, angle): + ''' + Find the corner points of the rotated w x h sized box at x,y + return the corner points and the min max points in the original space + ''' + C = zTransformPoints(rotate(angle),((x,y),(x+w,y),(x+w,y+h),(x,y+h))) + X = [x[0] for x in C] + Y = [x[1] for x in C] + return min(X), max(X), min(Y), max(Y), C + + +class _DrawTimeResizeable: + '''Addin class to provide the horribleness of _drawTimeResize''' + def _drawTimeResize(self,w,h): + if hasattr(self,'_canvas'): + canvas = self._canvas + drawing = canvas._drawing + drawing.width, drawing.height = w, h + if hasattr(canvas,'_drawTimeResize'): + canvas._drawTimeResize(w,h) + +class _SetKeyWordArgs: + def __init__(self, keywords={}): + """In general properties may be supplied to the constructor.""" + for key, value in keywords.items(): + setattr(self, key, value) + + +################################################################# +# +# Helper functions for working out bounds +# +################################################################# + +def getRectsBounds(rectList): + # filter out any None objects, e.g. empty groups + L = [x for x in rectList if x is not None] + if not L: return None + + xMin, yMin, xMax, yMax = L[0] + for (x1, y1, x2, y2) in L[1:]: + if x1 < xMin: + xMin = x1 + if x2 > xMax: + xMax = x2 + if y1 < yMin: + yMin = y1 + if y2 > yMax: + yMax = y2 + return (xMin, yMin, xMax, yMax) + +def _getBezierExtrema(y0,y1,y2,y3): + ''' + this is used to find if a curveTo path operator has extrema in its range + The curveTo operator is defined by the points y0, y1, y2, y3 + + B(t):=(1-t)^3*y0+3*(1-t)^2*t*y1+3*(1-t)*t^2*y2+t^3*y3 + :=t^3*(y3-3*y2+3*y1-y0)+t^2*(3*y2-6*y1+3*y0)+t*(3*y1-3*y0)+y0 + and is a cubic bezier curve. + + The differential is a quadratic + t^2*(3*y3-9*y2+9*y1-3*y0)+t*(6*y2-12*y1+6*y0)+3*y1-3*y0 + + The extrema must be at real roots, r, of the above which lie in 0<=r<=1 + + The quadratic coefficients are + a=3*y3-9*y2+9*y1-3*y0 b=6*y2-12*y1+6*y0 c=3*y1-3*y0 + or + a=y3-3*y2+3*y1-y0 b=2*y2-4*y1+2*y0 c=y1-y0 (remove common factor of 3) + or + a=y3-3*(y2-y1)-y0 b=2*(y2-2*y1+y0) c=y1-y0 + + The returned value is [y0,x1,x2,y3] where if found x1, x2 are any extremals that were found; + there can be 0, 1 or 2 extremals + ''' + a=y3-3*(y2-y1)-y0 + b=2*(y2-2*y1+y0) + c=y1-y0 + Y = [y0] #the set of points + + #standard method to find roots of quadratic + d = b*b - 4*a*c + if d>=0: + d = sqrt(d) + if b<0: d = -d + q = -0.5*(b+d) + R = [] + try: + R.append(q/a) + except: + pass + try: + R.append(c/q) + except: + pass + b *= 1.5 + c *= 3 + for t in R: + if 0<=t<=1: + #real root in range evaluate spline there and add to X + Y.append(t*(t*(t*a+b)+c)+y0) + Y.append(y3) + return Y + +def getPathBounds(points): + n = len(points) + f = lambda i,p = points: p[i] + xs = list(map(f,range(0,n,2))) + ys = list(map(f,range(1,n,2))) + return (min(xs), min(ys), max(xs), max(ys)) + +def getPointsBounds(pointList): + "Helper function for list of points" + first = pointList[0] + if isSeq(first): + xs = [xy[0] for xy in pointList] + ys = [xy[1] for xy in pointList] + return (min(xs), min(ys), max(xs), max(ys)) + else: + return getPathBounds(pointList) + +################################################################# +# +# And now the shapes themselves.... +# +################################################################# +class Shape(_SetKeyWordArgs,_DrawTimeResizeable): + """Base class for all nodes in the tree. Nodes are simply + packets of data to be created, stored, and ultimately + rendered - they don't do anything active. They provide + convenience methods for verification but do not + check attribiute assignments or use any clever setattr + tricks this time.""" + _attrMap = AttrMap() + + def copy(self): + """Return a clone of this shape.""" + + # implement this in the descendants as they need the right init methods. + raise NotImplementedError("No copy method implemented for %s" % self.__class__.__name__) + + def getProperties(self,recur=1): + """Interface to make it easy to extract automatic + documentation""" + + #basic nodes have no children so this is easy. + #for more complex objects like widgets you + #may need to override this. + props = {} + for key, value in self.__dict__.items(): + if key[0:1] != '_': + props[key] = value + return props + + def setProperties(self, props): + """Supports the bulk setting if properties from, + for example, a GUI application or a config file.""" + + self.__dict__.update(props) + #self.verify() + + def dumpProperties(self, prefix=""): + """Convenience. Lists them on standard output. You + may provide a prefix - mostly helps to generate code + samples for documentation.""" + + propList = list(self.getProperties().items()) + propList.sort() + if prefix: + prefix = prefix + '.' + for (name, value) in propList: + print('%s%s = %s' % (prefix, name, value)) + + def verify(self): + """If the programmer has provided the optional + _attrMap attribute, this checks all expected + attributes are present; no unwanted attributes + are present; and (if a checking function is found) + checks each attribute. Either succeeds or raises + an informative exception.""" + + if self._attrMap is not None: + for key in self.__dict__.keys(): + if key[0] != '_': + assert key in self._attrMap, "Unexpected attribute %s found in %s" % (key, self) + for attr, metavalue in self._attrMap.items(): + assert hasattr(self, attr), "Missing attribute %s from %s" % (attr, self) + value = getattr(self, attr) + assert metavalue.validate(value), "Invalid value %s for attribute %s in class %s" % (value, attr, self.__class__.__name__) + + if shapeChecking: + """This adds the ability to check every attribute assignment as it is made. + It slows down shapes but is a big help when developing. It does not + get defined if rl_config.shapeChecking = 0""" + def __setattr__(self, attr, value): + """By default we verify. This could be off + in some parallel base classes.""" + validateSetattr(self,attr,value) #from reportlab.lib.attrmap + + def getBounds(self): + "Returns bounding rectangle of object as (x1,y1,x2,y2)" + raise NotImplementedError("Shapes and widgets must implement getBounds") + +class Group(Shape): + """Groups elements together. May apply a transform + to its contents. Has a publicly accessible property + 'contents' which may be used to iterate over contents. + In addition, child nodes may be given a name in which + case they are subsequently accessible as properties.""" + + _attrMap = AttrMap( + transform = AttrMapValue(isTransform,desc="Coordinate transformation to apply",advancedUsage=1), + contents = AttrMapValue(isListOfShapes,desc="Contained drawable elements"), + strokeOverprint = AttrMapValue(isBoolean,desc='Turn on stroke overprinting'), + fillOverprint = AttrMapValue(isBoolean,desc='Turn on fill overprinting',advancedUsage=1), + overprintMask = AttrMapValue(isBoolean,desc='overprinting for ordinary CMYK',advancedUsage=1), + ) + + def __init__(self, *elements, **keywords): + """Initial lists of elements may be provided to allow + compact definitions in literal Python code. May or + may not be useful.""" + + # Groups need _attrMap to be an instance rather than + # a class attribute, as it may be extended at run time. + self._attrMap = self._attrMap.clone() + self.contents = [] + self.transform = (1,0,0,1,0,0) + for elt in elements: + self.add(elt) + # this just applies keywords; do it at the end so they + #don;t get overwritten + _SetKeyWordArgs.__init__(self, keywords) + + def _addNamedNode(self,name,node): + 'if name is not None add an attribute pointing to node and add to the attrMap' + if name: + if name not in list(self._attrMap.keys()): + self._attrMap[name] = AttrMapValue(isValidChild) + setattr(self, name, node) + + def add(self, node, name=None): + """Appends non-None child node to the 'contents' attribute. In addition, + if a name is provided, it is subsequently accessible by name + """ + # propagates properties down + if node is not None: + assert isValidChild(node), "Can only add Shape or UserNode objects to a Group" + self.contents.append(node) + self._addNamedNode(name,node) + + def _nn(self,node): + self.add(node) + return self.contents[-1] + + def insert(self, i, n, name=None): + 'Inserts sub-node n in contents at specified location' + if n is not None: + assert isValidChild(n), "Can only insert Shape or UserNode objects in a Group" + if i<0: + self.contents[i:i] =[n] + else: + self.contents.insert(i,n) + self._addNamedNode(name,n) + + def expandUserNodes(self): + """Return a new object which only contains primitive shapes.""" + + # many limitations - shared nodes become multiple ones, + obj = isinstance(self,Drawing) and Drawing(self.width,self.height) or Group() + obj._attrMap = self._attrMap.clone() + if hasattr(obj,'transform'): obj.transform = self.transform[:] + + self_contents = self.contents + a = obj.contents.append + for child in self_contents: + if isinstance(child, UserNode): + newChild = child.provideNode() + elif isinstance(child, Group): + newChild = child.expandUserNodes() + else: + newChild = child.copy() + a(newChild) + + self._copyNamedContents(obj) + return obj + + def _explode(self): + ''' return a fully expanded object''' + from reportlab.graphics.widgetbase import Widget + obj = Group() + if hasattr(obj,'transform'): obj.transform = self.transform[:] + P = self.contents[:] # pending nodes + while P: + n = P.pop(0) + if isinstance(n, UserNode): + P.append(n.provideNode()) + elif isinstance(n, Group): + n = n._explode() + if n.transform==(1,0,0,1,0,0): + obj.contents.extend(n.contents) + else: + obj.add(n) + else: + obj.add(n) + return obj + + def _copyContents(self,obj): + for child in self.contents: + obj.contents.append(child) + + def _copyNamedContents(self,obj,aKeys=None,noCopy=('contents',)): + from copy import copy + self_contents = self.contents + if not aKeys: aKeys = list(self._attrMap.keys()) + for k, v in self.__dict__.items(): + if v in self_contents: + pos = self_contents.index(v) + setattr(obj, k, obj.contents[pos]) + elif k in aKeys and k not in noCopy: + setattr(obj, k, copy(v)) + + def _copy(self,obj): + """copies to obj""" + obj._attrMap = self._attrMap.clone() + self._copyContents(obj) + self._copyNamedContents(obj) + return obj + + def copy(self): + """returns a copy""" + return self._copy(self.__class__()) + + def rotate(self, theta): + """Convenience to help you set transforms""" + self.transform = mmult(self.transform, rotate(theta)) + + def translate(self, dx, dy): + """Convenience to help you set transforms""" + self.transform = mmult(self.transform, translate(dx, dy)) + + def scale(self, sx, sy): + """Convenience to help you set transforms""" + self.transform = mmult(self.transform, scale(sx, sy)) + + + def skew(self, kx, ky): + """Convenience to help you set transforms""" + self.transform = mmult(mmult(self.transform, skewX(kx)),skewY(ky)) + + def shift(self, x, y): + '''Convenience function to set the origin arbitrarily''' + self.transform = self.transform[:-2]+(x,y) + + def asDrawing(self, width, height): + """ Convenience function to make a drawing from a group + After calling this the instance will be a drawing! + """ + self.__class__ = Drawing + self._attrMap.update(self._xtraAttrMap) + self.width = width + self.height = height + + def getContents(self): + '''Return the list of things to be rendered + override to get more complicated behaviour''' + b = getattr(self,'background',None) + C = self.contents + if b and b not in C: C = [b]+C + return C + + def getBounds(self): + if self.contents: + b = [] + for elem in self.contents: + b.append(elem.getBounds()) + x1 = getRectsBounds(b) + if x1 is None: return None + x1, y1, x2, y2 = x1 + trans = self.transform + corners = [[x1,y1], [x1, y2], [x2, y1], [x2,y2]] + newCorners = [] + for corner in corners: + newCorners.append(transformPoint(trans, corner)) + return getPointsBounds(newCorners) + else: + #empty group needs a sane default; this + #will happen when interactively creating a group + #nothing has been added to yet. The alternative is + #to handle None as an allowed return value everywhere. + return None + +def _addObjImport(obj,I,n=None): + '''add an import of obj's class to a dictionary of imports''' #' + from inspect import getmodule + c = obj.__class__ + m = getmodule(c).__name__ + n = n or c.__name__ + if m not in I: + I[m] = [n] + elif n not in I[m]: + I[m].append(n) + +def _repr(self,I=None): + '''return a repr style string with named fixed args first, then keywords''' + if isinstance(self,float): + return fp_str(self) + elif isSeq(self): + s = '' + for v in self: + s = s + '%s,' % _repr(v,I) + if isinstance(self,list): + return '[%s]' % s[:-1] + else: + return '(%s%s)' % (s[:-1],len(self)==1 and ',' or '') + elif self is EmptyClipPath: + if I: _addObjImport(self,I,'EmptyClipPath') + return 'EmptyClipPath' + elif isinstance(self,Shape): + if I: _addObjImport(self,I) + from inspect import getargs + args, varargs, varkw = getargs(self.__init__.__func__.__code__) + P = self.getProperties() + s = self.__class__.__name__+'(' + for n in args[1:]: + v = P[n] + del P[n] + s = s + '%s,' % _repr(v,I) + for n,v in P.items(): + v = P[n] + s = s + '%s=%s,' % (n, _repr(v,I)) + return s[:-1]+')' + else: + return repr(self) + +def _renderGroupPy(G,pfx,I,i=0,indent='\t\t'): + s = '' + C = getattr(G,'transform',None) + if C: s = s + ('%s%s.transform = %s\n' % (indent,pfx,_repr(C))) + C = G.contents + for n in C: + if isinstance(n, Group): + npfx = 'v%d' % i + i = i + 1 + s = s + '%s%s=%s._nn(Group())\n' % (indent,npfx,pfx) + s = s + _renderGroupPy(n,npfx,I,i,indent) + i = i - 1 + else: + s = s + '%s%s.add(%s)\n' % (indent,pfx,_repr(n,I)) + return s + +def _extraKW(self,pfx,**kw): + kw.update(self.__dict__) + R = {} + n = len(pfx) + for k in kw.keys(): + if k.startswith(pfx): + R[k[n:]] = kw[k] + return R + +class Drawing(Group, Flowable): + """Outermost container; the thing a renderer works on. + This has no properties except a height, width and list + of contents.""" + + _saveModes=( + 'pdf','ps','eps','gif','png','jpg','jpeg','pct', + 'pict','tiff','tif','py','bmp','svg','tiffp','tiffl','tiff1', + ) + + _xtraAttrMap = AttrMap( + width = AttrMapValue(isNumber,desc="Drawing width in points."), + height = AttrMapValue(isNumber,desc="Drawing height in points."), + canv = AttrMapValue(None), + background = AttrMapValue(isValidChildOrNone,desc="Background widget for the drawing e.g. Rect(0,0,width,height)"), + hAlign = AttrMapValue(OneOf("LEFT", "RIGHT", "CENTER", "CENTRE"), desc="Horizontal alignment within parent document"), + vAlign = AttrMapValue(OneOf("TOP", "BOTTOM", "CENTER", "CENTRE"), desc="Vertical alignment within parent document"), + #AR temporary hack to track back up. + #fontName = AttrMapValue(isStringOrNone), + renderScale = AttrMapValue(isNumber,desc="Global scaling for rendering"), + ) + + _attrMap = AttrMap(BASE=Group, + formats = AttrMapValue(SequenceOf( + OneOf('pdf','gif','png','tif','jpg','tiff','pct','pict', + 'bmp','tiffp','tiffl','tiff1','eps','svg','ps','py'), + lo=1,emptyOK=0), desc='One or more plot modes'), + ) + _attrMap.update(_xtraAttrMap) + + def __init__(self, width=400, height=200, *nodes, **keywords): + self.background = None + Group.__init__(self,*nodes,**keywords) + self.width = width + self.height = height + self.hAlign = 'LEFT' + self.vAlign = 'BOTTOM' + self.renderScale = 1.0 + + def _renderPy(self): + I = {'reportlab.graphics.shapes': ['_DrawingEditorMixin','Drawing','Group']} + G = _renderGroupPy(self._explode(),'self',I) + n = 'ExplodedDrawing_' + self.__class__.__name__ + s = '#Autogenerated by ReportLab guiedit do not edit\n' + for m, o in I.items(): + s = s + 'from %s import %s\n' % (m,str(o)[1:-1].replace("'","")) + s = s + '\nclass %s(_DrawingEditorMixin,Drawing):\n' % n + s = s + '\tdef __init__(self,width=%s,height=%s,*args,**kw):\n' % (self.width,self.height) + s = s + '\t\tDrawing.__init__(self,width,height,*args,**kw)\n' + s = s + G + s = s + '\n\nif __name__=="__main__": #NORUNTESTS\n\t%s().save(formats=[\'pdf\'],outDir=\'.\',fnRoot=None)\n' % n + return s + + def draw(self,showBoundary=_unset_): + """This is used by the Platypus framework to let the document + draw itself in a story. It is specific to PDF and should not + be used directly.""" + from reportlab.graphics import renderPDF + renderPDF.draw(self, self.canv, 0, 0, showBoundary=showBoundary) + + def wrap(self, availWidth, availHeight): + width = self.width + height = self.height + renderScale = self.renderScale + if renderScale!=1.0: + width *= renderScale + height *= renderScale + return width, height + + def expandUserNodes(self): + """Return a new drawing which only contains primitive shapes.""" + obj = Group.expandUserNodes(self) + obj.width = self.width + obj.height = self.height + return obj + + def copy(self): + """Returns a copy""" + return self._copy(self.__class__(self.width, self.height)) + + def asGroup(self,*args,**kw): + return self._copy(Group(*args,**kw)) + + def save(self, formats=None, verbose=None, fnRoot=None, outDir=None, title='', **kw): + """Saves copies of self in desired location and formats. + Multiple formats can be supported in one call + + the extra keywords can be of the form + _renderPM_dpi=96 (which passes dpi=96 to renderPM) + """ + genFmt = kw.pop('seqNumber','') + if isinstance(genFmt,int): + genFmt = '%4d: ' % genFmt + else: + genFmt = '' + genFmt += 'generating %s file %s' + from reportlab import rl_config + ext = '' + if not fnRoot: + fnRoot = getattr(self,'fileNamePattern',(self.__class__.__name__+'%03d')) + chartId = getattr(self,'chartId',0) + if hasattr(chartId,'__call__'): + chartId = chartId(self) + if hasattr(fnRoot,'__call__'): + fnRoot = fnRoot(chartId) + else: + try: + fnRoot = fnRoot % chartId + except TypeError as err: + #the exact error message changed from 2.2 to 2.3 so we need to + #check a substring + if str(err).find('not all arguments converted') < 0: raise + + if os.path.isabs(fnRoot): + outDir, fnRoot = os.path.split(fnRoot) + else: + outDir = outDir or getattr(self,'outDir','.') + outDir = outDir.rstrip().rstrip(os.sep) + if not outDir: outDir = '.' + if not os.path.isabs(outDir): outDir = os.path.join(getattr(self,'_override_CWD',os.path.dirname(sys.argv[0])),outDir) + if not os.path.isdir(outDir): os.makedirs(outDir) + fnroot = os.path.normpath(os.path.join(outDir,fnRoot)) + plotMode = os.path.splitext(fnroot) + if plotMode[1][1:].lower() in self._saveModes: + fnroot = plotMode[0] + + plotMode = [x.lower() for x in (formats or getattr(self,'formats',['pdf']))] + verbose = (verbose is not None and (verbose,) or (getattr(self,'verbose',verbose),))[0] + _saved = logger.warnOnce.enabled, logger.infoOnce.enabled + logger.warnOnce.enabled = logger.infoOnce.enabled = verbose + if 'pdf' in plotMode: + from reportlab.graphics import renderPDF + filename = fnroot+'.pdf' + if verbose: print(genFmt % ('PDF',filename)) + renderPDF.drawToFile(self, filename, title, showBoundary=getattr(self,'showBorder',rl_config.showBoundary),**_extraKW(self,'_renderPDF_',**kw)) + ext = ext + '/.pdf' + if sys.platform=='mac': + import macfs, macostools + macfs.FSSpec(filename).SetCreatorType("CARO", "PDF ") + macostools.touched(filename) + + for bmFmt in ('gif','png','tif','jpg','tiff','pct','pict', 'bmp','tiffp','tiffl','tiff1'): + if bmFmt in plotMode: + from reportlab.graphics import renderPM + filename = '%s.%s' % (fnroot,bmFmt) + if verbose: print(genFmt % (bmFmt,filename)) + dtc = getattr(self,'_drawTimeCollector',None) + if dtc: + dtcfmts = getattr(dtc,'formats',[bmFmt]) + if bmFmt in dtcfmts and not getattr(dtc,'disabled',0): + dtc.clear() + else: + dtc = None + renderPM.drawToFile(self, filename,fmt=bmFmt,showBoundary=getattr(self,'showBorder',rl_config.showBoundary),**_extraKW(self,'_renderPM_',**kw)) + ext = ext + '/.' + bmFmt + if dtc: dtc.save(filename) + + if 'eps' in plotMode: + try: + from rlextra.graphics import renderPS_SEP as renderPS + except ImportError: + from reportlab.graphics import renderPS + filename = fnroot+'.eps' + if verbose: print(genFmt % ('EPS',filename)) + renderPS.drawToFile(self, + filename, + title = fnroot, + dept = getattr(self,'EPS_info',['Testing'])[0], + company = getattr(self,'EPS_info',['','ReportLab'])[1], + preview = getattr(self,'preview',rl_config.eps_preview), + showBoundary=getattr(self,'showBorder',rl_config.showBoundary), + ttf_embed=getattr(self,'ttf_embed',rl_config.eps_ttf_embed), + **_extraKW(self,'_renderPS_',**kw)) + ext = ext + '/.eps' + + if 'svg' in plotMode: + from reportlab.graphics import renderSVG + filename = fnroot+'.svg' + if verbose: print(genFmt % ('SVG',filename)) + renderSVG.drawToFile(self, + filename, + showBoundary=getattr(self,'showBorder',rl_config.showBoundary),**_extraKW(self,'_renderSVG_',**kw)) + ext = ext + '/.svg' + + if 'ps' in plotMode: + from reportlab.graphics import renderPS + filename = fnroot+'.ps' + if verbose: print(genFmt % ('EPS',filename)) + renderPS.drawToFile(self, filename, showBoundary=getattr(self,'showBorder',rl_config.showBoundary),**_extraKW(self,'_renderPS_',**kw)) + ext = ext + '/.ps' + + if 'py' in plotMode: + filename = fnroot+'.py' + if verbose: print(genFmt % ('py',filename)) + open(filename,'wb').write(asBytes(self._renderPy().replace('\n',os.linesep))) + ext = ext + '/.py' + + logger.warnOnce.enabled, logger.infoOnce.enabled = _saved + if hasattr(self,'saveLogger'): + self.saveLogger(fnroot,ext) + return ext and fnroot+ext[1:] or '' + + def asString(self, format, verbose=None, preview=0, **kw): + """Converts to an 8 bit string in given format.""" + assert format in ('pdf','ps','eps','gif','png','jpg','jpeg','bmp','ppm','tiff','tif','py','pict','pct','tiffp','tiffl','tiff1'), 'Unknown file format "%s"' % format + from reportlab import rl_config + #verbose = verbose is not None and (verbose,) or (getattr(self,'verbose',verbose),)[0] + if format == 'pdf': + from reportlab.graphics import renderPDF + return renderPDF.drawToString(self) + elif format in ('gif','png','tif','tiff','jpg','pct','pict','bmp','ppm','tiffp','tiffl','tiff1'): + from reportlab.graphics import renderPM + return renderPM.drawToString(self, fmt=format,showBoundary=getattr(self,'showBorder', + rl_config.showBoundary),**_extraKW(self,'_renderPM_',**kw)) + elif format == 'eps': + try: + from rlextra.graphics import renderPS_SEP as renderPS + except ImportError: + from reportlab.graphics import renderPS + + return renderPS.drawToString(self, + preview = preview, + showBoundary=getattr(self,'showBorder',rl_config.showBoundary)) + elif format == 'ps': + from reportlab.graphics import renderPS + return renderPS.drawToString(self, showBoundary=getattr(self,'showBorder',rl_config.showBoundary)) + elif format == 'py': + return self._renderPy() + + def resized(self,kind='fit',lpad=0,rpad=0,bpad=0,tpad=0): + '''return a base class drawing which ensures all the contents fits''' + C = self.getContents() + oW = self.width + oH = self.height + drawing = Drawing(oW,oH,*C) + xL,yL,xH,yH = drawing.getBounds() + if kind=='fit' or (kind=='expand' and (xLoW-rpad or yLoH-tpad)): + drawing.width = xH-xL+lpad+rpad + drawing.height = yH-yL+tpad+bpad + drawing.transform = (1,0,0,1,lpad-xL,bpad-yL) + elif kind=='fitx' or (kind=='expandx' and (xLoW-rpad)): + drawing.width = xH-xL+lpad+rpad + drawing.transform = (1,0,0,1,lpad-xL,0) + elif kind=='fity' or (kind=='expandy' and (yLoH-tpad)): + drawing.height = yH-yL+tpad+bpad + drawing.transform = (1,0,0,1,0,bpad-yL) + return drawing + +class _DrawingEditorMixin: + '''This is a mixin to provide functionality for edited drawings''' + def _add(self,obj,value,name=None,validate=None,desc=None,pos=None): + ''' + effectively setattr(obj,name,value), but takes care of things with _attrMaps etc + ''' + ivc = isValidChild(value) + if name and hasattr(obj,'_attrMap'): + if '_attrMap' not in obj.__dict__: + obj._attrMap = obj._attrMap.clone() + if ivc and validate is None: validate = isValidChild + obj._attrMap[name] = AttrMapValue(validate,desc) + if hasattr(obj,'add') and ivc: + if pos: + obj.insert(pos,value,name) + else: + obj.add(value,name) + elif name: + setattr(obj,name,value) + else: + raise ValueError("Can't add, need name") + +class LineShape(Shape): + # base for types of lines + + _attrMap = AttrMap( + strokeColor = AttrMapValue(isColorOrNone), + strokeWidth = AttrMapValue(isNumber), + strokeLineCap = AttrMapValue(OneOf(0,1,2),desc="Line cap 0=butt, 1=round & 2=square"), + strokeLineJoin = AttrMapValue(OneOf(0,1,2),desc="Line join 0=miter, 1=round & 2=bevel"), + strokeMiterLimit = AttrMapValue(isNumber,desc="miter limit control miter line joins"), + strokeDashArray = AttrMapValue(isListOfNumbersOrNone,desc="a sequence of numbers represents on and off, e.g. (2,1)"), + strokeOpacity = AttrMapValue(isOpacity,desc="The level of transparency of the line, any real number betwen 0 and 1"), + strokeOverprint = AttrMapValue(isBoolean,desc='Turn on stroke overprinting'), + overprintMask = AttrMapValue(isBoolean,desc='overprinting for ordinary CMYK',advancedUsage=1), + ) + + def __init__(self, kw): + self.strokeColor = STATE_DEFAULTS['strokeColor'] + self.strokeWidth = 1 + self.strokeLineCap = 0 + self.strokeLineJoin = 0 + self.strokeMiterLimit = 0 + self.strokeDashArray = None + self.strokeOpacity = None + self.setProperties(kw) + + +class Line(LineShape): + _attrMap = AttrMap(BASE=LineShape, + x1 = AttrMapValue(isNumber,desc=""), + y1 = AttrMapValue(isNumber,desc=""), + x2 = AttrMapValue(isNumber,desc=""), + y2 = AttrMapValue(isNumber,desc=""), + ) + + def __init__(self, x1, y1, x2, y2, **kw): + LineShape.__init__(self, kw) + self.x1 = x1 + self.y1 = y1 + self.x2 = x2 + self.y2 = y2 + + def getBounds(self): + "Returns bounding rectangle of object as (x1,y1,x2,y2)" + return (self.x1, self.y1, self.x2, self.y2) + +class SolidShape(LineShape): + # base for anything with outline and content + + _attrMap = AttrMap(BASE=LineShape, + fillColor = AttrMapValue(isColorOrNone,desc="filling color of the shape, e.g. red"), + fillOpacity = AttrMapValue(isOpacity,desc="the level of transparency of the color, any real number between 0 and 1"), + fillOverprint = AttrMapValue(isBoolean,desc='Turn on fill overprinting'), + overprintMask = AttrMapValue(isBoolean,desc='overprinting for ordinary CMYK',advancedUsage=1), + ) + + def __init__(self, kw): + self.fillColor = STATE_DEFAULTS['fillColor'] + self.fillOpacity = None + # do this at the end so keywords overwrite + #the above settings + LineShape.__init__(self, kw) + + +# path operator constants +_MOVETO, _LINETO, _CURVETO, _CLOSEPATH = list(range(4)) +_PATH_OP_ARG_COUNT = (2, 2, 6, 0) # [moveTo, lineTo, curveTo, closePath] +_PATH_OP_NAMES=['moveTo','lineTo','curveTo','closePath'] + +def _renderPath(path, drawFuncs): + """Helper function for renderers.""" + # this could be a method of Path... + points = path.points + i = 0 + hadClosePath = 0 + hadMoveTo = 0 + for op in path.operators: + nArgs = _PATH_OP_ARG_COUNT[op] + func = drawFuncs[op] + j = i + nArgs + func(*points[i:j]) + i = j + if op == _CLOSEPATH: + hadClosePath = hadClosePath + 1 + if op == _MOVETO: + hadMoveTo += 1 + return hadMoveTo == hadClosePath + +class Path(SolidShape): + """Path, made up of straight lines and bezier curves.""" + + _attrMap = AttrMap(BASE=SolidShape, + points = AttrMapValue(isListOfNumbers), + operators = AttrMapValue(isListOfNumbers), + isClipPath = AttrMapValue(isBoolean), + ) + + def __init__(self, points=None, operators=None, isClipPath=0, **kw): + SolidShape.__init__(self, kw) + if points is None: + points = [] + if operators is None: + operators = [] + assert len(points) % 2 == 0, 'Point list must have even number of elements!' + self.points = points + self.operators = operators + self.isClipPath = isClipPath + + def copy(self): + new = self.__class__(self.points[:], self.operators[:]) + new.setProperties(self.getProperties()) + return new + + def moveTo(self, x, y): + self.points.extend([x, y]) + self.operators.append(_MOVETO) + + def lineTo(self, x, y): + self.points.extend([x, y]) + self.operators.append(_LINETO) + + def curveTo(self, x1, y1, x2, y2, x3, y3): + self.points.extend([x1, y1, x2, y2, x3, y3]) + self.operators.append(_CURVETO) + + def closePath(self): + self.operators.append(_CLOSEPATH) + + def getBounds(self): + points = self.points + try: #in case this complex algorithm is not yet ready :) + X = [] + aX = X.append + eX = X.extend + Y=[] + aY = Y.append + eY = Y.extend + i = 0 + for op in self.operators: + nArgs = _PATH_OP_ARG_COUNT[op] + j = i + nArgs + if nArgs==2: + #either moveTo or lineT0 + aX(points[i]) + aY(points[i+1]) + elif nArgs==6: + #curveTo + x1,x2,x3 = points[i:j:2] + eX(_getBezierExtrema(X[-1],x1,x2,x3)) + y1,y2,y3 = points[i+1:j:2] + eY(_getBezierExtrema(Y[-1],y1,y2,y3)) + i = j + return min(X),min(Y),max(X),max(Y) + except: + return getPathBounds(points) + +EmptyClipPath=Path() #special path + +def getArcPoints(centerx, centery, radius, startangledegrees, endangledegrees, yradius=None, degreedelta=None, reverse=None): + if yradius is None: yradius = radius + points = [] + from math import sin, cos, pi + degreestoradians = pi/180.0 + startangle = startangledegrees*degreestoradians + endangle = endangledegrees*degreestoradians + while endangle.001: + degreedelta = min(angle,degreedelta or 1.) + radiansdelta = degreedelta*degreestoradians + n = max(int(angle/radiansdelta+0.5),1) + radiansdelta = angle/n + n += 1 + else: + n = 1 + radiansdelta = 0 + + for angle in range(n): + angle = startangle+angle*radiansdelta + a((centerx+radius*cos(angle),centery+yradius*sin(angle))) + + if reverse: points.reverse() + return points + +class ArcPath(Path): + '''Path with an addArc method''' + def addArc(self, centerx, centery, radius, startangledegrees, endangledegrees, yradius=None, degreedelta=None, moveTo=None, reverse=None): + P = getArcPoints(centerx, centery, radius, startangledegrees, endangledegrees, yradius=yradius, degreedelta=degreedelta, reverse=reverse) + if moveTo or not len(self.operators): + self.moveTo(P[0][0],P[0][1]) + del P[0] + for x, y in P: self.lineTo(x,y) + +def definePath(pathSegs=[],isClipPath=0, dx=0, dy=0, **kw): + O = [] + P = [] + for seg in pathSegs: + if not isSeq(seg): + opName = seg + args = [] + else: + opName = seg[0] + args = seg[1:] + if opName not in _PATH_OP_NAMES: + raise ValueError('bad operator name %s' % opName) + op = _PATH_OP_NAMES.index(opName) + if len(args)!=_PATH_OP_ARG_COUNT[op]: + raise ValueError('%s bad arguments %s' % (opName,str(args))) + O.append(op) + P.extend(list(args)) + for d,o in (dx,0), (dy,1): + for i in range(o,len(P),2): + P[i] = P[i]+d + return Path(P,O,isClipPath,**kw) + +class Rect(SolidShape): + """Rectangle, possibly with rounded corners.""" + + _attrMap = AttrMap(BASE=SolidShape, + x = AttrMapValue(isNumber), + y = AttrMapValue(isNumber), + width = AttrMapValue(isNumber,desc="width of the object in points"), + height = AttrMapValue(isNumber,desc="height of the objects in points"), + rx = AttrMapValue(isNumber), + ry = AttrMapValue(isNumber), + ) + + def __init__(self, x, y, width, height, rx=0, ry=0, **kw): + SolidShape.__init__(self, kw) + self.x = x + self.y = y + self.width = width + self.height = height + self.rx = rx + self.ry = ry + + def copy(self): + new = self.__class__(self.x, self.y, self.width, self.height) + new.setProperties(self.getProperties()) + return new + + def getBounds(self): + return (self.x, self.y, self.x + self.width, self.y + self.height) + + +class Image(SolidShape): + """Bitmap image.""" + + _attrMap = AttrMap(BASE=SolidShape, + x = AttrMapValue(isNumber), + y = AttrMapValue(isNumber), + width = AttrMapValue(isNumberOrNone,desc="width of the object in points"), + height = AttrMapValue(isNumberOrNone,desc="height of the objects in points"), + path = AttrMapValue(None), + ) + + def __init__(self, x, y, width, height, path, **kw): + SolidShape.__init__(self, kw) + self.x = x + self.y = y + self.width = width + self.height = height + self.path = path + + def copy(self): + new = self.__class__(self.x, self.y, self.width, self.height, self.path) + new.setProperties(self.getProperties()) + return new + + def getBounds(self): + # bug fix contributed by Marcel Tromp + return (self.x, self.y, self.x + self.width, self.y + self.height) + +class Circle(SolidShape): + + _attrMap = AttrMap(BASE=SolidShape, + cx = AttrMapValue(isNumber,desc="x of the centre"), + cy = AttrMapValue(isNumber,desc="y of the centre"), + r = AttrMapValue(isNumber,desc="radius in points"), + ) + + def __init__(self, cx, cy, r, **kw): + SolidShape.__init__(self, kw) + self.cx = cx + self.cy = cy + self.r = r + + def copy(self): + new = self.__class__(self.cx, self.cy, self.r) + new.setProperties(self.getProperties()) + return new + + def getBounds(self): + return (self.cx - self.r, self.cy - self.r, self.cx + self.r, self.cy + self.r) + +class Ellipse(SolidShape): + _attrMap = AttrMap(BASE=SolidShape, + cx = AttrMapValue(isNumber,desc="x of the centre"), + cy = AttrMapValue(isNumber,desc="y of the centre"), + rx = AttrMapValue(isNumber,desc="x radius"), + ry = AttrMapValue(isNumber,desc="y radius"), + ) + + def __init__(self, cx, cy, rx, ry, **kw): + SolidShape.__init__(self, kw) + self.cx = cx + self.cy = cy + self.rx = rx + self.ry = ry + + def copy(self): + new = self.__class__(self.cx, self.cy, self.rx, self.ry) + new.setProperties(self.getProperties()) + return new + + def getBounds(self): + return (self.cx - self.rx, self.cy - self.ry, self.cx + self.rx, self.cy + self.ry) + +class Wedge(SolidShape): + """A "slice of a pie" by default translates to a polygon moves anticlockwise + from start angle to end angle""" + + _attrMap = AttrMap(BASE=SolidShape, + centerx = AttrMapValue(isNumber,desc="x of the centre"), + centery = AttrMapValue(isNumber,desc="y of the centre"), + radius = AttrMapValue(isNumber,desc="radius in points"), + startangledegrees = AttrMapValue(isNumber), + endangledegrees = AttrMapValue(isNumber), + yradius = AttrMapValue(isNumberOrNone), + radius1 = AttrMapValue(isNumberOrNone), + yradius1 = AttrMapValue(isNumberOrNone), + annular = AttrMapValue(isBoolean,desc='treat as annular ring'), + ) + + degreedelta = 1 # jump every 1 degrees + + def __init__(self, centerx, centery, radius, startangledegrees, endangledegrees, yradius=None, + annular=False, **kw): + SolidShape.__init__(self, kw) + while endangledegrees0.001: + degreedelta = min(self.degreedelta or 1.,angle) + radiansdelta = degreedelta*degreestoradians + n = max(1,int(angle/radiansdelta+0.5)) + radiansdelta = angle/n + n += 1 + else: + n = 1 + radiansdelta = 0 + CA = [] + CAA = CA.append + a = points.append + for angle in xrange(n): + angle = startangle+angle*radiansdelta + CAA((cos(angle),sin(angle))) + for c,s in CA: + a(centerx+radius*c) + a(centery+yradius*s) + if (radius1==0 or radius1 is None) and (yradius1==0 or yradius1 is None): + a(centerx); a(centery) + else: + CA.reverse() + for c,s in CA: + a(centerx+radius1*c) + a(centery+yradius1*s) + if self.annular: + P = Path() + P.moveTo(points[0],points[1]) + for x in xrange(2,2*n,2): + P.lineTo(points[x],points[x+1]) + P.closePath() + P.moveTo(points[2*n],points[2*n+1]) + for x in xrange(2*n+2,4*n,2): + P.lineTo(points[x],points[x+1]) + P.closePath() + return P + else: + return Polygon(points) + + def copy(self): + new = self.__class__(self.centerx, + self.centery, + self.radius, + self.startangledegrees, + self.endangledegrees) + new.setProperties(self.getProperties()) + return new + + def getBounds(self): + return self.asPolygon().getBounds() + +class Polygon(SolidShape): + """Defines a closed shape; Is implicitly + joined back to the start for you.""" + + _attrMap = AttrMap(BASE=SolidShape, + points = AttrMapValue(isListOfNumbers,desc="list of numbers in the form x1, y1, x2, y2 ... xn, yn"), + ) + + def __init__(self, points=[], **kw): + SolidShape.__init__(self, kw) + assert len(points) % 2 == 0, 'Point list must have even number of elements!' + self.points = points or [] + + def copy(self): + new = self.__class__(self.points) + new.setProperties(self.getProperties()) + return new + + def getBounds(self): + return getPointsBounds(self.points) + +class PolyLine(LineShape): + """Series of line segments. Does not define a + closed shape; never filled even if apparently joined. + Put the numbers in the list, not two-tuples.""" + + _attrMap = AttrMap(BASE=LineShape, + points = AttrMapValue(isListOfNumbers,desc="list of numbers in the form x1, y1, x2, y2 ... xn, yn"), + ) + + def __init__(self, points=[], **kw): + LineShape.__init__(self, kw) + points = points or [] + lenPoints = len(points) + if lenPoints: + if isSeq(points[0]): + L = [] + for (x,y) in points: + L.append(x) + L.append(y) + points = L + else: + assert len(points) % 2 == 0, 'Point list must have even number of elements!' + self.points = points + + def copy(self): + new = self.__class__(self.points) + new.setProperties(self.getProperties()) + return new + + def getBounds(self): + return getPointsBounds(self.points) + +def numericXShift(tA,text,w,fontName,fontSize,encoding=None,pivotCharacter=decimalSymbol): + dp = getattr(tA,'_dp',pivotCharacter) + i = text.rfind(dp) + if i>=0: + dpOffs = getattr(tA,'_dpLen',0) + w = dpOffs + stringWidth(text[:i],fontName,fontSize,encoding) + return w + +class String(Shape): + """Not checked against the spec, just a way to make something work. + Can be anchored left, middle or end.""" + + # to do. + _attrMap = AttrMap( + x = AttrMapValue(isNumber,desc="x point of anchoring"), + y = AttrMapValue(isNumber,desc="y point of anchoring"), + text = AttrMapValue(isString,desc="the text of the string"), + fontName = AttrMapValue(None,desc="font name of the text - font is either acrobat standard or registered when using external font."), + fontSize = AttrMapValue(isNumber,desc="font size"), + fillColor = AttrMapValue(isColorOrNone,desc="color of the font"), + textAnchor = AttrMapValue(OneOf('start','middle','end','numeric'),desc="treat (x,y) as one of the options below."), + encoding = AttrMapValue(isString), + ) + encoding = 'utf8' + + def __init__(self, x, y, text, **kw): + self.x = x + self.y = y + self.text = text + self.textAnchor = 'start' + self.fontName = STATE_DEFAULTS['fontName'] + self.fontSize = STATE_DEFAULTS['fontSize'] + self.fillColor = STATE_DEFAULTS['fillColor'] + self.setProperties(kw) + + def getEast(self): + return self.x + stringWidth(self.text,self.fontName,self.fontSize, self.encoding) + + def copy(self): + new = self.__class__(self.x, self.y, self.text) + new.setProperties(self.getProperties()) + return new + + def getBounds(self): + # assumes constant drop of 0.2*size to baseline + t = self.text + w = stringWidth(t,self.fontName,self.fontSize,self.encoding) + tA = self.textAnchor + x = self.x + if tA!='start': + if tA=='middle': + x -= 0.5*w + elif tA=='end': + x -= w + elif tA=='numeric': + x -= numericXShift(tA,t,w,self.fontName,self.fontSize,self.encoding) + return (x, self.y - 0.2 * self.fontSize, x+w, self.y + self.fontSize) + +class UserNode(_DrawTimeResizeable): + """A simple template for creating a new node. The user (Python + programmer) may subclasses this. provideNode() must be defined to + provide a Shape primitive when called by a renderer. It does + NOT inherit from Shape, as the renderer always replaces it, and + your own classes can safely inherit from it without getting + lots of unintended behaviour.""" + + def provideNode(self): + """Override this to create your own node. This lets widgets be + added to drawings; they must create a shape (typically a group) + so that the renderer can draw the custom node.""" + + raise NotImplementedError("this method must be redefined by the user/programmer") + + +def test(): + r = Rect(10,10,200,50) + import pprint + pp = pprint.pprint + w = sys.stdout.write + w('a Rectangle: ') + pp(r.getProperties()) + w('\nverifying...') + r.verify() + w(' OK\n') + #print 'setting rect.z = "spam"' + #r.z = 'spam' + w('deleting rect.width ') + del r.width + w('verifying...') + r.verify() + + +if __name__=='__main__': + test() diff --git a/reportlab/graphics/testdrawings.py b/reportlab/graphics/testdrawings.py new file mode 100644 index 00000000..1422d94e --- /dev/null +++ b/reportlab/graphics/testdrawings.py @@ -0,0 +1,296 @@ +#!/bin/env python +#Copyright ReportLab Europe Ltd. 2000-2012 +#see license.txt for license details +#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/graphics/testdrawings.py +__version__=''' $Id $ ''' +__doc__="""Defines some standard drawings to use as test cases + +This contains a number of routines to generate test drawings +for reportlab/graphics. For now they are contrived, but we will expand them +to try and trip up any parser. Feel free to add more. + +""" + +from reportlab.graphics.shapes import * +from reportlab.lib import colors + +def getDrawing1(): + """Hello World, on a rectangular background""" + + D = Drawing(400, 200) + D.add(Rect(50, 50, 300, 100, fillColor=colors.yellow)) #round corners + D.add(String(180,100, 'Hello World', fillColor=colors.red)) + + + return D + + +def getDrawing2(): + """This demonstrates the basic shapes. There are + no groups or references. Each solid shape should have + a purple fill.""" + D = Drawing(400, 200) #, fillColor=colors.purple) + + D.add(Line(10,10,390,190)) + D.add(Circle(100,100,20, fillColor=colors.purple)) + D.add(Circle(200,100,20, fillColor=colors.purple)) + D.add(Circle(300,100,20, fillColor=colors.purple)) + + D.add(Wedge(330,100,40, -10,40, fillColor=colors.purple)) + + D.add(PolyLine([120,10,130,20,140,10,150,20,160,10, + 170,20,180,10,190,20,200,10])) + + D.add(Polygon([300,20,350,20,390,80,300,75, 330, 40])) + + D.add(Ellipse(50, 150, 40, 20)) + + D.add(Rect(120, 150, 60, 30, + strokeWidth=10, + strokeColor=colors.red, + fillColor=colors.yellow)) #square corners + + D.add(Rect(220, 150, 60, 30, 10, 10)) #round corners + + D.add(String(10,50, 'Basic Shapes', fillColor=colors.black)) + + return D + + +##def getDrawing2(): +## """This drawing uses groups. Each group has two circles and a comment. +## The line style is set at group level and should be red for the left, +## bvlue for the right.""" +## D = Drawing(400, 200) +## +## Group1 = Group() +## +## Group1.add(String(50, 50, 'Group 1', fillColor=colors.black)) +## Group1.add(Circle(75,100,25)) +## Group1.add(Circle(125,100,25)) +## D.add(Group1) +## +## Group2 = Group( +## String(250, 50, 'Group 2', fillColor=colors.black), +## Circle(275,100,25), +## Circle(325,100,25)#, + + +##def getDrawing2(): +## """This drawing uses groups. Each group has two circles and a comment. +## The line style is set at group level and should be red for the left, +## bvlue for the right.""" +## D = Drawing(400, 200) +## +## Group1 = Group() +## +## Group1.add(String(50, 50, 'Group 1', fillColor=colors.black)) +## Group1.add(Circle(75,100,25)) +## Group1.add(Circle(125,100,25)) +## D.add(Group1) +## +## Group2 = Group( +## String(250, 50, 'Group 2', fillColor=colors.black), +## Circle(275,100,25), +## Circle(325,100,25)#, +## +## #group attributes +## #strokeColor=colors.blue +## ) +## D.add(Group2) + +## return D +## +## +##def getDrawing3(): +## """This uses a named reference object. The house is a 'subroutine' +## the basic brick colored walls are defined, but the roof and window +## color are undefined and may be set by the container.""" +## +## D = Drawing(400, 200, fill=colors.bisque) +## +## +## House = Group( +## Rect(2,20,36,30, fill=colors.bisque), #walls +## Polygon([0,20,40,20,20,5]), #roof +## Rect(8, 38, 8, 12), #door +## Rect(25, 38, 8, 7), #window +## Rect(8, 25, 8, 7), #window +## Rect(25, 25, 8, 7) #window +## +## ) +## D.addDef('MyHouse', House) +## +## # one row all the same color +## D.add(String(20, 40, 'British Street...',fill=colors.black)) +## for i in range(6): +## x = i * 50 +## D.add(NamedReference('MyHouse', +## House, +## transform=translate(x, 40), +## fill = colors.brown +## ) +## ) +## +## # now do a row all different +## D.add(String(20, 120, 'Mediterranean Street...',fill=colors.black)) +## x = 0 +## for color in (colors.blue, colors.yellow, colors.orange, +## colors.red, colors.green, colors.chartreuse): +## D.add(NamedReference('MyHouse', +## House, +## transform=translate(x,120), +## fill = color, +## ) +## ) +## x = x + 50 +## #..by popular demand, the mayor gets a big one at the end +## D.add(NamedReference('MyHouse', +## House, +## transform=mmult(translate(x,110), scale(1.2,1.2)), +## fill = color, +## ) +## ) +## +## +## return D +## +##def getDrawing4(): +## """This tests that attributes are 'unset' correctly when +## one steps back out of a drawing node. All the circles are part of a +## group setting the line color to blue; the second circle explicitly +## sets it to red. Ideally, the third circle should go back to blue.""" +## D = Drawing(400, 200) +## +## +## G = Group( +## Circle(100,100,20), +## Circle(200,100,20, stroke=colors.blue), +## Circle(300,100,20), +## stroke=colors.red, +## stroke_width=3, +## fill=colors.aqua +## ) +## D.add(G) +## +## +## D.add(String(10,50, 'Stack Unwinding - should be red, blue, red')) +## +## return D +## +## +##def getDrawing5(): +## """This Rotates Coordinate Axes""" +## D = Drawing(400, 200) +## +## +## +## Axis = Group( +## Line(0,0,100,0), #x axis +## Line(0,0,0,50), # y axis +## Line(0,10,10,10), #ticks on y axis +## Line(0,20,10,20), +## Line(0,30,10,30), +## Line(0,40,10,40), +## Line(10,0,10,10), #ticks on x axis +## Line(20,0,20,10), +## Line(30,0,30,10), +## Line(40,0,40,10), +## Line(50,0,50,10), +## Line(60,0,60,10), +## Line(70,0,70,10), +## Line(80,0,80,10), +## Line(90,0,90,10), +## String(20, 35, 'Axes', fill=colors.black) +## ) +## +## D.addDef('Axes', Axis) +## +## D.add(NamedReference('Axis', Axis, +## transform=translate(10,10))) +## D.add(NamedReference('Axis', Axis, +## transform=mmult(translate(150,10),rotate(15))) +## ) +## return D +## +##def getDrawing6(): +## """This Rotates Text""" +## D = Drawing(400, 300, fill=colors.black) +## +## xform = translate(200,150) +## C = (colors.black,colors.red,colors.green,colors.blue,colors.brown,colors.gray, colors.pink, +## colors.lavender,colors.lime, colors.mediumblue, colors.magenta, colors.limegreen) +## +## for i in range(12): +## D.add(String(0, 0, ' - - Rotated Text', fill=C[i%len(C)], transform=mmult(xform, rotate(30*i)))) +## +## return D +## +##def getDrawing7(): +## """This defines and tests a simple UserNode0 (the trailing zero denotes +## an experimental method which is not part of the supported API yet). +## Each of the four charts is a subclass of UserNode which generates a random +## series when rendered.""" +## +## class MyUserNode(UserNode0): +## import whrandom, math +## +## +## def provideNode(self, sender): +## """draw a simple chart that changes everytime it's drawn""" +## # print "here's a random number %s" % self.whrandom.random() +## #print "MyUserNode.provideNode being called by %s" % sender +## g = Group() +## #g._state = self._state # this is naughty +## PingoNode.__init__(g, self._state) # is this less naughty ? +## w = 80.0 +## h = 50.0 +## g.add(Rect(0,0, w, h, stroke=colors.black)) +## N = 10.0 +## x,y = (0,h) +## dx = w/N +## for ii in range(N): +## dy = (h/N) * self.whrandom.random() +## g.add(Line(x,y,x+dx, y-dy)) +## x = x + dx +## y = y - dy +## return g +## +## D = Drawing(400,200, fill=colors.white) # AR - same size as others +## +## D.add(MyUserNode()) +## +## graphcolor= [colors.green, colors.red, colors.brown, colors.purple] +## for ii in range(4): +## D.add(Group( MyUserNode(stroke=graphcolor[ii], stroke_width=2), +## transform=translate(ii*90,0) )) +## +## #un = MyUserNode() +## #print un.provideNode() +## return D +## +##def getDrawing8(): +## """Test Path operations--lineto, curveTo, etc.""" +## D = Drawing(400, 200, fill=None, stroke=colors.purple, stroke_width=2) +## +## xform = translate(200,100) +## C = (colors.black,colors.red,colors.green,colors.blue,colors.brown,colors.gray, colors.pink, +## colors.lavender,colors.lime, colors.mediumblue, colors.magenta, colors.limegreen) +## p = Path(50,50) +## p.lineTo(100,100) +## p.moveBy(-25,25) +## p.curveTo(150,125, 125,125, 200,50) +## p.curveTo(175, 75, 175, 98, 62, 87) +## +## +## D.add(p) +## D.add(String(10,30, 'Tests of path elements-lines and bezier curves-and text formating')) +## D.add(Line(220,150, 220,200, stroke=colors.red)) +## D.add(String(220,180, "Text should be centered", text_anchor="middle") ) +## +## +## return D + + +if __name__=='__main__': + print(__doc__) diff --git a/reportlab/graphics/testshapes.py b/reportlab/graphics/testshapes.py new file mode 100644 index 00000000..ce1b7833 --- /dev/null +++ b/reportlab/graphics/testshapes.py @@ -0,0 +1,580 @@ +#!/bin/env python +#Copyright ReportLab Europe Ltd. 2000-2012 +#see license.txt for license details +#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/graphics/testshapes.py + +# testshapes.py - draws shapes onto a PDF canvas. + + +__version__ = ''' $Id $ ''' +__doc__='''Execute this script to see some test drawings. + +This contains a number of routines to generate test drawings +for reportlab/graphics. For now many of them are contrived, +but we will expand them to try and trip up any parser. +Feel free to add more. +''' + +import os, sys + +from reportlab.lib import colors +from reportlab.lib.units import cm +from reportlab.lib.utils import asNative +from reportlab.pdfgen.canvas import Canvas +from reportlab.pdfbase.pdfmetrics import stringWidth +from reportlab.platypus import Flowable +from reportlab.graphics.shapes import * +from reportlab.graphics.renderPDF import _PDFRenderer +import unittest + +_FONTS = ['Times-Roman','Vera','Times-BoldItalic',] + +def _setup(): + from reportlab.pdfbase import pdfmetrics, ttfonts + pdfmetrics.registerFont(ttfonts.TTFont("Vera", "Vera.ttf")) + pdfmetrics.registerFont(ttfonts.TTFont("VeraBd", "VeraBd.ttf")) + pdfmetrics.registerFont(ttfonts.TTFont("VeraIt", "VeraIt.ttf")) + pdfmetrics.registerFont(ttfonts.TTFont("VeraBI", "VeraBI.ttf")) + F = ['Times-Roman','Courier','Helvetica','Vera', 'VeraBd', 'VeraIt', 'VeraBI'] + if sys.platform=='win32': + for name, ttf in [ + ('Adventurer Light SF','Advlit.ttf'),('ArialMS','ARIAL.TTF'), + ('Arial Unicode MS', 'ARIALUNI.TTF'), + ('Book Antiqua','BKANT.TTF'), + ('Century Gothic','GOTHIC.TTF'), + ('Comic Sans MS', 'COMIC.TTF'), + ('Elementary Heavy SF Bold','Vwagh.ttf'), + ('Firenze SF','flot.ttf'), + ('Garamond','GARA.TTF'), + ('Jagger','Rols.ttf'), + ('Monotype Corsiva','MTCORSVA.TTF'), + ('Seabird SF','seag.ttf'), + ('Tahoma','TAHOMA.TTF'), + ('VerdanaMS','VERDANA.TTF'), + ]: + for D in ('c:\WINNT','c:\Windows'): + fn = os.path.join(D,'Fonts',ttf) + if os.path.isfile(fn): + try: + f = ttfonts.TTFont(name, fn) + pdfmetrics.registerFont(f) + F.append(name) + except: + pass + return F + +def resetFonts(): + for f in _setup(): + if f not in _FONTS: + _FONTS.append(f) +from reportlab.rl_config import register_reset +register_reset(resetFonts) +resetFonts() + +######################################################### +# +# Collections of shape drawings. +# +######################################################### +def getFailedDrawing(funcName): + """Generate a drawing in case something goes really wrong. + + This will create a drawing to be displayed whenever some + other drawing could not be executed, because the generating + function does something terribly wrong! The box contains + an attention triangle, plus some error message. + """ + + D = Drawing(400, 200) + + points = [200,170, 140,80, 260,80] + D.add(Polygon(points, + strokeWidth=0.5*cm, + strokeColor=colors.red, + fillColor=colors.yellow)) + + s = String(200, 40, + "Error in generating function '%s'!" % funcName, + textAnchor='middle') + D.add(s) + + return D + + +# These are the real drawings to be eye-balled. + +def getDrawing01(): + """Hello World, on a rectangular background. + + The rectangle's fillColor is yellow. + The string's fillColor is red. + """ + + D = Drawing(400, 200) + D.add(Rect(50, 50, 300, 100, fillColor=colors.yellow)) + D.add(String(180,100, 'Hello World', fillColor=colors.red)) + D.add(String(180,86, b'Special characters \xc2\xa2\xc2\xa9\xc2\xae\xc2\xa3\xce\xb1\xce\xb2', fillColor=colors.red)) + + return D + + +def getDrawing02(): + """Various Line shapes. + + The lines are blue and their strokeWidth is 5 mm. + One line has a strokeDashArray set to [5, 10, 15]. + """ + + D = Drawing(400, 200) + D.add(Line(50,50, 300,100, + strokeColor=colors.blue, + strokeWidth=0.5*cm, + )) + D.add(Line(50,100, 300,50, + strokeColor=colors.blue, + strokeWidth=0.5*cm, + strokeDashArray=[5, 10, 15], + )) + + #x = 1/0 # Comment this to see the actual drawing! + + return D + + +def getDrawing03(): + """Text strings in various sizes and different fonts. + + Font size increases from 12 to 36 and from bottom left + to upper right corner. The first ones should be in + Times-Roman. Finally, a solitary Courier string at + the top right corner. + """ + + D = Drawing(400, 200) + for size in range(12, 36, 4): + D.add(String(10+size*2, + 10+size*2, + 'Hello World', + fontName=_FONTS[0], + fontSize=size)) + + D.add(String(150, 150, + 'Hello World', + fontName=_FONTS[1], + fontSize=36)) + return D + + +def getDrawing04(): + """Text strings in various colours. + + Colours are blue, yellow and red from bottom left + to upper right. + """ + + D = Drawing(400, 200) + i = 0 + for color in (colors.blue, colors.yellow, colors.red): + D.add(String(50+i*30, 50+i*30, + 'Hello World', fillColor=color)) + i = i + 1 + + return D + + +def getDrawing05(): + """Text strings with various anchors (alignments). + + Text alignment conforms to the anchors in the left column. + """ + + D = Drawing(400, 200) + + lineX = 250 + D.add(Line(lineX,10, lineX,190, strokeColor=colors.gray)) + + y = 130 + for anchor in ('start', 'middle', 'end'): + D.add(String(lineX, y, 'Hello World', textAnchor=anchor)) + D.add(String(50, y, anchor + ':')) + y = y - 30 + + return D + + +def getDrawing06(): + """This demonstrates all the basic shapes at once. + + There are no groups or references. + Each solid shape should have a green fill. + """ + + green = colors.green + + D = Drawing(400, 200) #, fillColor=green) + + D.add(Line(10,10, 390,190)) + + D.add(Circle(100,100,20, fillColor=green)) + D.add(Circle(200,100,40, fillColor=green)) + D.add(Circle(300,100,30, fillColor=green)) + + D.add(Wedge(330,100,40, -10,40, fillColor=green)) + + D.add(PolyLine([120,10, 130,20, 140,10, 150,20, 160,10, + 170,20, 180,10, 190,20, 200,10], fillColor=green)) + + D.add(Polygon([300,20, 350,20, 390,80, 300,75, 330,40], fillColor=green)) + + D.add(Ellipse(50,150, 40, 20, fillColor=green)) + + D.add(Rect(120,150, 60,30, + strokeWidth=10, + strokeColor=colors.yellow, + fillColor=green)) #square corners + D.add(Rect(220, 150, 60, 30, 10, 10, fillColor=green)) #round corners + + D.add(String(10,50, 'Basic Shapes', fillColor=colors.black, fontName='Helvetica')) + + return D + +def getDrawing07(): + """This tests the ability to translate and rotate groups. The first set of axes should be + near the bottom left of the drawing. The second should be rotated counterclockwise + by 15 degrees. The third should be rotated by 30 degrees.""" + D = Drawing(400, 200) + + Axis = Group( + Line(0,0,100,0), #x axis + Line(0,0,0,50), # y axis + Line(0,10,10,10), #ticks on y axis + Line(0,20,10,20), + Line(0,30,10,30), + Line(0,40,10,40), + Line(10,0,10,10), #ticks on x axis + Line(20,0,20,10), + Line(30,0,30,10), + Line(40,0,40,10), + Line(50,0,50,10), + Line(60,0,60,10), + Line(70,0,70,10), + Line(80,0,80,10), + Line(90,0,90,10), + String(20, 35, 'Axes', fill=colors.black) + ) + + firstAxisGroup = Group(Axis) + firstAxisGroup.translate(10,10) + D.add(firstAxisGroup) + + secondAxisGroup = Group(Axis) + secondAxisGroup.translate(150,10) + secondAxisGroup.rotate(15) + + D.add(secondAxisGroup) + + + thirdAxisGroup = Group(Axis, transform=mmult(translate(300,10), rotate(30))) + D.add(thirdAxisGroup) + + return D + + +def getDrawing08(): + """This tests the ability to scale coordinates. The bottom left set of axes should be + near the bottom left of the drawing. The bottom right should be stretched vertically + by a factor of 2. The top left one should be stretched horizontally by a factor of 2. + The top right should have the vertical axiss leaning over to the right by 30 degrees.""" + D = Drawing(400, 200) + + Axis = Group( + Line(0,0,100,0), #x axis + Line(0,0,0,50), # y axis + Line(0,10,10,10), #ticks on y axis + Line(0,20,10,20), + Line(0,30,10,30), + Line(0,40,10,40), + Line(10,0,10,10), #ticks on x axis + Line(20,0,20,10), + Line(30,0,30,10), + Line(40,0,40,10), + Line(50,0,50,10), + Line(60,0,60,10), + Line(70,0,70,10), + Line(80,0,80,10), + Line(90,0,90,10), + String(20, 35, 'Axes', fill=colors.black) + ) + + firstAxisGroup = Group(Axis) + firstAxisGroup.translate(10,10) + D.add(firstAxisGroup) + + secondAxisGroup = Group(Axis) + secondAxisGroup.translate(150,10) + secondAxisGroup.scale(1,2) + D.add(secondAxisGroup) + + thirdAxisGroup = Group(Axis) + thirdAxisGroup.translate(10,125) + thirdAxisGroup.scale(2,1) + D.add(thirdAxisGroup) + + fourthAxisGroup = Group(Axis) + fourthAxisGroup.translate(250,125) + fourthAxisGroup.skew(30,0) + D.add(fourthAxisGroup) + + + return D + +def getDrawing09(): + """This tests rotated strings + + Some renderers will have a separate mechanism for font drawing. This test + just makes sure strings get transformed the same way as regular graphics.""" + D = Drawing(400, 200) + + fontName = _FONTS[0] + fontSize = 12 + text = "I should be totally horizontal and enclosed in a box" + textWidth = stringWidth(text, fontName, fontSize) + + + g1 = Group( + String(20, 20, text, fontName=fontName, fontSize = fontSize), + Rect(18, 18, textWidth + 4, fontSize + 4, fillColor=None) + ) + D.add(g1) + + text = "I should slope up by 15 degrees, so my right end is higher than my left" + textWidth = stringWidth(text, fontName, fontSize) + g2 = Group( + String(20, 20, text, fontName=fontName, fontSize = fontSize), + Rect(18, 18, textWidth + 4, fontSize + 4, fillColor=None) + ) + g2.translate(0, 50) + g2.rotate(15) + D.add(g2) + + return D + +def getDrawing10(): + """This tests nested groups with multiple levels of coordinate transformation. + Each box should be staggered up and to the right, moving by 25 points each time.""" + D = Drawing(400, 200) + + fontName = _FONTS[0] + fontSize = 12 + + g1 = Group( + Rect(0, 0, 100, 20, fillColor=colors.yellow), + String(5, 5, 'Text in the box', fontName=fontName, fontSize = fontSize) + ) + D.add(g1) + + g2 = Group(g1, transform = translate(25,25)) + D.add(g2) + + g3 = Group(g2, transform = translate(25,25)) + D.add(g3) + + g4 = Group(g3, transform = translate(25,25)) + D.add(g4) + + + return D + +from reportlab.graphics.widgets.signsandsymbols import SmileyFace +def getDrawing11(): + '''test of anchoring''' + def makeSmiley(x, y, size, color): + "Make a smiley data item representation." + d = size + s = SmileyFace() + s.fillColor = color + s.x = x-d + s.y = y-d + s.size = d*2 + return s + + D = Drawing(400, 200) #, fillColor=colors.purple) + g = Group(transform=(1,0,0,1,0,0)) + g.add(makeSmiley(100,100,10,colors.red)) + g.add(Line(90,100,110,100,strokeColor=colors.green)) + g.add(Line(100,90,100,110,strokeColor=colors.green)) + D.add(g) + g = Group(transform=(2,0,0,2,100,-100)) + g.add(makeSmiley(100,100,10,colors.blue)) + g.add(Line(90,100,110,100,strokeColor=colors.green)) + g.add(Line(100,90,100,110,strokeColor=colors.green)) + D.add(g) + g = Group(transform=(2,0,0,2,0,0)) + return D + + +def getDrawing12(): + """Text strings in a non-standard font. + All that is required is to place the .afm and .pfb files + on the font patch given in rl_config.py, + for example in reportlab/lib/fonts/. + """ + faceName = "DarkGardenMK" + D = Drawing(400, 200) + for size in range(12, 36, 4): + D.add(String(10+size*2, + 10+size*2, + 'Hello World', + fontName=faceName, + fontSize=size)) + return D + +def getDrawing13(): + 'Test Various TTF Fonts' + + def drawit(F,w=400,h=200,fontSize=12,slack=2,gap=5): + D = Drawing(w,h) + th = 2*gap + fontSize*1.2 + gh = gap + .2*fontSize + y = h + maxx = 0 + for fontName in F: + y -= th + text = fontName+asNative(b': I should be totally horizontal and enclosed in a box and end in alphabetagamma \xc2\xa2\xc2\xa9\xc2\xae\xc2\xa3\xca\xa5\xd0\x96\xd6\x83\xd7\x90\xd9\x82\xe0\xa6\x95\xce\xb1\xce\xb2\xce\xb3') + textWidth = stringWidth(text, fontName, fontSize) + maxx = max(maxx,textWidth+20) + D.add( + Group(Rect(8, y-gh, textWidth + 4, th, strokeColor=colors.red, strokeWidth=.5, fillColor=colors.lightgrey), + String(10, y, text, fontName=fontName, fontSize = fontSize))) + y -= 5 + return maxx, h-y+gap, D + maxx, maxy, D = drawit(_FONTS) + if maxx>400 or maxy>200: _,_,D = drawit(_FONTS,maxx,maxy) + return D + +##def getDrawing14(): +## """This tests inherited properties. Each font should be as it says.""" +## D = Drawing(400, 200) +## +## fontSize = 12 +## D.fontName = 'Courier' +## +## g1 = Group( +## Rect(0, 0, 150, 20, fillColor=colors.yellow), +## String(5, 5, 'Inherited Courier', fontName=inherit, fontSize = fontSize) +## ) +## D.add(g1) +## +## g2 = Group(g1, transform = translate(25,25)) +## D.add(g2) +## +## g3 = Group(g2, transform = translate(25,25)) +## D.add(g3) +## +## g4 = Group(g3, transform = translate(25,25)) +## D.add(g4) +## +## +## return D +def getAllFunctionDrawingNames(doTTF=1): + "Get a list of drawing function names from somewhere." + + funcNames = [] + + # Here we get the names from the global name space. + symbols = list(globals().keys()) + symbols.sort() + for funcName in symbols: + if funcName[0:10] == 'getDrawing': + if doTTF or funcName!='getDrawing13': + funcNames.append(funcName) + + return funcNames + +def _evalFuncDrawing(name, D, l=None, g=None): + try: + d = eval(name + '()', g or globals(), l or locals()) + except: + d = getFailedDrawing(name) + D.append((d, eval(name + '.__doc__'), name[3:])) + +def getAllTestDrawings(doTTF=1): + D = [] + for f in getAllFunctionDrawingNames(doTTF=doTTF): + _evalFuncDrawing(f,D) + return D + +def writePDF(drawings): + "Create and save a PDF file containing some drawings." + + pdfPath = os.path.splitext(sys.argv[0])[0] + '.pdf' + c = Canvas(pdfPath) + c.setFont(_FONTS[0], 32) + c.drawString(80, 750, 'ReportLab Graphics-Shapes Test') + + # Print drawings in a loop, with their doc strings. + c.setFont(_FONTS[0], 12) + y = 740 + i = 1 + for (drawing, docstring, funcname) in drawings: + if y < 300: # Allows 5-6 lines of text. + c.showPage() + y = 740 + # Draw a title. + y = y - 30 + c.setFont(_FONTS[2],12) + c.drawString(80, y, '%s (#%d)' % (funcname, i)) + c.setFont(_FONTS[0],12) + y = y - 14 + textObj = c.beginText(80, y) + textObj.textLines(docstring) + c.drawText(textObj) + y = textObj.getY() + y = y - drawing.height + drawing.drawOn(c, 80, y) + i = i + 1 + + c.save() + print('wrote %s ' % pdfPath) + + +class ShapesTestCase(unittest.TestCase): + "Test generating all kinds of shapes." + + def setUp(self): + "Prepare some things before the tests start." + + self.funcNames = getAllFunctionDrawingNames() + self.drawings = [] + + + def tearDown(self): + "Do what has to be done after the tests are over." + + writePDF(self.drawings) + + + # This should always succeed. If each drawing would be + # wrapped in a dedicated test method like this one, it + # would be possible to have a count for wrong tests + # as well... Something like this is left for later... + def testAllDrawings(self): + "Make a list of drawings." + + for f in self.funcNames: + if f[0:10] == 'getDrawing': + # Make an instance and get its doc string. + # If that fails, use a default error drawing. + _evalFuncDrawing(f,self.drawings) + + +def makeSuite(): + "Make a test suite for unit testing." + + suite = unittest.TestSuite() + suite.addTest(ShapesTestCase('testAllDrawings')) + return suite + + +if __name__ == "__main__": + unittest.TextTestRunner().run(makeSuite()) diff --git a/reportlab/graphics/widgetbase.py b/reportlab/graphics/widgetbase.py new file mode 100644 index 00000000..056a1e4e --- /dev/null +++ b/reportlab/graphics/widgetbase.py @@ -0,0 +1,529 @@ +#Copyright ReportLab Europe Ltd. 2000-2012 +#see license.txt for license details +#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/graphics/widgetbase.py +__version__=''' $Id$ ''' +__doc__='''Base class for user-defined graphical widgets''' + +from reportlab.graphics import shapes +from reportlab import rl_config +from reportlab.lib import colors +from reportlab.lib.validators import * +from reportlab.lib.attrmap import * + +class PropHolder: + '''Base for property holders''' + + _attrMap = None + + def verify(self): + """If the _attrMap attribute is not None, this + checks all expected attributes are present; no + unwanted attributes are present; and (if a + checking function is found) checks each + attribute has a valid value. Either succeeds + or raises an informative exception. + """ + + if self._attrMap is not None: + for key in self.__dict__.keys(): + if key[0] != '_': + msg = "Unexpected attribute %s found in %s" % (key, self) + assert key in self._attrMap, msg + for attr, metavalue in self._attrMap.items(): + msg = "Missing attribute %s from %s" % (attr, self) + assert hasattr(self, attr), msg + value = getattr(self, attr) + args = (value, attr, self.__class__.__name__) + assert metavalue.validate(value), "Invalid value %s for attribute %s in class %s" % args + + if rl_config.shapeChecking: + """This adds the ability to check every attribute assignment + as it is made. It slows down shapes but is a big help when + developing. It does not get defined if rl_config.shapeChecking = 0. + """ + + def __setattr__(self, name, value): + """By default we verify. This could be off + in some parallel base classes.""" + validateSetattr(self,name,value) + + + def getProperties(self,recur=1): + """Returns a list of all properties which can be edited and + which are not marked as private. This may include 'child + widgets' or 'primitive shapes'. You are free to override + this and provide alternative implementations; the default + one simply returns everything without a leading underscore. + """ + + from reportlab.lib.validators import isValidChild + + # TODO when we need it, but not before - + # expose sequence contents? + + props = {} + for name in self.__dict__.keys(): + if name[0:1] != '_': + component = getattr(self, name) + + if recur and isValidChild(component): + # child object, get its properties too + childProps = component.getProperties(recur=recur) + for childKey, childValue in childProps.items(): + #key might be something indexed like '[2].fillColor' + #or simple like 'fillColor'; in the former case we + #don't need a '.' between me and my child. + if childKey[0] == '[': + props['%s%s' % (name, childKey)] = childValue + else: + props['%s.%s' % (name, childKey)] = childValue + else: + props[name] = component + + return props + + + def setProperties(self, propDict): + """Permits bulk setting of properties. These may include + child objects e.g. "chart.legend.width = 200". + + All assignments will be validated by the object as if they + were set individually in python code. + + All properties of a top-level object are guaranteed to be + set before any of the children, which may be helpful to + widget designers. + """ + + childPropDicts = {} + for name, value in propDict.items(): + parts = name.split('.', 1) + if len(parts) == 1: + #simple attribute, set it now + setattr(self, name, value) + else: + (childName, remains) = parts + try: + childPropDicts[childName][remains] = value + except KeyError: + childPropDicts[childName] = {remains: value} + + # now assign to children + for childName, childPropDict in childPropDicts.items(): + child = getattr(self, childName) + child.setProperties(childPropDict) + + + def dumpProperties(self, prefix=""): + """Convenience. Lists them on standard output. You + may provide a prefix - mostly helps to generate code + samples for documentation. + """ + + propList = list(self.getProperties().items()) + propList.sort() + if prefix: + prefix = prefix + '.' + for (name, value) in propList: + print('%s%s = %s' % (prefix, name, value)) + + +class Widget(PropHolder, shapes.UserNode): + """Base for all user-defined widgets. Keep as simple as possible. Does + not inherit from Shape so that we can rewrite shapes without breaking + widgets and vice versa.""" + + def _setKeywords(self,**kw): + for k,v in kw.items(): + if k not in self.__dict__: + setattr(self,k,v) + + def draw(self): + msg = "draw() must be implemented for each Widget!" + raise shapes.NotImplementedError(msg) + + def demo(self): + msg = "demo() must be implemented for each Widget!" + raise shapes.NotImplementedError(msg) + + def provideNode(self): + return self.draw() + + def getBounds(self): + "Return outer boundary as x1,y1,x2,y2. Can be overridden for efficiency" + return self.draw().getBounds() + +class ScaleWidget(Widget): + '''Contents with a scale and offset''' + _attrMap = AttrMap( + x = AttrMapValue(isNumber,desc="x offset"), + y = AttrMapValue(isNumber,desc="y offset"), + scale = AttrMapValue(isNumber,desc="scale"), + contents = AttrMapValue(None,desc="Contained drawable elements"), + ) + def __init__(self,x=0,y=0,scale=1.0,contents=None): + self.x = x + self.y = y + if not contents: contents=[] + elif not isinstance(contents,(tuple,list)): + contents = (contents,) + self.contents = list(contents) + self.scale = scale + + def draw(self): + return shapes.Group(transform=(self.scale,0,0,self.scale,self.x,self.y),*self.contents) + +_ItemWrapper={} + +class CloneMixin: + def clone(self,**kwds): + n = self.__class__() + n.__dict__.clear() + n.__dict__.update(self.__dict__) + if kwds: n.__dict__.update(kwds) + return n + +class TypedPropertyCollection(PropHolder): + """A container with properties for objects of the same kind. + + This makes it easy to create lists of objects. You initialize + it with a class of what it is to contain, and that is all you + can add to it. You can assign properties to the collection + as a whole, or to a numeric index within it; if so it creates + a new child object to hold that data. + + So: + wedges = TypedPropertyCollection(WedgeProperties) + wedges.strokeWidth = 2 # applies to all + wedges.strokeColor = colors.red # applies to all + wedges[3].strokeColor = colors.blue # only to one + + The last line should be taken as a prescription of how to + create wedge no. 3 if one is needed; no error is raised if + there are only two data points. + + We try and make sensible use of tuple indeces. + line[(3,x)] is backed by line[(3,)], line[3] & line + """ + + def __init__(self, exampleClass): + #give it same validation rules as what it holds + self.__dict__['_value'] = exampleClass() + self.__dict__['_children'] = {} + + def wKlassFactory(self,Klass): + class WKlass(Klass,CloneMixin): + def __getattr__(self,name): + try: + return self.__class__.__bases__[0].__getattr__(self,name) + except: + i = self._index + if i: + c = self._parent._children + if i in c and name in c[i].__dict__: + return getattr(c[i],name) + elif len(i)==1: + i = i[0] + if i in c and name in c[i].__dict__: + return getattr(c[i],name) + return getattr(self._parent,name) + return WKlass + + def __getitem__(self, index): + try: + return self._children[index] + except KeyError: + Klass = self._value.__class__ + if Klass in _ItemWrapper: + WKlass = _ItemWrapper[Klass] + else: + _ItemWrapper[Klass] = WKlass = self.wKlassFactory(Klass) + + child = WKlass() + child._parent = self + if type(index) in (type(()),type([])): + index = tuple(index) + if len(index)>1: + child._index = tuple(index[:-1]) + else: + child._index = None + else: + child._index = None + for i in filter(lambda x,K=list(child.__dict__.keys()): x in K,list(child._attrMap.keys())): + del child.__dict__[i] + + self._children[index] = child + return child + + def __contains__(self,key): + if type(key) in (type(()),type([])): key = tuple(key) + return key in self._children + + def __setitem__(self, key, value): + msg = "This collection can only hold objects of type %s" % self._value.__class__.__name__ + assert isinstance(value, self._value.__class__), msg + + def __len__(self): + return len(list(self._children.keys())) + + def getProperties(self,recur=1): + # return any children which are defined and whatever + # differs from the parent + props = {} + + for key, value in self._value.getProperties(recur=recur).items(): + props['%s' % key] = value + + for idx in self._children.keys(): + childProps = self._children[idx].getProperties(recur=recur) + for key, value in childProps.items(): + if not hasattr(self,key) or getattr(self, key)!=value: + newKey = '[%s].%s' % (idx, key) + props[newKey] = value + return props + + def setVector(self,**kw): + for name, value in kw.items(): + for i in range(len(value)): + setattr(self[i],name,value[i]) + + def __getattr__(self,name): + return getattr(self._value,name) + + def __setattr__(self,name,value): + return setattr(self._value,name,value) + +## No longer needed! +class StyleProperties(PropHolder): + """A container class for attributes used in charts and legends. + + Attributes contained can be those for any graphical element + (shape?) in the ReportLab graphics package. The idea for this + container class is to be useful in combination with legends + and/or the individual appearance of data series in charts. + + A legend could be as simple as a wrapper around a list of style + properties, where the 'desc' attribute contains a descriptive + string and the rest could be used by the legend e.g. to draw + something like a color swatch. The graphical presentation of + the legend would be its own business, though. + + A chart could be inspecting a legend or, more directly, a list + of style properties to pick individual attributes that it knows + about in order to render a particular row of the data. A bar + chart e.g. could simply use 'strokeColor' and 'fillColor' for + drawing the bars while a line chart could also use additional + ones like strokeWidth. + """ + + _attrMap = AttrMap( + strokeWidth = AttrMapValue(isNumber,desc='width of the stroke line'), + strokeLineCap = AttrMapValue(isNumber,desc='Line cap 0=butt, 1=round & 2=square',advancedUsage=1), + strokeLineJoin = AttrMapValue(isNumber,desc='Line join 0=miter, 1=round & 2=bevel',advancedUsage=1), + strokeMiterLimit = AttrMapValue(None,desc='miter limit control miter line joins',advancedUsage=1), + strokeDashArray = AttrMapValue(isListOfNumbersOrNone,desc='dashing patterns e.g. (1,3)'), + strokeOpacity = AttrMapValue(isNumber,desc='level of transparency (alpha) accepts values between 0..1',advancedUsage=1), + strokeColor = AttrMapValue(isColorOrNone,desc='the color of the stroke'), + fillColor = AttrMapValue(isColorOrNone,desc='the filling color'), + desc = AttrMapValue(isString), + ) + + def __init__(self, **kwargs): + "Initialize with attributes if any." + + for k, v in kwargs.items(): + setattr(self, k, v) + + + def __setattr__(self, name, value): + "Verify attribute name and value, before setting it." + validateSetattr(self,name,value) + + +class TwoCircles(Widget): + def __init__(self): + self.leftCircle = shapes.Circle(100,100,20, fillColor=colors.red) + self.rightCircle = shapes.Circle(300,100,20, fillColor=colors.red) + + def draw(self): + return shapes.Group(self.leftCircle, self.rightCircle) + + +class Face(Widget): + """This draws a face with two eyes. + + It exposes a couple of properties + to configure itself and hides all other details. + """ + + _attrMap = AttrMap( + x = AttrMapValue(isNumber), + y = AttrMapValue(isNumber), + size = AttrMapValue(isNumber), + skinColor = AttrMapValue(isColorOrNone), + eyeColor = AttrMapValue(isColorOrNone), + mood = AttrMapValue(OneOf('happy','sad','ok')), + ) + + def __init__(self): + self.x = 10 + self.y = 10 + self.size = 80 + self.skinColor = None + self.eyeColor = colors.blue + self.mood = 'happy' + + def demo(self): + pass + + def draw(self): + s = self.size # abbreviate as we will use this a lot + g = shapes.Group() + g.transform = [1,0,0,1,self.x, self.y] + + # background + g.add(shapes.Circle(s * 0.5, s * 0.5, s * 0.5, fillColor=self.skinColor)) + + # left eye + g.add(shapes.Circle(s * 0.35, s * 0.65, s * 0.1, fillColor=colors.white)) + g.add(shapes.Circle(s * 0.35, s * 0.65, s * 0.05, fillColor=self.eyeColor)) + + # right eye + g.add(shapes.Circle(s * 0.65, s * 0.65, s * 0.1, fillColor=colors.white)) + g.add(shapes.Circle(s * 0.65, s * 0.65, s * 0.05, fillColor=self.eyeColor)) + + # nose + g.add(shapes.Polygon( + points=[s * 0.5, s * 0.6, s * 0.4, s * 0.3, s * 0.6, s * 0.3], + fillColor=None)) + + # mouth + if self.mood == 'happy': + offset = -0.05 + elif self.mood == 'sad': + offset = +0.05 + else: + offset = 0 + + g.add(shapes.Polygon( + points = [ + s * 0.3, s * 0.2, #left of mouth + s * 0.7, s * 0.2, #right of mouth + s * 0.6, s * (0.2 + offset), # the bit going up or down + s * 0.4, s * (0.2 + offset) # the bit going up or down + ], + fillColor = colors.pink, + strokeColor = colors.red, + strokeWidth = s * 0.03 + )) + + return g + + +class TwoFaces(Widget): + def __init__(self): + self.faceOne = Face() + self.faceOne.mood = "happy" + self.faceTwo = Face() + self.faceTwo.x = 100 + self.faceTwo.mood = "sad" + + def draw(self): + """Just return a group""" + return shapes.Group(self.faceOne, self.faceTwo) + + def demo(self): + """The default case already looks good enough, + no implementation needed here""" + pass + +class Sizer(Widget): + "Container to show size of all enclosed objects" + + _attrMap = AttrMap(BASE=shapes.SolidShape, + contents = AttrMapValue(isListOfShapes,desc="Contained drawable elements"), + ) + def __init__(self, *elements): + self.contents = [] + self.fillColor = colors.cyan + self.strokeColor = colors.magenta + + for elem in elements: + self.add(elem) + + def _addNamedNode(self,name,node): + 'if name is not None add an attribute pointing to node and add to the attrMap' + if name: + if name not in list(self._attrMap.keys()): + self._attrMap[name] = AttrMapValue(isValidChild) + setattr(self, name, node) + + def add(self, node, name=None): + """Appends non-None child node to the 'contents' attribute. In addition, + if a name is provided, it is subsequently accessible by name + """ + # propagates properties down + if node is not None: + assert isValidChild(node), "Can only add Shape or UserNode objects to a Group" + self.contents.append(node) + self._addNamedNode(name,node) + + def getBounds(self): + # get bounds of each object + if self.contents: + b = [] + for elem in self.contents: + b.append(elem.getBounds()) + return shapes.getRectsBounds(b) + else: + return (0,0,0,0) + + def draw(self): + g = shapes.Group() + (x1, y1, x2, y2) = self.getBounds() + r = shapes.Rect( + x = x1, + y = y1, + width = x2-x1, + height = y2-y1, + fillColor = self.fillColor, + strokeColor = self.strokeColor + ) + g.add(r) + for elem in self.contents: + g.add(elem) + return g + +def test(): + from reportlab.graphics.charts.piecharts import WedgeProperties + wedges = TypedPropertyCollection(WedgeProperties) + wedges.fillColor = colors.red + wedges.setVector(fillColor=(colors.blue,colors.green,colors.white)) + print(len(_ItemWrapper)) + + d = shapes.Drawing(400, 200) + tc = TwoCircles() + d.add(tc) + from reportlab.graphics import renderPDF + renderPDF.drawToFile(d, 'sample_widget.pdf', 'A Sample Widget') + print('saved sample_widget.pdf') + + d = shapes.Drawing(400, 200) + f = Face() + f.skinColor = colors.yellow + f.mood = "sad" + d.add(f, name='theFace') + print('drawing 1 properties:') + d.dumpProperties() + renderPDF.drawToFile(d, 'face.pdf', 'A Sample Widget') + print('saved face.pdf') + + d2 = d.expandUserNodes() + renderPDF.drawToFile(d2, 'face_copy.pdf', 'An expanded drawing') + print('saved face_copy.pdf') + print('drawing 2 properties:') + d2.dumpProperties() + + +if __name__=='__main__': + test() diff --git a/reportlab/graphics/widgets/__init__.py b/reportlab/graphics/widgets/__init__.py new file mode 100644 index 00000000..b539fef4 --- /dev/null +++ b/reportlab/graphics/widgets/__init__.py @@ -0,0 +1,5 @@ +#Copyright ReportLab Europe Ltd. 2000-2012 +#see license.txt for license details +#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/graphics/widgets/__init__.py +__version__=''' $Id$ ''' +__doc__='''Some non-chart widgets''' diff --git a/reportlab/graphics/widgets/eventcal.py b/reportlab/graphics/widgets/eventcal.py new file mode 100644 index 00000000..d875e074 --- /dev/null +++ b/reportlab/graphics/widgets/eventcal.py @@ -0,0 +1,304 @@ +#see license.txt for license details +#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/graphics/widgets/eventcal.py +# Event Calendar widget +# author: Andy Robinson + +__version__=''' $Id$ ''' +__doc__="""This file is a +""" + +from reportlab.lib import colors +from reportlab.lib.validators import * +from reportlab.lib.attrmap import * +from reportlab.graphics.shapes import Line, Rect, Polygon, Drawing, Group, String, Circle, Wedge +from reportlab.graphics.charts.textlabels import Label +from reportlab.graphics.widgetbase import Widget +from reportlab.graphics import renderPDF + + + + +class EventCalendar(Widget): + def __init__(self): + self.x = 0 + self.y = 0 + self.width = 300 + self.height = 150 + self.timeColWidth = None # if declared, use it; otherwise auto-size. + self.trackRowHeight = 20 + self.data = [] # list of Event objects + self.trackNames = None + + self.startTime = None #displays ALL data on day if not set + self.endTime = None # displays ALL data on day if not set + self.day = 0 + + + # we will keep any internal geometry variables + # here. These are computed by computeSize(), + # which is the first thing done when drawing. + self._talksVisible = [] # subset of data which will get plotted, cache + self._startTime = None + self._endTime = None + self._trackCount = 0 + self._colWidths = [] + self._colLeftEdges = [] # left edge of each column + + def computeSize(self): + "Called at start of draw. Sets various column widths" + self._talksVisible = self.getRelevantTalks(self.data) + self._trackCount = len(self.getAllTracks()) + self.computeStartAndEndTimes() + self._colLeftEdges = [self.x] + if self.timeColWidth is None: + w = self.width / (1 + self._trackCount) + self._colWidths = [w] * (1+ self._trackCount) + for i in range(self._trackCount): + self._colLeftEdges.append(self._colLeftEdges[-1] + w) + else: + self._colWidths = [self.timeColWidth] + w = (self.width - self.timeColWidth) / self._trackCount + for i in range(self._trackCount): + self._colWidths.append(w) + self._colLeftEdges.append(self._colLeftEdges[-1] + w) + + + + def computeStartAndEndTimes(self): + "Work out first and last times to display" + if self.startTime: + self._startTime = self.startTime + else: + for (title, speaker, trackId, day, start, duration) in self._talksVisible: + + if self._startTime is None: #first one + self._startTime = start + else: + if start < self._startTime: + self._startTime = start + + if self.endTime: + self._endTime = self.endTime + else: + for (title, speaker, trackId, day, start, duration) in self._talksVisible: + if self._endTime is None: #first one + self._endTime = start + duration + else: + if start + duration > self._endTime: + self._endTime = start + duration + + + + + def getAllTracks(self): + tracks = [] + for (title, speaker, trackId, day, hours, duration) in self.data: + if trackId is not None: + if trackId not in tracks: + tracks.append(trackId) + tracks.sort() + return tracks + + def getRelevantTalks(self, talkList): + "Scans for tracks actually used" + used = [] + for talk in talkList: + (title, speaker, trackId, day, hours, duration) = talk + assert trackId != 0, "trackId must be None or 1,2,3... zero not allowed!" + if day == self.day: + if (((self.startTime is None) or ((hours + duration) >= self.startTime)) + and ((self.endTime is None) or (hours <= self.endTime))): + used.append(talk) + return used + + def scaleTime(self, theTime): + "Return y-value corresponding to times given" + axisHeight = self.height - self.trackRowHeight + # compute fraction between 0 and 1, 0 is at start of period + proportionUp = ((theTime - self._startTime) / (self._endTime - self._startTime)) + y = self.y + axisHeight - (axisHeight * proportionUp) + return y + + + def getTalkRect(self, startTime, duration, trackId, text): + "Return shapes for a specific talk" + g = Group() + y_bottom = self.scaleTime(startTime + duration) + y_top = self.scaleTime(startTime) + y_height = y_top - y_bottom + + if trackId is None: + #spans all columns + x = self._colLeftEdges[1] + width = self.width - self._colWidths[0] + else: + #trackId is 1-based and these arrays have the margin info in column + #zero, so no need to add 1 + x = self._colLeftEdges[trackId] + width = self._colWidths[trackId] + + lab = Label() + lab.setText(text) + lab.setOrigin(x + 0.5*width, y_bottom+0.5*y_height) + lab.boxAnchor = 'c' + lab.width = width + lab.height = y_height + lab.fontSize = 6 + + r = Rect(x, y_bottom, width, y_height, fillColor=colors.cyan) + g.add(r) + g.add(lab) + + #now for a label + # would expect to color-code and add text + return g + + def draw(self): + self.computeSize() + g = Group() + + # time column + g.add(Rect(self.x, self.y, self._colWidths[0], self.height - self.trackRowHeight, fillColor=colors.cornsilk)) + + # track headers + x = self.x + self._colWidths[0] + y = self.y + self.height - self.trackRowHeight + for trk in range(self._trackCount): + wid = self._colWidths[trk+1] + r = Rect(x, y, wid, self.trackRowHeight, fillColor=colors.yellow) + s = String(x + 0.5*wid, y, 'Track %d' % trk, align='middle') + g.add(r) + g.add(s) + x = x + wid + + for talk in self._talksVisible: + (title, speaker, trackId, day, start, duration) = talk + r = self.getTalkRect(start, duration, trackId, title + '\n' + speaker) + g.add(r) + + + return g + + + + +def test(): + "Make a conference event for day 1 of UP Python 2003" + + + d = Drawing(400,200) + + cal = EventCalendar() + cal.x = 50 + cal.y = 25 + cal.data = [ + # these might be better as objects instead of tuples, since I + # predict a large number of "optionsl" variables to affect + # formatting in future. + + #title, speaker, track id, day, start time (hrs), duration (hrs) + # track ID is 1-based not zero-based! + ('Keynote: Why design another programming language?', 'Guido van Rossum', None, 1, 9.0, 1.0), + + ('Siena Web Service Architecture', 'Marc-Andre Lemburg', 1, 1, 10.5, 1.5), + ('Extreme Programming in Python', 'Chris Withers', 2, 1, 10.5, 1.5), + ('Pattern Experiences in C++', 'Mark Radford', 3, 1, 10.5, 1.5), + ('What is the Type of std::toupper()', 'Gabriel Dos Reis', 4, 1, 10.5, 1.5), + ('Linguistic Variables: Clear Thinking with Fuzzy Logic ', 'Walter Banks', 5, 1, 10.5, 1.5), + + ('lunch, short presentations, vendor presentations', '', None, 1, 12.0, 2.0), + + ("CORBA? Isn't that obsolete", 'Duncan Grisby', 1, 1, 14.0, 1.5), + ("Python Design Patterns", 'Duncan Booth', 2, 1, 14.0, 1.5), + ("Inside Security Checks and Safe Exceptions", 'Brandon Bray', 3, 1, 14.0, 1.5), + ("Studying at a Distance", 'Panel Discussion, Panel to include Alan Lenton & Francis Glassborow', 4, 1, 14.0, 1.5), + ("Coding Standards - Given the ANSI C Standard why do I still need a coding Standard", 'Randy Marques', 5, 1, 14.0, 1.5), + + ("RESTful Python", 'Hamish Lawson', 1, 1, 16.0, 1.5), + ("Parsing made easier - a radical old idea", 'Andrew Koenig', 2, 1, 16.0, 1.5), + ("C++ & Multimethods", 'Julian Smith', 3, 1, 16.0, 1.5), + ("C++ Threading", 'Kevlin Henney', 4, 1, 16.0, 1.5), + ("The Organisation Strikes Back", 'Alan Griffiths & Sarah Lees', 5, 1, 16.0, 1.5), + + ('Birds of a Feather meeting', '', None, 1, 17.5, 2.0), + + ('Keynote: In the Spirit of C', 'Greg Colvin', None, 2, 9.0, 1.0), + + ('The Infinite Filing Cabinet - object storage in Python', 'Jacob Hallen', 1, 2, 10.5, 1.5), + ('Introduction to Python and Jython for C++ and Java Programmers', 'Alex Martelli', 2, 2, 10.5, 1.5), + ('Template metaprogramming in Haskell', 'Simon Peyton Jones', 3, 2, 10.5, 1.5), + ('Plenty People Programming: C++ Programming in a Group, Workshop with a difference', 'Nico Josuttis', 4, 2, 10.5, 1.5), + ('Design and Implementation of the Boost Graph Library', 'Jeremy Siek', 5, 2, 10.5, 1.5), + + ('lunch, short presentations, vendor presentations', '', None, 2, 12.0, 2.0), + + ("Building GUI Applications with PythonCard and PyCrust", 'Andy Todd', 1, 2, 14.0, 1.5), + ("Integrating Python, C and C++", 'Duncan Booth', 2, 2, 14.0, 1.5), + ("Secrets and Pitfalls of Templates", 'Nicolai Josuttis & David Vandevoorde', 3, 2, 14.0, 1.5), + ("Being a Mentor", 'Panel Discussion, Panel to include Alan Lenton & Francis Glassborow', 4, 2, 14.0, 1.5), + ("The Embedded C Extensions to C", 'Willem Wakker', 5, 2, 14.0, 1.5), + + ("Lightning Talks", 'Paul Brian', 1, 2, 16.0, 1.5), + ("Scripting Java Applications with Jython", 'Anthony Eden', 2, 2, 16.0, 1.5), + ("Metaprogramming and the Boost Metaprogramming Library", 'David Abrahams', 3, 2, 16.0, 1.5), + ("A Common Vendor ABI for C++ -- GCC's why, what and not", 'Nathan Sidwell & Gabriel Dos Reis', 4, 2, 16.0, 1.5), + ("The Timing and Cost of Choices", 'Hubert Matthews', 5, 2, 16.0, 1.5), + + ('Birds of a Feather meeting', '', None, 2, 17.5, 2.0), + + ('Keynote: The Cost of C & C++ Compatibility', 'Andy Koenig', None, 3, 9.0, 1.0), + + ('Prying Eyes: Generic Observer Implementations in C++', 'Andrei Alexandrescu', 1, 2, 10.5, 1.5), + ('The Roadmap to Generative Programming With C++', 'Ulrich Eisenecker', 2, 2, 10.5, 1.5), + ('Design Patterns in C++ and C# for the Common Language Runtime', 'Brandon Bray', 3, 2, 10.5, 1.5), + ('Extreme Hour (XH): (workshop) - Jutta Eckstein and Nico Josuttis', 'Jutta Ecstein', 4, 2, 10.5, 1.5), + ('The Lambda Library : Unnamed Functions for C++', 'Jaako Jarvi', 5, 2, 10.5, 1.5), + + ('lunch, short presentations, vendor presentations', '', None, 3, 12.0, 2.0), + + ('Reflective Metaprogramming', 'Daveed Vandevoorde', 1, 3, 14.0, 1.5), + ('Advanced Template Issues and Solutions (double session)', 'Herb Sutter',2, 3, 14.0, 3), + ('Concurrent Programming in Java (double session)', 'Angelika Langer', 3, 3, 14.0, 3), + ('What can MISRA-C (2nd Edition) do for us?', 'Chris Hills', 4, 3, 14.0, 1.5), + ('C++ Metaprogramming Concepts and Results', 'Walter E Brown', 5, 3, 14.0, 1.5), + + ('Binding C++ to Python with the Boost Python Library', 'David Abrahams', 1, 3, 16.0, 1.5), + ('Using Aspect Oriented Programming for Enterprise Application Integration', 'Arno Schmidmeier', 4, 3, 16.0, 1.5), + ('Defective C++', 'Marc Paterno', 5, 3, 16.0, 1.5), + + ("Speakers' Banquet & Birds of a Feather meeting", '', None, 3, 17.5, 2.0), + + ('Keynote: The Internet, Software and Computers - A Report Card', 'Alan Lenton', None, 4, 9.0, 1.0), + + ('Multi-Platform Software Development; Lessons from the Boost libraries', 'Beman Dawes', 1, 5, 10.5, 1.5), + ('The Stability of the C++ ABI', 'Steve Clamage', 2, 5, 10.5, 1.5), + ('Generic Build Support - A Pragmatic Approach to the Software Build Process', 'Randy Marques', 3, 5, 10.5, 1.5), + ('How to Handle Project Managers: a survival guide', 'Barb Byro', 4, 5, 10.5, 1.5), + + ('lunch, ACCU AGM', '', None, 5, 12.0, 2.0), + + ('Sauce: An OO recursive descent parser; its design and implementation.', 'Jon Jagger', 1, 5, 14.0, 1.5), + ('GNIRTS ESAC REWOL - Bringing the UNIX filters to the C++ iostream library.', 'JC van Winkel', 2, 5, 14.0, 1.5), + ('Pattern Writing: Live and Direct', 'Frank Buschmann & Kevlin Henney', 3, 5, 14.0, 3.0), + ('The Future of Programming Languages - A Goldfish Bowl', 'Francis Glassborow and friends', 3, 5, 14.0, 1.5), + + ('Honey, I Shrunk the Threads: Compile-time checked multithreaded transactions in C++', 'Andrei Alexandrescu', 1, 5, 16.0, 1.5), + ('Fun and Functionality with Functors', 'Lois Goldthwaite', 2, 5, 16.0, 1.5), + ('Agile Enough?', 'Alan Griffiths', 4, 5, 16.0, 1.5), + ("Conference Closure: A brief plenary session", '', None, 5, 17.5, 0.5), + + ] + + #return cal + cal.day = 1 + + d.add(cal) + + + for format in ['pdf']:#,'gif','png']: + out = d.asString(format) + open('eventcal.%s' % format, 'wb').write(out) + print('saved eventcal.%s' % format) + +if __name__=='__main__': + test() diff --git a/reportlab/graphics/widgets/flags.py b/reportlab/graphics/widgets/flags.py new file mode 100644 index 00000000..d2fedd2c --- /dev/null +++ b/reportlab/graphics/widgets/flags.py @@ -0,0 +1,880 @@ +#see license.txt for license details +#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/graphics/widgets/flags.py +# Flag Widgets - a collection of flags as widgets +# author: John Precedo (johnp@reportlab.com) + +__version__=''' $Id$ ''' +__doc__="""This file is a collection of flag graphics as widgets. + +All flags are represented at the ratio of 1:2, even where the official ratio for the flag is something else +(such as 3:5 for the German national flag). The only exceptions are for where this would look _very_ wrong, +such as the Danish flag whose (ratio is 28:37), or the Swiss flag (which is square). + +Unless otherwise stated, these flags are all the 'national flags' of the countries, rather than their +state flags, naval flags, ensigns or any other variants. (National flags are the flag flown by civilians +of a country and the ones usually used to represent a country abroad. State flags are the variants used by +the government and by diplomatic missions overseas). + +To check on how close these are to the 'official' representations of flags, check the World Flag Database at +http://www.flags.ndirect.co.uk/ + +The flags this file contains are: + +EU Members: +United Kingdom, Austria, Belgium, Denmark, Finland, France, Germany, Greece, Ireland, Italy, Luxembourg, +Holland (The Netherlands), Spain, Sweden + +Others: +USA, Czech Republic, European Union, Switzerland, Turkey, Brazil + +(Brazilian flag contributed by Publio da Costa Melo [publio@planetarium.com.br]). +""" + +from reportlab.lib import colors +from reportlab.lib.validators import * +from reportlab.lib.attrmap import * +from reportlab.graphics.shapes import Line, Rect, Polygon, Drawing, Group, String, Circle, Wedge +from reportlab.graphics.widgetbase import Widget +from reportlab.graphics import renderPDF +from reportlab.graphics.widgets.signsandsymbols import _Symbol +import copy +from math import sin, cos, pi + +validFlag=OneOf(None, + 'UK', + 'USA', + 'Afghanistan', + 'Austria', + 'Belgium', + 'China', + 'Cuba', + 'Denmark', + 'Finland', + 'France', + 'Germany', + 'Greece', + 'Ireland', + 'Italy', + 'Japan', + 'Luxembourg', + 'Holland', + 'Palestine', + 'Portugal', + 'Russia', + 'Spain', + 'Sweden', + 'Norway', + 'CzechRepublic', + 'Turkey', + 'Switzerland', + 'EU', + 'Brazil' + ) + +_size = 100. + +class Star(_Symbol): + """This draws a 5-pointed star. + + possible attributes: + 'x', 'y', 'size', 'fillColor', 'strokeColor' + + """ + _attrMap = AttrMap(BASE=_Symbol, + angle = AttrMapValue(isNumber, desc='angle in degrees'), + ) + _size = 100. + + def __init__(self): + _Symbol.__init__(self) + self.size = 100 + self.fillColor = colors.yellow + self.strokeColor = None + self.angle = 0 + + def demo(self): + D = Drawing(200, 100) + et = Star() + et.x=50 + et.y=0 + D.add(et) + labelFontSize = 10 + D.add(String(et.x+(et.size/2.0),(et.y-(1.2*labelFontSize)), + et.__class__.__name__, fillColor=colors.black, textAnchor='middle', + fontSize=labelFontSize)) + return D + + def draw(self): + s = float(self.size) #abbreviate as we will use this a lot + g = Group() + + # new algorithm from markers.StarFive + R = float(self.size)/2 + r = R*sin(18*(pi/180.0))/cos(36*(pi/180.0)) + P = [] + angle = 90 + for i in range(5): + for radius in R, r: + theta = angle*(pi/180.0) + P.append(radius*cos(theta)) + P.append(radius*sin(theta)) + angle = angle + 36 + # star specific bits + star = Polygon(P, + fillColor = self.fillColor, + strokeColor = self.strokeColor, + strokeWidth=s/50) + g.rotate(self.angle) + g.shift(self.x+self.dx,self.y+self.dy) + g.add(star) + + return g + +class Flag(_Symbol): + """This is a generic flag class that all the flags in this file use as a basis. + + This class basically provides edges and a tidy-up routine to hide any bits of + line that overlap the 'outside' of the flag + + possible attributes: + 'x', 'y', 'size', 'fillColor' + """ + + _attrMap = AttrMap(BASE=_Symbol, + fillColor = AttrMapValue(isColor, desc='Background color'), + border = AttrMapValue(isBoolean, 'Whether a background is drawn'), + kind = AttrMapValue(validFlag, desc='Which flag'), + ) + + _cache = {} + + def __init__(self,**kw): + _Symbol.__init__(self) + self.kind = None + self.size = 100 + self.fillColor = colors.white + self.border=1 + self.setProperties(kw) + + def availableFlagNames(self): + '''return a list of the things we can display''' + return [x for x in self._attrMap['kind'].validate._enum if x is not None] + + def _Flag_None(self): + s = _size # abbreviate as we will use this a lot + g = Group() + g.add(Rect(0, 0, s*2, s, fillColor = colors.purple, strokeColor = colors.black, strokeWidth=0)) + return g + + def _borderDraw(self,f): + s = self.size # abbreviate as we will use this a lot + g = Group() + g.add(f) + x, y, sW = self.x+self.dx, self.y+self.dy, self.strokeWidth/2. + g.insert(0,Rect(-sW, -sW, width=getattr(self,'_width',2*s)+3*sW, height=getattr(self,'_height',s)+2*sW, + fillColor = None, strokeColor = self.strokeColor, strokeWidth=sW*2)) + g.shift(x,y) + g.scale(s/_size, s/_size) + return g + + def draw(self): + kind = self.kind or 'None' + f = self._cache.get(kind) + if not f: + f = getattr(self,'_Flag_'+kind)() + self._cache[kind] = f._explode() + return self._borderDraw(f) + + def clone(self): + return copy.copy(self) + + def demo(self): + D = Drawing(200, 100) + name = self.availableFlagNames() + import time + name = name[int(time.time()) % len(name)] + fx = Flag() + fx.kind = name + fx.x = 0 + fx.y = 0 + D.add(fx) + labelFontSize = 10 + D.add(String(fx.x+(fx.size/2.0),(fx.y-(1.2*labelFontSize)), + name, fillColor=colors.black, textAnchor='middle', + fontSize=labelFontSize)) + labelFontSize = int(fx.size/4.0) + D.add(String(fx.x+(fx.size),(fx.y+((fx.size/2.0))), + "SAMPLE", fillColor=colors.gold, textAnchor='middle', + fontSize=labelFontSize, fontName="Helvetica-Bold")) + return D + + def _Flag_UK(self): + s = _size + g = Group() + w = s*2 + g.add(Rect(0, 0, w, s, fillColor = colors.navy, strokeColor = colors.black, strokeWidth=0)) + g.add(Polygon([0,0, s*.225,0, w,s*(1-.1125), w,s, w-s*.225,s, 0, s*.1125], fillColor = colors.mintcream, strokeColor=None, strokeWidth=0)) + g.add(Polygon([0,s*(1-.1125), 0, s, s*.225,s, w, s*.1125, w,0, w-s*.225,0], fillColor = colors.mintcream, strokeColor=None, strokeWidth=0)) + g.add(Polygon([0, s-(s/15.0), (s-((s/10.0)*4)), (s*0.65), (s-(s/10.0)*3), (s*0.65), 0, s], fillColor = colors.red, strokeColor = None, strokeWidth=0)) + g.add(Polygon([0, 0, (s-((s/10.0)*3)), (s*0.35), (s-((s/10.0)*2)), (s*0.35), (s/10.0), 0], fillColor = colors.red, strokeColor = None, strokeWidth=0)) + g.add(Polygon([w, s, (s+((s/10.0)*3)), (s*0.65), (s+((s/10.0)*2)), (s*0.65), w-(s/10.0), s], fillColor = colors.red, strokeColor = None, strokeWidth=0)) + g.add(Polygon([w, (s/15.0), (s+((s/10.0)*4)), (s*0.35), (s+((s/10.0)*3)), (s*0.35), w, 0], fillColor = colors.red, strokeColor = None, strokeWidth=0)) + g.add(Rect(((s*0.42)*2), 0, width=(0.16*s)*2, height=s, fillColor = colors.mintcream, strokeColor = None, strokeWidth=0)) + g.add(Rect(0, (s*0.35), width=w, height=s*0.3, fillColor = colors.mintcream, strokeColor = None, strokeWidth=0)) + g.add(Rect(((s*0.45)*2), 0, width=(0.1*s)*2, height=s, fillColor = colors.red, strokeColor = None, strokeWidth=0)) + g.add(Rect(0, (s*0.4), width=w, height=s*0.2, fillColor = colors.red, strokeColor = None, strokeWidth=0)) + return g + + def _Flag_USA(self): + s = _size # abbreviate as we will use this a lot + g = Group() + + box = Rect(0, 0, s*2, s, fillColor = colors.mintcream, strokeColor = colors.black, strokeWidth=0) + g.add(box) + + for stripecounter in range (13,0, -1): + stripeheight = s/13.0 + if not (stripecounter%2 == 0): + stripecolor = colors.red + else: + stripecolor = colors.mintcream + redorwhiteline = Rect(0, (s-(stripeheight*stripecounter)), width=s*2, height=stripeheight, + fillColor = stripecolor, strokeColor = None, strokeWidth=20) + g.add(redorwhiteline) + + bluebox = Rect(0, (s-(stripeheight*7)), width=0.8*s, height=stripeheight*7, + fillColor = colors.darkblue, strokeColor = None, strokeWidth=0) + g.add(bluebox) + + lss = s*0.045 + lss2 = lss/2.0 + s9 = s/9.0 + s7 = s/7.0 + for starxcounter in range(5): + for starycounter in range(4): + ls = Star() + ls.size = lss + ls.x = 0-s/22.0+lss/2.0+s7+starxcounter*s7 + ls.fillColor = colors.mintcream + ls.y = s-(starycounter+1)*s9+lss2 + g.add(ls) + + for starxcounter in range(6): + for starycounter in range(5): + ls = Star() + ls.size = lss + ls.x = 0-(s/22.0)+lss/2.0+s/14.0+starxcounter*s7 + ls.fillColor = colors.mintcream + ls.y = s-(starycounter+1)*s9+(s/18.0)+lss2 + g.add(ls) + return g + + def _Flag_Afghanistan(self): + s = _size + g = Group() + + box = Rect(0, 0, s*2, s, + fillColor = colors.mintcream, strokeColor = colors.black, strokeWidth=0) + g.add(box) + + greenbox = Rect(0, ((s/3.0)*2.0), width=s*2.0, height=s/3.0, + fillColor = colors.limegreen, strokeColor = None, strokeWidth=0) + g.add(greenbox) + + blackbox = Rect(0, 0, width=s*2.0, height=s/3.0, + fillColor = colors.black, strokeColor = None, strokeWidth=0) + g.add(blackbox) + return g + + def _Flag_Austria(self): + s = _size # abbreviate as we will use this a lot + g = Group() + + box = Rect(0, 0, s*2, s, fillColor = colors.mintcream, + strokeColor = colors.black, strokeWidth=0) + g.add(box) + + + redbox1 = Rect(0, 0, width=s*2.0, height=s/3.0, + fillColor = colors.red, strokeColor = None, strokeWidth=0) + g.add(redbox1) + + redbox2 = Rect(0, ((s/3.0)*2.0), width=s*2.0, height=s/3.0, + fillColor = colors.red, strokeColor = None, strokeWidth=0) + g.add(redbox2) + return g + + def _Flag_Belgium(self): + s = _size + g = Group() + + box = Rect(0, 0, s*2, s, + fillColor = colors.black, strokeColor = colors.black, strokeWidth=0) + g.add(box) + + + box1 = Rect(0, 0, width=(s/3.0)*2.0, height=s, + fillColor = colors.black, strokeColor = None, strokeWidth=0) + g.add(box1) + + box2 = Rect(((s/3.0)*2.0), 0, width=(s/3.0)*2.0, height=s, + fillColor = colors.gold, strokeColor = None, strokeWidth=0) + g.add(box2) + + box3 = Rect(((s/3.0)*4.0), 0, width=(s/3.0)*2.0, height=s, + fillColor = colors.red, strokeColor = None, strokeWidth=0) + g.add(box3) + return g + + def _Flag_China(self): + s = _size + g = Group() + self._width = w = s*1.5 + g.add(Rect(0, 0, w, s, fillColor=colors.red, strokeColor=None, strokeWidth=0)) + + def addStar(x,y,size,angle,g=g,w=s/20.0,x0=0,y0=s/2.0): + s = Star() + s.fillColor=colors.yellow + s.angle = angle + s.size = size*w*2 + s.x = x*w+x0 + s.y = y*w+y0 + g.add(s) + + addStar(5,5,3, 0) + addStar(10,1,1,36.86989765) + addStar(12,3,1,8.213210702) + addStar(12,6,1,16.60154960) + addStar(10,8,1,53.13010235) + return g + + def _Flag_Cuba(self): + s = _size + g = Group() + + for i in range(5): + stripe = Rect(0, i*s/5.0, width=s*2, height=s/5.0, + fillColor = [colors.darkblue, colors.mintcream][i%2], + strokeColor = None, + strokeWidth=0) + g.add(stripe) + + redwedge = Polygon(points = [ 0, 0, 4*s/5.0, (s/2.0), 0, s], + fillColor = colors.red, strokeColor = None, strokeWidth=0) + g.add(redwedge) + + star = Star() + star.x = 2.5*s/10.0 + star.y = s/2.0 + star.size = 3*s/10.0 + star.fillColor = colors.white + g.add(star) + + box = Rect(0, 0, s*2, s, + fillColor = None, + strokeColor = colors.black, + strokeWidth=0) + g.add(box) + + return g + + def _Flag_Denmark(self): + s = _size + g = Group() + self._width = w = s*1.4 + + box = Rect(0, 0, w, s, + fillColor = colors.red, strokeColor = colors.black, strokeWidth=0) + g.add(box) + + whitebox1 = Rect(((s/5.0)*2), 0, width=s/6.0, height=s, + fillColor = colors.mintcream, strokeColor = None, strokeWidth=0) + g.add(whitebox1) + + whitebox2 = Rect(0, ((s/2.0)-(s/12.0)), width=w, height=s/6.0, + fillColor = colors.mintcream, strokeColor = None, strokeWidth=0) + g.add(whitebox2) + return g + + def _Flag_Finland(self): + s = _size + g = Group() + + # crossbox specific bits + box = Rect(0, 0, s*2, s, + fillColor = colors.ghostwhite, strokeColor = colors.black, strokeWidth=0) + g.add(box) + + blueline1 = Rect((s*0.6), 0, width=0.3*s, height=s, + fillColor = colors.darkblue, strokeColor = None, strokeWidth=0) + g.add(blueline1) + + blueline2 = Rect(0, (s*0.4), width=s*2, height=s*0.3, + fillColor = colors.darkblue, strokeColor = None, strokeWidth=0) + g.add(blueline2) + return g + + def _Flag_France(self): + s = _size + g = Group() + + box = Rect(0, 0, s*2, s, fillColor = colors.navy, strokeColor = colors.black, strokeWidth=0) + g.add(box) + + bluebox = Rect(0, 0, width=((s/3.0)*2.0), height=s, + fillColor = colors.blue, strokeColor = None, strokeWidth=0) + g.add(bluebox) + + whitebox = Rect(((s/3.0)*2.0), 0, width=((s/3.0)*2.0), height=s, + fillColor = colors.mintcream, strokeColor = None, strokeWidth=0) + g.add(whitebox) + + redbox = Rect(((s/3.0)*4.0), 0, width=((s/3.0)*2.0), height=s, + fillColor = colors.red, + strokeColor = None, + strokeWidth=0) + g.add(redbox) + return g + + def _Flag_Germany(self): + s = _size + g = Group() + + box = Rect(0, 0, s*2, s, + fillColor = colors.gold, strokeColor = colors.black, strokeWidth=0) + g.add(box) + + blackbox1 = Rect(0, ((s/3.0)*2.0), width=s*2.0, height=s/3.0, + fillColor = colors.black, strokeColor = None, strokeWidth=0) + g.add(blackbox1) + + redbox1 = Rect(0, (s/3.0), width=s*2.0, height=s/3.0, + fillColor = colors.orangered, strokeColor = None, strokeWidth=0) + g.add(redbox1) + return g + + def _Flag_Greece(self): + s = _size + g = Group() + + box = Rect(0, 0, s*2, s, fillColor = colors.gold, + strokeColor = colors.black, strokeWidth=0) + g.add(box) + + for stripecounter in range (9,0, -1): + stripeheight = s/9.0 + if not (stripecounter%2 == 0): + stripecolor = colors.deepskyblue + else: + stripecolor = colors.mintcream + + blueorwhiteline = Rect(0, (s-(stripeheight*stripecounter)), width=s*2, height=stripeheight, + fillColor = stripecolor, strokeColor = None, strokeWidth=20) + g.add(blueorwhiteline) + + bluebox1 = Rect(0, ((s)-stripeheight*5), width=(stripeheight*5), height=stripeheight*5, + fillColor = colors.deepskyblue, strokeColor = None, strokeWidth=0) + g.add(bluebox1) + + whiteline1 = Rect(0, ((s)-stripeheight*3), width=stripeheight*5, height=stripeheight, + fillColor = colors.mintcream, strokeColor = None, strokeWidth=0) + g.add(whiteline1) + + whiteline2 = Rect((stripeheight*2), ((s)-stripeheight*5), width=stripeheight, height=stripeheight*5, + fillColor = colors.mintcream, strokeColor = None, strokeWidth=0) + g.add(whiteline2) + + return g + + def _Flag_Ireland(self): + s = _size + g = Group() + + box = Rect(0, 0, s*2, s, + fillColor = colors.forestgreen, strokeColor = colors.black, strokeWidth=0) + g.add(box) + + whitebox = Rect(((s*2.0)/3.0), 0, width=(2.0*(s*2.0)/3.0), height=s, + fillColor = colors.mintcream, strokeColor = None, strokeWidth=0) + g.add(whitebox) + + orangebox = Rect(((2.0*(s*2.0)/3.0)), 0, width=(s*2.0)/3.0, height=s, + fillColor = colors.darkorange, strokeColor = None, strokeWidth=0) + g.add(orangebox) + return g + + def _Flag_Italy(self): + s = _size + g = Group() + g.add(Rect(0,0,s*2,s,fillColor=colors.forestgreen,strokeColor=None, strokeWidth=0)) + g.add(Rect((2*s)/3.0, 0, width=(s*4)/3.0, height=s, fillColor = colors.mintcream, strokeColor = None, strokeWidth=0)) + g.add(Rect((4*s)/3.0, 0, width=(s*2)/3.0, height=s, fillColor = colors.red, strokeColor = None, strokeWidth=0)) + return g + + def _Flag_Japan(self): + s = _size + g = Group() + w = self._width = s*1.5 + g.add(Rect(0,0,w,s,fillColor=colors.mintcream,strokeColor=None, strokeWidth=0)) + g.add(Circle(cx=w/2.0,cy=s/2.0,r=0.3*w,fillColor=colors.red,strokeColor=None, strokeWidth=0)) + return g + + def _Flag_Luxembourg(self): + s = _size + g = Group() + + box = Rect(0, 0, s*2, s, + fillColor = colors.mintcream, strokeColor = colors.black, strokeWidth=0) + g.add(box) + + redbox = Rect(0, ((s/3.0)*2.0), width=s*2.0, height=s/3.0, + fillColor = colors.red, strokeColor = None, strokeWidth=0) + g.add(redbox) + + bluebox = Rect(0, 0, width=s*2.0, height=s/3.0, + fillColor = colors.dodgerblue, strokeColor = None, strokeWidth=0) + g.add(bluebox) + return g + + def _Flag_Holland(self): + s = _size + g = Group() + + box = Rect(0, 0, s*2, s, + fillColor = colors.mintcream, strokeColor = colors.black, strokeWidth=0) + g.add(box) + + redbox = Rect(0, ((s/3.0)*2.0), width=s*2.0, height=s/3.0, + fillColor = colors.red, strokeColor = None, strokeWidth=0) + g.add(redbox) + + bluebox = Rect(0, 0, width=s*2.0, height=s/3.0, + fillColor = colors.darkblue, strokeColor = None, strokeWidth=0) + g.add(bluebox) + return g + + def _Flag_Portugal(self): + return Group() + + def _Flag_Russia(self): + s = _size + g = Group() + w = self._width = s*1.5 + t = s/3.0 + g.add(Rect(0, 0, width=w, height=t, fillColor = colors.red, strokeColor = None, strokeWidth=0)) + g.add(Rect(0, t, width=w, height=t, fillColor = colors.blue, strokeColor = None, strokeWidth=0)) + g.add(Rect(0, 2*t, width=w, height=t, fillColor = colors.mintcream, strokeColor = None, strokeWidth=0)) + return g + + def _Flag_Spain(self): + s = _size + g = Group() + w = self._width = s*1.5 + g.add(Rect(0, 0, width=w, height=s, fillColor = colors.red, strokeColor = None, strokeWidth=0)) + g.add(Rect(0, (s/4.0), width=w, height=s/2.0, fillColor = colors.yellow, strokeColor = None, strokeWidth=0)) + return g + + def _Flag_Sweden(self): + s = _size + g = Group() + self._width = s*1.4 + box = Rect(0, 0, self._width, s, + fillColor = colors.dodgerblue, strokeColor = colors.black, strokeWidth=0) + g.add(box) + + box1 = Rect(((s/5.0)*2), 0, width=s/6.0, height=s, + fillColor = colors.gold, strokeColor = None, strokeWidth=0) + g.add(box1) + + box2 = Rect(0, ((s/2.0)-(s/12.0)), width=self._width, height=s/6.0, + fillColor = colors.gold, + strokeColor = None, + strokeWidth=0) + g.add(box2) + return g + + def _Flag_Norway(self): + s = _size + g = Group() + self._width = s*1.4 + + box = Rect(0, 0, self._width, s, + fillColor = colors.red, strokeColor = colors.black, strokeWidth=0) + g.add(box) + + box = Rect(0, 0, self._width, s, + fillColor = colors.red, strokeColor = colors.black, strokeWidth=0) + g.add(box) + + whiteline1 = Rect(((s*0.2)*2), 0, width=s*0.2, height=s, + fillColor = colors.ghostwhite, strokeColor = None, strokeWidth=0) + g.add(whiteline1) + + whiteline2 = Rect(0, (s*0.4), width=self._width, height=s*0.2, + fillColor = colors.ghostwhite, strokeColor = None, strokeWidth=0) + g.add(whiteline2) + + blueline1 = Rect(((s*0.225)*2), 0, width=0.1*s, height=s, + fillColor = colors.darkblue, strokeColor = None, strokeWidth=0) + g.add(blueline1) + + blueline2 = Rect(0, (s*0.45), width=self._width, height=s*0.1, + fillColor = colors.darkblue, strokeColor = None, strokeWidth=0) + g.add(blueline2) + return g + + def _Flag_CzechRepublic(self): + s = _size + g = Group() + box = Rect(0, 0, s*2, s, + fillColor = colors.mintcream, + strokeColor = colors.black, + strokeWidth=0) + g.add(box) + + redbox = Rect(0, 0, width=s*2, height=s/2.0, + fillColor = colors.red, + strokeColor = None, + strokeWidth=0) + g.add(redbox) + + bluewedge = Polygon(points = [ 0, 0, s, (s/2.0), 0, s], + fillColor = colors.darkblue, strokeColor = None, strokeWidth=0) + g.add(bluewedge) + return g + + def _Flag_Palestine(self): + s = _size + g = Group() + box = Rect(0, s/3.0, s*2, s/3.0, + fillColor = colors.mintcream, + strokeColor = None, + strokeWidth=0) + g.add(box) + + greenbox = Rect(0, 0, width=s*2, height=s/3.0, + fillColor = colors.limegreen, + strokeColor = None, + strokeWidth=0) + g.add(greenbox) + + blackbox = Rect(0, 2*s/3.0, width=s*2, height=s/3.0, + fillColor = colors.black, + strokeColor = None, + strokeWidth=0) + g.add(blackbox) + + redwedge = Polygon(points = [ 0, 0, 2*s/3.0, (s/2.0), 0, s], + fillColor = colors.red, strokeColor = None, strokeWidth=0) + g.add(redwedge) + return g + + def _Flag_Turkey(self): + s = _size + g = Group() + + box = Rect(0, 0, s*2, s, + fillColor = colors.red, + strokeColor = colors.black, + strokeWidth=0) + g.add(box) + + whitecircle = Circle(cx=((s*0.35)*2), cy=s/2.0, r=s*0.3, + fillColor = colors.mintcream, + strokeColor = None, + strokeWidth=0) + g.add(whitecircle) + + redcircle = Circle(cx=((s*0.39)*2), cy=s/2.0, r=s*0.24, + fillColor = colors.red, + strokeColor = None, + strokeWidth=0) + g.add(redcircle) + + ws = Star() + ws.angle = 15 + ws.size = s/5.0 + ws.x = (s*0.5)*2+ws.size/2.0 + ws.y = (s*0.5) + ws.fillColor = colors.mintcream + ws.strokeColor = None + g.add(ws) + return g + + def _Flag_Switzerland(self): + s = _size + g = Group() + self._width = s + + g.add(Rect(0, 0, s, s, fillColor = colors.red, strokeColor = colors.black, strokeWidth=0)) + g.add(Line((s/2.0), (s/5.5), (s/2), (s-(s/5.5)), + fillColor = colors.mintcream, strokeColor = colors.mintcream, strokeWidth=(s/5.0))) + g.add(Line((s/5.5), (s/2.0), (s-(s/5.5)), (s/2.0), + fillColor = colors.mintcream, strokeColor = colors.mintcream, strokeWidth=s/5.0)) + return g + + def _Flag_EU(self): + s = _size + g = Group() + w = self._width = 1.5*s + + g.add(Rect(0, 0, w, s, fillColor = colors.darkblue, strokeColor = None, strokeWidth=0)) + centerx=w/2.0 + centery=s/2.0 + radius=s/3.0 + yradius = radius + xradius = radius + nStars = 12 + delta = 2*pi/nStars + for i in range(nStars): + rad = i*delta + gs = Star() + gs.x=cos(rad)*radius+centerx + gs.y=sin(rad)*radius+centery + gs.size=s/10.0 + gs.fillColor=colors.gold + g.add(gs) + return g + + def _Flag_Brazil(self): + s = _size # abbreviate as we will use this a lot + g = Group() + + m = s/14.0 + self._width = w = (m * 20) + + def addStar(x,y,size, g=g, w=w, s=s, m=m): + st = Star() + st.fillColor=colors.mintcream + st.size = size*m + st.x = (w/2.0) + (x * (0.35 * m)) + st.y = (s/2.0) + (y * (0.35 * m)) + g.add(st) + + g.add(Rect(0, 0, w, s, fillColor = colors.green, strokeColor = None, strokeWidth=0)) + g.add(Polygon(points = [ 1.7*m, (s/2.0), (w/2.0), s-(1.7*m), w-(1.7*m),(s/2.0),(w/2.0), 1.7*m], + fillColor = colors.yellow, strokeColor = None, strokeWidth=0)) + g.add(Circle(cx=w/2.0, cy=s/2.0, r=3.5*m, + fillColor=colors.blue,strokeColor=None, strokeWidth=0)) + g.add(Wedge((w/2.0)-(2*m), 0, 8.5*m, 50, 98.1, 8.5*m, + fillColor=colors.mintcream,strokeColor=None, strokeWidth=0)) + g.add(Wedge((w/2.0), (s/2.0), 3.501*m, 156, 352, 3.501*m, + fillColor=colors.mintcream,strokeColor=None, strokeWidth=0)) + g.add(Wedge((w/2.0)-(2*m), 0, 8*m, 48.1, 100, 8*m, + fillColor=colors.blue,strokeColor=None, strokeWidth=0)) + g.add(Rect(0, 0, w, (s/4.0) + 1.7*m, + fillColor = colors.green, strokeColor = None, strokeWidth=0)) + g.add(Polygon(points = [ 1.7*m,(s/2.0), (w/2.0),s/2.0 - 2*m, w-(1.7*m),(s/2.0) , (w/2.0),1.7*m], + fillColor = colors.yellow, strokeColor = None, strokeWidth=0)) + g.add(Wedge(w/2.0, s/2.0, 3.502*m, 166, 342.1, 3.502*m, + fillColor=colors.blue,strokeColor=None, strokeWidth=0)) + + addStar(3.2,3.5,0.3) + addStar(-8.5,1.5,0.3) + addStar(-7.5,-3,0.3) + addStar(-4,-5.5,0.3) + addStar(0,-4.5,0.3) + addStar(7,-3.5,0.3) + addStar(-3.5,-0.5,0.25) + addStar(0,-1.5,0.25) + addStar(1,-2.5,0.25) + addStar(3,-7,0.25) + addStar(5,-6.5,0.25) + addStar(6.5,-5,0.25) + addStar(7,-4.5,0.25) + addStar(-5.5,-3.2,0.25) + addStar(-6,-4.2,0.25) + addStar(-1,-2.75,0.2) + addStar(2,-5.5,0.2) + addStar(4,-5.5,0.2) + addStar(5,-7.5,0.2) + addStar(5,-5.5,0.2) + addStar(6,-5.5,0.2) + addStar(-8.8,-3.2,0.2) + addStar(2.5,0.5,0.2) + addStar(-0.2,-3.2,0.14) + addStar(-7.2,-2,0.14) + addStar(0,-8,0.1) + + sTmp = "ORDEM E PROGRESSO" + nTmp = len(sTmp) + delta = 0.850848010347/nTmp + radius = 7.9 *m + centerx = (w/2.0)-(2*m) + centery = 0 + for i in range(nTmp): + rad = 2*pi - i*delta -4.60766922527 + x=cos(rad)*radius+centerx + y=sin(rad)*radius+centery + if i == 6: + z = 0.35*m + else: + z= 0.45*m + g2 = Group(String(x, y, sTmp[i], fontName='Helvetica-Bold', + fontSize = z,strokeColor=None,fillColor=colors.green)) + g2.rotate(rad) + g.add(g2) + return g + +def makeFlag(name): + flag = Flag() + flag.kind = name + return flag + +def test(): + """This function produces three pdf files with examples of all the signs and symbols from this file. + """ +# page 1 + + labelFontSize = 10 + + X = (20,245) + + flags = [ + 'UK', + 'USA', + 'Afghanistan', + 'Austria', + 'Belgium', + 'Denmark', + 'Cuba', + 'Finland', + 'France', + 'Germany', + 'Greece', + 'Ireland', + 'Italy', + 'Luxembourg', + 'Holland', + 'Palestine', + 'Portugal', + 'Spain', + 'Sweden', + 'Norway', + 'CzechRepublic', + 'Turkey', + 'Switzerland', + 'EU', + 'Brazil', + ] + y = Y0 = 530 + f = 0 + D = None + for name in flags: + if not D: D = Drawing(450,650) + flag = makeFlag(name) + i = flags.index(name) + flag.x = X[i%2] + flag.y = y + D.add(flag) + D.add(String(flag.x+(flag.size/2.0),(flag.y-(1.2*labelFontSize)), + name, fillColor=colors.black, textAnchor='middle', fontSize=labelFontSize)) + if i%2: y = y - 125 + if (i%2 and y<0) or name==flags[-1]: + renderPDF.drawToFile(D, 'flags%02d.pdf'%f, 'flags.py - Page #%d'%(f+1)) + y = Y0 + f = f+1 + D = None + +if __name__=='__main__': + test() diff --git a/reportlab/graphics/widgets/grids.py b/reportlab/graphics/widgets/grids.py new file mode 100644 index 00000000..693cbd7c --- /dev/null +++ b/reportlab/graphics/widgets/grids.py @@ -0,0 +1,519 @@ +#Copyright ReportLab Europe Ltd. 2000-2012 +#see license.txt for license details +#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/graphics/widgets/grids.py +__version__=''' $Id$ ''' + +from reportlab.lib import colors +from reportlab.lib.validators import isNumber, isColorOrNone, isBoolean, isListOfNumbers, OneOf, isListOfColors, isNumberOrNone +from reportlab.lib.attrmap import AttrMap, AttrMapValue +from reportlab.graphics.shapes import Drawing, Group, Line, Rect, LineShape, definePath, EmptyClipPath +from reportlab.graphics.widgetbase import Widget + +def frange(start, end=None, inc=None): + "A range function, that does accept float increments..." + + if end == None: + end = start + 0.0 + start = 0.0 + + if inc == None: + inc = 1.0 + + L = [] + end = end - inc*0.0001 #to avoid numrical problems + while 1: + next = start + len(L) * inc + if inc > 0 and next >= end: + break + elif inc < 0 and next <= end: + break + L.append(next) + + return L + + +def makeDistancesList(list): + """Returns a list of distances between adjacent numbers in some input list. + + E.g. [1, 1, 2, 3, 5, 7] -> [0, 1, 1, 2, 2] + """ + + d = [] + for i in range(len(list[:-1])): + d.append(list[i+1] - list[i]) + + return d + + +class Grid(Widget): + """This makes a rectangular grid of equidistant stripes. + + The grid contains an outer border rectangle, and stripes + inside which can be drawn with lines and/or as solid tiles. + The drawing order is: outer rectangle, then lines and tiles. + + The stripes' width is indicated as 'delta'. The sequence of + stripes can have an offset named 'delta0'. Both values need + to be positive! + """ + + _attrMap = AttrMap( + x = AttrMapValue(isNumber, desc="The grid's lower-left x position."), + y = AttrMapValue(isNumber, desc="The grid's lower-left y position."), + width = AttrMapValue(isNumber, desc="The grid's width."), + height = AttrMapValue(isNumber, desc="The grid's height."), + orientation = AttrMapValue(OneOf(('vertical', 'horizontal')), + desc='Determines if stripes are vertical or horizontal.'), + useLines = AttrMapValue(OneOf((0, 1)), + desc='Determines if stripes are drawn with lines.'), + useRects = AttrMapValue(OneOf((0, 1)), + desc='Determines if stripes are drawn with solid rectangles.'), + delta = AttrMapValue(isNumber, + desc='Determines the width/height of the stripes.'), + delta0 = AttrMapValue(isNumber, + desc='Determines the stripes initial width/height offset.'), + deltaSteps = AttrMapValue(isListOfNumbers, + desc='List of deltas to be used cyclically.'), + stripeColors = AttrMapValue(isListOfColors, + desc='Colors applied cyclically in the right or upper direction.'), + fillColor = AttrMapValue(isColorOrNone, + desc='Background color for entire rectangle.'), + strokeColor = AttrMapValue(isColorOrNone, + desc='Color used for lines.'), + strokeWidth = AttrMapValue(isNumber, + desc='Width used for lines.'), + rectStrokeColor = AttrMapValue(isColorOrNone, desc='Color for outer rect stroke.'), + rectStrokeWidth = AttrMapValue(isNumberOrNone, desc='Width for outer rect stroke.'), + ) + + def __init__(self): + self.x = 0 + self.y = 0 + self.width = 100 + self.height = 100 + self.orientation = 'vertical' + self.useLines = 0 + self.useRects = 1 + self.delta = 20 + self.delta0 = 0 + self.deltaSteps = [] + self.fillColor = colors.white + self.stripeColors = [colors.red, colors.green, colors.blue] + self.strokeColor = colors.black + self.strokeWidth = 2 + + + def demo(self): + D = Drawing(100, 100) + + g = Grid() + D.add(g) + + return D + + def makeOuterRect(self): + strokeColor = getattr(self,'rectStrokeColor',self.strokeColor) + strokeWidth = getattr(self,'rectStrokeWidth',self.strokeWidth) + if self.fillColor or (strokeColor and strokeWidth): + rect = Rect(self.x, self.y, self.width, self.height) + rect.fillColor = self.fillColor + rect.strokeColor = strokeColor + rect.strokeWidth = strokeWidth + return rect + else: + return None + + def makeLinePosList(self, start, isX=0): + "Returns a list of positions where to place lines." + + w, h = self.width, self.height + if isX: + length = w + else: + length = h + if self.deltaSteps: + r = [start + self.delta0] + i = 0 + while 1: + if r[-1] > start + length: + del r[-1] + break + r.append(r[-1] + self.deltaSteps[i % len(self.deltaSteps)]) + i = i + 1 + else: + r = frange(start + self.delta0, start + length, self.delta) + + r.append(start + length) + if self.delta0 != 0: + r.insert(0, start) + #print 'Grid.makeLinePosList() -> %s' % r + return r + + + def makeInnerLines(self): + # inner grid lines + group = Group() + + w, h = self.width, self.height + + if self.useLines == 1: + if self.orientation == 'vertical': + r = self.makeLinePosList(self.x, isX=1) + for x in r: + line = Line(x, self.y, x, self.y + h) + line.strokeColor = self.strokeColor + line.strokeWidth = self.strokeWidth + group.add(line) + elif self.orientation == 'horizontal': + r = self.makeLinePosList(self.y, isX=0) + for y in r: + line = Line(self.x, y, self.x + w, y) + line.strokeColor = self.strokeColor + line.strokeWidth = self.strokeWidth + group.add(line) + + return group + + + def makeInnerTiles(self): + # inner grid lines + group = Group() + + w, h = self.width, self.height + + # inner grid stripes (solid rectangles) + if self.useRects == 1: + cols = self.stripeColors + + if self.orientation == 'vertical': + r = self.makeLinePosList(self.x, isX=1) + elif self.orientation == 'horizontal': + r = self.makeLinePosList(self.y, isX=0) + + dist = makeDistancesList(r) + + i = 0 + for j in range(len(dist)): + if self.orientation == 'vertical': + x = r[j] + stripe = Rect(x, self.y, dist[j], h) + elif self.orientation == 'horizontal': + y = r[j] + stripe = Rect(self.x, y, w, dist[j]) + stripe.fillColor = cols[i % len(cols)] + stripe.strokeColor = None + group.add(stripe) + i = i + 1 + + return group + + + def draw(self): + # general widget bits + group = Group() + + group.add(self.makeOuterRect()) + group.add(self.makeInnerTiles()) + group.add(self.makeInnerLines(),name='_gridLines') + + return group + + +class DoubleGrid(Widget): + """This combines two ordinary Grid objects orthogonal to each other. + """ + + _attrMap = AttrMap( + x = AttrMapValue(isNumber, desc="The grid's lower-left x position."), + y = AttrMapValue(isNumber, desc="The grid's lower-left y position."), + width = AttrMapValue(isNumber, desc="The grid's width."), + height = AttrMapValue(isNumber, desc="The grid's height."), + grid0 = AttrMapValue(None, desc="The first grid component."), + grid1 = AttrMapValue(None, desc="The second grid component."), + ) + + def __init__(self): + self.x = 0 + self.y = 0 + self.width = 100 + self.height = 100 + + g0 = Grid() + g0.x = self.x + g0.y = self.y + g0.width = self.width + g0.height = self.height + g0.orientation = 'vertical' + g0.useLines = 1 + g0.useRects = 0 + g0.delta = 20 + g0.delta0 = 0 + g0.deltaSteps = [] + g0.fillColor = colors.white + g0.stripeColors = [colors.red, colors.green, colors.blue] + g0.strokeColor = colors.black + g0.strokeWidth = 1 + + g1 = Grid() + g1.x = self.x + g1.y = self.y + g1.width = self.width + g1.height = self.height + g1.orientation = 'horizontal' + g1.useLines = 1 + g1.useRects = 0 + g1.delta = 20 + g1.delta0 = 0 + g1.deltaSteps = [] + g1.fillColor = colors.white + g1.stripeColors = [colors.red, colors.green, colors.blue] + g1.strokeColor = colors.black + g1.strokeWidth = 1 + + self.grid0 = g0 + self.grid1 = g1 + + +## # This gives an AttributeError: +## # DoubleGrid instance has no attribute 'grid0' +## def __setattr__(self, name, value): +## if name in ('x', 'y', 'width', 'height'): +## setattr(self.grid0, name, value) +## setattr(self.grid1, name, value) + + + def demo(self): + D = Drawing(100, 100) + g = DoubleGrid() + D.add(g) + return D + + + def draw(self): + group = Group() + g0, g1 = self.grid0, self.grid1 + # Order groups to make sure both v and h lines + # are visible (works only when there is only + # one kind of stripes, v or h). + G = g0.useRects == 1 and g1.useRects == 0 and (g0,g1) or (g1,g0) + for g in G: + group.add(g.makeOuterRect()) + for g in G: + group.add(g.makeInnerTiles()) + group.add(g.makeInnerLines(),name='_gridLines') + + return group + + +class ShadedRect(Widget): + """This makes a rectangle with shaded colors between two colors. + + Colors are interpolated linearly between 'fillColorStart' + and 'fillColorEnd', both of which appear at the margins. + If 'numShades' is set to one, though, only 'fillColorStart' + is used. + """ + + _attrMap = AttrMap( + x = AttrMapValue(isNumber, desc="The grid's lower-left x position."), + y = AttrMapValue(isNumber, desc="The grid's lower-left y position."), + width = AttrMapValue(isNumber, desc="The grid's width."), + height = AttrMapValue(isNumber, desc="The grid's height."), + orientation = AttrMapValue(OneOf(('vertical', 'horizontal')), desc='Determines if stripes are vertical or horizontal.'), + numShades = AttrMapValue(isNumber, desc='The number of interpolating colors.'), + fillColorStart = AttrMapValue(isColorOrNone, desc='Start value of the color shade.'), + fillColorEnd = AttrMapValue(isColorOrNone, desc='End value of the color shade.'), + strokeColor = AttrMapValue(isColorOrNone, desc='Color used for border line.'), + strokeWidth = AttrMapValue(isNumber, desc='Width used for lines.'), + cylinderMode = AttrMapValue(isBoolean, desc='True if shading reverses in middle.'), + ) + + def __init__(self,**kw): + self.x = 0 + self.y = 0 + self.width = 100 + self.height = 100 + self.orientation = 'vertical' + self.numShades = 20 + self.fillColorStart = colors.pink + self.fillColorEnd = colors.black + self.strokeColor = colors.black + self.strokeWidth = 2 + self.cylinderMode = 0 + self.setProperties(kw) + + def demo(self): + D = Drawing(100, 100) + g = ShadedRect() + D.add(g) + + return D + + def _flipRectCorners(self): + "Flip rectangle's corners if width or height is negative." + x, y, width, height, fillColorStart, fillColorEnd = self.x, self.y, self.width, self.height, self.fillColorStart, self.fillColorEnd + if width < 0 and height > 0: + x = x + width + width = -width + if self.orientation=='vertical': fillColorStart, fillColorEnd = fillColorEnd, fillColorStart + elif height<0 and width>0: + y = y + height + height = -height + if self.orientation=='horizontal': fillColorStart, fillColorEnd = fillColorEnd, fillColorStart + elif height < 0 and height < 0: + x = x + width + width = -width + y = y + height + height = -height + return x, y, width, height, fillColorStart, fillColorEnd + + def draw(self): + # general widget bits + group = Group() + x, y, w, h, c0, c1 = self._flipRectCorners() + numShades = self.numShades + if self.cylinderMode: + if not numShades%2: numShades = numShades+1 + halfNumShades = int((numShades-1)/2) + 1 + num = float(numShades) # must make it float! + vertical = self.orientation == 'vertical' + if vertical: + if numShades == 1: + V = [x] + else: + V = frange(x, x + w, w/num) + else: + if numShades == 1: + V = [y] + else: + V = frange(y, y + h, h/num) + + for v in V: + stripe = vertical and Rect(v, y, w/num, h) or Rect(x, v, w, h/num) + if self.cylinderMode: + if V.index(v)>=halfNumShades: + col = colors.linearlyInterpolatedColor(c1,c0,V[halfNumShades],V[-1], v) + else: + col = colors.linearlyInterpolatedColor(c0,c1,V[0],V[halfNumShades], v) + else: + col = colors.linearlyInterpolatedColor(c0,c1,V[0],V[-1], v) + stripe.fillColor = col + stripe.strokeColor = col + stripe.strokeWidth = 1 + group.add(stripe) + if self.strokeColor and self.strokeWidth>=0: + rect = Rect(x, y, w, h) + rect.strokeColor = self.strokeColor + rect.strokeWidth = self.strokeWidth + rect.fillColor = None + group.add(rect) + return group + + +def colorRange(c0, c1, n): + "Return a range of intermediate colors between c0 and c1" + if n==1: return [c0] + + C = [] + if n>1: + lim = n-1 + for i in range(n): + C.append(colors.linearlyInterpolatedColor(c0,c1,0,lim, i)) + return C + + +def centroid(P): + '''compute average point of a set of points''' + cx = 0 + cy = 0 + for x,y in P: + cx+=x + cy+=y + n = float(len(P)) + return cx/n, cy/n + +def rotatedEnclosingRect(P, angle, rect): + ''' + given P a sequence P of x,y coordinate pairs and an angle in degrees + find the centroid of P and the axis at angle theta through it + find the extreme points of P wrt axis parallel distance and axis + orthogonal distance. Then compute the least rectangle that will still + enclose P when rotated by angle. + + The class R + ''' + from math import pi, cos, sin, tan + x0, y0 = centroid(P) + theta = (angle/180.)*pi + s,c=sin(theta),cos(theta) + def parallelAxisDist(xy,s=s,c=c,x0=x0,y0=y0): + x,y = xy + return (s*(y-y0)+c*(x-x0)) + def orthogonalAxisDist(xy,s=s,c=c,x0=x0,y0=y0): + x,y = xy + return (c*(y-y0)+s*(x-x0)) + L = list(map(parallelAxisDist,P)) + L.sort() + a0, a1 = L[0], L[-1] + L = list(map(orthogonalAxisDist,P)) + L.sort() + b0, b1 = L[0], L[-1] + rect.x, rect.width = a0, a1-a0 + rect.y, rect.height = b0, b1-b0 + g = Group(transform=(c,s,-s,c,x0,y0)) + g.add(rect) + return g + +class ShadedPolygon(Widget,LineShape): + _attrMap = AttrMap(BASE=LineShape, + angle = AttrMapValue(isNumber,desc="Shading angle"), + fillColorStart = AttrMapValue(isColorOrNone), + fillColorEnd = AttrMapValue(isColorOrNone), + numShades = AttrMapValue(isNumber, desc='The number of interpolating colors.'), + cylinderMode = AttrMapValue(isBoolean, desc='True if shading reverses in middle.'), + points = AttrMapValue(isListOfNumbers), + ) + + def __init__(self,**kw): + self.angle = 90 + self.fillColorStart = colors.red + self.fillColorEnd = colors.green + self.cylinderMode = 0 + self.numShades = 50 + self.points = [-1,-1,2,2,3,-1] + LineShape.__init__(self,kw) + + def draw(self): + P = self.points + P = list(map(lambda i, P=P:(P[i],P[i+1]),range(0,len(P),2))) + path = definePath([('moveTo',)+P[0]]+[('lineTo',)+x for x in P[1:]]+['closePath'], + fillColor=None, strokeColor=None) + path.isClipPath = 1 + g = Group() + g.add(path) + angle = self.angle + orientation = 'vertical' + if angle==180: + angle = 0 + elif angle in (90,270): + orientation ='horizontal' + angle = 0 + rect = ShadedRect(strokeWidth=0,strokeColor=None,orientation=orientation) + for k in 'fillColorStart', 'fillColorEnd', 'numShades', 'cylinderMode': + setattr(rect,k,getattr(self,k)) + g.add(rotatedEnclosingRect(P, angle, rect)) + g.add(EmptyClipPath) + path = path.copy() + path.isClipPath = 0 + path.strokeColor = self.strokeColor + path.strokeWidth = self.strokeWidth + g.add(path) + return g + +if __name__=='__main__': #noruntests + from reportlab.lib.colors import blue + from reportlab.graphics.shapes import Drawing + angle=45 + D = Drawing(120,120) + D.add(ShadedPolygon(points=(10,10,60,60,110,10),strokeColor=None,strokeWidth=1,angle=90,numShades=50,cylinderMode=0)) + D.save(formats=['gif'],fnRoot='shobj',outDir='/tmp') diff --git a/reportlab/graphics/widgets/markers.py b/reportlab/graphics/widgets/markers.py new file mode 100644 index 00000000..11851fd4 --- /dev/null +++ b/reportlab/graphics/widgets/markers.py @@ -0,0 +1,245 @@ +#Copyright ReportLab Europe Ltd. 2000-2013 +#see license.txt for license details + +__version__=''' $Id$ ''' +__doc__="""This modules defines a collection of markers used in charts. +""" + +from reportlab.graphics.shapes import Rect, Line, Circle, Polygon, Drawing, Group +from reportlab.graphics.widgets.signsandsymbols import SmileyFace +from reportlab.graphics.widgetbase import Widget +from reportlab.lib.validators import isNumber, isColorOrNone, OneOf, Validator +from reportlab.lib.attrmap import AttrMap, AttrMapValue +from reportlab.lib.colors import black +from reportlab.lib.utils import isFunction, isClass +from reportlab.graphics.widgets.flags import Flag +from math import sin, cos, pi +_toradians = pi/180.0 + +class Marker(Widget): + '''A polymorphic class of markers''' + _attrMap = AttrMap(BASE=Widget, + kind = AttrMapValue( + OneOf(None, 'Square', 'Diamond', 'Circle', 'Cross', 'Triangle', 'StarSix', + 'Pentagon', 'Hexagon', 'Heptagon', 'Octagon', 'StarFive', + 'FilledSquare', 'FilledCircle', 'FilledDiamond', 'FilledCross', + 'FilledTriangle','FilledStarSix', 'FilledPentagon', 'FilledHexagon', + 'FilledHeptagon', 'FilledOctagon', 'FilledStarFive', + 'Smiley','ArrowHead', 'FilledArrowHead'), + desc='marker type name'), + size = AttrMapValue(isNumber,desc='marker size'), + x = AttrMapValue(isNumber,desc='marker x coordinate'), + y = AttrMapValue(isNumber,desc='marker y coordinate'), + dx = AttrMapValue(isNumber,desc='marker x coordinate adjustment'), + dy = AttrMapValue(isNumber,desc='marker y coordinate adjustment'), + angle = AttrMapValue(isNumber,desc='marker rotation'), + fillColor = AttrMapValue(isColorOrNone, desc='marker fill colour'), + strokeColor = AttrMapValue(isColorOrNone, desc='marker stroke colour'), + strokeWidth = AttrMapValue(isNumber, desc='marker stroke width'), + arrowBarbDx = AttrMapValue(isNumber, desc='arrow only the delta x for the barbs'), + arrowHeight = AttrMapValue(isNumber, desc='arrow only height'), + ) + + def __init__(self,*args,**kw): + self.setProperties(kw) + self._setKeywords( + kind = None, + strokeColor = black, + strokeWidth = 0.1, + fillColor = None, + size = 5, + x = 0, + y = 0, + dx = 0, + dy = 0, + angle = 0, + arrowBarbDx = -1.25, + arrowHeight = 1.875, + ) + + def clone(self,**kwds): + n = self.__class__(**self.__dict__) + if kwds: n.__dict__.update(kwds) + return n + + def _Smiley(self): + x, y = self.x+self.dx, self.y+self.dy + d = self.size/2.0 + s = SmileyFace() + s.fillColor = self.fillColor + s.strokeWidth = self.strokeWidth + s.strokeColor = self.strokeColor + s.x = x-d + s.y = y-d + s.size = d*2 + return s + + def _Square(self): + x, y = self.x+self.dx, self.y+self.dy + d = self.size/2.0 + s = Rect(x-d,y-d,2*d,2*d,fillColor=self.fillColor,strokeColor=self.strokeColor,strokeWidth=self.strokeWidth) + return s + + def _Diamond(self): + d = self.size/2.0 + return self._doPolygon((-d,0,0,d,d,0,0,-d)) + + def _Circle(self): + x, y = self.x+self.dx, self.y+self.dy + s = Circle(x,y,self.size/2.0,fillColor=self.fillColor,strokeColor=self.strokeColor,strokeWidth=self.strokeWidth) + return s + + def _Cross(self): + x, y = self.x+self.dx, self.y+self.dy + s = float(self.size) + h, s = s/2, s/6 + return self._doPolygon((-s,-h,-s,-s,-h,-s,-h,s,-s,s,-s,h,s,h,s,s,h,s,h,-s,s,-s,s,-h)) + + def _Triangle(self): + x, y = self.x+self.dx, self.y+self.dy + r = float(self.size)/2 + c = 30*_toradians + s = sin(30*_toradians)*r + c = cos(c)*r + return self._doPolygon((0,r,-c,-s,c,-s)) + + def _StarSix(self): + r = float(self.size)/2 + c = 30*_toradians + s = sin(c)*r + c = cos(c)*r + z = s/2 + g = c/2 + return self._doPolygon((0,r,-z,s,-c,s,-s,0,-c,-s,-z,-s,0,-r,z,-s,c,-s,s,0,c,s,z,s)) + + def _StarFive(self): + R = float(self.size)/2 + r = R*sin(18*_toradians)/cos(36*_toradians) + P = [] + angle = 90 + for i in range(5): + for radius in R, r: + theta = angle*_toradians + P.append(radius*cos(theta)) + P.append(radius*sin(theta)) + angle = angle + 36 + return self._doPolygon(P) + + def _Pentagon(self): + return self._doNgon(5) + + def _Hexagon(self): + return self._doNgon(6) + + def _Heptagon(self): + return self._doNgon(7) + + def _Octagon(self): + return self._doNgon(8) + + def _ArrowHead(self): + s = self.size + h = self.arrowHeight + b = self.arrowBarbDx + return self._doPolygon((0,0,b,-h,s,0,b,h)) + + def _doPolygon(self,P): + x, y = self.x+self.dx, self.y+self.dy + if x or y: P = list(map(lambda i,P=P,A=[x,y]: P[i] + A[i&1], list(range(len(P))))) + return Polygon(P, strokeWidth =self.strokeWidth, strokeColor=self.strokeColor, fillColor=self.fillColor) + + def _doFill(self): + old = self.fillColor + if old is None: + self.fillColor = self.strokeColor + r = (self.kind and getattr(self,'_'+self.kind[6:]) or Group)() + self.fillColor = old + return r + + def _doNgon(self,n): + P = [] + size = float(self.size)/2 + for i in range(n): + r = (2.*i/n+0.5)*pi + P.append(size*cos(r)) + P.append(size*sin(r)) + return self._doPolygon(P) + + _FilledCircle = _doFill + _FilledSquare = _doFill + _FilledDiamond = _doFill + _FilledCross = _doFill + _FilledTriangle = _doFill + _FilledStarSix = _doFill + _FilledPentagon = _doFill + _FilledHexagon = _doFill + _FilledHeptagon = _doFill + _FilledOctagon = _doFill + _FilledStarFive = _doFill + _FilledArrowHead = _doFill + + def draw(self): + if self.kind: + m = getattr(self,'_'+self.kind) + if self.angle: + _x, _dx, _y, _dy = self.x, self.dx, self.y, self.dy + self.x, self.dx, self.y, self.dy = 0,0,0,0 + try: + m = m() + finally: + self.x, self.dx, self.y, self.dy = _x, _dx, _y, _dy + if not isinstance(m,Group): + _m, m = m, Group() + m.add(_m) + if self.angle: m.rotate(self.angle) + x, y = _x+_dx, _y+_dy + if x or y: m.shift(x,y) + else: + m = m() + else: + m = Group() + return m + +def uSymbol2Symbol(uSymbol,x,y,color): + if isFunction(uSymbol): + symbol = uSymbol(x, y, 5, color) + elif isClass(uSymbol) and issubclass(uSymbol,Widget): + size = 10. + symbol = uSymbol() + symbol.x = x - (size/2) + symbol.y = y - (size/2) + try: + symbol.size = size + symbol.color = color + except: + pass + elif isinstance(uSymbol,Marker) or isinstance(uSymbol,Flag): + symbol = uSymbol.clone() + if isinstance(uSymbol,Marker): symbol.fillColor = symbol.fillColor or color + symbol.x, symbol.y = x, y + else: + symbol = None + return symbol + +class _isSymbol(Validator): + def test(self,x): + return hasattr(x,'__call__') or isinstance(x,Marker) or isinstance(x,Flag) or (isinstance(x,type) and issubclass(x,Widget)) + +isSymbol = _isSymbol() + +def makeMarker(name,**kw): + if Marker._attrMap['kind'].validate(name): + m = Marker(**kw) + m.kind = name + elif name[-5:]=='_Flag' and Flag._attrMap['kind'].validate(name[:-5]): + m = Flag(**kw) + m.kind = name[:-5] + m.size = 10 + else: + raise ValueError("Invalid marker name %s" % name) + return m + +if __name__=='__main__': + D = Drawing() + D.add(Marker()) + D.save(fnRoot='Marker',formats=['pdf'], outDir='/tmp') diff --git a/reportlab/graphics/widgets/signsandsymbols.py b/reportlab/graphics/widgets/signsandsymbols.py new file mode 100644 index 00000000..87bcbaab --- /dev/null +++ b/reportlab/graphics/widgets/signsandsymbols.py @@ -0,0 +1,933 @@ +#Copyright ReportLab Europe Ltd. 2000-2012 +#see license.txt for license details +#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/graphics/widgets/signsandsymbols.py +# signsandsymbols.py +# A collection of new widgets +# author: John Precedo (johnp@reportlab.com) + +__version__=''' $Id$ ''' +__doc__="""This file is a collection of widgets to produce some common signs and symbols. + +Widgets include: + +- ETriangle (an equilateral triangle), +- RTriangle (a right angled triangle), +- Octagon, +- Crossbox, +- Tickbox, +- SmileyFace, +- StopSign, +- NoEntry, +- NotAllowed (the red roundel from 'no smoking' signs), +- NoSmoking, +- DangerSign (a black exclamation point in a yellow triangle), +- YesNo (returns a tickbox or a crossbox depending on a testvalue), +- FloppyDisk, +- ArrowOne, and +- ArrowTwo +""" + +from reportlab.lib import colors +from reportlab.lib.validators import * +from reportlab.lib.attrmap import * +from reportlab.graphics import shapes +from reportlab.graphics.widgetbase import Widget +from reportlab.graphics import renderPDF + + +class _Symbol(Widget): + """Abstract base widget + possible attributes: + 'x', 'y', 'size', 'fillColor', 'strokeColor' + """ + _nodoc = 1 + _attrMap = AttrMap( + x = AttrMapValue(isNumber,desc='symbol x coordinate'), + y = AttrMapValue(isNumber,desc='symbol y coordinate'), + dx = AttrMapValue(isNumber,desc='symbol x coordinate adjustment'), + dy = AttrMapValue(isNumber,desc='symbol x coordinate adjustment'), + size = AttrMapValue(isNumber), + fillColor = AttrMapValue(isColorOrNone), + strokeColor = AttrMapValue(isColorOrNone), + strokeWidth = AttrMapValue(isNumber), + ) + def __init__(self): + assert self.__class__.__name__!='_Symbol', 'Abstract class _Symbol instantiated' + self.x = self.y = self.dx = self.dy = 0 + self.size = 100 + self.fillColor = colors.red + self.strokeColor = None + self.strokeWidth = 0.1 + + def demo(self): + D = shapes.Drawing(200, 100) + s = float(self.size) + ob = self.__class__() + ob.x=50 + ob.y=0 + ob.draw() + D.add(ob) + D.add(shapes.String(ob.x+(s/2),(ob.y-12), + ob.__class__.__name__, fillColor=colors.black, textAnchor='middle', + fontSize=10)) + return D + +class ETriangle(_Symbol): + """This draws an equilateral triangle.""" + + def __init__(self): + pass #AbstractSymbol + + def draw(self): + # general widget bits + s = float(self.size) # abbreviate as we will use this a lot + g = shapes.Group() + + # Triangle specific bits + ae = s*0.125 #(ae = 'an eighth') + triangle = shapes.Polygon(points = [ + self.x, self.y, + self.x+s, self.y, + self.x+(s/2),self.y+s], + fillColor = self.fillColor, + strokeColor = self.strokeColor, + strokeWidth=s/50.) + g.add(triangle) + return g + +class RTriangle(_Symbol): + """This draws a right-angled triangle. + + possible attributes: + 'x', 'y', 'size', 'fillColor', 'strokeColor' + + """ + + def __init__(self): + self.x = 0 + self.y = 0 + self.size = 100 + self.fillColor = colors.green + self.strokeColor = None + + def draw(self): + # general widget bits + s = float(self.size) # abbreviate as we will use this a lot + g = shapes.Group() + + # Triangle specific bits + ae = s*0.125 #(ae = 'an eighth') + triangle = shapes.Polygon(points = [ + self.x, self.y, + self.x+s, self.y, + self.x,self.y+s], + fillColor = self.fillColor, + strokeColor = self.strokeColor, + strokeWidth=s/50.) + g.add(triangle) + return g + +class Octagon(_Symbol): + """This widget draws an Octagon. + + possible attributes: + 'x', 'y', 'size', 'fillColor', 'strokeColor' + + """ + + def __init__(self): + self.x = 0 + self.y = 0 + self.size = 100 + self.fillColor = colors.yellow + self.strokeColor = None + + def draw(self): + # general widget bits + s = float(self.size) # abbreviate as we will use this a lot + g = shapes.Group() + + # Octagon specific bits + athird=s/3 + + octagon = shapes.Polygon(points=[self.x+athird, self.y, + self.x, self.y+athird, + self.x, self.y+(athird*2), + self.x+athird, self.y+s, + self.x+(athird*2), self.y+s, + self.x+s, self.y+(athird*2), + self.x+s, self.y+athird, + self.x+(athird*2), self.y], + strokeColor = self.strokeColor, + fillColor = self.fillColor, + strokeWidth=10) + g.add(octagon) + return g + +class Crossbox(_Symbol): + """This draws a black box with a red cross in it - a 'checkbox'. + + possible attributes: + 'x', 'y', 'size', 'crossColor', 'strokeColor', 'crosswidth' + + """ + + _attrMap = AttrMap(BASE=_Symbol, + crossColor = AttrMapValue(isColorOrNone), + crosswidth = AttrMapValue(isNumber), + ) + + def __init__(self): + self.x = 0 + self.y = 0 + self.size = 100 + self.fillColor = colors.white + self.crossColor = colors.red + self.strokeColor = colors.black + self.crosswidth = 10 + + def draw(self): + # general widget bits + s = float(self.size) # abbreviate as we will use this a lot + g = shapes.Group() + + # crossbox specific bits + box = shapes.Rect(self.x+1, self.y+1, s-2, s-2, + fillColor = self.fillColor, + strokeColor = self.strokeColor, + strokeWidth=2) + g.add(box) + + crossLine1 = shapes.Line(self.x+(s*0.15), self.y+(s*0.15), self.x+(s*0.85), self.y+(s*0.85), + fillColor = self.crossColor, + strokeColor = self.crossColor, + strokeWidth = self.crosswidth) + g.add(crossLine1) + + crossLine2 = shapes.Line(self.x+(s*0.15), self.y+(s*0.85), self.x+(s*0.85) ,self.y+(s*0.15), + fillColor = self.crossColor, + strokeColor = self.crossColor, + strokeWidth = self.crosswidth) + g.add(crossLine2) + + return g + + +class Tickbox(_Symbol): + """This draws a black box with a red tick in it - another 'checkbox'. + + possible attributes: + 'x', 'y', 'size', 'tickColor', 'strokeColor', 'tickwidth' + +""" + + _attrMap = AttrMap(BASE=_Symbol, + tickColor = AttrMapValue(isColorOrNone), + tickwidth = AttrMapValue(isNumber), + ) + + def __init__(self): + self.x = 0 + self.y = 0 + self.size = 100 + self.tickColor = colors.red + self.strokeColor = colors.black + self.fillColor = colors.white + self.tickwidth = 10 + + def draw(self): + # general widget bits + s = float(self.size) # abbreviate as we will use this a lot + g = shapes.Group() + + # tickbox specific bits + box = shapes.Rect(self.x+1, self.y+1, s-2, s-2, + fillColor = self.fillColor, + strokeColor = self.strokeColor, + strokeWidth=2) + g.add(box) + + tickLine = shapes.PolyLine(points = [self.x+(s*0.15), self.y+(s*0.35), self.x+(s*0.35), self.y+(s*0.15), + self.x+(s*0.35), self.y+(s*0.15), self.x+(s*0.85) ,self.y+(s*0.85)], + fillColor = self.tickColor, + strokeColor = self.tickColor, + strokeWidth = self.tickwidth) + g.add(tickLine) + + return g + +class SmileyFace(_Symbol): + """This draws a classic smiley face. + + possible attributes: + 'x', 'y', 'size', 'fillColor' + + """ + + def __init__(self): + _Symbol.__init__(self) + self.x = 0 + self.y = 0 + self.size = 100 + self.fillColor = colors.yellow + self.strokeColor = colors.black + + def draw(self): + # general widget bits + s = float(self.size) # abbreviate as we will use this a lot + g = shapes.Group() + + # SmileyFace specific bits + g.add(shapes.Circle(cx=self.x+(s/2), cy=self.y+(s/2), r=s/2, + fillColor=self.fillColor, strokeColor=self.strokeColor, + strokeWidth=max(s/38.,self.strokeWidth))) + + for i in (1,2): + g.add(shapes.Ellipse(self.x+(s/3)*i,self.y+(s/3)*2, s/30, s/10, + fillColor=self.strokeColor, strokeColor = self.strokeColor, + strokeWidth=max(s/38.,self.strokeWidth))) + + # calculate a pointslist for the mouth + # THIS IS A HACK! - don't use if there is a 'shapes.Arc' + centerx=self.x+(s/2) + centery=self.y+(s/2) + radius=s/3 + yradius = radius + xradius = radius + startangledegrees=200 + endangledegrees=340 + degreedelta = 1 + pointslist = [] + a = pointslist.append + from math import sin, cos, pi + degreestoradians = pi/180.0 + radiansdelta = degreedelta*degreestoradians + startangle = startangledegrees*degreestoradians + endangle = endangledegrees*degreestoradians + while endangle>> font = UnicodeCIDFont('HeiseiMin-W3') + >>> font.stringWidth(unicode(','), 10) + 2.5 + >>> font.stringWidth(unicode('m'), 10) + 7.7800000000000002 + >>> font.stringWidth(u'\u6771\u4EAC', 10) + 20.0 + >>> + +""" + +from pprint import pprint as pp + +from reportlab.pdfbase._cidfontdata import defaultUnicodeEncodings +from reportlab.pdfbase.cidfonts import UnicodeCIDFont + + +def run(): + + buf = [] + buf.append('widthsByUnichar = {}') + for fontName, (language, encName) in defaultUnicodeEncodings.items(): + print('handling %s : %s : %s' % (fontName, language, encName)) + + #this does just about all of it for us, as all the info + #we need is present. + font = UnicodeCIDFont(fontName) + + widthsByCID = font.face._explicitWidths + cmap = font.encoding._cmap + nonStandardWidthsByUnichar = {} + for codePoint, cid in cmap.items(): + width = widthsByCID.get(cid, 1000) + if width != 1000: + nonStandardWidthsByUnichar[chr(codePoint)] = width + + + + print('created font width map (%d items). ' % len(nonStandardWidthsByUnichar)) + + buf.append('widthsByUnichar["%s"] = %s' % (fontName, repr(nonStandardWidthsByUnichar))) + + + src = '\n'.join(buf) + '\n' + open('canned_widths.py','w').write(src) + print('wrote canned_widths.py') + +if __name__=='__main__': + run() + diff --git a/reportlab/pdfbase/_cidfontdata.py b/reportlab/pdfbase/_cidfontdata.py new file mode 100644 index 00000000..b4f5ef27 --- /dev/null +++ b/reportlab/pdfbase/_cidfontdata.py @@ -0,0 +1,483 @@ +#Copyright ReportLab Europe Ltd. 2000-2012 +#see license.txt for license details +#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/pdfbase/_cidfontdata.py +#$Header $ +__version__=''' $Id$ ''' +__doc__=""" +This defines additional static data to support CID fonts. + +Canned data is provided for the Japanese fonts supported by Adobe. We +can add Chinese, Korean and Vietnamese in due course. The data was +extracted by creating very simple postscript documents and running +through Distiller, then examining the resulting PDFs. + +Each font is described as a big nested dictionary. This lets us keep +code out of the module altogether and avoid circular dependencies. + +The encoding and font data are grouped by some standard 'language +prefixes':: + + chs = Chinese Simplified (mainland) + cht = Chinese Traditional (Taiwan) + kor = Korean + jpn = Japanese +""" + + +languages = ['jpn', 'kor', 'cht', 'chs'] + +#breaking down the lists let us check if something is present +#for a specific language +typeFaces_chs = ['STSong-Light'] # to do +typeFaces_cht = ['MSung-Light'] #, 'MHei-Medium'] # to do +typeFaces_jpn = ['HeiseiMin-W3', 'HeiseiKakuGo-W5'] +typeFaces_kor = ['HYSMyeongJo-Medium','HYGothic-Medium'] + +allowedTypeFaces = typeFaces_chs + typeFaces_cht + typeFaces_jpn + typeFaces_kor + + + + +encodings_jpn = [ + # official encoding names, comments taken verbatim from PDF Spec + '83pv-RKSJ-H', #Macintosh, JIS X 0208 character set with KanjiTalk6 + #extensions, Shift-JIS encoding, Script Manager code 1 + '90ms-RKSJ-H', #Microsoft Code Page 932 (lfCharSet 0x80), JIS X 0208 + #character set with NEC and IBM extensions + '90ms-RKSJ-V', #Vertical version of 90ms-RKSJ-H + '90msp-RKSJ-H', #Same as 90ms-RKSJ-H, but replaces half-width Latin + #characters with proportional forms + '90msp-RKSJ-V', #Vertical version of 90msp-RKSJ-H + '90pv-RKSJ-H', #Macintosh, JIS X 0208 character set with KanjiTalk7 + #extensions, Shift-JIS encoding, Script Manager code 1 + 'Add-RKSJ-H', #JIS X 0208 character set with Fujitsu FMR extensions, + #Shift-JIS encoding + 'Add-RKSJ-V', #Vertical version of Add-RKSJ-H + 'EUC-H', #JIS X 0208 character set, EUC-JP encoding + 'EUC-V', #Vertical version of EUC-H + 'Ext-RKSJ-H', #JIS C 6226 (JIS78) character set with NEC extensions, + #Shift-JIS encoding + 'Ext-RKSJ-V', #Vertical version of Ext-RKSJ-H + 'H', #JIS X 0208 character set, ISO-2022-JP encoding, + 'V', #Vertical version of H + 'UniJIS-UCS2-H', #Unicode (UCS-2) encoding for the Adobe-Japan1 character + #collection + 'UniJIS-UCS2-V', #Vertical version of UniJIS-UCS2-H + 'UniJIS-UCS2-HW-H', #Same as UniJIS-UCS2-H, but replaces proportional Latin + #characters with half-width forms + 'UniJIS-UCS2-HW-V' #Vertical version of UniJIS-UCS2-HW-H + ] +encodings_kor = [ + 'KSC-EUC-H', # KS X 1001:1992 character set, EUC-KR encoding + 'KSC-EUC-V', # Vertical version of KSC-EUC-H + 'KSCms-UHC-H', # Microsoft Code Page 949 (lfCharSet 0x81), KS X 1001:1992 + #character set plus 8,822 additional hangul, Unified Hangul + #Code (UHC) encoding + 'KSCms-UHC-V', #Vertical version of KSCms-UHC-H + 'KSCms-UHC-HW-H', #Same as KSCms-UHC-H, but replaces proportional Latin + # characters with halfwidth forms + 'KSCms-UHC-HW-V', #Vertical version of KSCms-UHC-HW-H + 'KSCpc-EUC-H', #Macintosh, KS X 1001:1992 character set with MacOS-KH + #extensions, Script Manager Code 3 + 'UniKS-UCS2-H', #Unicode (UCS-2) encoding for the Adobe-Korea1 character collection + 'UniKS-UCS2-V' #Vertical version of UniKS-UCS2-H + + ] + +encodings_chs = [ + + 'GB-EUC-H', # Microsoft Code Page 936 (lfCharSet 0x86), GB 2312-80 + # character set, EUC-CN encoding + 'GB-EUC-V', # Vertical version of GB-EUC-H + 'GBpc-EUC-H', # Macintosh, GB 2312-80 character set, EUC-CN encoding, + # Script Manager code 2 + 'GBpc-EUC-V', # Vertical version of GBpc-EUC-H + 'GBK-EUC-H', # Microsoft Code Page 936 (lfCharSet 0x86), GBK character + # set, GBK encoding + 'GBK-EUC-V', # Vertical version of GBK-EUC-V + 'UniGB-UCS2-H', # Unicode (UCS-2) encoding for the Adobe-GB1 + # character collection + 'UniGB-UCS2-V' # Vertical version of UniGB-UCS2-H. + ] + +encodings_cht = [ + 'B5pc-H', # Macintosh, Big Five character set, Big Five encoding, + # Script Manager code 2 + 'B5pc-V', # Vertical version of B5pc-H + 'ETen-B5-H', # Microsoft Code Page 950 (lfCharSet 0x88), Big Five + # character set with ETen extensions + 'ETen-B5-V', # Vertical version of ETen-B5-H + 'ETenms-B5-H', # Microsoft Code Page 950 (lfCharSet 0x88), Big Five + # character set with ETen extensions; this uses proportional + # forms for half-width Latin characters. + 'ETenms-B5-V', # Vertical version of ETenms-B5-H + 'CNS-EUC-H', # CNS 11643-1992 character set, EUC-TW encoding + 'CNS-EUC-V', # Vertical version of CNS-EUC-H + 'UniCNS-UCS2-H', # Unicode (UCS-2) encoding for the Adobe-CNS1 + # character collection + 'UniCNS-UCS2-V' # Vertical version of UniCNS-UCS2-H. + ] + +# the Identity encodings simply dump out all character +# in the font in the order they were defined. +allowedEncodings = (['Identity-H', 'Identity-V'] + + encodings_chs + + encodings_cht + + encodings_jpn + + encodings_kor + ) + +defaultUnicodeEncodings = { + #we ddefine a default Unicode encoding for each face name; + #this should be the most commonly used horizontal unicode encoding; + #also define a 3-letter language code. + 'HeiseiMin-W3': ('jpn','UniJIS-UCS2-H'), + 'HeiseiKakuGo-W5': ('jpn','UniJIS-UCS2-H'), + 'STSong-Light': ('chs', 'UniGB-UCS2-H'), + 'MSung-Light': ('cht', 'UniGB-UCS2-H'), + #'MHei-Medium': ('cht', 'UniGB-UCS2-H'), + 'HYSMyeongJo-Medium': ('kor', 'UniKS-UCS2-H'), + 'HYGothic-Medium': ('kor','UniKS-UCS2-H'), + } + +typeFaces_chs = ['STSong-Light'] # to do +typeFaces_cht = ['MSung-Light', 'MHei-Medium'] # to do +typeFaces_jpn = ['HeiseiMin-W3', 'HeiseiKakuGo-W5'] +typeFaces_kor = ['HYSMyeongJo-Medium','HYGothic-Medium'] + + +#declare separately those used for unicode +unicode_encodings = [enc for enc in allowedEncodings if 'UCS2' in enc] + + +CIDFontInfo = {} +#statically describe the fonts in Adobe's Japanese Language Packs +CIDFontInfo['HeiseiMin-W3'] = { + 'Type':'/Font', + 'Subtype':'/Type0', + 'Name': '/%(internalName)s' , #<-- the internal name + 'BaseFont': '/HeiseiMin-W3', + 'Encoding': '/%(encodings)s', + + #there could be several descendant fonts if it is an old-style + #type 0 compound font. For CID fonts there is just one. + 'DescendantFonts': [{ + 'Type':'/Font', + 'Subtype':'/CIDFontType0', + 'BaseFont':'/HeiseiMin-W3', + 'FontDescriptor': { + 'Type': '/FontDescriptor', + 'Ascent': 723, + 'CapHeight': 709, + 'Descent': -241, + 'Flags': 6, + 'FontBBox': (-123, -257, 1001, 910), + 'FontName': '/HeiseiMin-W3', + 'ItalicAngle': 0, + 'StemV': 69, + 'XHeight': 450#, +# 'Style': {'Panose': '<010502020400000000000000>'} + }, + 'CIDSystemInfo': { + 'Registry': '(Adobe)', + 'Ordering': '(Japan1)', + 'Supplement': 2 + }, + #default width is 1000 em units + 'DW': 1000, + #widths of any which are not the default. + 'W': [1, [250, 333, 408, 500], + 5, [500, 833, 778, 180, 333], + 10, [333, 500, 564, 250, 333, 250, 278, 500], + 18, 26, 500, 27, 28, 278, 29, 31, 564, + 32, [444, 921, 722, 667], + 36, [667, 722, 611, 556, 722], + 41, [722, 333, 389, 722, 611, 889, 722], + 48, [722, 556, 722, 667, 556, 611, 722], + 55, [722, 944, 722], + 58, [722, 611, 333, 500, 333, 469, 500, 333, + 444, 500, 444, 500, 444, 333, 500], + 73, [500, 278], + 75, [278, 500, 278, 778, 500], 80, 82, 500, + 83, [333, 389, 278, 500], + 87, [500, 722, 500], + 90, [500, 444, 480, 200, 480, 333], + 97, [278], 99, [200], 101, [333, 500], 103, [500, 167], + 107, [500], 109, [500, 333], 111, [333, 556], + 113, [556, 500], 117, [250], 119, [350, 333, 444], + 123, [500], 126, [444, 333], 128, 137, 333, + 138, [1000, 889, 276, 611, 722, 889, 310, 667, 278], + 147, [278, 500, 722, 500, 564, 760, 564, 760], + 157, 158, 300, 159, [500, 300, 750], 162, 163, 750, + 164, 169, 722, 170, [667, 611], 172, 174, 611, 175, + 178, 333, 179, 185, 722, 187, 191, 722, 192, + [556, 444], 194, 203, 444, 204, 207, 278, 208, + 214, 500, 216, 222, 500, + 223, [556, 722, 611, 500, 389, 980, 444], + 231, [500], 323, [500], 325, [500], + 327, 389, 500] +## 'W': ( +## # starting at character ID 1, next n characters have the widths given. +## 1, (277,305,500,668,668,906,727,305,445,445,508,668,305,379,305,539), +## # all Characters from ID 17 to 26 are 668 em units wide +## 17, 26, 668, +## 27, (305, 305, 668, 668, 668, 566, 871, 727, 637, 652, 699, 574, 555, +## 676, 687, 242, 492, 664, 582, 789, 707, 734, 582, 734, 605, 605, +## 641, 668, 727, 945, 609, 609, 574, 445, 668, 445, 668, 668, 590, +## 555, 609, 547, 602, 574, 391, 609, 582, 234, 277, 539, 234, 895, +## 582, 605, 602, 602, 387, 508, 441, 582, 562, 781, 531, 570, 555, +## 449, 246, 449, 668), +## # these must be half width katakana and the like. +## 231, 632, 500 +## ) + }]# end list of descendant fonts + } #end HeiseiMin-W3 + +CIDFontInfo['HeiseiKakuGo-W5'] = {'Type':'/Font', + 'Subtype':'/Type0', + 'Name': '/%(internalName)s', #<-- the internal name + 'BaseFont': '/HeiseiKakuGo-W5', + 'Encoding': '/%(encodings)s', + 'DescendantFonts': [{'Type':'/Font', + 'Subtype':'/CIDFontType0', + 'BaseFont':'/HeiseiKakuGo-W5', + 'FontDescriptor': { + 'Type': '/FontDescriptor', + 'Ascent': 752, + 'CapHeight': 737, + 'Descent': -221, + 'Flags': 4, + 'FontBBox': [-92, -250, 1010, 922], + 'FontName': '/HeiseKakuGo-W5', + 'ItalicAngle': 0, + 'StemH': 0, + 'StemV': 114, + 'XHeight': 553, +## 'Style': {'Panose': '<0801020b0600000000000000>'} + }, + 'CIDSystemInfo': { + 'Registry': '(Adobe)', + 'Ordering': '(Japan1)', + 'Supplement': 2 + }, + 'DW': 1000, + 'W': ( + 1, (277,305,500,668,668,906,727,305,445,445,508,668,305,379,305,539), + 17, 26, 668, + 27, (305, 305, 668, 668, 668, 566, 871, 727, 637, 652, 699, 574, 555, + 676, 687, 242, 492, 664, 582, 789, 707, 734, 582, 734, 605, 605, + 641, 668, 727, 945, 609, 609, 574, 445, 668, 445, 668, 668, 590, + 555, 609, 547, 602, 574, 391, 609, 582, 234, 277, 539, 234, 895, + 582, 605, 602, 602, 387, 508, 441, 582, 562, 781, 531, 570, 555, + 449, 246, 449, 668), + 231, 632, 500 + ) + }] # end descendant fonts + } + +CIDFontInfo['HYGothic-Medium'] = {'Type':'/Font', + 'Subtype':'/Type0', + 'Name': '/%(internalName)s', #<-- the internal name + 'BaseFont': '/' + 'HYGothic-Medium', + 'Encoding': '/%(encodings)s', + 'DescendantFonts': [{'Type':'/Font', + 'Subtype':'/CIDFontType0', + 'BaseFont':'/'+'HYGothic-Medium', + 'FontDescriptor': { + 'Type': '/FontDescriptor', + 'Ascent': 752, + 'AvgWidth': -271, + 'CapHeight': 737, + 'Descent': -142, + 'Flags': 6, + 'FontBBox': [-6, -145, 1003, 880], + 'FontName': '/'+'HYSMyeongJo-Medium', + 'ItalicAngle': 0, + 'Leading': 148, + 'MaxWidth': 1000, + 'MissingWidth': 500, + 'StemH': 0, + 'StemV': 58, + 'XHeight': 553 + }, + 'CIDSystemInfo': { + 'Registry': '(Adobe)', + 'Ordering': '(Korea1)', + 'Supplement': 1 + }, + 'DW': 1000, + 'W': (1, 94, 500) + }] # end descendant fonts + } + +CIDFontInfo['HYSMyeongJo-Medium'] = {'Type':'/Font', + 'Subtype':'/Type0', + 'Name': '/%(internalName)s', #<-- the internal name + 'BaseFont': '/' + 'HYSMyeongJo-Medium', + 'Encoding': '/%(encodings)s', + 'DescendantFonts': [{'Type':'/Font', + 'Subtype':'/CIDFontType2', + 'BaseFont':'/'+'HYSMyeongJo-Medium', + 'FontDescriptor': { + 'Type': '/FontDescriptor', + 'Ascent': 752, + 'AvgWidth': 500, + 'CapHeight': 737, + 'Descent': -271, + 'Flags': 6, + 'FontBBox': [0, -148, 1001, 880], + 'FontName': '/'+'HYSMyeongJo-Medium', + 'ItalicAngle': 0, + 'Leading': 148, + 'MaxWidth': 1000, + 'MissingWidth': 500, + 'StemH': 91, + 'StemV': 58, + 'XHeight': 553 + }, + 'CIDSystemInfo': { + 'Registry': '(Adobe)', + 'Ordering': '(Korea1)', + 'Supplement': 1 + }, + 'DW': 1000, + 'W': [1, [333, 416], + 3, [416, 833, 625, 916, 833, 250, 500], + 10, 11, 500, + 12, [833, 291, 833, 291, 375, 625], + 18, 26, 625, 27, 28, 333, 29, 30, 833, + 31, [916, 500, 1000, 791, 708], + 36, [708, 750, 708, 666, 750, 791, 375, + 500, 791, 666, 916, 791, 750, 666, + 750, 708, 666, 791], + 54, [791, 750, 1000, 708], + 58, [708, 666, 500, 375, 500], + 63, 64, 500, + 65, [333, 541, 583, 541, 583], + 70, [583, 375, 583], + 73, [583, 291, 333, 583, 291, 875, 583], + 80, 82, 583, + 83, [458, 541, 375, 583], + 87, [583, 833, 625], + 90, [625, 500, 583], 93, 94, 583, + 95, [750] + ] + }] # end descendant fonts + } + +#WARNING - not checked, just copied Korean to get some output + +CIDFontInfo['STSong-Light'] = {'Type':'/Font', + 'Subtype':'/Type0', + 'Name': '/%(internalName)s', #<-- the internal name + 'BaseFont': '/' + 'STSong-Light', + 'Encoding': '/%(encodings)s', + 'DescendantFonts': [{'Type':'/Font', + 'Subtype':'/CIDFontType0', + 'BaseFont':'/'+'STSong-Light', + 'FontDescriptor': { + 'Type': '/FontDescriptor', + 'Ascent': 752, + 'CapHeight': 737, + 'Descent': -271, + 'Flags': 6, + 'FontBBox': [-25, -254, 1000, 880], + 'FontName': '/'+'STSongStd-Light', + 'ItalicAngle': 0, + 'Leading': 148, + 'MaxWidth': 1000, + 'MissingWidth': 500, + 'StemH': 91, + 'StemV': 58, + 'XHeight': 553 + }, + 'CIDSystemInfo': { + 'Registry': '(Adobe)', + 'Ordering': '(GB1)', + 'Supplement': 0 + }, + 'DW': 1000, + 'W': [1, [207, 270, 342, 467, 462, 797, 710, 239, 374], + 10, [374, 423, 605, 238, 375, 238, 334, 462], + 18, 26, 462, 27, 28, 238, 29, 31, 605, + 32, [344, 748, 684, 560, 695, 739, 563, 511, 729, + 793, 318, 312, 666, 526, 896, 758, 772, 544, + 772, 628, 465, 607, 753, 711, 972, 647, 620, + 607, 374, 333, 374, 606, 500, 239, 417, 503, + 427, 529, 415, 264, 444, 518, 241, 230, 495, + 228, 793, 527, 524], + 81, [524, 504, 338, 336, 277, 517, 450, 652, 466, + 452, 407, 370, 258, 370, 605] + ] + }] # end descendant fonts + } +CIDFontInfo['MSung-Light'] = {'Type':'/Font', + 'Subtype':'/Type0', + 'Name': '/%(internalName)s', #<-- the internal name + 'BaseFont': '/' + 'MSung-Light', + 'Encoding': '/%(encodings)s', + 'DescendantFonts': [{'Type':'/Font', + 'Subtype':'/CIDFontType0', + 'BaseFont':'/'+'MSung-Light', + 'FontDescriptor': { + 'Type': '/FontDescriptor', + 'Ascent': 752, + 'CapHeight': 737, + 'Descent': -271, + 'Flags': 6, + 'FontBBox': [-160, -249, 1015, 888], + 'FontName': '/'+'MSung-Light', + 'ItalicAngle': 0, + 'Leading': 148, + 'MaxWidth': 1000, + 'MissingWidth': 500, + 'StemH': 45, + 'StemV': 58, + 'XHeight': 553 + }, + 'CIDSystemInfo': { + 'Registry': '(Adobe)', + 'Ordering': '(CNS1)', + 'Supplement': 1 + }, + 'DW': 1000, + 'W': [1, 2, 250, 3, [408, 668, 490, 875, 698, 250, 240], + 10, [240, 417, 667, 250, 313, 250, 520, 500], + 18, 26, 500, 27, 28, 250, 29, 31, 667, + 32, [396, 921, 677, 615, 719, 760, 625, 552, 771, + 802, 354], + 43, [354, 781, 604, 927, 750, 823, 563, 823, 729, + 542, 698, 771, 729, 948, 771, 677, 635, 344, + 520, 344, 469, 500, 250, 469, 521, 427, 521, + 438, 271, 469, 531, 250], + 75, [250, 458, 240, 802, 531, 500, 521], + 82, [521, 365, 333, 292, 521, 458, 677, 479, 458, + 427, 480, 496, 480, 667]] + + }] # end descendant fonts + } + + +#this data was derived from the above width information and removes all dependency on CMAP files as long as we only use the unicode fonts. +widthsByUnichar = {} +widthsByUnichar["MSung-Light"] = {u' ': 250, u'$': 490, u'(': 240, u',': 250, u'0': 500, u'4': 500, u'8': 500, u'<': 667, u'@': 921, u'D': 760, u'H': 802, u'L': 604, u'P': 563, u'T': 698, u'X': 771, u'\\': 520, u'`': 250, u'd': 521, u'h': 531, u'l': 240, u'p': 521, u't': 292, u'x': 479, u'|': 496, u'#': 668, u"'": 250, u'+': 667, u'/': 520, u'3': 500, u'7': 500, u';': 250, u'?': 396, u'C': 719, u'G': 771, u'K': 781, u'O': 823, u'S': 542, u'W': 948, u'[': 344, u'_': 500, u'c': 427, u'g': 469, u'k': 458, u'o': 500, u's': 333, u'w': 677, u'{': 480, u'"': 408, u'&': 698, u'*': 417, u'.': 250, u'2': 500, u'6': 500, u':': 250, u'>': 667, u'B': 615, u'F': 552, u'J': 354, u'N': 750, u'R': 729, u'V': 729, u'Z': 635, u'^': 469, u'b': 521, u'f': 271, u'j': 250, u'n': 531, u'r': 365, u'v': 458, u'z': 427, u'~': 667, u'!': 250, u'%': 875, u')': 240, u'-': 313, u'1': 500, u'5': 500, u'9': 500, u'=': 667, u'A': 677, u'E': 625, u'I': 354, u'M': 927, u'Q': 823, u'U': 771, u'Y': 677, u']': 344, u'a': 469, u'e': 438, u'i': 250, u'm': 802, u'q': 521, u'u': 521, u'y': 458, u'}': 480} +widthsByUnichar["HeiseiKakuGo-W5"] = {u'\uff81': 500, u'\uff85': 500, u'\uff89': 500, u'\uff8d': 500, u'\uff91': 500, u'\uff95': 500, u'\uff99': 500, u'\uff9d': 500, u' ': 277, u'$': 668, u'(': 445, u',': 305, u'0': 668, u'\u0332': 668, u'4': 668, u'8': 668, u'<': 668, u'@': 871, u'D': 699, u'H': 687, u'L': 582, u'P': 582, u'T': 641, u'X': 609, u'`': 590, u'\uff62': 500, u'd': 602, u'\uff66': 500, u'h': 582, u'\uff6a': 500, u'l': 234, u'\uff6e': 500, u'p': 602, u'\uff72': 500, u't': 441, u'\uff76': 500, u'x': 531, u'\uff7a': 500, u'|': 246, u'\uff7e': 500, u'\uff82': 500, u'\uff86': 500, u'\uff8a': 500, u'\uff8e': 500, u'\uff92': 500, u'\uff96': 500, u'\uff9a': 500, u'\uff9e': 500, u'#': 668, u"'": 305, u'+': 668, u'/': 539, u'3': 668, u'7': 668, u';': 305, u'?': 566, u'C': 652, u'G': 676, u'K': 664, u'O': 734, u'S': 605, u'W': 945, u'[': 445, u'_': 668, u'\uff61': 500, u'c': 547, u'\uff65': 500, u'g': 609, u'\uff69': 500, u'k': 539, u'\uff6d': 500, u'o': 605, u'\uff71': 500, u's': 508, u'\uff75': 500, u'w': 781, u'\uff79': 500, u'{': 449, u'\uff7d': 500, u'\u0300': 590, u'\uff83': 500, u'\u2002': 500, u'\uff87': 500, u'\uff8b': 500, u'\uff8f': 500, u'\uff93': 500, u'\uff97': 500, u'\uff9b': 500, u'\uff9f': 500, u'"': 500, u'\xa5': 668, u'&': 727, u'*': 508, u'.': 305, u'2': 668, u'6': 668, u':': 305, u'>': 668, u'B': 637, u'F': 555, u'J': 492, u'N': 707, u'\u203e': 500, u'R': 605, u'V': 727, u'Z': 574, u'^': 668, u'b': 609, u'\uff64': 500, u'f': 391, u'\uff68': 500, u'j': 277, u'\uff6c': 500, u'n': 582, u'\uff70': 500, u'r': 387, u'\uff74': 500, u'v': 562, u'\uff78': 500, u'z': 555, u'\uff7c': 500, u'~': 668, u'\uff80': 500, u'\u0303': 668, u'\uff84': 500, u'\uff88': 500, u'\uff8c': 500, u'\u2011': 379, u'\uff90': 500, u'\uff94': 500, u'\uff98': 500, u'\uff9c': 500, u'!': 305, u'%': 906, u')': 445, u'-': 379, u'1': 668, u'5': 668, u'9': 668, u'=': 668, u'A': 727, u'E': 574, u'I': 242, u'M': 789, u'Q': 734, u'U': 668, u'Y': 609, u']': 445, u'a': 555, u'\uff63': 500, u'e': 574, u'\uff67': 500, u'i': 234, u'\uffe8': 500, u'\uff6b': 500, u'm': 895, u'\uff6f': 500, u'q': 602, u'\uff73': 500, u'u': 582, u'\uff77': 500, u'y': 570, u'\uff7b': 500, u'}': 449, u'\uff7f': 500} +widthsByUnichar["HYSMyeongJo-Medium"] = {u' ': 333, u'$': 625, u'(': 500, u',': 291, u'0': 625, u'4': 625, u'8': 625, u'<': 833, u'D': 750, u'H': 791, u'L': 666, u'P': 666, u'T': 791, u'X': 708, u'\\': 375, u'`': 333, u'd': 583, u'h': 583, u'l': 291, u'p': 583, u't': 375, u'x': 625, u'|': 583, u'#': 833, u"'": 250, u'+': 833, u'/': 375, u'3': 625, u'7': 625, u';': 333, u'?': 500, u'C': 708, u'G': 750, u'K': 791, u'O': 750, u'S': 666, u'[': 500, u'_': 500, u'c': 541, u'g': 583, u'k': 583, u'o': 583, u's': 541, u'w': 833, u'{': 583, u'"': 416, u'&': 833, u'*': 500, u'.': 291, u'2': 625, u'6': 625, u':': 333, u'>': 916, u'B': 708, u'F': 666, u'J': 500, u'N': 791, u'R': 708, u'V': 750, u'Z': 666, u'^': 500, u'b': 583, u'f': 375, u'j': 333, u'n': 583, u'r': 458, u'v': 583, u'z': 500, u'~': 750, u'!': 416, u'%': 916, u')': 500, u'-': 833, u'1': 625, u'5': 625, u'9': 625, u'=': 833, u'A': 791, u'E': 708, u'I': 375, u'M': 916, u'Q': 750, u'U': 791, u'Y': 708, u']': 500, u'a': 541, u'e': 583, u'i': 291, u'm': 875, u'q': 583, u'u': 583, u'y': 625, u'}': 583} +widthsByUnichar["STSong-Light"] = {u' ': 207, u'$': 462, u'(': 374, u',': 238, u'0': 462, u'4': 462, u'8': 462, u'<': 605, u'@': 748, u'D': 739, u'H': 793, u'L': 526, u'P': 544, u'T': 607, u'X': 647, u'\\': 333, u'`': 239, u'd': 529, u'h': 518, u'l': 228, u'p': 524, u't': 277, u'x': 466, u'|': 258, u'#': 467, u"'": 239, u'+': 605, u'/': 334, u'3': 462, u'7': 462, u';': 238, u'?': 344, u'C': 695, u'G': 729, u'K': 666, u'O': 772, u'S': 465, u'W': 972, u'[': 374, u'_': 500, u'c': 427, u'g': 444, u'k': 495, u'o': 524, u's': 336, u'w': 652, u'{': 370, u'"': 342, u'&': 710, u'*': 423, u'.': 238, u'2': 462, u'6': 462, u':': 238, u'>': 605, u'B': 560, u'F': 511, u'J': 312, u'N': 758, u'R': 628, u'V': 711, u'Z': 607, u'^': 606, u'b': 503, u'f': 264, u'j': 230, u'n': 527, u'r': 338, u'v': 450, u'z': 407, u'~': 605, u'!': 270, u'%': 797, u')': 374, u'-': 375, u'1': 462, u'5': 462, u'9': 462, u'=': 605, u'A': 684, u'E': 563, u'I': 318, u'M': 896, u'Q': 772, u'U': 753, u'Y': 620, u']': 374, u'a': 417, u'e': 415, u'i': 241, u'm': 793, u'q': 504, u'u': 517, u'y': 452, u'}': 370} +widthsByUnichar["HeiseiMin-W3"] = {u'\uff81': 500, u'\u0302': 333, u'\uff85': 500, u'\u0306': 333, u'\uff89': 500, u'\u030a': 333, u'\uff8d': 500, u'\uff91': 500, u'\ufb02': 556, u'\uff95': 500, u'\uff99': 500, u'\uff9d': 500, u' ': 250, u'\xa3': 500, u'\u2122': 980, u'$': 500, u'(': 333, u'\xab': 500, u',': 250, u'\xaf': 333, u'0': 500, u'\xb3': 300, u'\u0332': 500, u'4': 500, u'\xb7': 250, u'8': 500, u'\xbb': 500, u'<': 564, u'\xbf': 444, u'@': 921, u'\xc3': 722, u'\u0142': 278, u'D': 722, u'\xc7': 667, u'H': 722, u'\xcb': 611, u'L': 611, u'\xcf': 333, u'P': 556, u'\xd3': 722, u'\u0152': 889, u'T': 611, u'X': 722, u'\xdb': 722, u'\\': 278, u'\xdf': 500, u'\uff64': 500, u'`': 333, u'\xe3': 444, u'\uff62': 500, u'd': 500, u'\xe7': 444, u'\uff66': 500, u'h': 500, u'\xeb': 444, u'\uff6a': 500, u'l': 278, u'\xef': 278, u'\uff6e': 500, u'p': 500, u'\xf3': 500, u'\uff72': 500, u't': 278, u'\uff76': 500, u'x': 500, u'\xfb': 500, u'\uff7a': 500, u'|': 200, u'\xff': 500, u'\u017e': 444, u'\u0301': 333, u'\uff82': 500, u'\u0305': 500, u'\uff86': 500, u'\uff8a': 500, u'\uff8e': 500, u'\u2013': 500, u'\uff92': 500, u'\uff96': 500, u'\uff9a': 500, u'\uff9e': 500, u'#': 500, u'\xa4': 500, u"'": 180, u'\u203a': 333, u'+': 564, u'\xac': 564, u'/': 278, u'\u0131': 278, u'3': 500, u'7': 500, u'\xb8': 333, u';': 278, u'\xbc': 750, u'?': 444, u'\u0141': 611, u'\xc0': 722, u'C': 667, u'\xc4': 722, u'G': 722, u'\xc8': 611, u'K': 722, u'\xcc': 333, u'O': 722, u'\xd0': 722, u'S': 556, u'\u2022': 350, u'\xd4': 722, u'W': 944, u'\uff78': 500, u'\xd8': 722, u'[': 333, u'\xdc': 722, u'_': 500, u'\u0161': 389, u'\xe0': 444, u'c': 444, u'\uff65': 500, u'\xe4': 444, u'g': 500, u'\uff69': 500, u'\xe8': 444, u'k': 500, u'\uff6d': 500, u'\xec': 278, u'o': 500, u'\uff71': 500, u'\xf0': 500, u's': 389, u'\uff75': 500, u'\xf4': 500, u'w': 722, u'\uff79': 500, u'\xf8': 500, u'{': 480, u'\uff7e': 500, u'\u017d': 611, u'\xfc': 500, u'\u0300': 333, u'\uff83': 500, u'\u2002': 500, u'\u0304': 333, u'\uff87': 500, u'\u0308': 333, u'\uff8b': 500, u'\u030c': 333, u'\uff8f': 500, u'\uff93': 500, u'\u2012': 500, u'\uff97': 500, u'\uff9b': 500, u'\u201a': 333, u'\uff9f': 500, u'\u201e': 444, u'\xa1': 333, u'"': 408, u'\xa5': 500, u'&': 778, u'\xa9': 760, u'\u0328': 333, u'*': 500, u'\xad': 564, u'.': 250, u'\uffe8': 500, u'2': 500, u'\xb5': 500, u'6': 500, u'\xb9': 300, u':': 278, u'\xbd': 750, u'>': 564, u'\xc1': 722, u'\uff61': 500, u'B': 667, u'\xc5': 722, u'F': 556, u'\xc9': 611, u'J': 389, u'\xcd': 333, u'N': 722, u'\xd1': 722, u'\u203e': 500, u'R': 667, u'\xd5': 722, u'V': 722, u'\xd9': 722, u'Z': 611, u'\xdd': 722, u'^': 469, u'\xe1': 444, u'\u0160': 556, u'b': 500, u'\xe5': 444, u'\u2039': 333, u'f': 333, u'\xe9': 444, u'\uff68': 500, u'j': 278, u'\xed': 278, u'\uff6c': 500, u'n': 500, u'\xf1': 500, u'\uff70': 500, u'r': 333, u'\xf5': 500, u'\uff74': 500, u'v': 500, u'\xf9': 500, u'\u0178': 722, u'z': 444, u'\xfd': 500, u'\uff7c': 500, u'~': 333, u'\uff80': 500, u'\u0303': 333, u'\uff84': 500, u'\u0307': 333, u'\uff88': 500, u'\u030b': 333, u'\uff8c': 500, u'\u2011': 333, u'\uff90': 500, u'\uff94': 500, u'\uff98': 500, u'\uff9c': 500, u'\u2044': 167, u'!': 333, u'\xa2': 500, u'%': 833, u'\u0327': 333, u'\xa6': 200, u')': 333, u'\xaa': 276, u'-': 333, u'\xae': 760, u'1': 500, u'\xb2': 300, u'5': 500, u'9': 500, u'\xba': 310, u'=': 564, u'\xbe': 750, u'A': 722, u'\u01c0': 200, u'\xc2': 722, u'E': 611, u'\xc6': 889, u'I': 333, u'\xca': 611, u'M': 889, u'\xce': 333, u'Q': 722, u'\u0153': 722, u'\xd2': 722, u'U': 722, u'\xd6': 722, u'Y': 722, u'\ufb01': 556, u'\xda': 722, u']': 333, u'\xde': 556, u'a': 444, u'\uff63': 500, u'\xe2': 444, u'e': 444, u'\uff67': 500, u'\xe6': 667, u'i': 278, u'\uff7d': 500, u'\uff6b': 500, u'\xea': 444, u'm': 778, u'\uff6f': 500, u'\xee': 278, u'q': 500, u'\uff73': 500, u'\xf2': 500, u'u': 500, u'\uff77': 500, u'\xf6': 500, u'y': 500, u'\uff7b': 500, u'\xfa': 500, u'}': 480, u'\uff7f': 500, u'\xfe': 500} +widthsByUnichar["HYGothic-Medium"] = {u' ': 500, u'$': 500, u'(': 500, u',': 500, u'0': 500, u'4': 500, u'8': 500, u'<': 500, u'@': 500, u'D': 500, u'H': 500, u'L': 500, u'P': 500, u'T': 500, u'X': 500, u'\\': 500, u'`': 500, u'd': 500, u'h': 500, u'l': 500, u'p': 500, u't': 500, u'x': 500, u'|': 500, u'#': 500, u"'": 500, u'+': 500, u'/': 500, u'3': 500, u'7': 500, u';': 500, u'?': 500, u'C': 500, u'G': 500, u'K': 500, u'O': 500, u'S': 500, u'W': 500, u'[': 500, u'_': 500, u'c': 500, u'g': 500, u'k': 500, u'o': 500, u's': 500, u'w': 500, u'{': 500, u'"': 500, u'&': 500, u'*': 500, u'.': 500, u'2': 500, u'6': 500, u':': 500, u'>': 500, u'B': 500, u'F': 500, u'J': 500, u'N': 500, u'R': 500, u'V': 500, u'Z': 500, u'^': 500, u'b': 500, u'f': 500, u'j': 500, u'n': 500, u'r': 500, u'v': 500, u'z': 500, u'!': 500, u'%': 500, u')': 500, u'-': 500, u'1': 500, u'5': 500, u'9': 500, u'=': 500, u'A': 500, u'E': 500, u'I': 500, u'M': 500, u'Q': 500, u'U': 500, u'Y': 500, u']': 500, u'a': 500, u'e': 500, u'i': 500, u'm': 500, u'q': 500, u'u': 500, u'y': 500, u'}': 500} + + +#shift-jis saying 'This is Heisei-Minchou' +message1 = '\202\261\202\352\202\315\225\275\220\254\226\276\222\251\202\305\202\267\201B' +message2 = '\202\261\202\352\202\315\225\275\220\254\212p\203S\203V\203b\203N\202\305\202\267\201B' + +##def pswidths(text): +## words = text.split() +## out = [] +## for word in words: +## if word == '[': +## out.append(word) +## else: +## out.append(word + ',') +## return eval(''.join(out)) diff --git a/reportlab/pdfbase/_fontdata.py b/reportlab/pdfbase/_fontdata.py new file mode 100644 index 00000000..a26a2888 --- /dev/null +++ b/reportlab/pdfbase/_fontdata.py @@ -0,0 +1,255 @@ +#Copyright ReportLab Europe Ltd. 2000-2012 +#see license.txt for license details +#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/pdfbase/_fontdata.py +#$Header $ +__version__=''' $Id$ ''' +__doc__="""Database of font related things + + - standardFonts - tuple of the 14 standard string font names + - standardEncodings - tuple of the known standard font names + - encodings - a mapping object from standard encoding names (and minor variants) + to the encoding vectors ie the tuple of string glyph names + - widthsByFontGlyph - fontname x glyphname --> width of glyph + - widthVectorsByFont - fontName -> vector of widths + + This module defines a static, large data structure. At the request + of the Jython project, we have split this off into separate modules + as Jython cannot handle more than 64k of bytecode in the 'top level' + code of a Python module. +""" +import os, sys + +# mapping of name to width vector, starts empty until fonts are added +# e.g. widths['Courier'] = [...600,600,600,...] +widthVectorsByFont = {} +fontsByName = {} +fontsByBaseEnc = {} +# this is a list of the standard 14 font names in Acrobat Reader +standardFonts = ( + 'Courier', 'Courier-Bold', 'Courier-Oblique', 'Courier-BoldOblique', + 'Helvetica', 'Helvetica-Bold', 'Helvetica-Oblique', 'Helvetica-BoldOblique', + 'Times-Roman', 'Times-Bold', 'Times-Italic', 'Times-BoldItalic', + 'Symbol','ZapfDingbats') + +standardFontAttributes = { + #family, bold, italic defined for basic ones + 'Courier':('Courier',0,0), + 'Courier-Bold':('Courier',1,0), + 'Courier-Oblique':('Courier',0,1), + 'Courier-BoldOblique':('Courier',1,1), + + 'Helvetica':('Helvetica',0,0), + 'Helvetica-Bold':('Helvetica',1,0), + 'Helvetica-Oblique':('Helvetica',0,1), + 'Helvetica-BoldOblique':('Helvetica',1,1), + + 'Times-Roman':('Times-Roman',0,0), + 'Times-Bold':('Times-Roman',1,0), + 'Times-Italic':('Times-Roman',0,1), + 'Times-BoldItalic':('Times-Roman',1,1), + + 'Symbol':('Symbol',0,0), + 'ZapfDingbats':('ZapfDingbats',0,0) + + } + +#this maps fontnames to the equivalent filename root. +_font2fnrMapWin32 = { + 'symbol': 'sy______', + 'zapfdingbats': 'zd______', + 'helvetica': '_a______', + 'helvetica-bold': '_ab_____', + 'helvetica-boldoblique': '_abi____', + 'helvetica-oblique': '_ai_____', + 'times-bold': '_eb_____', + 'times-bolditalic': '_ebi____', + 'times-italic': '_ei_____', + 'times-roman': '_er_____', + 'courier-bold': 'cob_____', + 'courier-boldoblique': 'cobo____', + 'courier': 'com_____', + 'courier-oblique': 'coo_____', + } +if sys.platform in ('linux2',): + _font2fnrMapLinux2 ={ + 'symbol': 'Symbol', + 'zapfdingbats': 'ZapfDingbats', + 'helvetica': 'Arial', + 'helvetica-bold': 'Arial-Bold', + 'helvetica-boldoblique': 'Arial-BoldItalic', + 'helvetica-oblique': 'Arial-Italic', + 'times-bold': 'TimesNewRoman-Bold', + 'times-bolditalic':'TimesNewRoman-BoldItalic', + 'times-italic': 'TimesNewRoman-Italic', + 'times-roman': 'TimesNewRoman', + 'courier-bold': 'Courier-Bold', + 'courier-boldoblique': 'Courier-BoldOblique', + 'courier': 'Courier', + 'courier-oblique': 'Courier-Oblique', + } + _font2fnrMap = _font2fnrMapLinux2 + for k, v in _font2fnrMap.items(): + if k in _font2fnrMapWin32.keys(): + _font2fnrMapWin32[v.lower()] = _font2fnrMapWin32[k] + del k, v +else: + _font2fnrMap = _font2fnrMapWin32 + +def _findFNR(fontName): + return _font2fnrMap[fontName.lower()] + +from reportlab.rl_config import T1SearchPath +from reportlab.lib.utils import rl_isfile +def _searchT1Dirs(n,rl_isfile=rl_isfile,T1SearchPath=T1SearchPath): + assert T1SearchPath!=[], "No Type-1 font search path" + for d in T1SearchPath: + f = os.path.join(d,n) + if rl_isfile(f): return f + return None +del T1SearchPath, rl_isfile + +def findT1File(fontName,ext='.pfb'): + if sys.platform in ('linux2',) and ext=='.pfb': + try: + f = _searchT1Dirs(_findFNR(fontName)) + if f: return f + except: + pass + + try: + f = _searchT1Dirs(_font2fnrMapWin32[fontName.lower()]+ext) + if f: return f + except: + pass + + return _searchT1Dirs(_findFNR(fontName)+ext) + +# this lists the predefined font encodings - WinAnsi and MacRoman. We have +# not added MacExpert - it's possible, but would complicate life and nobody +# is asking. StandardEncoding means something special. +standardEncodings = ('WinAnsiEncoding','MacRomanEncoding','StandardEncoding','SymbolEncoding','ZapfDingbatsEncoding','PDFDocEncoding', 'MacExpertEncoding') + +#this is the global mapping of standard encodings to name vectors +class _Name2StandardEncodingMap(dict): + '''Trivial fake dictionary with some [] magic''' + _XMap = {'winansi':'WinAnsiEncoding','macroman': 'MacRomanEncoding','standard':'StandardEncoding','symbol':'SymbolEncoding', 'zapfdingbats':'ZapfDingbatsEncoding','pdfdoc':'PDFDocEncoding', 'macexpert':'MacExpertEncoding'} + def __setitem__(self,x,v): + y = x.lower() + if y[-8:]=='encoding': y = y[:-8] + y = self._XMap[y] + if y in self: raise IndexError('Encoding %s is already set' % y) + dict.__setitem__(self,y,v) + + def __getitem__(self,x): + y = x.lower() + if y[-8:]=='encoding': y = y[:-8] + y = self._XMap[y] + return dict.__getitem__(self,y) + +encodings = _Name2StandardEncodingMap() + +#due to compiled method size limits in Jython, +#we pull these in from separate modules to keep this module +#well under 64k. We might well be able to ditch many of +#these anyway now we run on Unicode. + +from reportlab.pdfbase._fontdata_enc_winansi import WinAnsiEncoding +from reportlab.pdfbase._fontdata_enc_macroman import MacRomanEncoding +from reportlab.pdfbase._fontdata_enc_standard import StandardEncoding +from reportlab.pdfbase._fontdata_enc_symbol import SymbolEncoding +from reportlab.pdfbase._fontdata_enc_zapfdingbats import ZapfDingbatsEncoding +from reportlab.pdfbase._fontdata_enc_pdfdoc import PDFDocEncoding +from reportlab.pdfbase._fontdata_enc_macexpert import MacExpertEncoding +encodings.update({ + 'WinAnsiEncoding': WinAnsiEncoding, + 'MacRomanEncoding': MacRomanEncoding, + 'StandardEncoding': StandardEncoding, + 'SymbolEncoding': SymbolEncoding, + 'ZapfDingbatsEncoding': ZapfDingbatsEncoding, + 'PDFDocEncoding': PDFDocEncoding, + 'MacExpertEncoding': MacExpertEncoding, +}) + +ascent_descent = { + 'Courier': (629, -157), + 'Courier-Bold': (626, -142), + 'Courier-BoldOblique': (626, -142), + 'Courier-Oblique': (629, -157), + 'Helvetica': (718, -207), + 'Helvetica-Bold': (718, -207), + 'Helvetica-BoldOblique': (718, -207), + 'Helvetica-Oblique': (718, -207), + 'Times-Roman': (683, -217), + 'Times-Bold': (676, -205), + 'Times-BoldItalic': (699, -205), + 'Times-Italic': (683, -205), + 'Symbol': (0, 0), + 'ZapfDingbats': (0, 0) + } + +# ditto about 64k limit - profusion of external files +import reportlab.pdfbase._fontdata_widths_courier +import reportlab.pdfbase._fontdata_widths_courierbold +import reportlab.pdfbase._fontdata_widths_courieroblique +import reportlab.pdfbase._fontdata_widths_courierboldoblique +import reportlab.pdfbase._fontdata_widths_helvetica +import reportlab.pdfbase._fontdata_widths_helveticabold +import reportlab.pdfbase._fontdata_widths_helveticaoblique +import reportlab.pdfbase._fontdata_widths_helveticaboldoblique +import reportlab.pdfbase._fontdata_widths_timesroman +import reportlab.pdfbase._fontdata_widths_timesbold +import reportlab.pdfbase._fontdata_widths_timesitalic +import reportlab.pdfbase._fontdata_widths_timesbolditalic +import reportlab.pdfbase._fontdata_widths_symbol +import reportlab.pdfbase._fontdata_widths_zapfdingbats +widthsByFontGlyph = { + 'Courier': + reportlab.pdfbase._fontdata_widths_courier.widths, + 'Courier-Bold': + reportlab.pdfbase._fontdata_widths_courierbold.widths, + 'Courier-Oblique': + reportlab.pdfbase._fontdata_widths_courieroblique.widths, + 'Courier-BoldOblique': + reportlab.pdfbase._fontdata_widths_courierboldoblique.widths, + 'Helvetica': + reportlab.pdfbase._fontdata_widths_helvetica.widths, + 'Helvetica-Bold': + reportlab.pdfbase._fontdata_widths_helveticabold.widths, + 'Helvetica-Oblique': + reportlab.pdfbase._fontdata_widths_helveticaoblique.widths, + 'Helvetica-BoldOblique': + reportlab.pdfbase._fontdata_widths_helveticaboldoblique.widths, + 'Times-Roman': + reportlab.pdfbase._fontdata_widths_timesroman.widths, + 'Times-Bold': + reportlab.pdfbase._fontdata_widths_timesbold.widths, + 'Times-Italic': + reportlab.pdfbase._fontdata_widths_timesitalic.widths, + 'Times-BoldItalic': + reportlab.pdfbase._fontdata_widths_timesbolditalic.widths, + 'Symbol': + reportlab.pdfbase._fontdata_widths_symbol.widths, + 'ZapfDingbats': + reportlab.pdfbase._fontdata_widths_zapfdingbats.widths, +} + + +#preserve the initial values here +def _reset( + initial_dicts=dict( + ascent_descent=ascent_descent.copy(), + fontsByBaseEnc=fontsByBaseEnc.copy(), + fontsByName=fontsByName.copy(), + standardFontAttributes=standardFontAttributes.copy(), + widthVectorsByFont=widthVectorsByFont.copy(), + widthsByFontGlyph=widthsByFontGlyph.copy(), + ) + ): + for k,v in initial_dicts.items(): + d=globals()[k] + d.clear() + d.update(v) + +from reportlab.rl_config import register_reset +register_reset(_reset) +del register_reset diff --git a/reportlab/pdfbase/_fontdata_enc_macexpert.py b/reportlab/pdfbase/_fontdata_enc_macexpert.py new file mode 100644 index 00000000..f0372db7 --- /dev/null +++ b/reportlab/pdfbase/_fontdata_enc_macexpert.py @@ -0,0 +1,28 @@ +MacExpertEncoding = (None, None, None, None, None, None, None, None, None, None, None, None, None, None, + None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, + 'space', 'exclamsmall', 'Hungarumlautsmall', 'centoldstyle', 'dollaroldstyle', 'dollarsuperior', 'ampersandsmall', + 'Acutesmall', 'parenleftsuperior', 'parenrightsuperior', 'twodotenleader', 'onedotenleader', 'comma', 'hyphen', + 'period', 'fraction', 'zerooldstyle', 'oneoldstyle', 'twooldstyle', 'threeoldstyle', 'fouroldstyle', + 'fiveoldstyle', 'sixoldstyle', 'sevenoldstyle', 'eightoldstyle', 'nineoldstyle', 'colon', 'semicolon', None, + 'threequartersemdash', None, 'questionsmall', None, None, None, None, 'Ethsmall', None, None, 'onequarter', + 'onehalf', 'threequarters', 'oneeighth', 'threeeighths', 'fiveeighths', 'seveneighths', 'onethird', 'twothirds', + None, None, None, None, None, None, 'ff', 'fi', 'fl', 'ffi', 'ffl', 'parenleftinferior', None, + 'parenrightinferior', 'Circumflexsmall', 'hypheninferior', 'Gravesmall', 'Asmall', 'Bsmall', 'Csmall', 'Dsmall', + 'Esmall', 'Fsmall', 'Gsmall', 'Hsmall', 'Ismall', 'Jsmall', 'Ksmall', 'Lsmall', 'Msmall', 'Nsmall', 'Osmall', + 'Psmall', 'Qsmall', 'Rsmall', 'Ssmall', 'Tsmall', 'Usmall', 'Vsmall', 'Wsmall', 'Xsmall', 'Ysmall', 'Zsmall', + 'colonmonetary', 'onefitted', 'rupiah', 'Tildesmall', None, None, 'asuperior', 'centsuperior', None, None, None, + None, 'Aacutesmall', 'Agravesmall', 'Acircumflexsmall', 'Adieresissmall', 'Atildesmall', 'Aringsmall', + 'Ccedillasmall', 'Eacutesmall', 'Egravesmall', 'Ecircumflexsmall', 'Edieresissmall', 'Iacutesmall', 'Igravesmall', + 'Icircumflexsmall', 'Idieresissmall', 'Ntildesmall', 'Oacutesmall', 'Ogravesmall', 'Ocircumflexsmall', + 'Odieresissmall', 'Otildesmall', 'Uacutesmall', 'Ugravesmall', 'Ucircumflexsmall', 'Udieresissmall', None, + 'eightsuperior', 'fourinferior', 'threeinferior', 'sixinferior', 'eightinferior', 'seveninferior', 'Scaronsmall', + None, 'centinferior', 'twoinferior', None, 'Dieresissmall', None, 'Caronsmall', 'osuperior', 'fiveinferior', None, + 'commainferior', 'periodinferior', 'Yacutesmall', None, 'dollarinferior', None, None, 'Thornsmall', None, + 'nineinferior', 'zeroinferior', 'Zcaronsmall', 'AEsmall', 'Oslashsmall', 'questiondownsmall', 'oneinferior', + 'Lslashsmall', None, None, None, None, None, None, 'Cedillasmall', None, None, None, None, None, 'OEsmall', + 'figuredash', 'hyphensuperior', None, None, None, None, 'exclamdownsmall', None, 'Ydieresissmall', None, + 'onesuperior', 'twosuperior', 'threesuperior', 'foursuperior', 'fivesuperior', 'sixsuperior', 'sevensuperior', + 'ninesuperior', 'zerosuperior', None, 'esuperior', 'rsuperior', 'tsuperior', None, None, 'isuperior', 'ssuperior', + 'dsuperior', None, None, None, None, None, 'lsuperior', 'Ogoneksmall', 'Brevesmall', 'Macronsmall', 'bsuperior', + 'nsuperior', 'msuperior', 'commasuperior', 'periodsuperior', 'Dotaccentsmall', 'Ringsmall', None, None, None, None) + diff --git a/reportlab/pdfbase/_fontdata_enc_macroman.py b/reportlab/pdfbase/_fontdata_enc_macroman.py new file mode 100644 index 00000000..b4067124 --- /dev/null +++ b/reportlab/pdfbase/_fontdata_enc_macroman.py @@ -0,0 +1,35 @@ +MacRomanEncoding = ( + None, None, None, None, None, None, None, None, None, None, None, None, + None, None, None, None, None, None, None, None, None, None, None, None, + None, None, None, None, None, None, None, None, 'space', 'exclam', + 'quotedbl', 'numbersign', 'dollar', 'percent', 'ampersand', + 'quotesingle', 'parenleft', 'parenright', 'asterisk', 'plus', 'comma', + 'hyphen', 'period', 'slash', 'zero', 'one', 'two', 'three', 'four', + 'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon', 'less', + 'equal', 'greater', 'question', 'at', 'A', 'B', 'C', 'D', 'E', 'F', + 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', + 'U', 'V', 'W', 'X', 'Y', 'Z', 'bracketleft', 'backslash', 'bracketright', + 'asciicircum', 'underscore', 'grave', 'a', 'b', 'c', 'd', 'e', 'f', + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', + 'u', 'v', 'w', 'x', 'y', 'z', 'braceleft', 'bar', 'braceright', + 'asciitilde', None, 'Adieresis', 'Aring', 'Ccedilla', 'Eacute', + 'Ntilde', 'Odieresis', 'Udieresis', 'aacute', 'agrave', 'acircumflex', + 'adieresis', 'atilde', 'aring', 'ccedilla', 'eacute', 'egrave', + 'ecircumflex', 'edieresis', 'iacute', 'igrave', 'icircumflex', + 'idieresis', 'ntilde', 'oacute', 'ograve', 'ocircumflex', 'odieresis', + 'otilde', 'uacute', 'ugrave', 'ucircumflex', 'udieresis', 'dagger', + 'degree', 'cent', 'sterling', 'section', 'bullet', 'paragraph', + 'germandbls', 'registered', 'copyright', 'trademark', 'acute', + 'dieresis', None, 'AE', 'Oslash', None, 'plusminus', None, None, 'yen', + 'mu', None, None, None, None, None, 'ordfeminine', 'ordmasculine', None, + 'ae', 'oslash', 'questiondown', 'exclamdown', 'logicalnot', None, 'florin', + None, None, 'guillemotleft', 'guillemotright', 'ellipsis', 'space', 'Agrave', + 'Atilde', 'Otilde', 'OE', 'oe', 'endash', 'emdash', 'quotedblleft', + 'quotedblright', 'quoteleft', 'quoteright', 'divide', None, 'ydieresis', + 'Ydieresis', 'fraction', 'currency', 'guilsinglleft', 'guilsinglright', + 'fi', 'fl', 'daggerdbl', 'periodcentered', 'quotesinglbase', + 'quotedblbase', 'perthousand', 'Acircumflex', 'Ecircumflex', 'Aacute', + 'Edieresis', 'Egrave', 'Iacute', 'Icircumflex', 'Idieresis', 'Igrave', + 'Oacute', 'Ocircumflex', None, 'Ograve', 'Uacute', 'Ucircumflex', + 'Ugrave', 'dotlessi', 'circumflex', 'tilde', 'macron', 'breve', + 'dotaccent', 'ring', 'cedilla', 'hungarumlaut', 'ogonek', 'caron') diff --git a/reportlab/pdfbase/_fontdata_enc_pdfdoc.py b/reportlab/pdfbase/_fontdata_enc_pdfdoc.py new file mode 100644 index 00000000..39ccf5ce --- /dev/null +++ b/reportlab/pdfbase/_fontdata_enc_pdfdoc.py @@ -0,0 +1,22 @@ +PDFDocEncoding = (None, None,None,None,None,None,None,None,None,None,None,None,None,None,None,None,None,None,None, + None,None,None,None,None,"breve","caron","circumflex", + "dotaccent","hungarumlaut","ogonek","ring","tilde","space","exclam","quotedbl","numbersign","dollar","percent", + "ampersand","quotesingle","parenleft","parenright","asterisk","plus","comma","hyphen","period","slash","zero", + "one","two","three","four","five","six","seven","eight","nine","colon","semicolon","less","equal","greater", + "question","at","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X", + "Y","Z","bracketleft","backslash","bracketright","asciicircum","underscore","grave","a","b","c","d","e","f","g", + "h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","braceleft","bar","braceright", + "asciitilde",None,"bullet","dagger","daggerdbl","ellipsis","emdash","endash","florin","fraction","guilsinglleft", + "guilsinglright","minus","perthousand","quotedblbase","quotedblleft","quotedblright","quoteleft","quoteright", + "quotesinglbase","trademark","fi","fl","Lslash","OE","Scaron","Ydieresis","Zcaron","dotlessi","lslash","oe", + "scaron","zcaron",None,"Euro","exclamdown","cent","sterling","currency","yen","brokenbar","section","dieresis", + "copyright","ordfeminine","guillemotleft","logicalnot",None,"registered","macron","degree","plusminus","twosuperior", + "threesuperior","acute","mu","paragraph","periodcentered","cedilla","onesuperior","ordmasculine","guillemotright", + "onequarter","onehalf","threequarters","questiondown","Agrave","Aacute","Acircumflex","Atilde","Adieresis","Aring", + "AE","Ccedilla","Egrave","Eacute","Ecircumflex","Edieresis","Igrave","Iacute","Icircumflex","Idieresis","Eth", + "Ntilde","Ograve","Oacute","Ocircumflex","Otilde","Odieresis","multiply","Oslash","Ugrave","Uacute","Ucircumflex", + "Udieresis","Yacute","Thorn","germandbls","agrave","aacute","acircumflex","atilde","adieresis","aring","ae", + "ccedilla","egrave","eacute","ecircumflex","edieresis","igrave","iacute","icircumflex","idieresis","eth","ntilde", + "ograve","oacute","ocircumflex","otilde","odieresis","divide","oslash","ugrave","uacute","ucircumflex","udieresis", + "yacute","thorn","ydieresis") + diff --git a/reportlab/pdfbase/_fontdata_enc_standard.py b/reportlab/pdfbase/_fontdata_enc_standard.py new file mode 100644 index 00000000..e17aa680 --- /dev/null +++ b/reportlab/pdfbase/_fontdata_enc_standard.py @@ -0,0 +1,15 @@ +StandardEncoding =(None,None,None,None,None,None,None,None,None,None,None,None,None,None,None,None,None,None,None,None,None,None,None,None,None,None,None,None,None,None,None,None,"space","exclam", + "quotedbl","numbersign","dollar","percent","ampersand","quoteright","parenleft","parenright","asterisk","plus", + "comma","hyphen","period","slash","zero","one","two","three","four","five","six","seven","eight","nine","colon", + "semicolon","less","equal","greater","question","at","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O", + "P","Q","R","S","T","U","V","W","X","Y","Z","bracketleft","backslash","bracketright","asciicircum","underscore", + "quoteleft","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y", + "z","braceleft","bar","braceright","asciitilde",None,None,None,None,None,None,None,None,None,None,None,None,None,None,None,None,None,None,None,None,None,None,None,None,None,None,None,None,None,None,None, + None,None,None,"exclamdown","cent","sterling","fraction","yen","florin","section","currency","quotesingle","quotedblleft", + "guillemotleft","guilsinglleft","guilsinglright","fi","fl",None,"endash","dagger","daggerdbl","periodcentered",None, + "paragraph","bullet","quotesinglbase","quotedblbase","quotedblright","guillemotright","ellipsis","perthousand", + None,"questiondown",None,"grave","acute","circumflex","tilde","macron","breve","dotaccent","dieresis",None,"ring", + "cedilla",None,"hungarumlaut","ogonek","caron","emdash",None,None,None,None,None,None,None,None,None,None,None,None,None,None,None,None,"AE",None,"ordfeminine", + None,None,None,None,"Lslash","Oslash","OE","ordmasculine",None,None,None,None,None,"ae",None,None,None,"dotlessi",None,None,"lslash","oslash", + "oe","germandbls",None,None,None,None) + diff --git a/reportlab/pdfbase/_fontdata_enc_symbol.py b/reportlab/pdfbase/_fontdata_enc_symbol.py new file mode 100644 index 00000000..cc399bbe --- /dev/null +++ b/reportlab/pdfbase/_fontdata_enc_symbol.py @@ -0,0 +1,30 @@ +SymbolEncoding = ( + None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, + None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, 'space', + 'exclam', 'universal', 'numbersign', 'existential', 'percent', 'ampersand', 'suchthat', + 'parenleft', 'parenright', 'asteriskmath', 'plus', 'comma', 'minus', 'period', 'slash', 'zero', + 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon', + 'less', 'equal', 'greater', 'question', 'congruent', 'Alpha', 'Beta', 'Chi', 'Delta', 'Epsilon', + 'Phi', 'Gamma', 'Eta', 'Iota', 'theta1', 'Kappa', 'Lambda', 'Mu', 'Nu', 'Omicron', 'Pi', 'Theta', + 'Rho', 'Sigma', 'Tau', 'Upsilon', 'sigma1', 'Omega', 'Xi', 'Psi', 'Zeta', 'bracketleft', + 'therefore', 'bracketright', 'perpendicular', 'underscore', 'radicalex', 'alpha', 'beta', 'chi', + 'delta', 'epsilon', 'phi', 'gamma', 'eta', 'iota', 'phi1', 'kappa', 'lambda', 'mu', 'nu', + 'omicron', 'pi', 'theta', 'rho', 'sigma', 'tau', 'upsilon', 'omega1', 'omega', 'xi', 'psi', 'zeta', + 'braceleft', 'bar', 'braceright', 'similar', None, None, None, None, None, None, None, None, None, + None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, + None, None, None, None, None, None, None, None, 'Euro', 'Upsilon1', 'minute', 'lessequal', + 'fraction', 'infinity', 'florin', 'club', 'diamond', 'heart', 'spade', 'arrowboth', 'arrowleft', + 'arrowup', 'arrowright', 'arrowdown', 'degree', 'plusminus', 'second', 'greaterequal', 'multiply', + 'proportional', 'partialdiff', 'bullet', 'divide', 'notequal', 'equivalence', 'approxequal', + 'ellipsis', 'arrowvertex', 'arrowhorizex', 'carriagereturn', 'aleph', 'Ifraktur', 'Rfraktur', + 'weierstrass', 'circlemultiply', 'circleplus', 'emptyset', 'intersection', 'union', + 'propersuperset', 'reflexsuperset', 'notsubset', 'propersubset', 'reflexsubset', 'element', + 'notelement', 'angle', 'gradient', 'registerserif', 'copyrightserif', 'trademarkserif', 'product', + 'radical', 'dotmath', 'logicalnot', 'logicaland', 'logicalor', 'arrowdblboth', 'arrowdblleft', + 'arrowdblup', 'arrowdblright', 'arrowdbldown', 'lozenge', 'angleleft', 'registersans', + 'copyrightsans', 'trademarksans', 'summation', 'parenlefttp', 'parenleftex', 'parenleftbt', + 'bracketlefttp', 'bracketleftex', 'bracketleftbt', 'bracelefttp', 'braceleftmid', 'braceleftbt', + 'braceex', None, 'angleright', 'integral', 'integraltp', 'integralex', 'integralbt', + 'parenrighttp', 'parenrightex', 'parenrightbt', 'bracketrighttp', 'bracketrightex', + 'bracketrightbt', 'bracerighttp', 'bracerightmid', 'bracerightbt', None) + diff --git a/reportlab/pdfbase/_fontdata_enc_winansi.py b/reportlab/pdfbase/_fontdata_enc_winansi.py new file mode 100644 index 00000000..8cf18ba8 --- /dev/null +++ b/reportlab/pdfbase/_fontdata_enc_winansi.py @@ -0,0 +1,37 @@ +WinAnsiEncoding = ( + None, None, None, None, None, None, None, None, None, None, None, None, + None, None, None, None, None, None, None, None, None, None, None, None, + None, None, None, None, None, None, None, None, 'space', 'exclam', + 'quotedbl', 'numbersign', 'dollar', 'percent', 'ampersand', + 'quotesingle', 'parenleft', 'parenright', 'asterisk', 'plus', 'comma', + 'hyphen', 'period', 'slash', 'zero', 'one', 'two', 'three', 'four', + 'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon', 'less', + 'equal', 'greater', 'question', 'at', 'A', 'B', 'C', 'D', 'E', 'F', + 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', + 'U', 'V', 'W', 'X', 'Y', 'Z', 'bracketleft', 'backslash', 'bracketright', + 'asciicircum', 'underscore', 'grave', 'a', 'b', 'c', 'd', 'e', 'f', + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', + 'u', 'v', 'w', 'x', 'y', 'z', 'braceleft', 'bar', 'braceright', + 'asciitilde', 'bullet', 'Euro', 'bullet', 'quotesinglbase', 'florin', + 'quotedblbase', 'ellipsis', 'dagger', 'daggerdbl', 'circumflex', + 'perthousand', 'Scaron', 'guilsinglleft', 'OE', 'bullet', 'Zcaron', + 'bullet', 'bullet', 'quoteleft', 'quoteright', 'quotedblleft', + 'quotedblright', 'bullet', 'endash', 'emdash', 'tilde', 'trademark', + 'scaron', 'guilsinglright', 'oe', 'bullet', 'zcaron', 'Ydieresis', + 'space', 'exclamdown', 'cent', 'sterling', 'currency', 'yen', 'brokenbar', + 'section', 'dieresis', 'copyright', 'ordfeminine', 'guillemotleft', + 'logicalnot', 'hyphen', 'registered', 'macron', 'degree', 'plusminus', + 'twosuperior', 'threesuperior', 'acute', 'mu', 'paragraph', 'periodcentered', + 'cedilla', 'onesuperior', 'ordmasculine', 'guillemotright', 'onequarter', + 'onehalf', 'threequarters', 'questiondown', 'Agrave', 'Aacute', + 'Acircumflex', 'Atilde', 'Adieresis', 'Aring', 'AE', 'Ccedilla', + 'Egrave', 'Eacute', 'Ecircumflex', 'Edieresis', 'Igrave', 'Iacute', + 'Icircumflex', 'Idieresis', 'Eth', 'Ntilde', 'Ograve', 'Oacute', + 'Ocircumflex', 'Otilde', 'Odieresis', 'multiply', 'Oslash', 'Ugrave', + 'Uacute', 'Ucircumflex', 'Udieresis', 'Yacute', 'Thorn', 'germandbls', + 'agrave', 'aacute', 'acircumflex', 'atilde', 'adieresis', 'aring', 'ae', + 'ccedilla', 'egrave', 'eacute', 'ecircumflex', 'edieresis', 'igrave', + 'iacute', 'icircumflex', 'idieresis', 'eth', 'ntilde', 'ograve', 'oacute', + 'ocircumflex', 'otilde', 'odieresis', 'divide', 'oslash', 'ugrave', 'uacute', + 'ucircumflex', 'udieresis', 'yacute', 'thorn', 'ydieresis') + diff --git a/reportlab/pdfbase/_fontdata_enc_zapfdingbats.py b/reportlab/pdfbase/_fontdata_enc_zapfdingbats.py new file mode 100644 index 00000000..80b66756 --- /dev/null +++ b/reportlab/pdfbase/_fontdata_enc_zapfdingbats.py @@ -0,0 +1,20 @@ +ZapfDingbatsEncoding = ( None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, + None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, + 'space', 'a1', 'a2', 'a202', 'a3', 'a4', 'a5', 'a119', 'a118', 'a117', 'a11', 'a12', 'a13', 'a14', + 'a15', 'a16', 'a105', 'a17', 'a18', 'a19', 'a20', 'a21', 'a22', 'a23', 'a24', 'a25', 'a26', 'a27', + 'a28', 'a6', 'a7', 'a8', 'a9', 'a10', 'a29', 'a30', 'a31', 'a32', 'a33', 'a34', 'a35', 'a36', + 'a37', 'a38', 'a39', 'a40', 'a41', 'a42', 'a43', 'a44', 'a45', 'a46', 'a47', 'a48', 'a49', 'a50', + 'a51', 'a52', 'a53', 'a54', 'a55', 'a56', 'a57', 'a58', 'a59', 'a60', 'a61', 'a62', 'a63', 'a64', + 'a65', 'a66', 'a67', 'a68', 'a69', 'a70', 'a71', 'a72', 'a73', 'a74', 'a203', 'a75', 'a204', 'a76', + 'a77', 'a78', 'a79', 'a81', 'a82', 'a83', 'a84', 'a97', 'a98', 'a99', 'a100', None, 'a89', 'a90', + 'a93', 'a94', 'a91', 'a92', 'a205', 'a85', 'a206', 'a86', 'a87', 'a88', 'a95', 'a96', None, None, + None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, + None, 'a101', 'a102', 'a103', 'a104', 'a106', 'a107', 'a108', 'a112', 'a111', 'a110', 'a109', + 'a120', 'a121', 'a122', 'a123', 'a124', 'a125', 'a126', 'a127', 'a128', 'a129', 'a130', 'a131', + 'a132', 'a133', 'a134', 'a135', 'a136', 'a137', 'a138', 'a139', 'a140', 'a141', 'a142', 'a143', + 'a144', 'a145', 'a146', 'a147', 'a148', 'a149', 'a150', 'a151', 'a152', 'a153', 'a154', 'a155', + 'a156', 'a157', 'a158', 'a159', 'a160', 'a161', 'a163', 'a164', 'a196', 'a165', 'a192', 'a166', + 'a167', 'a168', 'a169', 'a170', 'a171', 'a172', 'a173', 'a162', 'a174', 'a175', 'a176', 'a177', + 'a178', 'a179', 'a193', 'a180', 'a199', 'a181', 'a200', 'a182', None, 'a201', 'a183', 'a184', + 'a197', 'a185', 'a194', 'a198', 'a186', 'a195', 'a187', 'a188', 'a189', 'a190', 'a191', None) + diff --git a/reportlab/pdfbase/_fontdata_widths_courier.py b/reportlab/pdfbase/_fontdata_widths_courier.py new file mode 100644 index 00000000..f196a19a --- /dev/null +++ b/reportlab/pdfbase/_fontdata_widths_courier.py @@ -0,0 +1,229 @@ +widths = {'A': 600, + 'AE': 600, + 'Aacute': 600, + 'Acircumflex': 600, + 'Adieresis': 600, + 'Agrave': 600, + 'Aring': 600, + 'Atilde': 600, + 'B': 600, + 'C': 600, + 'Ccedilla': 600, + 'D': 600, + 'E': 600, + 'Eacute': 600, + 'Ecircumflex': 600, + 'Edieresis': 600, + 'Egrave': 600, + 'Eth': 600, + 'Euro': 600, + 'F': 600, + 'G': 600, + 'H': 600, + 'I': 600, + 'Iacute': 600, + 'Icircumflex': 600, + 'Idieresis': 600, + 'Igrave': 600, + 'J': 600, + 'K': 600, + 'L': 600, + 'Lslash': 600, + 'M': 600, + 'N': 600, + 'Ntilde': 600, + 'O': 600, + 'OE': 600, + 'Oacute': 600, + 'Ocircumflex': 600, + 'Odieresis': 600, + 'Ograve': 600, + 'Oslash': 600, + 'Otilde': 600, + 'P': 600, + 'Q': 600, + 'R': 600, + 'S': 600, + 'Scaron': 600, + 'T': 600, + 'Thorn': 600, + 'U': 600, + 'Uacute': 600, + 'Ucircumflex': 600, + 'Udieresis': 600, + 'Ugrave': 600, + 'V': 600, + 'W': 600, + 'X': 600, + 'Y': 600, + 'Yacute': 600, + 'Ydieresis': 600, + 'Z': 600, + 'Zcaron': 600, + 'a': 600, + 'aacute': 600, + 'acircumflex': 600, + 'acute': 600, + 'adieresis': 600, + 'ae': 600, + 'agrave': 600, + 'ampersand': 600, + 'aring': 600, + 'asciicircum': 600, + 'asciitilde': 600, + 'asterisk': 600, + 'at': 600, + 'atilde': 600, + 'b': 600, + 'backslash': 600, + 'bar': 600, + 'braceleft': 600, + 'braceright': 600, + 'bracketleft': 600, + 'bracketright': 600, + 'breve': 600, + 'brokenbar': 600, + 'bullet': 600, + 'c': 600, + 'caron': 600, + 'ccedilla': 600, + 'cedilla': 600, + 'cent': 600, + 'circumflex': 600, + 'colon': 600, + 'comma': 600, + 'copyright': 600, + 'currency': 600, + 'd': 600, + 'dagger': 600, + 'daggerdbl': 600, + 'degree': 600, + 'dieresis': 600, + 'divide': 600, + 'dollar': 600, + 'dotaccent': 600, + 'dotlessi': 600, + 'e': 600, + 'eacute': 600, + 'ecircumflex': 600, + 'edieresis': 600, + 'egrave': 600, + 'eight': 600, + 'ellipsis': 600, + 'emdash': 600, + 'endash': 600, + 'equal': 600, + 'eth': 600, + 'exclam': 600, + 'exclamdown': 600, + 'f': 600, + 'fi': 600, + 'five': 600, + 'fl': 600, + 'florin': 600, + 'four': 600, + 'fraction': 600, + 'g': 600, + 'germandbls': 600, + 'grave': 600, + 'greater': 600, + 'guillemotleft': 600, + 'guillemotright': 600, + 'guilsinglleft': 600, + 'guilsinglright': 600, + 'h': 600, + 'hungarumlaut': 600, + 'hyphen': 600, + 'i': 600, + 'iacute': 600, + 'icircumflex': 600, + 'idieresis': 600, + 'igrave': 600, + 'j': 600, + 'k': 600, + 'l': 600, + 'less': 600, + 'logicalnot': 600, + 'lslash': 600, + 'm': 600, + 'macron': 600, + 'minus': 600, + 'mu': 600, + 'multiply': 600, + 'n': 600, + 'nine': 600, + 'ntilde': 600, + 'numbersign': 600, + 'o': 600, + 'oacute': 600, + 'ocircumflex': 600, + 'odieresis': 600, + 'oe': 600, + 'ogonek': 600, + 'ograve': 600, + 'one': 600, + 'onehalf': 600, + 'onequarter': 600, + 'onesuperior': 600, + 'ordfeminine': 600, + 'ordmasculine': 600, + 'oslash': 600, + 'otilde': 600, + 'p': 600, + 'paragraph': 600, + 'parenleft': 600, + 'parenright': 600, + 'percent': 600, + 'period': 600, + 'periodcentered': 600, + 'perthousand': 600, + 'plus': 600, + 'plusminus': 600, + 'q': 600, + 'question': 600, + 'questiondown': 600, + 'quotedbl': 600, + 'quotedblbase': 600, + 'quotedblleft': 600, + 'quotedblright': 600, + 'quoteleft': 600, + 'quoteright': 600, + 'quotesinglbase': 600, + 'quotesingle': 600, + 'r': 600, + 'registered': 600, + 'ring': 600, + 's': 600, + 'scaron': 600, + 'section': 600, + 'semicolon': 600, + 'seven': 600, + 'six': 600, + 'slash': 600, + 'space': 600, + 'sterling': 600, + 't': 600, + 'thorn': 600, + 'three': 600, + 'threequarters': 600, + 'threesuperior': 600, + 'tilde': 600, + 'trademark': 600, + 'two': 600, + 'twosuperior': 600, + 'u': 600, + 'uacute': 600, + 'ucircumflex': 600, + 'udieresis': 600, + 'ugrave': 600, + 'underscore': 600, + 'v': 600, + 'w': 600, + 'x': 600, + 'y': 600, + 'yacute': 600, + 'ydieresis': 600, + 'yen': 600, + 'z': 600, + 'zcaron': 600, + 'zero': 600} diff --git a/reportlab/pdfbase/_fontdata_widths_courierbold.py b/reportlab/pdfbase/_fontdata_widths_courierbold.py new file mode 100644 index 00000000..f196a19a --- /dev/null +++ b/reportlab/pdfbase/_fontdata_widths_courierbold.py @@ -0,0 +1,229 @@ +widths = {'A': 600, + 'AE': 600, + 'Aacute': 600, + 'Acircumflex': 600, + 'Adieresis': 600, + 'Agrave': 600, + 'Aring': 600, + 'Atilde': 600, + 'B': 600, + 'C': 600, + 'Ccedilla': 600, + 'D': 600, + 'E': 600, + 'Eacute': 600, + 'Ecircumflex': 600, + 'Edieresis': 600, + 'Egrave': 600, + 'Eth': 600, + 'Euro': 600, + 'F': 600, + 'G': 600, + 'H': 600, + 'I': 600, + 'Iacute': 600, + 'Icircumflex': 600, + 'Idieresis': 600, + 'Igrave': 600, + 'J': 600, + 'K': 600, + 'L': 600, + 'Lslash': 600, + 'M': 600, + 'N': 600, + 'Ntilde': 600, + 'O': 600, + 'OE': 600, + 'Oacute': 600, + 'Ocircumflex': 600, + 'Odieresis': 600, + 'Ograve': 600, + 'Oslash': 600, + 'Otilde': 600, + 'P': 600, + 'Q': 600, + 'R': 600, + 'S': 600, + 'Scaron': 600, + 'T': 600, + 'Thorn': 600, + 'U': 600, + 'Uacute': 600, + 'Ucircumflex': 600, + 'Udieresis': 600, + 'Ugrave': 600, + 'V': 600, + 'W': 600, + 'X': 600, + 'Y': 600, + 'Yacute': 600, + 'Ydieresis': 600, + 'Z': 600, + 'Zcaron': 600, + 'a': 600, + 'aacute': 600, + 'acircumflex': 600, + 'acute': 600, + 'adieresis': 600, + 'ae': 600, + 'agrave': 600, + 'ampersand': 600, + 'aring': 600, + 'asciicircum': 600, + 'asciitilde': 600, + 'asterisk': 600, + 'at': 600, + 'atilde': 600, + 'b': 600, + 'backslash': 600, + 'bar': 600, + 'braceleft': 600, + 'braceright': 600, + 'bracketleft': 600, + 'bracketright': 600, + 'breve': 600, + 'brokenbar': 600, + 'bullet': 600, + 'c': 600, + 'caron': 600, + 'ccedilla': 600, + 'cedilla': 600, + 'cent': 600, + 'circumflex': 600, + 'colon': 600, + 'comma': 600, + 'copyright': 600, + 'currency': 600, + 'd': 600, + 'dagger': 600, + 'daggerdbl': 600, + 'degree': 600, + 'dieresis': 600, + 'divide': 600, + 'dollar': 600, + 'dotaccent': 600, + 'dotlessi': 600, + 'e': 600, + 'eacute': 600, + 'ecircumflex': 600, + 'edieresis': 600, + 'egrave': 600, + 'eight': 600, + 'ellipsis': 600, + 'emdash': 600, + 'endash': 600, + 'equal': 600, + 'eth': 600, + 'exclam': 600, + 'exclamdown': 600, + 'f': 600, + 'fi': 600, + 'five': 600, + 'fl': 600, + 'florin': 600, + 'four': 600, + 'fraction': 600, + 'g': 600, + 'germandbls': 600, + 'grave': 600, + 'greater': 600, + 'guillemotleft': 600, + 'guillemotright': 600, + 'guilsinglleft': 600, + 'guilsinglright': 600, + 'h': 600, + 'hungarumlaut': 600, + 'hyphen': 600, + 'i': 600, + 'iacute': 600, + 'icircumflex': 600, + 'idieresis': 600, + 'igrave': 600, + 'j': 600, + 'k': 600, + 'l': 600, + 'less': 600, + 'logicalnot': 600, + 'lslash': 600, + 'm': 600, + 'macron': 600, + 'minus': 600, + 'mu': 600, + 'multiply': 600, + 'n': 600, + 'nine': 600, + 'ntilde': 600, + 'numbersign': 600, + 'o': 600, + 'oacute': 600, + 'ocircumflex': 600, + 'odieresis': 600, + 'oe': 600, + 'ogonek': 600, + 'ograve': 600, + 'one': 600, + 'onehalf': 600, + 'onequarter': 600, + 'onesuperior': 600, + 'ordfeminine': 600, + 'ordmasculine': 600, + 'oslash': 600, + 'otilde': 600, + 'p': 600, + 'paragraph': 600, + 'parenleft': 600, + 'parenright': 600, + 'percent': 600, + 'period': 600, + 'periodcentered': 600, + 'perthousand': 600, + 'plus': 600, + 'plusminus': 600, + 'q': 600, + 'question': 600, + 'questiondown': 600, + 'quotedbl': 600, + 'quotedblbase': 600, + 'quotedblleft': 600, + 'quotedblright': 600, + 'quoteleft': 600, + 'quoteright': 600, + 'quotesinglbase': 600, + 'quotesingle': 600, + 'r': 600, + 'registered': 600, + 'ring': 600, + 's': 600, + 'scaron': 600, + 'section': 600, + 'semicolon': 600, + 'seven': 600, + 'six': 600, + 'slash': 600, + 'space': 600, + 'sterling': 600, + 't': 600, + 'thorn': 600, + 'three': 600, + 'threequarters': 600, + 'threesuperior': 600, + 'tilde': 600, + 'trademark': 600, + 'two': 600, + 'twosuperior': 600, + 'u': 600, + 'uacute': 600, + 'ucircumflex': 600, + 'udieresis': 600, + 'ugrave': 600, + 'underscore': 600, + 'v': 600, + 'w': 600, + 'x': 600, + 'y': 600, + 'yacute': 600, + 'ydieresis': 600, + 'yen': 600, + 'z': 600, + 'zcaron': 600, + 'zero': 600} diff --git a/reportlab/pdfbase/_fontdata_widths_courierboldoblique.py b/reportlab/pdfbase/_fontdata_widths_courierboldoblique.py new file mode 100644 index 00000000..f196a19a --- /dev/null +++ b/reportlab/pdfbase/_fontdata_widths_courierboldoblique.py @@ -0,0 +1,229 @@ +widths = {'A': 600, + 'AE': 600, + 'Aacute': 600, + 'Acircumflex': 600, + 'Adieresis': 600, + 'Agrave': 600, + 'Aring': 600, + 'Atilde': 600, + 'B': 600, + 'C': 600, + 'Ccedilla': 600, + 'D': 600, + 'E': 600, + 'Eacute': 600, + 'Ecircumflex': 600, + 'Edieresis': 600, + 'Egrave': 600, + 'Eth': 600, + 'Euro': 600, + 'F': 600, + 'G': 600, + 'H': 600, + 'I': 600, + 'Iacute': 600, + 'Icircumflex': 600, + 'Idieresis': 600, + 'Igrave': 600, + 'J': 600, + 'K': 600, + 'L': 600, + 'Lslash': 600, + 'M': 600, + 'N': 600, + 'Ntilde': 600, + 'O': 600, + 'OE': 600, + 'Oacute': 600, + 'Ocircumflex': 600, + 'Odieresis': 600, + 'Ograve': 600, + 'Oslash': 600, + 'Otilde': 600, + 'P': 600, + 'Q': 600, + 'R': 600, + 'S': 600, + 'Scaron': 600, + 'T': 600, + 'Thorn': 600, + 'U': 600, + 'Uacute': 600, + 'Ucircumflex': 600, + 'Udieresis': 600, + 'Ugrave': 600, + 'V': 600, + 'W': 600, + 'X': 600, + 'Y': 600, + 'Yacute': 600, + 'Ydieresis': 600, + 'Z': 600, + 'Zcaron': 600, + 'a': 600, + 'aacute': 600, + 'acircumflex': 600, + 'acute': 600, + 'adieresis': 600, + 'ae': 600, + 'agrave': 600, + 'ampersand': 600, + 'aring': 600, + 'asciicircum': 600, + 'asciitilde': 600, + 'asterisk': 600, + 'at': 600, + 'atilde': 600, + 'b': 600, + 'backslash': 600, + 'bar': 600, + 'braceleft': 600, + 'braceright': 600, + 'bracketleft': 600, + 'bracketright': 600, + 'breve': 600, + 'brokenbar': 600, + 'bullet': 600, + 'c': 600, + 'caron': 600, + 'ccedilla': 600, + 'cedilla': 600, + 'cent': 600, + 'circumflex': 600, + 'colon': 600, + 'comma': 600, + 'copyright': 600, + 'currency': 600, + 'd': 600, + 'dagger': 600, + 'daggerdbl': 600, + 'degree': 600, + 'dieresis': 600, + 'divide': 600, + 'dollar': 600, + 'dotaccent': 600, + 'dotlessi': 600, + 'e': 600, + 'eacute': 600, + 'ecircumflex': 600, + 'edieresis': 600, + 'egrave': 600, + 'eight': 600, + 'ellipsis': 600, + 'emdash': 600, + 'endash': 600, + 'equal': 600, + 'eth': 600, + 'exclam': 600, + 'exclamdown': 600, + 'f': 600, + 'fi': 600, + 'five': 600, + 'fl': 600, + 'florin': 600, + 'four': 600, + 'fraction': 600, + 'g': 600, + 'germandbls': 600, + 'grave': 600, + 'greater': 600, + 'guillemotleft': 600, + 'guillemotright': 600, + 'guilsinglleft': 600, + 'guilsinglright': 600, + 'h': 600, + 'hungarumlaut': 600, + 'hyphen': 600, + 'i': 600, + 'iacute': 600, + 'icircumflex': 600, + 'idieresis': 600, + 'igrave': 600, + 'j': 600, + 'k': 600, + 'l': 600, + 'less': 600, + 'logicalnot': 600, + 'lslash': 600, + 'm': 600, + 'macron': 600, + 'minus': 600, + 'mu': 600, + 'multiply': 600, + 'n': 600, + 'nine': 600, + 'ntilde': 600, + 'numbersign': 600, + 'o': 600, + 'oacute': 600, + 'ocircumflex': 600, + 'odieresis': 600, + 'oe': 600, + 'ogonek': 600, + 'ograve': 600, + 'one': 600, + 'onehalf': 600, + 'onequarter': 600, + 'onesuperior': 600, + 'ordfeminine': 600, + 'ordmasculine': 600, + 'oslash': 600, + 'otilde': 600, + 'p': 600, + 'paragraph': 600, + 'parenleft': 600, + 'parenright': 600, + 'percent': 600, + 'period': 600, + 'periodcentered': 600, + 'perthousand': 600, + 'plus': 600, + 'plusminus': 600, + 'q': 600, + 'question': 600, + 'questiondown': 600, + 'quotedbl': 600, + 'quotedblbase': 600, + 'quotedblleft': 600, + 'quotedblright': 600, + 'quoteleft': 600, + 'quoteright': 600, + 'quotesinglbase': 600, + 'quotesingle': 600, + 'r': 600, + 'registered': 600, + 'ring': 600, + 's': 600, + 'scaron': 600, + 'section': 600, + 'semicolon': 600, + 'seven': 600, + 'six': 600, + 'slash': 600, + 'space': 600, + 'sterling': 600, + 't': 600, + 'thorn': 600, + 'three': 600, + 'threequarters': 600, + 'threesuperior': 600, + 'tilde': 600, + 'trademark': 600, + 'two': 600, + 'twosuperior': 600, + 'u': 600, + 'uacute': 600, + 'ucircumflex': 600, + 'udieresis': 600, + 'ugrave': 600, + 'underscore': 600, + 'v': 600, + 'w': 600, + 'x': 600, + 'y': 600, + 'yacute': 600, + 'ydieresis': 600, + 'yen': 600, + 'z': 600, + 'zcaron': 600, + 'zero': 600} diff --git a/reportlab/pdfbase/_fontdata_widths_courieroblique.py b/reportlab/pdfbase/_fontdata_widths_courieroblique.py new file mode 100644 index 00000000..f196a19a --- /dev/null +++ b/reportlab/pdfbase/_fontdata_widths_courieroblique.py @@ -0,0 +1,229 @@ +widths = {'A': 600, + 'AE': 600, + 'Aacute': 600, + 'Acircumflex': 600, + 'Adieresis': 600, + 'Agrave': 600, + 'Aring': 600, + 'Atilde': 600, + 'B': 600, + 'C': 600, + 'Ccedilla': 600, + 'D': 600, + 'E': 600, + 'Eacute': 600, + 'Ecircumflex': 600, + 'Edieresis': 600, + 'Egrave': 600, + 'Eth': 600, + 'Euro': 600, + 'F': 600, + 'G': 600, + 'H': 600, + 'I': 600, + 'Iacute': 600, + 'Icircumflex': 600, + 'Idieresis': 600, + 'Igrave': 600, + 'J': 600, + 'K': 600, + 'L': 600, + 'Lslash': 600, + 'M': 600, + 'N': 600, + 'Ntilde': 600, + 'O': 600, + 'OE': 600, + 'Oacute': 600, + 'Ocircumflex': 600, + 'Odieresis': 600, + 'Ograve': 600, + 'Oslash': 600, + 'Otilde': 600, + 'P': 600, + 'Q': 600, + 'R': 600, + 'S': 600, + 'Scaron': 600, + 'T': 600, + 'Thorn': 600, + 'U': 600, + 'Uacute': 600, + 'Ucircumflex': 600, + 'Udieresis': 600, + 'Ugrave': 600, + 'V': 600, + 'W': 600, + 'X': 600, + 'Y': 600, + 'Yacute': 600, + 'Ydieresis': 600, + 'Z': 600, + 'Zcaron': 600, + 'a': 600, + 'aacute': 600, + 'acircumflex': 600, + 'acute': 600, + 'adieresis': 600, + 'ae': 600, + 'agrave': 600, + 'ampersand': 600, + 'aring': 600, + 'asciicircum': 600, + 'asciitilde': 600, + 'asterisk': 600, + 'at': 600, + 'atilde': 600, + 'b': 600, + 'backslash': 600, + 'bar': 600, + 'braceleft': 600, + 'braceright': 600, + 'bracketleft': 600, + 'bracketright': 600, + 'breve': 600, + 'brokenbar': 600, + 'bullet': 600, + 'c': 600, + 'caron': 600, + 'ccedilla': 600, + 'cedilla': 600, + 'cent': 600, + 'circumflex': 600, + 'colon': 600, + 'comma': 600, + 'copyright': 600, + 'currency': 600, + 'd': 600, + 'dagger': 600, + 'daggerdbl': 600, + 'degree': 600, + 'dieresis': 600, + 'divide': 600, + 'dollar': 600, + 'dotaccent': 600, + 'dotlessi': 600, + 'e': 600, + 'eacute': 600, + 'ecircumflex': 600, + 'edieresis': 600, + 'egrave': 600, + 'eight': 600, + 'ellipsis': 600, + 'emdash': 600, + 'endash': 600, + 'equal': 600, + 'eth': 600, + 'exclam': 600, + 'exclamdown': 600, + 'f': 600, + 'fi': 600, + 'five': 600, + 'fl': 600, + 'florin': 600, + 'four': 600, + 'fraction': 600, + 'g': 600, + 'germandbls': 600, + 'grave': 600, + 'greater': 600, + 'guillemotleft': 600, + 'guillemotright': 600, + 'guilsinglleft': 600, + 'guilsinglright': 600, + 'h': 600, + 'hungarumlaut': 600, + 'hyphen': 600, + 'i': 600, + 'iacute': 600, + 'icircumflex': 600, + 'idieresis': 600, + 'igrave': 600, + 'j': 600, + 'k': 600, + 'l': 600, + 'less': 600, + 'logicalnot': 600, + 'lslash': 600, + 'm': 600, + 'macron': 600, + 'minus': 600, + 'mu': 600, + 'multiply': 600, + 'n': 600, + 'nine': 600, + 'ntilde': 600, + 'numbersign': 600, + 'o': 600, + 'oacute': 600, + 'ocircumflex': 600, + 'odieresis': 600, + 'oe': 600, + 'ogonek': 600, + 'ograve': 600, + 'one': 600, + 'onehalf': 600, + 'onequarter': 600, + 'onesuperior': 600, + 'ordfeminine': 600, + 'ordmasculine': 600, + 'oslash': 600, + 'otilde': 600, + 'p': 600, + 'paragraph': 600, + 'parenleft': 600, + 'parenright': 600, + 'percent': 600, + 'period': 600, + 'periodcentered': 600, + 'perthousand': 600, + 'plus': 600, + 'plusminus': 600, + 'q': 600, + 'question': 600, + 'questiondown': 600, + 'quotedbl': 600, + 'quotedblbase': 600, + 'quotedblleft': 600, + 'quotedblright': 600, + 'quoteleft': 600, + 'quoteright': 600, + 'quotesinglbase': 600, + 'quotesingle': 600, + 'r': 600, + 'registered': 600, + 'ring': 600, + 's': 600, + 'scaron': 600, + 'section': 600, + 'semicolon': 600, + 'seven': 600, + 'six': 600, + 'slash': 600, + 'space': 600, + 'sterling': 600, + 't': 600, + 'thorn': 600, + 'three': 600, + 'threequarters': 600, + 'threesuperior': 600, + 'tilde': 600, + 'trademark': 600, + 'two': 600, + 'twosuperior': 600, + 'u': 600, + 'uacute': 600, + 'ucircumflex': 600, + 'udieresis': 600, + 'ugrave': 600, + 'underscore': 600, + 'v': 600, + 'w': 600, + 'x': 600, + 'y': 600, + 'yacute': 600, + 'ydieresis': 600, + 'yen': 600, + 'z': 600, + 'zcaron': 600, + 'zero': 600} diff --git a/reportlab/pdfbase/_fontdata_widths_helvetica.py b/reportlab/pdfbase/_fontdata_widths_helvetica.py new file mode 100644 index 00000000..10d74db2 --- /dev/null +++ b/reportlab/pdfbase/_fontdata_widths_helvetica.py @@ -0,0 +1,229 @@ +widths = {'A': 667, + 'AE': 1000, + 'Aacute': 667, + 'Acircumflex': 667, + 'Adieresis': 667, + 'Agrave': 667, + 'Aring': 667, + 'Atilde': 667, + 'B': 667, + 'C': 722, + 'Ccedilla': 722, + 'D': 722, + 'E': 667, + 'Eacute': 667, + 'Ecircumflex': 667, + 'Edieresis': 667, + 'Egrave': 667, + 'Eth': 722, + 'Euro': 556, + 'F': 611, + 'G': 778, + 'H': 722, + 'I': 278, + 'Iacute': 278, + 'Icircumflex': 278, + 'Idieresis': 278, + 'Igrave': 278, + 'J': 500, + 'K': 667, + 'L': 556, + 'Lslash': 556, + 'M': 833, + 'N': 722, + 'Ntilde': 722, + 'O': 778, + 'OE': 1000, + 'Oacute': 778, + 'Ocircumflex': 778, + 'Odieresis': 778, + 'Ograve': 778, + 'Oslash': 778, + 'Otilde': 778, + 'P': 667, + 'Q': 778, + 'R': 722, + 'S': 667, + 'Scaron': 667, + 'T': 611, + 'Thorn': 667, + 'U': 722, + 'Uacute': 722, + 'Ucircumflex': 722, + 'Udieresis': 722, + 'Ugrave': 722, + 'V': 667, + 'W': 944, + 'X': 667, + 'Y': 667, + 'Yacute': 667, + 'Ydieresis': 667, + 'Z': 611, + 'Zcaron': 611, + 'a': 556, + 'aacute': 556, + 'acircumflex': 556, + 'acute': 333, + 'adieresis': 556, + 'ae': 889, + 'agrave': 556, + 'ampersand': 667, + 'aring': 556, + 'asciicircum': 469, + 'asciitilde': 584, + 'asterisk': 389, + 'at': 1015, + 'atilde': 556, + 'b': 556, + 'backslash': 278, + 'bar': 260, + 'braceleft': 334, + 'braceright': 334, + 'bracketleft': 278, + 'bracketright': 278, + 'breve': 333, + 'brokenbar': 260, + 'bullet': 350, + 'c': 500, + 'caron': 333, + 'ccedilla': 500, + 'cedilla': 333, + 'cent': 556, + 'circumflex': 333, + 'colon': 278, + 'comma': 278, + 'copyright': 737, + 'currency': 556, + 'd': 556, + 'dagger': 556, + 'daggerdbl': 556, + 'degree': 400, + 'dieresis': 333, + 'divide': 584, + 'dollar': 556, + 'dotaccent': 333, + 'dotlessi': 278, + 'e': 556, + 'eacute': 556, + 'ecircumflex': 556, + 'edieresis': 556, + 'egrave': 556, + 'eight': 556, + 'ellipsis': 1000, + 'emdash': 1000, + 'endash': 556, + 'equal': 584, + 'eth': 556, + 'exclam': 278, + 'exclamdown': 333, + 'f': 278, + 'fi': 500, + 'five': 556, + 'fl': 500, + 'florin': 556, + 'four': 556, + 'fraction': 167, + 'g': 556, + 'germandbls': 611, + 'grave': 333, + 'greater': 584, + 'guillemotleft': 556, + 'guillemotright': 556, + 'guilsinglleft': 333, + 'guilsinglright': 333, + 'h': 556, + 'hungarumlaut': 333, + 'hyphen': 333, + 'i': 222, + 'iacute': 278, + 'icircumflex': 278, + 'idieresis': 278, + 'igrave': 278, + 'j': 222, + 'k': 500, + 'l': 222, + 'less': 584, + 'logicalnot': 584, + 'lslash': 222, + 'm': 833, + 'macron': 333, + 'minus': 584, + 'mu': 556, + 'multiply': 584, + 'n': 556, + 'nine': 556, + 'ntilde': 556, + 'numbersign': 556, + 'o': 556, + 'oacute': 556, + 'ocircumflex': 556, + 'odieresis': 556, + 'oe': 944, + 'ogonek': 333, + 'ograve': 556, + 'one': 556, + 'onehalf': 834, + 'onequarter': 834, + 'onesuperior': 333, + 'ordfeminine': 370, + 'ordmasculine': 365, + 'oslash': 611, + 'otilde': 556, + 'p': 556, + 'paragraph': 537, + 'parenleft': 333, + 'parenright': 333, + 'percent': 889, + 'period': 278, + 'periodcentered': 278, + 'perthousand': 1000, + 'plus': 584, + 'plusminus': 584, + 'q': 556, + 'question': 556, + 'questiondown': 611, + 'quotedbl': 355, + 'quotedblbase': 333, + 'quotedblleft': 333, + 'quotedblright': 333, + 'quoteleft': 222, + 'quoteright': 222, + 'quotesinglbase': 222, + 'quotesingle': 191, + 'r': 333, + 'registered': 737, + 'ring': 333, + 's': 500, + 'scaron': 500, + 'section': 556, + 'semicolon': 278, + 'seven': 556, + 'six': 556, + 'slash': 278, + 'space': 278, + 'sterling': 556, + 't': 278, + 'thorn': 556, + 'three': 556, + 'threequarters': 834, + 'threesuperior': 333, + 'tilde': 333, + 'trademark': 1000, + 'two': 556, + 'twosuperior': 333, + 'u': 556, + 'uacute': 556, + 'ucircumflex': 556, + 'udieresis': 556, + 'ugrave': 556, + 'underscore': 556, + 'v': 500, + 'w': 722, + 'x': 500, + 'y': 500, + 'yacute': 500, + 'ydieresis': 500, + 'yen': 556, + 'z': 500, + 'zcaron': 500, + 'zero': 556} diff --git a/reportlab/pdfbase/_fontdata_widths_helveticabold.py b/reportlab/pdfbase/_fontdata_widths_helveticabold.py new file mode 100644 index 00000000..7b9acd2c --- /dev/null +++ b/reportlab/pdfbase/_fontdata_widths_helveticabold.py @@ -0,0 +1,229 @@ +widths = {'A': 722, + 'AE': 1000, + 'Aacute': 722, + 'Acircumflex': 722, + 'Adieresis': 722, + 'Agrave': 722, + 'Aring': 722, + 'Atilde': 722, + 'B': 722, + 'C': 722, + 'Ccedilla': 722, + 'D': 722, + 'E': 667, + 'Eacute': 667, + 'Ecircumflex': 667, + 'Edieresis': 667, + 'Egrave': 667, + 'Eth': 722, + 'Euro': 556, + 'F': 611, + 'G': 778, + 'H': 722, + 'I': 278, + 'Iacute': 278, + 'Icircumflex': 278, + 'Idieresis': 278, + 'Igrave': 278, + 'J': 556, + 'K': 722, + 'L': 611, + 'Lslash': 611, + 'M': 833, + 'N': 722, + 'Ntilde': 722, + 'O': 778, + 'OE': 1000, + 'Oacute': 778, + 'Ocircumflex': 778, + 'Odieresis': 778, + 'Ograve': 778, + 'Oslash': 778, + 'Otilde': 778, + 'P': 667, + 'Q': 778, + 'R': 722, + 'S': 667, + 'Scaron': 667, + 'T': 611, + 'Thorn': 667, + 'U': 722, + 'Uacute': 722, + 'Ucircumflex': 722, + 'Udieresis': 722, + 'Ugrave': 722, + 'V': 667, + 'W': 944, + 'X': 667, + 'Y': 667, + 'Yacute': 667, + 'Ydieresis': 667, + 'Z': 611, + 'Zcaron': 611, + 'a': 556, + 'aacute': 556, + 'acircumflex': 556, + 'acute': 333, + 'adieresis': 556, + 'ae': 889, + 'agrave': 556, + 'ampersand': 722, + 'aring': 556, + 'asciicircum': 584, + 'asciitilde': 584, + 'asterisk': 389, + 'at': 975, + 'atilde': 556, + 'b': 611, + 'backslash': 278, + 'bar': 280, + 'braceleft': 389, + 'braceright': 389, + 'bracketleft': 333, + 'bracketright': 333, + 'breve': 333, + 'brokenbar': 280, + 'bullet': 350, + 'c': 556, + 'caron': 333, + 'ccedilla': 556, + 'cedilla': 333, + 'cent': 556, + 'circumflex': 333, + 'colon': 333, + 'comma': 278, + 'copyright': 737, + 'currency': 556, + 'd': 611, + 'dagger': 556, + 'daggerdbl': 556, + 'degree': 400, + 'dieresis': 333, + 'divide': 584, + 'dollar': 556, + 'dotaccent': 333, + 'dotlessi': 278, + 'e': 556, + 'eacute': 556, + 'ecircumflex': 556, + 'edieresis': 556, + 'egrave': 556, + 'eight': 556, + 'ellipsis': 1000, + 'emdash': 1000, + 'endash': 556, + 'equal': 584, + 'eth': 611, + 'exclam': 333, + 'exclamdown': 333, + 'f': 333, + 'fi': 611, + 'five': 556, + 'fl': 611, + 'florin': 556, + 'four': 556, + 'fraction': 167, + 'g': 611, + 'germandbls': 611, + 'grave': 333, + 'greater': 584, + 'guillemotleft': 556, + 'guillemotright': 556, + 'guilsinglleft': 333, + 'guilsinglright': 333, + 'h': 611, + 'hungarumlaut': 333, + 'hyphen': 333, + 'i': 278, + 'iacute': 278, + 'icircumflex': 278, + 'idieresis': 278, + 'igrave': 278, + 'j': 278, + 'k': 556, + 'l': 278, + 'less': 584, + 'logicalnot': 584, + 'lslash': 278, + 'm': 889, + 'macron': 333, + 'minus': 584, + 'mu': 611, + 'multiply': 584, + 'n': 611, + 'nine': 556, + 'ntilde': 611, + 'numbersign': 556, + 'o': 611, + 'oacute': 611, + 'ocircumflex': 611, + 'odieresis': 611, + 'oe': 944, + 'ogonek': 333, + 'ograve': 611, + 'one': 556, + 'onehalf': 834, + 'onequarter': 834, + 'onesuperior': 333, + 'ordfeminine': 370, + 'ordmasculine': 365, + 'oslash': 611, + 'otilde': 611, + 'p': 611, + 'paragraph': 556, + 'parenleft': 333, + 'parenright': 333, + 'percent': 889, + 'period': 278, + 'periodcentered': 278, + 'perthousand': 1000, + 'plus': 584, + 'plusminus': 584, + 'q': 611, + 'question': 611, + 'questiondown': 611, + 'quotedbl': 474, + 'quotedblbase': 500, + 'quotedblleft': 500, + 'quotedblright': 500, + 'quoteleft': 278, + 'quoteright': 278, + 'quotesinglbase': 278, + 'quotesingle': 238, + 'r': 389, + 'registered': 737, + 'ring': 333, + 's': 556, + 'scaron': 556, + 'section': 556, + 'semicolon': 333, + 'seven': 556, + 'six': 556, + 'slash': 278, + 'space': 278, + 'sterling': 556, + 't': 333, + 'thorn': 611, + 'three': 556, + 'threequarters': 834, + 'threesuperior': 333, + 'tilde': 333, + 'trademark': 1000, + 'two': 556, + 'twosuperior': 333, + 'u': 611, + 'uacute': 611, + 'ucircumflex': 611, + 'udieresis': 611, + 'ugrave': 611, + 'underscore': 556, + 'v': 556, + 'w': 778, + 'x': 556, + 'y': 556, + 'yacute': 556, + 'ydieresis': 556, + 'yen': 556, + 'z': 500, + 'zcaron': 500, + 'zero': 556} diff --git a/reportlab/pdfbase/_fontdata_widths_helveticaboldoblique.py b/reportlab/pdfbase/_fontdata_widths_helveticaboldoblique.py new file mode 100644 index 00000000..7b9acd2c --- /dev/null +++ b/reportlab/pdfbase/_fontdata_widths_helveticaboldoblique.py @@ -0,0 +1,229 @@ +widths = {'A': 722, + 'AE': 1000, + 'Aacute': 722, + 'Acircumflex': 722, + 'Adieresis': 722, + 'Agrave': 722, + 'Aring': 722, + 'Atilde': 722, + 'B': 722, + 'C': 722, + 'Ccedilla': 722, + 'D': 722, + 'E': 667, + 'Eacute': 667, + 'Ecircumflex': 667, + 'Edieresis': 667, + 'Egrave': 667, + 'Eth': 722, + 'Euro': 556, + 'F': 611, + 'G': 778, + 'H': 722, + 'I': 278, + 'Iacute': 278, + 'Icircumflex': 278, + 'Idieresis': 278, + 'Igrave': 278, + 'J': 556, + 'K': 722, + 'L': 611, + 'Lslash': 611, + 'M': 833, + 'N': 722, + 'Ntilde': 722, + 'O': 778, + 'OE': 1000, + 'Oacute': 778, + 'Ocircumflex': 778, + 'Odieresis': 778, + 'Ograve': 778, + 'Oslash': 778, + 'Otilde': 778, + 'P': 667, + 'Q': 778, + 'R': 722, + 'S': 667, + 'Scaron': 667, + 'T': 611, + 'Thorn': 667, + 'U': 722, + 'Uacute': 722, + 'Ucircumflex': 722, + 'Udieresis': 722, + 'Ugrave': 722, + 'V': 667, + 'W': 944, + 'X': 667, + 'Y': 667, + 'Yacute': 667, + 'Ydieresis': 667, + 'Z': 611, + 'Zcaron': 611, + 'a': 556, + 'aacute': 556, + 'acircumflex': 556, + 'acute': 333, + 'adieresis': 556, + 'ae': 889, + 'agrave': 556, + 'ampersand': 722, + 'aring': 556, + 'asciicircum': 584, + 'asciitilde': 584, + 'asterisk': 389, + 'at': 975, + 'atilde': 556, + 'b': 611, + 'backslash': 278, + 'bar': 280, + 'braceleft': 389, + 'braceright': 389, + 'bracketleft': 333, + 'bracketright': 333, + 'breve': 333, + 'brokenbar': 280, + 'bullet': 350, + 'c': 556, + 'caron': 333, + 'ccedilla': 556, + 'cedilla': 333, + 'cent': 556, + 'circumflex': 333, + 'colon': 333, + 'comma': 278, + 'copyright': 737, + 'currency': 556, + 'd': 611, + 'dagger': 556, + 'daggerdbl': 556, + 'degree': 400, + 'dieresis': 333, + 'divide': 584, + 'dollar': 556, + 'dotaccent': 333, + 'dotlessi': 278, + 'e': 556, + 'eacute': 556, + 'ecircumflex': 556, + 'edieresis': 556, + 'egrave': 556, + 'eight': 556, + 'ellipsis': 1000, + 'emdash': 1000, + 'endash': 556, + 'equal': 584, + 'eth': 611, + 'exclam': 333, + 'exclamdown': 333, + 'f': 333, + 'fi': 611, + 'five': 556, + 'fl': 611, + 'florin': 556, + 'four': 556, + 'fraction': 167, + 'g': 611, + 'germandbls': 611, + 'grave': 333, + 'greater': 584, + 'guillemotleft': 556, + 'guillemotright': 556, + 'guilsinglleft': 333, + 'guilsinglright': 333, + 'h': 611, + 'hungarumlaut': 333, + 'hyphen': 333, + 'i': 278, + 'iacute': 278, + 'icircumflex': 278, + 'idieresis': 278, + 'igrave': 278, + 'j': 278, + 'k': 556, + 'l': 278, + 'less': 584, + 'logicalnot': 584, + 'lslash': 278, + 'm': 889, + 'macron': 333, + 'minus': 584, + 'mu': 611, + 'multiply': 584, + 'n': 611, + 'nine': 556, + 'ntilde': 611, + 'numbersign': 556, + 'o': 611, + 'oacute': 611, + 'ocircumflex': 611, + 'odieresis': 611, + 'oe': 944, + 'ogonek': 333, + 'ograve': 611, + 'one': 556, + 'onehalf': 834, + 'onequarter': 834, + 'onesuperior': 333, + 'ordfeminine': 370, + 'ordmasculine': 365, + 'oslash': 611, + 'otilde': 611, + 'p': 611, + 'paragraph': 556, + 'parenleft': 333, + 'parenright': 333, + 'percent': 889, + 'period': 278, + 'periodcentered': 278, + 'perthousand': 1000, + 'plus': 584, + 'plusminus': 584, + 'q': 611, + 'question': 611, + 'questiondown': 611, + 'quotedbl': 474, + 'quotedblbase': 500, + 'quotedblleft': 500, + 'quotedblright': 500, + 'quoteleft': 278, + 'quoteright': 278, + 'quotesinglbase': 278, + 'quotesingle': 238, + 'r': 389, + 'registered': 737, + 'ring': 333, + 's': 556, + 'scaron': 556, + 'section': 556, + 'semicolon': 333, + 'seven': 556, + 'six': 556, + 'slash': 278, + 'space': 278, + 'sterling': 556, + 't': 333, + 'thorn': 611, + 'three': 556, + 'threequarters': 834, + 'threesuperior': 333, + 'tilde': 333, + 'trademark': 1000, + 'two': 556, + 'twosuperior': 333, + 'u': 611, + 'uacute': 611, + 'ucircumflex': 611, + 'udieresis': 611, + 'ugrave': 611, + 'underscore': 556, + 'v': 556, + 'w': 778, + 'x': 556, + 'y': 556, + 'yacute': 556, + 'ydieresis': 556, + 'yen': 556, + 'z': 500, + 'zcaron': 500, + 'zero': 556} diff --git a/reportlab/pdfbase/_fontdata_widths_helveticaoblique.py b/reportlab/pdfbase/_fontdata_widths_helveticaoblique.py new file mode 100644 index 00000000..10d74db2 --- /dev/null +++ b/reportlab/pdfbase/_fontdata_widths_helveticaoblique.py @@ -0,0 +1,229 @@ +widths = {'A': 667, + 'AE': 1000, + 'Aacute': 667, + 'Acircumflex': 667, + 'Adieresis': 667, + 'Agrave': 667, + 'Aring': 667, + 'Atilde': 667, + 'B': 667, + 'C': 722, + 'Ccedilla': 722, + 'D': 722, + 'E': 667, + 'Eacute': 667, + 'Ecircumflex': 667, + 'Edieresis': 667, + 'Egrave': 667, + 'Eth': 722, + 'Euro': 556, + 'F': 611, + 'G': 778, + 'H': 722, + 'I': 278, + 'Iacute': 278, + 'Icircumflex': 278, + 'Idieresis': 278, + 'Igrave': 278, + 'J': 500, + 'K': 667, + 'L': 556, + 'Lslash': 556, + 'M': 833, + 'N': 722, + 'Ntilde': 722, + 'O': 778, + 'OE': 1000, + 'Oacute': 778, + 'Ocircumflex': 778, + 'Odieresis': 778, + 'Ograve': 778, + 'Oslash': 778, + 'Otilde': 778, + 'P': 667, + 'Q': 778, + 'R': 722, + 'S': 667, + 'Scaron': 667, + 'T': 611, + 'Thorn': 667, + 'U': 722, + 'Uacute': 722, + 'Ucircumflex': 722, + 'Udieresis': 722, + 'Ugrave': 722, + 'V': 667, + 'W': 944, + 'X': 667, + 'Y': 667, + 'Yacute': 667, + 'Ydieresis': 667, + 'Z': 611, + 'Zcaron': 611, + 'a': 556, + 'aacute': 556, + 'acircumflex': 556, + 'acute': 333, + 'adieresis': 556, + 'ae': 889, + 'agrave': 556, + 'ampersand': 667, + 'aring': 556, + 'asciicircum': 469, + 'asciitilde': 584, + 'asterisk': 389, + 'at': 1015, + 'atilde': 556, + 'b': 556, + 'backslash': 278, + 'bar': 260, + 'braceleft': 334, + 'braceright': 334, + 'bracketleft': 278, + 'bracketright': 278, + 'breve': 333, + 'brokenbar': 260, + 'bullet': 350, + 'c': 500, + 'caron': 333, + 'ccedilla': 500, + 'cedilla': 333, + 'cent': 556, + 'circumflex': 333, + 'colon': 278, + 'comma': 278, + 'copyright': 737, + 'currency': 556, + 'd': 556, + 'dagger': 556, + 'daggerdbl': 556, + 'degree': 400, + 'dieresis': 333, + 'divide': 584, + 'dollar': 556, + 'dotaccent': 333, + 'dotlessi': 278, + 'e': 556, + 'eacute': 556, + 'ecircumflex': 556, + 'edieresis': 556, + 'egrave': 556, + 'eight': 556, + 'ellipsis': 1000, + 'emdash': 1000, + 'endash': 556, + 'equal': 584, + 'eth': 556, + 'exclam': 278, + 'exclamdown': 333, + 'f': 278, + 'fi': 500, + 'five': 556, + 'fl': 500, + 'florin': 556, + 'four': 556, + 'fraction': 167, + 'g': 556, + 'germandbls': 611, + 'grave': 333, + 'greater': 584, + 'guillemotleft': 556, + 'guillemotright': 556, + 'guilsinglleft': 333, + 'guilsinglright': 333, + 'h': 556, + 'hungarumlaut': 333, + 'hyphen': 333, + 'i': 222, + 'iacute': 278, + 'icircumflex': 278, + 'idieresis': 278, + 'igrave': 278, + 'j': 222, + 'k': 500, + 'l': 222, + 'less': 584, + 'logicalnot': 584, + 'lslash': 222, + 'm': 833, + 'macron': 333, + 'minus': 584, + 'mu': 556, + 'multiply': 584, + 'n': 556, + 'nine': 556, + 'ntilde': 556, + 'numbersign': 556, + 'o': 556, + 'oacute': 556, + 'ocircumflex': 556, + 'odieresis': 556, + 'oe': 944, + 'ogonek': 333, + 'ograve': 556, + 'one': 556, + 'onehalf': 834, + 'onequarter': 834, + 'onesuperior': 333, + 'ordfeminine': 370, + 'ordmasculine': 365, + 'oslash': 611, + 'otilde': 556, + 'p': 556, + 'paragraph': 537, + 'parenleft': 333, + 'parenright': 333, + 'percent': 889, + 'period': 278, + 'periodcentered': 278, + 'perthousand': 1000, + 'plus': 584, + 'plusminus': 584, + 'q': 556, + 'question': 556, + 'questiondown': 611, + 'quotedbl': 355, + 'quotedblbase': 333, + 'quotedblleft': 333, + 'quotedblright': 333, + 'quoteleft': 222, + 'quoteright': 222, + 'quotesinglbase': 222, + 'quotesingle': 191, + 'r': 333, + 'registered': 737, + 'ring': 333, + 's': 500, + 'scaron': 500, + 'section': 556, + 'semicolon': 278, + 'seven': 556, + 'six': 556, + 'slash': 278, + 'space': 278, + 'sterling': 556, + 't': 278, + 'thorn': 556, + 'three': 556, + 'threequarters': 834, + 'threesuperior': 333, + 'tilde': 333, + 'trademark': 1000, + 'two': 556, + 'twosuperior': 333, + 'u': 556, + 'uacute': 556, + 'ucircumflex': 556, + 'udieresis': 556, + 'ugrave': 556, + 'underscore': 556, + 'v': 500, + 'w': 722, + 'x': 500, + 'y': 500, + 'yacute': 500, + 'ydieresis': 500, + 'yen': 556, + 'z': 500, + 'zcaron': 500, + 'zero': 556} diff --git a/reportlab/pdfbase/_fontdata_widths_symbol.py b/reportlab/pdfbase/_fontdata_widths_symbol.py new file mode 100644 index 00000000..a18f2f69 --- /dev/null +++ b/reportlab/pdfbase/_fontdata_widths_symbol.py @@ -0,0 +1,190 @@ +widths = {'Alpha': 722, + 'Beta': 667, + 'Chi': 722, + 'Delta': 612, + 'Epsilon': 611, + 'Eta': 722, + 'Euro': 750, + 'Gamma': 603, + 'Ifraktur': 686, + 'Iota': 333, + 'Kappa': 722, + 'Lambda': 686, + 'Mu': 889, + 'Nu': 722, + 'Omega': 768, + 'Omicron': 722, + 'Phi': 763, + 'Pi': 768, + 'Psi': 795, + 'Rfraktur': 795, + 'Rho': 556, + 'Sigma': 592, + 'Tau': 611, + 'Theta': 741, + 'Upsilon': 690, + 'Upsilon1': 620, + 'Xi': 645, + 'Zeta': 611, + 'aleph': 823, + 'alpha': 631, + 'ampersand': 778, + 'angle': 768, + 'angleleft': 329, + 'angleright': 329, + 'apple': 790, + 'approxequal': 549, + 'arrowboth': 1042, + 'arrowdblboth': 1042, + 'arrowdbldown': 603, + 'arrowdblleft': 987, + 'arrowdblright': 987, + 'arrowdblup': 603, + 'arrowdown': 603, + 'arrowhorizex': 1000, + 'arrowleft': 987, + 'arrowright': 987, + 'arrowup': 603, + 'arrowvertex': 603, + 'asteriskmath': 500, + 'bar': 200, + 'beta': 549, + 'braceex': 494, + 'braceleft': 480, + 'braceleftbt': 494, + 'braceleftmid': 494, + 'bracelefttp': 494, + 'braceright': 480, + 'bracerightbt': 494, + 'bracerightmid': 494, + 'bracerighttp': 494, + 'bracketleft': 333, + 'bracketleftbt': 384, + 'bracketleftex': 384, + 'bracketlefttp': 384, + 'bracketright': 333, + 'bracketrightbt': 384, + 'bracketrightex': 384, + 'bracketrighttp': 384, + 'bullet': 460, + 'carriagereturn': 658, + 'chi': 549, + 'circlemultiply': 768, + 'circleplus': 768, + 'club': 753, + 'colon': 278, + 'comma': 250, + 'congruent': 549, + 'copyrightsans': 790, + 'copyrightserif': 790, + 'degree': 400, + 'delta': 494, + 'diamond': 753, + 'divide': 549, + 'dotmath': 250, + 'eight': 500, + 'element': 713, + 'ellipsis': 1000, + 'emptyset': 823, + 'epsilon': 439, + 'equal': 549, + 'equivalence': 549, + 'eta': 603, + 'exclam': 333, + 'existential': 549, + 'five': 500, + 'florin': 500, + 'four': 500, + 'fraction': 167, + 'gamma': 411, + 'gradient': 713, + 'greater': 549, + 'greaterequal': 549, + 'heart': 753, + 'infinity': 713, + 'integral': 274, + 'integralbt': 686, + 'integralex': 686, + 'integraltp': 686, + 'intersection': 768, + 'iota': 329, + 'kappa': 549, + 'lambda': 549, + 'less': 549, + 'lessequal': 549, + 'logicaland': 603, + 'logicalnot': 713, + 'logicalor': 603, + 'lozenge': 494, + 'minus': 549, + 'minute': 247, + 'mu': 576, + 'multiply': 549, + 'nine': 500, + 'notelement': 713, + 'notequal': 549, + 'notsubset': 713, + 'nu': 521, + 'numbersign': 500, + 'omega': 686, + 'omega1': 713, + 'omicron': 549, + 'one': 500, + 'parenleft': 333, + 'parenleftbt': 384, + 'parenleftex': 384, + 'parenlefttp': 384, + 'parenright': 333, + 'parenrightbt': 384, + 'parenrightex': 384, + 'parenrighttp': 384, + 'partialdiff': 494, + 'percent': 833, + 'period': 250, + 'perpendicular': 658, + 'phi': 521, + 'phi1': 603, + 'pi': 549, + 'plus': 549, + 'plusminus': 549, + 'product': 823, + 'propersubset': 713, + 'propersuperset': 713, + 'proportional': 713, + 'psi': 686, + 'question': 444, + 'radical': 549, + 'radicalex': 500, + 'reflexsubset': 713, + 'reflexsuperset': 713, + 'registersans': 790, + 'registerserif': 790, + 'rho': 549, + 'second': 411, + 'semicolon': 278, + 'seven': 500, + 'sigma': 603, + 'sigma1': 439, + 'similar': 549, + 'six': 500, + 'slash': 278, + 'space': 250, + 'spade': 753, + 'suchthat': 439, + 'summation': 713, + 'tau': 439, + 'therefore': 863, + 'theta': 521, + 'theta1': 631, + 'three': 500, + 'trademarksans': 786, + 'trademarkserif': 890, + 'two': 500, + 'underscore': 500, + 'union': 768, + 'universal': 713, + 'upsilon': 576, + 'weierstrass': 987, + 'xi': 493, + 'zero': 500, + 'zeta': 494} diff --git a/reportlab/pdfbase/_fontdata_widths_timesbold.py b/reportlab/pdfbase/_fontdata_widths_timesbold.py new file mode 100644 index 00000000..97adc79a --- /dev/null +++ b/reportlab/pdfbase/_fontdata_widths_timesbold.py @@ -0,0 +1,229 @@ +widths = {'A': 722, + 'AE': 1000, + 'Aacute': 722, + 'Acircumflex': 722, + 'Adieresis': 722, + 'Agrave': 722, + 'Aring': 722, + 'Atilde': 722, + 'B': 667, + 'C': 722, + 'Ccedilla': 722, + 'D': 722, + 'E': 667, + 'Eacute': 667, + 'Ecircumflex': 667, + 'Edieresis': 667, + 'Egrave': 667, + 'Eth': 722, + 'Euro': 500, + 'F': 611, + 'G': 778, + 'H': 778, + 'I': 389, + 'Iacute': 389, + 'Icircumflex': 389, + 'Idieresis': 389, + 'Igrave': 389, + 'J': 500, + 'K': 778, + 'L': 667, + 'Lslash': 667, + 'M': 944, + 'N': 722, + 'Ntilde': 722, + 'O': 778, + 'OE': 1000, + 'Oacute': 778, + 'Ocircumflex': 778, + 'Odieresis': 778, + 'Ograve': 778, + 'Oslash': 778, + 'Otilde': 778, + 'P': 611, + 'Q': 778, + 'R': 722, + 'S': 556, + 'Scaron': 556, + 'T': 667, + 'Thorn': 611, + 'U': 722, + 'Uacute': 722, + 'Ucircumflex': 722, + 'Udieresis': 722, + 'Ugrave': 722, + 'V': 722, + 'W': 1000, + 'X': 722, + 'Y': 722, + 'Yacute': 722, + 'Ydieresis': 722, + 'Z': 667, + 'Zcaron': 667, + 'a': 500, + 'aacute': 500, + 'acircumflex': 500, + 'acute': 333, + 'adieresis': 500, + 'ae': 722, + 'agrave': 500, + 'ampersand': 833, + 'aring': 500, + 'asciicircum': 581, + 'asciitilde': 520, + 'asterisk': 500, + 'at': 930, + 'atilde': 500, + 'b': 556, + 'backslash': 278, + 'bar': 220, + 'braceleft': 394, + 'braceright': 394, + 'bracketleft': 333, + 'bracketright': 333, + 'breve': 333, + 'brokenbar': 220, + 'bullet': 350, + 'c': 444, + 'caron': 333, + 'ccedilla': 444, + 'cedilla': 333, + 'cent': 500, + 'circumflex': 333, + 'colon': 333, + 'comma': 250, + 'copyright': 747, + 'currency': 500, + 'd': 556, + 'dagger': 500, + 'daggerdbl': 500, + 'degree': 400, + 'dieresis': 333, + 'divide': 570, + 'dollar': 500, + 'dotaccent': 333, + 'dotlessi': 278, + 'e': 444, + 'eacute': 444, + 'ecircumflex': 444, + 'edieresis': 444, + 'egrave': 444, + 'eight': 500, + 'ellipsis': 1000, + 'emdash': 1000, + 'endash': 500, + 'equal': 570, + 'eth': 500, + 'exclam': 333, + 'exclamdown': 333, + 'f': 333, + 'fi': 556, + 'five': 500, + 'fl': 556, + 'florin': 500, + 'four': 500, + 'fraction': 167, + 'g': 500, + 'germandbls': 556, + 'grave': 333, + 'greater': 570, + 'guillemotleft': 500, + 'guillemotright': 500, + 'guilsinglleft': 333, + 'guilsinglright': 333, + 'h': 556, + 'hungarumlaut': 333, + 'hyphen': 333, + 'i': 278, + 'iacute': 278, + 'icircumflex': 278, + 'idieresis': 278, + 'igrave': 278, + 'j': 333, + 'k': 556, + 'l': 278, + 'less': 570, + 'logicalnot': 570, + 'lslash': 278, + 'm': 833, + 'macron': 333, + 'minus': 570, + 'mu': 556, + 'multiply': 570, + 'n': 556, + 'nine': 500, + 'ntilde': 556, + 'numbersign': 500, + 'o': 500, + 'oacute': 500, + 'ocircumflex': 500, + 'odieresis': 500, + 'oe': 722, + 'ogonek': 333, + 'ograve': 500, + 'one': 500, + 'onehalf': 750, + 'onequarter': 750, + 'onesuperior': 300, + 'ordfeminine': 300, + 'ordmasculine': 330, + 'oslash': 500, + 'otilde': 500, + 'p': 556, + 'paragraph': 540, + 'parenleft': 333, + 'parenright': 333, + 'percent': 1000, + 'period': 250, + 'periodcentered': 250, + 'perthousand': 1000, + 'plus': 570, + 'plusminus': 570, + 'q': 556, + 'question': 500, + 'questiondown': 500, + 'quotedbl': 555, + 'quotedblbase': 500, + 'quotedblleft': 500, + 'quotedblright': 500, + 'quoteleft': 333, + 'quoteright': 333, + 'quotesinglbase': 333, + 'quotesingle': 278, + 'r': 444, + 'registered': 747, + 'ring': 333, + 's': 389, + 'scaron': 389, + 'section': 500, + 'semicolon': 333, + 'seven': 500, + 'six': 500, + 'slash': 278, + 'space': 250, + 'sterling': 500, + 't': 333, + 'thorn': 556, + 'three': 500, + 'threequarters': 750, + 'threesuperior': 300, + 'tilde': 333, + 'trademark': 1000, + 'two': 500, + 'twosuperior': 300, + 'u': 556, + 'uacute': 556, + 'ucircumflex': 556, + 'udieresis': 556, + 'ugrave': 556, + 'underscore': 500, + 'v': 500, + 'w': 722, + 'x': 500, + 'y': 500, + 'yacute': 500, + 'ydieresis': 500, + 'yen': 500, + 'z': 444, + 'zcaron': 444, + 'zero': 500} diff --git a/reportlab/pdfbase/_fontdata_widths_timesbolditalic.py b/reportlab/pdfbase/_fontdata_widths_timesbolditalic.py new file mode 100644 index 00000000..e7c6be43 --- /dev/null +++ b/reportlab/pdfbase/_fontdata_widths_timesbolditalic.py @@ -0,0 +1,229 @@ +widths = {'A': 667, + 'AE': 944, + 'Aacute': 667, + 'Acircumflex': 667, + 'Adieresis': 667, + 'Agrave': 667, + 'Aring': 667, + 'Atilde': 667, + 'B': 667, + 'C': 667, + 'Ccedilla': 667, + 'D': 722, + 'E': 667, + 'Eacute': 667, + 'Ecircumflex': 667, + 'Edieresis': 667, + 'Egrave': 667, + 'Eth': 722, + 'Euro': 500, + 'F': 667, + 'G': 722, + 'H': 778, + 'I': 389, + 'Iacute': 389, + 'Icircumflex': 389, + 'Idieresis': 389, + 'Igrave': 389, + 'J': 500, + 'K': 667, + 'L': 611, + 'Lslash': 611, + 'M': 889, + 'N': 722, + 'Ntilde': 722, + 'O': 722, + 'OE': 944, + 'Oacute': 722, + 'Ocircumflex': 722, + 'Odieresis': 722, + 'Ograve': 722, + 'Oslash': 722, + 'Otilde': 722, + 'P': 611, + 'Q': 722, + 'R': 667, + 'S': 556, + 'Scaron': 556, + 'T': 611, + 'Thorn': 611, + 'U': 722, + 'Uacute': 722, + 'Ucircumflex': 722, + 'Udieresis': 722, + 'Ugrave': 722, + 'V': 667, + 'W': 889, + 'X': 667, + 'Y': 611, + 'Yacute': 611, + 'Ydieresis': 611, + 'Z': 611, + 'Zcaron': 611, + 'a': 500, + 'aacute': 500, + 'acircumflex': 500, + 'acute': 333, + 'adieresis': 500, + 'ae': 722, + 'agrave': 500, + 'ampersand': 778, + 'aring': 500, + 'asciicircum': 570, + 'asciitilde': 570, + 'asterisk': 500, + 'at': 832, + 'atilde': 500, + 'b': 500, + 'backslash': 278, + 'bar': 220, + 'braceleft': 348, + 'braceright': 348, + 'bracketleft': 333, + 'bracketright': 333, + 'breve': 333, + 'brokenbar': 220, + 'bullet': 350, + 'c': 444, + 'caron': 333, + 'ccedilla': 444, + 'cedilla': 333, + 'cent': 500, + 'circumflex': 333, + 'colon': 333, + 'comma': 250, + 'copyright': 747, + 'currency': 500, + 'd': 500, + 'dagger': 500, + 'daggerdbl': 500, + 'degree': 400, + 'dieresis': 333, + 'divide': 570, + 'dollar': 500, + 'dotaccent': 333, + 'dotlessi': 278, + 'e': 444, + 'eacute': 444, + 'ecircumflex': 444, + 'edieresis': 444, + 'egrave': 444, + 'eight': 500, + 'ellipsis': 1000, + 'emdash': 1000, + 'endash': 500, + 'equal': 570, + 'eth': 500, + 'exclam': 389, + 'exclamdown': 389, + 'f': 333, + 'fi': 556, + 'five': 500, + 'fl': 556, + 'florin': 500, + 'four': 500, + 'fraction': 167, + 'g': 500, + 'germandbls': 500, + 'grave': 333, + 'greater': 570, + 'guillemotleft': 500, + 'guillemotright': 500, + 'guilsinglleft': 333, + 'guilsinglright': 333, + 'h': 556, + 'hungarumlaut': 333, + 'hyphen': 333, + 'i': 278, + 'iacute': 278, + 'icircumflex': 278, + 'idieresis': 278, + 'igrave': 278, + 'j': 278, + 'k': 500, + 'l': 278, + 'less': 570, + 'logicalnot': 606, + 'lslash': 278, + 'm': 778, + 'macron': 333, + 'minus': 606, + 'mu': 576, + 'multiply': 570, + 'n': 556, + 'nine': 500, + 'ntilde': 556, + 'numbersign': 500, + 'o': 500, + 'oacute': 500, + 'ocircumflex': 500, + 'odieresis': 500, + 'oe': 722, + 'ogonek': 333, + 'ograve': 500, + 'one': 500, + 'onehalf': 750, + 'onequarter': 750, + 'onesuperior': 300, + 'ordfeminine': 266, + 'ordmasculine': 300, + 'oslash': 500, + 'otilde': 500, + 'p': 500, + 'paragraph': 500, + 'parenleft': 333, + 'parenright': 333, + 'percent': 833, + 'period': 250, + 'periodcentered': 250, + 'perthousand': 1000, + 'plus': 570, + 'plusminus': 570, + 'q': 500, + 'question': 500, + 'questiondown': 500, + 'quotedbl': 555, + 'quotedblbase': 500, + 'quotedblleft': 500, + 'quotedblright': 500, + 'quoteleft': 333, + 'quoteright': 333, + 'quotesinglbase': 333, + 'quotesingle': 278, + 'r': 389, + 'registered': 747, + 'ring': 333, + 's': 389, + 'scaron': 389, + 'section': 500, + 'semicolon': 333, + 'seven': 500, + 'six': 500, + 'slash': 278, + 'space': 250, + 'sterling': 500, + 't': 278, + 'thorn': 500, + 'three': 500, + 'threequarters': 750, + 'threesuperior': 300, + 'tilde': 333, + 'trademark': 1000, + 'two': 500, + 'twosuperior': 300, + 'u': 556, + 'uacute': 556, + 'ucircumflex': 556, + 'udieresis': 556, + 'ugrave': 556, + 'underscore': 500, + 'v': 444, + 'w': 667, + 'x': 500, + 'y': 444, + 'yacute': 444, + 'ydieresis': 444, + 'yen': 500, + 'z': 389, + 'zcaron': 389, + 'zero': 500} diff --git a/reportlab/pdfbase/_fontdata_widths_timesitalic.py b/reportlab/pdfbase/_fontdata_widths_timesitalic.py new file mode 100644 index 00000000..77aaa16f --- /dev/null +++ b/reportlab/pdfbase/_fontdata_widths_timesitalic.py @@ -0,0 +1,229 @@ +widths = {'A': 611, + 'AE': 889, + 'Aacute': 611, + 'Acircumflex': 611, + 'Adieresis': 611, + 'Agrave': 611, + 'Aring': 611, + 'Atilde': 611, + 'B': 611, + 'C': 667, + 'Ccedilla': 667, + 'D': 722, + 'E': 611, + 'Eacute': 611, + 'Ecircumflex': 611, + 'Edieresis': 611, + 'Egrave': 611, + 'Eth': 722, + 'Euro': 500, + 'F': 611, + 'G': 722, + 'H': 722, + 'I': 333, + 'Iacute': 333, + 'Icircumflex': 333, + 'Idieresis': 333, + 'Igrave': 333, + 'J': 444, + 'K': 667, + 'L': 556, + 'Lslash': 556, + 'M': 833, + 'N': 667, + 'Ntilde': 667, + 'O': 722, + 'OE': 944, + 'Oacute': 722, + 'Ocircumflex': 722, + 'Odieresis': 722, + 'Ograve': 722, + 'Oslash': 722, + 'Otilde': 722, + 'P': 611, + 'Q': 722, + 'R': 611, + 'S': 500, + 'Scaron': 500, + 'T': 556, + 'Thorn': 611, + 'U': 722, + 'Uacute': 722, + 'Ucircumflex': 722, + 'Udieresis': 722, + 'Ugrave': 722, + 'V': 611, + 'W': 833, + 'X': 611, + 'Y': 556, + 'Yacute': 556, + 'Ydieresis': 556, + 'Z': 556, + 'Zcaron': 556, + 'a': 500, + 'aacute': 500, + 'acircumflex': 500, + 'acute': 333, + 'adieresis': 500, + 'ae': 667, + 'agrave': 500, + 'ampersand': 778, + 'aring': 500, + 'asciicircum': 422, + 'asciitilde': 541, + 'asterisk': 500, + 'at': 920, + 'atilde': 500, + 'b': 500, + 'backslash': 278, + 'bar': 275, + 'braceleft': 400, + 'braceright': 400, + 'bracketleft': 389, + 'bracketright': 389, + 'breve': 333, + 'brokenbar': 275, + 'bullet': 350, + 'c': 444, + 'caron': 333, + 'ccedilla': 444, + 'cedilla': 333, + 'cent': 500, + 'circumflex': 333, + 'colon': 333, + 'comma': 250, + 'copyright': 760, + 'currency': 500, + 'd': 500, + 'dagger': 500, + 'daggerdbl': 500, + 'degree': 400, + 'dieresis': 333, + 'divide': 675, + 'dollar': 500, + 'dotaccent': 333, + 'dotlessi': 278, + 'e': 444, + 'eacute': 444, + 'ecircumflex': 444, + 'edieresis': 444, + 'egrave': 444, + 'eight': 500, + 'ellipsis': 889, + 'emdash': 889, + 'endash': 500, + 'equal': 675, + 'eth': 500, + 'exclam': 333, + 'exclamdown': 389, + 'f': 278, + 'fi': 500, + 'five': 500, + 'fl': 500, + 'florin': 500, + 'four': 500, + 'fraction': 167, + 'g': 500, + 'germandbls': 500, + 'grave': 333, + 'greater': 675, + 'guillemotleft': 500, + 'guillemotright': 500, + 'guilsinglleft': 333, + 'guilsinglright': 333, + 'h': 500, + 'hungarumlaut': 333, + 'hyphen': 333, + 'i': 278, + 'iacute': 278, + 'icircumflex': 278, + 'idieresis': 278, + 'igrave': 278, + 'j': 278, + 'k': 444, + 'l': 278, + 'less': 675, + 'logicalnot': 675, + 'lslash': 278, + 'm': 722, + 'macron': 333, + 'minus': 675, + 'mu': 500, + 'multiply': 675, + 'n': 500, + 'nine': 500, + 'ntilde': 500, + 'numbersign': 500, + 'o': 500, + 'oacute': 500, + 'ocircumflex': 500, + 'odieresis': 500, + 'oe': 667, + 'ogonek': 333, + 'ograve': 500, + 'one': 500, + 'onehalf': 750, + 'onequarter': 750, + 'onesuperior': 300, + 'ordfeminine': 276, + 'ordmasculine': 310, + 'oslash': 500, + 'otilde': 500, + 'p': 500, + 'paragraph': 523, + 'parenleft': 333, + 'parenright': 333, + 'percent': 833, + 'period': 250, + 'periodcentered': 250, + 'perthousand': 1000, + 'plus': 675, + 'plusminus': 675, + 'q': 500, + 'question': 500, + 'questiondown': 500, + 'quotedbl': 420, + 'quotedblbase': 556, + 'quotedblleft': 556, + 'quotedblright': 556, + 'quoteleft': 333, + 'quoteright': 333, + 'quotesinglbase': 333, + 'quotesingle': 214, + 'r': 389, + 'registered': 760, + 'ring': 333, + 's': 389, + 'scaron': 389, + 'section': 500, + 'semicolon': 333, + 'seven': 500, + 'six': 500, + 'slash': 278, + 'space': 250, + 'sterling': 500, + 't': 278, + 'thorn': 500, + 'three': 500, + 'threequarters': 750, + 'threesuperior': 300, + 'tilde': 333, + 'trademark': 980, + 'two': 500, + 'twosuperior': 300, + 'u': 500, + 'uacute': 500, + 'ucircumflex': 500, + 'udieresis': 500, + 'ugrave': 500, + 'underscore': 500, + 'v': 444, + 'w': 667, + 'x': 444, + 'y': 444, + 'yacute': 444, + 'ydieresis': 444, + 'yen': 500, + 'z': 389, + 'zcaron': 389, + 'zero': 500} diff --git a/reportlab/pdfbase/_fontdata_widths_timesroman.py b/reportlab/pdfbase/_fontdata_widths_timesroman.py new file mode 100644 index 00000000..82d0347c --- /dev/null +++ b/reportlab/pdfbase/_fontdata_widths_timesroman.py @@ -0,0 +1,229 @@ +widths = {'A': 722, + 'AE': 889, + 'Aacute': 722, + 'Acircumflex': 722, + 'Adieresis': 722, + 'Agrave': 722, + 'Aring': 722, + 'Atilde': 722, + 'B': 667, + 'C': 667, + 'Ccedilla': 667, + 'D': 722, + 'E': 611, + 'Eacute': 611, + 'Ecircumflex': 611, + 'Edieresis': 611, + 'Egrave': 611, + 'Eth': 722, + 'Euro': 500, + 'F': 556, + 'G': 722, + 'H': 722, + 'I': 333, + 'Iacute': 333, + 'Icircumflex': 333, + 'Idieresis': 333, + 'Igrave': 333, + 'J': 389, + 'K': 722, + 'L': 611, + 'Lslash': 611, + 'M': 889, + 'N': 722, + 'Ntilde': 722, + 'O': 722, + 'OE': 889, + 'Oacute': 722, + 'Ocircumflex': 722, + 'Odieresis': 722, + 'Ograve': 722, + 'Oslash': 722, + 'Otilde': 722, + 'P': 556, + 'Q': 722, + 'R': 667, + 'S': 556, + 'Scaron': 556, + 'T': 611, + 'Thorn': 556, + 'U': 722, + 'Uacute': 722, + 'Ucircumflex': 722, + 'Udieresis': 722, + 'Ugrave': 722, + 'V': 722, + 'W': 944, + 'X': 722, + 'Y': 722, + 'Yacute': 722, + 'Ydieresis': 722, + 'Z': 611, + 'Zcaron': 611, + 'a': 444, + 'aacute': 444, + 'acircumflex': 444, + 'acute': 333, + 'adieresis': 444, + 'ae': 667, + 'agrave': 444, + 'ampersand': 778, + 'aring': 444, + 'asciicircum': 469, + 'asciitilde': 541, + 'asterisk': 500, + 'at': 921, + 'atilde': 444, + 'b': 500, + 'backslash': 278, + 'bar': 200, + 'braceleft': 480, + 'braceright': 480, + 'bracketleft': 333, + 'bracketright': 333, + 'breve': 333, + 'brokenbar': 200, + 'bullet': 350, + 'c': 444, + 'caron': 333, + 'ccedilla': 444, + 'cedilla': 333, + 'cent': 500, + 'circumflex': 333, + 'colon': 278, + 'comma': 250, + 'copyright': 760, + 'currency': 500, + 'd': 500, + 'dagger': 500, + 'daggerdbl': 500, + 'degree': 400, + 'dieresis': 333, + 'divide': 564, + 'dollar': 500, + 'dotaccent': 333, + 'dotlessi': 278, + 'e': 444, + 'eacute': 444, + 'ecircumflex': 444, + 'edieresis': 444, + 'egrave': 444, + 'eight': 500, + 'ellipsis': 1000, + 'emdash': 1000, + 'endash': 500, + 'equal': 564, + 'eth': 500, + 'exclam': 333, + 'exclamdown': 333, + 'f': 333, + 'fi': 556, + 'five': 500, + 'fl': 556, + 'florin': 500, + 'four': 500, + 'fraction': 167, + 'g': 500, + 'germandbls': 500, + 'grave': 333, + 'greater': 564, + 'guillemotleft': 500, + 'guillemotright': 500, + 'guilsinglleft': 333, + 'guilsinglright': 333, + 'h': 500, + 'hungarumlaut': 333, + 'hyphen': 333, + 'i': 278, + 'iacute': 278, + 'icircumflex': 278, + 'idieresis': 278, + 'igrave': 278, + 'j': 278, + 'k': 500, + 'l': 278, + 'less': 564, + 'logicalnot': 564, + 'lslash': 278, + 'm': 778, + 'macron': 333, + 'minus': 564, + 'mu': 500, + 'multiply': 564, + 'n': 500, + 'nine': 500, + 'ntilde': 500, + 'numbersign': 500, + 'o': 500, + 'oacute': 500, + 'ocircumflex': 500, + 'odieresis': 500, + 'oe': 722, + 'ogonek': 333, + 'ograve': 500, + 'one': 500, + 'onehalf': 750, + 'onequarter': 750, + 'onesuperior': 300, + 'ordfeminine': 276, + 'ordmasculine': 310, + 'oslash': 500, + 'otilde': 500, + 'p': 500, + 'paragraph': 453, + 'parenleft': 333, + 'parenright': 333, + 'percent': 833, + 'period': 250, + 'periodcentered': 250, + 'perthousand': 1000, + 'plus': 564, + 'plusminus': 564, + 'q': 500, + 'question': 444, + 'questiondown': 444, + 'quotedbl': 408, + 'quotedblbase': 444, + 'quotedblleft': 444, + 'quotedblright': 444, + 'quoteleft': 333, + 'quoteright': 333, + 'quotesinglbase': 333, + 'quotesingle': 180, + 'r': 333, + 'registered': 760, + 'ring': 333, + 's': 389, + 'scaron': 389, + 'section': 500, + 'semicolon': 278, + 'seven': 500, + 'six': 500, + 'slash': 278, + 'space': 250, + 'sterling': 500, + 't': 278, + 'thorn': 500, + 'three': 500, + 'threequarters': 750, + 'threesuperior': 300, + 'tilde': 333, + 'trademark': 980, + 'two': 500, + 'twosuperior': 300, + 'u': 500, + 'uacute': 500, + 'ucircumflex': 500, + 'udieresis': 500, + 'ugrave': 500, + 'underscore': 500, + 'v': 500, + 'w': 722, + 'x': 500, + 'y': 500, + 'yacute': 500, + 'ydieresis': 500, + 'yen': 500, + 'z': 444, + 'zcaron': 444, + 'zero': 500} diff --git a/reportlab/pdfbase/_fontdata_widths_zapfdingbats.py b/reportlab/pdfbase/_fontdata_widths_zapfdingbats.py new file mode 100644 index 00000000..5fc9f7ff --- /dev/null +++ b/reportlab/pdfbase/_fontdata_widths_zapfdingbats.py @@ -0,0 +1,202 @@ +widths = {'a1': 974, + 'a10': 692, + 'a100': 668, + 'a101': 732, + 'a102': 544, + 'a103': 544, + 'a104': 910, + 'a105': 911, + 'a106': 667, + 'a107': 760, + 'a108': 760, + 'a109': 626, + 'a11': 960, + 'a110': 694, + 'a111': 595, + 'a112': 776, + 'a117': 690, + 'a118': 791, + 'a119': 790, + 'a12': 939, + 'a120': 788, + 'a121': 788, + 'a122': 788, + 'a123': 788, + 'a124': 788, + 'a125': 788, + 'a126': 788, + 'a127': 788, + 'a128': 788, + 'a129': 788, + 'a13': 549, + 'a130': 788, + 'a131': 788, + 'a132': 788, + 'a133': 788, + 'a134': 788, + 'a135': 788, + 'a136': 788, + 'a137': 788, + 'a138': 788, + 'a139': 788, + 'a14': 855, + 'a140': 788, + 'a141': 788, + 'a142': 788, + 'a143': 788, + 'a144': 788, + 'a145': 788, + 'a146': 788, + 'a147': 788, + 'a148': 788, + 'a149': 788, + 'a15': 911, + 'a150': 788, + 'a151': 788, + 'a152': 788, + 'a153': 788, + 'a154': 788, + 'a155': 788, + 'a156': 788, + 'a157': 788, + 'a158': 788, + 'a159': 788, + 'a16': 933, + 'a160': 894, + 'a161': 838, + 'a162': 924, + 'a163': 1016, + 'a164': 458, + 'a165': 924, + 'a166': 918, + 'a167': 927, + 'a168': 928, + 'a169': 928, + 'a17': 945, + 'a170': 834, + 'a171': 873, + 'a172': 828, + 'a173': 924, + 'a174': 917, + 'a175': 930, + 'a176': 931, + 'a177': 463, + 'a178': 883, + 'a179': 836, + 'a18': 974, + 'a180': 867, + 'a181': 696, + 'a182': 874, + 'a183': 760, + 'a184': 946, + 'a185': 865, + 'a186': 967, + 'a187': 831, + 'a188': 873, + 'a189': 927, + 'a19': 755, + 'a190': 970, + 'a191': 918, + 'a192': 748, + 'a193': 836, + 'a194': 771, + 'a195': 888, + 'a196': 748, + 'a197': 771, + 'a198': 888, + 'a199': 867, + 'a2': 961, + 'a20': 846, + 'a200': 696, + 'a201': 874, + 'a202': 974, + 'a203': 762, + 'a204': 759, + 'a205': 509, + 'a206': 410, + 'a21': 762, + 'a22': 761, + 'a23': 571, + 'a24': 677, + 'a25': 763, + 'a26': 760, + 'a27': 759, + 'a28': 754, + 'a29': 786, + 'a3': 980, + 'a30': 788, + 'a31': 788, + 'a32': 790, + 'a33': 793, + 'a34': 794, + 'a35': 816, + 'a36': 823, + 'a37': 789, + 'a38': 841, + 'a39': 823, + 'a4': 719, + 'a40': 833, + 'a41': 816, + 'a42': 831, + 'a43': 923, + 'a44': 744, + 'a45': 723, + 'a46': 749, + 'a47': 790, + 'a48': 792, + 'a49': 695, + 'a5': 789, + 'a50': 776, + 'a51': 768, + 'a52': 792, + 'a53': 759, + 'a54': 707, + 'a55': 708, + 'a56': 682, + 'a57': 701, + 'a58': 826, + 'a59': 815, + 'a6': 494, + 'a60': 789, + 'a61': 789, + 'a62': 707, + 'a63': 687, + 'a64': 696, + 'a65': 689, + 'a66': 786, + 'a67': 787, + 'a68': 713, + 'a69': 791, + 'a7': 552, + 'a70': 785, + 'a71': 791, + 'a72': 873, + 'a73': 761, + 'a74': 762, + 'a75': 759, + 'a76': 892, + 'a77': 892, + 'a78': 788, + 'a79': 784, + 'a8': 537, + 'a81': 438, + 'a82': 138, + 'a83': 277, + 'a84': 415, + 'a85': 509, + 'a86': 410, + 'a87': 234, + 'a88': 234, + 'a89': 390, + 'a9': 577, + 'a90': 390, + 'a91': 276, + 'a92': 276, + 'a93': 317, + 'a94': 317, + 'a95': 334, + 'a96': 334, + 'a97': 392, + 'a98': 392, + 'a99': 668, + 'space': 278} diff --git a/reportlab/pdfbase/cidfonts.py b/reportlab/pdfbase/cidfonts.py new file mode 100644 index 00000000..22a5c37f --- /dev/null +++ b/reportlab/pdfbase/cidfonts.py @@ -0,0 +1,520 @@ +#Copyright ReportLab Europe Ltd. 2000-2012 +#see license.txt for license details +#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/pdfbase/cidfonts.py +#$Header $ +__version__=''' $Id$ ''' +__doc__="""CID (Asian multi-byte) font support. + +This defines classes to represent CID fonts. They know how to calculate +their own width and how to write themselves into PDF files.""" + +import os +import marshal +import time +try: + from hashlib import md5 +except ImportError: + from md5 import md5 + +import reportlab +from reportlab.pdfbase import pdfmetrics +from reportlab.pdfbase._cidfontdata import allowedTypeFaces, allowedEncodings, CIDFontInfo, \ + defaultUnicodeEncodings, widthsByUnichar +from reportlab.pdfgen.canvas import Canvas +from reportlab.pdfbase import pdfdoc +from reportlab.lib.rl_accel import escapePDF +from reportlab.rl_config import CMapSearchPath +from reportlab.lib.utils import isSeq, isBytes + +#quick hackery for 2.0 release. Now we always do unicode, and have built in +#the CMAP data, any code to load CMap files is not needed. +DISABLE_CMAP = True + + +def findCMapFile(name): + "Returns full filename, or raises error" + for dirname in CMapSearchPath: + cmapfile = dirname + os.sep + name + if os.path.isfile(cmapfile): + #print "found", cmapfile + return cmapfile + raise IOError('CMAP file for encodings "%s" not found!' % name) + +def structToPDF(structure): + "Converts deeply nested structure to PDFdoc dictionary/array objects" + if isinstance(structure,dict): + newDict = {} + for k, v in structure.items(): + newDict[k] = structToPDF(v) + return pdfdoc.PDFDictionary(newDict) + elif isSeq(structure): + newList = [] + for elem in structure: + newList.append(structToPDF(elem)) + return pdfdoc.PDFArray(newList) + else: + return structure + +class CIDEncoding(pdfmetrics.Encoding): + """Multi-byte encoding. These are loaded from CMAP files. + + A CMAP file is like a mini-codec. It defines the correspondence + between code points in the (multi-byte) input data and Character + IDs. """ + # aims to do similar things to Brian Hooper's CMap class, + # but I could not get it working and had to rewrite. + # also, we should really rearrange our current encoding + # into a SingleByteEncoding since many of its methods + # should not apply here. + + def __init__(self, name, useCache=1): + self.name = name + self._mapFileHash = None + self._codeSpaceRanges = [] + self._notDefRanges = [] + self._cmap = {} + self.source = None + if not DISABLE_CMAP: + if useCache: + from reportlab.lib.utils import get_rl_tempdir + fontmapdir = get_rl_tempdir('FastCMAPS') + if os.path.isfile(fontmapdir + os.sep + name + '.fastmap'): + self.fastLoad(fontmapdir) + self.source = fontmapdir + os.sep + name + '.fastmap' + else: + self.parseCMAPFile(name) + self.source = 'CMAP: ' + name + self.fastSave(fontmapdir) + else: + self.parseCMAPFile(name) + + def _hash(self, text): + hasher = md5() + hasher.update(text) + return hasher.digest() + + def parseCMAPFile(self, name): + """This is a tricky one as CMAP files are Postscript + ones. Some refer to others with a 'usecmap' + command""" + #started = time.clock() + cmapfile = findCMapFile(name) + # this will CRAWL with the unicode encodings... + rawdata = open(cmapfile, 'r').read() + + self._mapFileHash = self._hash(rawdata) + #if it contains the token 'usecmap', parse the other + #cmap file first.... + usecmap_pos = rawdata.find('usecmap') + if usecmap_pos > -1: + #they tell us to look in another file + #for the code space ranges. The one + # to use will be the previous word. + chunk = rawdata[0:usecmap_pos] + words = chunk.split() + otherCMAPName = words[-1] + #print 'referred to another CMAP %s' % otherCMAPName + self.parseCMAPFile(otherCMAPName) + # now continue parsing this, as it may + # override some settings + + + words = rawdata.split() + while words != []: + if words[0] == 'begincodespacerange': + words = words[1:] + while words[0] != 'endcodespacerange': + strStart, strEnd, words = words[0], words[1], words[2:] + start = int(strStart[1:-1], 16) + end = int(strEnd[1:-1], 16) + self._codeSpaceRanges.append((start, end),) + elif words[0] == 'beginnotdefrange': + words = words[1:] + while words[0] != 'endnotdefrange': + strStart, strEnd, strValue = words[0:3] + start = int(strStart[1:-1], 16) + end = int(strEnd[1:-1], 16) + value = int(strValue) + self._notDefRanges.append((start, end, value),) + words = words[3:] + elif words[0] == 'begincidrange': + words = words[1:] + while words[0] != 'endcidrange': + strStart, strEnd, strValue = words[0:3] + start = int(strStart[1:-1], 16) + end = int(strEnd[1:-1], 16) + value = int(strValue) + # this means that 'start' corresponds to 'value', + # start+1 corresponds to value+1 and so on up + # to end + offset = 0 + while start + offset <= end: + self._cmap[start + offset] = value + offset + offset = offset + 1 + words = words[3:] + + else: + words = words[1:] + #finished = time.clock() + #print 'parsed CMAP %s in %0.4f seconds' % (self.name, finished - started) + + def translate(self, text): + "Convert a string into a list of CIDs" + output = [] + cmap = self._cmap + lastChar = '' + for char in text: + if lastChar != '': + #print 'convert character pair "%s"' % (lastChar + char) + num = ord(lastChar) * 256 + ord(char) + else: + #print 'convert character "%s"' % char + num = ord(char) + lastChar = char + found = 0 + for low, high in self._codeSpaceRanges: + if low < num < high: + try: + cid = cmap[num] + #print '%d -> %d' % (num, cid) + except KeyError: + #not defined. Try to find the appropriate + # notdef character, or failing that return + # zero + cid = 0 + for low2, high2, notdef in self._notDefRanges: + if low2 < num < high2: + cid = notdef + break + output.append(cid) + found = 1 + break + if found: + lastChar = '' + else: + lastChar = char + return output + + def fastSave(self, directory): + f = open(os.path.join(directory, self.name + '.fastmap'), 'wb') + marshal.dump(self._mapFileHash, f) + marshal.dump(self._codeSpaceRanges, f) + marshal.dump(self._notDefRanges, f) + marshal.dump(self._cmap, f) + f.close() + + def fastLoad(self, directory): + started = time.clock() + f = open(os.path.join(directory, self.name + '.fastmap'), 'rb') + self._mapFileHash = marshal.load(f) + self._codeSpaceRanges = marshal.load(f) + self._notDefRanges = marshal.load(f) + self._cmap = marshal.load(f) + f.close() + finished = time.clock() + #print 'loaded %s in %0.4f seconds' % (self.name, finished - started) + + def getData(self): + """Simple persistence helper. Return a dict with all that matters.""" + return { + 'mapFileHash': self._mapFileHash, + 'codeSpaceRanges': self._codeSpaceRanges, + 'notDefRanges': self._notDefRanges, + 'cmap': self._cmap, + } + +class CIDTypeFace(pdfmetrics.TypeFace): + """Multi-byte type face. + + Conceptually similar to a single byte typeface, + but the glyphs are identified by a numeric Character + ID (CID) and not a glyph name. """ + def __init__(self, name): + """Initialised from one of the canned dictionaries in allowedEncodings + + Or rather, it will be shortly...""" + pdfmetrics.TypeFace.__init__(self, name) + self._extractDictInfo(name) + def _extractDictInfo(self, name): + try: + fontDict = CIDFontInfo[name] + except KeyError: + raise KeyError("Unable to find information on CID typeface '%s'" % name + + "Only the following font names work:" + repr(allowedTypeFaces)) + descFont = fontDict['DescendantFonts'][0] + self.ascent = descFont['FontDescriptor']['Ascent'] + self.descent = descFont['FontDescriptor']['Descent'] + self._defaultWidth = descFont['DW'] + self._explicitWidths = self._expandWidths(descFont['W']) + + # should really support self.glyphWidths, self.glyphNames + # but not done yet. + + + def _expandWidths(self, compactWidthArray): + """Expands Adobe nested list structure to get a dictionary of widths. + + Here is an example of such a structure.:: + + ( + # starting at character ID 1, next n characters have the widths given. + 1, (277,305,500,668,668,906,727,305,445,445,508,668,305,379,305,539), + # all Characters from ID 17 to 26 are 668 em units wide + 17, 26, 668, + 27, (305, 305, 668, 668, 668, 566, 871, 727, 637, 652, 699, 574, 555, + 676, 687, 242, 492, 664, 582, 789, 707, 734, 582, 734, 605, 605, + 641, 668, 727, 945, 609, 609, 574, 445, 668, 445, 668, 668, 590, + 555, 609, 547, 602, 574, 391, 609, 582, 234, 277, 539, 234, 895, + 582, 605, 602, 602, 387, 508, 441, 582, 562, 781, 531, 570, 555, + 449, 246, 449, 668), + # these must be half width katakana and the like. + 231, 632, 500 + ) + + """ + data = compactWidthArray[:] + widths = {} + while data: + start, data = data[0], data[1:] + if isSeq(data[0]): + items, data = data[0], data[1:] + for offset in range(len(items)): + widths[start + offset] = items[offset] + else: + end, width, data = data[0], data[1], data[2:] + for idx in range(start, end+1): + widths[idx] = width + return widths + + def getCharWidth(self, characterId): + return self._explicitWidths.get(characterId, self._defaultWidth) + +class CIDFont(pdfmetrics.Font): + "Represents a built-in multi-byte font" + _multiByte = 1 + + def __init__(self, face, encoding): + + assert face in allowedTypeFaces, "TypeFace '%s' not supported! Use any of these instead: %s" % (face, allowedTypeFaces) + self.faceName = face + #should cache in registry... + self.face = CIDTypeFace(face) + + assert encoding in allowedEncodings, "Encoding '%s' not supported! Use any of these instead: %s" % (encoding, allowedEncodings) + self.encodingName = encoding + self.encoding = CIDEncoding(encoding) + + #legacy hack doing quick cut and paste. + self.fontName = self.faceName + '-' + self.encodingName + self.name = self.fontName + + # need to know if it is vertical or horizontal + self.isVertical = (self.encodingName[-1] == 'V') + + #no substitutes initially + self.substitutionFonts = [] + + def formatForPdf(self, text): + encoded = escapePDF(text) + #print 'encoded CIDFont:', encoded + return encoded + + def stringWidth(self, text, size, encoding=None): + """This presumes non-Unicode input. UnicodeCIDFont wraps it for that context""" + cidlist = self.encoding.translate(text) + if self.isVertical: + #this part is "not checked!" but seems to work. + #assume each is 1000 ems high + return len(cidlist) * size + else: + w = 0 + for cid in cidlist: + w = w + self.face.getCharWidth(cid) + return 0.001 * w * size + + + def addObjects(self, doc): + """The explicit code in addMinchoObjects and addGothicObjects + will be replaced by something that pulls the data from + _cidfontdata.py in the next few days.""" + internalName = 'F' + repr(len(doc.fontMapping)+1) + + bigDict = CIDFontInfo[self.face.name] + bigDict['Name'] = '/' + internalName + bigDict['Encoding'] = '/' + self.encodingName + + #convert to PDF dictionary/array objects + cidObj = structToPDF(bigDict) + + # link into document, and add to font map + r = doc.Reference(cidObj, internalName) + fontDict = doc.idToObject['BasicFonts'].dict + fontDict[internalName] = r + doc.fontMapping[self.name] = '/' + internalName + + +class UnicodeCIDFont(CIDFont): + """Wraps up CIDFont to hide explicit encoding choice; + encodes text for output as UTF16. + + lang should be one of 'jpn',chs','cht','kor' for now. + if vertical is set, it will select a different widths array + and possibly glyphs for some punctuation marks. + + halfWidth is only for Japanese. + + + >>> dodgy = UnicodeCIDFont('nonexistent') + Traceback (most recent call last): + ... + KeyError: "don't know anything about CID font nonexistent" + >>> heisei = UnicodeCIDFont('HeiseiMin-W3') + >>> heisei.name + 'HeiseiMin-W3' + >>> heisei.language + 'jpn' + >>> heisei.encoding.name + 'UniJIS-UCS2-H' + >>> #This is how PDF data gets encoded. + >>> print(heisei.formatForPdf('hello')) + \\000h\\000e\\000l\\000l\\000o + >>> tokyo = u'\u6771\u4AEC' + >>> print(heisei.formatForPdf(tokyo)) + gqJ\\354 + >>> print(heisei.stringWidth(tokyo,10)) + 20.0 + >>> print(heisei.stringWidth('hello world',10)) + 45.83 + """ + + def __init__(self, face, isVertical=False, isHalfWidth=False): + #pass + try: + lang, defaultEncoding = defaultUnicodeEncodings[face] + except KeyError: + raise KeyError("don't know anything about CID font %s" % face) + + #we know the languages now. + self.language = lang + + #rebuilt encoding string. They follow rules which work + #for the 7 fonts provided. + enc = defaultEncoding[:-1] + if isHalfWidth: + enc = enc + 'HW-' + if isVertical: + enc = enc + 'V' + else: + enc = enc + 'H' + + #now we can do the more general case + CIDFont.__init__(self, face, enc) + #self.encName = 'utf_16_le' + #it's simpler for unicode, just use the face name + self.name = self.fontName = face + self.vertical = isVertical + self.isHalfWidth = isHalfWidth + + self.unicodeWidths = widthsByUnichar[self.name] + + + def formatForPdf(self, text): + #these ones should be encoded asUTF16 minus the BOM + from codecs import utf_16_be_encode + #print 'formatting %s: %s' % (type(text), repr(text)) + if isBytes(text): + text = text.decode('utf8') + utfText = utf_16_be_encode(text)[0] + encoded = escapePDF(utfText) + #print ' encoded:',encoded + return encoded + # + #result = escapePDF(encoded) + #print ' -> %s' % repr(result) + #return result + + + def stringWidth(self, text, size, encoding=None): + "Just ensure we do width test on characters, not bytes..." + if isBytes(text): + text = text.decode('utf8') + + widths = self.unicodeWidths + return size * 0.001 * sum([widths.get(uch, 1000) for uch in text]) + #return CIDFont.stringWidth(self, text, size, encoding) + + +def precalculate(cmapdir): + # crunches through all, making 'fastmap' files + import os + files = os.listdir(cmapdir) + for file in files: + if os.path.isfile(cmapdir + os.sep + file + '.fastmap'): + continue + try: + enc = CIDEncoding(file) + except: + print('cannot parse %s, skipping' % enc) + continue + enc.fastSave(cmapdir) + print('saved %s.fastmap' % file) + +def test(): + # only works if you have cirrect encodings on your box! + c = Canvas('test_japanese.pdf') + c.setFont('Helvetica', 30) + c.drawString(100,700, 'Japanese Font Support') + + pdfmetrics.registerFont(CIDFont('HeiseiMin-W3','90ms-RKSJ-H')) + pdfmetrics.registerFont(CIDFont('HeiseiKakuGo-W5','90ms-RKSJ-H')) + + + # the two typefaces + c.setFont('HeiseiMin-W3-90ms-RKSJ-H', 16) + # this says "This is HeiseiMincho" in shift-JIS. Not all our readers + # have a Japanese PC, so I escaped it. On a Japanese-capable + # system, print the string to see Kanji + message1 = '\202\261\202\352\202\315\225\275\220\254\226\276\222\251\202\305\202\267\201B' + c.drawString(100, 675, message1) + c.save() + print('saved test_japanese.pdf') + + +## print 'CMAP_DIR = ', CMAP_DIR +## tf1 = CIDTypeFace('HeiseiMin-W3') +## print 'ascent = ',tf1.ascent +## print 'descent = ',tf1.descent +## for cid in [1,2,3,4,5,18,19,28,231,1742]: +## print 'width of cid %d = %d' % (cid, tf1.getCharWidth(cid)) + + encName = '90ms-RKSJ-H' + enc = CIDEncoding(encName) + print(message1, '->', enc.translate(message1)) + + f = CIDFont('HeiseiMin-W3','90ms-RKSJ-H') + print('width = %0.2f' % f.stringWidth(message1, 10)) + + + #testing all encodings +## import time +## started = time.time() +## import glob +## for encName in _cidfontdata.allowedEncodings: +## #encName = '90ms-RKSJ-H' +## enc = CIDEncoding(encName) +## print 'encoding %s:' % encName +## print ' codeSpaceRanges = %s' % enc._codeSpaceRanges +## print ' notDefRanges = %s' % enc._notDefRanges +## print ' mapping size = %d' % len(enc._cmap) +## finished = time.time() +## print 'constructed all encodings in %0.2f seconds' % (finished - started) + +if __name__=='__main__': + import doctest + from reportlab.pdfbase import cidfonts + doctest.testmod(cidfonts) + #test() + + + + diff --git a/reportlab/pdfbase/pdfdoc.py b/reportlab/pdfbase/pdfdoc.py new file mode 100644 index 00000000..248d258e --- /dev/null +++ b/reportlab/pdfbase/pdfdoc.py @@ -0,0 +1,2394 @@ +#Copyright ReportLab Europe Ltd. 2000-2012 +#see license.txt for license details +#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/pdfbase/pdfdoc.py +__version__=''' $Id$ ''' +__doc__=""" +The module pdfdoc.py handles the 'outer structure' of PDF documents, ensuring that +all objects are properly cross-referenced and indexed to the nearest byte. The +'inner structure' - the page descriptions - are presumed to be generated before +each page is saved. +pdfgen.py calls this and provides a 'canvas' object to handle page marking operators. +piddlePDF calls pdfgen and offers a high-level interface. + +The classes within this generally mirror structures in the PDF file +and are not part of any public interface. Instead, canvas and font +classes are made available elsewhere for users to manipulate. +""" +import types, binascii, codecs +from collections import OrderedDict +from reportlab.pdfbase import pdfutils +from reportlab import rl_config +from reportlab.lib.utils import import_zlib, open_for_read, makeFileName, isSeq, isBytes, isUnicode, _digester, isStr, bytestr, isPy3 +from reportlab.lib.rl_accel import escapePDF, fp_str, asciiBase85Encode, asciiBase85Decode +from reportlab.pdfbase import pdfmetrics +from hashlib import md5 + +from sys import platform +from sys import version_info +from sys import stderr + +if platform[:4] == 'java' and version_info[:2] == (2, 1): + # workaround for list()-bug in Jython 2.1 (should be fixed in 2.2) + def list(sequence): + def f(x): + return x + return list(map(f, sequence)) + +class PDFError(Exception): + pass + +# __InternalName__ is a special attribute that can only be set by the Document arbitrator +__InternalName__ = "__InternalName__" + +# __RefOnly__ marks reference only elements that must be formatted on top level +__RefOnly__ = "__RefOnly__" + +# __Comment__ provides a (one line) comment to inline with an object ref, if present +# if it is more than one line then percentize it... +__Comment__ = "__Comment__" + +# name for standard font dictionary +BasicFonts = "BasicFonts" + +# name for the pages object +Pages = "Pages" + + +PDF_VERSION_DEFAULT = (1, 3) +PDF_SUPPORT_VERSION = dict( #map keyword to min version that supports it + transparency = (1, 4), + ) + +if isPy3: + def pdfdocEnc(x): + return x.encode('extpdfdoc') if isinstance(x,str) else x +else: + def pdfdocEnc(x): + return x.encode('extpdfdoc') if isinstance(x,unicode) else x + +def format(element, document, toplevel=0): + """Indirection step for formatting. + Ensures that document parameters alter behaviour + of formatting for all elements. + """ + if isinstance(element,PDFObject): + if not toplevel and hasattr(element, __RefOnly__): + # the object cannot be a component at non top level. + # make a reference to it and return it's format + return document.Reference(element).format(document) + else: + f = element.format(document) + if not rl_config.invariant and rl_config.pdfComments and hasattr(element, __Comment__): + f = pdfdocEnc("%% %s\r\n" % element.__Comment__)+f + return f + elif type(element) in (float, int): + #use a controlled number formatting routine + #instead of str, so Jython/Python etc do not differ + return pdfdocEnc(fp_str(element)) + elif isBytes(element): + return element + elif isUnicode(element): + return pdfdocEnc(element) + else: + return pdfdocEnc(str(element)) + +def xObjectName(externalname): + return "FormXob.%s" % externalname + +# backwards compatibility +formName = xObjectName + +# no encryption +class NoEncryption: + def encode(self, t): + "encode a string, stream, text" + return t + def prepare(self, document): + # get ready to do encryption + pass + def register(self, objnum, version): + # enter a new direct object + pass + def info(self): + # the representation of self in file if any (should be None or PDFDict) + return None + +class PDFObject(object): + pass + +class DummyDoc(PDFObject): + "used to bypass encryption when required" + encrypt = NoEncryption() + +### the global document structure manager +class PDFDocument(PDFObject): + # set this to define filters + defaultStreamFilters = None + encrypt = NoEncryption() # default no encryption + def __init__(self, + dummyoutline=0, + compression=rl_config.pageCompression, + invariant=rl_config.invariant, + filename=None, + pdfVersion=PDF_VERSION_DEFAULT, + ): + self._ID = None + self.objectcounter = 0 + self.shadingCounter = 0 + self.inObject = None + self.pageCounter = 1 + + # allow None value to be passed in to mean 'give system defaults' + if invariant is None: + self.invariant = rl_config.invariant + else: + self.invariant = invariant + self.setCompression(compression) + self._pdfVersion = pdfVersion + # signature for creating PDF ID + sig = self.signature = md5() + sig.update(b"a reportlab document") + if not self.invariant: + cat = _getTimeStamp() + else: + cat = 946684800.0 + cat = ascii(cat) + sig.update(bytestr(cat)) # initialize with timestamp digest + # mapping of internal identifier ("Page001") to PDF objectnumber and generation number (34, 0) + self.idToObjectNumberAndVersion = {} + # mapping of internal identifier ("Page001") to PDF object (PDFPage instance) + self.idToObject = {} + # internal id to file location + self.idToOffset = {} + # number to id + self.numberToId = {} + cat = self.Catalog = self._catalog = PDFCatalog() + pages = self.Pages = PDFPages() + cat.Pages = pages + if dummyoutline: + outlines = PDFOutlines0() + else: + outlines = PDFOutlines() + self.Outlines = self.outline = outlines + cat.Outlines = outlines + self.info = PDFInfo() + self.info.invariant = self.invariant + #self.Reference(self.Catalog) + #self.Reference(self.Info) + self.fontMapping = {} + #make an empty font dictionary + DD = PDFDictionary({}) + DD.__Comment__ = "The standard fonts dictionary" + self.Reference(DD, BasicFonts) + self.delayedFonts = [] + + def setCompression(self, onoff): + # XXX: maybe this should also set self.defaultStreamFilters? + self.compression = onoff + + def ensureMinPdfVersion(self, *keys): + "Ensure that the pdf version is greater than or equal to that specified by the keys" + for k in keys: + self._pdfVersion = max(self._pdfVersion, PDF_SUPPORT_VERSION[k]) + + def updateSignature(self, thing): + "add information to the signature" + if self._ID: return # but not if its used already! + self.signature.update(bytestr(thing)) + + def ID(self): + "A unique fingerprint for the file (unless in invariant mode)" + if self._ID: + return self._ID + digest = self.signature.digest() + doc = DummyDoc() + IDs = PDFString(digest,enc='raw').format(doc) + self._ID = (b'\r\n % ReportLab generated PDF document -- digest (http://www.reportlab.com)\r\n [' + +IDs+b' '+IDs+b']\r\n') + return self._ID + + def SaveToFile(self, filename, canvas): + if hasattr(getattr(filename, "write",None),'__call__'): + myfile = 0 + f = filename + filename = makeFileName(getattr(filename,'name','')) + else : + myfile = 1 + filename = makeFileName(filename) + f = open(filename, "wb") + data = self.GetPDFData(canvas) + if isUnicode(data): + data = data.encode('latin1') + f.write(data) + if myfile: + f.close() + import os + if os.name=='mac': + from reportlab.lib.utils import markfilename + markfilename(filename) # do platform specific file junk + if getattr(canvas,'_verbosity',None): print('saved %s' % (filename,)) + + def GetPDFData(self, canvas): + # realize delayed fonts + for fnt in self.delayedFonts: + fnt.addObjects(self) + # add info stuff to signature + self.info.invariant = self.invariant + self.info.digest(self.signature) + ### later: maybe add more info to sig? + # prepare outline + self.Reference(self.Catalog) + self.Reference(self.info) + outline = self.outline + outline.prepare(self, canvas) + return self.format() + + def inPage(self): + """specify the current object as a page (enables reference binding and other page features)""" + if self.inObject is not None: + if self.inObject=="page": return + raise ValueError("can't go in page already in object %s" % self.inObject) + self.inObject = "page" + + def inForm(self): + """specify that we are in a form xobject (disable page features, etc)""" + # don't need this check anymore since going in a form pushes old context at canvas level. + #if self.inObject not in ["form", None]: + # raise ValueError("can't go in form already in object %s" % self.inObject) + self.inObject = "form" + # don't need to do anything else, I think... + + def getInternalFontName(self, psfontname): + fm = self.fontMapping + if psfontname in fm: + return fm[psfontname] + else: + try: + # does pdfmetrics know about it? if so, add + fontObj = pdfmetrics.getFont(psfontname) + if fontObj._dynamicFont: + raise PDFError("getInternalFontName(%s) called for a dynamic font" % repr(psfontname)) + fontObj.addObjects(self) + #self.addFont(fontObj) + return fm[psfontname] + except KeyError: + raise PDFError("Font %s not known!" % repr(psfontname)) + + def thisPageName(self): + return "Page"+repr(self.pageCounter) + + def thisPageRef(self): + return PDFObjectReference(self.thisPageName()) + + def addPage(self, page): + name = self.thisPageName() + self.Reference(page, name) + self.Pages.addPage(page) + self.pageCounter += 1 + self.inObject = None + + def addForm(self, name, form): + """add a Form XObject.""" + # XXX should check that name is a legal PDF name + if self.inObject != "form": + self.inForm() + self.Reference(form, xObjectName(name)) + self.inObject = None + + def annotationName(self, externalname): + return "Annot.%s"%externalname + + def addAnnotation(self, name, annotation): + self.Reference(annotation, self.annotationName(name)) + + def refAnnotation(self, name): + internalname = self.annotationName(name) + return PDFObjectReference(internalname) + + def addShading(self, shading): + name = "Sh%d" % self.shadingCounter + self.Reference(shading, name) + self.shadingCounter += 1 + return name + + def addColor(self,cmyk): + sname = cmyk.spotName + if not sname: + if cmyk.cyan==0 and cmyk.magenta==0 and cmyk.yellow==0: + sname = 'BLACK' + elif cmyk.black==0 and cmyk.magenta==0 and cmyk.yellow==0: + sname = 'CYAN' + elif cmyk.cyan==0 and cmyk.black==0 and cmyk.yellow==0: + sname = 'MAGENTA' + elif cmyk.cyan==0 and cmyk.magenta==0 and cmyk.black==0: + sname = 'YELLOW' + if not sname: + raise ValueError("CMYK colour %r used without a spotName" % cmyk) + else: + cmyk = cmyk.clone(spotName = sname) + name = PDFName(sname)[1:] + if name not in self.idToObject: + sep = PDFSeparationCMYKColor(cmyk).value() #PDFArray([/Separation /name /DeviceCMYK tint_tf]) + self.Reference(sep,name) + return name,sname + + def setTitle(self, title): + "embeds in PDF file" + if title is None: + self.info.title = '(anonymous)' + else: + self.info.title = title + + def setAuthor(self, author): + "embedded in PDF file" + #allow resetting to clear it + if author is None: + self.info.author = '(anonymous)' + else: + self.info.author = author + + def setSubject(self, subject): + "embeds in PDF file" + + #allow resetting to clear it + if subject is None: + self.info.subject = '(unspecified)' + else: + self.info.subject = subject + + def setCreator(self, creator): + "embeds in PDF file" + + #allow resetting to clear it + if creator is None: + self.info.creator = '(unspecified)' + else: + self.info.creator = creator + + def setKeywords(self, keywords): + "embeds a string containing keywords in PDF file" + + #allow resetting to clear it but ensure it's a string + if keywords is None: + self.info.keywords = '' + else: + self.info.keywords = keywords + + def setDateFormatter(self, dateFormatter): + self.info._dateFormatter = dateFormatter + + def getAvailableFonts(self): + fontnames = list(self.fontMapping.keys()) + # the standard 14 are also always available! (even if not initialized yet) + from reportlab.pdfbase import _fontdata + for name in _fontdata.standardFonts: + if name not in fontnames: + fontnames.append(name) + fontnames.sort() + return fontnames + + def format(self): + # register the Catalog/INfo and then format the objects one by one until exhausted + # (possible infinite loop if there is a bug that continually makes new objects/refs...) + # Prepare encryption + self.encrypt.prepare(self) + cat = self.Catalog + info = self.info + self.Reference(self.Catalog) + self.Reference(self.info) + # register the encryption dictionary if present + encryptref = None + encryptinfo = self.encrypt.info() + if encryptinfo: + encryptref = self.Reference(encryptinfo) + # make std fonts (this could be made optional + counter = 0 # start at first object (object 1 after preincrement) + ids = [] # the collection of object ids in object number order + numbertoid = self.numberToId + idToNV = self.idToObjectNumberAndVersion + idToOb = self.idToObject + idToOf = self.idToOffset + ### note that new entries may be "appended" DURING FORMATTING + done = None + # __accum__ allows objects to know where they are in the file etc etc + self.__accum__ = File = PDFFile(self._pdfVersion) # output collector + while done is None: + counter += 1 # do next object... + if counter in numbertoid: + id = numbertoid[counter] + #printidToOb + obj = idToOb[id] + IO = PDFIndirectObject(id, obj) + # register object number and version + #encrypt.register(id, + IOf = IO.format(self) + # add a comment to the PDF output + if not rl_config.invariant and rl_config.pdfComments: + try: + classname = obj.__class__.__name__ + except: + classname = ascii(obj) + File.add("%% %s: class %s \r\n" % (ascii(id), classname[:50])) + offset = File.add(IOf) + idToOf[id] = offset + ids.append(id) + else: + done = 1 + del self.__accum__ + # sanity checks (must happen AFTER formatting) + lno = len(numbertoid) + if counter-1!=lno: + raise ValueError("counter %s doesn't match number to id dictionary %s" %(counter, lno)) + # now add the xref + xref = PDFCrossReferenceTable() + xref.addsection(0, ids) + xreff = xref.format(self) + xrefoffset = File.add(xreff) + # now add the trailer + trailer = PDFTrailer( + startxref = xrefoffset, + Size = lno+1, + Root = self.Reference(cat), + Info = self.Reference(info), + Encrypt = encryptref, + ID = self.ID(), + ) + trailerf = trailer.format(self) + File.add(trailerf) + for ds in getattr(self,'_digiSigs',[]): + ds.sign(File) + # return string format for pdf file + return File.format(self) + + def hasForm(self, name): + """test for existence of named form""" + internalname = xObjectName(name) + return internalname in self.idToObject + + def getFormBBox(self, name, boxType="MediaBox"): + """get the declared bounding box of the form as a list. + If you specify a different PDF box definition (e.g. the + ArtBox) and it has one, that's what you'll get.""" + internalname = xObjectName(name) + if internalname in self.idToObject: + theform = self.idToObject[internalname] + if hasattr(theform,'_extra_pageCatcher_info'): + return theform._extra_pageCatcher_info[boxType] + if isinstance(theform, PDFFormXObject): + # internally defined form + return theform.BBoxList() + elif isinstance(theform, PDFStream): + # externally defined form + return list(theform.dictionary.dict[boxType].sequence) + else: + raise ValueError("I don't understand the form instance %s" % repr(name)) + + def getXObjectName(self, name): + """Lets canvas find out what form is called internally. + Never mind whether it is defined yet or not.""" + return xObjectName(name) + + def xobjDict(self, formnames): + """construct an xobject dict (for inclusion in a resource dict, usually) + from a list of form names (images not yet supported)""" + D = {} + for name in formnames: + internalname = xObjectName(name) + reference = PDFObjectReference(internalname) + D[internalname] = reference + #print "xobjDict D", D + return PDFDictionary(D) + + def Reference(self, obj, name=None): + ### note references may "grow" during the final formatting pass: don't use d.keys()! + # don't make references to other references, or non instances, unless they are named! + iob = isinstance(obj,PDFObject) + idToObject = self.idToObject + if name is None and (not iob or obj.__class__ is PDFObjectReference): + return obj + if hasattr(obj, __InternalName__): + # already registered + intname = obj.__InternalName__ + if name is not None and name!=intname: + raise ValueError("attempt to reregister object %s with new name %s" % ( + repr(intname), repr(name))) + if intname not in idToObject: + raise ValueError("object of type %s named as %s, but not registered" % (type(obj),ascii(intname))) + return PDFObjectReference(intname) + # otherwise register the new object + objectcounter = self.objectcounter = self.objectcounter+1 + if name is None: + name = "R"+repr(objectcounter) + if name in idToObject: + other = idToObject[name] + if other!=obj: + raise ValueError("redefining named object: "+repr(name)) + return PDFObjectReference(name) + if iob: + obj.__InternalName__ = name + #print "name", name, "counter", objectcounter + self.idToObjectNumberAndVersion[name] = (objectcounter, 0) + self.numberToId[objectcounter] = name + idToObject[name] = obj + return PDFObjectReference(name) + +### chapter 4 Objects +PDFtrue = "true" +PDFfalse = "false" +PDFnull = "null" + +class PDFText(PDFObject): + def __init__(self, t): + self.t = t + def format(self, document): + t = self.t + if isUnicode(t): + t = t.encode('utf-8') + result = binascii.hexlify(document.encrypt.encode(t)) + return b"<" + result + b">" + def __str__(self): + dummydoc = DummyDoc() + return self.format(dummydoc) + +def PDFnumber(n): + return n + +import re +_re_cleanparens=re.compile('[^()]') +del re +def _isbalanced(s): + '''test whether a string is balanced in parens''' + s = _re_cleanparens.sub('',s) + n = 0 + for c in s: + if c=='(': n+=1 + else: + n -= 1 + if n<0: return 0 + return not n and 1 or 0 + +def _checkPdfdoc(utext): + '''return true if no Pdfdoc encoding errors''' + try: + utext.encode('pdfdoc') + return 1 + except UnicodeEncodeError as e: + return 0 + +class PDFString(PDFObject): + def __init__(self, s, escape=1, enc='auto'): + '''s can be unicode/utf8 or a PDFString + if escape is true then the output will be passed through escape + if enc is raw then the string will be left alone + if enc is auto we'll try and automatically adapt to utf_16_be if the + effective string is not entirely in pdfdoc + ''' + if isinstance(s,PDFString): + self.s = s.s + self.escape = s.escape + self.enc = s.enc + else: + self.s = s + self.escape = escape + self.enc = enc + def format(self, document): + s = self.s + enc = getattr(self,'enc','auto') + if (isBytes(s)): + if enc is 'auto': + try: + u = s.decode(s.startswith(codecs.BOM_UTF16_BE) and 'utf16' or 'utf8') + if _checkPdfdoc(u): + s = u.encode('pdfdoc') + else: + s = codecs.BOM_UTF16_BE+u.encode('utf_16_be') + except: + try: + s.decode('pdfdoc') + except: + stderr.write('Error in %s' % (repr(s),)) + raise + elif isUnicode(s): + if enc is 'auto': + if _checkPdfdoc(s): + s = s.encode('pdfdoc') + else: + s = codecs.BOM_UTF16_BE+s.encode('utf_16_be') + else: + s = codecs.BOM_UTF16_BE+s.encode('utf_16_be') + else: + raise ValueError('PDFString argument must be str/unicode not %s' % type(s)) + + escape = getattr(self,'escape',1) + if not isinstance(document.encrypt,NoEncryption): + s = document.encrypt.encode(s) + escape = 1 + if escape: + try: + es = "(%s)" % escapePDF(s) + except: + raise ValueError("cannot escape %s %s" % (s, repr(s))) + if escape&2: + es = es.replace('\\012','\n') + if escape&4 and _isbalanced(es): + es = es.replace('\\(','(').replace('\\)',')') + return pdfdocEnc(es) + else: + return b'(' + s + b')' + + def __str__(self): + return "(%s)" % escapePDF(self.s) + +def PDFName(data,lo=chr(0x21),hi=chr(0x7e)): + # might need to change this to class for encryption + # NOTE: RESULT MUST ALWAYS SUPPORT MEANINGFUL COMPARISONS (EQUALITY) AND HASH + # first convert the name + L = list(data) + for i,c in enumerate(L): + if chi or c in "%()<>{}[]#": + L[i] = "#"+hex(ord(c))[2:] # forget the 0x thing... + return "/"+(''.join(L)) + +class PDFDictionary(PDFObject): + multiline = True + def __init__(self, dict=None): + """dict should be namestring to value eg "a": 122 NOT pdfname to value NOT "/a":122""" + if dict is None: + self.dict = {} + else: + self.dict = dict.copy() + def __setitem__(self, name, value): + self.dict[name] = value + def __getitem__(self, a): + return self.dict[a] + def __contains__(self,a): + return a in self.dict + def Reference(self, name, document): + self.dict[name] = document.Reference(self.dict[name]) + def format(self, document,IND=b'\r\n '): + dict = self.dict + try: + keys = list(dict.keys()) + except: + print(ascii(dict)) + raise + if not isinstance(dict,OrderedDict): keys.sort() + L = [(format(PDFName(k),document)+b" "+format(dict[k],document)) for k in keys] + if self.multiline and rl_config.pdfMultiLine: + L = IND.join(L) + else: + # break up every 6 elements anyway + t=L.insert + for i in reversed(range(6, len(L), 6)): + t(i,b'\r\n ') + L = b" ".join(L) + return b'<< '+L+b' >>' + + def copy(self): + return PDFDictionary(self.dict) + + def normalize(self): + #normalize the names to use RL standard ie Name not /Name + D = self.dict + K = [k for k in D.keys() if k.startswith('/')] + for k in K: + D[k[1:]] = D.pop(k) + +class checkPDFNames: + def __init__(self,*names): + self.names = list(map(PDFName,names)) + def __call__(self,value): + if not value.startswith('/'): + value=PDFName(value) + if value in self.names: + return value + +def checkPDFBoolean(value): + if value in ('true','false'): return value + +class CheckedPDFDictionary(PDFDictionary): + validate = {} + def __init__(self,dict=None,validate=None): + PDFDictionary.__init__(self,dict) + if validate: self.validate = validate + + def __setitem__(self,name,value): + if name not in self.validate: + raise ValueError('invalid key, %r' % name) + cvalue = self.validate[name](value) + if cvalue is None: + raise ValueError('Bad value %r for key %r' % (value,name)) + PDFDictionary.__setitem__(self,name,cvalue) + +class ViewerPreferencesPDFDictionary(CheckedPDFDictionary): + validate=dict( + HideToolbar=checkPDFBoolean, + HideMenubar=checkPDFBoolean, + HideWindowUI=checkPDFBoolean, + FitWindow=checkPDFBoolean, + CenterWindow=checkPDFBoolean, + DisplayDocTitle=checkPDFBoolean, #contributed by mark Erbaugh + NonFullScreenPageMode=checkPDFNames(*'UseNone UseOutlines UseThumbs UseOC'.split()), + Direction=checkPDFNames(*'L2R R2L'.split()), + ViewArea=checkPDFNames(*'MediaBox CropBox BleedBox TrimBox ArtBox'.split()), + ViewClip=checkPDFNames(*'MediaBox CropBox BleedBox TrimBox ArtBox'.split()), + PrintArea=checkPDFNames(*'MediaBox CropBox BleedBox TrimBox ArtBox'.split()), + PrintClip=checkPDFNames(*'MediaBox CropBox BleedBox TrimBox ArtBox'.split()), + PrintScaling=checkPDFNames(*'None AppDefault'.split()), + ) + +# stream filters are objects to support round trip and +# possibly in the future also support parameters +class PDFStreamFilterZCompress: + pdfname = "FlateDecode" + def encode(self, text): + from reportlab.lib.utils import import_zlib + zlib = import_zlib() + if not zlib: raise ImportError("cannot z-compress zlib unavailable") + if isUnicode(text): + text = text.encode('utf8') + return zlib.compress(text) + def decode(self, encoded): + from reportlab.lib.utils import import_zlib + zlib = import_zlib() + if not zlib: raise ImportError("cannot z-decompress zlib unavailable") + return zlib.decompress(encoded) + +# need only one of these, unless we implement parameters later +PDFZCompress = PDFStreamFilterZCompress() + +class PDFStreamFilterBase85Encode: + pdfname = "ASCII85Decode" + def encode(self, text): + from reportlab.pdfbase.pdfutils import _wrap + text = asciiBase85Encode(text) + if rl_config.wrapA85: + text = _wrap(text) + return text + def decode(self, text): + return asciiBase85Decode(text) + +# need only one of these too +PDFBase85Encode = PDFStreamFilterBase85Encode() + +class PDFStream(PDFObject): + '''set dictionary elements explicitly stream.dictionary[name]=value''' + ### compression stuff not implemented yet + __RefOnly__ = 1 # must be at top level + def __init__(self, dictionary=None, content=None, filters=None): + if dictionary is None: + dictionary = PDFDictionary() + self.dictionary = dictionary + self.content = content + self.filters = filters + def format(self, document): + dictionary = self.dictionary + # copy it for modification + dictionary = PDFDictionary(dictionary.dict.copy()) + content = self.content + filters = self.filters + if self.content is None: + raise ValueError("stream content not set") + if filters is None: + filters = document.defaultStreamFilters + # only apply filters if they haven't been applied elsewhere + if filters is not None and "Filter" not in dictionary.dict: + # apply filters in reverse order listed + rf = list(filters) + rf.reverse() + fnames = [] + for f in rf: + #print "*****************content:"; print repr(content[:200]) + #print "*****************filter", f.pdfname + content = f.encode(content) + fnames.insert(0, PDFName(f.pdfname)) + #print "*****************finally:"; print content[:200] + #print "****** FILTERS", fnames + #stop + dictionary["Filter"] = PDFArray(fnames) + # "stream encoding is done after all filters have been applied" + content = document.encrypt.encode(content) + fc = format(content, document) + dictionary["Length"] = len(content) + fd = format(dictionary, document) + return fd+b'\r\nstream\r\n'+fc+b'endstream\r\n' + +def teststream(content=None): + #content = "" # test + if content is None: + content = teststreamcontent + content = content.strip() + content = content.replace("\n", '\n\r') + '\n\r' + S = PDFStream(content = content, + filters=rl_config.useA85 and [PDFBase85Encode,PDFZCompress] or [PDFZCompress]) + # nothing else needed... + S.__Comment__ = "test stream" + return S + +teststreamcontent = """ +1 0 0 1 0 0 cm BT /F9 12 Tf 14.4 TL ET +1.00 0.00 1.00 rg +n 72.00 72.00 432.00 648.00 re B* +""" +class PDFArray(PDFObject): + multiline = True + def __init__(self, sequence): + self.sequence = list(sequence) + def References(self, document): + """make all objects in sequence references""" + self.sequence = list(map(document.Reference, self.sequence)) + def format(self, document, IND=b'\r\n '): + L = [format(e, document) for e in self.sequence] + if self.multiline and rl_config.pdfMultiLine: + L = IND.join(L) + else: + n=len(L) + if n>10: + # break up every 10 elements anyway + t=L.insert + for i in reversed(range(10, n, 10)): + t(i,b'\r\n ') + L = b' '.join(L) + else: + L = b' '.join(L) + return b'[ ' + L + b' ]' + +class PDFArrayCompact(PDFArray): + multiline=False + +class PDFIndirectObject(PDFObject): + __RefOnly__ = 1 + def __init__(self, name, content): + self.name = name + self.content = content + def format(self, document): + name = self.name + n, v = document.idToObjectNumberAndVersion[name] + # set encryption parameters + document.encrypt.register(n, v) + fcontent = format(self.content, document, toplevel=1) # yes this is at top level + return (pdfdocEnc("%s %s obj\r\n"%(n,v)) + +fcontent+ (b'' if fcontent.endswith(b'\r\n') else b'\r\n') + +b'endobj\r\n') + +class PDFObjectReference(PDFObject): + def __init__(self, name): + self.name = name + def format(self, document): + try: + return pdfdocEnc("%s %s R" % document.idToObjectNumberAndVersion[self.name]) + except: + raise KeyError("forward reference to %s not resolved upon final formatting" % repr(self.name)) + +class PDFFile(PDFObject): + ### just accumulates strings: keeps track of current offset + def __init__(self,pdfVersion=PDF_VERSION_DEFAULT): + self.strings = [] + self.write = self.strings.append + self.offset = 0 + ### chapter 5 + # Following Ken Lunde's advice and the PDF spec, this includes + # some high-order bytes. I chose the characters for Tokyo + # in Shift-JIS encoding, as these cannot be mistaken for + # any other encoding, and we'll be able to tell if something + # has run our PDF files through a dodgy Unicode conversion. + self.add((pdfdocEnc("%%PDF-%s.%s" % pdfVersion) + + b'\r\n%\223\214\213\236 ReportLab Generated PDF document http://www.reportlab.com\r\n' + )) + + def closeOrReset(self): + pass + + def add(self, s): + """should be constructed as late as possible, return position where placed""" + s = pdfdocEnc(s) + result = self.offset + self.offset = result+len(s) + self.write(s) + return result + + def format(self, document): + return b''.join(self.strings) + +XREFFMT = '%0.10d %0.5d n' + +class PDFCrossReferenceSubsection(PDFObject): + def __init__(self, firstentrynumber, idsequence): + self.firstentrynumber = firstentrynumber + self.idsequence = idsequence + def format(self, document): + """id sequence should represent contiguous object nums else error. free numbers not supported (yet)""" + firstentrynumber = self.firstentrynumber + idsequence = self.idsequence + entries = list(idsequence) + nentries = len(idsequence) + # special case: object number 0 is always free + taken = {} + if firstentrynumber==0: + taken[0] = "standard free entry" + nentries = nentries+1 + entries.insert(0, "0000000000 65535 f") + idToNV = document.idToObjectNumberAndVersion + idToOffset = document.idToOffset + lastentrynumber = firstentrynumber+nentries-1 + for id in idsequence: + (num, version) = idToNV[id] + if num in taken: + raise ValueError("object number collision %s %s %s" % (num, repr(id), repr(taken[id]))) + if num>lastentrynumber or num +class PDFPageLabels(PDFCatalog): + __comment__ = None + __RefOnly__ = 0 + __Defaults__ = {} + __NoDefault__ = ["Nums"] + __Refs__ = [] + + def __init__(self): + self.labels = [] + + def addPageLabel(self, page, label): + """ Adds a new PDFPageLabel to this catalog. + The 'page' argument, an integer, is the page number in the PDF document + with which the 'label' should be associated. Page numbering in the PDF + starts at zero! Thus, to change the label on the first page, '0' should be + provided as an argument, and to change the 6th page, '5' should be provided + as the argument. + + The 'label' argument should be a PDFPageLabel instance, which describes the + format of the labels starting on page 'page' in the PDF and continuing + until the next encounter of a PDFPageLabel. + + The order in which labels are added is not important. + """ + self.labels.append((page, label)) + + def format(self, document): + self.labels.sort() + labels = [] + for page, label in self.labels: + labels.append(page) + labels.append(label) + + self.Nums = PDFArray(labels) #PDFArray makes a copy with list() + return PDFCatalog.format(self, document) + +class PDFPageLabel(PDFCatalog): + __Comment__ = None + __RefOnly__ = 0 + __Defaults__ = {} + __NoDefault__ = "Type S P St".split() + __convertible__ = 'ARABIC ROMAN_UPPER ROMAN_LOWER LETTERS_UPPER LETTERS_LOWER' + + ARABIC = 'D' + ROMAN_UPPER = 'R' + ROMAN_LOWER = 'r' + LETTERS_UPPER = 'A' + LETTERS_LOWER = 'a' + + def __init__(self, style=None, start=None, prefix=None): + """ + A PDFPageLabel changes the style of page numbering as displayed in a PDF + viewer. PDF page labels have nothing to do with 'physical' page numbers + printed on a canvas, but instead influence the 'logical' page numbers + displayed by PDF viewers. However, when using roman numerals (i, ii, + iii...) or page prefixes for appendecies (A.1, A.2...) on the physical + pages PDF page labels are necessary to change the logical page numbers + displayed by the PDF viewer to match up with the physical numbers. A + PDFPageLabel changes the properties of numbering at the page on which it + appears (see the class 'PDFPageLabels' for specifying where a PDFPageLabel + is associated) and all subsequent pages, until a new PDFPageLabel is + encountered. + + The arguments to this initialiser determine the properties of all + subsequent page labels. 'style' determines the numberings style, arabic, + roman, letters; 'start' specifies the starting number; and 'prefix' any + prefix to be applied to the page numbers. All these arguments can be left + out or set to None. + + * style: + + - None: No numbering, can be used to display the prefix only. + - PDFPageLabel.ARABIC: Use arabic numbers: 1, 2, 3, 4... + - PDFPageLabel.ROMAN_UPPER: Use upper case roman numerals: I, II, III... + - PDFPageLabel.ROMAN_LOWER: Use lower case roman numerals: i, ii, iii... + - PDFPageLabel.LETTERS_UPPER: Use upper case letters: A, B, C, D... + - PDFPageLabel.LETTERS_LOWER: Use lower case letters: a, b, c, d... + + * start: + + - An integer specifying the starting number for this PDFPageLabel. This + can be used when numbering style changes to reset the page number back + to one, ie from roman to arabic, or from arabic to appendecies. Can be + any positive integer or None. I'm not sure what the effect of + specifying None is, probably that page numbering continues with the + current sequence, I'd have to check the spec to clarify though. + + * prefix: + + - A string which is prefixed to the page numbers. Can be used to display + appendecies in the format: A.1, A.2, ..., B.1, B.2, ... where a + PDFPageLabel is used to set the properties for the first page of each + appendix to restart the page numbering at one and set the prefix to the + appropriate letter for current appendix. The prefix can also be used to + display text only, if the 'style' is set to None. This can be used to + display strings such as 'Front', 'Back', or 'Cover' for the covers on + books. + + """ + if style: + if style.upper() in self.__convertible__: style = getattr(self,style.upper()) + self.S = PDFName(style) + if start: self.St = PDFnumber(start) + if prefix: self.P = PDFString(prefix) +#ends code contributed by Christian Jacobs + +def testpage(document): + P = PDFPage() + P.Contents = teststream() + pages = document.Pages + P.Parent = document.Reference(pages) + P.MediaBox = PDFArray([0, 0, 595, 841]) + resources = PDFResourceDictionary() + resources.allProcs() # enable all procsets + resources.basicFonts() + P.Resources = resources + pages.addPage(P) + +#### DUMMY OUTLINES IMPLEMENTATION FOR testing +DUMMYOUTLINE = """ +<< + /Count + 0 + /Type + /Outlines +>>""" + +class PDFOutlines0(PDFObject): + __Comment__ = "TEST OUTLINE!" + text = DUMMYOUTLINE.replace("\n", '\r\n') + __RefOnly__ = 1 + def format(self, document): + return pdfdocEnc(self.text) + +class OutlineEntryObject(PDFObject): + "an entry in an outline" + Title = Dest = Parent = Prev = Next = First = Last = Count = None + def format(self, document): + D = {} + D["Title"] = PDFString(self.Title) + D["Parent"] = self.Parent + D["Dest"] = self.Dest + for n in ("Prev", "Next", "First", "Last", "Count"): + v = getattr(self, n) + if v is not None: + D[n] = v + PD = PDFDictionary(D) + return PD.format(document) + +class PDFOutlines(PDFObject): + """ + takes a recursive list of outline destinations like:: + + out = PDFOutline1() + out.setNames(canvas, # requires canvas for name resolution + "chapter1dest", + ("chapter2dest", + ["chapter2section1dest", + "chapter2section2dest", + "chapter2conclusiondest"] + ), # end of chapter2 description + "chapter3dest", + ("chapter4dest", ["c4s1", "c4s2"]) + ) + + Higher layers may build this structure incrementally. KISS at base level. + """ + # first attempt, many possible features missing. + #no init for now + mydestinations = ready = None + counter = 0 + currentlevel = -1 # ie, no levels yet + + def __init__(self): + self.destinationnamestotitles = {} + self.destinationstotitles = {} + self.levelstack = [] + self.buildtree = [] + self.closedict = {} # dictionary of "closed" destinations in the outline + + def addOutlineEntry(self, destinationname, level=0, title=None, closed=None): + """destinationname of None means "close the tree" """ + if destinationname is None and level!=0: + raise ValueError("close tree must have level of 0") + if not isinstance(level,int): raise ValueError("level must be integer, got %s" % type(level)) + if level<0: raise ValueError("negative levels not allowed") + if title is None: title = destinationname + currentlevel = self.currentlevel + stack = self.levelstack + tree = self.buildtree + # adjust currentlevel and stack to match level + if level>currentlevel: + if level>currentlevel+1: + raise ValueError("can't jump from outline level %s to level %s, need intermediates (destinationname=%r, title=%r)" %(currentlevel, level, destinationname, title)) + level = currentlevel = currentlevel+1 + stack.append([]) + while levelref + if isSeq(object): + L = [] + for o in object: + L.append(self.translateNames(canvas, o)) + if isinstance(object,tuple): + return tuple(L) + return L + # bug contributed by Benjamin Dumke + raise TypeError("in outline, destination name must be string: got a %s"%type(object)) + + def prepare(self, document, canvas): + """prepare all data structures required for save operation (create related objects)""" + if self.mydestinations is None: + if self.levelstack: + self.addOutlineEntry(None) # close the tree + destnames = self.levelstack[0] + #from pprint import pprint; pprint(destnames); stop + self.mydestinations = self.translateNames(canvas, destnames) + else: + self.first = self.last = None + self.count = 0 + self.ready = 1 + return + #self.first = document.objectReference("Outline.First") + #self.last = document.objectReference("Outline.Last") + # XXXX this needs to be generalized for closed entries! + self.count = count(self.mydestinations, self.closedict) + (self.first, self.last) = self.maketree(document, self.mydestinations, toplevel=1) + self.ready = 1 + + def maketree(self, document, destinationtree, Parent=None, toplevel=0): + if toplevel: + levelname = "Outline" + Parent = document.Reference(document.Outlines) + else: + self.count = self.count+1 + levelname = "Outline.%s" % self.count + if Parent is None: + raise ValueError("non-top level outline elt parent must be specified") + if not isSeq(destinationtree): + raise ValueError("destinationtree must be list or tuple, got %s") + nelts = len(destinationtree) + lastindex = nelts-1 + lastelt = firstref = lastref = None + destinationnamestotitles = self.destinationnamestotitles + closedict = self.closedict + for index in range(nelts): + eltobj = OutlineEntryObject() + eltobj.Parent = Parent + eltname = "%s.%s" % (levelname, index) + eltref = document.Reference(eltobj, eltname) + #document.add(eltname, eltobj) + if lastelt is not None: + lastelt.Next = eltref + eltobj.Prev = lastref + if firstref is None: + firstref = eltref + lastref = eltref + lastelt = eltobj # advance eltobj + lastref = eltref + elt = destinationtree[index] + if isinstance(elt,dict): + # simple leaf {name: dest} + leafdict = elt + elif isinstance(elt,tuple): + # leaf with subsections: ({name: ref}, subsections) XXXX should clean up (see count(...)) + try: + (leafdict, subsections) = elt + except: + raise ValueError("destination tree elt tuple should have two elts, got %s" % len(elt)) + eltobj.Count = count(subsections, closedict) + (eltobj.First, eltobj.Last) = self.maketree(document, subsections, eltref) + else: + raise ValueError("destination tree elt should be dict or tuple, got %s" % type(elt)) + try: + [(Title, Dest)] = list(leafdict.items()) + except: + raise ValueError("bad outline leaf dictionary, should have one entry "+bytestr(elt)) + eltobj.Title = destinationnamestotitles[Title] + eltobj.Dest = Dest + if isinstance(elt,tuple) and Dest in closedict: + # closed subsection, count should be negative + eltobj.Count = -eltobj.Count + return (firstref, lastref) + +def count(tree, closedict=None): + """utility for outline: recursively count leaves in a tuple/list tree""" + from operator import add + if isinstance(tree,tuple): + # leaf with subsections XXXX should clean up this structural usage + (leafdict, subsections) = tree + [(Title, Dest)] = list(leafdict.items()) + if closedict and Dest in closedict: + return 1 # closed tree element + if isSeq(tree): + #return reduce(add, map(count, tree)) + counts = [] + for e in tree: + counts.append(count(e, closedict)) + return sum(counts) #used to be: return reduce(add, counts) + return 1 + +class PDFInfo(PDFObject): + """PDF documents can have basic information embedded, viewable from + File | Document Info in Acrobat Reader. If this is wrong, you get + Postscript errors while printing, even though it does not print.""" + producer = "ReportLab PDF Library - www.reportlab.com" + creator = "ReportLab PDF Library - www.reportlab.com" + title = "untitled" + author = "anonymous" + subject = "unspecified" + keywords = "" + _dateFormatter = None + + def __init__(self): + self.invariant = rl_config.invariant + + def digest(self, md5object): + # add self information to signature + for x in (self.title, self.author, self.subject, self.keywords): + md5object.update(bytestr(x)) + + def format(self, document): + D = {} + D["Title"] = PDFString(self.title) + D["Author"] = PDFString(self.author) + D["CreationDate"] = PDFDate(invariant=self.invariant,dateFormatter=self._dateFormatter) + D["Producer"] = PDFString(self.producer) + D["Creator"] = PDFString(self.creator) + D["Subject"] = PDFString(self.subject) + D["Keywords"] = PDFString(self.keywords) + + PD = PDFDictionary(D) + return PD.format(document) + + def copy(self): + "shallow copy - useful in pagecatchering" + thing = self.__klass__() + for k, v in self.__dict__.items(): + setattr(thing, k, v) + return thing +# skipping thumbnails, etc + +class Annotation(PDFObject): + """superclass for all annotations.""" + defaults = [("Type", PDFName("Annot"),)] + required = ("Type", "Rect", "Contents", "Subtype") + permitted = required+( + "Border", "C", "T", "M", "F", "H", "BS", "AA", "AS", "Popup", "P", "AP") + def cvtdict(self, d, escape=1): + """transform dict args from python form to pdf string rep as needed""" + Rect = d["Rect"] + if not isStr(Rect): + d["Rect"] = PDFArray(Rect) + d["Contents"] = PDFString(d["Contents"],escape) + return d + def AnnotationDict(self, **kw): + if 'escape' in kw: + escape = kw['escape'] + del kw['escape'] + else: + escape = 1 + d = {} + for (name,val) in self.defaults: + d[name] = val + d.update(kw) + for name in self.required: + if name not in d: + raise ValueError("keyword argument %s missing" % name) + d = self.cvtdict(d,escape=escape) + permitted = self.permitted + for name in d.keys(): + if name not in permitted: + raise ValueError("bad annotation dictionary name %s" % name) + return PDFDictionary(d) + def Dict(self): + raise ValueError("DictString undefined for virtual superclass Annotation, must overload") + # but usually + #return self.AnnotationDict(self, Rect=(a,b,c,d)) or whatever + def format(self, document): + D = self.Dict() + return D.format(document) + +class TextAnnotation(Annotation): + permitted = Annotation.permitted + ( + "Open", "Name") + def __init__(self, Rect, Contents, **kw): + self.Rect = Rect + self.Contents = Contents + self.otherkw = kw + def Dict(self): + d = {} + d.update(self.otherkw) + d["Rect"] = self.Rect + d["Contents"] = self.Contents + d["Subtype"] = "/Text" + return self.AnnotationDict(**d) + +class FreeTextAnnotation(Annotation): + permitted = Annotation.permitted + ("DA",) + def __init__(self, Rect, Contents, DA, **kw): + self.Rect = Rect + self.Contents = Contents + self.DA = DA + self.otherkw = kw + def Dict(self): + d = {} + d.update(self.otherkw) + d["Rect"] = self.Rect + d["Contents"] = self.Contents + d["DA"] = self.DA + d["Subtype"] = "/FreeText" + return self.AnnotationDict(**d) + +class LinkAnnotation(Annotation): + + permitted = Annotation.permitted + ( + "Dest", "A", "PA") + def __init__(self, Rect, Contents, Destination, Border="[0 0 1]", **kw): + self.Border = Border + self.Rect = Rect + self.Contents = Contents + self.Destination = Destination + self.otherkw = kw + + def dummyDictString(self): # old, testing + return """ + << /Type /Annot /Subtype /Link /Rect [71 717 190 734] /Border [16 16 1] + /Dest [23 0 R /Fit] >> + """ + + def Dict(self): + d = {} + d.update(self.otherkw) + d["Border"] = self.Border + d["Rect"] = self.Rect + d["Contents"] = self.Contents + d["Subtype"] = "/Link" + d["Dest"] = self.Destination + return self.AnnotationDict(**d) + +class HighlightAnnotation(Annotation): + """ + HighlightAnnotation is an annotation that highlights the selected area. + + Rect is the mouseover area that will show the contents. + + QuadPoints is a list of points to highlight, you can have many groups of + four QuadPoints to allow highlighting many lines. + """ + permitted = Annotation.permitted + ("QuadPoints", ) + + def __init__(self, Rect, Contents, QuadPoints, Color=[0.83, 0.89, 0.95], **kw): + self.Rect = Rect + self.Contents = Contents + self.otherkw = kw + self.QuadPoints = QuadPoints + self.Color = Color + + def cvtdict(self, d, escape=1): + """transform dict args from python form to pdf string rep as needed""" + Rect = d["Rect"] + Quad = d["QuadPoints"] + Color = d["C"] + if not isinstance(Rect, str): + d["Rect"] = PDFArray(Rect).format(d, IND=b" ") + if not isinstance(Quad, str): + d["QuadPoints"] = PDFArray(Quad).format(d, IND=b" ") + if not isinstance(Color, str): + d["C"] = PDFArray(Color).format(d, IND=b" ") + d["Contents"] = PDFString(d["Contents"], escape) + return d + + def Dict(self): + d = {} + d.update(self.otherkw) + d["Rect"] = self.Rect + d["Contents"] = self.Contents + d["Subtype"] = "/Highlight" + d["QuadPoints"] = self.QuadPoints + d["C"] = self.Color + return self.AnnotationDict(**d) + + +def rect_to_quad(Rect): + """ + Utility method to convert a Rect to a QuadPoint + """ + return [Rect[0], Rect[1], Rect[2], Rect[1], + Rect[0], Rect[3], Rect[2], Rect[3]] + +# skipping names tree +# skipping actions +# skipping names trees +# skipping to chapter 7 + +class PDFRectangle(PDFObject): + def __init__(self, llx, lly, urx, ury): + self.llx, self.lly, self.ulx, self.ury = llx, lly, urx, ury + def format(self, document): + A = PDFArray([self.llx, self.lly, self.ulx, self.ury]) + return format(A, document) + +_NOWT=None +def _getTimeStamp(): + global _NOWT + if not _NOWT: + import time + _NOWT = time.time() + return _NOWT + +class PDFDate(PDFObject): + # gmt offset now suppported properly + def __init__(self, invariant=rl_config.invariant, dateFormatter=None): + if invariant: + now = (2000,1,1,0,0,0,0) + self.dhh = 0 + self.dmm = 0 + else: + import time + now = tuple(time.localtime(_getTimeStamp())[:6]) + from time import timezone + self.dhh = int(timezone / (3600.0)) + self.dmm = (timezone % 3600) % 60 + self.date = now[:6] + self.dateFormatter = dateFormatter + + def format(self, doc): + dfmt = self.dateFormatter or ( + lambda yyyy,mm,dd,hh,m,s: + "D:%04d%02d%02d%02d%02d%02d%+03d'%02d'" + % (yyyy,mm,dd,hh,m,s,self.dhh,self.dmm)) + return format(PDFString(dfmt(*self.date)), doc) + +class Destination(PDFObject): + """ + + not a PDFObject! This is a placeholder that can delegates + to a pdf object only after it has been defined by the methods + below. + + EG a Destination can refer to Appendix A before it has been + defined, but only if Appendix A is explicitly noted as a destination + and resolved before the document is generated... + + For example the following sequence causes resolution before doc generation. + d = Destination() + d.fit() # or other format defining method call + d.setPage(p) + (at present setPageRef is called on generation of the page). + """ + representation = format = page = None + def __init__(self,name): + self.name = name + self.fmt = self.page = None + def format(self, document): + f = self.fmt + if f is None: raise ValueError("format not resolved %s" % self.name) + p = self.page + if p is None: raise ValueError("Page reference unbound %s" % self.name) + f.page = p + return f.format(document) + def xyz(self, left, top, zoom): # see pdfspec mar 11 99 pp184+ + self.fmt = PDFDestinationXYZ(None, left, top, zoom) + def fit(self): + self.fmt = PDFDestinationFit(None) + def fitb(self): + self.fmt = PDFDestinationFitB(None) + def fith(self, top): + self.fmt = PDFDestinationFitH(None,top) + def fitv(self, left): + self.fmt = PDFDestinationFitV(None, left) + def fitbh(self, top): + self.fmt = PDFDestinationFitBH(None, top) + def fitbv(self, left): + self.fmt = PDFDestinationFitBV(None, left) + def fitr(self, left, bottom, right, top): + self.fmt = PDFDestinationFitR(None, left, bottom, right, top) + def setPage(self, page): + self.page = page + #self.fmt.page = page # may not yet be defined! + +class PDFDestinationXYZ(PDFObject): + typename = "XYZ" + def __init__(self, page, left, top, zoom): + self.page = page + self.top = top + self.zoom = zoom + self.left = left + def format(self, document): + pageref = document.Reference(self.page) + A = PDFArray( [ pageref, PDFName(self.typename), self.left, self.top, self.zoom ] ) + return format(A, document) + +class PDFDestinationFit(PDFObject): + typename = "Fit" + def __init__(self, page): + self.page = page + def format(self, document): + pageref = document.Reference(self.page) + A = PDFArray( [ pageref, PDFName(self.typename) ] ) + return format(A, document) + +class PDFDestinationFitB(PDFDestinationFit): + typename = "FitB" + +class PDFDestinationFitH(PDFObject): + typename = "FitH" + def __init__(self, page, top): + self.page = page; self.top=top + def format(self, document): + pageref = document.Reference(self.page) + A = PDFArray( [ pageref, PDFName(self.typename), self.top ] ) + return format(A, document) + +class PDFDestinationFitBH(PDFDestinationFitH): + typename = "FitBH" + +class PDFDestinationFitV(PDFObject): + typename = "FitV" + def __init__(self, page, left): + self.page = page; self.left=left + def format(self, document): + pageref = document.Reference(self.page) + A = PDFArray( [ pageref, PDFName(self.typename), self.left ] ) + return format(A, document) + +class PDFDestinationFitBV(PDFDestinationFitV): + typename = "FitBV" + +class PDFDestinationFitR(PDFObject): + typename = "FitR" + def __init__(self, page, left, bottom, right, top): + self.page = page; self.left=left; self.bottom=bottom; self.right=right; self.top=top + def format(self, document): + pageref = document.Reference(self.page) + A = PDFArray( [ pageref, PDFName(self.typename), self.left, self.bottom, self.right, self.top] ) + return format(A, document) + +# named destinations need nothing + +# skipping filespecs + +class PDFResourceDictionary(PDFObject): + """each element *could* be reset to a reference if desired""" + def __init__(self): + self.ColorSpace = {} + self.XObject = {} + self.ExtGState = {} + self.Font = {} + self.Pattern = {} + self.ProcSet = [] + self.Properties = {} + self.Shading = {} + # ?by default define the basicprocs + self.basicProcs() + stdprocs = [PDFName(s) for s in "PDF Text ImageB ImageC ImageI".split()] + dict_attributes = ("ColorSpace", "XObject", "ExtGState", "Font", "Pattern", "Properties", "Shading") + + def allProcs(self): + # define all standard procsets + self.ProcSet = self.stdprocs + + def basicProcs(self): + self.ProcSet = self.stdprocs[:2] # just PDF and Text + + def basicFonts(self): + self.Font = PDFObjectReference(BasicFonts) + + def setColorSpace(self,colorsUsed): + for c,s in colorsUsed.items(): + self.ColorSpace[s] = PDFObjectReference(c) + + def setShading(self,shadingUsed): + for c,s in shadingUsed.items(): + self.Shading[s] = PDFObjectReference(c) + + def format(self, document): + D = {} + for dname in self.dict_attributes: + v = getattr(self, dname) + if isinstance(v,dict): + if v: + dv = PDFDictionary(v) + D[dname] = dv + else: + D[dname] = v + v = self.ProcSet + dname = "ProcSet" + if isSeq(v): + if v: + dv = PDFArray(v) + D[dname] = dv + else: + D[dname] = v + DD = PDFDictionary(D) + return format(DD, document) + +############################################################################## +# +# Font objects - the PDFDocument.addFont() method knows which of these +# to construct when given a user-facing Font object +# +############################################################################## +class PDFType1Font(PDFObject): + """no init: set attributes explicitly""" + __RefOnly__ = 1 + # note! /Name appears to be an undocumented attribute.... + name_attributes = "Type Subtype BaseFont Name".split() + Type = "Font" + Subtype = "Type1" + # these attributes are assumed to already be of the right type + local_attributes = "FirstChar LastChar Widths Encoding ToUnicode FontDescriptor".split() + def format(self, document): + D = {} + for name in self.name_attributes: + if hasattr(self, name): + value = getattr(self, name) + D[name] = PDFName(value) + for name in self.local_attributes: + if hasattr(self, name): + value = getattr(self, name) + D[name] = value + #print D + PD = PDFDictionary(D) + return PD.format(document) + +## These attribute listings will be useful in future, even if we +## put them elsewhere + +class PDFTrueTypeFont(PDFType1Font): + Subtype = "TrueType" + #local_attributes = "FirstChar LastChar Widths Encoding ToUnicode FontDescriptor".split() #same + +##class PDFMMType1Font(PDFType1Font): +## Subtype = "MMType1" +## +##class PDFType3Font(PDFType1Font): +## Subtype = "Type3" +## local_attributes = "FirstChar LastChar Widths CharProcs FontBBox FontMatrix Resources Encoding".split() +## +##class PDFType0Font(PDFType1Font): +## Subtype = "Type0" +## local_attributes = "DescendantFonts Encoding".split( +## +##class PDFCIDFontType0(PDFType1Font): +## Subtype = "CIDFontType0" +## local_attributes = "CIDSystemInfo FontDescriptor DW W DW2 W2 Registry Ordering Supplement".split() +## +##class PDFCIDFontType0(PDFType1Font): +## Subtype = "CIDFontType2" +## local_attributes = "BaseFont CIDToGIDMap CIDSystemInfo FontDescriptor DW W DW2 W2".split() +## +##class PDFEncoding(PDFType1Font): +## Type = "Encoding" +## name_attributes = "Type BaseEncoding".split() +## # these attributes are assumed to already be of the right type +## local_attributes = ["Differences"] +## + +# UGLY ALERT - this needs turning into something O-O, it was hacked +# across from the pdfmetrics.Encoding class to avoid circularity + +# skipping CMaps + +class PDFFormXObject(PDFObject): + # like page requires .info set by some higher level (doc) + # XXXX any resource used in a form must be propagated up to the page that (recursively) uses + # the form!! (not implemented yet). + XObjects = Annots = BBox = Matrix = Contents = stream = Resources = None + hasImages = 1 # probably should change + compression = 0 + def __init__(self, lowerx, lowery, upperx, uppery): + #not done + self.lowerx = lowerx; self.lowery=lowery; self.upperx=upperx; self.uppery=uppery + + def setStreamList(self, data): + if isSeq(data): + data = '\r\n'.join(data) + self.stream = pdfdocEnc(data) + + def BBoxList(self): + "get the declared bounding box for the form as a list" + if self.BBox: + return list(self.BBox.sequence) + else: + return [self.lowerx, self.lowery, self.upperx, self.uppery] + + def format(self, document): + self.BBox = self.BBox or PDFArray([self.lowerx, self.lowery, self.upperx, self.uppery]) + self.Matrix = self.Matrix or PDFArray([1, 0, 0, 1, 0, 0]) + if not self.Annots: + self.Annots = None + else: + #these must be transferred to the page when the form is used + raise ValueError("annotations don't work in PDFFormXObjects yet") + if not self.Contents: + stream = self.stream + if not stream: + self.Contents = teststream() + else: + S = PDFStream() + S.content = stream + # need to add filter stuff (?) + S.__Comment__ = "xobject form stream" + self.Contents = S + if not self.Resources: + resources = PDFResourceDictionary() + # fonts! + resources.basicFonts() + if self.hasImages: + resources.allProcs() + else: + resources.basicProcs() + if self.XObjects: + #print "XObjects", self.XObjects.dict + resources.XObject = self.XObjects + self.Resources=resources + if self.compression: + self.Contents.filters = rl_config.useA85 and [PDFBase85Encode, PDFZCompress] or [PDFZCompress] + sdict = self.Contents.dictionary + sdict["Type"] = PDFName("XObject") + sdict["Subtype"] = PDFName("Form") + sdict["FormType"] = 1 + sdict["BBox"] = self.BBox + sdict["Matrix"] = self.Matrix + sdict["Resources"] = self.Resources + return self.Contents.format(document) + +class PDFPostScriptXObject(PDFObject): + "For embedding PD (e.g. tray commands) in PDF" + def __init__(self, content=None): + self.content = content + + def format(self, document): + S = PDFStream() + S.content = self.content + S.__Comment__ = "xobject postscript stream" + sdict = S.dictionary + sdict["Type"] = PDFName("XObject") + sdict["Subtype"] = PDFName("PS") + return S.format(document) + +_mode2CS={'RGB':'DeviceRGB', 'L':'DeviceGray', 'CMYK':'DeviceCMYK'} +class PDFImageXObject(PDFObject): + # first attempts at a hard-coded one + # in the file, Image XObjects are stream objects. We already + # have a PDFStream object with 3 attributes: dictionary, content + # and filters. So the job of this thing is to construct the + # right PDFStream instance and ask it to format itself. + def __init__(self, name, source=None, mask=None): + self.name = name + self.width = 24 + self.height = 23 + self.bitsPerComponent = 1 + self.colorSpace = 'DeviceGray' + self._filters = rl_config.useA85 and ('ASCII85Decode',) or () + self.streamContent = """ + 003B00 002700 002480 0E4940 114920 14B220 3CB650 + 75FE88 17FF8C 175F14 1C07E2 3803C4 703182 F8EDFC + B2BBC2 BB6F84 31BFC2 18EA3C 0E3E00 07FC00 03F800 + 1E1800 1FF800> + """ + self.mask = mask + + if source is None: + pass # use the canned one. + elif hasattr(source,'jpeg_fh'): + self.loadImageFromSRC(source) #it is already a PIL Image + else: + # it is a filename + import os + ext = os.path.splitext(source)[1].lower() + src = open_for_read(source) + if not(ext in ('.jpg', '.jpeg') and self.loadImageFromJPEG(src)): + if rl_config.useA85: + self.loadImageFromA85(src) + else: + self.loadImageFromRaw(src) + + def loadImageFromA85(self,source): + IMG=[] + imagedata = [s.strip() for s in pdfutils.makeA85Image(source,IMG=IMG)] + words = imagedata[1].split() + self.width, self.height = (int(words[1]),int(words[3])) + self.colorSpace = {'/RGB':'DeviceRGB', '/G':'DeviceGray', '/CMYK':'DeviceCMYK'}[words[7]] + self.bitsPerComponent = 8 + self._filters = 'ASCII85Decode','FlateDecode' #'A85','Fl' + if IMG: self._checkTransparency(IMG[0]) + elif self.mask=='auto': self.mask = None + self.streamContent = ''.join(imagedata[3:-1]) + + def loadImageFromJPEG(self,imageFile): + try: + try: + info = pdfutils.readJPEGInfo(imageFile) + finally: + imageFile.seek(0) #reset file pointer + except: + return False + self.width, self.height = info[0], info[1] + self.bitsPerComponent = 8 + if info[2] == 1: + self.colorSpace = 'DeviceGray' + elif info[2] == 3: + self.colorSpace = 'DeviceRGB' + else: #maybe should generate an error, is this right for CMYK? + self.colorSpace = 'DeviceCMYK' + self._dotrans = 1 + self.streamContent = imageFile.read() + if rl_config.useA85: + self.streamContent = asciiBase85Encode(self.streamContent) + self._filters = 'ASCII85Decode','DCTDecode' #'A85','DCT' + else: + self._filters = 'DCTDecode', #'DCT' + self.mask = None + return True + + def loadImageFromRaw(self,source): + IMG=[] + imagedata = pdfutils.makeRawImage(source,IMG=IMG) + words = imagedata[1].split() + self.width = int(words[1]) + self.height = int(words[3]) + self.colorSpace = {'/RGB':'DeviceRGB', '/G':'DeviceGray', '/CMYK':'DeviceCMYK'}[words[7]] + self.bitsPerComponent = 8 + self._filters = 'FlateDecode', #'Fl' + if IMG: self._checkTransparency(IMG[0]) + elif self.mask=='auto': self.mask = None + self.streamContent = ''.join(imagedata[3:-1]) + + def _checkTransparency(self,im): + if self.mask=='auto': + if im._dataA: + self.mask = None + self._smask = PDFImageXObject(_digester(im._dataA.getRGBData()),im._dataA,mask=None) + self._smask._decode = [0,1] + else: + tc = im.getTransparent() + if tc: + self.mask = (tc[0], tc[0], tc[1], tc[1], tc[2], tc[2]) + else: + self.mask = None + elif hasattr(self.mask,'rgb'): + _ = self.mask.rgb() + self.mask = _[0],_[0],_[1],_[1],_[2],_[2] + + def loadImageFromSRC(self, im): + "Extracts the stream, width and height" + fp = im.jpeg_fh() + if fp: + self.loadImageFromJPEG(fp) + else: + zlib = import_zlib() + if not zlib: return + self.width, self.height = im.getSize() + raw = im.getRGBData() + #assert len(raw) == self.width*self.height, "Wrong amount of data for image expected %sx%s=%s got %s" % (self.width,self.height,self.width*self.height,len(raw)) + self.streamContent = zlib.compress(raw) + if rl_config.useA85: + self.streamContent = asciiBase85Encode(self.streamContent) + self._filters = 'ASCII85Decode','FlateDecode' #'A85','Fl' + else: + self._filters = 'FlateDecode', #'Fl' + self.colorSpace= _mode2CS[im.mode] + self.bitsPerComponent = 8 + self._checkTransparency(im) + + def format(self, document): + S = PDFStream(content = self.streamContent) + dict = S.dictionary + dict["Type"] = PDFName("XObject") + dict["Subtype"] = PDFName("Image") + dict["Width"] = self.width + dict["Height"] = self.height + dict["BitsPerComponent"] = self.bitsPerComponent + dict["ColorSpace"] = PDFName(self.colorSpace) + if self.colorSpace=='DeviceCMYK' and getattr(self,'_dotrans',0): + dict["Decode"] = PDFArray([1,0,1,0,1,0,1,0]) + elif getattr(self,'_decode',None): + dict["Decode"] = PDFArray(self._decode) + dict["Filter"] = PDFArray(map(PDFName,self._filters)) + dict["Length"] = len(self.streamContent) + if self.mask: dict["Mask"] = PDFArray(self.mask) + if getattr(self,'smask',None): dict["SMask"] = self.smask + return S.format(document) + +class PDFSeparationCMYKColor: + def __init__(self, cmyk): + from reportlab.lib.colors import CMYKColor + if not isinstance(cmyk,CMYKColor): + raise ValueError('%s needs a CMYKColor argument' % self.__class__.__name__) + elif not cmyk.spotName: + raise ValueError('%s needs a CMYKColor argument with a spotName' % self.__class__.__name__) + self.cmyk = cmyk + + def _makeFuncPS(self): + '''create the postscript code for the tint transfer function + effectively this is tint*c, tint*y, ... tint*k''' + R = [].append + for i,v in enumerate(self.cmyk.cmyk()): + v=float(v) + if i==3: + if v==0.0: + R('pop') + R('0.0') + else: + R(str(v)) + R('mul') + else: + if v==0: + R('0.0') + else: + R('dup') + R(str(v)) + R('mul') + R('exch') + return '{%s}' % (' '.join(R.__self__)) + + def value(self): + return PDFArrayCompact(( + PDFName('Separation'), + PDFName(self.cmyk.spotName), + PDFName('DeviceCMYK'), + PDFStream( + dictionary=PDFDictionary(dict( + FunctionType=4, + Domain=PDFArrayCompact((0,1)), + Range=PDFArrayCompact((0,1,0,1,0,1,0,1)) + )), + content=self._makeFuncPS(), + filters=None,#[PDFBase85Encode, PDFZCompress], + ) + )) + +class PDFFunction(PDFObject): + """superclass for all function types.""" + defaults = [] + required = ("FunctionType", "Domain") + permitted = required+("Range",) + def FunctionDict(self, **kw): + d = {} + for (name,val) in self.defaults: + d[name] = val + d.update(kw) + for name in self.required: + if name not in d: + raise ValueError("keyword argument %s missing" % name) + permitted = self.permitted + for name in d.keys(): + if name not in permitted: + raise ValueError("bad annotation dictionary name %s" % name) + return PDFDictionary(d) + + def Dict(self, document): + raise ValueError("Dict undefined for virtual superclass PDFShading, must overload") + # but usually + #return self.FunctionDict(self, ...) + + def format(self, document): + D = self.Dict(document) + return D.format(document) + +class PDFExponentialFunction(PDFFunction): + defaults = PDFFunction.defaults + [("Domain", PDFArrayCompact((0.0, 1.0)))] + required = PDFFunction.required + ("N",) + permitted = PDFFunction.permitted + ("C0", "C1", "N") + def __init__(self, C0, C1, N, **kw): + self.C0 = C0 + self.C1 = C1 + self.N = N + self.otherkw = kw + def Dict(self, document): + d = {} + d.update(self.otherkw) + d["FunctionType"] = 2 + d["C0"] = PDFArrayCompact(self.C0) + d["C1"] = PDFArrayCompact(self.C1) + d["N"] = self.N + return self.FunctionDict(**d) + +class PDFStitchingFunction(PDFFunction): + required = PDFFunction.required + ("Functions", "Bounds", "Encode") + permitted = PDFFunction.permitted + ("Functions", "Bounds", "Encode") + def __init__(self, Functions, Bounds, Encode, **kw): + self.Functions = Functions + self.Bounds = Bounds + self.Encode = Encode + self.otherkw = kw + def Dict(self, document): + d = {} + d.update(self.otherkw) + d["FunctionType"] = 3 + d["Functions"] = PDFArray([document.Reference(x) for x in self.Functions]) + d["Bounds"] = PDFArray(self.Bounds) + d["Encode"] = PDFArray(self.Encode) + return self.FunctionDict(**d) + +class PDFShading(PDFObject): + """superclass for all shading types.""" + required = ("ShadingType", "ColorSpace") + permitted = required+("Background", "BBox", "AntiAlias") + def ShadingDict(self, **kw): + d = {} + d.update(kw) + for name in self.required: + if name not in d: + raise ValueError("keyword argument %s missing" % name) + permitted = self.permitted + for name in d.keys(): + if name not in permitted: + raise ValueError("bad annotation dictionary name %s" % name) + return PDFDictionary(d) + + def Dict(self, document): + raise ValueError("Dict undefined for virtual superclass PDFShading, must overload") + # but usually + #return self.ShadingDict(self, ...) + + def format(self, document): + D = self.Dict(document) + return D.format(document) + +class PDFFunctionShading(PDFShading): + required = PDFShading.required + ("Function",) + permitted = PDFShading.permitted + ("Domain", "Matrix", "Function") + def __init__(self, Function, ColorSpace, **kw): + self.Function = Function + self.ColorSpace = ColorSpace + self.otherkw = kw + def Dict(self, document): + d = {} + d.update(self.otherkw) + d["ShadingType"] = 1 + d["ColorSpace"] = PDFName(self.ColorSpace) + d["Function"] = document.Reference(self.Function) + return self.ShadingDict(**d) + +class PDFAxialShading(PDFShading): + required = PDFShading.required + ("Coords", "Function") + permitted = PDFShading.permitted + ( + "Coords", "Domain", "Function", "Extend") + def __init__(self, x0, y0, x1, y1, Function, ColorSpace, **kw): + self.Coords = (x0, y0, x1, y1) + self.Function = Function + self.ColorSpace = ColorSpace + self.otherkw = kw + def Dict(self, document): + d = {} + d.update(self.otherkw) + d["ShadingType"] = 2 + d["ColorSpace"] = PDFName(self.ColorSpace) + d["Coords"] = PDFArrayCompact(self.Coords) + d["Function"] = document.Reference(self.Function) + return self.ShadingDict(**d) + +class PDFRadialShading(PDFShading): + required = PDFShading.required + ("Coords", "Function") + permitted = PDFShading.permitted + ( + "Coords", "Domain", "Function", "Extend") + def __init__(self, x0, y0, r0, x1, y1, r1, Function, ColorSpace, **kw): + self.Coords = (x0, y0, r0, x1, y1, r1) + self.Function = Function + self.ColorSpace = ColorSpace + self.otherkw = kw + def Dict(self, document): + d = {} + d.update(self.otherkw) + d["ShadingType"] = 3 + d["ColorSpace"] = PDFName(self.ColorSpace) + d["Coords"] = PDFArrayCompact(self.Coords) + d["Function"] = document.Reference(self.Function) + return self.ShadingDict(**d) + +if __name__=="__main__": + print("There is no script interpretation for pdfdoc.") diff --git a/reportlab/pdfbase/pdfform.py b/reportlab/pdfbase/pdfform.py new file mode 100644 index 00000000..90cb1bc7 --- /dev/null +++ b/reportlab/pdfbase/pdfform.py @@ -0,0 +1,634 @@ + +"""Support for Acrobat Forms in ReportLab documents + +This module is somewhat experimental at this time. + +Includes basic support for + textfields, + select fields (drop down lists), and + check buttons. + +The public interface consists of functions at the moment. +At some later date these operations may be made into canvas +methods. (comments?) + +The ...Absolute(...) functions position the fields with respect +to the absolute canvas coordinate space -- that is, they do not +respect any coordinate transforms in effect for the canvas. + +The ...Relative(...) functions position the ONLY THE LOWER LEFT +CORNER of the field using the coordinate transform in effect for +the canvas. THIS WILL ONLY WORK CORRECTLY FOR TRANSLATED COORDINATES +-- THE SHAPE, SIZE, FONTSIZE, AND ORIENTATION OF THE FIELD WILL NOT BE EFFECTED +BY SCALING, ROTATION, SKEWING OR OTHER NON-TRANSLATION COORDINATE +TRANSFORMS. + +Please note that all field names (titles) in a given document must be unique. +Textfields and select fields only support the "base 14" canvas fonts +at this time. + +See individual function docstrings below for more information. + +The function test1(...) generates a simple test file. + +THIS CONTRIBUTION WAS COMMISSIONED BY REPORTLAB USERS +WHO WISH TO REMAIN ANONYMOUS. +""" + +### NOTE: MAKE THE STRING FORMATS DYNAMIC IN PATTERNS TO SUPPORT ENCRYPTION XXXX + +import string +from reportlab.pdfbase.pdfdoc import PDFString, PDFStream, PDFDictionary, PDFName, PDFObject +from reportlab.lib.colors import obj_R_G_B + +#==========================public interfaces + +def textFieldAbsolute(canvas, title, x, y, width, height, value="", maxlen=1000000, multiline=0): + """Place a text field on the current page + with name title at ABSOLUTE position (x,y) with + dimensions (width, height), using value as the default value and + maxlen as the maximum permissible length. If multiline is set make + it a multiline field. + """ + theform = getForm(canvas) + return theform.textField(canvas, title, x, y, x+width, y+height, value, maxlen, multiline) + +def textFieldRelative(canvas, title, xR, yR, width, height, value="", maxlen=1000000, multiline=0): + "same as textFieldAbsolute except the x and y are relative to the canvas coordinate transform" + (xA, yA) = canvas.absolutePosition(xR,yR) + return textFieldAbsolute(canvas, title, xA, yA, width, height, value, maxlen, multiline) + +def buttonFieldAbsolute(canvas, title, value, x, y): + """Place a check button field on the current page + with name title and default value value (one of "Yes" or "Off") + at ABSOLUTE position (x,y). + """ + theform = getForm(canvas) + return theform.buttonField(canvas, title, value, x, y) + +def buttonFieldRelative(canvas, title, value, xR, yR): + "same as buttonFieldAbsolute except the x and y are relative to the canvas coordinate transform" + (xA, yA) = canvas.absolutePosition(xR,yR) + return buttonFieldAbsolute(canvas, title, value, xA, yA) + +def selectFieldAbsolute(canvas, title, value, options, x, y, width, height): + """Place a select field (drop down list) on the current page + with name title and + with options listed in the sequence options + default value value (must be one of options) + at ABSOLUTE position (x,y) with dimensions (width, height).""" + theform = getForm(canvas) + theform.selectField(canvas, title, value, options, x, y, x+width, y+height) + +def selectFieldRelative(canvas, title, value, options, xR, yR, width, height): + "same as textFieldAbsolute except the x and y are relative to the canvas coordinate transform" + (xA, yA) = canvas.absolutePosition(xR,yR) + return selectFieldAbsolute(canvas, title, value, options, xA, yA, width, height) + +def test1(): + from reportlab.pdfgen import canvas + fn = "formtest1.pdf" + c = canvas.Canvas(fn) + # first page + c.setFont("Courier", 10) + c.drawString(100, 500, "hello world") + textFieldAbsolute(c, "fieldA", 100, 600, 100, 20, "default value") + textFieldAbsolute(c, "fieldB", 100, 300, 100, 50, "another default value", multiline=1) + selectFieldAbsolute(c, "fieldC", "France", ["Canada", "France", "China"], 100, 200, 100, 20) + c.rect(100, 600, 100, 20) + buttonFieldAbsolute(c, "field2", "Yes", 100, 700) + c.rect(100, 700, 20, 20) + buttonFieldAbsolute(c, "field3", "Off", 100, 800) + c.rect(100, 800, 20, 20) + # second page + c.showPage() + c.setFont("Helvetica", 7) + c.translate(50, 20) + c.drawString(100, 500, "hello world") + textFieldRelative(c, "fieldA_1", 100, 600, 100, 20, "default value 2") + c.setStrokeColorRGB(1,0,0) + c.setFillColorRGB(0,1,0.5) + textFieldRelative(c, "fieldB_1", 100, 300, 100, 50, "another default value 2", multiline=1) + selectFieldRelative(c, "fieldC_1", "France 1", ["Canada 0", "France 1", "China 2"], 100, 200, 100, 20) + c.rect(100, 600, 100, 20) + buttonFieldRelative(c, "field2_1", "Yes", 100, 700) + c.rect(100, 700, 20, 20) + buttonFieldRelative(c, "field3_1", "Off", 100, 800) + c.rect(100, 800, 20, 20) + c.save() + print("wrote", fn) + +#==========================end of public interfaces + +from reportlab.pdfbase.pdfpattern import PDFPattern, PDFPatternIf + +def getForm(canvas): + "get form from canvas, create the form if needed" + try: + return canvas.AcroForm + except AttributeError: + theform = canvas.AcroForm = AcroForm() + # install the form in the document + d = canvas._doc + cat = d._catalog + cat.AcroForm = theform + return theform + +class AcroForm(PDFObject): + def __init__(self): + self.fields = [] + def textField(self, canvas, title, xmin, ymin, xmax, ymax, value="", maxlen=1000000, multiline=0): + # determine the page ref + doc = canvas._doc + page = doc.thisPageRef() + # determine text info + R, G, B = obj_R_G_B(canvas._fillColorObj) + #print "rgb", (R,G,B) + font = canvas. _fontname + fontsize = canvas. _fontsize + field = TextField(title, value, xmin, ymin, xmax, ymax, page, maxlen, + font, fontsize, R, G, B, multiline) + self.fields.append(field) + canvas._addAnnotation(field) + def selectField(self, canvas, title, value, options, xmin, ymin, xmax, ymax): + # determine the page ref + doc = canvas._doc + page = doc.thisPageRef() + # determine text info + R, G, B = obj_R_G_B(canvas._fillColorObj) + #print "rgb", (R,G,B) + font = canvas. _fontname + fontsize = canvas. _fontsize + field = SelectField(title, value, options, xmin, ymin, xmax, ymax, page, + font=font, fontsize=fontsize, R=R, G=G, B=B) + self.fields.append(field) + canvas._addAnnotation(field) + def buttonField(self, canvas, title, value, xmin, ymin): + # determine the page ref + doc = canvas._doc + page = doc.thisPageRef() + field = ButtonField(title, value, xmin, ymin, page) + self.fields.append(field) + canvas._addAnnotation(field) + def format(self, document): + from reportlab.pdfbase.pdfdoc import PDFArray + proxy = PDFPattern(FormPattern, Resources=getattr(self,'resources',GLOBALRESOURCES), + NeedAppearances=getattr(self,'needAppearances','false'), + fields=PDFArray(self.fields), SigFlags=getattr(self,'sigFlags',0)) + return proxy.format(document) + +FormPattern = [ +'<<\r\n', +'/NeedAppearances ',['NeedAppearances'],'\r\n' +'/DA ', PDFString('/Helv 0 Tf 0 g '), '\r\n', +'/DR ',["Resources"],'\r\n', +'/Fields ', ["fields"],'\r\n', +PDFPatternIf('SigFlags',['\r\n/SigFlags ',['SigFlags']]), +'>>' +] + +def FormFontsDictionary(): + from reportlab.pdfbase.pdfdoc import PDFDictionary + fontsdictionary = PDFDictionary() + fontsdictionary.__RefOnly__ = 1 + for fullname, shortname in FORMFONTNAMES.items(): + fontsdictionary[shortname] = FormFont(fullname, shortname) + fontsdictionary["ZaDb"] = ZADB.clone() + return fontsdictionary + +def FormResources(): + return PDFPattern(FormResourcesDictionaryPattern, + Encoding=ENCODING.clone(), Font=GLOBALFONTSDICTIONARY) + +ZaDbPattern = [ +' <<' +' /BaseFont' +' /ZapfDingbats' +' /Name' +' /ZaDb' +' /Subtype' +' /Type1' +' /Type' +' /Font' +'>>'] + + +FormResourcesDictionaryPattern = [ +'<<', +' /Encoding ', +["Encoding"], '\r\n', +' /Font ', +["Font"], '\r\n', +'>>' +] + +FORMFONTNAMES = { + "Helvetica": "Helv", + "Helvetica-Bold": "HeBo", + 'Courier': "Cour", + 'Courier-Bold': "CoBo", + 'Courier-Oblique': "CoOb", + 'Courier-BoldOblique': "CoBO", + 'Helvetica-Oblique': "HeOb", + 'Helvetica-BoldOblique': "HeBO", + 'Times-Roman': "Time", + 'Times-Bold': "TiBo", + 'Times-Italic': "TiIt", + 'Times-BoldItalic': "TiBI", + } + +EncodingPattern = [ +'<<', +' /PDFDocEncoding ', +["PDFDocEncoding"], '\r\n', +'>>', +] + +PDFDocEncodingPattern = [ +'<<' +' /Differences' +' [' +' 24' +' /breve' +' /caron' +' /circumflex' +' /dotaccent' +' /hungarumlaut' +' /ogonek' +' /ring' +' /tilde' +' 39' +' /quotesingle' +' 96' +' /grave' +' 128' +' /bullet' +' /dagger' +' /daggerdbl' +' /ellipsis' +' /emdash' +' /endash' +' /florin' +' /fraction' +' /guilsinglleft' +' /guilsinglright' +' /minus' +' /perthousand' +' /quotedblbase' +' /quotedblleft' +' /quotedblright' +' /quoteleft' +' /quoteright' +' /quotesinglbase' +' /trademark' +' /fi' +' /fl' +' /Lslash' +' /OE' +' /Scaron' +' /Ydieresis' +' /Zcaron' +' /dotlessi' +' /lslash' +' /oe' +' /scaron' +' /zcaron' +' 160' +' /Euro' +' 164' +' /currency' +' 166' +' /brokenbar' +' 168' +' /dieresis' +' /copyright' +' /ordfeminine' +' 172' +' /logicalnot' +' /.notdef' +' /registered' +' /macron' +' /degree' +' /plusminus' +' /twosuperior' +' /threesuperior' +' /acute' +' /mu' +' 183' +' /periodcentered' +' /cedilla' +' /onesuperior' +' /ordmasculine' +' 188' +' /onequarter' +' /onehalf' +' /threequarters' +' 192' +' /Agrave' +' /Aacute' +' /Acircumflex' +' /Atilde' +' /Adieresis' +' /Aring' +' /AE' +' /Ccedilla' +' /Egrave' +' /Eacute' +' /Ecircumflex' +' /Edieresis' +' /Igrave' +' /Iacute' +' /Icircumflex' +' /Idieresis' +' /Eth' +' /Ntilde' +' /Ograve' +' /Oacute' +' /Ocircumflex' +' /Otilde' +' /Odieresis' +' /multiply' +' /Oslash' +' /Ugrave' +' /Uacute' +' /Ucircumflex' +' /Udieresis' +' /Yacute' +' /Thorn' +' /germandbls' +' /agrave' +' /aacute' +' /acircumflex' +' /atilde' +' /adieresis' +' /aring' +' /ae' +' /ccedilla' +' /egrave' +' /eacute' +' /ecircumflex' +' /edieresis' +' /igrave' +' /iacute' +' /icircumflex' +' /idieresis' +' /eth' +' /ntilde' +' /ograve' +' /oacute' +' /ocircumflex' +' /otilde' +' /odieresis' +' /divide' +' /oslash' +' /ugrave' +' /uacute' +' /ucircumflex' +' /udieresis' +' /yacute' +' /thorn' +' /ydieresis' +' ]' +' /Type' +' /Encoding' +'>>'] + +def FormFont(BaseFont, Name): + from reportlab.pdfbase.pdfdoc import PDFName + return PDFPattern(FormFontPattern, BaseFont=PDFName(BaseFont), Name=PDFName(Name), Encoding=PDFDOCENC.clone()) + +FormFontPattern = [ +'<<', +' /BaseFont ', +["BaseFont"], '\r\n', +' /Encoding ', +["Encoding"], '\r\n', +' /Name ', +["Name"], '\r\n', +' /Subtype ' +' /Type1 ' +' /Type ' +' /Font ' +'>>' ] + +def resetPdfForm(): + global PDFDOCENC,ENCODING,GLOBALFONTSDICTIONARY,GLOBALRESOURCES,ZADB + PDFDOCENC = PDFPattern(PDFDocEncodingPattern) + ENCODING = PDFPattern(EncodingPattern, PDFDocEncoding=PDFDOCENC.clone()) + ZADB = PDFPattern(ZaDbPattern) + GLOBALFONTSDICTIONARY = FormFontsDictionary() + GLOBALRESOURCES = FormResources() +from reportlab.rl_config import register_reset +register_reset(resetPdfForm) +resetPdfForm() + +def TextField(title, value, xmin, ymin, xmax, ymax, page, + maxlen=1000000, font="Helvetica-Bold", fontsize=9, R=0, G=0, B=0.627, multiline=0): + from reportlab.pdfbase.pdfdoc import PDFString, PDFName + Flags = 0 + if multiline: + Flags = Flags | (1<<12) # bit 13 is at position 12 :) + fontname = FORMFONTNAMES[font] + return PDFPattern(TextFieldPattern, + value=PDFString(value), maxlen=maxlen, page=page, + title=PDFString(title), + xmin=xmin, ymin=ymin, xmax=xmax, ymax=ymax, + fontname=PDFName(fontname), fontsize=fontsize, R=R, G=G, B=B, Flags=Flags) + + +TextFieldPattern = [ +'<<' +' /DA' +' (', ["fontname"],' ',["fontsize"],' Tf ',["R"],' ',["G"],' ',["B"],' rg)' +' /DV ', +["value"], '\r\n', +' /F 4 /FT /Tx' +'/MK << /BC [ 0 0 0 ] >>' +' /MaxLen ', +["maxlen"], '\r\n', +' /P ', +["page"], '\r\n', +' /Rect ' +' [', ["xmin"], " ", ["ymin"], " ", ["xmax"], " ", ["ymax"], ' ]' +'/Subtype /Widget' +' /T ', +["title"], '\r\n', +' /Type' +' /Annot' +' /V ', +["value"], '\r\n', +' /Ff ', +["Flags"],'\r\n', +'>>'] + +def SelectField(title, value, options, xmin, ymin, xmax, ymax, page, + font="Helvetica-Bold", fontsize=9, R=0, G=0, B=0.627): + #print "ARGS", (title, value, options, xmin, ymin, xmax, ymax, page, font, fontsize, R, G, B) + from reportlab.pdfbase.pdfdoc import PDFString, PDFName, PDFArray + if value not in options: + raise ValueError("value %s must be one of options %s" % (repr(value), repr(options))) + fontname = FORMFONTNAMES[font] + optionstrings = list(map(PDFString, options)) + optionarray = PDFArray(optionstrings) + return PDFPattern(SelectFieldPattern, + Options=optionarray, + Selected=PDFString(value), Page=page, + Name=PDFString(title), + xmin=xmin, ymin=ymin, xmax=xmax, ymax=ymax, + fontname=PDFName(fontname), fontsize=fontsize, R=R, G=G, B=B) + +SelectFieldPattern = [ +'<< % a select list\r\n' +' /DA ', +' (', ["fontname"],' ',["fontsize"],' Tf ',["R"],' ',["G"],' ',["B"],' rg)\r\n', +#' (/Helv 12 Tf 0 g)\r\n', +' /DV ', +["Selected"],'\r\n', +' /F ', +' 4\r\n', +' /FT ', +' /Ch\r\n', +' /MK ', +' <<', +' /BC', +' [', +' 0', +' 0', +' 0', +' ]', +' /BG', +' [', +' 1', +' 1', +' 1', +' ]', +' >>\r\n', +' /Opt ', +["Options"],'\r\n', +' /P ', +["Page"],'\r\n', +'/Rect', +' [',["xmin"], " ", ["ymin"], " ", ["xmax"], " ", ["ymax"], +' ] \r\n', +'/Subtype', +' /Widget\r\n', +' /T ', +["Name"],'\r\n', +' /Type ', +' /Annot', +' /V ', +["Selected"],'\r\n', +'>>'] + +def ButtonField(title, value, xmin, ymin, page): + if value not in ("Yes", "Off"): + raise ValueError("button value must be 'Yes' or 'Off': "+repr(value)) + (dx, dy) = (16.77036, 14.90698) + return PDFPattern(ButtonFieldPattern, + Name=PDFString(title), + xmin=xmin, ymin=ymin, xmax=xmin+dx, ymax=ymin+dy, + Hide=HIDE, + APDOff=APDOFF, + APDYes=APDYES, + APNYes=APNYES, + Value=PDFName(value), + Page=page) + +ButtonFieldPattern = ['<< ', +'/AA', +' <<', +' /D ', +["Hide"],'\r\n', +#' %(imported.18.0)s', +' >> ', +'/AP ', +' <<', +' /D', +' <<', +' /Off ', +#' %(imported.40.0)s', +["APDOff"], '\r\n', +' /Yes ', +#' %(imported.39.0)s', +["APDYes"], '\r\n', +' >>', '\r\n', +' /N', +' << ', +' /Yes ', +#' %(imported.38.0)s', +["APNYes"], '\r\n', +' >>', +' >>\r\n', +' /AS ', +["Value"], '\r\n', +' /DA ', +PDFString('/ZaDb 0 Tf 0 g'), '\r\n', +'/DV ', +["Value"], '\r\n', +'/F ', +' 4 ', +'/FT ', +' /Btn ', +'/H ', +' /T ', +'/MK ', +' <<', +' /AC (\\376\\377)', +#PDFString('\376\377'), +' /CA ', +PDFString('4'), +' /RC ', +PDFString('\376\377'), +' >> ','\r\n', +'/P ', +["Page"], '\r\n', +'/Rect', +' [',["xmin"], " ", ["ymin"], " ", ["xmax"], " ", ["ymax"], +' ] ','\r\n', +'/Subtype', +' /Widget ', +'/T ', +["Name"], '\r\n', +'/Type', +' /Annot ', +'/V ', +["Value"], '\r\n', +' >>'] + +HIDE = PDFPattern([ +'<< ' +'/S ' +' /Hide ' +'>>']) + +def buttonStreamDictionary(): + "everything except the length for the button appearance streams" + result = PDFDictionary() + result["SubType"] = "/Form" + result["BBox"] = "[0 0 16.77036 14.90698]" + font = PDFDictionary() + font["ZaDb"] = ZADB.clone() + resources = PDFDictionary() + resources["ProcSet"] = "[ /PDF /Text ]" + resources["Font"] = font + result["Resources"] = resources + return result + +def ButtonStream(content): + dict = buttonStreamDictionary() + result = PDFStream(dict, content) + result.filters = [] + return result + +APDOFF = ButtonStream('0.749 g 0 0 16.7704 14.907 re f\r\n') +APDYES = ButtonStream( +'0.749 g 0 0 16.7704 14.907 re f q 1 1 14.7704 12.907 re W '+ +'n BT /ZaDb 11.3086 Tf 0 g 1 0 0 1 3.6017 3.3881 Tm (4) Tj ET\r\n') +APNYES = ButtonStream( +'q 1 1 14.7704 12.907 re W n BT /ZaDb 11.3086 Tf 0 g 1 0 0 1 3.6017 3.3881 Tm (4) Tj ET Q\r\n') + + +#==== script interpretation + +if __name__=="__main__": + test1() diff --git a/reportlab/pdfbase/pdfmetrics.py b/reportlab/pdfbase/pdfmetrics.py new file mode 100644 index 00000000..9a7566fb --- /dev/null +++ b/reportlab/pdfbase/pdfmetrics.py @@ -0,0 +1,799 @@ +#Copyright ReportLab Europe Ltd. 2000-2012 +#see license.txt for license details +#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/pdfbase/pdfmetrics.py +#$Header $ +__version__=''' $Id$ ''' +__doc__="""This provides a database of font metric information and +efines Font, Encoding and TypeFace classes aimed at end users. + +There are counterparts to some of these in pdfbase/pdfdoc.py, but +the latter focus on constructing the right PDF objects. These +classes are declarative and focus on letting the user construct +and query font objects. + +The module maintains a registry of font objects at run time. + +It is independent of the canvas or any particular context. It keeps +a registry of Font, TypeFace and Encoding objects. Ideally these +would be pre-loaded, but due to a nasty circularity problem we +trap attempts to access them and do it on first access. +""" +import string, os, sys +from reportlab.pdfbase import _fontdata +from reportlab.lib.logger import warnOnce +from reportlab.lib.utils import rl_isfile, rl_glob, rl_isdir, open_and_read, open_and_readlines, findInPaths, isSeq, isStr, isUnicode, isPy3 +from reportlab.rl_config import defaultEncoding, T1SearchPath +from reportlab.lib.rl_accel import unicode2T1, instanceStringWidthT1 +from reportlab.pdfbase import rl_codecs +_notdefChar = b'n' + +rl_codecs.RL_Codecs.register() +standardFonts = _fontdata.standardFonts +standardEncodings = _fontdata.standardEncodings + +_typefaces = {} +_encodings = {} +_fonts = {} + + +class FontError(Exception): + pass +class FontNotFoundError(Exception): + pass + +def parseAFMFile(afmFileName): + """Quick and dirty - gives back a top-level dictionary + with top-level items, and a 'widths' key containing + a dictionary of glyph names and widths. Just enough + needed for embedding. A better parser would accept + options for what data you wwanted, and preserve the + order.""" + + lines = open_and_readlines(afmFileName, 'r') + if len(lines)<=1: + #likely to be a MAC file + if lines: lines = lines[0].split('\r') + if len(lines)<=1: + raise ValueError('AFM file %s hasn\'t enough data' % afmFileName) + topLevel = {} + glyphLevel = [] + + lines = [l.strip() for l in lines] + lines = [l for l in lines if not l.lower().startswith('comment')] + #pass 1 - get the widths + inMetrics = 0 # os 'TOP', or 'CHARMETRICS' + for line in lines: + if line[0:16] == 'StartCharMetrics': + inMetrics = 1 + elif line[0:14] == 'EndCharMetrics': + inMetrics = 0 + elif inMetrics: + chunks = line.split(';') + chunks = [chunk.strip() for chunk in chunks] + cidChunk, widthChunk, nameChunk = chunks[0:3] + + # character ID + l, r = cidChunk.split() + assert l == 'C', 'bad line in font file %s' % line + cid = int(r) + + # width + l, r = widthChunk.split() + assert l == 'WX', 'bad line in font file %s' % line + width = int(r) + + # name + l, r = nameChunk.split() + assert l == 'N', 'bad line in font file %s' % line + name = r + + glyphLevel.append((cid, width, name)) + + # pass 2 font info + inHeader = 0 + for line in lines: + if line[0:16] == 'StartFontMetrics': + inHeader = 1 + if line[0:16] == 'StartCharMetrics': + inHeader = 0 + elif inHeader: + if line[0:7] == 'Comment': pass + try: + left, right = line.split(' ',1) + except: + raise ValueError("Header information error in afm %s: line='%s'" % (afmFileName, line)) + try: + right = int(right) + except: + pass + topLevel[left] = right + + + return (topLevel, glyphLevel) + +class TypeFace: + def __init__(self, name): + self.name = name + self.glyphNames = [] + self.glyphWidths = {} + self.ascent = 0 + self.descent = 0 + + + # all typefaces of whatever class should have these 3 attributes. + # these are the basis for family detection. + self.familyName = None # should set on load/construction if possible + self.bold = 0 # bold faces should set this + self.italic = 0 #italic faces should set this + + if name == 'ZapfDingbats': + self.requiredEncoding = 'ZapfDingbatsEncoding' + elif name == 'Symbol': + self.requiredEncoding = 'SymbolEncoding' + else: + self.requiredEncoding = None + if name in standardFonts: + self.builtIn = 1 + self._loadBuiltInData(name) + else: + self.builtIn = 0 + + def _loadBuiltInData(self, name): + """Called for the built in 14 fonts. Gets their glyph data. + We presume they never change so this can be a shared reference.""" + name = str(name) #needed for pycanvas&jython/2.1 compatibility + self.glyphWidths = _fontdata.widthsByFontGlyph[name] + self.glyphNames = list(self.glyphWidths.keys()) + self.ascent,self.descent = _fontdata.ascent_descent[name] + + def getFontFiles(self): + "Info function, return list of the font files this depends on." + return [] + + def findT1File(self, ext='.pfb'): + possible_exts = (ext.lower(), ext.upper()) + if hasattr(self,'pfbFileName'): + r_basename = os.path.splitext(self.pfbFileName)[0] + for e in possible_exts: + if rl_isfile(r_basename + e): + return r_basename + e + try: + r = _fontdata.findT1File(self.name) + except: + afm = bruteForceSearchForAFM(self.name) + if afm: + if ext.lower() == '.pfb': + for e in possible_exts: + pfb = os.path.splitext(afm)[0] + e + if rl_isfile(pfb): + r = pfb + else: + r = None + elif ext.lower() == '.afm': + r = afm + else: + r = None + if r is None: + warnOnce("Can't find %s for face '%s'" % (ext, self.name)) + return r + +def bruteForceSearchForFile(fn,searchPath=None): + if searchPath is None: from reportlab.rl_config import T1SearchPath as searchPath + if rl_isfile(fn): return fn + bfn = os.path.basename(fn) + for dirname in searchPath: + if not rl_isdir(dirname): continue + tfn = os.path.join(dirname,bfn) + if rl_isfile(tfn): return tfn + return fn + +def bruteForceSearchForAFM(faceName): + """Looks in all AFM files on path for face with given name. + + Returns AFM file name or None. Ouch!""" + from reportlab.rl_config import T1SearchPath + + for dirname in T1SearchPath: + if not rl_isdir(dirname): continue + possibles = rl_glob(dirname + os.sep + '*.[aA][fF][mM]') + for possible in possibles: + try: + topDict, glyphDict = parseAFMFile(possible) + if topDict['FontName'] == faceName: + return possible + except: + t,v,b=sys.exc_info() + v.args = (' '.join(map(str,v.args))+', while looking for faceName=%r' % faceName,) + raise + + +#for faceName in standardFonts: +# registerTypeFace(TypeFace(faceName)) + + +class Encoding: + """Object to help you create and refer to encodings.""" + def __init__(self, name, base=None): + self.name = name + self.frozen = 0 + if name in standardEncodings: + assert base is None, "Can't have a base encoding for a standard encoding" + self.baseEncodingName = name + self.vector = _fontdata.encodings[name] + elif base == None: + # assume based on the usual one + self.baseEncodingName = defaultEncoding + self.vector = _fontdata.encodings[defaultEncoding] + elif isStr(base): + baseEnc = getEncoding(base) + self.baseEncodingName = baseEnc.name + self.vector = baseEnc.vector[:] + elif isSeq(base): + self.baseEncodingName = defaultEncoding + self.vector = base[:] + elif isinstance(base, Encoding): + # accept a vector + self.baseEncodingName = base.name + self.vector = base.vector[:] + + def __getitem__(self, index): + "Return glyph name for that code point, or None" + # THIS SHOULD BE INLINED FOR SPEED + return self.vector[index] + + def __setitem__(self, index, value): + # should fail if they are frozen + assert self.frozen == 0, 'Cannot modify a frozen encoding' + if self.vector[index]!=value: + L = list(self.vector) + L[index] = value + self.vector = tuple(L) + + def freeze(self): + self.vector = tuple(self.vector) + self.frozen = 1 + + def isEqual(self, other): + return self.name==other.name and tuple(self.vector)==tuple(other.vector) + + def modifyRange(self, base, newNames): + """Set a group of character names starting at the code point 'base'.""" + assert self.frozen == 0, 'Cannot modify a frozen encoding' + idx = base + for name in newNames: + self.vector[idx] = name + idx = idx + 1 + + def getDifferences(self, otherEnc): + """ + Return a compact list of the code points differing between two encodings + + This is in the Adobe format: list of + [[b1, name1, name2, name3], + [b2, name4]] + + where b1...bn is the starting code point, and the glyph names following + are assigned consecutive code points. + + """ + + ranges = [] + curRange = None + for i in range(len(self.vector)): + glyph = self.vector[i] + if glyph==otherEnc.vector[i]: + if curRange: + ranges.append(curRange) + curRange = [] + else: + if curRange: + curRange.append(glyph) + elif glyph: + curRange = [i, glyph] + if curRange: + ranges.append(curRange) + return ranges + + def makePDFObject(self): + "Returns a PDF Object representing self" + # avoid circular imports - this cannot go at module level + from reportlab.pdfbase import pdfdoc + + D = {} + baseEnc = getEncoding(self.baseEncodingName) + differences = self.getDifferences(baseEnc) #[None] * 256) + + # if no differences, we just need the base name + if differences == []: + return pdfdoc.PDFName(self.baseEncodingName) + else: + #make up a dictionary describing the new encoding + diffArray = [] + for range in differences: + diffArray.append(range[0]) # numbers go 'as is' + for glyphName in range[1:]: + if glyphName is not None: + # there is no way to 'unset' a character in the base font. + diffArray.append('/' + glyphName) + + #print 'diffArray = %s' % diffArray + D["Differences"] = pdfdoc.PDFArray(diffArray) + D["BaseEncoding"] = pdfdoc.PDFName(self.baseEncodingName) + D["Type"] = pdfdoc.PDFName("Encoding") + PD = pdfdoc.PDFDictionary(D) + return PD + +#for encName in standardEncodings: +# registerEncoding(Encoding(encName)) + + +standardT1SubstitutionFonts = [] +class Font: + """Represents a font (i.e combination of face and encoding). + + Defines suitable machinery for single byte fonts. This is + a concrete class which can handle the basic built-in fonts; + not clear yet if embedded ones need a new font class or + just a new typeface class (which would do the job through + composition)""" + + _multiByte = 0 # do not want our own stringwidth + _dynamicFont = 0 # do not want dynamic subsetting + + def __init__(self, name, faceName, encName): + self.fontName = name + face = self.face = getTypeFace(faceName) + self.encoding= getEncoding(encName) + self.encName = encName + if face.builtIn and face.requiredEncoding is None: + _ = standardT1SubstitutionFonts + else: + _ = [] + self.substitutionFonts = _ + self._calcWidths() + self._notdefChar = _notdefChar + self._notdefFont = name=='ZapfDingbats' and self or _notdefFont + + def stringWidth(self, text, size, encoding='utf8'): + return instanceStringWidthT1(self, text, size, encoding=encoding) + + def __repr__(self): + return "<%s %s>" % (self.__class__.__name__, self.face.name) + + def _calcWidths(self): + """Vector of widths for stringWidth function""" + #synthesize on first request + w = [0] * 256 + gw = self.face.glyphWidths + vec = self.encoding.vector + for i in range(256): + glyphName = vec[i] + if glyphName is not None: + try: + width = gw[glyphName] + w[i] = width + except KeyError: + import reportlab.rl_config + if reportlab.rl_config.warnOnMissingFontGlyphs: + print('typeface "%s" does not have a glyph "%s", bad font!' % (self.face.name, glyphName)) + else: + pass + self.widths = w + + def _formatWidths(self): + "returns a pretty block in PDF Array format to aid inspection" + text = b'[' + for i in range(256): + text = text + b' ' + bytes(str(self.widths[i]),'utf8') + if i == 255: + text = text + b' ]' + if i % 16 == 15: + text = text + b'\n' + return text + + def addObjects(self, doc): + """Makes and returns one or more PDF objects to be added + to the document. The caller supplies the internal name + to be used (typically F1, F2... in sequence) """ + # avoid circular imports - this cannot go at module level + from reportlab.pdfbase import pdfdoc + + # construct a Type 1 Font internal object + internalName = 'F' + repr(len(doc.fontMapping)+1) + pdfFont = pdfdoc.PDFType1Font() + pdfFont.Name = internalName + pdfFont.BaseFont = self.face.name + pdfFont.__Comment__ = 'Font %s' % self.fontName + pdfFont.Encoding = self.encoding.makePDFObject() + + # is it a built-in one? if not, need more stuff. + if not self.face.name in standardFonts: + pdfFont.FirstChar = 0 + pdfFont.LastChar = 255 + pdfFont.Widths = pdfdoc.PDFArray(self.widths) + pdfFont.FontDescriptor = self.face.addObjects(doc) + # now link it in + ref = doc.Reference(pdfFont, internalName) + + # also refer to it in the BasicFonts dictionary + fontDict = doc.idToObject['BasicFonts'].dict + fontDict[internalName] = pdfFont + + # and in the font mappings + doc.fontMapping[self.fontName] = '/' + internalName + +PFB_MARKER=chr(0x80) +PFB_ASCII=chr(1) +PFB_BINARY=chr(2) +PFB_EOF=chr(3) + +if isPy3: + def _pfbCheck(p,d,m,fn): + if chr(d[p])!=PFB_MARKER or chr(d[p+1])!=m: + raise ValueError('Bad pfb file\'%s\' expected chr(%d)chr(%d) at char %d, got chr(%d)chr(%d)' % (fn,ord(PFB_MARKER),ord(m),p,d[p],d[p+1])) + if m==PFB_EOF: return + p = p + 2 + l = (((((d[p+3])<<8)|(d[p+2])<<8)|(d[p+1]))<<8)|(d[p]) + p = p + 4 + if p+l>len(d): + raise ValueError('Bad pfb file\'%s\' needed %d+%d bytes have only %d!' % (fn,p,l,len(d))) + return p, p+l +else: + def _pfbSegLen(p,d): + '''compute a pfb style length from the first 4 bytes of string d''' + return ((((ord(d[p+3])<<8)|ord(d[p+2])<<8)|ord(d[p+1]))<<8)|ord(d[p]) + + def _pfbCheck(p,d,m,fn): + if d[p]!=PFB_MARKER or d[p+1]!=m: + raise ValueError('Bad pfb file\'%s\' expected chr(%d)chr(%d) at char %d, got chr(%d)chr(%d)' % (fn,ord(PFB_MARKER),ord(m),p,ord(d[p]),ord(d[p+1]))) + if m==PFB_EOF: return + p = p + 2 + l = _pfbSegLen(p,d) + p = p + 4 + if p+l>len(d): + raise ValueError('Bad pfb file\'%s\' needed %d+%d bytes have only %d!' % (fn,p,l,len(d))) + return p, p+l + +class EmbeddedType1Face(TypeFace): + """A Type 1 font other than one of the basic 14. + + Its glyph data will be embedded in the PDF file.""" + def __init__(self, afmFileName, pfbFileName): + # ignore afm file for now + TypeFace.__init__(self, None) + #None is a hack, name will be supplied by AFM parse lower done + #in this __init__ method. + afmFileName = findInPaths(afmFileName,T1SearchPath) + pfbFileName = findInPaths(pfbFileName,T1SearchPath) + self.afmFileName = os.path.abspath(afmFileName) + self.pfbFileName = os.path.abspath(pfbFileName) + self.requiredEncoding = None + self._loadGlyphs(pfbFileName) + self._loadMetrics(afmFileName) + + def getFontFiles(self): + return [self.afmFileName, self.pfbFileName] + + def _loadGlyphs(self, pfbFileName): + """Loads in binary glyph data, and finds the four length + measurements needed for the font descriptor""" + pfbFileName = bruteForceSearchForFile(pfbFileName) + assert rl_isfile(pfbFileName), 'file %s not found' % pfbFileName + d = open_and_read(pfbFileName, 'b') + s1, l1 = _pfbCheck(0,d,PFB_ASCII,pfbFileName) + s2, l2 = _pfbCheck(l1,d,PFB_BINARY,pfbFileName) + s3, l3 = _pfbCheck(l2,d,PFB_ASCII,pfbFileName) + _pfbCheck(l3,d,PFB_EOF,pfbFileName) + self._binaryData = d[s1:l1]+d[s2:l2]+d[s3:l3] + + self._length = len(self._binaryData) + self._length1 = l1-s1 + self._length2 = l2-s2 + self._length3 = l3-s3 + + + def _loadMetrics(self, afmFileName): + """Loads in and parses font metrics""" + #assert os.path.isfile(afmFileName), "AFM file %s not found" % afmFileName + afmFileName = bruteForceSearchForFile(afmFileName) + (topLevel, glyphData) = parseAFMFile(afmFileName) + + self.name = topLevel['FontName'] + self.familyName = topLevel['FamilyName'] + self.ascent = topLevel.get('Ascender', 1000) + self.descent = topLevel.get('Descender', 0) + self.capHeight = topLevel.get('CapHeight', 1000) + self.italicAngle = topLevel.get('ItalicAngle', 0) + self.stemV = topLevel.get('stemV', 0) + self.xHeight = topLevel.get('XHeight', 1000) + + strBbox = topLevel.get('FontBBox', [0,0,1000,1000]) + tokens = strBbox.split() + self.bbox = [] + for tok in tokens: + self.bbox.append(int(tok)) + + glyphWidths = {} + for (cid, width, name) in glyphData: + glyphWidths[name] = width + self.glyphWidths = glyphWidths + self.glyphNames = list(glyphWidths.keys()) + self.glyphNames.sort() + + # for font-specific encodings like Symbol, Dingbats, Carta we + # need to make a new encoding as well.... + if topLevel.get('EncodingScheme', None) == 'FontSpecific': + names = [None] * 256 + for (code, width, name) in glyphData: + if code >=0 and code <=255: + names[code] = name + encName = self.name + 'Encoding' + self.requiredEncoding = encName + enc = Encoding(encName, names) + registerEncoding(enc) + + def addObjects(self, doc): + """Add whatever needed to PDF file, and return a FontDescriptor reference""" + from reportlab.pdfbase import pdfdoc + + fontFile = pdfdoc.PDFStream() + fontFile.content = self._binaryData + #fontFile.dictionary['Length'] = self._length + fontFile.dictionary['Length1'] = self._length1 + fontFile.dictionary['Length2'] = self._length2 + fontFile.dictionary['Length3'] = self._length3 + #fontFile.filters = [pdfdoc.PDFZCompress] + + fontFileRef = doc.Reference(fontFile, 'fontFile:' + self.pfbFileName) + + fontDescriptor = pdfdoc.PDFDictionary({ + 'Type': '/FontDescriptor', + 'Ascent':self.ascent, + 'CapHeight':self.capHeight, + 'Descent':self.descent, + 'Flags': 34, + 'FontBBox':pdfdoc.PDFArray(self.bbox), + 'FontName':pdfdoc.PDFName(self.name), + 'ItalicAngle':self.italicAngle, + 'StemV':self.stemV, + 'XHeight':self.xHeight, + 'FontFile': fontFileRef, + }) + fontDescriptorRef = doc.Reference(fontDescriptor, 'fontDescriptor:' + self.name) + return fontDescriptorRef + +def registerTypeFace(face): + assert isinstance(face, TypeFace), 'Not a TypeFace: %s' % face + _typefaces[face.name] = face + if not face.name in standardFonts: + # HACK - bold/italic do not apply for type 1, so egister + # all combinations of mappings. + registerFontFamily(face.name) + +def registerEncoding(enc): + assert isinstance(enc, Encoding), 'Not an Encoding: %s' % enc + if enc.name in _encodings: + # already got one, complain if they are not the same + if enc.isEqual(_encodings[enc.name]): + enc.freeze() + else: + raise FontError('Encoding "%s" already registered with a different name vector!' % enc.name) + else: + _encodings[enc.name] = enc + enc.freeze() + # have not yet dealt with immutability! + +def registerFontFamily(family,normal=None,bold=None,italic=None,boldItalic=None): + from reportlab.lib import fonts + if not normal: normal = family + family = family.lower() + if not boldItalic: boldItalic = italic or bold or normal + if not bold: bold = normal + if not italic: italic = normal + fonts.addMapping(family, 0, 0, normal) + fonts.addMapping(family, 1, 0, bold) + fonts.addMapping(family, 0, 1, italic) + fonts.addMapping(family, 1, 1, boldItalic) + +def registerFont(font): + "Registers a font, including setting up info for accelerated stringWidth" + #assert isinstance(font, Font), 'Not a Font: %s' % font + fontName = font.fontName + _fonts[fontName] = font + if font._multiByte: + # CID fonts don't need to have typeface registered. + #need to set mappings so it can go in a paragraph even if within + # bold tags + registerFontFamily(font.fontName) + +def getTypeFace(faceName): + """Lazily construct known typefaces if not found""" + try: + return _typefaces[faceName] + except KeyError: + # not found, construct it if known + if faceName in standardFonts: + face = TypeFace(faceName) + (face.familyName, face.bold, face.italic) = _fontdata.standardFontAttributes[faceName] + registerTypeFace(face) +## print 'auto-constructing type face %s with family=%s, bold=%d, italic=%d' % ( +## face.name, face.familyName, face.bold, face.italic) + return face + else: + #try a brute force search + afm = bruteForceSearchForAFM(faceName) + if afm: + for e in ('.pfb', '.PFB'): + pfb = os.path.splitext(afm)[0] + e + if rl_isfile(pfb): break + assert rl_isfile(pfb), 'file %s not found!' % pfb + face = EmbeddedType1Face(afm, pfb) + registerTypeFace(face) + return face + else: + raise + +def getEncoding(encName): + """Lazily construct known encodings if not found""" + try: + return _encodings[encName] + except KeyError: + if encName in standardEncodings: + enc = Encoding(encName) + registerEncoding(enc) + #print 'auto-constructing encoding %s' % encName + return enc + else: + raise + +def findFontAndRegister(fontName): + '''search for and register a font given its name''' + fontName = str(fontName) + assert type(fontName) is str, 'fontName=%s is not required type str' % ascii(fontName) + #it might have a font-specific encoding e.g. Symbol + # or Dingbats. If not, take the default. + face = getTypeFace(fontName) + if face.requiredEncoding: + font = Font(fontName, fontName, face.requiredEncoding) + else: + font = Font(fontName, fontName, defaultEncoding) + registerFont(font) + return font + +def getFont(fontName): + """Lazily constructs known fonts if not found. + + Names of form 'face-encoding' will be built if + face and encoding are known. Also if the name is + just one of the standard 14, it will make up a font + in the default encoding.""" + try: + return _fonts[fontName] + except KeyError: + return findFontAndRegister(fontName) + +_notdefFont = getFont('ZapfDingbats') +standardT1SubstitutionFonts.extend([getFont('Symbol'),_notdefFont]) + +def getAscentDescent(fontName,fontSize=None): + font = getFont(fontName) + try: + ascent = font.ascent + descent = font.descent + except: + ascent = font.face.ascent + descent = font.face.descent + if fontSize: + norm = fontSize/1000. + return ascent*norm, descent*norm + else: + return ascent, descent + +def getAscent(fontName,fontSize=None): + return getAscentDescent(fontName,fontSize)[0] + +def getDescent(fontName,fontSize=None): + return getAscentDescent(fontName,fontSize)[1] + +def getRegisteredFontNames(): + "Returns what's in there" + reg = list(_fonts.keys()) + reg.sort() + return reg + +def stringWidth(text, fontName, fontSize, encoding='utf8'): + """Compute width of string in points; + not accelerated as fast enough because of instanceStringWidthT1/TTF""" + return getFont(fontName).stringWidth(text, fontSize, encoding=encoding) + +def dumpFontData(): + print('Registered Encodings:') + keys = list(_encodings.keys()) + keys.sort() + for encName in keys: + print(' ',encName) + + print() + print('Registered Typefaces:') + faces = list(_typefaces.keys()) + faces.sort() + for faceName in faces: + print(' ',faceName) + + + print() + print('Registered Fonts:') + k = list(_fonts.keys()) + k.sort() + for key in k: + font = _fonts[key] + print(' %s (%s/%s)' % (font.fontName, font.face.name, font.encoding.name)) + +def test3widths(texts): + # checks all 3 algorithms give same answer, note speed + import time + for fontName in standardFonts[0:1]: +## t0 = time.time() +## for text in texts: +## l1 = stringWidth(text, fontName, 10) +## t1 = time.time() +## print 'fast stringWidth took %0.4f' % (t1 - t0) + + t0 = time.time() + w = getFont(fontName).widths + for text in texts: + l2 = 0 + for ch in text: + l2 = l2 + w[ord(ch)] + t1 = time.time() + print('slow stringWidth took %0.4f' % (t1 - t0)) + + t0 = time.time() + for text in texts: + l3 = getFont(fontName).stringWidth(text, 10) + t1 = time.time() + print('class lookup and stringWidth took %0.4f' % (t1 - t0)) + print() + +def testStringWidthAlgorithms(): + rawdata = open('../../rlextra/rml2pdf/doc/rml_user_guide.prep').read() + print('rawdata length %d' % len(rawdata)) + print('test one huge string...') + test3widths([rawdata]) + print() + words = rawdata.split() + print('test %d shorter strings (average length %0.2f chars)...' % (len(words), 1.0*len(rawdata)/len(words))) + test3widths(words) + + +def test(): + helv = TypeFace('Helvetica') + registerTypeFace(helv) + print(helv.glyphNames[0:30]) + + wombat = TypeFace('Wombat') + print(wombat.glyphNames) + registerTypeFace(wombat) + + dumpFontData() + +#preserve the initial values here +def _reset( + initial_dicts = dict( + _typefaces = _typefaces.copy(), + _encodings = _encodings.copy(), + _fonts = _fonts.copy(), + ) + ): + for k,v in initial_dicts.items(): + d=globals()[k] + d.clear() + d.update(v) + +from reportlab.rl_config import register_reset +register_reset(_reset) +del register_reset + +if __name__=='__main__': + test() + testStringWidthAlgorithms() diff --git a/reportlab/pdfbase/pdfpattern.py b/reportlab/pdfbase/pdfpattern.py new file mode 100644 index 00000000..774ff334 --- /dev/null +++ b/reportlab/pdfbase/pdfpattern.py @@ -0,0 +1,93 @@ +__doc__="""helper for importing pdf structures into a ReportLab generated document +""" +from reportlab.pdfbase.pdfdoc import format, PDFObject, pdfdocEnc +from reportlab.lib.utils import strTypes + +def _patternSequenceCheck(pattern_sequence): + allowedTypes = strTypes if isinstance(strTypes, tuple) else (strTypes,) + allowedTypes = allowedTypes + (PDFObject,PDFPatternIf) + for x in pattern_sequence: + if not isinstance(x,allowedTypes): + if len(x)!=1: + raise ValueError("sequence elts must be strings/bytes/PDFPatternIfs or singletons containing strings: "+ascii(x)) + if not isinstance(x[0],strTypes): + raise ValueError("Singletons must contain strings/bytes or PDFObject instances only: "+ascii(x[0])) + +class PDFPattern(PDFObject): + __RefOnly__ = 1 + def __init__(self, pattern_sequence, **keywordargs): + """ + Description of a kind of PDF object using a pattern. + + Pattern sequence should contain strings, singletons of form [string] or + PDFPatternIf objects. + Strings are literal strings to be used in the object. + Singletons are names of keyword arguments to include. + PDFpatternIf objects allow some conditionality. + Keyword arguments can be non-instances which are substituted directly in string conversion, + or they can be object instances in which case they should be pdfdoc.* style + objects with a x.format(doc) method. + Keyword arguments may be set on initialization or subsequently using __setitem__, before format. + "constant object" instances can also be inserted in the patterns. + """ + _patternSequenceCheck(pattern_sequence) + self.pattern = pattern_sequence + self.arguments = keywordargs + + def __setitem__(self, item, value): + self.arguments[item] = value + + def __getitem__(self, item): + return self.arguments[item] + + def eval(self,L): + arguments = self.arguments + document = self.__document + for x in L: + if isinstance(x,strTypes): + yield pdfdocEnc(x) + elif isinstance(x,PDFObject): + yield x.format(document) + elif isinstance(x,PDFPatternIf): + result = list(self.eval(x.cond)) + cond = result and result[0] + for z in self.eval(x.thenPart if cond else x.elsePart): + yield z + else: + name = x[0] + value = arguments.get(name, None) + if value is None: + raise ValueError("%s value not defined" % ascii(name)) + if isinstance(value,PDFObject): + yield format(value,document) + elif isinstance(value,strTypes): + yield pdfdocEnc(value) + else: + yield pdfdocEnc(str(value)) + + def format(self, document): + self.__document = document + try: + return b"".join(self.eval(self.pattern)) + finally: + del self.__document + + def clone(self): + c = object.__new__(self.__class__) + c.pattern = self.pattern + c.arguments = self.arguments + return c + +class PDFPatternIf(object): + '''cond will be evaluated as [cond] in PDFpattern eval. + It should evaluate to a list with value 0/1 etc etc. + thenPart is a list to be evaluated if the cond evaulates true, + elsePart is the false sequence. + ''' + def __init__(self,cond,thenPart=[],elsePart=[]): + if not isinstance(cond,list): cond = [cond] + for x in cond, thenPart, elsePart: + _patternSequenceCheck(x) + self.cond = cond + self.thenPart = thenPart + self.elsePart = elsePart diff --git a/reportlab/pdfbase/pdfutils.py b/reportlab/pdfbase/pdfutils.py new file mode 100644 index 00000000..aad6ffa4 --- /dev/null +++ b/reportlab/pdfbase/pdfutils.py @@ -0,0 +1,284 @@ +#Copyright ReportLab Europe Ltd. 2000-2012 +#see license.txt for license details +#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/pdfbase/pdfutils.py +__version__=''' $Id$ ''' +__doc__='' +# pdfutils.py - everything to do with images, streams, +# compression, and some constants + +import sys +import os +import binascii +from reportlab import rl_config +from reportlab.lib.utils import getBytesIO, ImageReader, isUnicode, isPy3 +from reportlab.lib.rl_accel import asciiBase85Encode, asciiBase85Decode + +def _chunker(src,dst=[],chunkSize=60): + for i in range(0,len(src),chunkSize): + dst.append(src[i:i+chunkSize]) + return dst + +########################################################## +# +# Image compression helpers. Preprocessing a directory +# of images will offer a vast speedup. +# +########################################################## +_mode2cs = {'RGB':'RGB', 'CMYK': 'CMYK', 'L': 'G'} +_mode2bpp = {'RGB': 3, 'CMYK':4, 'L':1} +def makeA85Image(filename,IMG=None): + import zlib + img = ImageReader(filename) + if IMG is not None: IMG.append(img) + + imgwidth, imgheight = img.getSize() + raw = img.getRGBData() + + code = [] + append = code.append + # this describes what is in the image itself + append('BI') + append('/W %s /H %s /BPC 8 /CS /%s /F [/A85 /Fl]' % (imgwidth, imgheight,_mode2cs[img.mode])) + append('ID') + #use a flate filter and Ascii Base 85 + assert len(raw) == imgwidth * imgheight*_mode2bpp[img.mode], "Wrong amount of data for image" + compressed = zlib.compress(raw) #this bit is very fast... + encoded = asciiBase85Encode(compressed) #...sadly this may not be + + #append in blocks of 60 characters + _chunker(encoded,code) + + append('EI') + return code +def makeRawImage(filename,IMG=None): + import zlib + img = ImageReader(filename) + if IMG is not None: IMG.append(img) + + imgwidth, imgheight = img.getSize() + raw = img.getRGBData() + + code = [] + append = code.append + # this describes what is in the image itself + append('BI') + append('/W %s /H %s /BPC 8 /CS /%s /F [/Fl]' % (imgwidth, imgheight,_mode2cs[img.mode])) + append('ID') + #use a flate filter + assert len(raw) == imgwidth * imgheight*_mode2bpp[img.mode], "Wrong amount of data for image" + compressed = zlib.compress(raw) #this bit is very fast... + + #append in blocks of 60 characters + _chunker(compressed,code) + + append('EI') + return code + +def cacheImageFile(filename, returnInMemory=0, IMG=None): + "Processes image as if for encoding, saves to a file with .a85 extension." + + cachedname = os.path.splitext(filename)[0] + (rl_config.useA85 and '.a85' or '.bin') + if filename==cachedname: + if cachedImageExists(filename): + from reportlab.lib.utils import open_for_read + if returnInMemory: return filter(None,open_for_read(cachedname).read().split('\r\n')) + else: + raise IOError('No such cached image %s' % filename) + else: + if rl_config.useA85: + code = makeA85Image(filename,IMG) + else: + code = makeRawImage(filename,IMG) + if returnInMemory: return code + + #save it to a file + f = open(cachedname,'wb') + f.write('\r\n'.join(code)+'\r\n') + f.close() + if rl_config.verbose: + print('cached image as %s' % cachedname) + + +def preProcessImages(spec): + """Preprocesses one or more image files. + + Accepts either a filespec ('C:\mydir\*.jpg') or a list + of image filenames, crunches them all to save time. Run this + to save huge amounts of time when repeatedly building image + documents.""" + + import glob + + if isinstance(spec,str): + filelist = glob.glob(spec) + else: #list or tuple OK + filelist = spec + + for filename in filelist: + if cachedImageExists(filename): + if rl_config.verbose: + print('cached version of %s already exists' % filename) + else: + cacheImageFile(filename) + + +def cachedImageExists(filename): + """Determines if a cached image already exists for a given file. + + Determines if a cached image exists which has the same name + and equal or newer date to the given file.""" + cachedname = os.path.splitext(filename)[0] + (rl_config.useA85 and '.a85' or 'bin') + if os.path.isfile(cachedname): + #see if it is newer + original_date = os.stat(filename)[8] + cached_date = os.stat(cachedname)[8] + if original_date > cached_date: + return 0 + else: + return 1 + else: + return 0 + + +############################################################## +# +# PDF Helper functions +# +############################################################## + +def _normalizeLineEnds(text,desired='\r\n',unlikely='\x00\x01\x02\x03'): + """Normalizes different line end character(s). + + Ensures all instances of CR, LF and CRLF end up as + the specified one.""" + + return (text + .replace('\r\n', unlikely) + .replace('\r', unlikely) + .replace('\n', unlikely) + .replace(unlikely, desired)) + +def _AsciiHexEncode(input): + """Encodes input using ASCII-Hex coding. + + This is a verbose encoding used for binary data within + a PDF file. One byte binary becomes two bytes of ASCII. + Helper function used by images.""" + if isUnicode(input): + input = input.encode('utf-8') + output = getBytesIO() + output.write(binascii.b2a_hex(input)) + output.write(b'>') + return output.getvalue() + + +def _AsciiHexDecode(input): + """Decodes input using ASCII-Hex coding. + + Not used except to provide a test of the inverse function.""" + + #strip out all whitespace + if not isUnicode(input): + input = input.decode('utf-8') + stripped = ''.join(input.split()) + assert stripped[-1] == '>', 'Invalid terminator for Ascii Hex Stream' + stripped = stripped[:-1] #chop off terminator + assert len(stripped) % 2 == 0, 'Ascii Hex stream has odd number of bytes' + + return ''.join([chr(int(stripped[i:i+2],16)) for i in range(0,len(stripped),2)]) + +def _wrap(input, columns=60): + "Wraps input at a given column size by inserting \r\n characters." + output = [] + length = len(input) + i = 0 + pos = columns * i + while pos < length: + output.append(input[pos:pos+columns]) + i = i + 1 + pos = columns * i + #avoid HP printer problem + if len(output[-1])==1: + output[-2:] = [output[-2][:-1],output[-2][-1]+output[-1]] + return '\r\n'.join(output) + + +######################################################################### +# +# JPEG processing code - contributed by Eric Johnson +# +######################################################################### + +# Read data from the JPEG file. We should probably be using PIL to +# get this information for us -- but this way is more fun! +# Returns (width, height, color components) as a triple +# This is based on Thomas Merz's code from GhostScript (viewjpeg.ps) +def readJPEGInfo(image): + "Read width, height and number of components from open JPEG file." + + import struct + from reportlab.pdfbase.pdfdoc import PDFError + + #Acceptable JPEG Markers: + # SROF0=baseline, SOF1=extended sequential or SOF2=progressive + validMarkers = [0xC0, 0xC1, 0xC2] + + #JPEG markers without additional parameters + noParamMarkers = \ + [ 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0x01 ] + + #Unsupported JPEG Markers + unsupportedMarkers = \ + [ 0xC3, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCD, 0xCE, 0xCF ] + + #read JPEG marker segments until we find SOFn marker or EOF + done = 0 + while not done: + x = struct.unpack('B', image.read(1)) + if x[0] == 0xFF: #found marker + x = struct.unpack('B', image.read(1)) + #print "Marker: ", '%0.2x' % x[0] + #check marker type is acceptable and process it + if x[0] in validMarkers: + image.seek(2, 1) #skip segment length + x = struct.unpack('B', image.read(1)) #data precision + if x[0] != 8: + raise PDFError('JPEG must have 8 bits per component') + y = struct.unpack('BB', image.read(2)) + height = (y[0] << 8) + y[1] + y = struct.unpack('BB', image.read(2)) + width = (y[0] << 8) + y[1] + y = struct.unpack('B', image.read(1)) + color = y[0] + return width, height, color + elif x[0] in unsupportedMarkers: + raise PDFError('JPEG Unsupported JPEG marker: %0.2x' % x[0]) + elif x[0] not in noParamMarkers: + #skip segments with parameters + #read length and skip the data + x = struct.unpack('BB', image.read(2)) + image.seek( (x[0] << 8) + x[1] - 2, 1) + +class _fusc: + def __init__(self,k, n): + assert k, 'Argument k should be a non empty string' + self._k = k + self._klen = len(k) + self._n = int(n) or 7 + + def encrypt(self,s): + return self.__rotate(asciiBase85Encode(''.join(map(chr,self.__fusc(list(map(ord,s)))))),self._n) + + def decrypt(self,s): + return ''.join(map(chr,self.__fusc(list(map(ord,asciiBase85Decode(self.__rotate(s,-self._n))))))) + + def __rotate(self,s,n): + l = len(s) + if n<0: n = l+n + n %= l + if not n: return s + return s[-n:]+s[:l-n] + + def __fusc(self,s): + slen = len(s) + return list(map(lambda x,y: x ^ y,s,list(map(ord,((int(slen/self._klen)+1)*self._k)[:slen])))) diff --git a/reportlab/pdfbase/rl_codecs.py b/reportlab/pdfbase/rl_codecs.py new file mode 100644 index 00000000..bf3a4195 --- /dev/null +++ b/reportlab/pdfbase/rl_codecs.py @@ -0,0 +1,1054 @@ +#codecs support +__all__=['RL_Codecs'] +from collections import namedtuple +StdCodecData=namedtuple('StdCodecData','exceptions rexceptions') +ExtCodecData=namedtuple('ExtCodecData','baseName exceptions rexceptions') +class RL_Codecs: + __rl_codecs_data = { + 'winansi':StdCodecData({ + 0x007f: 0x2022, # BULLET + 0x0080: 0x20ac, # EURO SIGN + 0x0081: 0x2022, # BULLET + 0x0082: 0x201a, # SINGLE LOW-9 QUOTATION MARK + 0x0083: 0x0192, # LATIN SMALL LETTER F WITH HOOK + 0x0084: 0x201e, # DOUBLE LOW-9 QUOTATION MARK + 0x0085: 0x2026, # HORIZONTAL ELLIPSIS + 0x0086: 0x2020, # DAGGER + 0x0087: 0x2021, # DOUBLE DAGGER + 0x0088: 0x02c6, # MODIFIER LETTER CIRCUMFLEX ACCENT + 0x0089: 0x2030, # PER MILLE SIGN + 0x008a: 0x0160, # LATIN CAPITAL LETTER S WITH CARON + 0x008b: 0x2039, # SINGLE LEFT-POINTING ANGLE QUOTATION MARK + 0x008c: 0x0152, # LATIN CAPITAL LIGATURE OE + 0x008d: 0x2022, # BULLET + 0x008e: 0x017d, # LATIN CAPITAL LETTER Z WITH CARON + 0x008f: 0x2022, # BULLET + 0x0090: 0x2022, # BULLET + 0x0091: 0x2018, # LEFT SINGLE QUOTATION MARK + 0x0092: 0x2019, # RIGHT SINGLE QUOTATION MARK + 0x0093: 0x201c, # LEFT DOUBLE QUOTATION MARK + 0x0094: 0x201d, # RIGHT DOUBLE QUOTATION MARK + 0x0095: 0x2022, # BULLET + 0x0096: 0x2013, # EN DASH + 0x0097: 0x2014, # EM DASH + 0x0098: 0x02dc, # SMALL TILDE + 0x0099: 0x2122, # TRADE MARK SIGN + 0x009a: 0x0161, # LATIN SMALL LETTER S WITH CARON + 0x009b: 0x203a, # SINGLE RIGHT-POINTING ANGLE QUOTATION MARK + 0x009c: 0x0153, # LATIN SMALL LIGATURE OE + 0x009d: 0x2022, # BULLET + 0x009e: 0x017e, # LATIN SMALL LETTER Z WITH CARON + 0x009f: 0x0178, # LATIN CAPITAL LETTER Y WITH DIAERESIS + 0x00a0: 0x0020, # SPACE + }, {0x2022:0x7f,0x20:0x20,0xa0:0x20}), + 'macroman':StdCodecData({ + 0x007f: None, # UNDEFINED + 0x0080: 0x00c4, # LATIN CAPITAL LETTER A WITH DIAERESIS + 0x0081: 0x00c5, # LATIN CAPITAL LETTER A WITH RING ABOVE + 0x0082: 0x00c7, # LATIN CAPITAL LETTER C WITH CEDILLA + 0x0083: 0x00c9, # LATIN CAPITAL LETTER E WITH ACUTE + 0x0084: 0x00d1, # LATIN CAPITAL LETTER N WITH TILDE + 0x0085: 0x00d6, # LATIN CAPITAL LETTER O WITH DIAERESIS + 0x0086: 0x00dc, # LATIN CAPITAL LETTER U WITH DIAERESIS + 0x0087: 0x00e1, # LATIN SMALL LETTER A WITH ACUTE + 0x0088: 0x00e0, # LATIN SMALL LETTER A WITH GRAVE + 0x0089: 0x00e2, # LATIN SMALL LETTER A WITH CIRCUMFLEX + 0x008a: 0x00e4, # LATIN SMALL LETTER A WITH DIAERESIS + 0x008b: 0x00e3, # LATIN SMALL LETTER A WITH TILDE + 0x008c: 0x00e5, # LATIN SMALL LETTER A WITH RING ABOVE + 0x008d: 0x00e7, # LATIN SMALL LETTER C WITH CEDILLA + 0x008e: 0x00e9, # LATIN SMALL LETTER E WITH ACUTE + 0x008f: 0x00e8, # LATIN SMALL LETTER E WITH GRAVE + 0x0090: 0x00ea, # LATIN SMALL LETTER E WITH CIRCUMFLEX + 0x0091: 0x00eb, # LATIN SMALL LETTER E WITH DIAERESIS + 0x0092: 0x00ed, # LATIN SMALL LETTER I WITH ACUTE + 0x0093: 0x00ec, # LATIN SMALL LETTER I WITH GRAVE + 0x0094: 0x00ee, # LATIN SMALL LETTER I WITH CIRCUMFLEX + 0x0095: 0x00ef, # LATIN SMALL LETTER I WITH DIAERESIS + 0x0096: 0x00f1, # LATIN SMALL LETTER N WITH TILDE + 0x0097: 0x00f3, # LATIN SMALL LETTER O WITH ACUTE + 0x0098: 0x00f2, # LATIN SMALL LETTER O WITH GRAVE + 0x0099: 0x00f4, # LATIN SMALL LETTER O WITH CIRCUMFLEX + 0x009a: 0x00f6, # LATIN SMALL LETTER O WITH DIAERESIS + 0x009b: 0x00f5, # LATIN SMALL LETTER O WITH TILDE + 0x009c: 0x00fa, # LATIN SMALL LETTER U WITH ACUTE + 0x009d: 0x00f9, # LATIN SMALL LETTER U WITH GRAVE + 0x009e: 0x00fb, # LATIN SMALL LETTER U WITH CIRCUMFLEX + 0x009f: 0x00fc, # LATIN SMALL LETTER U WITH DIAERESIS + 0x00a0: 0x2020, # DAGGER + 0x00a1: 0x00b0, # DEGREE SIGN + 0x00a4: 0x00a7, # SECTION SIGN + 0x00a5: 0x2022, # BULLET + 0x00a6: 0x00b6, # PILCROW SIGN + 0x00a7: 0x00df, # LATIN SMALL LETTER SHARP S + 0x00a8: 0x00ae, # REGISTERED SIGN + 0x00aa: 0x2122, # TRADE MARK SIGN + 0x00ab: 0x00b4, # ACUTE ACCENT + 0x00ac: 0x00a8, # DIAERESIS + 0x00ad: None, # UNDEFINED + 0x00ae: 0x00c6, # LATIN CAPITAL LETTER AE + 0x00af: 0x00d8, # LATIN CAPITAL LETTER O WITH STROKE + 0x00b0: None, # UNDEFINED + 0x00b2: None, # UNDEFINED + 0x00b3: None, # UNDEFINED + 0x00b4: 0x00a5, # YEN SIGN + 0x00b6: None, # UNDEFINED + 0x00b7: None, # UNDEFINED + 0x00b8: None, # UNDEFINED + 0x00b9: None, # UNDEFINED + 0x00ba: None, # UNDEFINED + 0x00bb: 0x00aa, # FEMININE ORDINAL INDICATOR + 0x00bc: 0x00ba, # MASCULINE ORDINAL INDICATOR + 0x00bd: None, # UNDEFINED + 0x00be: 0x00e6, # LATIN SMALL LETTER AE + 0x00bf: 0x00f8, # LATIN SMALL LETTER O WITH STROKE + 0x00c0: 0x00bf, # INVERTED QUESTION MARK + 0x00c1: 0x00a1, # INVERTED EXCLAMATION MARK + 0x00c2: 0x00ac, # NOT SIGN + 0x00c3: None, # UNDEFINED + 0x00c4: 0x0192, # LATIN SMALL LETTER F WITH HOOK + 0x00c5: None, # UNDEFINED + 0x00c6: None, # UNDEFINED + 0x00c7: 0x00ab, # LEFT-POINTING DOUBLE ANGLE QUOTATION MARK + 0x00c8: 0x00bb, # RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK + 0x00c9: 0x2026, # HORIZONTAL ELLIPSIS + 0x00ca: 0x0020, # SPACE + 0x00cb: 0x00c0, # LATIN CAPITAL LETTER A WITH GRAVE + 0x00cc: 0x00c3, # LATIN CAPITAL LETTER A WITH TILDE + 0x00cd: 0x00d5, # LATIN CAPITAL LETTER O WITH TILDE + 0x00ce: 0x0152, # LATIN CAPITAL LIGATURE OE + 0x00cf: 0x0153, # LATIN SMALL LIGATURE OE + 0x00d0: 0x2013, # EN DASH + 0x00d1: 0x2014, # EM DASH + 0x00d2: 0x201c, # LEFT DOUBLE QUOTATION MARK + 0x00d3: 0x201d, # RIGHT DOUBLE QUOTATION MARK + 0x00d4: 0x2018, # LEFT SINGLE QUOTATION MARK + 0x00d5: 0x2019, # RIGHT SINGLE QUOTATION MARK + 0x00d6: 0x00f7, # DIVISION SIGN + 0x00d7: None, # UNDEFINED + 0x00d8: 0x00ff, # LATIN SMALL LETTER Y WITH DIAERESIS + 0x00d9: 0x0178, # LATIN CAPITAL LETTER Y WITH DIAERESIS + 0x00da: 0x2044, # FRACTION SLASH + 0x00db: 0x00a4, # CURRENCY SIGN + 0x00dc: 0x2039, # SINGLE LEFT-POINTING ANGLE QUOTATION MARK + 0x00dd: 0x203a, # SINGLE RIGHT-POINTING ANGLE QUOTATION MARK + 0x00de: 0xfb01, # LATIN SMALL LIGATURE FI + 0x00df: 0xfb02, # LATIN SMALL LIGATURE FL + 0x00e0: 0x2021, # DOUBLE DAGGER + 0x00e1: 0x00b7, # MIDDLE DOT + 0x00e2: 0x201a, # SINGLE LOW-9 QUOTATION MARK + 0x00e3: 0x201e, # DOUBLE LOW-9 QUOTATION MARK + 0x00e4: 0x2030, # PER MILLE SIGN + 0x00e5: 0x00c2, # LATIN CAPITAL LETTER A WITH CIRCUMFLEX + 0x00e6: 0x00ca, # LATIN CAPITAL LETTER E WITH CIRCUMFLEX + 0x00e7: 0x00c1, # LATIN CAPITAL LETTER A WITH ACUTE + 0x00e8: 0x00cb, # LATIN CAPITAL LETTER E WITH DIAERESIS + 0x00e9: 0x00c8, # LATIN CAPITAL LETTER E WITH GRAVE + 0x00ea: 0x00cd, # LATIN CAPITAL LETTER I WITH ACUTE + 0x00eb: 0x00ce, # LATIN CAPITAL LETTER I WITH CIRCUMFLEX + 0x00ec: 0x00cf, # LATIN CAPITAL LETTER I WITH DIAERESIS + 0x00ed: 0x00cc, # LATIN CAPITAL LETTER I WITH GRAVE + 0x00ee: 0x00d3, # LATIN CAPITAL LETTER O WITH ACUTE + 0x00ef: 0x00d4, # LATIN CAPITAL LETTER O WITH CIRCUMFLEX + 0x00f0: None, # UNDEFINED + 0x00f1: 0x00d2, # LATIN CAPITAL LETTER O WITH GRAVE + 0x00f2: 0x00da, # LATIN CAPITAL LETTER U WITH ACUTE + 0x00f3: 0x00db, # LATIN CAPITAL LETTER U WITH CIRCUMFLEX + 0x00f4: 0x00d9, # LATIN CAPITAL LETTER U WITH GRAVE + 0x00f5: 0x0131, # LATIN SMALL LETTER DOTLESS I + 0x00f6: 0x02c6, # MODIFIER LETTER CIRCUMFLEX ACCENT + 0x00f7: 0x02dc, # SMALL TILDE + 0x00f8: 0x00af, # MACRON + 0x00f9: 0x02d8, # BREVE + 0x00fa: 0x02d9, # DOT ABOVE + 0x00fb: 0x02da, # RING ABOVE + 0x00fc: 0x00b8, # CEDILLA + 0x00fd: 0x02dd, # DOUBLE ACUTE ACCENT + 0x00fe: 0x02db, # OGONEK + 0x00ff: 0x02c7, # CARON + },None), + 'standard':StdCodecData({ + 0x0027: 0x2019, # RIGHT SINGLE QUOTATION MARK + 0x0060: 0x2018, # LEFT SINGLE QUOTATION MARK + 0x007f: None, # UNDEFINED + 0x0080: None, # UNDEFINED + 0x0081: None, # UNDEFINED + 0x0082: None, # UNDEFINED + 0x0083: None, # UNDEFINED + 0x0084: None, # UNDEFINED + 0x0085: None, # UNDEFINED + 0x0086: None, # UNDEFINED + 0x0087: None, # UNDEFINED + 0x0088: None, # UNDEFINED + 0x0089: None, # UNDEFINED + 0x008a: None, # UNDEFINED + 0x008b: None, # UNDEFINED + 0x008c: None, # UNDEFINED + 0x008d: None, # UNDEFINED + 0x008e: None, # UNDEFINED + 0x008f: None, # UNDEFINED + 0x0090: None, # UNDEFINED + 0x0091: None, # UNDEFINED + 0x0092: None, # UNDEFINED + 0x0093: None, # UNDEFINED + 0x0094: None, # UNDEFINED + 0x0095: None, # UNDEFINED + 0x0096: None, # UNDEFINED + 0x0097: None, # UNDEFINED + 0x0098: None, # UNDEFINED + 0x0099: None, # UNDEFINED + 0x009a: None, # UNDEFINED + 0x009b: None, # UNDEFINED + 0x009c: None, # UNDEFINED + 0x009d: None, # UNDEFINED + 0x009e: None, # UNDEFINED + 0x009f: None, # UNDEFINED + 0x00a0: None, # UNDEFINED + 0x00a4: 0x2044, # FRACTION SLASH + 0x00a6: 0x0192, # LATIN SMALL LETTER F WITH HOOK + 0x00a8: 0x00a4, # CURRENCY SIGN + 0x00a9: 0x0027, # APOSTROPHE + 0x00aa: 0x201c, # LEFT DOUBLE QUOTATION MARK + 0x00ac: 0x2039, # SINGLE LEFT-POINTING ANGLE QUOTATION MARK + 0x00ad: 0x203a, # SINGLE RIGHT-POINTING ANGLE QUOTATION MARK + 0x00ae: 0xfb01, # LATIN SMALL LIGATURE FI + 0x00af: 0xfb02, # LATIN SMALL LIGATURE FL + 0x00b0: None, # UNDEFINED + 0x00b1: 0x2013, # EN DASH + 0x00b2: 0x2020, # DAGGER + 0x00b3: 0x2021, # DOUBLE DAGGER + 0x00b4: 0x00b7, # MIDDLE DOT + 0x00b5: None, # UNDEFINED + 0x00b7: 0x2022, # BULLET + 0x00b8: 0x201a, # SINGLE LOW-9 QUOTATION MARK + 0x00b9: 0x201e, # DOUBLE LOW-9 QUOTATION MARK + 0x00ba: 0x201d, # RIGHT DOUBLE QUOTATION MARK + 0x00bc: 0x2026, # HORIZONTAL ELLIPSIS + 0x00bd: 0x2030, # PER MILLE SIGN + 0x00be: None, # UNDEFINED + 0x00c0: None, # UNDEFINED + 0x00c1: 0x0060, # GRAVE ACCENT + 0x00c2: 0x00b4, # ACUTE ACCENT + 0x00c3: 0x02c6, # MODIFIER LETTER CIRCUMFLEX ACCENT + 0x00c4: 0x02dc, # SMALL TILDE + 0x00c5: 0x00af, # MACRON + 0x00c6: 0x02d8, # BREVE + 0x00c7: 0x02d9, # DOT ABOVE + 0x00c8: 0x00a8, # DIAERESIS + 0x00c9: None, # UNDEFINED + 0x00ca: 0x02da, # RING ABOVE + 0x00cb: 0x00b8, # CEDILLA + 0x00cc: None, # UNDEFINED + 0x00cd: 0x02dd, # DOUBLE ACUTE ACCENT + 0x00ce: 0x02db, # OGONEK + 0x00cf: 0x02c7, # CARON + 0x00d0: 0x2014, # EM DASH + 0x00d1: None, # UNDEFINED + 0x00d2: None, # UNDEFINED + 0x00d3: None, # UNDEFINED + 0x00d4: None, # UNDEFINED + 0x00d5: None, # UNDEFINED + 0x00d6: None, # UNDEFINED + 0x00d7: None, # UNDEFINED + 0x00d8: None, # UNDEFINED + 0x00d9: None, # UNDEFINED + 0x00da: None, # UNDEFINED + 0x00db: None, # UNDEFINED + 0x00dc: None, # UNDEFINED + 0x00dd: None, # UNDEFINED + 0x00de: None, # UNDEFINED + 0x00df: None, # UNDEFINED + 0x00e0: None, # UNDEFINED + 0x00e1: 0x00c6, # LATIN CAPITAL LETTER AE + 0x00e2: None, # UNDEFINED + 0x00e3: 0x00aa, # FEMININE ORDINAL INDICATOR + 0x00e4: None, # UNDEFINED + 0x00e5: None, # UNDEFINED + 0x00e6: None, # UNDEFINED + 0x00e7: None, # UNDEFINED + 0x00e8: 0x0141, # LATIN CAPITAL LETTER L WITH STROKE + 0x00e9: 0x00d8, # LATIN CAPITAL LETTER O WITH STROKE + 0x00ea: 0x0152, # LATIN CAPITAL LIGATURE OE + 0x00eb: 0x00ba, # MASCULINE ORDINAL INDICATOR + 0x00ec: None, # UNDEFINED + 0x00ed: None, # UNDEFINED + 0x00ee: None, # UNDEFINED + 0x00ef: None, # UNDEFINED + 0x00f0: None, # UNDEFINED + 0x00f1: 0x00e6, # LATIN SMALL LETTER AE + 0x00f2: None, # UNDEFINED + 0x00f3: None, # UNDEFINED + 0x00f4: None, # UNDEFINED + 0x00f5: 0x0131, # LATIN SMALL LETTER DOTLESS I + 0x00f6: None, # UNDEFINED + 0x00f7: None, # UNDEFINED + 0x00f8: 0x0142, # LATIN SMALL LETTER L WITH STROKE + 0x00f9: 0x00f8, # LATIN SMALL LETTER O WITH STROKE + 0x00fa: 0x0153, # LATIN SMALL LIGATURE OE + 0x00fb: 0x00df, # LATIN SMALL LETTER SHARP S + 0x00fc: None, # UNDEFINED + 0x00fd: None, # UNDEFINED + 0x00fe: None, # UNDEFINED + 0x00ff: None, # UNDEFINED + },None), + 'symbol':StdCodecData({ + 0x0022: 0x2200, # FOR ALL + 0x0024: 0x2203, # THERE EXISTS + 0x0027: 0x220b, # CONTAINS AS MEMBER + 0x002a: 0x2217, # ASTERISK OPERATOR + 0x002d: 0x2212, # MINUS SIGN + 0x0040: 0x2245, # APPROXIMATELY EQUAL TO + 0x0041: 0x0391, # GREEK CAPITAL LETTER ALPHA + 0x0042: 0x0392, # GREEK CAPITAL LETTER BETA + 0x0043: 0x03a7, # GREEK CAPITAL LETTER CHI + 0x0044: 0x2206, # INCREMENT + 0x0045: 0x0395, # GREEK CAPITAL LETTER EPSILON + 0x0046: 0x03a6, # GREEK CAPITAL LETTER PHI + 0x0047: 0x0393, # GREEK CAPITAL LETTER GAMMA + 0x0048: 0x0397, # GREEK CAPITAL LETTER ETA + 0x0049: 0x0399, # GREEK CAPITAL LETTER IOTA + 0x004a: 0x03d1, # GREEK THETA SYMBOL + 0x004b: 0x039a, # GREEK CAPITAL LETTER KAPPA + 0x004c: 0x039b, # GREEK CAPITAL LETTER LAMDA + 0x004d: 0x039c, # GREEK CAPITAL LETTER MU + 0x004e: 0x039d, # GREEK CAPITAL LETTER NU + 0x004f: 0x039f, # GREEK CAPITAL LETTER OMICRON + 0x0050: 0x03a0, # GREEK CAPITAL LETTER PI + 0x0051: 0x0398, # GREEK CAPITAL LETTER THETA + 0x0052: 0x03a1, # GREEK CAPITAL LETTER RHO + 0x0053: 0x03a3, # GREEK CAPITAL LETTER SIGMA + 0x0054: 0x03a4, # GREEK CAPITAL LETTER TAU + 0x0055: 0x03a5, # GREEK CAPITAL LETTER UPSILON + 0x0056: 0x03c2, # GREEK SMALL LETTER FINAL SIGMA + 0x0057: 0x2126, # OHM SIGN + 0x0058: 0x039e, # GREEK CAPITAL LETTER XI + 0x0059: 0x03a8, # GREEK CAPITAL LETTER PSI + 0x005a: 0x0396, # GREEK CAPITAL LETTER ZETA + 0x005c: 0x2234, # THEREFORE + 0x005e: 0x22a5, # UP TACK + 0x0060: 0xf8e5, # [unknown unicode name for radicalex] + 0x0061: 0x03b1, # GREEK SMALL LETTER ALPHA + 0x0062: 0x03b2, # GREEK SMALL LETTER BETA + 0x0063: 0x03c7, # GREEK SMALL LETTER CHI + 0x0064: 0x03b4, # GREEK SMALL LETTER DELTA + 0x0065: 0x03b5, # GREEK SMALL LETTER EPSILON + 0x0066: 0x03c6, # GREEK SMALL LETTER PHI + 0x0067: 0x03b3, # GREEK SMALL LETTER GAMMA + 0x0068: 0x03b7, # GREEK SMALL LETTER ETA + 0x0069: 0x03b9, # GREEK SMALL LETTER IOTA + 0x006a: 0x03d5, # GREEK PHI SYMBOL + 0x006b: 0x03ba, # GREEK SMALL LETTER KAPPA + 0x006c: 0x03bb, # GREEK SMALL LETTER LAMDA + 0x006d: 0x00b5, # MICRO SIGN + 0x006e: 0x03bd, # GREEK SMALL LETTER NU + 0x006f: 0x03bf, # GREEK SMALL LETTER OMICRON + 0x0070: 0x03c0, # GREEK SMALL LETTER PI + 0x0071: 0x03b8, # GREEK SMALL LETTER THETA + 0x0072: 0x03c1, # GREEK SMALL LETTER RHO + 0x0073: 0x03c3, # GREEK SMALL LETTER SIGMA + 0x0074: 0x03c4, # GREEK SMALL LETTER TAU + 0x0075: 0x03c5, # GREEK SMALL LETTER UPSILON + 0x0076: 0x03d6, # GREEK PI SYMBOL + 0x0077: 0x03c9, # GREEK SMALL LETTER OMEGA + 0x0078: 0x03be, # GREEK SMALL LETTER XI + 0x0079: 0x03c8, # GREEK SMALL LETTER PSI + 0x007a: 0x03b6, # GREEK SMALL LETTER ZETA + 0x007e: 0x223c, # TILDE OPERATOR + 0x007f: None, # UNDEFINED + 0x0080: None, # UNDEFINED + 0x0081: None, # UNDEFINED + 0x0082: None, # UNDEFINED + 0x0083: None, # UNDEFINED + 0x0084: None, # UNDEFINED + 0x0085: None, # UNDEFINED + 0x0086: None, # UNDEFINED + 0x0087: None, # UNDEFINED + 0x0088: None, # UNDEFINED + 0x0089: None, # UNDEFINED + 0x008a: None, # UNDEFINED + 0x008b: None, # UNDEFINED + 0x008c: None, # UNDEFINED + 0x008d: None, # UNDEFINED + 0x008e: None, # UNDEFINED + 0x008f: None, # UNDEFINED + 0x0090: None, # UNDEFINED + 0x0091: None, # UNDEFINED + 0x0092: None, # UNDEFINED + 0x0093: None, # UNDEFINED + 0x0094: None, # UNDEFINED + 0x0095: None, # UNDEFINED + 0x0096: None, # UNDEFINED + 0x0097: None, # UNDEFINED + 0x0098: None, # UNDEFINED + 0x0099: None, # UNDEFINED + 0x009a: None, # UNDEFINED + 0x009b: None, # UNDEFINED + 0x009c: None, # UNDEFINED + 0x009d: None, # UNDEFINED + 0x009e: None, # UNDEFINED + 0x009f: None, # UNDEFINED + 0x00a0: 0x20ac, # EURO SIGN + 0x00a1: 0x03d2, # GREEK UPSILON WITH HOOK SYMBOL + 0x00a2: 0x2032, # PRIME + 0x00a3: 0x2264, # LESS-THAN OR EQUAL TO + 0x00a4: 0x2044, # FRACTION SLASH + 0x00a5: 0x221e, # INFINITY + 0x00a6: 0x0192, # LATIN SMALL LETTER F WITH HOOK + 0x00a7: 0x2663, # BLACK CLUB SUIT + 0x00a8: 0x2666, # BLACK DIAMOND SUIT + 0x00a9: 0x2665, # BLACK HEART SUIT + 0x00aa: 0x2660, # BLACK SPADE SUIT + 0x00ab: 0x2194, # LEFT RIGHT ARROW + 0x00ac: 0x2190, # LEFTWARDS ARROW + 0x00ad: 0x2191, # UPWARDS ARROW + 0x00ae: 0x2192, # RIGHTWARDS ARROW + 0x00af: 0x2193, # DOWNWARDS ARROW + 0x00b2: 0x2033, # DOUBLE PRIME + 0x00b3: 0x2265, # GREATER-THAN OR EQUAL TO + 0x00b4: 0x00d7, # MULTIPLICATION SIGN + 0x00b5: 0x221d, # PROPORTIONAL TO + 0x00b6: 0x2202, # PARTIAL DIFFERENTIAL + 0x00b7: 0x2022, # BULLET + 0x00b8: 0x00f7, # DIVISION SIGN + 0x00b9: 0x2260, # NOT EQUAL TO + 0x00ba: 0x2261, # IDENTICAL TO + 0x00bb: 0x2248, # ALMOST EQUAL TO + 0x00bc: 0x2026, # HORIZONTAL ELLIPSIS + 0x00bd: 0xf8e6, # [unknown unicode name for arrowvertex] + 0x00be: 0xf8e7, # [unknown unicode name for arrowhorizex] + 0x00bf: 0x21b5, # DOWNWARDS ARROW WITH CORNER LEFTWARDS + 0x00c0: 0x2135, # ALEF SYMBOL + 0x00c1: 0x2111, # BLACK-LETTER CAPITAL I + 0x00c2: 0x211c, # BLACK-LETTER CAPITAL R + 0x00c3: 0x2118, # SCRIPT CAPITAL P + 0x00c4: 0x2297, # CIRCLED TIMES + 0x00c5: 0x2295, # CIRCLED PLUS + 0x00c6: 0x2205, # EMPTY SET + 0x00c7: 0x2229, # INTERSECTION + 0x00c8: 0x222a, # UNION + 0x00c9: 0x2283, # SUPERSET OF + 0x00ca: 0x2287, # SUPERSET OF OR EQUAL TO + 0x00cb: 0x2284, # NOT A SUBSET OF + 0x00cc: 0x2282, # SUBSET OF + 0x00cd: 0x2286, # SUBSET OF OR EQUAL TO + 0x00ce: 0x2208, # ELEMENT OF + 0x00cf: 0x2209, # NOT AN ELEMENT OF + 0x00d0: 0x2220, # ANGLE + 0x00d1: 0x2207, # NABLA + 0x00d2: 0xf6da, # [unknown unicode name for registerserif] + 0x00d3: 0xf6d9, # [unknown unicode name for copyrightserif] + 0x00d4: 0xf6db, # [unknown unicode name for trademarkserif] + 0x00d5: 0x220f, # N-ARY PRODUCT + 0x00d6: 0x221a, # SQUARE ROOT + 0x00d7: 0x22c5, # DOT OPERATOR + 0x00d8: 0x00ac, # NOT SIGN + 0x00d9: 0x2227, # LOGICAL AND + 0x00da: 0x2228, # LOGICAL OR + 0x00db: 0x21d4, # LEFT RIGHT DOUBLE ARROW + 0x00dc: 0x21d0, # LEFTWARDS DOUBLE ARROW + 0x00dd: 0x21d1, # UPWARDS DOUBLE ARROW + 0x00de: 0x21d2, # RIGHTWARDS DOUBLE ARROW + 0x00df: 0x21d3, # DOWNWARDS DOUBLE ARROW + 0x00e0: 0x25ca, # LOZENGE + 0x00e1: 0x2329, # LEFT-POINTING ANGLE BRACKET + 0x00e2: 0xf8e8, # [unknown unicode name for registersans] + 0x00e3: 0xf8e9, # [unknown unicode name for copyrightsans] + 0x00e4: 0xf8ea, # [unknown unicode name for trademarksans] + 0x00e5: 0x2211, # N-ARY SUMMATION + 0x00e6: 0xf8eb, # [unknown unicode name for parenlefttp] + 0x00e7: 0xf8ec, # [unknown unicode name for parenleftex] + 0x00e8: 0xf8ed, # [unknown unicode name for parenleftbt] + 0x00e9: 0xf8ee, # [unknown unicode name for bracketlefttp] + 0x00ea: 0xf8ef, # [unknown unicode name for bracketleftex] + 0x00eb: 0xf8f0, # [unknown unicode name for bracketleftbt] + 0x00ec: 0xf8f1, # [unknown unicode name for bracelefttp] + 0x00ed: 0xf8f2, # [unknown unicode name for braceleftmid] + 0x00ee: 0xf8f3, # [unknown unicode name for braceleftbt] + 0x00ef: 0xf8f4, # [unknown unicode name for braceex] + 0x00f0: None, # UNDEFINED + 0x00f1: 0x232a, # RIGHT-POINTING ANGLE BRACKET + 0x00f2: 0x222b, # INTEGRAL + 0x00f3: 0x2320, # TOP HALF INTEGRAL + 0x00f4: 0xf8f5, # [unknown unicode name for integralex] + 0x00f5: 0x2321, # BOTTOM HALF INTEGRAL + 0x00f6: 0xf8f6, # [unknown unicode name for parenrighttp] + 0x00f7: 0xf8f7, # [unknown unicode name for parenrightex] + 0x00f8: 0xf8f8, # [unknown unicode name for parenrightbt] + 0x00f9: 0xf8f9, # [unknown unicode name for bracketrighttp] + 0x00fa: 0xf8fa, # [unknown unicode name for bracketrightex] + 0x00fb: 0xf8fb, # [unknown unicode name for bracketrightbt] + 0x00fc: 0xf8fc, # [unknown unicode name for bracerighttp] + 0x00fd: 0xf8fd, # [unknown unicode name for bracerightmid] + 0x00fe: 0xf8fe, # [unknown unicode name for bracerightbt] + 0x00ff: None, # UNDEFINED + }, + { + 0x0394:0x0044, # GREEK CAPITAL LETTER DELTA + 0x03a9:0x0057, # GREEK CAPITAL LETTER OMEGA + 0x03bc:0x006d, # GREEK SMALL LETTER MU + } + ), + 'zapfdingbats':StdCodecData({ + 0x0021: 0x2701, # UPPER BLADE SCISSORS + 0x0022: 0x2702, # BLACK SCISSORS + 0x0023: 0x2703, # LOWER BLADE SCISSORS + 0x0024: 0x2704, # WHITE SCISSORS + 0x0025: 0x260e, # BLACK TELEPHONE + 0x0026: 0x2706, # TELEPHONE LOCATION SIGN + 0x0027: 0x2707, # TAPE DRIVE + 0x0028: 0x2708, # AIRPLANE + 0x0029: 0x2709, # ENVELOPE + 0x002a: 0x261b, # BLACK RIGHT POINTING INDEX + 0x002b: 0x261e, # WHITE RIGHT POINTING INDEX + 0x002c: 0x270c, # VICTORY HAND + 0x002d: 0x270d, # WRITING HAND + 0x002e: 0x270e, # LOWER RIGHT PENCIL + 0x002f: 0x270f, # PENCIL + 0x0030: 0x2710, # UPPER RIGHT PENCIL + 0x0031: 0x2711, # WHITE NIB + 0x0032: 0x2712, # BLACK NIB + 0x0033: 0x2713, # CHECK MARK + 0x0034: 0x2714, # HEAVY CHECK MARK + 0x0035: 0x2715, # MULTIPLICATION X + 0x0036: 0x2716, # HEAVY MULTIPLICATION X + 0x0037: 0x2717, # BALLOT X + 0x0038: 0x2718, # HEAVY BALLOT X + 0x0039: 0x2719, # OUTLINED GREEK CROSS + 0x003a: 0x271a, # HEAVY GREEK CROSS + 0x003b: 0x271b, # OPEN CENTRE CROSS + 0x003c: 0x271c, # HEAVY OPEN CENTRE CROSS + 0x003d: 0x271d, # LATIN CROSS + 0x003e: 0x271e, # SHADOWED WHITE LATIN CROSS + 0x003f: 0x271f, # OUTLINED LATIN CROSS + 0x0040: 0x2720, # MALTESE CROSS + 0x0041: 0x2721, # STAR OF DAVID + 0x0042: 0x2722, # FOUR TEARDROP-SPOKED ASTERISK + 0x0043: 0x2723, # FOUR BALLOON-SPOKED ASTERISK + 0x0044: 0x2724, # HEAVY FOUR BALLOON-SPOKED ASTERISK + 0x0045: 0x2725, # FOUR CLUB-SPOKED ASTERISK + 0x0046: 0x2726, # BLACK FOUR POINTED STAR + 0x0047: 0x2727, # WHITE FOUR POINTED STAR + 0x0048: 0x2605, # BLACK STAR + 0x0049: 0x2729, # STRESS OUTLINED WHITE STAR + 0x004a: 0x272a, # CIRCLED WHITE STAR + 0x004b: 0x272b, # OPEN CENTRE BLACK STAR + 0x004c: 0x272c, # BLACK CENTRE WHITE STAR + 0x004d: 0x272d, # OUTLINED BLACK STAR + 0x004e: 0x272e, # HEAVY OUTLINED BLACK STAR + 0x004f: 0x272f, # PINWHEEL STAR + 0x0050: 0x2730, # SHADOWED WHITE STAR + 0x0051: 0x2731, # HEAVY ASTERISK + 0x0052: 0x2732, # OPEN CENTRE ASTERISK + 0x0053: 0x2733, # EIGHT SPOKED ASTERISK + 0x0054: 0x2734, # EIGHT POINTED BLACK STAR + 0x0055: 0x2735, # EIGHT POINTED PINWHEEL STAR + 0x0056: 0x2736, # SIX POINTED BLACK STAR + 0x0057: 0x2737, # EIGHT POINTED RECTILINEAR BLACK STAR + 0x0058: 0x2738, # HEAVY EIGHT POINTED RECTILINEAR BLACK STAR + 0x0059: 0x2739, # TWELVE POINTED BLACK STAR + 0x005a: 0x273a, # SIXTEEN POINTED ASTERISK + 0x005b: 0x273b, # TEARDROP-SPOKED ASTERISK + 0x005c: 0x273c, # OPEN CENTRE TEARDROP-SPOKED ASTERISK + 0x005d: 0x273d, # HEAVY TEARDROP-SPOKED ASTERISK + 0x005e: 0x273e, # SIX PETALLED BLACK AND WHITE FLORETTE + 0x005f: 0x273f, # BLACK FLORETTE + 0x0060: 0x2740, # WHITE FLORETTE + 0x0061: 0x2741, # EIGHT PETALLED OUTLINED BLACK FLORETTE + 0x0062: 0x2742, # CIRCLED OPEN CENTRE EIGHT POINTED STAR + 0x0063: 0x2743, # HEAVY TEARDROP-SPOKED PINWHEEL ASTERISK + 0x0064: 0x2744, # SNOWFLAKE + 0x0065: 0x2745, # TIGHT TRIFOLIATE SNOWFLAKE + 0x0066: 0x2746, # HEAVY CHEVRON SNOWFLAKE + 0x0067: 0x2747, # SPARKLE + 0x0068: 0x2748, # HEAVY SPARKLE + 0x0069: 0x2749, # BALLOON-SPOKED ASTERISK + 0x006a: 0x274a, # EIGHT TEARDROP-SPOKED PROPELLER ASTERISK + 0x006b: 0x274b, # HEAVY EIGHT TEARDROP-SPOKED PROPELLER ASTERISK + 0x006c: 0x25cf, # BLACK CIRCLE + 0x006d: 0x274d, # SHADOWED WHITE CIRCLE + 0x006e: 0x25a0, # BLACK SQUARE + 0x006f: 0x274f, # LOWER RIGHT DROP-SHADOWED WHITE SQUARE + 0x0070: 0x2750, # UPPER RIGHT DROP-SHADOWED WHITE SQUARE + 0x0071: 0x2751, # LOWER RIGHT SHADOWED WHITE SQUARE + 0x0072: 0x2752, # UPPER RIGHT SHADOWED WHITE SQUARE + 0x0073: 0x25b2, # BLACK UP-POINTING TRIANGLE + 0x0074: 0x25bc, # BLACK DOWN-POINTING TRIANGLE + 0x0075: 0x25c6, # BLACK DIAMOND + 0x0076: 0x2756, # BLACK DIAMOND MINUS WHITE X + 0x0077: 0x25d7, # RIGHT HALF BLACK CIRCLE + 0x0078: 0x2758, # LIGHT VERTICAL BAR + 0x0079: 0x2759, # MEDIUM VERTICAL BAR + 0x007a: 0x275a, # HEAVY VERTICAL BAR + 0x007b: 0x275b, # HEAVY SINGLE TURNED COMMA QUOTATION MARK ORNAMENT + 0x007c: 0x275c, # HEAVY SINGLE COMMA QUOTATION MARK ORNAMENT + 0x007d: 0x275d, # HEAVY DOUBLE TURNED COMMA QUOTATION MARK ORNAMENT + 0x007e: 0x275e, # HEAVY DOUBLE COMMA QUOTATION MARK ORNAMENT + 0x007f: None, # UNDEFINED + 0x0080: 0x2768, # MEDIUM LEFT PARENTHESIS ORNAMENT + 0x0081: 0x2769, # MEDIUM RIGHT PARENTHESIS ORNAMENT + 0x0082: 0x276a, # MEDIUM FLATTENED LEFT PARENTHESIS ORNAMENT + 0x0083: 0x276b, # MEDIUM FLATTENED RIGHT PARENTHESIS ORNAMENT + 0x0084: 0x276c, # MEDIUM LEFT-POINTING ANGLE BRACKET ORNAMENT + 0x0085: 0x276d, # MEDIUM RIGHT-POINTING ANGLE BRACKET ORNAMENT + 0x0086: 0x276e, # HEAVY LEFT-POINTING ANGLE QUOTATION MARK ORNAMENT + 0x0087: 0x276f, # HEAVY RIGHT-POINTING ANGLE QUOTATION MARK ORNAMENT + 0x0088: 0x2770, # HEAVY LEFT-POINTING ANGLE BRACKET ORNAMENT + 0x0089: 0x2771, # HEAVY RIGHT-POINTING ANGLE BRACKET ORNAMENT + 0x008a: 0x2772, # LIGHT LEFT TORTOISE SHELL BRACKET ORNAMENT + 0x008b: 0x2773, # LIGHT RIGHT TORTOISE SHELL BRACKET ORNAMENT + 0x008c: 0x2774, # MEDIUM LEFT CURLY BRACKET ORNAMENT + 0x008d: 0x2775, # MEDIUM RIGHT CURLY BRACKET ORNAMENT + 0x008e: None, # UNDEFINED + 0x008f: None, # UNDEFINED + 0x0090: None, # UNDEFINED + 0x0091: None, # UNDEFINED + 0x0092: None, # UNDEFINED + 0x0093: None, # UNDEFINED + 0x0094: None, # UNDEFINED + 0x0095: None, # UNDEFINED + 0x0096: None, # UNDEFINED + 0x0097: None, # UNDEFINED + 0x0098: None, # UNDEFINED + 0x0099: None, # UNDEFINED + 0x009a: None, # UNDEFINED + 0x009b: None, # UNDEFINED + 0x009c: None, # UNDEFINED + 0x009d: None, # UNDEFINED + 0x009e: None, # UNDEFINED + 0x009f: None, # UNDEFINED + 0x00a0: None, # UNDEFINED + 0x00a1: 0x2761, # CURVED STEM PARAGRAPH SIGN ORNAMENT + 0x00a2: 0x2762, # HEAVY EXCLAMATION MARK ORNAMENT + 0x00a3: 0x2763, # HEAVY HEART EXCLAMATION MARK ORNAMENT + 0x00a4: 0x2764, # HEAVY BLACK HEART + 0x00a5: 0x2765, # ROTATED HEAVY BLACK HEART BULLET + 0x00a6: 0x2766, # FLORAL HEART + 0x00a7: 0x2767, # ROTATED FLORAL HEART BULLET + 0x00a8: 0x2663, # BLACK CLUB SUIT + 0x00a9: 0x2666, # BLACK DIAMOND SUIT + 0x00aa: 0x2665, # BLACK HEART SUIT + 0x00ab: 0x2660, # BLACK SPADE SUIT + 0x00ac: 0x2460, # CIRCLED DIGIT ONE + 0x00ad: 0x2461, # CIRCLED DIGIT TWO + 0x00ae: 0x2462, # CIRCLED DIGIT THREE + 0x00af: 0x2463, # CIRCLED DIGIT FOUR + 0x00b0: 0x2464, # CIRCLED DIGIT FIVE + 0x00b1: 0x2465, # CIRCLED DIGIT SIX + 0x00b2: 0x2466, # CIRCLED DIGIT SEVEN + 0x00b3: 0x2467, # CIRCLED DIGIT EIGHT + 0x00b4: 0x2468, # CIRCLED DIGIT NINE + 0x00b5: 0x2469, # CIRCLED NUMBER TEN + 0x00b6: 0x2776, # DINGBAT NEGATIVE CIRCLED DIGIT ONE + 0x00b7: 0x2777, # DINGBAT NEGATIVE CIRCLED DIGIT TWO + 0x00b8: 0x2778, # DINGBAT NEGATIVE CIRCLED DIGIT THREE + 0x00b9: 0x2779, # DINGBAT NEGATIVE CIRCLED DIGIT FOUR + 0x00ba: 0x277a, # DINGBAT NEGATIVE CIRCLED DIGIT FIVE + 0x00bb: 0x277b, # DINGBAT NEGATIVE CIRCLED DIGIT SIX + 0x00bc: 0x277c, # DINGBAT NEGATIVE CIRCLED DIGIT SEVEN + 0x00bd: 0x277d, # DINGBAT NEGATIVE CIRCLED DIGIT EIGHT + 0x00be: 0x277e, # DINGBAT NEGATIVE CIRCLED DIGIT NINE + 0x00bf: 0x277f, # DINGBAT NEGATIVE CIRCLED NUMBER TEN + 0x00c0: 0x2780, # DINGBAT CIRCLED SANS-SERIF DIGIT ONE + 0x00c1: 0x2781, # DINGBAT CIRCLED SANS-SERIF DIGIT TWO + 0x00c2: 0x2782, # DINGBAT CIRCLED SANS-SERIF DIGIT THREE + 0x00c3: 0x2783, # DINGBAT CIRCLED SANS-SERIF DIGIT FOUR + 0x00c4: 0x2784, # DINGBAT CIRCLED SANS-SERIF DIGIT FIVE + 0x00c5: 0x2785, # DINGBAT CIRCLED SANS-SERIF DIGIT SIX + 0x00c6: 0x2786, # DINGBAT CIRCLED SANS-SERIF DIGIT SEVEN + 0x00c7: 0x2787, # DINGBAT CIRCLED SANS-SERIF DIGIT EIGHT + 0x00c8: 0x2788, # DINGBAT CIRCLED SANS-SERIF DIGIT NINE + 0x00c9: 0x2789, # DINGBAT CIRCLED SANS-SERIF NUMBER TEN + 0x00ca: 0x278a, # DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT ONE + 0x00cb: 0x278b, # DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT TWO + 0x00cc: 0x278c, # DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT THREE + 0x00cd: 0x278d, # DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT FOUR + 0x00ce: 0x278e, # DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT FIVE + 0x00cf: 0x278f, # DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT SIX + 0x00d0: 0x2790, # DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT SEVEN + 0x00d1: 0x2791, # DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT EIGHT + 0x00d2: 0x2792, # DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT NINE + 0x00d3: 0x2793, # DINGBAT NEGATIVE CIRCLED SANS-SERIF NUMBER TEN + 0x00d4: 0x2794, # HEAVY WIDE-HEADED RIGHTWARDS ARROW + 0x00d5: 0x2192, # RIGHTWARDS ARROW + 0x00d6: 0x2194, # LEFT RIGHT ARROW + 0x00d7: 0x2195, # UP DOWN ARROW + 0x00d8: 0x2798, # HEAVY SOUTH EAST ARROW + 0x00d9: 0x2799, # HEAVY RIGHTWARDS ARROW + 0x00da: 0x279a, # HEAVY NORTH EAST ARROW + 0x00db: 0x279b, # DRAFTING POINT RIGHTWARDS ARROW + 0x00dc: 0x279c, # HEAVY ROUND-TIPPED RIGHTWARDS ARROW + 0x00dd: 0x279d, # TRIANGLE-HEADED RIGHTWARDS ARROW + 0x00de: 0x279e, # HEAVY TRIANGLE-HEADED RIGHTWARDS ARROW + 0x00df: 0x279f, # DASHED TRIANGLE-HEADED RIGHTWARDS ARROW + 0x00e0: 0x27a0, # HEAVY DASHED TRIANGLE-HEADED RIGHTWARDS ARROW + 0x00e1: 0x27a1, # BLACK RIGHTWARDS ARROW + 0x00e2: 0x27a2, # THREE-D TOP-LIGHTED RIGHTWARDS ARROWHEAD + 0x00e3: 0x27a3, # THREE-D BOTTOM-LIGHTED RIGHTWARDS ARROWHEAD + 0x00e4: 0x27a4, # BLACK RIGHTWARDS ARROWHEAD + 0x00e5: 0x27a5, # HEAVY BLACK CURVED DOWNWARDS AND RIGHTWARDS ARROW + 0x00e6: 0x27a6, # HEAVY BLACK CURVED UPWARDS AND RIGHTWARDS ARROW + 0x00e7: 0x27a7, # SQUAT BLACK RIGHTWARDS ARROW + 0x00e8: 0x27a8, # HEAVY CONCAVE-POINTED BLACK RIGHTWARDS ARROW + 0x00e9: 0x27a9, # RIGHT-SHADED WHITE RIGHTWARDS ARROW + 0x00ea: 0x27aa, # LEFT-SHADED WHITE RIGHTWARDS ARROW + 0x00eb: 0x27ab, # BACK-TILTED SHADOWED WHITE RIGHTWARDS ARROW + 0x00ec: 0x27ac, # FRONT-TILTED SHADOWED WHITE RIGHTWARDS ARROW + 0x00ed: 0x27ad, # HEAVY LOWER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW + 0x00ee: 0x27ae, # HEAVY UPPER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW + 0x00ef: 0x27af, # NOTCHED LOWER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW + 0x00f0: None, # UNDEFINED + 0x00f1: 0x27b1, # NOTCHED UPPER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW + 0x00f2: 0x27b2, # CIRCLED HEAVY WHITE RIGHTWARDS ARROW + 0x00f3: 0x27b3, # WHITE-FEATHERED RIGHTWARDS ARROW + 0x00f4: 0x27b4, # BLACK-FEATHERED SOUTH EAST ARROW + 0x00f5: 0x27b5, # BLACK-FEATHERED RIGHTWARDS ARROW + 0x00f6: 0x27b6, # BLACK-FEATHERED NORTH EAST ARROW + 0x00f7: 0x27b7, # HEAVY BLACK-FEATHERED SOUTH EAST ARROW + 0x00f8: 0x27b8, # HEAVY BLACK-FEATHERED RIGHTWARDS ARROW + 0x00f9: 0x27b9, # HEAVY BLACK-FEATHERED NORTH EAST ARROW + 0x00fa: 0x27ba, # TEARDROP-BARBED RIGHTWARDS ARROW + 0x00fb: 0x27bb, # HEAVY TEARDROP-SHANKED RIGHTWARDS ARROW + 0x00fc: 0x27bc, # WEDGE-TAILED RIGHTWARDS ARROW + 0x00fd: 0x27bd, # HEAVY WEDGE-TAILED RIGHTWARDS ARROW + 0x00fe: 0x27be, # OPEN-OUTLINED RIGHTWARDS ARROW + 0x00ff: None, # UNDEFINED + },None), + 'pdfdoc':StdCodecData({ + 0x007f: None, # UNDEFINED + 0x0080: 0x2022, # BULLET + 0x0081: 0x2020, # DAGGER + 0x0082: 0x2021, # DOUBLE DAGGER + 0x0083: 0x2026, # HORIZONTAL ELLIPSIS + 0x0084: 0x2014, # EM DASH + 0x0085: 0x2013, # EN DASH + 0x0086: 0x0192, # LATIN SMALL LETTER F WITH HOOK + 0x0087: 0x2044, # FRACTION SLASH + 0x0088: 0x2039, # SINGLE LEFT-POINTING ANGLE QUOTATION MARK + 0x0089: 0x203a, # SINGLE RIGHT-POINTING ANGLE QUOTATION MARK + 0x008a: 0x2212, # MINUS SIGN + 0x008b: 0x2030, # PER MILLE SIGN + 0x008c: 0x201e, # DOUBLE LOW-9 QUOTATION MARK + 0x008d: 0x201c, # LEFT DOUBLE QUOTATION MARK + 0x008e: 0x201d, # RIGHT DOUBLE QUOTATION MARK + 0x008f: 0x2018, # LEFT SINGLE QUOTATION MARK + 0x0090: 0x2019, # RIGHT SINGLE QUOTATION MARK + 0x0091: 0x201a, # SINGLE LOW-9 QUOTATION MARK + 0x0092: 0x2122, # TRADE MARK SIGN + 0x0093: 0xfb01, # LATIN SMALL LIGATURE FI + 0x0094: 0xfb02, # LATIN SMALL LIGATURE FL + 0x0095: 0x0141, # LATIN CAPITAL LETTER L WITH STROKE + 0x0096: 0x0152, # LATIN CAPITAL LIGATURE OE + 0x0097: 0x0160, # LATIN CAPITAL LETTER S WITH CARON + 0x0098: 0x0178, # LATIN CAPITAL LETTER Y WITH DIAERESIS + 0x0099: 0x017d, # LATIN CAPITAL LETTER Z WITH CARON + 0x009a: 0x0131, # LATIN SMALL LETTER DOTLESS I + 0x009b: 0x0142, # LATIN SMALL LETTER L WITH STROKE + 0x009c: 0x0153, # LATIN SMALL LIGATURE OE + 0x009d: 0x0161, # LATIN SMALL LETTER S WITH CARON + 0x009e: 0x017e, # LATIN SMALL LETTER Z WITH CARON + 0x009f: None, # UNDEFINED + 0x00a0: 0x20ac, # EURO SIGN + 0x00ad: None, # UNDEFINED + 24: 0x02d8, #breve + 25: 0x02c7, #caron + 26: 0x02c6, #circumflex + 27: 0x02d9, #dotaccent + 28: 0x02dd, #hungarumlaut + 29: 0x02db, #ogonek + 30: 0x02da, #ring + 31: 0x02dc, #tilde + },None), + 'macexpert':StdCodecData({ + 0x0021: 0xf721, # [unknown unicode name for exclamsmall] + 0x0022: 0xf6f8, # [unknown unicode name for Hungarumlautsmall] + 0x0023: 0xf7a2, # [unknown unicode name for centoldstyle] + 0x0024: 0xf724, # [unknown unicode name for dollaroldstyle] + 0x0025: 0xf6e4, # [unknown unicode name for dollarsuperior] + 0x0026: 0xf726, # [unknown unicode name for ampersandsmall] + 0x0027: 0xf7b4, # [unknown unicode name for Acutesmall] + 0x0028: 0x207d, # SUPERSCRIPT LEFT PARENTHESIS + 0x0029: 0x207e, # SUPERSCRIPT RIGHT PARENTHESIS + 0x002a: 0x2025, # TWO DOT LEADER + 0x002b: 0x2024, # ONE DOT LEADER + 0x002f: 0x2044, # FRACTION SLASH + 0x0030: 0xf730, # [unknown unicode name for zerooldstyle] + 0x0031: 0xf731, # [unknown unicode name for oneoldstyle] + 0x0032: 0xf732, # [unknown unicode name for twooldstyle] + 0x0033: 0xf733, # [unknown unicode name for threeoldstyle] + 0x0034: 0xf734, # [unknown unicode name for fouroldstyle] + 0x0035: 0xf735, # [unknown unicode name for fiveoldstyle] + 0x0036: 0xf736, # [unknown unicode name for sixoldstyle] + 0x0037: 0xf737, # [unknown unicode name for sevenoldstyle] + 0x0038: 0xf738, # [unknown unicode name for eightoldstyle] + 0x0039: 0xf739, # [unknown unicode name for nineoldstyle] + 0x003c: None, # UNDEFINED + 0x003d: 0xf6de, # [unknown unicode name for threequartersemdash] + 0x003e: None, # UNDEFINED + 0x003f: 0xf73f, # [unknown unicode name for questionsmall] + 0x0040: None, # UNDEFINED + 0x0041: None, # UNDEFINED + 0x0042: None, # UNDEFINED + 0x0043: None, # UNDEFINED + 0x0044: 0xf7f0, # [unknown unicode name for Ethsmall] + 0x0045: None, # UNDEFINED + 0x0046: None, # UNDEFINED + 0x0047: 0x00bc, # VULGAR FRACTION ONE QUARTER + 0x0048: 0x00bd, # VULGAR FRACTION ONE HALF + 0x0049: 0x00be, # VULGAR FRACTION THREE QUARTERS + 0x004a: 0x215b, # VULGAR FRACTION ONE EIGHTH + 0x004b: 0x215c, # VULGAR FRACTION THREE EIGHTHS + 0x004c: 0x215d, # VULGAR FRACTION FIVE EIGHTHS + 0x004d: 0x215e, # VULGAR FRACTION SEVEN EIGHTHS + 0x004e: 0x2153, # VULGAR FRACTION ONE THIRD + 0x004f: 0x2154, # VULGAR FRACTION TWO THIRDS + 0x0050: None, # UNDEFINED + 0x0051: None, # UNDEFINED + 0x0052: None, # UNDEFINED + 0x0053: None, # UNDEFINED + 0x0054: None, # UNDEFINED + 0x0055: None, # UNDEFINED + 0x0056: 0xfb00, # LATIN SMALL LIGATURE FF + 0x0057: 0xfb01, # LATIN SMALL LIGATURE FI + 0x0058: 0xfb02, # LATIN SMALL LIGATURE FL + 0x0059: 0xfb03, # LATIN SMALL LIGATURE FFI + 0x005a: 0xfb04, # LATIN SMALL LIGATURE FFL + 0x005b: 0x208d, # SUBSCRIPT LEFT PARENTHESIS + 0x005c: None, # UNDEFINED + 0x005d: 0x208e, # SUBSCRIPT RIGHT PARENTHESIS + 0x005e: 0xf6f6, # [unknown unicode name for Circumflexsmall] + 0x005f: 0xf6e5, # [unknown unicode name for hypheninferior] + 0x0060: 0xf760, # [unknown unicode name for Gravesmall] + 0x0061: 0xf761, # [unknown unicode name for Asmall] + 0x0062: 0xf762, # [unknown unicode name for Bsmall] + 0x0063: 0xf763, # [unknown unicode name for Csmall] + 0x0064: 0xf764, # [unknown unicode name for Dsmall] + 0x0065: 0xf765, # [unknown unicode name for Esmall] + 0x0066: 0xf766, # [unknown unicode name for Fsmall] + 0x0067: 0xf767, # [unknown unicode name for Gsmall] + 0x0068: 0xf768, # [unknown unicode name for Hsmall] + 0x0069: 0xf769, # [unknown unicode name for Ismall] + 0x006a: 0xf76a, # [unknown unicode name for Jsmall] + 0x006b: 0xf76b, # [unknown unicode name for Ksmall] + 0x006c: 0xf76c, # [unknown unicode name for Lsmall] + 0x006d: 0xf76d, # [unknown unicode name for Msmall] + 0x006e: 0xf76e, # [unknown unicode name for Nsmall] + 0x006f: 0xf76f, # [unknown unicode name for Osmall] + 0x0070: 0xf770, # [unknown unicode name for Psmall] + 0x0071: 0xf771, # [unknown unicode name for Qsmall] + 0x0072: 0xf772, # [unknown unicode name for Rsmall] + 0x0073: 0xf773, # [unknown unicode name for Ssmall] + 0x0074: 0xf774, # [unknown unicode name for Tsmall] + 0x0075: 0xf775, # [unknown unicode name for Usmall] + 0x0076: 0xf776, # [unknown unicode name for Vsmall] + 0x0077: 0xf777, # [unknown unicode name for Wsmall] + 0x0078: 0xf778, # [unknown unicode name for Xsmall] + 0x0079: 0xf779, # [unknown unicode name for Ysmall] + 0x007a: 0xf77a, # [unknown unicode name for Zsmall] + 0x007b: 0x20a1, # COLON SIGN + 0x007c: 0xf6dc, # [unknown unicode name for onefitted] + 0x007d: 0xf6dd, # [unknown unicode name for rupiah] + 0x007e: 0xf6fe, # [unknown unicode name for Tildesmall] + 0x007f: None, # UNDEFINED + 0x0080: None, # UNDEFINED + 0x0081: 0xf6e9, # [unknown unicode name for asuperior] + 0x0082: 0xf6e0, # [unknown unicode name for centsuperior] + 0x0083: None, # UNDEFINED + 0x0084: None, # UNDEFINED + 0x0085: None, # UNDEFINED + 0x0086: None, # UNDEFINED + 0x0087: 0xf7e1, # [unknown unicode name for Aacutesmall] + 0x0088: 0xf7e0, # [unknown unicode name for Agravesmall] + 0x0089: 0xf7e2, # [unknown unicode name for Acircumflexsmall] + 0x008a: 0xf7e4, # [unknown unicode name for Adieresissmall] + 0x008b: 0xf7e3, # [unknown unicode name for Atildesmall] + 0x008c: 0xf7e5, # [unknown unicode name for Aringsmall] + 0x008d: 0xf7e7, # [unknown unicode name for Ccedillasmall] + 0x008e: 0xf7e9, # [unknown unicode name for Eacutesmall] + 0x008f: 0xf7e8, # [unknown unicode name for Egravesmall] + 0x0090: 0xf7ea, # [unknown unicode name for Ecircumflexsmall] + 0x0091: 0xf7eb, # [unknown unicode name for Edieresissmall] + 0x0092: 0xf7ed, # [unknown unicode name for Iacutesmall] + 0x0093: 0xf7ec, # [unknown unicode name for Igravesmall] + 0x0094: 0xf7ee, # [unknown unicode name for Icircumflexsmall] + 0x0095: 0xf7ef, # [unknown unicode name for Idieresissmall] + 0x0096: 0xf7f1, # [unknown unicode name for Ntildesmall] + 0x0097: 0xf7f3, # [unknown unicode name for Oacutesmall] + 0x0098: 0xf7f2, # [unknown unicode name for Ogravesmall] + 0x0099: 0xf7f4, # [unknown unicode name for Ocircumflexsmall] + 0x009a: 0xf7f6, # [unknown unicode name for Odieresissmall] + 0x009b: 0xf7f5, # [unknown unicode name for Otildesmall] + 0x009c: 0xf7fa, # [unknown unicode name for Uacutesmall] + 0x009d: 0xf7f9, # [unknown unicode name for Ugravesmall] + 0x009e: 0xf7fb, # [unknown unicode name for Ucircumflexsmall] + 0x009f: 0xf7fc, # [unknown unicode name for Udieresissmall] + 0x00a0: None, # UNDEFINED + 0x00a1: 0x2078, # SUPERSCRIPT EIGHT + 0x00a2: 0x2084, # SUBSCRIPT FOUR + 0x00a3: 0x2083, # SUBSCRIPT THREE + 0x00a4: 0x2086, # SUBSCRIPT SIX + 0x00a5: 0x2088, # SUBSCRIPT EIGHT + 0x00a6: 0x2087, # SUBSCRIPT SEVEN + 0x00a7: 0xf6fd, # [unknown unicode name for Scaronsmall] + 0x00a8: None, # UNDEFINED + 0x00a9: 0xf6df, # [unknown unicode name for centinferior] + 0x00aa: 0x2082, # SUBSCRIPT TWO + 0x00ab: None, # UNDEFINED + 0x00ac: 0xf7a8, # [unknown unicode name for Dieresissmall] + 0x00ad: None, # UNDEFINED + 0x00ae: 0xf6f5, # [unknown unicode name for Caronsmall] + 0x00af: 0xf6f0, # [unknown unicode name for osuperior] + 0x00b0: 0x2085, # SUBSCRIPT FIVE + 0x00b1: None, # UNDEFINED + 0x00b2: 0xf6e1, # [unknown unicode name for commainferior] + 0x00b3: 0xf6e7, # [unknown unicode name for periodinferior] + 0x00b4: 0xf7fd, # [unknown unicode name for Yacutesmall] + 0x00b5: None, # UNDEFINED + 0x00b6: 0xf6e3, # [unknown unicode name for dollarinferior] + 0x00b7: None, # UNDEFINED + 0x00b8: None, # UNDEFINED + 0x00b9: 0xf7fe, # [unknown unicode name for Thornsmall] + 0x00ba: None, # UNDEFINED + 0x00bb: 0x2089, # SUBSCRIPT NINE + 0x00bc: 0x2080, # SUBSCRIPT ZERO + 0x00bd: 0xf6ff, # [unknown unicode name for Zcaronsmall] + 0x00be: 0xf7e6, # [unknown unicode name for AEsmall] + 0x00bf: 0xf7f8, # [unknown unicode name for Oslashsmall] + 0x00c0: 0xf7bf, # [unknown unicode name for questiondownsmall] + 0x00c1: 0x2081, # SUBSCRIPT ONE + 0x00c2: 0xf6f9, # [unknown unicode name for Lslashsmall] + 0x00c3: None, # UNDEFINED + 0x00c4: None, # UNDEFINED + 0x00c5: None, # UNDEFINED + 0x00c6: None, # UNDEFINED + 0x00c7: None, # UNDEFINED + 0x00c8: None, # UNDEFINED + 0x00c9: 0xf7b8, # [unknown unicode name for Cedillasmall] + 0x00ca: None, # UNDEFINED + 0x00cb: None, # UNDEFINED + 0x00cc: None, # UNDEFINED + 0x00cd: None, # UNDEFINED + 0x00ce: None, # UNDEFINED + 0x00cf: 0xf6fa, # [unknown unicode name for OEsmall] + 0x00d0: 0x2012, # FIGURE DASH + 0x00d1: 0xf6e6, # [unknown unicode name for hyphensuperior] + 0x00d2: None, # UNDEFINED + 0x00d3: None, # UNDEFINED + 0x00d4: None, # UNDEFINED + 0x00d5: None, # UNDEFINED + 0x00d6: 0xf7a1, # [unknown unicode name for exclamdownsmall] + 0x00d7: None, # UNDEFINED + 0x00d8: 0xf7ff, # [unknown unicode name for Ydieresissmall] + 0x00d9: None, # UNDEFINED + 0x00da: 0x00b9, # SUPERSCRIPT ONE + 0x00db: 0x00b2, # SUPERSCRIPT TWO + 0x00dc: 0x00b3, # SUPERSCRIPT THREE + 0x00dd: 0x2074, # SUPERSCRIPT FOUR + 0x00de: 0x2075, # SUPERSCRIPT FIVE + 0x00df: 0x2076, # SUPERSCRIPT SIX + 0x00e0: 0x2077, # SUPERSCRIPT SEVEN + 0x00e1: 0x2079, # SUPERSCRIPT NINE + 0x00e2: 0x2070, # SUPERSCRIPT ZERO + 0x00e3: None, # UNDEFINED + 0x00e4: 0xf6ec, # [unknown unicode name for esuperior] + 0x00e5: 0xf6f1, # [unknown unicode name for rsuperior] + 0x00e6: 0xf6f3, # [unknown unicode name for tsuperior] + 0x00e7: None, # UNDEFINED + 0x00e8: None, # UNDEFINED + 0x00e9: 0xf6ed, # [unknown unicode name for isuperior] + 0x00ea: 0xf6f2, # [unknown unicode name for ssuperior] + 0x00eb: 0xf6eb, # [unknown unicode name for dsuperior] + 0x00ec: None, # UNDEFINED + 0x00ed: None, # UNDEFINED + 0x00ee: None, # UNDEFINED + 0x00ef: None, # UNDEFINED + 0x00f0: None, # UNDEFINED + 0x00f1: 0xf6ee, # [unknown unicode name for lsuperior] + 0x00f2: 0xf6fb, # [unknown unicode name for Ogoneksmall] + 0x00f3: 0xf6f4, # [unknown unicode name for Brevesmall] + 0x00f4: 0xf7af, # [unknown unicode name for Macronsmall] + 0x00f5: 0xf6ea, # [unknown unicode name for bsuperior] + 0x00f6: 0x207f, # SUPERSCRIPT LATIN SMALL LETTER N + 0x00f7: 0xf6ef, # [unknown unicode name for msuperior] + 0x00f8: 0xf6e2, # [unknown unicode name for commasuperior] + 0x00f9: 0xf6e8, # [unknown unicode name for periodsuperior] + 0x00fa: 0xf6f7, # [unknown unicode name for Dotaccentsmall] + 0x00fb: 0xf6fc, # [unknown unicode name for Ringsmall] + 0x00fc: None, # UNDEFINED + 0x00fd: None, # UNDEFINED + 0x00fe: None, # UNDEFINED + 0x00ff: None, # UNDEFINED + },None), + } + __rl_extension_codecs = { + 'extpdfdoc':ExtCodecData('pdfdoc',{0x000a:0x000a,0x000d:0x000d},None), + } + #for k,v in __rl_codecs_data.items(): + # __rl_codecs_data[k+'enc'] = __rl_codecs_data[k+'encoding'] = v + #del k,v + + def __init__(self): + raise NotImplementedError + + def _256_exception_codec(name,exceptions,rexceptions,baseRange=range(32,256)): + import codecs + decoding_map = codecs.make_identity_dict(baseRange) + decoding_map.update(exceptions) + encoding_map = codecs.make_encoding_map(decoding_map) + if rexceptions: encoding_map.update(rexceptions) + ### Codec APIs + class Codec(codecs.Codec): + def encode(self,input,errors='strict',charmap_encode=codecs.charmap_encode,encoding_map=encoding_map): + return charmap_encode(input,errors,encoding_map) + + def decode(self,input,errors='strict',charmap_decode=codecs.charmap_decode,decoding_map=decoding_map): + return charmap_decode(input,errors,decoding_map) + + class StreamWriter(Codec,codecs.StreamWriter): + pass + + class StreamReader(Codec,codecs.StreamReader): + pass + C = Codec() + return codecs.CodecInfo(C.encode,C.decode,streamreader=StreamReader,streamwriter=StreamWriter,name=name) + _256_exception_codec=staticmethod(_256_exception_codec) + + __rl_codecs_cache = {} + + def __rl_codecs(name,cache=__rl_codecs_cache,data=__rl_codecs_data,extension_codecs=__rl_extension_codecs): + try: + return cache[name] + except KeyError: + if name in extension_codecs: + x = extension_codecs[name] + e,r = data[x.baseName] + if x.exceptions: + if e: + e = e.copy() + e.update(x.exceptions) + else: + e = x.exceptions + if x.rexceptions: + if r: + r = r.copy() + r.update(x.rexceptions) + else: + r = x.exceptions + else: + e,r = data[name] + cache[name] = c = RL_Codecs._256_exception_codec(name,e,r) + return c + __rl_codecs=staticmethod(__rl_codecs) + + def _rl_codecs(name): + name = name.lower() + from reportlab.pdfbase.pdfmetrics import standardEncodings + for e in standardEncodings+('ExtPdfdocEncoding',): + e = e[:-8].lower() + if name.startswith(e): return RL_Codecs.__rl_codecs(e) + return None + _rl_codecs=staticmethod(_rl_codecs) + + def register(): + import codecs + codecs.register(RL_Codecs._rl_codecs) + register=staticmethod(register) diff --git a/reportlab/pdfbase/ttfonts.py b/reportlab/pdfbase/ttfonts.py new file mode 100644 index 00000000..4f873962 --- /dev/null +++ b/reportlab/pdfbase/ttfonts.py @@ -0,0 +1,1220 @@ +#Copyright ReportLab Europe Ltd. 2000-2012 +#see license.txt for license details +__version__ = '$Id$' +__doc__="""TrueType font support + +This defines classes to represent TrueType fonts. They know how to calculate +their own width and how to write themselves into PDF files. They support +subsetting and embedding and can represent all 16-bit Unicode characters. + +Note on dynamic fonts +--------------------- + +Usually a Font in ReportLab corresponds to a fixed set of PDF objects (Font, +FontDescriptor, Encoding). But with dynamic font subsetting a single TTFont +will result in a number of Font/FontDescriptor/Encoding object sets, and the +contents of those will depend on the actual characters used for printing. + +To support dynamic font subsetting a concept of "dynamic font" was introduced. +Dynamic Fonts have a _dynamicFont attribute set to 1. + +Dynamic fonts have the following additional functions:: + + def splitString(self, text, doc): + '''Splits text into a number of chunks, each of which belongs to a + single subset. Returns a list of tuples (subset, string). Use + subset numbers with getSubsetInternalName. Doc is used to identify + a document so that different documents may have different dynamically + constructed subsets.''' + + def getSubsetInternalName(self, subset, doc): + '''Returns the name of a PDF Font object corresponding to a given + subset of this dynamic font. Use this function instead of + PDFDocument.getInternalFontName.''' + +You must never call PDFDocument.getInternalFontName for dynamic fonts. + +If you have a traditional static font, mapping to PDF text output operators +is simple:: + + '%s 14 Tf (%s) Tj' % (getInternalFontName(psfontname), text) + +If you have a dynamic font, use this instead:: + + for subset, chunk in font.splitString(text, doc): + '%s 14 Tf (%s) Tj' % (font.getSubsetInternalName(subset, doc), chunk) + +(Tf is a font setting operator and Tj is a text ouput operator. You should +also escape invalid characters in Tj argument, see TextObject._formatText. +Oh, and that 14 up there is font size.) + +Canvas and TextObject have special support for dynamic fonts. +""" + +from struct import pack, unpack, error as structError +from reportlab.lib.utils import getBytesIO, isPy3, bytestr, isUnicode, char2int +from reportlab.pdfbase import pdfmetrics, pdfdoc +from reportlab import rl_config +from reportlab.lib.rl_accel import hex32, add32, calcChecksum, instanceStringWidthTTF +from collections import namedtuple + +class TTFError(pdfdoc.PDFError): + "TrueType font exception" + pass + + +if isPy3: + def SUBSETN(n,table=bytes.maketrans(b'0123456789',b'ABCDEFGIJK')): + return bytes('%6.6d'%n,'ASCII').translate(table) +else: + import string + def SUBSETN(n,table=string.maketrans(b'0123456789',b'ABCDEFGIJK'),translate=string.translate): + return translate('%6.6d'%n,table) +# +# Helpers +# +def makeToUnicodeCMap(fontname, subset): + """Creates a ToUnicode CMap for a given subset. See Adobe + _PDF_Reference (ISBN 0-201-75839-3) for more information.""" + cmap = [ + "/CIDInit /ProcSet findresource begin", + "12 dict begin", + "begincmap", + "/CIDSystemInfo", + "<< /Registry (%s)" % fontname, + "/Ordering (%s)" % fontname, + "/Supplement 0", + ">> def", + "/CMapName /%s def" % fontname, + "/CMapType 2 def", + "1 begincodespacerange", + "<00> <%02X>" % (len(subset) - 1), + "endcodespacerange", + "%d beginbfchar" % len(subset) + ] + ["<%02X> <%04X>" % (i,v) for i,v in enumerate(subset)] + [ + "endbfchar", + "endcmap", + "CMapName currentdict /CMap defineresource pop", + "end", + "end" + ] + return '\n'.join(cmap) + +def splice(stream, offset, value): + """Splices the given value into stream at the given offset and + returns the resulting stream (the original is unchanged)""" + return stream[:offset] + value + stream[offset + len(value):] + +def _set_ushort(stream, offset, value): + """Writes the given unsigned short value into stream at the given + offset and returns the resulting stream (the original is unchanged)""" + return splice(stream, offset, pack(">H", value)) +# +# TrueType font handling +# + +GF_ARG_1_AND_2_ARE_WORDS = 1 << 0 +GF_ARGS_ARE_XY_VALUES = 1 << 1 +GF_ROUND_XY_TO_GRID = 1 << 2 +GF_WE_HAVE_A_SCALE = 1 << 3 +GF_RESERVED = 1 << 4 +GF_MORE_COMPONENTS = 1 << 5 +GF_WE_HAVE_AN_X_AND_Y_SCALE = 1 << 6 +GF_WE_HAVE_A_TWO_BY_TWO = 1 << 7 +GF_WE_HAVE_INSTRUCTIONS = 1 << 8 +GF_USE_MY_METRICS = 1 << 9 +GF_OVERLAP_COMPOUND = 1 << 10 +GF_SCALED_COMPONENT_OFFSET = 1 << 11 +GF_UNSCALED_COMPONENT_OFFSET = 1 << 12 + +def TTFOpenFile(fn): + '''Opens a TTF file possibly after searching TTFSearchPath + returns (filename,file) + ''' + from reportlab.lib.utils import rl_isfile, open_for_read + try: + f = open_for_read(fn,'rb') + return fn, f + except IOError: + import os + if not os.path.isabs(fn): + for D in rl_config.TTFSearchPath: + tfn = os.path.join(D,fn) + if rl_isfile(tfn): + f = open_for_read(tfn,'rb') + return tfn, f + raise TTFError('Can\'t open file "%s"' % fn) + +class TTFontParser: + "Basic TTF file parser" + ttfVersions = (0x00010000,0x74727565,0x74746366) + ttcVersions = (0x00010000,0x00020000) + fileKind='TTF' + + def __init__(self, file, validate=0,subfontIndex=0): + """Loads and parses a TrueType font file. file can be a filename or a + file object. If validate is set to a false values, skips checksum + validation. This can save time, especially if the font is large. + """ + self.validate = validate + self.readFile(file) + isCollection = self.readHeader() + if isCollection: + self.readTTCHeader() + self.getSubfont(subfontIndex) + else: + if self.validate: self.checksumFile() + self.readTableDirectory() + self.subfontNameX = b'' + + def readTTCHeader(self): + self.ttcVersion = self.read_ulong() + self.fileKind = 'TTC' + self.ttfVersions = self.ttfVersions[:-1] + if self.ttcVersion not in self.ttcVersions: + raise TTFError('"%s" is not a %s file: can\'t read version 0x%8.8x' %(self.filename,self.fileKind,self.ttcVersion)) + self.numSubfonts = self.read_ulong() + self.subfontOffsets = [] + a = self.subfontOffsets.append + for i in xrange(self.numSubfonts): + a(self.read_ulong()) + + def getSubfont(self,subfontIndex): + if self.fileKind!='TTC': + raise TTFError('"%s" is not a TTC file: use this method' % (self.filename,self.fileKind)) + try: + pos = self.subfontOffsets[subfontIndex] + except IndexError: + raise TTFError('TTC file "%s": bad subfontIndex %s not in [0,%d]' % (self.filename,subfontIndex,self.numSubfonts-1)) + self.seek(pos) + self.readHeader() + self.readTableDirectory() + self.subfontNameX = bytestr('-'+str(subfontIndex)) + + def readTableDirectory(self): + try: + self.numTables = self.read_ushort() + self.searchRange = self.read_ushort() + self.entrySelector = self.read_ushort() + self.rangeShift = self.read_ushort() + + # Read table directory + self.table = {} + self.tables = [] + for n in xrange(self.numTables): + record = {} + record['tag'] = self.read_tag() + record['checksum'] = self.read_ulong() + record['offset'] = self.read_ulong() + record['length'] = self.read_ulong() + self.tables.append(record) + self.table[record['tag']] = record + except: + raise TTFError('Corrupt %s file "%s" cannot read Table Directory' % (self.fileKind, self.filename)) + if self.validate: self.checksumTables() + + def readHeader(self): + '''read the sfnt header at the current position''' + try: + self.version = version = self.read_ulong() + except: + raise TTFError('"%s" is not a %s file: can\'t read version' %(self.filename,self.fileKind)) + + if version==0x4F54544F: + raise TTFError('%s file "%s": postscript outlines are not supported'%(self.fileKind,self.filename)) + + if version not in self.ttfVersions: + raise TTFError('Not a TrueType font: version=0x%8.8X' % version) + return version==self.ttfVersions[-1] + + def readFile(self,f): + if hasattr(f,'read'): + self.filename = '(ttf)' + else: + self.filename, f = TTFOpenFile(f) + + self._ttf_data = f.read() + self._pos = 0 + + def checksumTables(self): + # Check the checksums for all tables + for t in self.tables: + table = self.get_chunk(t['offset'], t['length']) + checksum = calcChecksum(table) + if t['tag'] == 'head': + adjustment = unpack('>l', table[8:8+4])[0] + checksum = add32(checksum, -adjustment) + xchecksum = t['checksum'] + if xchecksum != checksum: + raise TTFError('TTF file "%s": invalid checksum %s table: %s (expected %s)' % (self.filename,hex32(checksum),t['tag'],hex32(xchecksum))) + + def checksumFile(self): + # Check the checksums for the whole file + checksum = calcChecksum(self._ttf_data) + if 0xB1B0AFBA!=checksum: + raise TTFError('TTF file "%s": invalid checksum %s (expected 0xB1B0AFBA) len: %d &3: %d' % (self.filename,hex32(checksum),len(self._ttf_data),(len(self._ttf_data)&3))) + + def get_table_pos(self, tag): + "Returns the offset and size of a given TTF table." + offset = self.table[tag]['offset'] + length = self.table[tag]['length'] + return (offset, length) + + def seek(self, pos): + "Moves read pointer to a given offset in file." + self._pos = pos + + def skip(self, delta): + "Skip the given number of bytes." + self._pos = self._pos + delta + + def seek_table(self, tag, offset_in_table = 0): + """Moves read pointer to the given offset within a given table and + returns absolute offset of that position in the file.""" + self._pos = self.get_table_pos(tag)[0] + offset_in_table + return self._pos + + if isPy3: + def read_tag(self): + "Read a 4-character tag" + self._pos += 4 + return str(self._ttf_data[self._pos - 4:self._pos],'utf8') + + def get_chunk(self, pos, length): + "Return a chunk of raw data at given position" + return bytes(self._ttf_data[pos:pos+length]) + + def read_uint8(self): + self._pos += 1 + return int(self._ttf_data[self._pos-1]) + else: + def read_tag(self): + "Read a 4-character tag" + self._pos += 4 + return self._ttf_data[self._pos - 4:self._pos] + + def get_chunk(self, pos, length): + "Return a chunk of raw data at given position" + return self._ttf_data[pos:pos+length] + + def read_uint8(self): + self._pos += 1 + return ord(self._ttf_data[self._pos-1]) + + def read_ushort(self): + "Reads an unsigned short" + self._pos += 2 + return unpack('>H',self._ttf_data[self._pos-2:self._pos])[0] + + def read_ulong(self): + "Reads an unsigned long" + self._pos += 4 + return unpack('>L',self._ttf_data[self._pos - 4:self._pos])[0] + + def read_short(self): + "Reads a signed short" + self._pos += 2 + try: + return unpack('>h',self._ttf_data[self._pos-2:self._pos])[0] + except structError as error: + raise TTFError(error) + + def get_ushort(self, pos): + "Return an unsigned short at given position" + return unpack('>H',self._ttf_data[pos:pos+2])[0] + + def get_ulong(self, pos): + "Return an unsigned long at given position" + return unpack('>L',self._ttf_data[pos:pos+4])[0] + + def get_table(self, tag): + "Return the given TTF table" + pos, length = self.get_table_pos(tag) + return self._ttf_data[pos:pos+length] + +class TTFontMaker: + "Basic TTF file generator" + + def __init__(self): + "Initializes the generator." + self.tables = {} + + def add(self, tag, data): + "Adds a table to the TTF file." + if tag == 'head': + data = splice(data, 8, b'\0\0\0\0') + self.tables[tag] = data + + def makeStream(self): + "Finishes the generation and returns the TTF file as a string" + stm = getBytesIO() + write = stm.write + + tables = self.tables + numTables = len(tables) + searchRange = 1 + entrySelector = 0 + while searchRange * 2 <= numTables: + searchRange = searchRange * 2 + entrySelector = entrySelector + 1 + searchRange = searchRange * 16 + rangeShift = numTables * 16 - searchRange + + # Header + write(pack(">lHHHH", 0x00010000, numTables, searchRange, + entrySelector, rangeShift)) + + # Table directory + offset = 12 + numTables * 16 + wStr = (lambda x:write(bytes(tag,'latin1'))) if isPy3 else write + tables_items = list(sorted(tables.items())) + for tag, data in tables_items: + if tag == 'head': + head_start = offset + checksum = calcChecksum(data) + wStr(tag) + write(pack(">LLL", checksum, offset, len(data))) + paddedLength = (len(data)+3)&~3 + offset = offset + paddedLength + + # Table data + for tag, data in tables_items: + data += b"\0\0\0" + write(data[:len(data)&~3]) + + checksum = calcChecksum(stm.getvalue()) + checksum = add32(0xB1B0AFBA, -checksum) + stm.seek(head_start + 8) + write(pack('>L', checksum)) + + return stm.getvalue() + +#this is used in the cmap encoding fmt==2 case +CMapFmt2SubHeader = namedtuple('CMapFmt2SubHeader', 'firstCode entryCount idDelta idRangeOffset') + +class TTFontFile(TTFontParser): + "TTF file parser and generator" + + def __init__(self, file, charInfo=1, validate=0,subfontIndex=0): + """Loads and parses a TrueType font file. + + file can be a filename or a file object. If validate is set to a false + values, skips checksum validation. This can save time, especially if + the font is large. See TTFontFile.extractInfo for more information. + """ + TTFontParser.__init__(self, file, validate=validate,subfontIndex=subfontIndex) + self.extractInfo(charInfo) + + def extractInfo(self, charInfo=1): + """ + Extract typographic information from the loaded font file. + + The following attributes will be set:: + + name PostScript font name + flags Font flags + ascent Typographic ascender in 1/1000ths of a point + descent Typographic descender in 1/1000ths of a point + capHeight Cap height in 1/1000ths of a point (0 if not available) + bbox Glyph bounding box [l,t,r,b] in 1/1000ths of a point + _bbox Glyph bounding box [l,t,r,b] in unitsPerEm + unitsPerEm Glyph units per em + italicAngle Italic angle in degrees ccw + stemV stem weight in 1/1000ths of a point (approximate) + + If charInfo is true, the following will also be set:: + + defaultWidth default glyph width in 1/1000ths of a point + charWidths dictionary of character widths for every supported UCS character + code + + This will only work if the font has a Unicode cmap (platform 3, + encoding 1, format 4 or platform 0 any encoding format 4). Setting + charInfo to false avoids this requirement + + """ + # name - Naming table + name_offset = self.seek_table("name") + format = self.read_ushort() + if format != 0: + raise TTFError("Unknown name table format (%d)" % format) + numRecords = self.read_ushort() + string_data_offset = name_offset + self.read_ushort() + names = {1:None,2:None,3:None,4:None,6:None} + K = list(names.keys()) + nameCount = len(names) + for i in xrange(numRecords): + platformId = self.read_ushort() + encodingId = self.read_ushort() + languageId = self.read_ushort() + nameId = self.read_ushort() + length = self.read_ushort() + offset = self.read_ushort() + if nameId not in K: continue + N = None + if platformId == 3 and encodingId == 1 and languageId == 0x409: # Microsoft, Unicode, US English, PS Name + opos = self._pos + try: + self.seek(string_data_offset + offset) + if length % 2 != 0: + raise TTFError("PostScript name is UTF-16BE string of odd length") + length /= 2 + N = [] + A = N.append + while length > 0: + char = self.read_ushort() + A(bytes([char]) if isPy3 else chr(char)) + length -= 1 + N = b''.join(N) + finally: + self._pos = opos + elif platformId == 1 and encodingId == 0 and languageId == 0: # Macintosh, Roman, English, PS Name + # According to OpenType spec, if PS name exists, it must exist + # both in MS Unicode and Macintosh Roman formats. Apparently, + # you can find live TTF fonts which only have Macintosh format. + N = self.get_chunk(string_data_offset + offset, length) + if N and names[nameId]==None: + names[nameId] = N + nameCount -= 1 + if nameCount==0: break + if names[6] is not None: + psName = names[6].replace(b" ", b"-") #Dinu Gherman's fix for font names with spaces + elif names[4] is not None: + psName = names[4].replace(b" ", b"-") + # Fine, one last try before we bail. + elif names[1] is not None: + psName = names[1].replace(b" ", b"-") + else: + psName = None + + # Don't just assume, check for None since some shoddy fonts cause crashes here... + if not psName: + raise TTFError("Could not find PostScript font name") + for c in psName: + if char2int(c)>126 or c in b' [](){}<>/%': + raise TTFError("psName=%r contains invalid character %s" % (psName,ascii(c))) + self.name = psName + self.familyName = names[1] or psName + self.styleName = names[2] or 'Regular' + self.fullName = names[4] or psName + self.uniqueFontID = names[3] or psName + + # head - Font header table + self.seek_table("head") + ver_maj, ver_min = self.read_ushort(), self.read_ushort() + if ver_maj != 1: + raise TTFError('Unknown head table version %d.%04x' % (ver_maj, ver_min)) + self.fontRevision = self.read_ushort(), self.read_ushort() + + self.skip(4) + magic = self.read_ulong() + if magic != 0x5F0F3CF5: + raise TTFError('Invalid head table magic %04x' % magic) + self.skip(2) + self.unitsPerEm = unitsPerEm = self.read_ushort() + scale = lambda x, unitsPerEm=unitsPerEm: x * 1000. / unitsPerEm + self.skip(16) + xMin = self.read_short() + yMin = self.read_short() + xMax = self.read_short() + yMax = self.read_short() + self.bbox = list(map(scale, [xMin, yMin, xMax, yMax])) + self.skip(3*2) + indexToLocFormat = self.read_ushort() + glyphDataFormat = self.read_ushort() + + # OS/2 - OS/2 and Windows metrics table + # (needs data from head table) + if "OS/2" in self.table: + self.seek_table("OS/2") + version = self.read_ushort() + self.skip(2) + usWeightClass = self.read_ushort() + self.skip(2) + fsType = self.read_ushort() + if fsType == 0x0002 or (fsType & 0x0300) != 0: + raise TTFError('Font does not allow subsetting/embedding (%04X)' % fsType) + self.skip(58) #11*2 + 10 + 4*4 + 4 + 3*2 + sTypoAscender = self.read_short() + sTypoDescender = self.read_short() + self.ascent = scale(sTypoAscender) # XXX: for some reason it needs to be multiplied by 1.24--1.28 + self.descent = scale(sTypoDescender) + + if version > 1: + self.skip(16) #3*2 + 2*4 + 2 + sCapHeight = self.read_short() + self.capHeight = scale(sCapHeight) + else: + self.capHeight = self.ascent + else: + # Microsoft TTFs require an OS/2 table; Apple ones do not. Try to + # cope. The data is not very important anyway. + usWeightClass = 500 + self.ascent = scale(yMax) + self.descent = scale(yMin) + self.capHeight = self.ascent + + # There's no way to get stemV from a TTF file short of analyzing actual outline data + # This fuzzy formula is taken from pdflib sources, but we could just use 0 here + self.stemV = 50 + int((usWeightClass / 65.0) ** 2) + + # post - PostScript table + # (needs data from OS/2 table) + self.seek_table("post") + ver_maj, ver_min = self.read_ushort(), self.read_ushort() + if ver_maj not in (1, 2, 3, 4): + # Adobe/MS documents 1, 2, 2.5, 3; Apple also has 4. + # From Apple docs it seems that we do not need to care + # about the exact version, so if you get this error, you can + # try to remove this check altogether. + raise TTFError('Unknown post table version %d.%04x' % (ver_maj, ver_min)) + self.italicAngle = self.read_short() + self.read_ushort() / 65536.0 + self.underlinePosition = self.read_short() + self.underlineThickness = self.read_short() + isFixedPitch = self.read_ulong() + + self.flags = FF_SYMBOLIC # All fonts that contain characters + # outside the original Adobe character + # set are considered "symbolic". + if self.italicAngle!= 0: + self.flags = self.flags | FF_ITALIC + if usWeightClass >= 600: # FW_REGULAR == 500, FW_SEMIBOLD == 600 + self.flags = self.flags | FF_FORCEBOLD + if isFixedPitch: + self.flags = self.flags | FF_FIXED + # XXX: FF_SERIF? FF_SCRIPT? FF_ALLCAP? FF_SMALLCAP? + + # hhea - Horizontal header table + self.seek_table("hhea") + ver_maj, ver_min = self.read_ushort(), self.read_ushort() + if ver_maj != 1: + raise TTFError('Unknown hhea table version %d.%04x' % (ver_maj, ver_min)) + self.skip(28) + metricDataFormat = self.read_ushort() + if metricDataFormat != 0: + raise TTFError('Unknown horizontal metric data format (%d)' % metricDataFormat) + numberOfHMetrics = self.read_ushort() + if numberOfHMetrics == 0: + raise TTFError('Number of horizontal metrics is 0') + + # maxp - Maximum profile table + self.seek_table("maxp") + ver_maj, ver_min = self.read_ushort(), self.read_ushort() + if ver_maj != 1: + raise TTFError('Unknown maxp table version %d.%04x' % (ver_maj, ver_min)) + self.numGlyphs = numGlyphs = self.read_ushort() + + if not charInfo: + self.charToGlyph = None + self.defaultWidth = None + self.charWidths = None + return + + if glyphDataFormat != 0: + raise TTFError('Unknown glyph data format (%d)' % glyphDataFormat) + + # cmap - Character to glyph index mapping table + cmap_offset = self.seek_table("cmap") + cmapVersion = self.read_ushort() + cmapTableCount = self.read_ushort() + if cmapTableCount==0 and cmapVersion!=0: + cmapTableCount, cmapVersion = cmapVersion, cmapTableCount + encoffs = None + enc = 0 + for n in xrange(cmapTableCount): + platform = self.read_ushort() + encoding = self.read_ushort() + offset = self.read_ulong() + if platform==3: + enc = 1 + encoffs = offset + elif platform==1 and encoding==0 and enc!=1: + enc = 2 + encoffs = offset + elif platform==1 and encoding==1: + enc = 1 + encoffs = offset + elif platform==0 and encoding!=5: + enc = 1 + encoffs = offset + if encoffs is None: + raise TTFError('could not find a suitable cmap encoding') + encoffs += cmap_offset + self.seek(encoffs) + fmt = self.read_ushort() + self.charToGlyph = charToGlyph = {} + glyphToChar = {} + if fmt in (13,12,10,8): + self.skip(2) #padding + length = self.read_ulong() + lang = self.read_ulong() + else: + length = self.read_ushort() + lang = self.read_ushort() + if fmt==0: + T = [self.read_uint8() for i in xrange(length-6)] + for unichar in xrange(min(256,self.numGlyphs,len(table))): + glyph = T[glyph] + charToGlyph[unichar] = glyph + glyphToChar.setdefault(glyph,[]).append(unichar) + elif fmt==4: + limit = encoffs + length + segCount = int(self.read_ushort() / 2.0) + self.skip(6) + endCount = [self.read_ushort() for _ in xrange(segCount)] + self.skip(2) + startCount = [self.read_ushort() for _ in xrange(segCount)] + idDelta = [self.read_short() for _ in xrange(segCount)] + idRangeOffset_start = self._pos + idRangeOffset = [self.read_ushort() for _ in xrange(segCount)] + + # Now it gets tricky. + for n in xrange(segCount): + for unichar in xrange(startCount[n], endCount[n] + 1): + if idRangeOffset[n] == 0: + glyph = (unichar + idDelta[n]) & 0xFFFF + else: + offset = (unichar - startCount[n]) * 2 + idRangeOffset[n] + offset = idRangeOffset_start + 2 * n + offset + if offset >= limit: + # workaround for broken fonts (like Thryomanes) + glyph = 0 + else: + glyph = self.get_ushort(offset) + if glyph != 0: + glyph = (glyph + idDelta[n]) & 0xFFFF + charToGlyph[unichar] = glyph + glyphToChar.setdefault(glyph,[]).append(unichar) + elif fmt==6: + first = self.read_ushort() + count = self.read_ushort() + for glyph in xrange(first,first+count): + unichar = self.read_ushort() + charToGlyph[unichar] = glyph + glyphToChar.setdefault(glyph,[]).append(unichar) + elif fmt==10: + first = self.read_ulong() + count = self.read_ulong() + for glyph in xrange(first,first+count): + unichar = self.read_ushort() + charToGlyph[unichar] = glyph + glyphToChar.setdefault(glyph,[]).append(unichar) + elif fmt==12: + segCount = self.read_ulong() + for n in xrange(segCount): + start = self.read_ulong() + end = self.read_ulong() + inc = self.read_ulong() - start + for unichar in xrange(start,end+1): + glyph = unichar + inc + charToGlyph[unichar] = glyph + glyphToChar.setdefault(glyph,[]).append(unichar) + elif fmt==13: + segCount = self.read_ulong() + for n in xrange(segCount): + start = self.read_ulong() + end = self.read_ulong() + gid = self.read_ulong() + for unichar in xrange(start,end+1): + charToGlyph[unichar] = gid + glyphToChar.setdefault(gid,[]).append(unichar) + elif fmt==2: + T = [self.read_ushort() for i in xrange(256)] #subheader keys + maxSHK = max(T) + SH = [] + for i in xrange(maxSHK+1): + firstCode = self.read_ushort() + entryCount = self.read_ushort() + idDelta = self.read_ushort() + idRangeOffset = (self.read_ushort()-(maxSHK-i)*8-2)>>1 + SH.append(CMapFmt2SubHeader(firstCode,entryCount,idDelta,idRangeOffset)) + #number of glyph indexes to read. it is the length of the entire subtable minus that bit we've read so far + entryCount = (length-(self._pos-(cmap_offset+encoffs)))>>1 + glyphs = [self.read_short() for i in xrange(entryCount)] + last = -1 + for unichar in xrange(256): + if T[unichar]==0: + #Special case, single byte encoding entry, look unichar up in subhead + if last!=-1: + glyph = 0 + elif (unichar=SH[0].firstCode+SH[0].entryCount or + SH[0].idRangeOffset+(unichar-SH[0].firstCode)>=entryCount): + glyph = 0 + else: + glyph = glyphs[SH[0].idRangeOffset+(unichar-SH[0].firstCode)] + if glyph!=0: + glyph += SH[0].idDelta + #assume the single byte codes are ascii + if glyph!=0 and glyph=entryCount: + glyph = 0 + else: + glyph = glyphs[SH[k].idRangeOffset+j] + if glyph!= 0: + glyph += SH[k].idDelta + if glyph!=0 and glyph 0: "missing character" + glyphMap = [0] # new glyph index -> old glyph index + glyphSet = {0:0} # old glyph index -> new glyph index + codeToGlyph = {} # unicode -> new glyph index + for code in subset: + if code in self.charToGlyph: + originalGlyphIdx = self.charToGlyph[code] + else: + originalGlyphIdx = 0 + if originalGlyphIdx not in glyphSet: + glyphSet[originalGlyphIdx] = len(glyphMap) + glyphMap.append(originalGlyphIdx) + codeToGlyph[code] = glyphSet[originalGlyphIdx] + + # Also include glyphs that are parts of composite glyphs + start = self.get_table_pos('glyf')[0] + n = 0 + while n < len(glyphMap): + originalGlyphIdx = glyphMap[n] + glyphPos = self.glyphPos[originalGlyphIdx] + glyphLen = self.glyphPos[originalGlyphIdx + 1] - glyphPos + n += 1 + if not glyphLen: continue + self.seek(start + glyphPos) + numberOfContours = self.read_short() + if numberOfContours < 0: + # composite glyph + self.skip(8) + flags = GF_MORE_COMPONENTS + while flags & GF_MORE_COMPONENTS: + flags = self.read_ushort() + glyphIdx = self.read_ushort() + if glyphIdx not in glyphSet: + glyphSet[glyphIdx] = len(glyphMap) + glyphMap.append(glyphIdx) + if flags & GF_ARG_1_AND_2_ARE_WORDS: + self.skip(4) + else: + self.skip(2) + if flags & GF_WE_HAVE_A_SCALE: + self.skip(2) + elif flags & GF_WE_HAVE_AN_X_AND_Y_SCALE: + self.skip(4) + elif flags & GF_WE_HAVE_A_TWO_BY_TWO: + self.skip(8) + + + # The following tables are simply copied from the original + for tag in ('name', 'OS/2', 'cvt ', 'fpgm', 'prep'): + try: + output.add(tag, self.get_table(tag)) + except KeyError: + # Apparently some of the tables are optional (cvt, fpgm, prep). + # The lack of the required ones (name, OS/2) would have already + # been caught before. + pass + + # post - PostScript + post = b"\x00\x03\x00\x00" + self.get_table('post')[4:16] + b"\x00" * 16 + output.add('post', post) + + numGlyphs = len(glyphMap) + + # hmtx - Horizontal Metrics + hmtx = [] + for n in xrange(numGlyphs): + aw, lsb = self.hmetrics[glyphMap[n]] + hmtx.append(int(aw)) + hmtx.append(int(lsb)) + + #work out n as 0 or first aw that's the start of a run + n = len(hmtx)-2 + while n and hmtx[n]==hmtx[n-2]: + n -= 2 + if not n: n = 2 #need at least one pair + numberOfHMetrics = n>>1 #number of full H Metric pairs + hmtx = hmtx[:n] + hmtx[n+1::2] #full pairs + all the trailing lsb's + + hmtx = pack(*([">%dH" % len(hmtx)] + hmtx)) + output.add('hmtx', hmtx) + + # hhea - Horizontal Header + hhea = self.get_table('hhea') + hhea = _set_ushort(hhea, 34, numberOfHMetrics) + output.add('hhea', hhea) + + # maxp - Maximum Profile + maxp = self.get_table('maxp') + maxp = _set_ushort(maxp, 4, numGlyphs) + output.add('maxp', maxp) + + # cmap - Character to glyph mapping + # XXX maybe use format 0 if possible, not 6? + entryCount = len(subset) + length = 10 + entryCount * 2 + cmap = [0, 1, # version, number of tables + 1, 0, 0,12, # platform, encoding, offset (hi,lo) + 6, length, 0, # format, length, language + 0, + entryCount] + \ + list(map(codeToGlyph.get, subset)) + cmap = pack(*([">%dH" % len(cmap)] + cmap)) + output.add('cmap', cmap) + + # glyf - Glyph data + glyphData = self.get_table('glyf') + offsets = [] + glyf = [] + pos = 0 + for n in xrange(numGlyphs): + offsets.append(pos) + originalGlyphIdx = glyphMap[n] + glyphPos = self.glyphPos[originalGlyphIdx] + glyphLen = self.glyphPos[originalGlyphIdx + 1] - glyphPos + data = glyphData[glyphPos:glyphPos+glyphLen] + # Fix references in composite glyphs + if glyphLen > 2 and unpack(">h", data[:2])[0] < 0: + # composite glyph + pos_in_glyph = 10 + flags = GF_MORE_COMPONENTS + while flags & GF_MORE_COMPONENTS: + flags = unpack(">H", data[pos_in_glyph:pos_in_glyph+2])[0] + glyphIdx = unpack(">H", data[pos_in_glyph+2:pos_in_glyph+4])[0] + data = _set_ushort(data, pos_in_glyph + 2, glyphSet[glyphIdx]) + pos_in_glyph = pos_in_glyph + 4 + if flags & GF_ARG_1_AND_2_ARE_WORDS: + pos_in_glyph = pos_in_glyph + 4 + else: + pos_in_glyph = pos_in_glyph + 2 + if flags & GF_WE_HAVE_A_SCALE: + pos_in_glyph = pos_in_glyph + 2 + elif flags & GF_WE_HAVE_AN_X_AND_Y_SCALE: + pos_in_glyph = pos_in_glyph + 4 + elif flags & GF_WE_HAVE_A_TWO_BY_TWO: + pos_in_glyph = pos_in_glyph + 8 + glyf.append(data) + pos = pos + glyphLen + if pos % 4 != 0: + padding = 4 - pos % 4 + glyf.append(b'\0' * padding) + pos = pos + padding + offsets.append(pos) + output.add('glyf', b''.join(glyf)) + + # loca - Index to location + loca = [] + if (pos + 1) >> 1 > 0xFFFF: + indexToLocFormat = 1 # long format + for offset in offsets: + loca.append(offset) + loca = pack(*([">%dL" % len(loca)] + loca)) + else: + indexToLocFormat = 0 # short format + for offset in offsets: + loca.append(offset >> 1) + loca = pack(*([">%dH" % len(loca)] + loca)) + output.add('loca', loca) + + # head - Font header + head = self.get_table('head') + head = _set_ushort(head, 50, indexToLocFormat) + output.add('head', head) + + return output.makeStream() + + +# +# TrueType font embedding +# + +# PDF font flags (see PDF Reference Guide table 5.19) +FF_FIXED = 1 << 1-1 +FF_SERIF = 1 << 2-1 +FF_SYMBOLIC = 1 << 3-1 +FF_SCRIPT = 1 << 4-1 +FF_NONSYMBOLIC = 1 << 6-1 +FF_ITALIC = 1 << 7-1 +FF_ALLCAP = 1 << 17-1 +FF_SMALLCAP = 1 << 18-1 +FF_FORCEBOLD = 1 << 19-1 + +class TTFontFace(TTFontFile, pdfmetrics.TypeFace): + """TrueType typeface. + + Conceptually similar to a single byte typeface, but the glyphs are + identified by UCS character codes instead of glyph names.""" + + def __init__(self, filename, validate=0, subfontIndex=0): + "Loads a TrueType font from filename." + pdfmetrics.TypeFace.__init__(self, None) + TTFontFile.__init__(self, filename, validate=validate, subfontIndex=subfontIndex) + + def getCharWidth(self, code): + "Returns the width of character U+" + return self.charWidths.get(code, self.defaultWidth) + + def addSubsetObjects(self, doc, fontname, subset): + """Generate a TrueType font subset and add it to the PDF document. + Returns a PDFReference to the new FontDescriptor object.""" + + fontFile = pdfdoc.PDFStream() + fontFile.content = self.makeSubset(subset) + fontFile.dictionary['Length1'] = len(fontFile.content) + if doc.compression: + fontFile.filters = [pdfdoc.PDFZCompress] + fontFileRef = doc.Reference(fontFile, 'fontFile:%s(%s)' % (self.filename, fontname)) + + flags = self.flags & ~ FF_NONSYMBOLIC + flags = flags | FF_SYMBOLIC + + fontDescriptor = pdfdoc.PDFDictionary({ + 'Type': '/FontDescriptor', + 'Ascent': self.ascent, + 'CapHeight': self.capHeight, + 'Descent': self.descent, + 'Flags': flags, + 'FontBBox': pdfdoc.PDFArray(self.bbox), + 'FontName': pdfdoc.PDFName(fontname), + 'ItalicAngle': self.italicAngle, + 'StemV': self.stemV, + 'FontFile2': fontFileRef, + }) + return doc.Reference(fontDescriptor, 'fontDescriptor:' + fontname) + +class TTEncoding: + """Encoding for TrueType fonts (always UTF-8). + + TTEncoding does not directly participate in PDF object creation, since + we need a number of different 8-bit encodings for every generated font + subset. TTFont itself cares about that.""" + + def __init__(self): + self.name = "UTF-8" + +class TTFont: + """Represents a TrueType font. + + Its encoding is always UTF-8. + + Note: you cannot use the same TTFont object for different documents + at the same time. + + Example of usage: + + font = ttfonts.TTFont('PostScriptFontName', '/path/to/font.ttf') + pdfmetrics.registerFont(font) + + canvas.setFont('PostScriptFontName', size) + canvas.drawString(x, y, "Some text encoded in UTF-8") + """ + class State: + namePrefix = 'F' + def __init__(self,asciiReadable=None): + self.assignments = {} + self.nextCode = 0 + self.internalName = None + self.frozen = 0 + + if asciiReadable is None: + asciiReadable = rl_config.ttfAsciiReadable + + if asciiReadable: + # Let's add the first 128 unicodes to the 0th subset, so ' ' + # always has code 32 (for word spacing to work) and the ASCII + # output is readable + subset0 = list(xrange(128)) + self.subsets = [subset0] + for n in subset0: + self.assignments[n] = n + self.nextCode = 128 + else: + self.subsets = [[32]*33] + self.assignments[32] = 32 + + _multiByte = 1 # We want our own stringwidth + _dynamicFont = 1 # We want dynamic subsetting + + def __init__(self, name, filename, validate=0, subfontIndex=0,asciiReadable=None): + """Loads a TrueType font from filename. + + If validate is set to a false values, skips checksum validation. This + can save time, especially if the font is large. + """ + self.fontName = name + self.face = TTFontFace(filename, validate=validate, subfontIndex=subfontIndex) + self.encoding = TTEncoding() + from weakref import WeakKeyDictionary + self.state = WeakKeyDictionary() + if asciiReadable is None: + asciiReadable = rl_config.ttfAsciiReadable + self._asciiReadable = asciiReadable + + def stringWidth(self,text,size,encoding='utf8'): + return instanceStringWidthTTF(self,text,size,encoding) + + def _assignState(self,doc,asciiReadable=None,namePrefix=None): + '''convenience function for those wishing to roll their own state properties''' + if asciiReadable is None: + asciiReadable = self._asciiReadable + try: + state = self.state[doc] + except KeyError: + state = self.state[doc] = TTFont.State(asciiReadable) + if namePrefix is not None: + state.namePrefix = namePrefix + return state + + def splitString(self, text, doc, encoding='utf-8'): + """Splits text into a number of chunks, each of which belongs to a + single subset. Returns a list of tuples (subset, string). Use subset + numbers with getSubsetInternalName. Doc is needed for distinguishing + subsets when building different documents at the same time.""" + asciiReadable = self._asciiReadable + try: state = self.state[doc] + except KeyError: state = self.state[doc] = TTFont.State(asciiReadable) + curSet = -1 + cur = [] + results = [] + if not isUnicode(text): + text = text.decode('utf-8') # encoding defaults to utf-8 + assignments = state.assignments + subsets = state.subsets + for code in map(ord,text): + if code in assignments: + n = assignments[code] + else: + if state.frozen: + raise pdfdoc.PDFError("Font %s is already frozen, cannot add new character U+%04X" % (self.fontName, code)) + n = state.nextCode + if n&0xFF==32: + # make code 32 always be a space character + if n!=32: subsets[n >> 8].append(32) + state.nextCode += 1 + n = state.nextCode + state.nextCode += 1 + assignments[code] = n + if n>32: + if not(n&0xFF): subsets.append([]) + subsets[n >> 8].append(code) + else: + subsets[0][n] = code + if (n >> 8) != curSet: + if cur: + results.append((curSet,bytes(cur) if isPy3 else ''.join(chr(c) for c in cur))) + curSet = (n >> 8) + cur = [] + cur.append(n & 0xFF) + if cur: + results.append((curSet,bytes(cur) if isPy3 else ''.join(chr(c) for c in cur))) + return results + + def getSubsetInternalName(self, subset, doc): + """Returns the name of a PDF Font object corresponding to a given + subset of this dynamic font. Use this function instead of + PDFDocument.getInternalFontName.""" + try: state = self.state[doc] + except KeyError: state = self.state[doc] = TTFont.State(self._asciiReadable) + if subset < 0 or subset >= len(state.subsets): + raise IndexError('Subset %d does not exist in font %s' % (subset, self.fontName)) + if state.internalName is None: + state.internalName = state.namePrefix +repr(len(doc.fontMapping) + 1) + doc.fontMapping[self.fontName] = '/' + state.internalName + doc.delayedFonts.append(self) + return '/%s+%d' % (state.internalName, subset) + + def addObjects(self, doc): + """Makes one or more PDF objects to be added to the document. The + caller supplies the internal name to be used (typically F1, F2, ... in + sequence). + + This method creates a number of Font and FontDescriptor objects. Every + FontDescriptor is a (no more than) 256 character subset of the original + TrueType font.""" + try: state = self.state[doc] + except KeyError: state = self.state[doc] = TTFont.State(self._asciiReadable) + state.frozen = 1 + for n,subset in enumerate(state.subsets): + internalName = self.getSubsetInternalName(n, doc)[1:] + baseFontName = (b''.join((SUBSETN(n),b'+',self.face.name,self.face.subfontNameX))).decode('pdfdoc') + + pdfFont = pdfdoc.PDFTrueTypeFont() + pdfFont.__Comment__ = 'Font %s subset %d' % (self.fontName, n) + pdfFont.Name = internalName + pdfFont.BaseFont = baseFontName + + pdfFont.FirstChar = 0 + pdfFont.LastChar = len(subset) - 1 + + widths = list(map(self.face.getCharWidth, subset)) + pdfFont.Widths = pdfdoc.PDFArray(widths) + + cmapStream = pdfdoc.PDFStream() + cmapStream.content = makeToUnicodeCMap(baseFontName, subset) + if doc.compression: + cmapStream.filters = [pdfdoc.PDFZCompress] + pdfFont.ToUnicode = doc.Reference(cmapStream, 'toUnicodeCMap:' + baseFontName) + + pdfFont.FontDescriptor = self.face.addSubsetObjects(doc, baseFontName, subset) + + # link it in + ref = doc.Reference(pdfFont, internalName) + fontDict = doc.idToObject['BasicFonts'].dict + fontDict[internalName] = pdfFont + del self.state[doc] diff --git a/reportlab/pdfgen/__init__.py b/reportlab/pdfgen/__init__.py new file mode 100644 index 00000000..934fc827 --- /dev/null +++ b/reportlab/pdfgen/__init__.py @@ -0,0 +1,5 @@ +#Copyright ReportLab Europe Ltd. 2000-2012 +#see license.txt for license details +#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/pdfgen/__init__.py +__version__=''' $Id$ ''' +__doc__='''Defines a high-level Canvas interface for creating PDF files''' diff --git a/reportlab/pdfgen/canvas.py b/reportlab/pdfgen/canvas.py new file mode 100644 index 00000000..e84b85fd --- /dev/null +++ b/reportlab/pdfgen/canvas.py @@ -0,0 +1,1837 @@ +#Copyright ReportLab Europe Ltd. 2000-2012 +#see license.txt for license details +__version__=''' $Id$ ''' +__doc__=""" +The Canvas object is the primary interface for creating PDF files. See +doc/reportlab-userguide.pdf for copious examples. +""" + +__all__ = ['Canvas'] +ENABLE_TRACKING = 1 # turn this off to do profile testing w/o tracking + +import os +import sys +import re +import hashlib +from string import digits +import tempfile +from math import sin, cos, tan, pi, ceil +from reportlab import rl_config +from reportlab.pdfbase import pdfutils +from reportlab.pdfbase import pdfdoc +from reportlab.pdfbase import pdfmetrics +from reportlab.pdfgen import pdfgeom, pathobject, textobject +from reportlab.lib.colors import black, _chooseEnforceColorSpace, Color, CMYKColor, toColor +from reportlab.lib.utils import import_zlib, ImageReader, isSeq, isStr, isUnicode, _digester +from reportlab.lib.rl_accel import fp_str, escapePDF +from reportlab.lib.boxstuff import aspectRatioFix + +digitPat = re.compile('\d') #used in decimal alignment +zlib = import_zlib() + +# Robert Kern +# Constants for closing paths. +# May be useful if one changes 'arc' and 'rect' to take a +# default argument that tells how to close the path. +# That way we can draw filled shapes. + +FILL_EVEN_ODD = 0 +FILL_NON_ZERO = 1 + #this is used by path-closing routines. + #map stroke, fill, fillmode -> operator + # fillmode: 1 = non-Zero (obviously), 0 = evenOdd +PATH_OPS = {(0, 0, FILL_EVEN_ODD) : 'n', #no op + (0, 0, FILL_NON_ZERO) : 'n', #no op + (1, 0, FILL_EVEN_ODD) : 'S', #stroke only + (1, 0, FILL_NON_ZERO) : 'S', #stroke only + (0, 1, FILL_EVEN_ODD) : 'f*', #Fill only + (0, 1, FILL_NON_ZERO) : 'f', #Fill only + (1, 1, FILL_EVEN_ODD) : 'B*', #Stroke and Fill + (1, 1, FILL_NON_ZERO) : 'B', #Stroke and Fill + } + +def _annFormat(D,color,thickness,dashArray,hradius=0,vradius=0): + from reportlab.pdfbase.pdfdoc import PDFArray, PDFDictionary + if color and 'C' not in D: + D["C"] = PDFArray([color.red, color.green, color.blue]) + if 'Border' not in D: + border = [hradius,vradius,thickness or 0] + if dashArray: + border.append(PDFArray(dashArray)) + D["Border"] = PDFArray(border) +# BS = PDFDictionary() +# bss = 'S' +# if dashArray: +# BS['D'] = PDFArray(dashArray) +# bss = 'D' +# BS['W'] = thickness or 0 +# BS['S'] = bss +# D['BS'] = BS + +# helpers to guess color space for gradients +def _normalizeColor(aColor): + if isinstance(aColor, CMYKColor): + d = aColor.density + return "DeviceCMYK", tuple(c*d for c in aColor.cmyk()) + elif isinstance(aColor, Color): + return "DeviceRGB", aColor.rgb() + elif isinstance(aColor, (tuple, list)): + l = len(aColor) + if l == 3: + return "DeviceRGB", aColor + elif l == 4: + return "DeviceCMYK", aColor + elif isinstance(aColor, str): + return _normalizeColor(toColor(aColor)) + raise ValueError("Unknown color %r" % aColor) + +def _normalizeColors(colors): + space = None + outcolors = [] + for aColor in colors: + nspace, outcolor = _normalizeColor(aColor) + if space is not None and space != nspace: + raise ValueError("Mismatch in color spaces: %s and %s" % (space, nspace)) + space = nspace + outcolors.append(outcolor) + return space, outcolors + +def _buildColorFunction(colors, positions): + from reportlab.pdfbase.pdfdoc import PDFExponentialFunction, PDFStitchingFunction + if positions is not None and len(positions) != len(colors): + raise ValueError("need to have the same number of colors and positions") + # simplified functions for edge cases + if len(colors) == 1: + # for completeness + return PDFExponentialFunction(N=1, C0=colors[0], C1=colors[0]) + if len(colors) == 2: + if positions is None or (positions[0] == 0 and positions[1] == 1): + return PDFExponentialFunction(N=1, C0=colors[0], C1=colors[1]) + # equally distribute if positions not specified + if positions is None: + nc = len(colors) + positions = [(1.0*x)/(nc-1) for x in range(nc)] + else: + # sort positions and colors in increasing order + poscolors = list(zip(positions, colors)) + poscolors.sort(key=lambda x: x[0]) + # add endpoint positions if not already present + if poscolors[0][0] != 0: + poscolors.insert(0, (0.0, poscolors[0][1])) + if poscolors[-1][0] != 1: + poscolors.append((1.0, poscolors[-1][1])) + positions, colors = list(zip(*poscolors)) # unzip + # build stitching function + functions = [] + bounds = [pos for pos in positions[1:-1]] + encode = [] + lastcolor = colors[0] + for color in colors[1:]: + functions.append(PDFExponentialFunction(N=1, C0=lastcolor, C1=color)) + lastcolor = color + encode.append(0.0) + encode.append(1.0) + return PDFStitchingFunction(functions, bounds, encode, Domain="[0.0 1.0]") + +class ExtGState: + defaults = dict( + CA=1, + ca=1, + OP=False, + op=False, + OPM=0, + ) + + def __init__(self): + self._d = {} + self._c = {} + + def set(self,canv,a,v): + d = self.defaults[a] + isbool = isinstance(d,bool) + if isbool: v=bool(v) + if v!=self._d.get(a,d) or (a=='op' and self.getValue('OP')!=d): + self._d[a] = v + if isbool: v=str(v).lower() + t = a,v + if t in self._c: + name = self._c[t] + else: + name = 'gRLs'+str(len(self._c)) + self._c[t] = name + canv._code.append('/%s gs' % name) + + def getValue(self,a): + return self._d.get(a,self.defaults[a]) + + def getState(self): + S = {} + for t,name in self._c.items(): + S[name] = pdfdoc.PDFDictionary(dict((t,))) + return S and pdfdoc.PDFDictionary(S) or None + + def pushCopy(self): + '''the states must be shared across push/pop, but the values not''' + x = self.__class__() + x._d = self._d.copy() + x._c = self._c + return x + +class Canvas(textobject._PDFColorSetter): + """This class is the programmer's interface to the PDF file format. Methods + are (or will be) provided here to do just about everything PDF can do. + + The underlying model to the canvas concept is that of a graphics state machine + that at any given point in time has a current font, fill color (for figure + interiors), stroke color (for figure borders), line width and geometric transform, among + many other characteristics. + + Canvas methods generally either draw something (like canvas.line) using the + current state of the canvas or change some component of the canvas + state (like canvas.setFont). The current state can be saved and restored + using the saveState/restoreState methods. + + Objects are "painted" in the order they are drawn so if, for example + two rectangles overlap the last draw will appear "on top". PDF form + objects (supported here) are used to draw complex drawings only once, + for possible repeated use. + + There are other features of canvas which are not visible when printed, + such as outlines and bookmarks which are used for navigating a document + in a viewer. + + Here is a very silly example usage which generates a Hello World pdf document. + + Example:: + + from reportlab.pdfgen import canvas + c = canvas.Canvas("hello.pdf") + from reportlab.lib.units import inch + # move the origin up and to the left + c.translate(inch,inch) + # define a large font + c.setFont("Helvetica", 80) + # choose some colors + c.setStrokeColorRGB(0.2,0.5,0.3) + c.setFillColorRGB(1,0,1) + # draw a rectangle + c.rect(inch,inch,6*inch,9*inch, fill=1) + # make text go straight up + c.rotate(90) + # change color + c.setFillColorRGB(0,0,0.77) + # say hello (note after rotate the y coord needs to be negative!) + c.drawString(3*inch, -3*inch, "Hello World") + c.showPage() + c.save() + + """ + + def __init__(self,filename, + pagesize=None, + bottomup = 1, + pageCompression=None, + invariant = None, + verbosity=0, + encrypt=None, + cropMarks=None, + pdfVersion=None, + enforceColorSpace=None, + ): + """Create a canvas of a given size. etc. + + You may pass a file-like object to filename as an alternative to + a string. + For more information about the encrypt parameter refer to the setEncrypt method. + + Most of the attributes are private - we will use set/get methods + as the preferred interface. Default page size is A4. + cropMarks may be True/False or an object with parameters borderWidth, markColor, markWidth + and markLength + + if enforceColorSpace is in ('cmyk', 'rgb', 'sep','sep_black','sep_cmyk') then one of + the standard _PDFColorSetter callables will be used to enforce appropriate color settings. + If it is a callable then that will be used. + """ + if pagesize is None: pagesize = rl_config.defaultPageSize + if invariant is None: invariant = rl_config.invariant + self._filename = filename + + self._doc = pdfdoc.PDFDocument(compression=pageCompression, + invariant=invariant, filename=filename, + pdfVersion=pdfVersion or pdfdoc.PDF_VERSION_DEFAULT, + ) + + self._enforceColorSpace = _chooseEnforceColorSpace(enforceColorSpace) + + #this only controls whether it prints 'saved ...' - 0 disables + self._verbosity = verbosity + + #this is called each time a page is output if non-null + self._onPage = None + self._cropMarks = cropMarks + + self._pagesize = pagesize + self._hanging_pagesize = None + self._pageRotation = 0 + #self._currentPageHasImages = 0 + self._pageTransition = None + self._pageDuration = None + self._destinations = {} # dictionary of destinations for cross indexing. + + self.setPageCompression(pageCompression) + self._pageNumber = 1 # keep a count + # when we create a form we need to save operations not in the form + self._codeStack = [] + self._restartAccumulators() # restart all accumulation state (generalized, arw) + self._annotationCount = 0 + + self._outlines = [] # list for a name tree + self._psCommandsBeforePage = [] #for postscript tray/font commands + self._psCommandsAfterPage = [] #for postscript tray/font commands + + #PostScript has the origin at bottom left. It is easy to achieve a top- + #down coord system by translating to the top of the page and setting y + #scale to -1, but then text is inverted. So self.bottomup is used + #to also set the text matrix accordingly. You can now choose your + #drawing coordinates. + self.bottomup = bottomup + self.imageCaching = rl_config.defaultImageCaching + self.init_graphics_state() + self._make_preamble() + self.state_stack = [] + + self.setEncrypt(encrypt) + + def setEncrypt(self, encrypt): + ''' + Set the encryption used for the pdf generated by this canvas. + If encrypt is a string object, it is used as the user password for the pdf. + If encrypt is an instance of reportlab.lib.pdfencrypt.StandardEncryption, this object is + used to encrypt the pdf. This allows more finegrained control over the encryption settings. + ''' + if encrypt: + from reportlab.lib import pdfencrypt + if isStr(encrypt): #encrypt is the password itself + if isUnicode(encrypt): + encrypt = encrypt.encode('utf-8') + encrypt = pdfencrypt.StandardEncryption(encrypt) #now it's the encrypt object + encrypt.setAllPermissions(1) + elif not isinstance(encrypt, pdfencrypt.StandardEncryption): + raise TypeError('Expected string or instance of reportlab.lib.pdfencrypt.StandardEncryption as encrypt parameter but got %r' % encrypt) + self._doc.encrypt = encrypt + else: + try: + del self._doc.encrypt + except AttributeError: + pass + + def init_graphics_state(self): + #initial graphics state, never modify any of these in place + self._x = 0 + self._y = 0 + self._fontname = rl_config.canvas_basefontname + self._fontsize = 12 + + self._textMode = 0 #track if between BT/ET + self._leading = 14.4 + self._currentMatrix = (1., 0., 0., 1., 0., 0.) + self._fillMode = 0 #even-odd + + #text state + self._charSpace = 0 + self._wordSpace = 0 + self._horizScale = 100 + self._textRenderMode = 0 + self._rise = 0 + self._textLineMatrix = (1., 0., 0., 1., 0., 0.) + self._textMatrix = (1., 0., 0., 1., 0., 0.) + + # line drawing + self._lineCap = 0 + self._lineJoin = 0 + self._lineDash = None #not done + self._lineWidth = 1 + self._mitreLimit = 0 + + self._fillColorObj = self._strokeColorObj = rl_config.canvas_baseColor or (0,0,0) + self._extgstate = ExtGState() + + def push_state_stack(self): + state = {} + d = self.__dict__ + for name in self.STATE_ATTRIBUTES: + state[name] = d[name] #getattr(self, name) + self.state_stack.append(state) + self._extgstate = self._extgstate.pushCopy() + + def pop_state_stack(self): + self.__dict__.update(self.state_stack.pop()) + + STATE_ATTRIBUTES = """_x _y _fontname _fontsize _textMode _leading _currentMatrix _fillMode + _charSpace _wordSpace _horizScale _textRenderMode _rise _textLineMatrix + _textMatrix _lineCap _lineJoin _lineDash _lineWidth _mitreLimit _fillColorObj + _strokeColorObj _extgstate""".split() + STATE_RANGE = list(range(len(STATE_ATTRIBUTES))) + + #self._addStandardFonts() + + def _make_preamble(self): + P = [].append + if self.bottomup: + P('1 0 0 1 0 0 cm') + else: + P('1 0 0 -1 0 %s cm' % fp_str(self._pagesize[1])) + C = self._code + n = len(C) + if self._fillColorObj != (0,0,0): + self.setFillColor(self._fillColorObj) + if self._strokeColorObj != (0,0,0): + self.setStrokeColor(self._strokeColorObj) + P(' '.join(C[n:])) + del C[n:] + font = pdfmetrics.getFont(self._fontname) + if not font._dynamicFont: + #set an initial font + if font.face.builtIn or not getattr(self,'_drawTextAsPath',False): + P('BT %s 12 Tf 14.4 TL ET' % self._doc.getInternalFontName(self._fontname)) + self._preamble = ' '.join(P.__self__) + + def _escape(self, s): + return escapePDF(s) + + #info functions - non-standard + def setAuthor(self, author): + """identify the author for invisible embedding inside the PDF document. + the author annotation will appear in the the text of the file but will + not automatically be seen when the document is viewed, but is visible + in document properties etc etc.""" + self._doc.setAuthor(author) + + def setDateFormatter(self, dateFormatter): + """accepts a func(yyyy,mm,dd,hh,m,s) used to create embedded formatted date""" + self._doc.setDateFormatter(dateFormatter) + + def addOutlineEntry(self, title, key, level=0, closed=None): + """Adds a new entry to the outline at given level. If LEVEL not specified, + entry goes at the top level. If level specified, it must be + no more than 1 greater than the outline level in the last call. + + The key must be the (unique) name of a bookmark. + the title is the (non-unique) name to be displayed for the entry. + + If closed is set then the entry should show no subsections by default + when displayed. + + Example:: + + c.addOutlineEntry("first section", "section1") + c.addOutlineEntry("introduction", "s1s1", 1, closed=1) + c.addOutlineEntry("body", "s1s2", 1) + c.addOutlineEntry("detail1", "s1s2s1", 2) + c.addOutlineEntry("detail2", "s1s2s2", 2) + c.addOutlineEntry("conclusion", "s1s3", 1) + c.addOutlineEntry("further reading", "s1s3s1", 2) + c.addOutlineEntry("second section", "section1") + c.addOutlineEntry("introduction", "s2s1", 1) + c.addOutlineEntry("body", "s2s2", 1, closed=1) + c.addOutlineEntry("detail1", "s2s2s1", 2) + c.addOutlineEntry("detail2", "s2s2s2", 2) + c.addOutlineEntry("conclusion", "s2s3", 1) + c.addOutlineEntry("further reading", "s2s3s1", 2) + + generated outline looks like:: + + - first section + |- introduction + |- body + | |- detail1 + | |- detail2 + |- conclusion + | |- further reading + - second section + |- introduction + |+ body + |- conclusion + | |- further reading + + Note that the second "body" is closed. + + Note that you can jump from level 5 to level 3 but not + from 3 to 5: instead you need to provide all intervening + levels going down (4 in this case). Note that titles can + collide but keys cannot. + """ + #to be completed + #self._outlines.append(title) + self._doc.outline.addOutlineEntry(key, level, title, closed=closed) + + def setOutlineNames0(self, *nametree): # keep this for now (?) + """nametree should can be a recursive tree like so:: + + c.setOutlineNames( + "chapter1dest", + ("chapter2dest", + ["chapter2section1dest", + "chapter2section2dest", + "chapter2conclusiondest"] + ), # end of chapter2 description + "chapter3dest", + ("chapter4dest", ["c4s1", "c4s2"]) + ) + + each of the string names inside must be bound to a bookmark + before the document is generated. + """ + self._doc.outline.setNames(*((self,)+nametree)) + + def setTitle(self, title): + """write a title into the PDF file that won't automatically display + in the document itself.""" + self._doc.setTitle(title) + + def setSubject(self, subject): + """write a subject into the PDF file that won't automatically display + in the document itself.""" + self._doc.setSubject(subject) + + def setCreator(self, creator): + """write a creator into the PDF file that won't automatically display + in the document itself. This should be used to name the original app + which is passing data into ReportLab, if you wish to name it.""" + self._doc.setCreator(creator) + + def setKeywords(self, keywords): + """write a list of keywords into the PDF file which shows in document properties. + Either submit a single string or a list/tuple""" + if isinstance(keywords,(list,tuple)): + keywords = ', '.join(keywords) + self._doc.setKeywords(keywords) + + def pageHasData(self): + "Info function - app can call it after showPage to see if it needs a save" + return len(self._code) == 0 + + def showOutline(self): + """Specify that Acrobat Reader should start with the outline tree visible. + showFullScreen() and showOutline() conflict; the one called last + wins.""" + self._doc._catalog.showOutline() + + def showFullScreen0(self): + """Specify that Acrobat Reader should start in full screen mode. + showFullScreen() and showOutline() conflict; the one called last + wins.""" + self._doc._catalog.showFullScreen() + + def _setStrokeAlpha(self,v): + """ + Define the transparency/opacity of strokes. 0 is fully + transparent, 1 is fully opaque. + + Note that calling this function will cause a version 1.4 PDF + to be generated (rather than 1.3). + """ + self._doc.ensureMinPdfVersion('transparency') + self._extgstate.set(self,'CA',v) + + def _setFillAlpha(self,v): + """ + Define the transparency/opacity of non-strokes. 0 is fully + transparent, 1 is fully opaque. + + Note that calling this function will cause a version 1.4 PDF + to be generated (rather than 1.3). + """ + self._doc.ensureMinPdfVersion('transparency') + self._extgstate.set(self,'ca',v) + + def _setStrokeOverprint(self,v): + self._extgstate.set(self,'OP',v) + + def _setFillOverprint(self,v): + self._extgstate.set(self,'op',v) + + def _setOverprintMask(self,v): + self._extgstate.set(self,'OPM',v and 1 or 0) + + def _getCmShift(self): + cM = self._cropMarks + if cM: + bleedW = max(0,getattr(cM,'bleedWidth',0)) + bw = max(0,getattr(cM,'borderWidth',36)) + if bleedW: + bw -= bleedW + return bw + + def showPage(self): + """Close the current page and possibly start on a new page.""" + # ensure a space at the end of the stream - Acrobat does + # not mind, but Ghostscript dislikes 'Qendstream' even if + # the length marker finishes after 'Q' + + pageWidth = self._pagesize[0] + pageHeight = self._pagesize[1] + cM = self._cropMarks + code = self._code + if cM: + bw = max(0,getattr(cM,'borderWidth',36)) + if bw: + markLast = getattr(cM,'markLast',1) + ml = min(bw,max(0,getattr(cM,'markLength',18))) + mw = getattr(cM,'markWidth',0.5) + mc = getattr(cM,'markColor',black) + mg = 2*bw-ml + cx0 = len(code) + if ml and mc: + self.saveState() + self.setStrokeColor(mc) + self.setLineWidth(mw) + self.lines([ + (bw,0,bw,ml), + (pageWidth+bw,0,pageWidth+bw,ml), + (bw,pageHeight+mg,bw,pageHeight+2*bw), + (pageWidth+bw,pageHeight+mg,pageWidth+bw,pageHeight+2*bw), + (0,bw,ml,bw), + (pageWidth+mg,bw,pageWidth+2*bw,bw), + (0,pageHeight+bw,ml,pageHeight+bw), + (pageWidth+mg,pageHeight+bw,pageWidth+2*bw,pageHeight+bw), + ]) + self.restoreState() + if markLast: + #if the marks are to be drawn after the content + #save the code we just drew for later use + L = code[cx0:] + del code[cx0:] + cx0 = len(code) + + bleedW = max(0,getattr(cM,'bleedWidth',0)) + self.saveState() + self.translate(bw-bleedW,bw-bleedW) + if bleedW: + #scale everything + self.scale(1+(2.0*bleedW)/pageWidth,1+(2.0*bleedW)/pageHeight) + + #move our translation/expansion code to the beginning + C = code[cx0:] + del code[cx0:] + code[0:0] = C + self.restoreState() + if markLast: + code.extend(L) + pageWidth = 2*bw + pageWidth + pageHeight = 2*bw + pageHeight + + code.append(' ') + page = pdfdoc.PDFPage() + page.pagewidth = pageWidth + page.pageheight = pageHeight + page.Rotate = self._pageRotation + page.hasImages = self._currentPageHasImages + page.setPageTransition(self._pageTransition) + page.setCompression(self._pageCompression) + if self._pageDuration is not None: + page.Dur = self._pageDuration + + strm = self._psCommandsBeforePage + [self._preamble] + code + self._psCommandsAfterPage + page.setStream(strm) + self._setColorSpace(page) + self._setExtGState(page) + self._setXObjects(page) + self._setShadingUsed(page) + self._setAnnotations(page) + self._doc.addPage(page) + + if self._onPage: self._onPage(self._pageNumber) + self._startPage() + + def _startPage(self): + #now get ready for the next one + if self._hanging_pagesize: + self.setPageSize(self._hanging_pagesize) + self._hanging_pagesize = None + self._pageNumber += 1 + self._restartAccumulators() + self.init_graphics_state() + self.state_stack = [] + + def setPageCallBack(self, func): + """func(pageNum) will be called on each page end. + + This is mainly a hook for progress monitoring. + Call setPageCallback(None) to clear a callback.""" + self._onPage = func + + def _setAnnotations(self,page): + page.Annots = self._annotationrefs + + def _setColorSpace(self,obj): + obj._colorsUsed = self._colorsUsed + + def _setShadingUsed(self, page): + page._shadingUsed = self._shadingUsed + + def _setXObjects(self, thing): + """for pages and forms, define the XObject dictionary for resources, if needed""" + forms = self._formsinuse + if forms: + xobjectsdict = self._doc.xobjDict(forms) + thing.XObjects = xobjectsdict + else: + thing.XObjects = None + + def _bookmarkReference(self, name): + """get a reference to a (possibly undefined, possibly unbound) bookmark""" + d = self._destinations + try: + return d[name] + except: + result = d[name] = pdfdoc.Destination(name) # newly defined, unbound + return result + + def bookmarkPage(self, key, + fit="Fit", + left=None, + top=None, + bottom=None, + right=None, + zoom=None + ): + """ + This creates a bookmark to the current page which can + be referred to with the given key elsewhere. + + PDF offers very fine grained control over how Acrobat + reader is zoomed when people link to this. The default + is to keep the user's current zoom settings. the last + arguments may or may not be needed depending on the + choice of 'fitType'. + + Fit types and the other arguments they use are: + + - XYZ left top zoom - fine grained control. null + or zero for any of the parameters means 'leave + as is', so "0,0,0" will keep the reader's settings. + NB. Adobe Reader appears to prefer "null" to 0's. + + - Fit - entire page fits in window + + - FitH top - top coord at top of window, width scaled + to fit. + + - FitV left - left coord at left of window, height + scaled to fit + + - FitR left bottom right top - scale window to fit + the specified rectangle + + (question: do we support /FitB, FitBH and /FitBV + which are hangovers from version 1.1 / Acrobat 3.0?)""" + dest = self._bookmarkReference(key) + self._doc.inPage() # try to enable page-only features + pageref = self._doc.thisPageRef() + + #None = "null" for PDF + if left is None: + left = "null" + if top is None: + top = "null" + if bottom is None: + bottom = "null" + if right is None: + right = "null" + if zoom is None: + zoom = "null" + + if fit == "XYZ": + dest.xyz(left,top,zoom) + elif fit == "Fit": + dest.fit() + elif fit == "FitH": + dest.fith(top) + elif fit == "FitV": + dest.fitv(left) + elif fit == "FitR": + dest.fitr(left,bottom,right,top) + #Do we need these (version 1.1 / Acrobat 3 versions)? + elif fit == "FitB": + dest.fitb() + elif fit == "FitBH": + dest.fitbh(top) + elif fit == "FitBV": + dest.fitbv(left) + else: + raise ValueError("Unknown Fit type %s" % ascii(fit)) + + dest.setPage(pageref) + return dest + + def bookmarkHorizontalAbsolute(self, key, top, left=0, fit='XYZ', **kw): + """Bind a bookmark (destination) to the current page at a horizontal position. + Note that the yhorizontal of the book mark is with respect to the default + user space (where the origin is at the lower left corner of the page) + and completely ignores any transform (translation, scale, skew, rotation, + etcetera) in effect for the current graphics state. The programmer is + responsible for making sure the bookmark matches an appropriate item on + the page.""" + #This method should probably be deprecated since it is just a sub-set of bookmarkPage + return self.bookmarkPage(key, fit=fit, top=top, left=left, zoom=0) + + def bookmarkHorizontal(self, key, relativeX, relativeY, **kw): + """w.r.t. the current transformation, bookmark this horizontal.""" + (left, top) = self.absolutePosition(relativeX,relativeY) + self.bookmarkHorizontalAbsolute(key, top, left=left, **kw) + + #def _inPage0(self): disallowed! + # """declare a page, enable page features""" + # self._doc.inPage() + + #def _inForm0(self): + # "deprecated in favore of beginForm...endForm" + # self._doc.inForm() + + def doForm(self, name): + """use a form XObj in current operation stream. + + The form should either have been defined previously using + beginForm ... endForm, or may be defined later. If it is not + defined at save time, an exception will be raised. The form + will be drawn within the context of the current graphics + state.""" + self._code.append("/%s Do" % self._doc.getXObjectName(name)) + self._formsinuse.append(name) + + def hasForm(self, name): + """Query whether form XObj really exists yet.""" + return self._doc.hasForm(name) + + ###################################################### + # + # Image routines + # + ###################################################### + def drawInlineImage(self, image, x,y, width=None,height=None, + preserveAspectRatio=False,anchor='c'): + """See drawImage, which should normally be used instead... + + drawInlineImage behaves like drawImage, but stores the image content + within the graphics stream for the page. This means that the mask + parameter for transparency is not available. It also means that there + is no saving in file size or time if the same image is reused. + + In theory it allows images to be displayed slightly faster; however, + we doubt if the difference is noticeable to any human user these days. + Only use this if you have studied the PDF specification and know the + implications. + """ + + self._currentPageHasImages = 1 + from reportlab.pdfgen.pdfimages import PDFImage + img_obj = PDFImage(image, x,y, width, height) + img_obj.drawInlineImage(self, + preserveAspectRatio=preserveAspectRatio, + anchor=anchor) + return (img_obj.width, img_obj.height) + + def drawImage(self, image, x, y, width=None, height=None, mask=None, + preserveAspectRatio=False, anchor='c'): + """Draws the image (ImageReader object or filename) as specified. + + "image" may be an image filename or an ImageReader object. + + x and y define the lower left corner of the image you wish to + draw (or of its bounding box, if using preserveAspectRation below). + + If width and height are not given, the width and height of the + image in pixels is used at a scale of 1 point to 1 pixel. + + If width and height are given, the image will be stretched to fill + the given rectangle bounded by (x, y, x+width, y-height). + + If you supply negative widths and/or heights, it inverts them and adjusts + x and y accordingly. + + The method returns the width and height of the underlying image, since + this is often useful for layout algorithms and saves you work if you have + not specified them yourself. + + The mask parameter supports transparent backgrounds. It takes 6 numbers + and defines the range of RGB values which will be masked out or treated + as transparent. For example with [0,2,40,42,136,139], it will mask out + any pixels with a Red value from 0-2, Green from 40-42 and + Blue from 136-139 (on a scale of 0-255). + + New post version 2.0: drawImage can center an image in a box you + provide, while preserving its aspect ratio. For example, you might + have a fixed square box in your design, and a collection of photos + which might be landscape or portrait that you want to appear within + the box. If preserveAspectRatio is true, your image will appear within + the box specified. + + + If preserveAspectRatio is True, the anchor property can be used to + specify how images should fit into the given box. It should + be set to one of the following values, taken from the points of + the compass (plus 'c' for 'centre'): + + nw n ne + w c e + sw s se + + The default value is 'c' for 'centre'. Thus, if you want your + bitmaps to always be centred and appear at the top of the given box, + set anchor='n'. There are good examples of this in the output + of test_pdfgen_general.py + + Unlike drawInlineImage, this creates 'external images' which + are only stored once in the PDF file but can be drawn many times. + If you give it the same filename twice, even at different locations + and sizes, it will reuse the first occurrence, resulting in a saving + in file size and generation time. If you use ImageReader objects, + it tests whether the image content has changed before deciding + whether to reuse it. + + In general you should use drawImage in preference to drawInlineImage + unless you have read the PDF Spec and understand the tradeoffs.""" + + self._currentPageHasImages = 1 + + # first, generate a unique name/signature for the image. If ANYTHING + # is different, even the mask, this should be different. + if isinstance(image,ImageReader): + rawdata = image.getRGBData() + smask = image._dataA + if mask=='auto' and smask: + mdata = smask.getRGBData() + else: + mdata = str(mask) + if isUnicode(mdata): + mdata = mdata.encode('utf8') + name = _digester(rawdata+mdata) + else: + #filename, use it + s = '%s%s' % (image, mask) + if isUnicode(s): + s = s.encode('utf-8') + name = _digester(s) + + # in the pdf document, this will be prefixed with something to + # say it is an XObject. Does it exist yet? + regName = self._doc.getXObjectName(name) + imgObj = self._doc.idToObject.get(regName, None) + if not imgObj: + #first time seen, create and register the PDFImageXobject + imgObj = pdfdoc.PDFImageXObject(name, image, mask=mask) + imgObj.name = name + self._setXObjects(imgObj) + self._doc.Reference(imgObj, regName) + self._doc.addForm(name, imgObj) + smask = getattr(imgObj,'_smask',None) + if smask: #set up the softmask obtained above + mRegName = self._doc.getXObjectName(smask.name) + mImgObj = self._doc.idToObject.get(mRegName, None) + if not mImgObj: + self._setXObjects(smask) + imgObj.smask = self._doc.Reference(smask,mRegName) + else: + imgObj.smask = pdfdoc.PDFObjectReference(mRegName) + del imgObj._smask + + # ensure we have a size, as PDF will make it 1x1 pixel otherwise! + x,y,width,height,scaled = aspectRatioFix(preserveAspectRatio,anchor,x,y,width,height,imgObj.width,imgObj.height) + + # scale and draw + self.saveState() + self.translate(x, y) + self.scale(width, height) + self._code.append("/%s Do" % regName) + self.restoreState() + + # track what's been used on this page + self._formsinuse.append(name) + + return (imgObj.width, imgObj.height) + + def _restartAccumulators(self): + if self._codeStack: + # restore the saved code + saved = self._codeStack[-1] + del self._codeStack[-1] + self._code, self._formsinuse, self._annotationrefs, self._formData,self._colorsUsed, self._shadingUsed = saved + else: + self._code = [] # ready for more... + self._psCommandsAfterPage = [] + self._currentPageHasImages = 1 # for safety... + self._formsinuse = [] + self._annotationrefs = [] + self._formData = None + self._colorsUsed = {} + self._shadingUsed = {} + + def _pushAccumulators(self): + "when you enter a form, save accumulator info not related to the form for page (if any)" + saved = (self._code, self._formsinuse, self._annotationrefs, self._formData, self._colorsUsed, self._shadingUsed) + self._codeStack.append(saved) + self._code = [] # ready for more... + self._currentPageHasImages = 1 # for safety... + self._formsinuse = [] + self._annotationrefs = [] + self._formData = None + self._colorsUsed = {} + self._shadingUsed = {} + + def _setExtGState(self, obj): + obj.ExtGState = self._extgstate.getState() + + def beginForm(self, name, lowerx=0, lowery=0, upperx=None, uppery=None): + """declare the current graphics stream to be a named form. + A graphics stream can either be a page or a form, not both. + Some operations (like bookmarking) are permitted for pages + but not forms. The form will not automatically be shown in the + document but must be explicitly referenced using doForm in pages + that require the form.""" + self.push_state_stack() + self.init_graphics_state() + if self._code or self._formData: + # save the code that is not in the formf + self._pushAccumulators() + #self._codeStack.append(self._code) + #self._code = [] + self._formData = (name, lowerx, lowery, upperx, uppery) + self._doc.inForm() + #self._inForm0() + + def endForm(self,**extra_attributes): + """emit the current collection of graphics operations as a Form + as declared previously in beginForm.""" + (name, lowerx, lowery, upperx, uppery) = self._formData + #self.makeForm0(name, lowerx, lowery, upperx, uppery) + # fall through! makeForm0 disallowed + #def makeForm0(self, name, lowerx=0, lowery=0, upperx=None, uppery=None): + """Like showpage, but make a form using accumulated operations instead""" + # deprecated in favor or beginForm(...)... endForm() + (w,h) = self._pagesize + if upperx is None: upperx=w + if uppery is None: uppery=h + form = pdfdoc.PDFFormXObject(lowerx=lowerx, lowery=lowery, upperx=upperx, uppery=uppery) + form.compression = self._pageCompression + form.setStreamList([self._preamble] + self._code) # ??? minus preamble (seems to be needed!) + for k, v in extra_attributes.items(): + setattr(form,k,v) + self._setColorSpace(form) + self._setExtGState(form) + self._setXObjects(form) + self._setAnnotations(form) + self._doc.addForm(name, form) + self._restartAccumulators() + self.pop_state_stack() + + def addPostScriptCommand(self, command, position=1): + """Embed literal Postscript in the document. + + With position=0, it goes at very beginning of page stream; + with position=1, at current point; and + with position=2, at very end of page stream. What that does + to the resulting Postscript depends on Adobe's header :-) + + Use with extreme caution, but sometimes needed for printer tray commands. + Acrobat 4.0 will export Postscript to a printer or file containing + the given commands. Adobe Reader 6.0 no longer does as this feature is + deprecated. 5.0, I don't know about (please let us know!). This was + funded by Bob Marshall of Vector.co.uk and tested on a Lexmark 750. + See test_pdfbase_postscript.py for 2 test cases - one will work on + any Postscript device, the other uses a 'setpapertray' command which + will error in Distiller but work on printers supporting it. + """ + #check if we've done this one already... + if isUnicode(command): + rawName = 'PS' + hashlib.md5(command.encode('utf-8')).hexdigest() + else: + rawName = 'PS' + hashlib.md5(command).hexdigest() + regName = self._doc.getXObjectName(rawName) + psObj = self._doc.idToObject.get(regName, None) + if not psObj: + #first use of this chunk of Postscript, make an object + psObj = pdfdoc.PDFPostScriptXObject(command + '\r\n') + self._setXObjects(psObj) + self._doc.Reference(psObj, regName) + self._doc.addForm(rawName, psObj) + if position == 0: + self._psCommandsBeforePage.append("/%s Do" % regName) + elif position==1: + self._code.append("/%s Do" % regName) + else: + self._psCommandsAfterPage.append("/%s Do" % regName) + + self._formsinuse.append(rawName) + + def _absRect(self,rect,relative=0): + if not rect: + w,h = self._pagesize + rect = (0,0,w,h) + elif relative: + lx, ly, ux, uy = rect + xll,yll = self.absolutePosition(lx,ly) + xur,yur = self.absolutePosition(ux, uy) + xul,yul = self.absolutePosition(lx, uy) + xlr,ylr = self.absolutePosition(ux, ly) + xs = xll, xur, xul, xlr + ys = yll, yur, yul, ylr + xmin, ymin = min(xs), min(ys) + xmax, ymax = max(xs), max(ys) + rect = xmin, ymin, xmax, ymax + bw = self._getCmShift() + if bw: + rect = rect[0]+bw,rect[1]+bw,rect[2]+bw,rect[3]+bw + return rect + + def freeTextAnnotation(self, contents, DA, Rect=None, addtopage=1, name=None, relative=0, **kw): + """DA is the default appearance string???""" + Rect = self._absRect(Rect,relative) + self._addAnnotation(pdfdoc.FreeTextAnnotation(Rect, contents, DA, **kw), name, addtopage) + + def textAnnotation(self, contents, Rect=None, addtopage=1, name=None, relative=0, **kw): + """Experimental, but works. + """ + Rect = self._absRect(Rect,relative) + self._addAnnotation(pdfdoc.TextAnnotation(Rect, contents, **kw), name, addtopage) + textAnnotation0 = textAnnotation #deprecated + + def highlightAnnotation(self, contents, Rect, QuadPoints=None, Color=[0.83, 0.89, 0.95], addtopage=1, + name=None, relative=0, **kw): + """ + Allows adding of a highlighted annotation. + + Rect: Mouseover area to show contents of annotation + QuadPoints: List of four x/y points [TOP-LEFT, TOP-RIGHT, BOTTOM-LEFT, BOTTOM-RIGHT] + These points outline the areas to highlight. + You can have multiple groups of four to allow multiple highlighted areas. + Is in the format [x1, y1, x2, y2, x3, y3, x4, y4, x1, y1, x2, y2, x3, y3, x4, y4] etc + QuadPoints defaults to be area inside of passed in Rect + Color: The color of the highlighting. + """ + Rect = self._absRect(Rect, relative) + if not QuadPoints: + QuadPoints = pdfdoc.rect_to_quad(Rect) + self._addAnnotation(pdfdoc.HighlightAnnotation(Rect, contents, QuadPoints, Color, **kw), name, addtopage) + + def inkAnnotation(self, contents, InkList=None, Rect=None, addtopage=1, name=None, relative=0, **kw): + raise NotImplementedError + "Experimental" + Rect = self._absRect(Rect,relative) + if not InkList: + InkList = ((100,100,100,h-100,w-100,h-100,w-100,100),) + self._addAnnotation(pdfdoc.InkAnnotation(Rect, contents, InkList, **kw), name, addtopage) + inkAnnotation0 = inkAnnotation #deprecated + + def linkAbsolute(self, contents, destinationname, Rect=None, addtopage=1, name=None, + thickness=0, color=None, dashArray=None, **kw): + """rectangular link annotation positioned wrt the default user space. + The identified rectangle on the page becomes a "hot link" which + when clicked will send the viewer to the page and position identified + by the destination. + + Rect identifies (lowerx, lowery, upperx, uppery) for lower left + and upperright points of the rectangle. Translations and other transforms + are IGNORED (the rectangular position is given with respect + to the default user space. + destinationname should be the name of a bookmark (which may be defined later + but must be defined before the document is generated). + + You may want to use the keyword argument Border='[0 0 0]' to + suppress the visible rectangle around the during viewing link.""" + return self.linkRect(contents, destinationname, Rect, addtopage, name, relative=0, + thickness=thickness, color=color, dashArray=dashArray, **kw) + + def linkRect(self, contents, destinationname, Rect=None, addtopage=1, name=None, relative=1, + thickness=0, color=None, dashArray=None, **kw): + """rectangular link annotation w.r.t the current user transform. + if the transform is skewed/rotated the absolute rectangle will use the max/min x/y + """ + destination = self._bookmarkReference(destinationname) # permitted to be undefined... must bind later... + Rect = self._absRect(Rect,relative) + kw["Rect"] = Rect + kw["Contents"] = contents + kw["Destination"] = destination + _annFormat(kw,color,thickness,dashArray) + return self._addAnnotation(pdfdoc.LinkAnnotation(**kw), name, addtopage) + + def linkURL(self, url, rect, relative=0, thickness=0, color=None, dashArray=None, kind="URI", **kw): + """Create a rectangular URL 'hotspot' in the given rectangle. + + if relative=1, this is in the current coord system, otherwise + in absolute page space. + The remaining options affect the border appearance; the border is + drawn by Acrobat, not us. Set thickness to zero to hide it. + Any border drawn this way is NOT part of the page stream and + will not show when printed to a Postscript printer or distilled; + it is safest to draw your own.""" + from reportlab.pdfbase.pdfdoc import PDFDictionary, PDFName, PDFArray, PDFString + #tried the documented BS element in the pdf spec but it + #does not work, and Acrobat itself does not appear to use it! + + ann = PDFDictionary(dict=kw) + ann["Type"] = PDFName("Annot") + ann["Subtype"] = PDFName("Link") + ann["Rect"] = PDFArray(self._absRect(rect,relative)) # the whole page for testing + + # the action is a separate dictionary + A = PDFDictionary() + A["Type"] = PDFName("Action") # not needed? + uri = PDFString(url) + A['S'] = PDFName(kind) + if kind=="URI": + A["URI"] = uri + elif kind=='GoToR': + A["F"] = uri + A["D"] = "[ 0 /XYZ null null null ]" + else: + raise ValueError("Unknown linkURI kind '%s'" % kind) + + ann["A"] = A + _annFormat(ann,color,thickness,dashArray) + self._addAnnotation(ann) + + def _addAnnotation(self, annotation, name=None, addtopage=1): + count = self._annotationCount = self._annotationCount+1 + if not name: name="NUMBER"+repr(count) + self._doc.addAnnotation(name, annotation) + if addtopage: + self._annotatePage(name) + + def _annotatePage(self, name): + ref = self._doc.refAnnotation(name) + self._annotationrefs.append(ref) + + def getPageNumber(self): + "get the page number for the current page being generated." + return self._pageNumber + + def save(self): + """Saves and close the PDF document in the file. + If there is current data a ShowPage is executed automatically. + After this operation the canvas must not be used further.""" + if len(self._code): self.showPage() + self._doc.SaveToFile(self._filename, self) + + def getpdfdata(self): + """Returns the PDF data that would normally be written to a file. + If there is current data a ShowPage is executed automatically. + After this operation the canvas must not be used further.""" + if len(self._code): self.showPage() + s = self._doc.GetPDFData(self) + if isUnicode(s): + s = s.encode('utf-8') + return s + + def setPageSize(self, size): + """accepts a 2-tuple in points for paper size for this + and subsequent pages""" + self._pagesize = size + self._make_preamble() + + def setPageRotation(self, rot): + """Instruct display device that this page is to be rotated""" + assert rot % 90.0 == 0.0, "Rotation must be a multiple of 90 degrees" + self._pageRotation = rot + + def addLiteral(self, s, escaped=1): + """introduce the literal text of PDF operations s into the current stream. + Only use this if you are an expert in the PDF file format.""" + s = str(s) # make sure its a string + if escaped==0: + s = self._escape(s) # convert to string for safety + self._code.append(s) + + ###################################################################### + # + # coordinate transformations + # + ###################################################################### + def resetTransforms(self): + """I want to draw something (eg, string underlines) w.r.t. the default user space. + Reset the matrix! This should be used usually as follows:: + + canv.saveState() + canv.resetTransforms() + #...draw some stuff in default space coords... + canv.restoreState() # go back! + """ + # we have to adjoin the inverse, since reset is not a basic operation (without save/restore) + (selfa, selfb, selfc, selfd, selfe, selff) = self._currentMatrix + det = selfa*selfd - selfc*selfb + resulta = selfd/det + resultc = -selfc/det + resulte = (selfc*selff - selfd*selfe)/det + resultd = selfa/det + resultb = -selfb/det + resultf = (selfe*selfb - selff*selfa)/det + self.transform(resulta, resultb, resultc, resultd, resulte, resultf) + + def transform(self, a,b,c,d,e,f): + """adjoin a mathematical transform to the current graphics state matrix. + Not recommended for beginners.""" + #How can Python track this? + if ENABLE_TRACKING: + a0,b0,c0,d0,e0,f0 = self._currentMatrix + self._currentMatrix = (a0*a+c0*b, b0*a+d0*b, + a0*c+c0*d, b0*c+d0*d, + a0*e+c0*f+e0, b0*e+d0*f+f0) + if self._code and self._code[-1][-3:]==' cm': + L = self._code[-1].split() + a0, b0, c0, d0, e0, f0 = list(map(float,L[-7:-1])) + s = len(L)>7 and join(L)+ ' %s cm' or '%s cm' + self._code[-1] = s % fp_str(a0*a+c0*b,b0*a+d0*b,a0*c+c0*d,b0*c+d0*d,a0*e+c0*f+e0,b0*e+d0*f+f0) + else: + self._code.append('%s cm' % fp_str(a,b,c,d,e,f)) + + def absolutePosition(self, x, y): + """return the absolute position of x,y in user space w.r.t. default user space""" + if not ENABLE_TRACKING: + raise ValueError("tracking not enabled! (canvas.ENABLE_TRACKING=0)") + (a,b,c,d,e,f) = self._currentMatrix + xp = a*x + c*y + e + yp = b*x + d*y + f + return (xp, yp) + + def translate(self, dx, dy): + """move the origin from the current (0,0) point to the (dx,dy) point + (with respect to the current graphics state).""" + self.transform(1,0,0,1,dx,dy) + + def scale(self, x, y): + """Scale the horizontal dimension by x and the vertical by y + (with respect to the current graphics state). + For example canvas.scale(2.0, 0.5) will make everything short and fat.""" + self.transform(x,0,0,y,0,0) + + def rotate(self, theta): + """Canvas.rotate(theta) + + Rotate the canvas by the angle theta (in degrees).""" + c = cos(theta * pi / 180) + s = sin(theta * pi / 180) + self.transform(c, s, -s, c, 0, 0) + + def skew(self, alpha, beta): + tanAlpha = tan(alpha * pi / 180) + tanBeta = tan(beta * pi / 180) + self.transform(1, tanAlpha, tanBeta, 1, 0, 0) + + ###################################################################### + # + # graphics state management + # + ###################################################################### + + def saveState(self): + """Save the current graphics state to be restored later by restoreState. + + For example: + canvas.setFont("Helvetica", 20) + canvas.saveState() + ... + canvas.setFont("Courier", 9) + ... + canvas.restoreState() + # if the save/restore pairs match then font is Helvetica 20 again. + """ + self.push_state_stack() + self._code.append('q') + + def restoreState(self): + """restore the graphics state to the matching saved state (see saveState).""" + self._code.append('Q') + self.pop_state_stack() + + ############################################################### + # + # Drawing methods. These draw things directly without + # fiddling around with Path objects. We can add any geometry + # methods we wish as long as their meaning is precise and + # they are of general use. + # + # In general there are two patterns. Closed shapes + # have the pattern shape(self, args, stroke=1, fill=0); + # by default they draw an outline only. Line segments come + # in three flavours: line, bezier, arc (which is a segment + # of an elliptical arc, approximated by up to four bezier + # curves, one for each quadrant. + # + # In the case of lines, we provide a 'plural' to unroll + # the inner loop; it is useful for drawing big grids + ################################################################ + + #--------first the line drawing methods----------------------- + + def line(self, x1,y1, x2,y2): + """draw a line segment from (x1,y1) to (x2,y2) (with color, thickness and + other attributes determined by the current graphics state).""" + self._code.append('n %s m %s l S' % (fp_str(x1, y1), fp_str(x2, y2))) + + def lines(self, linelist): + """Like line(), permits many lines to be drawn in one call. + for example for the figure:: + + | + -- -- + | + + crosshairs = [(20,0,20,10), (20,30,20,40), (0,20,10,20), (30,20,40,20)] + canvas.lines(crosshairs) + """ + self._code.append('n') + for (x1,y1,x2,y2) in linelist: + self._code.append('%s m %s l' % (fp_str(x1, y1), fp_str(x2, y2))) + self._code.append('S') + + def grid(self, xlist, ylist): + """Lays out a grid in current line style. Supply list of + x an y positions.""" + assert len(xlist) > 1, "x coordinate list must have 2+ items" + assert len(ylist) > 1, "y coordinate list must have 2+ items" + lines = [] + y0, y1 = ylist[0], ylist[-1] + x0, x1 = xlist[0], xlist[-1] + for x in xlist: + lines.append((x,y0,x,y1)) + for y in ylist: + lines.append((x0,y,x1,y)) + self.lines(lines) + + def bezier(self, x1, y1, x2, y2, x3, y3, x4, y4): + "Bezier curve with the four given control points" + self._code.append('n %s m %s c S' % + (fp_str(x1, y1), fp_str(x2, y2, x3, y3, x4, y4)) + ) + def arc(self, x1,y1, x2,y2, startAng=0, extent=90): + """Draw a partial ellipse inscribed within the rectangle x1,y1,x2,y2, + starting at startAng degrees and covering extent degrees. Angles + start with 0 to the right (+x) and increase counter-clockwise. + These should have x1 + from reportlab.pdfbase.pdfdoc import PDFAxialShading + colorSpace, ncolors = _normalizeColors(colors) + fcn = _buildColorFunction(ncolors, positions) + if extend: + extendStr = "[true true]" + else: + extendStr = "[false false]" + shading = PDFAxialShading(x0, y0, x1, y1, Function=fcn, + ColorSpace=colorSpace, Extend=extendStr) + self.shade(shading) + + def radialGradient(self, x, y, radius, colors, positions=None, extend=True): + #this code contributed by Peter Johnson + from reportlab.pdfbase.pdfdoc import PDFRadialShading + colorSpace, ncolors = _normalizeColors(colors) + fcn = _buildColorFunction(ncolors, positions) + if extend: + extendStr = "[true true]" + else: + extendStr = "[false false]" + shading = PDFRadialShading(x, y, 0.0, x, y, radius, Function=fcn, + ColorSpace=colorSpace, Extend=extendStr) + self.shade(shading) + + ################################################## + # + # Text methods + # + # As with graphics, a separate object ensures that + # everything is bracketed between text operators. + # The methods below are a high-level convenience. + # use PDFTextObject for multi-line text. + ################################################## + + def drawString(self, x, y, text, mode=None): + """Draws a string in the current text styles.""" + if sys.version_info[0] == 3 and not isinstance(text, str): + text = text.decode('utf-8') + #we could inline this for speed if needed + t = self.beginText(x, y) + if mode is not None: t.setTextRenderMode(mode) + t.textLine(text) + self.drawText(t) + + def drawRightString(self, x, y, text, mode=None): + """Draws a string right-aligned with the x coordinate""" + if sys.version_info[0] == 3 and not isinstance(text, str): + text = text.decode('utf-8') + width = self.stringWidth(text, self._fontname, self._fontsize) + t = self.beginText(x - width, y) + if mode is not None: t.setTextRenderMode(mode) + t.textLine(text) + self.drawText(t) + + def drawCentredString(self, x, y, text,mode=None): + """Draws a string centred on the x coordinate. + + We're British, dammit, and proud of our spelling!""" + if sys.version_info[0] == 3 and not isinstance(text, str): + text = text.decode('utf-8') + width = self.stringWidth(text, self._fontname, self._fontsize) + t = self.beginText(x - 0.5*width, y) + if mode is not None: t.setTextRenderMode(mode) + t.textLine(text) + self.drawText(t) + + def drawAlignedString(self, x, y, text, pivotChar=rl_config.decimalSymbol): + """Draws a string aligned on the first '.' (or other pivot character). + + The centre position of the pivot character will be used as x. + So, you could draw a straight line down through all the decimals in a + column of numbers, and anything without a decimal should be + optically aligned with those that have. + + There is one special rule to help with accounting formatting. Here's + how normal numbers should be aligned on the 'dot'. Look at the + LAST two:: + + 12,345,67 + 987.15 + 42 + -1,234.56 + (456.78) + (456) + 27 inches + 13cm + + Since the last three do not contain a dot, a crude dot-finding + rule would place them wrong. So we test for the special case + where no pivot is found, digits are present, but the last character + is not a digit. We then work back from the end of the string + This case is a tad slower but hopefully rare. + + """ + parts = text.split(pivotChar,1) + pivW = self.stringWidth(pivotChar, self._fontname, self._fontsize) + + if len(parts) == 1 and digitPat.search(text) is not None and text[-1] not in digits: + #we have no decimal but it ends in a bracket, or 'in' or something. + #the cut should be after the last digit. + leftText = parts[0][0:-1] + rightText = parts[0][-1] + #any more? + while leftText[-1] not in digits: + rightText = leftText[-1] + rightText + leftText = leftText[0:-1] + + self.drawRightString(x-0.5*pivW, y, leftText) + self.drawString(x-0.5*pivW, y, rightText) + + else: + #normal case + leftText = parts[0] + self.drawRightString(x-0.5*pivW, y, leftText) + if len(parts) > 1: + rightText = pivotChar + parts[1] + self.drawString(x-0.5*pivW, y, rightText) + + def getAvailableFonts(self): + """Returns the list of PostScript font names available. + + Standard set now, but may grow in future with font embedding.""" + fontnames = self._doc.getAvailableFonts() + fontnames.sort() + return fontnames + + def addFont(self, fontObj): + "add a new font for subsequent use." + self._doc.addFont(fontObj) + + def _addStandardFonts(self): + """Ensures the standard 14 fonts are available in the system encoding. + Called by canvas on initialization""" + for fontName in pdfmetrics.standardFonts: + self.addFont(pdfmetrics.fontsByName[fontName]) + + def listLoadedFonts0(self): + "Convenience function to list all loaded fonts" + names = list(pdfmetrics.widths.keys()) + names.sort() + return names + + def setFont(self, psfontname, size, leading = None): + """Sets the font. If leading not specified, defaults to 1.2 x + font size. Raises a readable exception if an illegal font + is supplied. Font names are case-sensitive! Keeps track + of font name and size for metrics.""" + self._fontname = psfontname + self._fontsize = size + if leading is None: + leading = size * 1.2 + self._leading = leading + font = pdfmetrics.getFont(self._fontname) + if not font._dynamicFont: + if font.face.builtIn or not getattr(self,'_drawTextAsPath',False): + pdffontname = self._doc.getInternalFontName(psfontname) + self._code.append('BT %s %s Tf %s TL ET' % (pdffontname, fp_str(size), fp_str(leading))) + + def setFontSize(self, size=None, leading=None): + '''Sets font size or leading without knowing the font face''' + if size is None: size = self._fontsize + if leading is None: leading = self._leading + self.setFont(self._fontname, size, leading) + + def stringWidth(self, text, fontName=None, fontSize=None): + "gets width of a string in the given font and size" + return pdfmetrics.stringWidth(text, fontName or self._fontname, + (fontSize,self._fontsize)[fontSize is None]) + + # basic graphics modes + + def setLineWidth(self, width): + self._lineWidth = width + self._code.append('%s w' % fp_str(width)) + + def setLineCap(self, mode): + """0=butt,1=round,2=square""" + assert mode in (0,1,2), "Line caps allowed: 0=butt,1=round,2=square" + self._lineCap = mode + self._code.append('%d J' % mode) + + def setLineJoin(self, mode): + """0=mitre, 1=round, 2=bevel""" + assert mode in (0,1,2), "Line Joins allowed: 0=mitre, 1=round, 2=bevel" + self._lineJoin = mode + self._code.append('%d j' % mode) + + def setMiterLimit(self, limit): + self._miterLimit = limit + self._code.append('%s M' % fp_str(limit)) + + def setDash(self, array=[], phase=0): + """Two notations. pass two numbers, or an array and phase""" + if isinstance(array,(int,float)): + self._code.append('[%s %s] 0 d' % (array, phase)) + elif isSeq(array): + assert phase >= 0, "phase is a length in user space" + textarray = ' '.join([str(s) for s in array]) + self._code.append('[%s] %s d' % (textarray, phase)) + + # path stuff - the separate path object builds it + + def beginPath(self): + """Returns a fresh path object. Paths are used to draw + complex figures. The object returned follows the protocol + for a pathobject.PDFPathObject instance""" + return pathobject.PDFPathObject() + + def drawPath(self, aPath, stroke=1, fill=0): + "Draw the path object in the mode indicated" + self._code.append(str(aPath.getCode())) + self._strokeAndFill(stroke,fill) + + def _strokeAndFill(self,stroke,fill): + self._code.append(PATH_OPS[stroke, fill, self._fillMode]) + + def clipPath(self, aPath, stroke=1, fill=0): + "clip as well as drawing" + gc = aPath.getCode(); pathops = PATH_OPS[stroke, fill, self._fillMode] + clip = (self._fillMode == FILL_EVEN_ODD and ' W* ' or ' W ') + item = "%s%s%s" % (gc, clip, pathops) # ensure string conversion + self._code.append(item) + #self._code.append( aPath.getCode() + # + (self._fillMode == FILL_EVEN_ODD and ' W* ' or ' W ') + # + PATH_OPS[stroke,fill,self._fillMode]) + + def beginText(self, x=0, y=0): + """Returns a fresh text object. Text objects are used + to add large amounts of text. See textobject.PDFTextObject""" + return textobject.PDFTextObject(self, x, y) + + def drawText(self, aTextObject): + """Draws a text object""" + self._code.append(str(aTextObject.getCode())) + + def setPageCompression(self, pageCompression=1): + """Possible values None, 1 or 0 + If None the value from rl_config will be used. + If on, the page data will be compressed, leading to much + smaller files, but takes a little longer to create the files. + This applies to all subsequent pages, or until setPageCompression() + is next called.""" + if pageCompression is None: pageCompression = rl_config.pageCompression + if pageCompression and not zlib: + self._pageCompression = 0 + else: + self._pageCompression = pageCompression + self._doc.setCompression(self._pageCompression) + + def setPageDuration(self, duration=None): + """Allows hands-off animation of presentations :-) + + If this is set to a number, in full screen mode, Acrobat Reader + will advance to the next page after this many seconds. The + duration of the transition itself (fade/flicker etc.) is controlled + by the 'duration' argument to setPageTransition; this controls + the time spent looking at the page. This is effective for all + subsequent pages.""" + + self._pageDuration = duration + + def setPageTransition(self, effectname=None, duration=1, + direction=0,dimension='H',motion='I'): + """PDF allows page transition effects for use when giving + presentations. There are six possible effects. You can + just guive the effect name, or supply more advanced options + to refine the way it works. There are three types of extra + argument permitted, and here are the allowed values:: + + direction_arg = [0,90,180,270] + dimension_arg = ['H', 'V'] + motion_arg = ['I','O'] (start at inside or outside) + + This table says which ones take which arguments:: + + PageTransitionEffects = { + 'Split': [direction_arg, motion_arg], + 'Blinds': [dimension_arg], + 'Box': [motion_arg], + 'Wipe' : [direction_arg], + 'Dissolve' : [], + 'Glitter':[direction_arg] + } + + Have fun! + """ + # This builds a Python dictionary with the right arguments + # for the Trans dictionary in the PDFPage object, + # and stores it in the variable _pageTransition. + # showPage later passes this to the setPageTransition method + # of the PDFPage object, which turns it to a PDFDictionary. + self._pageTransition = {} + if not effectname: + return + + #first check each optional argument has an allowed value + if direction in [0,90,180,270]: + direction_arg = ('Di', '/%d' % direction) + else: + raise pdfdoc.PDFError(' directions allowed are 0,90,180,270') + + if dimension in ['H', 'V']: + dimension_arg = ('Dm', '/' + dimension) + else: + raise pdfdoc.PDFError('dimension values allowed are H and V') + + if motion in ['I','O']: + motion_arg = ('M', '/' + motion) + else: + raise pdfdoc.PDFError('motion values allowed are I and O') + + # this says which effects require which argument types from above + PageTransitionEffects = { + 'Split': [direction_arg, motion_arg], + 'Blinds': [dimension_arg], + 'Box': [motion_arg], + 'Wipe' : [direction_arg], + 'Dissolve' : [], + 'Glitter':[direction_arg] + } + + try: + args = PageTransitionEffects[effectname] + except KeyError: + raise pdfdoc.PDFError('Unknown Effect Name "%s"' % effectname) + + # now build the dictionary + transDict = {} + transDict['Type'] = '/Trans' + transDict['D'] = '%d' % duration + transDict['S'] = '/' + effectname + for (key, value) in args: + transDict[key] = value + self._pageTransition = transDict + + def getCurrentPageContent(self): + """Return uncompressed contents of current page buffer. + + This is useful in creating test cases and assertions of what + got drawn, without necessarily saving pages to disk""" + return '\n'.join(self._code) + + def setViewerPreference(self,pref,value): + '''set one of the allowed enbtries in the documents viewer preferences''' + catalog = self._doc.Catalog + VP = getattr(catalog,'ViewerPreferences',None) + if VP is None: + from reportlab.pdfbase.pdfdoc import ViewerPreferencesPDFDictionary + VP = catalog.ViewerPreferences = ViewerPreferencesPDFDictionary() + VP[pref] = value + + def getViewerPreference(self,pref): + '''you'll get an error here if none have been set''' + return self._doc.Catalog.ViewerPreferences[pref] + + def delViewerPreference(self,pref): + '''you'll get an error here if none have been set''' + del self._doc.Catalog.ViewerPreferences[pref] + + def addPageLabel(self, pageNum, style=None, start=None, prefix=None): + '''add a PDFPageLabel for pageNum''' + catalog = self._doc.Catalog + PL = getattr(catalog,'PageLabels',None) + if PL is None: + from reportlab.pdfbase.pdfdoc import PDFPageLabels + PL = catalog.PageLabels = PDFPageLabels() + + from reportlab.pdfbase.pdfdoc import PDFPageLabel + PL.addPageLabel(pageNum,PDFPageLabel(style,start,prefix)) + +if __name__ == '__main__': + print('For test scripts, look in tests') diff --git a/reportlab/pdfgen/pathobject.py b/reportlab/pdfgen/pathobject.py new file mode 100644 index 00000000..07b56e43 --- /dev/null +++ b/reportlab/pdfgen/pathobject.py @@ -0,0 +1,127 @@ +#Copyright ReportLab Europe Ltd. 2000-2012 +#see license.txt for license details +#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/pdfgen/pathobject.py +__version__=''' $Id$ ''' +__doc__=""" +PDFPathObject is an efficient way to draw paths on a Canvas. Do not +instantiate directly, obtain one from the Canvas instead. + +Progress Reports: +8.83, 2000-01-13, gmcm: created from pdfgen.py + +""" + +from reportlab.pdfgen import pdfgeom +from reportlab.lib.rl_accel import fp_str + + +class PDFPathObject: + """Represents a graphic path. There are certain 'modes' to PDF + drawing, and making a separate object to expose Path operations + ensures they are completed with no run-time overhead. Ask + the Canvas for a PDFPath with getNewPathObject(); moveto/lineto/ + curveto wherever you want; add whole shapes; and then add it back + into the canvas with one of the relevant operators. + + Path objects are probably not long, so we pack onto one line + + the code argument allows a canvas to get the operatiosn appended directly so + avoiding the final getCode + """ + def __init__(self,code=None): + self._code = (code,[])[code is None] + self._code_append = self._init_code_append + + def _init_code_append(self,c): + assert c.endswith(' m') or c.endswith(' re'), 'path must start with a moveto or rect' + code_append = self._code.append + code_append('n') + code_append(c) + self._code_append = code_append + + def getCode(self): + "pack onto one line; used internally" + return ' '.join(self._code) + + def moveTo(self, x, y): + self._code_append('%s m' % fp_str(x,y)) + + def lineTo(self, x, y): + self._code_append('%s l' % fp_str(x,y)) + + def curveTo(self, x1, y1, x2, y2, x3, y3): + self._code_append('%s c' % fp_str(x1, y1, x2, y2, x3, y3)) + + def arc(self, x1,y1, x2,y2, startAng=0, extent=90): + """Contributed to piddlePDF by Robert Kern, 28/7/99. + Draw a partial ellipse inscribed within the rectangle x1,y1,x2,y2, + starting at startAng degrees and covering extent degrees. Angles + start with 0 to the right (+x) and increase counter-clockwise. + These should have x1.""" + + self._curves(pdfgeom.bezierArc(x1,y1, x2,y2, startAng, extent)) + + def arcTo(self, x1,y1, x2,y2, startAng=0, extent=90): + """Like arc, but draws a line from the current point to + the start if the start is not the current point.""" + self._curves(pdfgeom.bezierArc(x1,y1, x2,y2, startAng, extent),'lineTo') + + def rect(self, x, y, width, height): + """Adds a rectangle to the path""" + self._code_append('%s re' % fp_str((x, y, width, height))) + + def ellipse(self, x, y, width, height): + """adds an ellipse to the path""" + self._curves(pdfgeom.bezierArc(x, y, x + width,y + height, 0, 360)) + + def _curves(self,curves,initial='moveTo'): + getattr(self,initial)(*curves[0][:2]) + for curve in curves: + self.curveTo(*curve[2:]) + + def circle(self, x_cen, y_cen, r): + """adds a circle to the path""" + x1 = x_cen - r + y1 = y_cen - r + width = height = 2*r + self.ellipse(x1, y1, width, height) + + def roundRect(self, x, y, width, height, radius): + """Draws a rectangle with rounded corners. The corners are + approximately quadrants of a circle, with the given radius.""" + #use a precomputed set of factors for the bezier approximation + #to a circle. There are six relevant points on the x axis and y axis. + #sketch them and it should all make sense! + t = 0.4472 * radius + + x0 = x + x1 = x0 + t + x2 = x0 + radius + x3 = x0 + width - radius + x4 = x0 + width - t + x5 = x0 + width + + y0 = y + y1 = y0 + t + y2 = y0 + radius + y3 = y0 + height - radius + y4 = y0 + height - t + y5 = y0 + height + + self.moveTo(x2, y0) + self.lineTo(x3, y0) #bottom row + self.curveTo(x4, y0, x5, y1, x5, y2) #bottom right + self.lineTo(x5, y3) #right edge + self.curveTo(x5, y4, x4, y5, x3, y5) #top right + self.lineTo(x2, y5) #top row + self.curveTo(x1, y5, x0, y4, x0, y3) #top left + self.lineTo(x0, y2) #left edge + self.curveTo(x0, y1, x1, y0, x2, y0) #bottom left + self.close() + + def close(self): + "draws a line back to where it started" + self._code_append('h') diff --git a/reportlab/pdfgen/pdfgeom.py b/reportlab/pdfgen/pdfgeom.py new file mode 100644 index 00000000..3d5c801c --- /dev/null +++ b/reportlab/pdfgen/pdfgeom.py @@ -0,0 +1,77 @@ +#Copyright ReportLab Europe Ltd. 2000-2012 +#see license.txt for license details +#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/pdfgen/pdfgeom.py +__version__=''' $Id$ ''' +__doc__=""" +This module includes any mathematical methods needed for PIDDLE. +It should have no dependencies beyond the Python library. + +So far, just Robert Kern's bezierArc. +""" + +from math import sin, cos, pi, ceil + + +def bezierArc(x1,y1, x2,y2, startAng=0, extent=90): + """bezierArc(x1,y1, x2,y2, startAng=0, extent=90) --> List of Bezier +curve control points. + +(x1, y1) and (x2, y2) are the corners of the enclosing rectangle. The +coordinate system has coordinates that increase to the right and down. +Angles, measured in degress, start with 0 to the right (the positive X +axis) and increase counter-clockwise. The arc extends from startAng +to startAng+extent. I.e. startAng=0 and extent=180 yields an openside-down +semi-circle. + +The resulting coordinates are of the form (x1,y1, x2,y2, x3,y3, x4,y4) +such that the curve goes from (x1, y1) to (x4, y4) with (x2, y2) and +(x3, y3) as their respective Bezier control points.""" + + x1,y1, x2,y2 = min(x1,x2), max(y1,y2), max(x1,x2), min(y1,y2) + + if abs(extent) <= 90: + arcList = [startAng] + fragAngle = float(extent) + Nfrag = 1 + else: + arcList = [] + Nfrag = int(ceil(abs(extent)/90.)) + fragAngle = float(extent) / Nfrag + + x_cen = (x1+x2)/2. + y_cen = (y1+y2)/2. + rx = (x2-x1)/2. + ry = (y2-y1)/2. + halfAng = fragAngle * pi / 360. + kappa = abs(4. / 3. * (1. - cos(halfAng)) / sin(halfAng)) + + if fragAngle < 0: + sign = -1 + else: + sign = 1 + + pointList = [] + + for i in range(Nfrag): + theta0 = (startAng + i*fragAngle) * pi / 180. + theta1 = (startAng + (i+1)*fragAngle) *pi / 180. + if fragAngle > 0: + pointList.append((x_cen + rx * cos(theta0), + y_cen - ry * sin(theta0), + x_cen + rx * (cos(theta0) - kappa * sin(theta0)), + y_cen - ry * (sin(theta0) + kappa * cos(theta0)), + x_cen + rx * (cos(theta1) + kappa * sin(theta1)), + y_cen - ry * (sin(theta1) - kappa * cos(theta1)), + x_cen + rx * cos(theta1), + y_cen - ry * sin(theta1))) + else: + pointList.append((x_cen + rx * cos(theta0), + y_cen - ry * sin(theta0), + x_cen + rx * (cos(theta0) + kappa * sin(theta0)), + y_cen - ry * (sin(theta0) - kappa * cos(theta0)), + x_cen + rx * (cos(theta1) - kappa * sin(theta1)), + y_cen - ry * (sin(theta1) + kappa * cos(theta1)), + x_cen + rx * cos(theta1), + y_cen - ry * sin(theta1))) + + return pointList \ No newline at end of file diff --git a/reportlab/pdfgen/pdfimages.py b/reportlab/pdfgen/pdfimages.py new file mode 100644 index 00000000..d5822dfb --- /dev/null +++ b/reportlab/pdfgen/pdfimages.py @@ -0,0 +1,217 @@ +#Copyright ReportLab Europe Ltd. 2000-2012 +#see license.txt for license details +#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/pdfgen/pdfimages.py +__version__=''' $Id$ ''' +__doc__=""" +Image functionality sliced out of canvas.py for generalization +""" + +import os +import reportlab +from reportlab import rl_config +from reportlab.pdfbase import pdfutils +from reportlab.pdfbase import pdfdoc +from reportlab.lib.utils import import_zlib, haveImages, getBytesIO, isStr +from reportlab.lib.rl_accel import fp_str, asciiBase85Encode +from reportlab.lib.boxstuff import aspectRatioFix + + +class PDFImage: + """Wrapper around different "image sources". You can make images + from a PIL Image object, a filename (in which case it uses PIL), + an image we previously cached (optimisation, hardly used these + days) or a JPEG (which PDF supports natively).""" + + def __init__(self, image, x,y, width=None, height=None, caching=0): + self.image = image + self.x = x + self.y = y + self.width = width + self.height = height + self.filename = None + self.imageCaching = caching + # the following facts need to be determined, + # whatever the source. Declare what they are + # here for clarity. + self.colorSpace = 'DeviceRGB' + self.bitsPerComponent = 8 + self.filters = [] + self.source = None # JPEG or PIL, set later + self.getImageData() + + def jpg_imagedata(self): + #directly process JPEG files + #open file, needs some error handling!! + fp = open(self.image, 'rb') + try: + result = self._jpg_imagedata(fp) + finally: + fp.close() + return result + + def _jpg_imagedata(self,imageFile): + info = pdfutils.readJPEGInfo(imageFile) + self.source = 'JPEG' + imgwidth, imgheight = info[0], info[1] + if info[2] == 1: + colorSpace = 'DeviceGray' + elif info[2] == 3: + colorSpace = 'DeviceRGB' + else: #maybe should generate an error, is this right for CMYK? + colorSpace = 'DeviceCMYK' + imageFile.seek(0) #reset file pointer + imagedata = [] + #imagedata.append('BI /Width %d /Height /BitsPerComponent 8 /ColorSpace /%s /Filter [/Filter [ /ASCII85Decode /DCTDecode] ID' % (info[0], info[1], colorSpace)) + imagedata.append('BI /W %d /H %d /BPC 8 /CS /%s /F [%s/DCT] ID' % (imgwidth, imgheight, colorSpace, rl_config.useA85 and '/A85 ' or '')) + #write in blocks of (??) 60 characters per line to a list + data = imageFile.read() + if rl_config.useA85: + data = asciiBase85Encode(data) + pdfutils._chunker(data,imagedata) + imagedata.append('EI') + return (imagedata, imgwidth, imgheight) + + def cache_imagedata(self): + image = self.image + if not pdfutils.cachedImageExists(image): + zlib = import_zlib() + if not zlib: return + if not haveImages: return + pdfutils.cacheImageFile(image) + + #now we have one cached, slurp it in + cachedname = os.path.splitext(image)[0] + (rl_config.useA85 and '.a85' or '.bin') + imagedata = open(cachedname,'rb').readlines() + #trim off newlines... + imagedata = list(map(str.strip, imagedata)) + return imagedata + + def PIL_imagedata(self): + image = self.image + if image.format=='JPEG': + fp=image.fp + fp.seek(0) + return self._jpg_imagedata(fp) + self.source = 'PIL' + zlib = import_zlib() + if not zlib: return + + bpc = 8 + # Use the colorSpace in the image + if image.mode == 'CMYK': + myimage = image + colorSpace = 'DeviceCMYK' + bpp = 4 + elif image.mode == '1': + myimage = image + colorSpace = 'DeviceGray' + bpp = 1 + bpc = 1 + elif image.mode == 'L': + myimage = image + colorSpace = 'DeviceGray' + bpp = 1 + else: + myimage = image.convert('RGB') + colorSpace = 'RGB' + bpp = 3 + imgwidth, imgheight = myimage.size + + # this describes what is in the image itself + # *NB* according to the spec you can only use the short form in inline images + imagedata=['BI /W %d /H %d /BPC %d /CS /%s /F [%s/Fl] ID' % (imgwidth, imgheight, bpc, colorSpace, rl_config.useA85 and '/A85 ' or '')] + + #use a flate filter and, optionally, Ascii Base 85 to compress + raw = (myimage.tobytes if hasattr(myimage,'tobytes') else myimage.tostring)() + rowstride = (imgwidth*bpc*bpp+7)>>3 + assert len(raw) == rowstride*imgheight, "Wrong amount of data for image" + data = zlib.compress(raw) #this bit is very fast... + if rl_config.useA85: + data = asciiBase85Encode(data) #...sadly this may not be + #append in blocks of 60 characters + pdfutils._chunker(data,imagedata) + imagedata.append('EI') + return (imagedata, imgwidth, imgheight) + + def non_jpg_imagedata(self,image): + if not self.imageCaching: + imagedata = pdfutils.cacheImageFile(image,returnInMemory=1) + else: + imagedata = self.cache_imagedata() + words = imagedata[1].split() + imgwidth = int(words[1]) + imgheight = int(words[3]) + return imagedata, imgwidth, imgheight + + def getImageData(self,preserveAspectRatio=False): + "Gets data, height, width - whatever type of image" + image = self.image + + if isStr(image): + self.filename = image + if os.path.splitext(image)[1] in ['.jpg', '.JPG', '.jpeg', '.JPEG']: + try: + imagedata, imgwidth, imgheight = self.jpg_imagedata() + except: + imagedata, imgwidth, imgheight = self.non_jpg_imagedata(image) #try for normal kind of image + else: + imagedata, imgwidth, imgheight = self.non_jpg_imagedata(image) + else: + import sys + if sys.platform[0:4] == 'java': + #jython, PIL not available + imagedata, imgwidth, imgheight = self.JAVA_imagedata() + else: + imagedata, imgwidth, imgheight = self.PIL_imagedata() + self.imageData = imagedata + self.imgwidth = imgwidth + self.imgheight = imgheight + self.width = self.width or imgwidth + self.height = self.height or imgheight + + def drawInlineImage(self, canvas, preserveAspectRatio=False,anchor='sw'): + """Draw an Image into the specified rectangle. If width and + height are omitted, they are calculated from the image size. + Also allow file names as well as images. This allows a + caching mechanism""" + width = self.width + height = self.height + if width<1e-6 or height<1e-6: return False + x,y,self.width,self.height, scaled = aspectRatioFix(preserveAspectRatio,anchor,self.x,self.y,width,height,self.imgwidth,self.imgheight) + # this says where and how big to draw it + if not canvas.bottomup: y = y+height + canvas._code.append('q %s 0 0 %s cm' % (fp_str(self.width), fp_str(self.height, x, y))) + # self._code.extend(imagedata) if >=python-1.5.2 + for line in self.imageData: + canvas._code.append(line) + canvas._code.append('Q') + return True + + def format(self, document): + """Allow it to be used within pdfdoc framework. This only + defines how it is stored, not how it is drawn later.""" + + dict = pdfdoc.PDFDictionary() + dict['Type'] = '/XObject' + dict['Subtype'] = '/Image' + dict['Width'] = self.width + dict['Height'] = self.height + dict['BitsPerComponent'] = 8 + dict['ColorSpace'] = pdfdoc.PDFName(self.colorSpace) + content = '\n'.join(self.imageData[3:-1]) + '\n' + strm = pdfdoc.PDFStream(dictionary=dict, content=content) + return strm.format(document) + +if __name__=='__main__': + srcfile = os.path.join( + os.path.dirname(reportlab.__file__), + 'test', + 'pythonpowered.gif' + ) + assert os.path.isfile(srcfile), 'image not found' + pdfdoc.LongFormat = 1 + img = PDFImage(srcfile, 100, 100) + import pprint + doc = pdfdoc.PDFDocument() + print('source=',img.source) + print(img.format(doc)) diff --git a/reportlab/pdfgen/textobject.py b/reportlab/pdfgen/textobject.py new file mode 100644 index 00000000..ce6c2483 --- /dev/null +++ b/reportlab/pdfgen/textobject.py @@ -0,0 +1,465 @@ +#Copyright ReportLab Europe Ltd. 2000-2012 +#see license.txt for license details +#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/pdfgen/textobject.py +__version__=''' $Id$ ''' +__doc__=""" +PDFTextObject is an efficient way to add text to a Canvas. Do not +instantiate directly, obtain one from the Canvas instead. + +Progress Reports: +8.83, 2000-01-13, gmcm: created from pdfgen.py +""" +import string +from types import * +from reportlab.lib.colors import Color, CMYKColor, CMYKColorSep, toColor, black, white, _CMYK_black, _CMYK_white +from reportlab.lib.utils import isBytes, isStr, asUnicode +from reportlab.lib.rl_accel import fp_str +from reportlab.pdfbase import pdfmetrics +from reportlab.rl_config import rtlSupport + +log2vis = None +if rtlSupport: + try: + from pyfribidi2 import log2vis, ON as DIR_ON, LTR as DIR_LTR, RTL as DIR_RTL + directionsMap = dict(LTR=DIR_LTR,RTL=DIR_RTL) + except: + import warnings + warnings.warn('pyfribidi is not installed - RTL not supported') + +class _PDFColorSetter: + '''Abstracts the color setting operations; used in Canvas and Textobject + asseumes we have a _code object''' + def _checkSeparation(self,cmyk): + if isinstance(cmyk,CMYKColorSep): + name,sname = self._doc.addColor(cmyk) + if name not in self._colorsUsed: + self._colorsUsed[name] = sname + return name + + #if this is set to a callable(color) --> color it can be used to check color setting + #see eg _enforceCMYK/_enforceRGB + _enforceColorSpace = None + + def setFillColorCMYK(self, c, m, y, k, alpha=None): + """set the fill color useing negative color values + (cyan, magenta, yellow and darkness value). + Takes 4 arguments between 0.0 and 1.0""" + self.setFillColor((c,m,y,k),alpha=alpha) + + def setStrokeColorCMYK(self, c, m, y, k, alpha=None): + """set the stroke color useing negative color values + (cyan, magenta, yellow and darkness value). + Takes 4 arguments between 0.0 and 1.0""" + self.setStrokeColor((c,m,y,k),alpha=alpha) + + def setFillColorRGB(self, r, g, b, alpha=None): + """Set the fill color using positive color description + (Red,Green,Blue). Takes 3 arguments between 0.0 and 1.0""" + self.setFillColor((r,g,b),alpha=alpha) + + def setStrokeColorRGB(self, r, g, b, alpha=None): + """Set the stroke color using positive color description + (Red,Green,Blue). Takes 3 arguments between 0.0 and 1.0""" + self.setStrokeColor((r,g,b),alpha=alpha) + + def setFillColor(self, aColor, alpha=None): + """Takes a color object, allowing colors to be referred to by name""" + if self._enforceColorSpace: + aColor = self._enforceColorSpace(aColor) + if isinstance(aColor, CMYKColor): + d = aColor.density + c,m,y,k = (d*aColor.cyan, d*aColor.magenta, d*aColor.yellow, d*aColor.black) + self._fillColorObj = aColor + name = self._checkSeparation(aColor) + if name: + self._code.append('/%s cs %s scn' % (name,fp_str(d))) + else: + self._code.append('%s k' % fp_str(c, m, y, k)) + elif isinstance(aColor, Color): + rgb = (aColor.red, aColor.green, aColor.blue) + self._fillColorObj = aColor + self._code.append('%s rg' % fp_str(rgb) ) + elif isinstance(aColor,(tuple,list)): + l = len(aColor) + if l==3: + self._fillColorObj = aColor + self._code.append('%s rg' % fp_str(aColor) ) + elif l==4: + self._fillColorObj = aColor + self._code.append('%s k' % fp_str(aColor)) + else: + raise ValueError('Unknown color %r' % aColor) + elif isStr(aColor): + self.setFillColor(toColor(aColor)) + else: + raise ValueError('Unknown color %r' % aColor) + if alpha is not None: + self.setFillAlpha(alpha) + elif getattr(aColor, 'alpha', None) is not None: + self.setFillAlpha(aColor.alpha) + + def setStrokeColor(self, aColor, alpha=None): + """Takes a color object, allowing colors to be referred to by name""" + if self._enforceColorSpace: + aColor = self._enforceColorSpace(aColor) + if isinstance(aColor, CMYKColor): + d = aColor.density + c,m,y,k = (d*aColor.cyan, d*aColor.magenta, d*aColor.yellow, d*aColor.black) + self._strokeColorObj = aColor + name = self._checkSeparation(aColor) + if name: + self._code.append('/%s CS %s SCN' % (name,fp_str(d))) + else: + self._code.append('%s K' % fp_str(c, m, y, k)) + elif isinstance(aColor, Color): + rgb = (aColor.red, aColor.green, aColor.blue) + self._strokeColorObj = aColor + self._code.append('%s RG' % fp_str(rgb) ) + elif isinstance(aColor,(tuple,list)): + l = len(aColor) + if l==3: + self._strokeColorObj = aColor + self._code.append('%s RG' % fp_str(aColor) ) + elif l==4: + self._strokeColorObj = aColor + self._code.append('%s K' % fp_str(aColor)) + else: + raise ValueError('Unknown color %r' % aColor) + elif isStr(aColor): + self.setStrokeColor(toColor(aColor)) + else: + raise ValueError('Unknown color %r' % aColor) + if alpha is not None: + self.setStrokeAlpha(alpha) + elif getattr(aColor, 'alpha', None) is not None: + self.setStrokeAlpha(aColor.alpha) + + def setFillGray(self, gray, alpha=None): + """Sets the gray level; 0.0=black, 1.0=white""" + self._fillColorObj = (gray, gray, gray) + self._code.append('%s g' % fp_str(gray)) + if alpha is not None: + self.setFillAlpha(alpha) + + def setStrokeGray(self, gray, alpha=None): + """Sets the gray level; 0.0=black, 1.0=white""" + self._strokeColorObj = (gray, gray, gray) + self._code.append('%s G' % fp_str(gray)) + if alpha is not None: + self.setFillAlpha(alpha) + + def setStrokeAlpha(self,a): + if not (isinstance(a,(float,int)) and 0<=a<=1): + raise ValueError('setStrokeAlpha invalid value %r' % a) + getattr(self,'_setStrokeAlpha',lambda x: None)(a) + + def setFillAlpha(self,a): + if not (isinstance(a,(float,int)) and 0<=a<=1): + raise ValueError('setFillAlpha invalid value %r' % a) + getattr(self,'_setFillAlpha',lambda x: None)(a) + + def setStrokeOverprint(self,a): + getattr(self,'_setStrokeOverprint',lambda x: None)(a) + + def setFillOverprint(self,a): + getattr(self,'_setFillOverprint',lambda x: None)(a) + + def setOverprintMask(self,a): + getattr(self,'_setOverprintMask',lambda x: None)(a) + +class PDFTextObject(_PDFColorSetter): + """PDF logically separates text and graphics drawing; text + operations need to be bracketed between BT (Begin text) and + ET operators. This class ensures text operations are + properly encapusalted. Ask the canvas for a text object + with beginText(x, y). Do not construct one directly. + Do not use multiple text objects in parallel; PDF is + not multi-threaded! + + It keeps track of x and y coordinates relative to its origin.""" + + def __init__(self, canvas, x=0,y=0, direction=None): + self._code = ['BT'] #no point in [] then append RGB + self._canvas = canvas #canvas sets this so it has access to size info + self._fontname = self._canvas._fontname + self._fontsize = self._canvas._fontsize + self._leading = self._canvas._leading + self._doc = self._canvas._doc + self._colorsUsed = self._canvas._colorsUsed + self._enforceColorSpace = getattr(canvas,'_enforceColorSpace',None) + font = pdfmetrics.getFont(self._fontname) + self._curSubset = -1 + self.direction = direction + self.setTextOrigin(x, y) + self._textRenderMode = 0 + self._clipping = 0 + + def getCode(self): + "pack onto one line; used internally" + self._code.append('ET') + if self._clipping: + self._code.append('%d Tr' % (self._textRenderMode^4)) + return ' '.join(self._code) + + def setTextOrigin(self, x, y): + if self._canvas.bottomup: + self._code.append('1 0 0 1 %s Tm' % fp_str(x, y)) #bottom up + else: + self._code.append('1 0 0 -1 %s Tm' % fp_str(x, y)) #top down + + # The current cursor position is at the text origin + self._x0 = self._x = x + self._y0 = self._y = y + + def setTextTransform(self, a, b, c, d, e, f): + "Like setTextOrigin, but does rotation, scaling etc." + if not self._canvas.bottomup: + c = -c #reverse bottom row of the 2D Transform + d = -d + self._code.append('%s Tm' % fp_str(a, b, c, d, e, f)) + + # The current cursor position is at the text origin Note that + # we aren't keeping track of all the transform on these + # coordinates: they are relative to the rotations/sheers + # defined in the matrix. + self._x0 = self._x = e + self._y0 = self._y = f + + def moveCursor(self, dx, dy): + """Starts a new line at an offset dx,dy from the start of the + current line. This does not move the cursor relative to the + current position, and it changes the current offset of every + future line drawn (i.e. if you next do a textLine() call, it + will move the cursor to a position one line lower than the + position specificied in this call. """ + + # Check if we have a previous move cursor call, and combine + # them if possible. + if self._code and self._code[-1][-3:]==' Td': + L = self._code[-1].split() + if len(L)==3: + del self._code[-1] + else: + self._code[-1] = ''.join(L[:-4]) + + # Work out the last movement + lastDx = float(L[-3]) + lastDy = float(L[-2]) + + # Combine the two movement + dx += lastDx + dy -= lastDy + + # We will soon add the movement to the line origin, so if + # we've already done this for lastDx, lastDy, remove it + # first (so it will be right when added back again). + self._x0 -= lastDx + self._y0 -= lastDy + + # Output the move text cursor call. + self._code.append('%s Td' % fp_str(dx, -dy)) + + # Keep track of the new line offsets and the cursor position + self._x0 += dx + self._y0 += dy + self._x = self._x0 + self._y = self._y0 + + def setXPos(self, dx): + """Starts a new line dx away from the start of the + current line - NOT from the current point! So if + you call it in mid-sentence, watch out.""" + self.moveCursor(dx,0) + + def getCursor(self): + """Returns current text position relative to the last origin.""" + return (self._x, self._y) + + def getStartOfLine(self): + """Returns a tuple giving the text position of the start of the + current line.""" + return (self._x0, self._y0) + + def getX(self): + """Returns current x position relative to the last origin.""" + return self._x + + def getY(self): + """Returns current y position relative to the last origin.""" + return self._y + + def _setFont(self, psfontname, size): + """Sets the font and fontSize + Raises a readable exception if an illegal font + is supplied. Font names are case-sensitive! Keeps track + of font anme and size for metrics.""" + self._fontname = psfontname + self._fontsize = size + font = pdfmetrics.getFont(self._fontname) + + if font._dynamicFont: + self._curSubset = -1 + else: + pdffontname = self._canvas._doc.getInternalFontName(psfontname) + self._code.append('%s %s Tf' % (pdffontname, fp_str(size))) + + def setFont(self, psfontname, size, leading = None): + """Sets the font. If leading not specified, defaults to 1.2 x + font size. Raises a readable exception if an illegal font + is supplied. Font names are case-sensitive! Keeps track + of font anme and size for metrics.""" + self._fontname = psfontname + self._fontsize = size + if leading is None: + leading = size * 1.2 + self._leading = leading + font = pdfmetrics.getFont(self._fontname) + if font._dynamicFont: + self._curSubset = -1 + else: + pdffontname = self._canvas._doc.getInternalFontName(psfontname) + self._code.append('%s %s Tf %s TL' % (pdffontname, fp_str(size), fp_str(leading))) + + def setCharSpace(self, charSpace): + """Adjusts inter-character spacing""" + self._charSpace = charSpace + self._code.append('%s Tc' % fp_str(charSpace)) + + def setWordSpace(self, wordSpace): + """Adjust inter-word spacing. This can be used + to flush-justify text - you get the width of the + words, and add some space between them.""" + self._wordSpace = wordSpace + self._code.append('%s Tw' % fp_str(wordSpace)) + + def setHorizScale(self, horizScale): + "Stretches text out horizontally" + self._horizScale = 100 + horizScale + self._code.append('%s Tz' % fp_str(horizScale)) + + def setLeading(self, leading): + "How far to move down at the end of a line." + self._leading = leading + self._code.append('%s TL' % fp_str(leading)) + + def setTextRenderMode(self, mode): + """Set the text rendering mode. + + 0 = Fill text + 1 = Stroke text + 2 = Fill then stroke + 3 = Invisible + 4 = Fill text and add to clipping path + 5 = Stroke text and add to clipping path + 6 = Fill then stroke and add to clipping path + 7 = Add to clipping path + + after we start clipping we mustn't change the mode back until after the ET + """ + + assert mode in (0,1,2,3,4,5,6,7), "mode must be in (0,1,2,3,4,5,6,7)" + if (mode & 4)!=self._clipping: + mode |= 4 + self._clipping = mode & 4 + if self._textRenderMode!=mode: + self._textRenderMode = mode + self._code.append('%d Tr' % mode) + + def setRise(self, rise): + "Move text baseline up or down to allow superscript/subscripts" + self._rise = rise + self._y = self._y - rise # + ? _textLineMatrix? + self._code.append('%s Ts' % fp_str(rise)) + + def _formatText(self, text): + "Generates PDF text output operator(s)" + if log2vis and self.direction in ('LTR','RTL'): + # Use pyfribidi to write the text in the correct visual order. + text = log2vis(text, directionsMap.get(self.direction.upper(),DIR_ON)) + canv = self._canvas + font = pdfmetrics.getFont(self._fontname) + R = [] + if font._dynamicFont: + #it's a truetype font and should be utf8. If an error is raised, + for subset, t in font.splitString(text, canv._doc): + if subset!=self._curSubset: + pdffontname = font.getSubsetInternalName(subset, canv._doc) + R.append("%s %s Tf %s TL" % (pdffontname, fp_str(self._fontsize), fp_str(self._leading))) + self._curSubset = subset + R.append("(%s) Tj" % canv._escape(t)) + elif font._multiByte: + #all the fonts should really work like this - let them know more about PDF... + R.append("%s %s Tf %s TL" % ( + canv._doc.getInternalFontName(font.fontName), + fp_str(self._fontsize), + fp_str(self._leading) + )) + R.append("(%s) Tj" % font.formatForPdf(text)) + else: + #convert to T1 coding + fc = font + if isBytes(text): + try: + text = text.decode('utf8') + except UnicodeDecodeError as e: + i,j = e.args[2:4] + raise UnicodeDecodeError(*(e.args[:4]+('%s\n%s-->%s<--%s' % (e.args[4],text[max(i-10,0):i],text[i:j],text[j:j+10]),))) + + for f, t in pdfmetrics.unicode2T1(text,[font]+font.substitutionFonts): + if f!=fc: + R.append("%s %s Tf %s TL" % (canv._doc.getInternalFontName(f.fontName), fp_str(self._fontsize), fp_str(self._leading))) + fc = f + R.append("(%s) Tj" % canv._escape(t)) + if font!=fc: + R.append("%s %s Tf %s TL" % (canv._doc.getInternalFontName(self._fontname), fp_str(self._fontsize), fp_str(self._leading))) + return ' '.join(R) + + def _textOut(self, text, TStar=0): + "prints string at current point, ignores text cursor" + self._code.append('%s%s' % (self._formatText(text), (TStar and ' T*' or ''))) + + def textOut(self, text): + """prints string at current point, text cursor moves across.""" + self._x = self._x + self._canvas.stringWidth(text, self._fontname, self._fontsize) + self._code.append(self._formatText(text)) + + def textLine(self, text=''): + """prints string at current point, text cursor moves down. + Can work with no argument to simply move the cursor down.""" + # Update the coordinates of the cursor + self._x = self._x0 + if self._canvas.bottomup: + self._y = self._y - self._leading + else: + self._y = self._y + self._leading + + # Update the location of the start of the line + # self._x0 is unchanged + self._y0 = self._y + + # Output the text followed by a PDF newline command + self._code.append('%s T*' % self._formatText(text)) + + def textLines(self, stuff, trim=1): + """prints multi-line or newlined strings, moving down. One + comon use is to quote a multi-line block in your Python code; + since this may be indented, by default it trims whitespace + off each line and from the beginning; set trim=0 to preserve + whitespace.""" + if isStr(stuff): + lines = asUnicode(stuff).strip().split(u'\n') + if trim==1: + lines = [s.strip() for s in lines] + elif isinstance(stuff,(tuple,list)): + lines = stuff + else: + assert 1==0, "argument to textlines must be string,, list or tuple" + + # Output each line one at a time. This used to be a long-hand + # copy of the textLine code, now called as a method. + for line in lines: + self.textLine(line) + + def __nonzero__(self): + 'PDFTextObject is true if it has something done after the init' + return self._code != ['BT'] diff --git a/reportlab/platypus/__init__.py b/reportlab/platypus/__init__.py new file mode 100644 index 00000000..ec6071aa --- /dev/null +++ b/reportlab/platypus/__init__.py @@ -0,0 +1,17 @@ +#Copyright ReportLab Europe Ltd. 2000-2012 +#see license.txt for license details +#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/platypus/__init__.py +__version__=''' $Id$ ''' +__doc__='''Page Layout and Typography Using Scripts" - higher-level framework for flowing documents''' + +from reportlab.platypus.flowables import Flowable, Image, Macro, PageBreak, Preformatted, Spacer, XBox, \ + CondPageBreak, KeepTogether, TraceInfo, FailOnWrap, FailOnDraw, PTOContainer, \ + KeepInFrame, ParagraphAndImage, ImageAndFlowables, ListFlowable, ListItem, FrameBG, \ + PageBreakIfNotEmpty +from reportlab.platypus.paragraph import Paragraph, cleanBlockQuotedText, ParaLines +from reportlab.platypus.paraparser import ParaFrag +from reportlab.platypus.tables import Table, TableStyle, CellStyle, LongTable +from reportlab.platypus.frames import Frame +from reportlab.platypus.doctemplate import BaseDocTemplate, NextPageTemplate, PageTemplate, ActionFlowable, \ + SimpleDocTemplate, FrameBreak, PageBegin, Indenter, NotAtTopPageBreak +from reportlab.platypus.xpreformatted import XPreformatted diff --git a/reportlab/platypus/doctemplate.py b/reportlab/platypus/doctemplate.py new file mode 100644 index 00000000..d9f32405 --- /dev/null +++ b/reportlab/platypus/doctemplate.py @@ -0,0 +1,1250 @@ +#Copyright ReportLab Europe Ltd. 2000-2012 +#see license.txt for license details +#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/platypus/doctemplate.py + +__version__=''' $Id$ ''' + +__doc__=""" +This module contains the core structure of platypus. + +rlatypus constructs documents. Document styles are determined by DocumentTemplates. + +Each DocumentTemplate contains one or more PageTemplates which defines the look of the +pages of the document. + +Each PageTemplate has a procedure for drawing the "non-flowing" part of the page +(for example the header, footer, page number, fixed logo graphic, watermark, etcetera) and +a set of Frames which enclose the flowing part of the page (for example the paragraphs, +tables, or non-fixed diagrams of the text). + +A document is built when a DocumentTemplate is fed a sequence of Flowables. +The action of the build consumes the flowables in order and places them onto +frames on pages as space allows. When a frame runs out of space the next frame +of the page is used. If no frame remains a new page is created. A new page +can also be created if a page break is forced. + +The special invisible flowable NextPageTemplate can be used to specify +the page template for the next page (which by default is the one being used +for the current frame). +""" + +from reportlab.platypus.flowables import * +from reportlab.lib.units import inch +from reportlab.platypus.paragraph import Paragraph +from reportlab.platypus.frames import Frame +from reportlab.rl_config import defaultPageSize, verbose +import reportlab.lib.sequencer +from reportlab.pdfgen import canvas +from reportlab.lib.utils import isSeq, encode_label, decode_label, annotateException, strTypes +try: + set +except NameError: + from sets import Set as set + +import sys +import logging +logger = logging.getLogger("reportlab.platypus") + +class LayoutError(Exception): + pass + +def _fSizeString(f): + #used to get size during error messages + w=getattr(f,'width',None) + if w is None: + w=getattr(f,'_width',None) + + h=getattr(f,'height',None) + if h is None: + h=getattr(f,'_height',None) + #tables in particular may have some nasty large culprit + if hasattr(f, '_culprit'): + c = ', %s, ' % f._culprit() + else: + c = '' + if w is not None or h is not None: + if w is None: w='???' + if h is None: h='???' + return '(%s x %s)%s' % (w,h,c) + return '' + +def _doNothing(canvas, doc): + "Dummy callback for onPage" + pass + +class PTCycle(list): + def __new__(cls,*args,**kwds): + self = list.__new__(cls,*args,**kwds) + self._restart = 0 + self._idx = 0 + return self + + @property + def next_value(self): + v = self[self._idx] + self._idx += 1 + if self._idx>=len(self): + self._idx = self._restart + return v + + @property + def peek(self): + return self[self._idx] + +class IndexingFlowable(Flowable): + """Abstract interface definition for flowables which might + hold references to other pages or themselves be targets + of cross-references. XRefStart, XRefDest, Table of Contents, + Indexes etc.""" + def isIndexing(self): + return 1 + + def isSatisfied(self): + return 1 + + def notify(self, kind, stuff): + """This will be called by the framework wherever 'stuff' happens. + 'kind' will be a value that can be used to decide whether to + pay attention or not.""" + pass + + def beforeBuild(self): + """Called by multiBuild before it starts; use this to clear + old contents""" + pass + + def afterBuild(self): + """Called after build ends but before isSatisfied""" + pass + +class ActionFlowable(Flowable): + '''This Flowable is never drawn, it can be used for data driven controls + For example to change a page template (from one column to two, for example) + use NextPageTemplate which creates an ActionFlowable. + ''' + def __init__(self,action=()): + #must call super init to ensure it has a width and height (of zero), + #as in some cases the packer might get called on it... + Flowable.__init__(self) + if not isSeq(action): + action = (action,) + self.action = tuple(action) + + def apply(self,doc): + ''' + This is called by the doc.build processing to allow the instance to + implement its behaviour + ''' + action = self.action[0] + args = tuple(self.action[1:]) + arn = 'handle_'+action + if arn=="handle_nextPageTemplate" and args[0]=='main': + pass + try: + getattr(doc,arn)(*args) + except AttributeError as aerr: + if aerr.args[0]==arn: + raise NotImplementedError("Can't handle ActionFlowable(%s)" % action) + else: + raise + except: + annotateException("\nhandle_%s args=%s"%(action,ascii(args))) + + def __call__(self): + return self + + def identity(self, maxLen=None): + return "ActionFlowable: %s%s" % (str(self.action),self._frameName()) + +class LCActionFlowable(ActionFlowable): + locChanger = 1 #we cause a frame or page change + + def wrap(self, availWidth, availHeight): + '''Should never be called.''' + raise NotImplementedError + + def draw(self): + '''Should never be called.''' + raise NotImplementedError + +class NextFrameFlowable(ActionFlowable): + def __init__(self,ix,resume=0): + ActionFlowable.__init__(self,('nextFrame',ix,resume)) + +class CurrentFrameFlowable(LCActionFlowable): + def __init__(self,ix,resume=0): + ActionFlowable.__init__(self,('currentFrame',ix,resume)) + +class NullActionFlowable(ActionFlowable): + def apply(self,doc): + pass + +class _FrameBreak(LCActionFlowable): + ''' + A special ActionFlowable that allows setting doc._nextFrameIndex + + eg story.append(FrameBreak('mySpecialFrame')) + ''' + def __call__(self,ix=None,resume=0): + r = self.__class__(self.action+(resume,)) + r._ix = ix + return r + + def apply(self,doc): + if getattr(self,'_ix',None): + doc.handle_nextFrame(self._ix) + ActionFlowable.apply(self,doc) + +FrameBreak = _FrameBreak('frameEnd') +PageBegin = LCActionFlowable('pageBegin') + +def _evalMeasurement(n): + if isinstance(n,str): + from reportlab.platypus.paraparser import _num + n = _num(n) + if isSeq(n): n = n[1] + return n + +class FrameActionFlowable(Flowable): + _fixedWidth = _fixedHeight = 1 + def __init__(self,*arg,**kw): + raise NotImplementedError('Abstract Class') + + def frameAction(self,frame): + raise NotImplementedError('Abstract Class') + +class Indenter(FrameActionFlowable): + """Increases or decreases left and right margins of frame. + + This allows one to have a 'context-sensitive' indentation + and makes nested lists way easier. + """ + _ZEROSIZE=True + width=0 + height=0 + def __init__(self, left=0, right=0): + self.left = _evalMeasurement(left) + self.right = _evalMeasurement(right) + + def frameAction(self, frame): + frame._leftExtraIndent += self.left + frame._rightExtraIndent += self.right + +class NotAtTopPageBreak(FrameActionFlowable): + def __init__(self,nextTemplate=None): + self.nextTemplate = nextTemplate + + def frameAction(self,frame): + if not frame._atTop: + frame.add_generated_content(PageBreak(nextTemplate=self.nextTemplate)) + +class NextPageTemplate(ActionFlowable): + """When you get to the next page, use the template specified (change to two column, for example) """ + def __init__(self,pt): + ActionFlowable.__init__(self,('nextPageTemplate',pt)) + +class PageTemplate: + """ + essentially a list of Frames and an onPage routine to call at the start + of a page when this is selected. onPageEnd gets called at the end. + derived classes can also implement beforeDrawPage and afterDrawPage if they want + """ + def __init__(self,id=None,frames=[],onPage=_doNothing, onPageEnd=_doNothing, + pagesize=None, autoNextPageTemplate=None): + frames = frames or [] + if not isSeq(frames): frames = [frames] + assert [x for x in frames if not isinstance(x,Frame)]==[], "frames argument error" + self.id = id + self.frames = frames + self.onPage = onPage + self.onPageEnd = onPageEnd + self.pagesize = pagesize + self.autoNextPageTemplate = autoNextPageTemplate + + def beforeDrawPage(self,canv,doc): + """Override this if you want additional functionality or prefer + a class based page routine. Called before any flowables for + this page are processed.""" + pass + + def checkPageSize(self,canv,doc): + """This gets called by the template framework + If canv size != template size then the canv size is set to + the template size or if that's not available to the + doc size. + """ + #### NEVER EVER EVER COMPARE FLOATS FOR EQUALITY + #RGB converting pagesizes to ints means we are accurate to one point + #RGB I suggest we should be aiming a little better + cp = None + dp = None + sp = None + if canv._pagesize: cp = list(map(int, canv._pagesize)) + if self.pagesize: sp = list(map(int, self.pagesize)) + if doc.pagesize: dp = list(map(int, doc.pagesize)) + if cp!=sp: + if sp: + canv.setPageSize(self.pagesize) + elif cp!=dp: + canv.setPageSize(doc.pagesize) + + def afterDrawPage(self, canv, doc): + """This is called after the last flowable for the page has + been processed. You might use this if the page header or + footer needed knowledge of what flowables were drawn on + this page.""" + pass + +def _addGeneratedContent(flowables,frame): + S = getattr(frame,'_generated_content',None) + if S: + flowables[0:0] = S + del frame._generated_content + + +class onDrawStr(str): + def __new__(cls,value,onDraw,label,kind=None): + self = str.__new__(cls,value) + self.onDraw = onDraw + self.kind = kind + self.label = label + return self + +class PageAccumulator: + '''gadget to accumulate information in a page + and then allow it to be interrogated at the end + of the page''' + _count = 0 + def __init__(self,name=None): + if name is None: + name = self.__class__.__name__+str(self.__class__._count) + self.__class__._count += 1 + self.name = name + self.data = [] + + def reset(self): + self.data[:] = [] + + def add(self,*args): + self.data.append(args) + + def onDrawText(self,*args): + return '' % (self.name,encode_label(args)) + + def __call__(self,canv,kind,label): + self.add(*decode_label(label)) + + def attachToPageTemplate(self,pt): + if pt.onPage: + def onPage(canv,doc,oop=pt.onPage): + self.onPage(canv,doc) + oop(canv,doc) + else: + def onPage(canv,doc): + self.onPage(canv,doc) + pt.onPage = onPage + if pt.onPageEnd: + def onPageEnd(canv,doc,oop=pt.onPageEnd): + self.onPageEnd(canv,doc) + oop(canv,doc) + else: + def onPageEnd(canv,doc): + self.onPageEnd(canv,doc) + pt.onPageEnd = onPageEnd + + def onPage(self,canv,doc): + '''this will be called at the start of the page''' + setattr(canv,self.name,self) #push ourselves onto the canvas + self.reset() + + def onPageEnd(self,canv,doc): + '''this will be called at the end of a page''' + self.pageEndAction(canv,doc) + try: + delattr(canv,self.name) + except: + pass + self.reset() + + def pageEndAction(self,canv,doc): + '''this should be overridden to do something useful''' + pass + + def onDrawStr(self,value,*args): + return onDrawStr(value,self,encode_label(args)) + +class BaseDocTemplate: + """ + First attempt at defining a document template class. + + The basic idea is simple. + + 1) The document has a list of data associated with it + this data should derive from flowables. We'll have + special classes like PageBreak, FrameBreak to do things + like forcing a page end etc. + + 2) The document has one or more page templates. + + 3) Each page template has one or more frames. + + 4) The document class provides base methods for handling the + story events and some reasonable methods for getting the + story flowables into the frames. + + 5) The document instances can override the base handler routines. + + Most of the methods for this class are not called directly by the user, + but in some advanced usages they may need to be overridden via subclassing. + + EXCEPTION: doctemplate.build(...) must be called for most reasonable uses + since it builds a document using the page template. + + Each document template builds exactly one document into a file specified + by the filename argument on initialization. + + Possible keyword arguments for the initialization: + + - pageTemplates: A list of templates. Must be nonempty. Names + assigned to the templates are used for referring to them so no two used + templates should have the same name. For example you might want one template + for a title page, one for a section first page, one for a first page of + a chapter and two more for the interior of a chapter on odd and even pages. + If this argument is omitted then at least one pageTemplate should be provided + using the addPageTemplates method before the document is built. + - pageSize: a 2-tuple or a size constant from reportlab/lib/pagesizes.pu. + Used by the SimpleDocTemplate subclass which does NOT accept a list of + pageTemplates but makes one for you; ignored when using pageTemplates. + + - showBoundary: if set draw a box around the frame boundaries. + - leftMargin: + - rightMargin: + - topMargin: + - bottomMargin: Margin sizes in points (default 1 inch). These margins may be + overridden by the pageTemplates. They are primarily of interest for the + SimpleDocumentTemplate subclass. + + - allowSplitting: If set flowables (eg, paragraphs) may be split across frames or pages + (default: 1) + - title: Internal title for document (does not automatically display on any page) + - author: Internal author for document (does not automatically display on any page) + """ + _initArgs = { 'pagesize':defaultPageSize, + 'pageTemplates':[], + 'showBoundary':0, + 'leftMargin':inch, + 'rightMargin':inch, + 'topMargin':inch, + 'bottomMargin':inch, + 'allowSplitting':1, + 'title':None, + 'author':None, + 'subject':None, + 'creator':None, + 'keywords':[], + 'invariant':None, + 'pageCompression':None, + '_pageBreakQuick':1, + 'rotation':0, + '_debug':0, + 'encrypt': None, + 'cropMarks': None, + 'enforceColorSpace': None, + } + _invalidInitArgs = () + _firstPageTemplateIndex = 0 + + def __init__(self, filename, **kw): + """create a document template bound to a filename (see class documentation for keyword arguments)""" + self.filename = filename + self._nameSpace = dict(doc=self) + self._lifetimes = {} + + for k in self._initArgs.keys(): + if k not in kw: + v = self._initArgs[k] + else: + if k in self._invalidInitArgs: + raise ValueError("Invalid argument %s" % k) + v = kw[k] + setattr(self,k,v) + + p = self.pageTemplates + self.pageTemplates = [] + self.addPageTemplates(p) + + # facility to assist multi-build and cross-referencing. + # various hooks can put things into here - key is what + # you want, value is a page number. This can then be + # passed to indexing flowables. + self._pageRefs = {} + self._indexingFlowables = [] + + #callback facility for progress monitoring + self._onPage = None + self._onProgress = None + self._flowableCount = 0 # so we know how far to go + + #infinite loop detection if we start doing lots of empty pages + self._curPageFlowableCount = 0 + self._emptyPages = 0 + self._emptyPagesAllowed = 10 + + #context sensitive margins - set by story, not from outside + self._leftExtraIndent = 0.0 + self._rightExtraIndent = 0.0 + self._frameBGs = [] + + self._calc() + self.afterInit() + + def _calc(self): + self._rightMargin = self.pagesize[0] - self.rightMargin + self._topMargin = self.pagesize[1] - self.topMargin + self.width = self._rightMargin - self.leftMargin + self.height = self._topMargin - self.bottomMargin + + def setPageCallBack(self, func): + 'Simple progress monitor - func(pageNo) called on each new page' + self._onPage = func + + def setProgressCallBack(self, func): + '''Cleverer progress monitor - func(typ, value) called regularly''' + self._onProgress = func + + def clean_hanging(self): + 'handle internal postponed actions' + while len(self._hanging): + self.handle_flowable(self._hanging) + + def addPageTemplates(self,pageTemplates): + 'add one or a sequence of pageTemplates' + if not isSeq(pageTemplates): + pageTemplates = [pageTemplates] + #this test below fails due to inconsistent imports! + #assert filter(lambda x: not isinstance(x,PageTemplate), pageTemplates)==[], "pageTemplates argument error" + for t in pageTemplates: + self.pageTemplates.append(t) + + def handle_documentBegin(self): + '''implement actions at beginning of document''' + self._hanging = [PageBegin] + self.pageTemplate = self.pageTemplates[self._firstPageTemplateIndex] + self.page = 0 + self.beforeDocument() + + def handle_pageBegin(self): + """Perform actions required at beginning of page. + shouldn't normally be called directly""" + self.page += 1 + if self._debug: logger.debug("beginning page %d" % self.page) + self.pageTemplate.beforeDrawPage(self.canv,self) + self.pageTemplate.checkPageSize(self.canv,self) + self.pageTemplate.onPage(self.canv,self) + for f in self.pageTemplate.frames: f._reset() + self.beforePage() + #keep a count of flowables added to this page. zero indicates bad stuff + self._curPageFlowableCount = 0 + if hasattr(self,'_nextFrameIndex'): + del self._nextFrameIndex + self.frame = self.pageTemplate.frames[0] + self.frame._debug = self._debug + self.handle_frameBegin() + + def _setPageTemplate(self): + if hasattr(self,'_nextPageTemplateCycle'): + #they are cycling through pages'; we keep the index + self.pageTemplate = self._nextPageTemplateCycle.next_value + elif hasattr(self,'_nextPageTemplateIndex'): + self.pageTemplate = self.pageTemplates[self._nextPageTemplateIndex] + del self._nextPageTemplateIndex + elif self.pageTemplate.autoNextPageTemplate: + self.handle_nextPageTemplate(self.pageTemplate.autoNextPageTemplate) + self.pageTemplate = self.pageTemplates[self._nextPageTemplateIndex] + + def _samePT(self,npt): + if isSeq(npt): + return getattr(self,'_nextPageTemplateCycle',[]) + if isinstance(npt,strTypes): + return npt == (self.pageTemplates[self._nextPageTemplateIndex].id if hasattr(self,'_nextPageTemplateIndex') else self.pageTemplate.id) + if isinstance(npt,int) and 0<=npt= self._emptyPagesAllowed: + if 1: + ident = "More than %d pages generated without content - halting layout. Likely that a flowable is too large for any frame." % self._emptyPagesAllowed + #leave to keep apart from the raise + raise LayoutError(ident) + else: + pass #attempt to restore to good state + else: + if self._onProgress: + self._onProgress('PAGE', self.canv.getPageNumber()) + self.pageTemplate.afterDrawPage(self.canv, self) + self.pageTemplate.onPageEnd(self.canv, self) + self.afterPage() + if self._debug: logger.debug("ending page %d" % self.page) + self.canv.setPageRotation(getattr(self.pageTemplate,'rotation',self.rotation)) + self.canv.showPage() + self._setPageTemplate() + if self._emptyPages==0: + pass #store good state here + self._hanging.append(PageBegin) + + def handle_pageBreak(self,slow=None): + '''some might choose not to end all the frames''' + if self._pageBreakQuick and not slow: + self.handle_pageEnd() + else: + n = len(self._hanging) + while len(self._hanging)==n: + self.handle_frameEnd() + + def handle_frameBegin(self,resume=0): + '''What to do at the beginning of a frame''' + f = self.frame + if f._atTop: + if self.showBoundary or self.frame.showBoundary: + self.frame.drawBoundary(self.canv) + f._leftExtraIndent = self._leftExtraIndent + f._rightExtraIndent = self._rightExtraIndent + f._frameBGs = self._frameBGs + + def handle_frameEnd(self,resume=0): + ''' Handles the semantics of the end of a frame. This includes the selection of + the next frame or if this is the last frame then invoke pageEnd. + ''' + self._removeVars(('frame',)) + self._leftExtraIndent = self.frame._leftExtraIndent + self._rightExtraIndent = self.frame._rightExtraIndent + self._frameBGs = self.frame._frameBGs + + f = self.frame + if hasattr(self,'_nextFrameIndex'): + self.frame = self.pageTemplate.frames[self._nextFrameIndex] + self.frame._debug = self._debug + del self._nextFrameIndex + self.handle_frameBegin(resume) + elif hasattr(f,'lastFrame') or f is self.pageTemplate.frames[-1]: + self.handle_pageEnd() + self.frame = None + else: + self.frame = self.pageTemplate.frames[self.pageTemplate.frames.index(f) + 1] + self.frame._debug = self._debug + self.handle_frameBegin() + + def handle_nextPageTemplate(self,pt): + '''On endPage change to the page template with name or index pt''' + if isinstance(pt,strTypes): + if hasattr(self, '_nextPageTemplateCycle'): del self._nextPageTemplateCycle + for t in self.pageTemplates: + if t.id == pt: + self._nextPageTemplateIndex = self.pageTemplates.index(t) + return + raise ValueError("can't find template('%s')"%pt) + elif isinstance(pt,int): + if hasattr(self, '_nextPageTemplateCycle'): del self._nextPageTemplateCycle + self._nextPageTemplateIndex = pt + elif isSeq(pt): + #used for alternating left/right pages + #collect the refs to the template objects, complain if any are bad + c = PTCycle() + for ptn in pt: + found = 0 + if ptn=='*': #special case name used to short circuit the iteration + c._restart = len(c) + continue + for t in self.pageTemplates: + if t.id == ptn: + c.append(t) + found = 1 + if not found: + raise ValueError("Cannot find page template called %s" % ptn) + if not c: + raise ValueError("No valid page templates in cycle") + elif c._restart>len(c): + raise ValueError("Invalid cycle restart position") + + #ensure we start on the first one + self._nextPageTemplateCycle = c + else: + raise TypeError("argument pt should be string or integer or list") + + def handle_nextFrame(self,fx,resume=0): + '''On endFrame change to the frame with name or index fx''' + if isinstance(fx,strTypes): + for f in self.pageTemplate.frames: + if f.id == fx: + self._nextFrameIndex = self.pageTemplate.frames.index(f) + return + raise ValueError("can't find frame('%s') in %r(%s) which has frames %r"%(fx,self.pageTemplate,self.pageTemplate.id,[(f,f.id) for f in self.pageTemplate.frames])) + elif isinstance(fx,int): + self._nextFrameIndex = fx + else: + raise TypeError("argument fx should be string or integer") + + def handle_currentFrame(self,fx,resume=0): + '''change to the frame with name or index fx''' + self.handle_nextFrame(fx,resume) + self.handle_frameEnd(resume) + + def handle_breakBefore(self, flowables): + '''preprocessing step to allow pageBreakBefore and frameBreakBefore attributes''' + first = flowables[0] + # if we insert a page break before, we'll process that, see it again, + # and go in an infinite loop. So we need to set a flag on the object + # saying 'skip me'. This should be unset on the next pass + if hasattr(first, '_skipMeNextTime'): + delattr(first, '_skipMeNextTime') + return + # this could all be made much quicker by putting the attributes + # in to the flowables with a defult value of 0 + if hasattr(first,'pageBreakBefore') and first.pageBreakBefore == 1: + first._skipMeNextTime = 1 + first.insert(0, PageBreak()) + return + if hasattr(first,'style') and hasattr(first.style, 'pageBreakBefore') and first.style.pageBreakBefore == 1: + first._skipMeNextTime = 1 + flowables.insert(0, PageBreak()) + return + if hasattr(first,'frameBreakBefore') and first.frameBreakBefore == 1: + first._skipMeNextTime = 1 + flowables.insert(0, FrameBreak()) + return + if hasattr(first,'style') and hasattr(first.style, 'frameBreakBefore') and first.style.frameBreakBefore == 1: + first._skipMeNextTime = 1 + flowables.insert(0, FrameBreak()) + return + + def handle_keepWithNext(self, flowables): + "implements keepWithNext" + i = 0 + n = len(flowables) + while i maxPasses: + raise IndexError("Index entries not resolved after %d passes" % maxPasses) + + #work through any edits + while mbe: + e = mbe.pop(0) + e[0](*e[1:]) + + del self._multiBuildEdits + if verbose: print('saved') + return passes + + #these are pure virtuals override in derived classes + #NB these get called at suitable places by the base class + #so if you derive and override the handle_xxx methods + #it's up to you to ensure that they maintain the needed consistency + def afterInit(self): + """This is called after initialisation of the base class.""" + pass + + def beforeDocument(self): + """This is called before any processing is + done on the document.""" + pass + + def beforePage(self): + """This is called at the beginning of page + processing, and immediately before the + beforeDrawPage method of the current page + template.""" + pass + + def afterPage(self): + """This is called after page processing, and + immediately after the afterDrawPage method + of the current page template.""" + pass + + def filterFlowables(self,flowables): + '''called to filter flowables at the start of the main handle_flowable method. + Upon return if flowables[0] has been set to None it is discarded and the main + method returns. + ''' + pass + + def afterFlowable(self, flowable): + '''called after a flowable has been rendered''' + pass + + _allowedLifetimes = 'page','frame','build','forever' + def docAssign(self,var,expr,lifetime): + if not isinstance(expr,strTypes): expr=str(expr) + expr=expr.strip() + var=var.strip() + self.docExec('%s=(%s)'%(var.strip(),expr.strip()),lifetime) + + def docExec(self,stmt,lifetime): + stmt=stmt.strip() + NS=self._nameSpace + K0=list(NS.keys()) + try: + if lifetime not in self._allowedLifetimes: + raise ValueError('bad lifetime %r not in %r'%(lifetime,self._allowedLifetimes)) + exec(stmt, {},NS) + except: + exc = sys.exc_info()[1] + args = list(exc.args) + msg = '\ndocExec %s lifetime=%r failed!' % (stmt,lifetime) + args.append(msg) + exc.args = tuple(args) + for k in NS.keys(): + if k not in K0: + del NS[k] + raise + self._addVars([k for k in NS.keys() if k not in K0],lifetime) + + def _addVars(self,vars,lifetime): + '''add namespace variables to lifetimes lists''' + LT=self._lifetimes + for var in vars: + for v in LT.values(): + if var in v: + v.remove(var) + LT.setdefault(lifetime,set([])).add(var) + + def _removeVars(self,lifetimes): + '''remove namespace variables for with lifetime in lifetimes''' + LT=self._lifetimes + NS=self._nameSpace + for lifetime in lifetimes: + for k in LT.setdefault(lifetime,[]): + try: + del NS[k] + except KeyError: + pass + del LT[lifetime] + + def docEval(self,expr): + try: + return eval(expr.strip(),{},self._nameSpace) + except: + exc = sys.exc_info()[1] + args = list(exc.args) + args[-1] += '\ndocEval %s failed!' % expr + exc.args = tuple(args) + raise + +class SimpleDocTemplate(BaseDocTemplate): + """A special case document template that will handle many simple documents. + See documentation for BaseDocTemplate. No pageTemplates are required + for this special case. A page templates are inferred from the + margin information and the onFirstPage, onLaterPages arguments to the build method. + + A document which has all pages with the same look except for the first + page may can be built using this special approach. + """ + _invalidInitArgs = ('pageTemplates',) + + def handle_pageBegin(self): + '''override base method to add a change of page template after the firstpage. + ''' + self._handle_pageBegin() + self._handle_nextPageTemplate('Later') + + def build(self,flowables,onFirstPage=_doNothing, onLaterPages=_doNothing, canvasmaker=canvas.Canvas): + """build the document using the flowables. Annotate the first page using the onFirstPage + function and later pages using the onLaterPages function. The onXXX pages should follow + the signature + + def myOnFirstPage(canvas, document): + # do annotations and modify the document + ... + + The functions can do things like draw logos, page numbers, + footers, etcetera. They can use external variables to vary + the look (for example providing page numbering or section names). + """ + self._calc() #in case we changed margins sizes etc + frameT = Frame(self.leftMargin, self.bottomMargin, self.width, self.height, id='normal') + self.addPageTemplates([PageTemplate(id='First',frames=frameT, onPage=onFirstPage,pagesize=self.pagesize), + PageTemplate(id='Later',frames=frameT, onPage=onLaterPages,pagesize=self.pagesize)]) + if onFirstPage is _doNothing and hasattr(self,'onFirstPage'): + self.pageTemplates[0].beforeDrawPage = self.onFirstPage + if onLaterPages is _doNothing and hasattr(self,'onLaterPages'): + self.pageTemplates[1].beforeDrawPage = self.onLaterPages + BaseDocTemplate.build(self,flowables, canvasmaker=canvasmaker) + +def progressCB(typ, value): + """Example prototype for progress monitoring. + + This aims to provide info about what is going on + during a big job. It should enable, for example, a reasonably + smooth progress bar to be drawn. We design the argument + signature to be predictable and conducive to programming in + other (type safe) languages. If set, this will be called + repeatedly with pairs of values. The first is a string + indicating the type of call; the second is a numeric value. + + typ 'STARTING', value = 0 + typ 'SIZE_EST', value = numeric estimate of job size + typ 'PASS', value = number of this rendering pass + typ 'PROGRESS', value = number between 0 and SIZE_EST + typ 'PAGE', value = page number of page + type 'FINISHED', value = 0 + + The sequence is + STARTING - always called once + SIZE_EST - always called once + PROGRESS - called often + PAGE - called often when page is emitted + FINISHED - called when really, really finished + + some juggling is needed to accurately estimate numbers of + pages in pageDrawing mode. + + NOTE: the SIZE_EST is a guess. It is possible that the + PROGRESS value may slightly exceed it, or may even step + back a little on rare occasions. The only way to be + really accurate would be to do two passes, and I don't + want to take that performance hit. + """ + print('PROGRESS MONITOR: %-10s %d' % (typ, value)) + +if __name__ == '__main__': + from reportlab.lib.styles import _baseFontName, _baseFontNameB + def myFirstPage(canvas, doc): + from reportlab.lib.colors import red + PAGE_HEIGHT = canvas._pagesize[1] + canvas.saveState() + canvas.setStrokeColor(red) + canvas.setLineWidth(5) + canvas.line(66,72,66,PAGE_HEIGHT-72) + canvas.setFont(_baseFontNameB,24) + canvas.drawString(108, PAGE_HEIGHT-108, "TABLE OF CONTENTS DEMO") + canvas.setFont(_baseFontName,12) + canvas.drawString(4 * inch, 0.75 * inch, "First Page") + canvas.restoreState() + + def myLaterPages(canvas, doc): + from reportlab.lib.colors import red + PAGE_HEIGHT = canvas._pagesize[1] + canvas.saveState() + canvas.setStrokeColor(red) + canvas.setLineWidth(5) + canvas.line(66,72,66,PAGE_HEIGHT-72) + canvas.setFont(_baseFontName,12) + canvas.drawString(4 * inch, 0.75 * inch, "Page %d" % doc.page) + canvas.restoreState() + + def run(): + objects_to_draw = [] + from reportlab.lib.styles import ParagraphStyle + #from paragraph import Paragraph + from reportlab.platypus.doctemplate import SimpleDocTemplate + + #need a style + normal = ParagraphStyle('normal') + normal.firstLineIndent = 18 + normal.spaceBefore = 6 + from reportlab.lib.randomtext import randomText + import random + for i in range(15): + height = 0.5 + (2*random.random()) + box = XBox(6 * inch, height * inch, 'Box Number %d' % i) + objects_to_draw.append(box) + para = Paragraph(randomText(), normal) + objects_to_draw.append(para) + + SimpleDocTemplate('doctemplate.pdf').build(objects_to_draw, + onFirstPage=myFirstPage,onLaterPages=myLaterPages) + + run() diff --git a/reportlab/platypus/figures.py b/reportlab/platypus/figures.py new file mode 100644 index 00000000..33aaad62 --- /dev/null +++ b/reportlab/platypus/figures.py @@ -0,0 +1,433 @@ +#Copyright ReportLab Europe Ltd. 2000-2012 +#see license.txt for license details +#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/platypus/figures.py +"""This includes some demos of platypus for use in the API proposal""" +__version__=''' $Id$ ''' + +import os + +from reportlab.lib import colors +from reportlab.pdfgen.canvas import Canvas +from reportlab.lib.styles import ParagraphStyle +from reportlab.lib.utils import recursiveImport, strTypes +from reportlab.platypus import Frame +from reportlab.platypus import Flowable +from reportlab.platypus import Paragraph +from reportlab.lib.units import inch +from reportlab.lib.enums import TA_LEFT, TA_RIGHT, TA_CENTER +from reportlab.lib.validators import isColor +from reportlab.lib.colors import toColor +from reportlab.lib.styles import _baseFontName, _baseFontNameI + +captionStyle = ParagraphStyle('Caption', fontName=_baseFontNameI, fontSize=10, alignment=TA_CENTER) + +class Figure(Flowable): + def __init__(self, width, height, caption="", + captionFont=_baseFontNameI, captionSize=12, + background=None, + captionTextColor=toColor('black'), + captionBackColor=None, + border=None, + spaceBefore=12, + spaceAfter=12, + captionGap=None, + captionAlign='centre', + captionPosition='bottom', + hAlign='CENTER', + ): + Flowable.__init__(self) + self.width = width + self.figureHeight = height + self.caption = caption + self.captionFont = captionFont + self.captionSize = captionSize + self.captionTextColor = captionTextColor + self.captionBackColor = captionBackColor + self.captionGap = captionGap or 0.5*captionSize + self.captionAlign = captionAlign + self.captionPosition = captionPosition + self._captionData = None + self.captionHeight = 0 # work out later + self.background = background + self.border = border + self.spaceBefore = spaceBefore + self.spaceAfter = spaceAfter + self.hAlign=hAlign + self._getCaptionPara() #Larry Meyn's fix - otherwise they all get the number of the last chapter. + + def _getCaptionPara(self): + caption = self.caption + captionFont = self.captionFont + captionSize = self.captionSize + captionTextColor = self.captionTextColor + captionBackColor = self.captionBackColor + captionAlign = self.captionAlign + captionPosition = self.captionPosition + if self._captionData!=(caption,captionFont,captionSize,captionTextColor,captionBackColor,captionAlign,captionPosition): + self._captionData = (caption,captionFont,captionSize,captionTextColor,captionBackColor,captionAlign,captionPosition) + if isinstance(caption,Paragraph): + self.captionPara = caption + elif isinstance(caption,strTypes): + self.captionStyle = ParagraphStyle( + 'Caption', + fontName=captionFont, + fontSize=captionSize, + leading=1.2*captionSize, + textColor = captionTextColor, + backColor = captionBackColor, + #seems to be getting ignored + spaceBefore=self.captionGap, + alignment=TA_LEFT if captionAlign=='left' else TA_RIGHT if captionAlign=='right' else TA_CENTER, + ) + #must build paragraph now to get sequencing in synch with rest of story + self.captionPara = Paragraph(self.caption, self.captionStyle) + else: + raise ValueError('Figure caption of type %r is not a string or Paragraph' % type(caption)) + + def wrap(self, availWidth, availHeight): + # try to get the caption aligned + if self.caption: + self._getCaptionPara() + w, h = self.captionPara.wrap(self.width, availHeight - self.figureHeight) + self.captionHeight = h + self.captionGap + self.height = self.captionHeight + self.figureHeight + if w>self.width: self.width = w + else: + self.height = self.figureHeight + if self.hAlign in ('CENTER','CENTRE',TA_CENTER): + self.dx = 0.5 * (availWidth - self.width) + elif self.hAlign in ('RIGHT',TA_RIGHT): + self.dx = availWidth - self.width + else: + self.dx = 0 + return (self.width, self.height) + + def draw(self): + self.canv.translate(self.dx, 0) + if self.caption and self.captionPosition=='bottom': + self.canv.translate(0, self.captionHeight) + if self.background: + self.drawBackground() + if self.border: + self.drawBorder() + self.canv.saveState() + self.drawFigure() + self.canv.restoreState() + if self.caption: + if self.captionPosition=='bottom': + self.canv.translate(0, -self.captionHeight) + else: + self.canv.translate(0, self.figureHeight+self.captionGap) + self._getCaptionPara() + self.drawCaption() + + def drawBorder(self): + canv = self.canv + border = self.border + bc = getattr(border,'color',None) + bw = getattr(border,'width',None) + bd = getattr(border,'dashArray',None) + ss = bc or bw or bd + if ss: + canv.saveState() + if bc: canv.setStrokeColor(bc) + if bw: canv.setLineWidth(bw) + if bd: canv.setDash(bd) + canv.rect(0, 0, self.width, self.figureHeight,fill=0,stroke=1) + if ss: + canv.restoreState() + + def _doBackground(self, color): + self.canv.saveState() + self.canv.setFillColor(self.background) + self.canv.rect(0, 0, self.width, self.figureHeight, fill=1) + self.canv.restoreState() + + def drawBackground(self): + """For use when using a figure on a differently coloured background. + Allows you to specify a colour to be used as a background for the figure.""" + if isColor(self.background): + self._doBackground(self.background) + else: + try: + c = toColor(self.background) + self._doBackground(c) + except: + pass + + def drawCaption(self): + self.captionPara.drawOn(self.canv, 0, 0) + + def drawFigure(self): + pass + +def drawPage(canvas,x, y, width, height): + #draws something which looks like a page + pth = canvas.beginPath() + corner = 0.05*width + + # shaded backdrop offset a little + canvas.setFillColorRGB(0.5,0.5,0.5) + canvas.rect(x + corner, y - corner, width, height, stroke=0, fill=1) + + #'sheet of paper' in light yellow + canvas.setFillColorRGB(1,1,0.9) + canvas.setLineWidth(0) + canvas.rect(x, y, width, height, stroke=1, fill=1) + + #reset + canvas.setFillColorRGB(0,0,0) + canvas.setStrokeColorRGB(0,0,0) + +class PageFigure(Figure): + """Shows a blank page in a frame, and draws on that. Used in + illustrations of how PLATYPUS works.""" + def __init__(self, background=None): + Figure.__init__(self, 3*inch, 3*inch) + self.caption = 'Figure 1 - a blank page' + self.captionStyle = captionStyle + self.background = background + + def drawVirtualPage(self): + pass + + def drawFigure(self): + drawPage(self.canv, 0.625*inch, 0.25*inch, 1.75*inch, 2.5*inch) + self.canv.translate(0.625*inch, 0.25*inch) + self.canv.scale(1.75/8.27, 2.5/11.69) + self.drawVirtualPage() + +class PlatPropFigure1(PageFigure): + """This shows a page with a frame on it""" + def __init__(self): + PageFigure.__init__(self) + self.caption = "Figure 1 - a page with a simple frame" + def drawVirtualPage(self): + demo1(self.canv) + +class FlexFigure(Figure): + """Base for a figure class with a caption. Can grow or shrink in proportion""" + def __init__(self, width, height, caption, background=None, + captionFont='Helvetica-Oblique',captionSize=8, + captionTextColor=colors.black, + shrinkToFit=1, + growToFit=1, + spaceBefore=12, + spaceAfter=12, + captionGap=9, + captionAlign='centre', + captionPosition='top', + scaleFactor=None, + hAlign='CENTER', + border=1, + ): + Figure.__init__(self, width, height, caption, + captionFont=captionFont, + captionSize=captionSize, + background=None, + captionTextColor=captionTextColor, + spaceBefore = spaceBefore, + spaceAfter = spaceAfter, + captionGap=captionGap, + captionAlign=captionAlign, + captionPosition=captionPosition, + hAlign=hAlign, + border=border, + ) + self.shrinkToFit = shrinkToFit #if set and wrap is too tight, shrinks + self.growToFit = growToFit #if set and wrap is too small, grows + self.scaleFactor = scaleFactor + self._scaleFactor = None + self.background = background + + def _scale(self,availWidth,availHeight): + "Rescale to fit according to the rules, but only once" + if self._scaleFactor is None or self.width>availWidth or self.height>availHeight: + w, h = Figure.wrap(self, availWidth, availHeight) + captionHeight = h - self.figureHeight + if self.scaleFactor is None: + #scale factor None means auto + self._scaleFactor = min(availWidth/self.width,(availHeight-captionHeight)/self.figureHeight) + else: #they provided a factor + self._scaleFactor = self.scaleFactor + if self._scaleFactor<1 and self.shrinkToFit: + self.width = self.width * self._scaleFactor - 0.0001 + self.figureHeight = self.figureHeight * self._scaleFactor + elif self._scaleFactor>1 and self.growToFit: + self.width = self.width*self._scaleFactor - 0.0001 + self.figureHeight = self.figureHeight * self._scaleFactor + + def wrap(self, availWidth, availHeight): + self._scale(availWidth,availHeight) + return Figure.wrap(self, availWidth, availHeight) + + def split(self, availWidth, availHeight): + self._scale(availWidth,availHeight) + return Figure.split(self, availWidth, availHeight) + +class ImageFigure(FlexFigure): + """Image with a caption below it""" + def __init__(self, filename, caption, background=None,scaleFactor=None,hAlign='CENTER',border=None): + assert os.path.isfile(filename), 'image file %s not found' % filename + from reportlab.lib.utils import ImageReader + w, h = ImageReader(filename).getSize() + self.filename = filename + FlexFigure.__init__(self, w, h, caption, background,scaleFactor=scaleFactor,hAlign=hAlign,border=border) + + def drawFigure(self): + self.canv.drawImage(self.filename, + 0, 0,self.width, self.figureHeight) + +class DrawingFigure(FlexFigure): + """Drawing with a caption below it. Clunky, scaling fails.""" + def __init__(self, modulename, classname, caption, baseDir=None, background=None): + module = recursiveImport(modulename, baseDir) + klass = getattr(module, classname) + self.drawing = klass() + FlexFigure.__init__(self, + self.drawing.width, + self.drawing.height, + caption, + background) + self.growToFit = 1 + + def drawFigure(self): + self.canv.scale(self._scaleFactor, self._scaleFactor) + self.drawing.drawOn(self.canv, 0, 0) + +try: + from rlextra.pageCatcher.pageCatcher import restoreForms, storeForms, storeFormsInMemory, restoreFormsInMemory + _hasPageCatcher = 1 +except ImportError: + _hasPageCatcher = 0 +if _hasPageCatcher: + #################################################################### + # + # PageCatcher plugins + # These let you use our PageCatcher product to add figures + # to other documents easily. + #################################################################### + class PageCatcherCachingMixIn: + "Helper functions to cache pages for figures" + + def getFormName(self, pdfFileName, pageNo): + #naming scheme works within a directory only + dirname, filename = os.path.split(pdfFileName) + root, ext = os.path.splitext(filename) + return '%s_page%d' % (root, pageNo) + + def needsProcessing(self, pdfFileName, pageNo): + "returns 1 if no forms or form is older" + formName = self.getFormName(pdfFileName, pageNo) + if os.path.exists(formName + '.frm'): + formModTime = os.stat(formName + '.frm')[8] + pdfModTime = os.stat(pdfFileName)[8] + return (pdfModTime > formModTime) + else: + return 1 + + def processPDF(self, pdfFileName, pageNo): + formName = self.getFormName(pdfFileName, pageNo) + storeForms(pdfFileName, formName + '.frm', + prefix= formName + '_', + pagenumbers=[pageNo]) + #print 'stored %s.frm' % formName + return formName + '.frm' + + class cachePageCatcherFigureNonA4(FlexFigure, PageCatcherCachingMixIn): + """PageCatcher page with a caption below it. Size to be supplied.""" + # This should merge with PageFigure into one class that reuses + # form information to determine the page orientation... + def __init__(self, filename, pageNo, caption, width, height, background=None): + self.dirname, self.filename = os.path.split(filename) + if self.dirname == '': + self.dirname = os.curdir + self.pageNo = pageNo + self.formName = self.getFormName(self.filename, self.pageNo) + '_' + str(pageNo) + FlexFigure.__init__(self, width, height, caption, background) + + def drawFigure(self): + self.canv.saveState() + if not self.canv.hasForm(self.formName): + restorePath = self.dirname + os.sep + self.filename + #does the form file exist? if not, generate it. + formFileName = self.getFormName(restorePath, self.pageNo) + '.frm' + if self.needsProcessing(restorePath, self.pageNo): + #print 'preprocessing PDF %s page %s' % (restorePath, self.pageNo) + self.processPDF(restorePath, self.pageNo) + names = restoreForms(formFileName, self.canv) + self.canv.scale(self._scaleFactor, self._scaleFactor) + self.canv.doForm(self.formName) + self.canv.restoreState() + + class cachePageCatcherFigure(cachePageCatcherFigureNonA4): + """PageCatcher page with a caption below it. Presumes A4, Portrait. + This needs our commercial PageCatcher product, or you'll get a blank.""" + def __init__(self, filename, pageNo, caption, width=595, height=842, background=None): + cachePageCatcherFigureNonA4.__init__(self, filename, pageNo, caption, width, height, background=background) + + class PageCatcherFigureNonA4(FlexFigure): + """PageCatcher page with a caption below it. Size to be supplied.""" + # This should merge with PageFigure into one class that reuses + # form information to determine the page orientation... + _cache = {} + def __init__(self, filename, pageNo, caption, width, height, background=None, caching=None): + fn = self.filename = filename + self.pageNo = pageNo + fn = fn.replace(os.sep,'_').replace('/','_').replace('\\','_').replace('-','_').replace(':','_') + self.prefix = fn.replace('.','_')+'_'+str(pageNo)+'_' + self.formName = self.prefix + str(pageNo) + self.caching = caching + FlexFigure.__init__(self, width, height, caption, background) + + def drawFigure(self): + if not self.canv.hasForm(self.formName): + if self.filename in self._cache: + f,data = self._cache[self.filename] + else: + f = open(self.filename,'rb') + pdf = f.read() + f.close() + f, data = storeFormsInMemory(pdf, pagenumbers=[self.pageNo], prefix=self.prefix) + if self.caching=='memory': + self._cache[self.filename] = f, data + f = restoreFormsInMemory(data, self.canv) + self.canv.saveState() + self.canv.scale(self._scaleFactor, self._scaleFactor) + self.canv.doForm(self.formName) + self.canv.restoreState() + + class PageCatcherFigure(PageCatcherFigureNonA4): + """PageCatcher page with a caption below it. Presumes A4, Portrait. + This needs our commercial PageCatcher product, or you'll get a blank.""" + def __init__(self, filename, pageNo, caption, width=595, height=842, background=None, caching=None): + PageCatcherFigureNonA4.__init__(self, filename, pageNo, caption, width, height, background=background, caching=caching) + +def demo1(canvas): + frame = Frame( + 2*inch, # x + 4*inch, # y at bottom + 4*inch, # width + 5*inch, # height + showBoundary = 1 # helps us see what's going on + ) + bodyStyle = ParagraphStyle('Body', fontName=_baseFontName, fontSize=24, leading=28, spaceBefore=6) + para1 = Paragraph('Spam spam spam spam. ' * 5, bodyStyle) + para2 = Paragraph('Eggs eggs eggs. ' * 5, bodyStyle) + mydata = [para1, para2] + + #this does the packing and drawing. The frame will consume + #items from the front of the list as it prints them + frame.addFromList(mydata,canvas) + +def test1(): + c = Canvas('figures.pdf') + f = Frame(inch, inch, 6*inch, 9*inch, showBoundary=1) + v = PlatPropFigure1() + v.captionTextColor = toColor('blue') + v.captionBackColor = toColor('lightyellow') + f.addFromList([v],c) + c.save() + +if __name__ == '__main__': + test1() diff --git a/reportlab/platypus/flowables.py b/reportlab/platypus/flowables.py new file mode 100644 index 00000000..f14c3640 --- /dev/null +++ b/reportlab/platypus/flowables.py @@ -0,0 +1,1979 @@ +#Copyright ReportLab Europe Ltd. 2000-2012 +#see license.txt for license details +#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/platypus/flowables.py +__version__=''' $Id$ ''' +__doc__=""" +A flowable is a "floating element" in a document whose exact position is determined by the +other elements that precede it, such as a paragraph, a diagram interspersed between paragraphs, +a section header, etcetera. Examples of non-flowables include page numbering annotations, +headers, footers, fixed diagrams or logos, among others. + +Flowables are defined here as objects which know how to determine their size and which +can draw themselves onto a page with respect to a relative "origin" position determined +at a higher level. The object's draw() method should assume that (0,0) corresponds to the +bottom left corner of the enclosing rectangle that will contain the object. The attributes +vAlign and hAlign may be used by 'packers' as hints as to how the object should be placed. + +Some Flowables also know how to "split themselves". For example a +long paragraph might split itself between one page and the next. + +Packers should set the canv attribute during wrap, split & draw operations to allow +the flowable to work out sizes etc in the proper context. + +The "text" of a document usually consists mainly of a sequence of flowables which +flow into a document from top to bottom (with column and page breaks controlled by +higher level components). +""" +import os +from copy import deepcopy, copy +from reportlab.lib.colors import red, gray, lightgrey +from reportlab.lib.rl_accel import fp_str +from reportlab.lib.enums import TA_LEFT, TA_CENTER, TA_RIGHT, TA_JUSTIFY +from reportlab.lib.styles import _baseFontName +from reportlab.lib.utils import strTypes +from reportlab.pdfbase import pdfutils +from reportlab.pdfbase.pdfmetrics import stringWidth +from reportlab.rl_config import _FUZZ, overlapAttachedSpace, ignoreContainerActions, listWrapOnFakeWidth +import collections + +__all__=('TraceInfo','Flowable','XBox','Preformatted','Image','Spacer','PageBreak','SlowPageBreak', + 'CondPageBreak','KeepTogether','Macro','CallerMacro','ParagraphAndImage', + 'FailOnWrap','HRFlowable','PTOContainer','KeepInFrame','UseUpSpace', + 'ListFlowable','ListItem','DDIndenter','LIIndenter', + 'DocAssign', 'DocExec', 'DocAssert', 'DocPara', 'DocIf', 'DocWhile', + 'PageBreakIfNotEmpty', + ) +class TraceInfo: + "Holder for info about where an object originated" + def __init__(self): + self.srcFile = '(unknown)' + self.startLineNo = -1 + self.startLinePos = -1 + self.endLineNo = -1 + self.endLinePos = -1 + +############################################################# +# Flowable Objects - a base class and a few examples. +# One is just a box to get some metrics. We also have +# a paragraph, an image and a special 'page break' +# object which fills the space. +############################################################# +class Flowable: + """Abstract base class for things to be drawn. Key concepts: + + 1. It knows its size + 2. It draws in its own coordinate system (this requires the + base API to provide a translate() function. + + """ + _fixedWidth = 0 #assume wrap results depend on arguments? + _fixedHeight = 0 + + def __init__(self): + self.width = 0 + self.height = 0 + self.wrapped = 0 + + #these are hints to packers/frames as to how the floable should be positioned + self.hAlign = 'LEFT' #CENTER/CENTRE or RIGHT + self.vAlign = 'BOTTOM' #MIDDLE or TOP + + #optional holder for trace info + self._traceInfo = None + self._showBoundary = None + + #many flowables handle text and must be processed in the + #absence of a canvas. tagging them with their encoding + #helps us to get conversions right. Use Python codec names. + self.encoding = None + + def _drawOn(self,canv): + '''ensure canv is set on and then draw''' + self.canv = canv + self.draw()#this is the bit you overload + del self.canv + + def _hAlignAdjust(self,x,sW=0): + if sW and hasattr(self,'hAlign'): + a = self.hAlign + if a in ('CENTER','CENTRE', TA_CENTER): + x += 0.5*sW + elif a in ('RIGHT',TA_RIGHT): + x += sW + elif a not in ('LEFT',TA_LEFT): + raise ValueError("Bad hAlign value "+str(a)) + return x + + def drawOn(self, canvas, x, y, _sW=0): + "Tell it to draw itself on the canvas. Do not override" + x = self._hAlignAdjust(x,_sW) + canvas.saveState() + canvas.translate(x, y) + self._drawOn(canvas) + if hasattr(self, '_showBoundary') and self._showBoundary: + #diagnostic tool support + canvas.setStrokeColor(gray) + canvas.rect(0,0,self.width, self.height) + canvas.restoreState() + + def wrapOn(self, canv, aW, aH): + '''intended for use by packers allows setting the canvas on + during the actual wrap''' + self.canv = canv + w, h = self.wrap(aW,aH) + del self.canv + return w, h + + def wrap(self, availWidth, availHeight): + """This will be called by the enclosing frame before objects + are asked their size, drawn or whatever. It returns the + size actually used.""" + return (self.width, self.height) + + def minWidth(self): + """This should return the minimum required width""" + return getattr(self,'_minWidth',self.width) + + def splitOn(self, canv, aW, aH): + '''intended for use by packers allows setting the canvas on + during the actual split''' + self.canv = canv + S = self.split(aW,aH) + del self.canv + return S + + def split(self, availWidth, availheight): + """This will be called by more sophisticated frames when + wrap fails. Stupid flowables should return []. Clever flowables + should split themselves and return a list of flowables. + If they decide that nothing useful can be fitted in the + available space (e.g. if you have a table and not enough + space for the first row), also return []""" + return [] + + def getKeepWithNext(self): + """returns boolean determining whether the next flowable should stay with this one""" + if hasattr(self,'keepWithNext'): return self.keepWithNext + elif hasattr(self,'style') and hasattr(self.style,'keepWithNext'): return self.style.keepWithNext + else: return 0 + + def getSpaceAfter(self): + """returns how much space should follow this item if another item follows on the same page.""" + if hasattr(self,'spaceAfter'): return self.spaceAfter + elif hasattr(self,'style') and hasattr(self.style,'spaceAfter'): return self.style.spaceAfter + else: return 0 + + def getSpaceBefore(self): + """returns how much space should precede this item if another item precedess on the same page.""" + if hasattr(self,'spaceBefore'): return self.spaceBefore + elif hasattr(self,'style') and hasattr(self.style,'spaceBefore'): return self.style.spaceBefore + else: return 0 + + def isIndexing(self): + """Hook for IndexingFlowables - things which have cross references""" + return 0 + + def identity(self, maxLen=None): + ''' + This method should attempt to return a string that can be used to identify + a particular flowable uniquely. The result can then be used for debugging + and or error printouts + ''' + if hasattr(self, 'getPlainText'): + r = self.getPlainText(identify=1) + elif hasattr(self, 'text'): + r = str(self.text) + else: + r = '...' + if r and maxLen: + r = r[:maxLen] + return "<%s at %s%s>%s" % (self.__class__.__name__, hex(id(self)), self._frameName(), r) + + def _doctemplateAttr(self,a): + return getattr(getattr(getattr(self,'canv',None),'_doctemplate',None),a,None) + + def _frameName(self): + f = getattr(self,'_frame',None) + if not f: f = self._doctemplateAttr('frame') + if f and f.id: return ' frame=%s' % f.id + return '' + +class XBox(Flowable): + """Example flowable - a box with an x through it and a caption. + This has a known size, so does not need to respond to wrap().""" + def __init__(self, width, height, text = 'A Box'): + Flowable.__init__(self) + self.width = width + self.height = height + self.text = text + + def __repr__(self): + return "XBox(w=%s, h=%s, t=%s)" % (self.width, self.height, self.text) + + def draw(self): + self.canv.rect(0, 0, self.width, self.height) + self.canv.line(0, 0, self.width, self.height) + self.canv.line(0, self.height, self.width, 0) + + #centre the text + self.canv.setFont(_baseFontName,12) + self.canv.drawCentredString(0.5*self.width, 0.5*self.height, self.text) + +def _trimEmptyLines(lines): + #don't want the first or last to be empty + while len(lines) and lines[0].strip() == '': + lines = lines[1:] + while len(lines) and lines[-1].strip() == '': + lines = lines[:-1] + return lines + +def _dedenter(text,dedent=0): + ''' + tidy up text - carefully, it is probably code. If people want to + indent code within a source script, you can supply an arg to dedent + and it will chop off that many character, otherwise it leaves + left edge intact. + ''' + lines = text.split('\n') + if dedent>0: + templines = _trimEmptyLines(lines) + lines = [] + for line in templines: + line = line[dedent:].rstrip() + lines.append(line) + else: + lines = _trimEmptyLines(lines) + + return lines + + +SPLIT_CHARS = "[{( ,.;:/\\-" + +def splitLines(lines, maximum_length, split_characters, new_line_characters): + if split_characters is None: + split_characters = SPLIT_CHARS + if new_line_characters is None: + new_line_characters = "" + # Return a table of lines + lines_splitted = [] + for line in lines: + if len(line) > maximum_length: + splitLine(line, lines_splitted, maximum_length, \ + split_characters, new_line_characters) + else: + lines_splitted.append(line) + return lines_splitted + +def splitLine(line_to_split, lines_splitted, maximum_length, \ +split_characters, new_line_characters): + # Used to implement the characters added + #at the beginning of each new line created + first_line = True + + # Check if the text can be splitted + while line_to_split and len(line_to_split)>0: + + # Index of the character where we can split + split_index = 0 + + # Check if the line length still exceeds the maximum length + if len(line_to_split) <= maximum_length: + # Return the remaining of the line + split_index = len(line_to_split) + else: + # Iterate for each character of the line + for line_index in range(maximum_length): + # Check if the character is in the list + # of allowed characters to split on + if line_to_split[line_index] in split_characters: + split_index = line_index + 1 + + # If the end of the line was reached + # with no character to split on + if split_index==0: + split_index = line_index + 1 + + if first_line: + lines_splitted.append(line_to_split[0:split_index]) + first_line = False + maximum_length -= len(new_line_characters) + else: + lines_splitted.append(new_line_characters + \ + line_to_split[0:split_index]) + + # Remaining text to split + line_to_split = line_to_split[split_index:] + +class Preformatted(Flowable): + """This is like the HTML
 tag.
+    It attempts to display text exactly as you typed it in a fixed width "typewriter" font.
+    By default the line breaks are exactly where you put them, and it will not be wrapped.
+    You can optionally define a maximum line length and the code will be wrapped; and 
+    extra characters to be inserted at the beginning of each wrapped line (e.g. '> ').
+    """
+    def __init__(self, text, style, bulletText = None, dedent=0, maxLineLength=None, splitChars=None, newLineChars=""):
+        """text is the text to display. If dedent is set then common leading space
+        will be chopped off the front (for example if the entire text is indented
+        6 spaces or more then each line will have 6 spaces removed from the front).
+        """
+        self.style = style
+        self.bulletText = bulletText
+        self.lines = _dedenter(text,dedent)
+        if text and maxLineLength:
+            self.lines = splitLines(
+                                self.lines, 
+                                maxLineLength, 
+                                splitChars, 
+                                newLineChars
+                        )
+
+    def __repr__(self):
+        bT = self.bulletText
+        H = "Preformatted("
+        if bT is not None:
+            H = "Preformatted(bulletText=%s," % repr(bT)
+        return "%s'''\\ \n%s''')" % (H, '\n'.join(self.lines))
+
+    def wrap(self, availWidth, availHeight):
+        self.width = availWidth
+        self.height = self.style.leading*len(self.lines)
+        return (self.width, self.height)
+
+    def minWidth(self):
+        style = self.style
+        fontSize = style.fontSize
+        fontName = style.fontName
+        return max([stringWidth(line,fontName,fontSize) for line in self.lines])
+
+    def split(self, availWidth, availHeight):
+        #returns two Preformatted objects
+
+        #not sure why they can be called with a negative height
+        if availHeight < self.style.leading:
+            return []
+
+        linesThatFit = int(availHeight * 1.0 / self.style.leading)
+
+        text1 = '\n'.join(self.lines[0:linesThatFit])
+        text2 = '\n'.join(self.lines[linesThatFit:])
+        style = self.style
+        if style.firstLineIndent != 0:
+            style = deepcopy(style)
+            style.firstLineIndent = 0
+        return [Preformatted(text1, self.style), Preformatted(text2, style)]
+
+    def draw(self):
+        #call another method for historical reasons.  Besides, I
+        #suspect I will be playing with alternate drawing routines
+        #so not doing it here makes it easier to switch.
+
+        cur_x = self.style.leftIndent
+        cur_y = self.height - self.style.fontSize
+        self.canv.addLiteral('%PreformattedPara')
+        if self.style.textColor:
+            self.canv.setFillColor(self.style.textColor)
+        tx = self.canv.beginText(cur_x, cur_y)
+        #set up the font etc.
+        tx.setFont( self.style.fontName,
+                    self.style.fontSize,
+                    self.style.leading)
+
+        for text in self.lines:
+            tx.textLine(text)
+        self.canv.drawText(tx)
+
+class Image(Flowable):
+    """an image (digital picture).  Formats supported by PIL/Java 1.4 (the Python/Java Imaging Library
+       are supported.  At the present time images as flowables are always centered horozontally
+       in the frame. We allow for two kinds of lazyness to allow for many images in a document
+       which could lead to file handle starvation.
+       lazy=1 don't open image until required.
+       lazy=2 open image when required then shut it.
+    """
+    _fixedWidth = 1
+    _fixedHeight = 1
+    def __init__(self, filename, width=None, height=None, kind='direct', mask="auto", lazy=1):
+        """If size to draw at not specified, get it from the image."""
+        self.hAlign = 'CENTER'
+        self._mask = mask
+        fp = hasattr(filename,'read')
+        if fp:
+            self._file = filename
+            self.filename = repr(filename)
+        else:
+            self._file = self.filename = filename
+        if not fp and os.path.splitext(filename)[1] in ['.jpg', '.JPG', '.jpeg', '.JPEG']:
+            # if it is a JPEG, will be inlined within the file -
+            # but we still need to know its size now
+            from reportlab.lib.utils import open_for_read
+            f = open_for_read(filename, 'b')
+            try:
+                try:
+                    info = pdfutils.readJPEGInfo(f)
+                except:
+                    #couldn't read as a JPEG, try like normal
+                    self._setup(width,height,kind,lazy)
+                    return
+            finally:
+                f.close()
+            self.imageWidth = info[0]
+            self.imageHeight = info[1]
+            self._img = None
+            self._setup(width,height,kind,0)
+        elif fp:
+            self._setup(width,height,kind,0)
+        else:
+            self._setup(width,height,kind,lazy)
+
+    def _setup(self,width,height,kind,lazy):
+        self._lazy = lazy
+        self._width = width
+        self._height = height
+        self._kind = kind
+        if lazy<=0: self._setup_inner()
+
+    def _setup_inner(self):
+        width = self._width
+        height = self._height
+        kind = self._kind
+        img = self._img
+        if img: self.imageWidth, self.imageHeight = img.getSize()
+        if self._lazy>=2: del self._img
+        if kind in ['direct','absolute']:
+            self.drawWidth = width or self.imageWidth
+            self.drawHeight = height or self.imageHeight
+        elif kind in ['percentage','%']:
+            self.drawWidth = self.imageWidth*width*0.01
+            self.drawHeight = self.imageHeight*height*0.01
+        elif kind in ['bound','proportional']:
+            factor = min(float(width)/self.imageWidth,float(height)/self.imageHeight)
+            self.drawWidth = self.imageWidth*factor
+            self.drawHeight = self.imageHeight*factor
+
+    def _restrictSize(self,aW,aH):
+        if self.drawWidth>aW+_FUZZ or self.drawHeight>aH+_FUZZ:
+            self._oldDrawSize = self.drawWidth, self.drawHeight
+            factor = min(float(aW)/self.drawWidth,float(aH)/self.drawHeight)
+            self.drawWidth *= factor
+            self.drawHeight *= factor
+        return self.drawWidth, self.drawHeight
+
+    def _unRestrictSize(self):
+        dwh = getattr(self,'_oldDrawSize',None)
+        if dwh:
+            self.drawWidth, self.drawHeight = dwh
+
+    def __getattr__(self,a):
+        if a=='_img':
+            from reportlab.lib.utils import ImageReader  #this may raise an error
+            self._img = ImageReader(self._file)
+            if not isinstance(self._file,strTypes):
+                self._file = None
+                if self._lazy>=2: self._lazy = 1    #here we're assuming we cannot read again
+            return self._img
+        elif a in ('drawWidth','drawHeight','imageWidth','imageHeight'):
+            self._setup_inner()
+            return self.__dict__[a]
+        raise AttributeError(".%s" % (id(self),a))
+
+    def wrap(self, availWidth, availHeight):
+        #the caller may decide it does not fit.
+        return self.drawWidth, self.drawHeight
+
+    def draw(self):
+        lazy = self._lazy
+        if lazy>=2: self._lazy = 1
+        self.canv.drawImage(    self._img or self.filename,
+                                getattr(self,'_offs_x',0),
+                                getattr(self,'_offs_y',0),
+                                self.drawWidth,
+                                self.drawHeight,
+                                mask=self._mask,
+                                )
+        if lazy>=2:
+            self._img = self._file = None
+            self._lazy = lazy
+
+    def identity(self,maxLen=None):
+        r = Flowable.identity(self,maxLen)
+        if r[-4:]=='>...' and isinstance(self.filename,str):
+            r = "%s filename=%s>" % (r[:-4],self.filename)
+        return r
+
+class NullDraw(Flowable):
+    def draw(self):
+        pass
+
+class Spacer(NullDraw):
+    """A spacer just takes up space and doesn't draw anything - it guarantees
+       a gap between objects."""
+    _fixedWidth = 1
+    _fixedHeight = 1
+    def __init__(self, width, height, isGlue=False):
+        self.width = width
+        if isGlue:
+            self.height = 1e-4
+            self.spacebefore = height
+        self.height = height
+
+    def __repr__(self):
+        return "%s(%s, %s)" % (self.__class__.__name__,self.width, self.height)
+
+class UseUpSpace(NullDraw):
+    def __init__(self):
+        pass
+
+    def __repr__(self):
+        return "%s()" % self.__class__.__name__
+
+    def wrap(self, availWidth, availHeight):
+        self.width = availWidth
+        self.height = availHeight
+        return (availWidth,availHeight-1e-8)  #step back a point
+
+class PageBreak(UseUpSpace):
+    """Move on to the next page in the document.
+       This works by consuming all remaining space in the frame!"""
+    def __init__(self,nextTemplate=None):
+        self.nextTemplate = nextTemplate
+
+class SlowPageBreak(PageBreak):
+    pass
+
+class PageBreakIfNotEmpty(PageBreak):
+    pass
+
+class CondPageBreak(Spacer):
+    """use up a frame if not enough vertical space effectively CondFrameBreak"""
+    def __init__(self, height):
+        self.height = height
+
+    def __repr__(self):
+        return "CondPageBreak(%s)" %(self.height,)
+
+    def wrap(self, availWidth, availHeight):
+        if availHeightaH and (not self._maxHeight or aH>self._maxHeight)
+        C1 = (self._H0>aH) or C0 and atTop
+        if C0 or C1:
+            if C0:
+                from reportlab.platypus.doctemplate import FrameBreak
+                A = FrameBreak
+            else:
+                from reportlab.platypus.doctemplate import NullActionFlowable
+                A = NullActionFlowable
+            S.insert(0,A())
+        return S
+
+    def identity(self, maxLen=None):
+        msg = "<%s at %s%s> containing :%s" % (self.__class__.__name__,hex(id(self)),self._frameName(),"\n".join([f.identity() for f in self._content]))
+        if maxLen:
+            return msg[0:maxLen]
+        else:
+            return msg
+
+class Macro(Flowable):
+    """This is not actually drawn (i.e. it has zero height)
+    but is executed when it would fit in the frame.  Allows direct
+    access to the canvas through the object 'canvas'"""
+    def __init__(self, command):
+        self.command = command
+    def __repr__(self):
+        return "Macro(%s)" % repr(self.command)
+    def wrap(self, availWidth, availHeight):
+        return (0,0)
+    def draw(self):
+        exec(self.command, globals(), {'canvas':self.canv})
+
+def _nullCallable(*args,**kwds):
+    pass
+
+class CallerMacro(Flowable):
+    '''
+    like Macro, but with callable command(s)
+    drawCallable(self)
+    wrapCallable(self,aW,aH)
+    '''
+    def __init__(self, drawCallable=None, wrapCallable=None):
+        self._drawCallable = drawCallable or _nullCallable
+        self._wrapCallable = wrapCallable or _nullCallable
+    def __repr__(self):
+        return "CallerMacro(%r,%r)" % (self._drawCallable,self._wrapCallable)
+    def wrap(self, aW, aH):
+        self._wrapCallable(self,aW,aH)
+        return (0,0)
+    def draw(self):
+        self._drawCallable(self)
+
+class ParagraphAndImage(Flowable):
+    '''combine a Paragraph and an Image'''
+    def __init__(self,P,I,xpad=3,ypad=3,side='right'):
+        self.P = P
+        self.I = I
+        self.xpad = xpad
+        self.ypad = ypad
+        self._side = side
+
+    def getSpaceBefore(self):
+        return max(self.P.getSpaceBefore(),self.I.getSpaceBefore())
+
+    def getSpaceAfter(self):
+        return max(self.P.getSpaceAfter(),self.I.getSpaceAfter())
+
+    def wrap(self,availWidth,availHeight):
+        wI, hI = self.I.wrap(availWidth,availHeight)
+        self.wI = wI
+        self.hI = hI
+        # work out widths array for breaking
+        self.width = availWidth
+        P = self.P
+        style = P.style
+        xpad = self.xpad
+        ypad = self.ypad
+        leading = style.leading
+        leftIndent = style.leftIndent
+        later_widths = availWidth - leftIndent - style.rightIndent
+        intermediate_widths = later_widths - xpad - wI
+        first_line_width = intermediate_widths - style.firstLineIndent
+        P.width = 0
+        nIW = int((hI+ypad)/(leading*1.0))
+        P.blPara = P.breakLines([first_line_width] + nIW*[intermediate_widths]+[later_widths])
+        if self._side=='left':
+            self._offsets = [wI+xpad]*(1+nIW)+[0]
+        P.height = len(P.blPara.lines)*leading
+        self.height = max(hI,P.height)
+        return (self.width, self.height)
+
+    def split(self,availWidth, availHeight):
+        P, wI, hI, ypad = self.P, self.wI, self.hI, self.ypad
+        if hI+ypad>availHeight or len(P.frags)<=0: return []
+        S = P.split(availWidth,availHeight)
+        if not S: return S
+        P = self.P = S[0]
+        del S[0]
+        style = P.style
+        P.height = len(self.P.blPara.lines)*style.leading
+        self.height = max(hI,P.height)
+        return [self]+S
+
+    def draw(self):
+        canv = self.canv
+        if self._side=='left':
+            self.I.drawOn(canv,0,self.height-self.hI)
+            self.P._offsets = self._offsets
+            try:
+                self.P.drawOn(canv,0,0)
+            finally:
+                del self.P._offsets
+        else:
+            self.I.drawOn(canv,self.width-self.wI-self.xpad,self.height-self.hI)
+            self.P.drawOn(canv,0,0)
+
+class FailOnWrap(NullDraw):
+    def wrap(self, availWidth, availHeight):
+        raise ValueError("FailOnWrap flowable wrapped and failing as ordered!")
+
+class FailOnDraw(Flowable):
+    def wrap(self, availWidth, availHeight):
+        return 0,0
+
+    def draw(self):
+        raise ValueError("FailOnDraw flowable drawn, and failing as ordered!")
+
+class HRFlowable(Flowable):
+    '''Like the hr tag'''
+    def __init__(self,
+            width="80%",
+            thickness=1,
+            lineCap='round',
+            color=lightgrey,
+            spaceBefore=1, spaceAfter=1,
+            hAlign='CENTER', vAlign='BOTTOM',
+            dash=None):
+        Flowable.__init__(self)
+        self.width = width
+        self.lineWidth = thickness
+        self.lineCap=lineCap
+        self.spaceBefore = spaceBefore
+        self.spaceAfter = spaceAfter
+        self.color = color
+        self.hAlign = hAlign
+        self.vAlign = vAlign
+        self.dash = dash
+
+    def __repr__(self):
+        return "HRFlowable(width=%s, height=%s)" % (self.width, self.height)
+
+    def wrap(self, availWidth, availHeight):
+        w = self.width
+        if type(w) is type(''):
+            w = w.strip()
+            if w.endswith('%'): w = availWidth*float(w[:-1])*0.01
+            else: w = float(w)
+        w = min(w,availWidth)
+        self._width = w
+        return w, self.lineWidth
+
+    def draw(self):
+        canv = self.canv
+        canv.saveState()
+        canv.setLineWidth(self.lineWidth)
+        canv.setLineCap({'butt':0,'round':1, 'square': 2}[self.lineCap.lower()])
+        canv.setStrokeColor(self.color)
+        if self.dash: canv.setDash(self.dash)
+        canv.line(0, 0, self._width, self.height)
+        canv.restoreState()
+
+class _PTOInfo:
+    def __init__(self,trailer,header):
+        self.trailer = _flowableSublist(trailer)
+        self.header = _flowableSublist(header)
+
+def cdeepcopy(obj):
+    if hasattr(obj,'deepcopy'):
+        return obj.deepcopy()
+    else:
+        return deepcopy(obj)
+
+class _Container(_ContainerSpace):  #Abstract some common container like behaviour
+    def drawOn(self, canv, x, y, _sW=0, scale=1.0, content=None, aW=None):
+        '''we simulate being added to a frame'''
+        from reportlab.platypus.doctemplate import ActionFlowable, Indenter
+        x0 = x
+        y0 = y
+        pS = 0
+        if aW is None: aW = self.width
+        aW *= scale
+        if content is None:
+            content = self._content
+        x = self._hAlignAdjust(x,_sW*scale)
+        y += self.height*scale
+        yt = y
+        frame = getattr(self,'_frame',None)
+        for c in content:
+            if not ignoreContainerActions and isinstance(c,ActionFlowable):
+                c.apply(self.canv._doctemplate)
+                continue
+            if isinstance(c,Indenter):
+                x += c.left*scale
+                aW -= (c.left+c.right)*scale
+                continue
+            w, h = c.wrapOn(canv,aW,0xfffffff)
+            if (w<_FUZZ or h<_FUZZ) and not getattr(c,'_ZEROSIZE',None): continue
+            if yt!=y:
+                s = c.getSpaceBefore()
+                if not getattr(c,'_SPACETRANSFER',False):
+                    h += max(s-pS,0)
+            y -= h
+            fbg = getattr(frame,'_frameBGs',None)
+            s = c.getSpaceAfter()
+            if getattr(c,'_SPACETRANSFER',False):
+                s = pS
+            pS = s
+            if fbg:
+                fbgl, fbgr, fbgc = fbg[-1]
+                fbw = scale*(frame._width-fbgl-fbgr)
+                fbh = y + h + pS
+                fby = max(y0,y-pS)
+                fbh = max(0,fbh-fby)
+                if abs(fbw)>_FUZZ and abs(fbh)>_FUZZ:
+                    canv.saveState()
+                    canv.setFillColor(fbgc)
+                    canv.rect(x0+scale*(fbgl-frame._leftPadding)-0.1,fby-0.1,fbw+0.2,fbh+0.2,stroke=0,fill=1)
+                    canv.restoreState()
+            c._frame = frame
+            c.drawOn(canv,x,y,_sW=aW-w)
+            if c is not content[-1] and not getattr(c,'_SPACETRANSFER',None):
+                y -= pS
+            del c._frame
+
+    def copyContent(self,content=None):
+        C = [].append
+        for c in (content or self._content):
+            C(cdeepcopy(c))
+        self._content = C.__self__
+
+class PTOContainer(_Container,Flowable):
+    '''PTOContainer(contentList,trailerList,headerList)
+
+    A container for flowables decorated with trailer & header lists.
+    If the split operation would be called then the trailer and header
+    lists are injected before and after the split. This allows specialist
+    "please turn over" and "continued from previous" like behaviours.'''
+    def __init__(self,content,trailer=None,header=None):
+        I = _PTOInfo(trailer,header)
+        self._content = C = []
+        for _ in _flowableSublist(content):
+            if isinstance(_,PTOContainer):
+                C.extend(_._content)
+            else:
+                C.append(_)
+                if not hasattr(_,'_ptoinfo'): _._ptoinfo = I
+
+    def wrap(self,availWidth,availHeight):
+        self.width, self.height = _listWrapOn(self._content,availWidth,self.canv)
+        return self.width,self.height
+
+    def split(self, availWidth, availHeight):
+        from reportlab.platypus.doctemplate import Indenter
+        if availHeight<0: return []
+        canv = self.canv
+        C = self._content
+        x = i = H = pS = hx = 0
+        n = len(C)
+        I2W = {}
+        dLeft = dRight = 0
+        for x in xrange(n):
+            c = C[x]
+            I = c._ptoinfo
+            if I not in I2W.keys():
+                T = I.trailer
+                Hdr = I.header
+                tW, tH = _listWrapOn(T, availWidth, self.canv)
+                if len(T):  #trailer may have no content
+                    tSB = T[0].getSpaceBefore()
+                else:
+                    tSB = 0
+                I2W[I] = T,tW,tH,tSB
+            else:
+                T,tW,tH,tSB = I2W[I]
+            _, h = c.wrapOn(canv,availWidth,0xfffffff)
+            if isinstance(c,Indenter):
+                dw = c.left+c.right
+                dLeft += c.left
+                dRight += c.right
+                availWidth -= dw
+                pS = 0
+                hx = 0
+            else:
+                if x:
+                    hx = max(c.getSpaceBefore()-pS,0)
+                    h += hx
+                pS = c.getSpaceAfter()
+            H += h+pS
+            tHS = tH+max(tSB,pS)
+            if H+tHS>=availHeight-_FUZZ: break
+            i += 1
+
+        #first retract last thing we tried
+        H -= (h+pS)
+
+        #attempt a sub split on the last one we have
+        aH = (availHeight-H-tHS-hx)*0.99999
+        if aH>=0.05*availHeight:
+            SS = c.splitOn(canv,availWidth,aH)
+        else:
+            SS = []
+
+        if abs(dLeft)+abs(dRight)>1e-8:
+            R1I = [Indenter(-dLeft,-dRight)]
+            R2I = [Indenter(dLeft,dRight)]
+        else:
+            R1I = R2I = []
+
+        if not SS:
+            j = i
+            while i>1 and C[i-1].getKeepWithNext():
+                i -= 1
+                C[i].keepWithNext = 0
+
+            if i==1 and C[0].getKeepWithNext():
+                #robin's black sheep
+                i = j
+                C[0].keepWithNext = 0
+
+        F = [UseUpSpace()]
+
+        if len(SS)>1:
+            R1 = C[:i]+SS[:1]+R1I+T+F
+            R2 = Hdr+R2I+SS[1:]+C[i+1:]
+        elif not i:
+            return []
+        else:
+            R1 = C[:i]+R1I+T+F
+            R2 = Hdr+R2I+C[i:]
+        T =  R1 + [PTOContainer(R2,[copy(x) for x in I.trailer],[copy(x) for x in I.header])]
+        return T
+
+#utility functions used by KeepInFrame
+def _hmodel(s0,s1,h0,h1):
+    # calculate the parameters in the model
+    # h = a/s**2 + b/s
+    a11 = 1./s0**2
+    a12 = 1./s0
+    a21 = 1./s1**2
+    a22 = 1./s1
+    det = a11*a22-a12*a21
+    b11 = a22/det
+    b12 = -a12/det
+    b21 = -a21/det
+    b22 = a11/det
+    a = b11*h0+b12*h1
+    b = b21*h0+b22*h1
+    return a,b
+
+def _qsolve(h,ab):
+    '''solve the model v = a/s**2 + b/s for an s which gives us v==h'''
+    a,b = ab
+    if abs(a)<=_FUZZ:
+        return b/h
+    t = 0.5*b/a
+    from math import sqrt
+    f = -h/a
+    r = t*t-f
+    if r<0: return None
+    r = sqrt(r)
+    if t>=0:
+        s1 = -t - r
+    else:
+        s1 = -t + r
+    s2 = f/s1
+    return max(1./s1, 1./s2)
+
+class KeepInFrame(_Container,Flowable):
+    def __init__(self, maxWidth, maxHeight, content=[], mergeSpace=1, mode='shrink', name='',hAlign='LEFT',vAlign='BOTTOM', fakeWidth=None):
+        '''mode describes the action to take when overflowing
+            error       raise an error in the normal way
+            continue    ignore ie just draw it and report maxWidth, maxHeight
+            shrink      shrinkToFit
+            truncate    fit as much as possible
+            set fakeWidth to False to make _listWrapOn do the 'right' thing
+        '''
+        self.name = name
+        self.maxWidth = maxWidth
+        self.maxHeight = maxHeight
+        self.mode = mode
+        assert mode in ('error','overflow','shrink','truncate'), '%s invalid mode value %s' % (self.identity(),mode)
+        assert maxHeight>=0,  '%s invalid maxHeight value %s' % (self.identity(),maxHeight)
+        if mergeSpace is None: mergeSpace = overlapAttachedSpace
+        self.mergespace = mergeSpace
+        self._content = content or []
+        self.vAlign = vAlign
+        self.hAlign = hAlign
+        self.fakeWidth = fakeWidth
+
+    def _getAvailableWidth(self):
+        return self.maxWidth - self._leftExtraIndent - self._rightExtraIndent
+
+    def identity(self, maxLen=None):
+        return "<%s at %s%s%s> size=%sx%s" % (self.__class__.__name__, hex(id(self)), self._frameName(),
+                getattr(self,'name','') and (' name="%s"'% getattr(self,'name','')) or '',
+                getattr(self,'maxWidth','') and (' maxWidth=%s'%fp_str(getattr(self,'maxWidth',0))) or '',
+                getattr(self,'maxHeight','')and (' maxHeight=%s' % fp_str(getattr(self,'maxHeight')))or '')
+
+    def wrap(self,availWidth,availHeight):
+        from reportlab.platypus.doctemplate import LayoutError
+        mode = self.mode
+        maxWidth = float(min(self.maxWidth or availWidth,availWidth))
+        maxHeight = float(min(self.maxHeight or availHeight,availHeight))
+        fakeWidth = self.fakeWidth
+        W, H = _listWrapOn(self._content,maxWidth,self.canv, fakeWidth=fakeWidth)
+        if (mode=='error' and (W>maxWidth+_FUZZ or H>maxHeight+_FUZZ)):
+            ident = 'content %sx%s too large for %s' % (W,H,self.identity(30))
+            #leave to keep apart from the raise
+            raise LayoutError(ident)
+        elif W<=maxWidth+_FUZZ and H<=maxHeight+_FUZZ:
+            self.width = W-_FUZZ      #we take what we get
+            self.height = H-_FUZZ
+        elif mode in ('overflow','truncate'):   #we lie
+            self.width = min(maxWidth,W)-_FUZZ
+            self.height = min(maxHeight,H)-_FUZZ
+        else:
+            def func(x):
+                x = float(x)
+                W, H = _listWrapOn(self._content,x*maxWidth,self.canv, fakeWidth=fakeWidth)
+                W /= x
+                H /= x
+                return W, H
+            W0 = W
+            H0 = H
+            s0 = 1
+            if W>maxWidth+_FUZZ:
+                #squeeze out the excess width and or Height
+                s1 = W/maxWidth     #linear model
+                W, H = func(s1)
+                if H<=maxHeight+_FUZZ:
+                    self.width = W-_FUZZ
+                    self.height = H-_FUZZ
+                    self._scale = s1
+                    return W,H
+                s0 = s1
+                H0 = H
+                W0 = W
+            s1 = H/maxHeight
+            W, H = func(s1)
+            self.width = W-_FUZZ
+            self.height = H-_FUZZ
+            self._scale = s1
+            if H=maxHeight+_FUZZ:
+                #the standard case W should be OK, H is short we want
+                #to find the smallest s with H<=maxHeight
+                H1 = H
+                for f in 0, 0.01, 0.05, 0.10, 0.15:
+                    #apply the quadratic model
+                    s = _qsolve(maxHeight*(1-f),_hmodel(s0,s1,H0,H1))
+                    W, H = func(s)
+                    if H<=maxHeight+_FUZZ and W<=maxWidth+_FUZZ:
+                        self.width = W-_FUZZ
+                        self.height = H-_FUZZ
+                        self._scale = s
+                        break
+
+        return self.width, self.height
+
+    def drawOn(self, canv, x, y, _sW=0):
+        scale = getattr(self,'_scale',1.0)
+        truncate = self.mode=='truncate'
+        ss = scale!=1.0 or truncate
+        if ss:
+            canv.saveState()
+            if truncate:
+                p = canv.beginPath()
+                p.rect(x, y, self.width,self.height)
+                canv.clipPath(p,stroke=0)
+            else:
+                canv.translate(x,y)
+                x=y=0
+                canv.scale(1.0/scale, 1.0/scale)
+        _Container.drawOn(self, canv, x, y, _sW=_sW, scale=scale)
+        if ss: canv.restoreState()
+
+class ImageAndFlowables(_Container,Flowable):
+    '''combine a list of flowables and an Image'''
+    def __init__(self,I,F,imageLeftPadding=0,imageRightPadding=3,imageTopPadding=0,imageBottomPadding=3,
+                    imageSide='right', imageHref=None):
+        self._content = _flowableSublist(F)
+        self._I = I
+        self._irpad = imageRightPadding
+        self._ilpad = imageLeftPadding
+        self._ibpad = imageBottomPadding
+        self._itpad = imageTopPadding
+        self._side = imageSide
+        self.imageHref = imageHref
+
+    def deepcopy(self):
+        c = copy(self)  #shallow
+        self._reset()
+        c.copyContent() #partially deep?
+        return c
+
+    def getSpaceAfter(self):
+        if hasattr(self,'_C1'):
+            C = self._C1
+        elif hasattr(self,'_C0'):
+            C = self._C0
+        else:
+            C = self._content
+        return _Container.getSpaceAfter(self,C)
+
+    def getSpaceBefore(self):
+        return max(self._I.getSpaceBefore(),_Container.getSpaceBefore(self))
+
+    def _reset(self):
+        for a in ('_wrapArgs','_C0','_C1'):
+            try:
+                delattr(self,a)
+            except:
+                pass
+
+    def wrap(self,availWidth,availHeight):
+        canv = self.canv
+        I = self._I
+        if hasattr(self,'_wrapArgs'):
+            if self._wrapArgs==(availWidth,availHeight) and getattr(I,'_oldDrawSize',None) is None:
+                return self.width,self.height
+            self._reset()
+            I._unRestrictSize()
+        self._wrapArgs = availWidth, availHeight
+        I.wrap(availWidth,availHeight)
+        wI, hI = I._restrictSize(availWidth,availHeight)
+        self._wI = wI
+        self._hI = hI
+        ilpad = self._ilpad
+        irpad = self._irpad
+        ibpad = self._ibpad
+        itpad = self._itpad
+        self._iW = iW = availWidth - irpad - wI - ilpad
+        aH = itpad + hI + ibpad
+        if iW>_FUZZ:
+            W,H0,self._C0,self._C1 = self._findSplit(canv,iW,aH)
+        else:
+            W = availWidth
+            H0 = 0
+        if W>iW+_FUZZ:
+            self._C0 = []
+            self._C1 = self._content
+        aH = self._aH = max(aH,H0)
+        self.width = availWidth
+        if not self._C1:
+            self.height = aH
+        else:
+            W1,H1 = _listWrapOn(self._C1,availWidth,canv)
+            self.height = aH+H1
+        return self.width, self.height
+
+    def split(self,availWidth, availHeight):
+        if hasattr(self,'_wrapArgs'):
+            I = self._I
+            if self._wrapArgs!=(availWidth,availHeight) or getattr(I,'_oldDrawSize',None) is not None:
+                self._reset()
+                I._unRestrictSize()
+        W,H=self.wrap(availWidth,availHeight)
+        if self._aH>availHeight: return []
+        C1 = self._C1
+        if C1:
+            S = C1[0].split(availWidth,availHeight-self._aH)
+            if not S:
+                _C1 = []
+            else:
+                _C1 = [S[0]]
+                C1 = S[1:]+C1[1:]
+        else:
+            _C1 = []
+        return [ImageAndFlowables(
+                    self._I,
+                    self._C0+_C1,
+                    imageLeftPadding=self._ilpad,
+                    imageRightPadding=self._irpad,
+                    imageTopPadding=self._itpad,
+                    imageBottomPadding=self._ibpad,
+                    imageSide=self._side, imageHref=self.imageHref)
+                    ]+C1
+
+    def drawOn(self, canv, x, y, _sW=0):
+        if self._side=='left':
+            Ix = x + self._ilpad
+            Fx = Ix+ self._irpad + self._wI
+        else:
+            Ix = x + self.width-self._wI-self._irpad
+            Fx = x
+        self._I.drawOn(canv,Ix,y+self.height-self._itpad-self._hI)
+
+        if self.imageHref:
+            canv.linkURL(self.imageHref, (Ix, y+self.height-self._itpad-self._hI, Ix + self._wI, y+self.height), relative=1)
+
+        if self._C0:
+            _Container.drawOn(self, canv, Fx, y, content=self._C0, aW=self._iW)
+        if self._C1:
+            aW, aH = self._wrapArgs
+            _Container.drawOn(self, canv, x, y-self._aH,content=self._C1, aW=aW)
+
+    def _findSplit(self,canv,availWidth,availHeight,mergeSpace=1,obj=None):
+        '''return max width, required height for a list of flowables F'''
+        W = 0
+        H = 0
+        pS = sB = 0
+        atTop = 1
+        F = self._content
+        for i,f in enumerate(F):
+            w,h = f.wrapOn(canv,availWidth,0xfffffff)
+            if w<=_FUZZ or h<=_FUZZ: continue
+            W = max(W,w)
+            if not atTop:
+                s = f.getSpaceBefore()
+                if mergeSpace: s = max(s-pS,0)
+                H += s
+            else:
+                if obj is not None: obj._spaceBefore = f.getSpaceBefore()
+                atTop = 0
+            if H>=availHeight or w>availWidth:
+                return W, availHeight, F[:i],F[i:]
+            H += h
+            if H>availHeight:
+                from reportlab.platypus.paragraph import Paragraph
+                aH = availHeight-(H-h)
+                if isinstance(f,(Paragraph,Preformatted)):
+                    leading = f.style.leading
+                    nH = leading*int(aH/float(leading))+_FUZZ
+                    if nH1:
+            S[0] = TopPadder(S[0])
+        return S
+
+    def drawOn(self, canvas, x, y, _sW=0):
+        self.__f.drawOn(canvas,x,y-max(0,self.__dh-1e-8),_sW)
+
+    def __setattr__(self,a,v):
+        setattr(self.__f,a,v)
+
+    def __getattr__(self,a):
+        return getattr(self.__f,a)
+
+    def __delattr__(self,a):
+        delattr(self.__f,a)
+
+class DocAssign(NullDraw):
+    '''At wrap time this flowable evaluates var=expr in the doctemplate namespace'''
+    _ZEROSIZE=1
+    def __init__(self,var,expr,life='forever'):
+        Flowable.__init__(self)
+        self.args = var,expr,life
+
+    def funcWrap(self,aW,aH):
+        NS=self._doctemplateAttr('_nameSpace')
+        NS.update(dict(availableWidth=aW,availableHeight=aH))
+        try:
+            return self.func()
+        finally:
+            for k in 'availableWidth','availableHeight':
+                try:
+                    del NS[k]
+                except:
+                    pass
+
+    def func(self):
+        return self._doctemplateAttr('d'+self.__class__.__name__[1:])(*self.args)
+
+    def wrap(self,aW,aH):
+        self.funcWrap(aW,aH)
+        return 0,0
+
+class DocExec(DocAssign):
+    '''at wrap time exec stmt in doc._nameSpace'''
+    def __init__(self,stmt,lifetime='forever'):
+        Flowable.__init__(self)
+        self.args=stmt,lifetime
+
+class DocPara(DocAssign):
+    '''at wrap time create a paragraph with the value of expr as text
+    if format is specified it should use %(__expr__)s for string interpolation
+    of the expression expr (if any). It may also use %(name)s interpolations
+    for other variables in the namespace.
+    suitable defaults will be used if style and klass are None
+    '''
+    def __init__(self,expr,format=None,style=None,klass=None,escape=True):
+        Flowable.__init__(self)
+        self.expr=expr
+        self.format=format
+        self.style=style
+        self.klass=klass
+        self.escape=escape
+
+    def func(self):
+        expr = self.expr
+        if expr:
+            if not isinstance(expr,str): expr = str(expr)
+            return self._doctemplateAttr('docEval')(expr)
+
+    def add_content(self,*args):
+        self._doctemplateAttr('frame').add_generated_content(*args)
+
+    def get_value(self,aW,aH):
+        value = self.funcWrap(aW,aH)
+        if self.format:
+            NS=self._doctemplateAttr('_nameSpace').copy()
+            NS.update(dict(availableWidth=aW,availableHeight=aH))
+            NS['__expr__'] = value
+            value = self.format % NS
+        else:
+            value = str(value)
+        return value
+
+    def wrap(self,aW,aH):
+        value = self.get_value(aW,aH)
+        P = self.klass
+        if not P:
+            from reportlab.platypus.paragraph import Paragraph as P
+        style = self.style
+        if not style:
+            from reportlab.lib.styles import getSampleStyleSheet
+            style=getSampleStyleSheet()['Code']
+        if self.escape:
+            from xml.sax.saxutils import escape
+            value=escape(value)
+        self.add_content(P(value,style=style))
+        return 0,0
+
+class DocAssert(DocPara):
+    def __init__(self,cond,format=None):
+        Flowable.__init__(self)
+        self.expr=cond
+        self.format=format
+
+    def funcWrap(self,aW,aH):
+        self._cond = DocPara.funcWrap(self,aW,aH)
+        return self._cond
+
+    def wrap(self,aW,aH):
+        value = self.get_value(aW,aH)
+        if not bool(self._cond):
+            raise AssertionError(value)
+        return 0,0
+
+class DocIf(DocPara):
+    def __init__(self,cond,thenBlock,elseBlock=[]):
+        Flowable.__init__(self)
+        self.expr = cond
+        self.blocks = elseBlock or [],thenBlock
+
+    def checkBlock(self,block):
+        if not isinstance(block,(list,tuple)):
+            block = (block,)
+        return block
+
+    def wrap(self,aW,aH):
+        self.add_content(*self.checkBlock(self.blocks[int(bool(self.funcWrap(aW,aH)))]))
+        return 0,0
+
+class DocWhile(DocIf):
+    def __init__(self,cond,whileBlock):
+        Flowable.__init__(self)
+        self.expr = cond
+        self.block = self.checkBlock(whileBlock)
+
+    def wrap(self,aW,aH):
+        if bool(self.funcWrap(aW,aH)):
+            self.add_content(*(list(self.block)+[self]))
+        return 0,0
diff --git a/reportlab/platypus/frames.py b/reportlab/platypus/frames.py
new file mode 100644
index 00000000..81a3277c
--- /dev/null
+++ b/reportlab/platypus/frames.py
@@ -0,0 +1,282 @@
+#Copyright ReportLab Europe Ltd. 2000-2012
+#see license.txt for license details
+#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/platypus/frames.py
+
+__version__=''' $Id$ '''
+
+__doc__="""A frame is a container for content on a page.
+"""
+
+import logging
+logger = logging.getLogger('reportlab.platypus')
+
+_geomAttr=('x1', 'y1', 'width', 'height', 'leftPadding', 'bottomPadding', 'rightPadding', 'topPadding')
+from reportlab import rl_config, isPy3
+_FUZZ=rl_config._FUZZ
+
+class ShowBoundaryValue:
+    def __init__(self,color=(0,0,0),width=0.1):
+        self.color = color
+        self.width = width
+
+    if isPy3:
+        def __bool__(self):
+            return self.color is not None and self.width>=0
+    else:
+        def __nonzero__(self):
+            return self.color is not None and self.width>=0
+
+
+class Frame:
+    '''
+    A Frame is a piece of space in a document that is filled by the
+    "flowables" in the story.  For example in a book like document most
+    pages have the text paragraphs in one or two frames.  For generality
+    a page might have several frames (for example for 3 column text or
+    for text that wraps around a graphic).
+
+    After creation a Frame is not usually manipulated directly by the
+    applications program -- it is used internally by the platypus modules.
+
+    Here is a diagramatid abstraction for the definitional part of a Frame::
+
+                width                    x2,y2
+        +---------------------------------+
+        | l  top padding                r | h
+        | e +-------------------------+ i | e
+        | f |                         | g | i
+        | t |                         | h | g
+        |   |                         | t | h
+        | p |                         |   | t
+        | a |                         | p |
+        | d |                         | a |
+        |   |                         | d |
+        |   +-------------------------+   |
+        |    bottom padding               |
+        +---------------------------------+
+        (x1,y1) <-- lower left corner
+
+    NOTE!! Frames are stateful objects.  No single frame should be used in
+    two documents at the same time (especially in the presence of multithreading.
+    '''
+    def __init__(self, x1, y1, width,height, leftPadding=6, bottomPadding=6,
+            rightPadding=6, topPadding=6, id=None, showBoundary=0,
+            overlapAttachedSpace=None,_debug=None):
+        self.id = id
+        self._debug = _debug
+
+        #these say where it goes on the page
+        self.__dict__['_x1'] = x1
+        self.__dict__['_y1'] = y1
+        self.__dict__['_width'] = width
+        self.__dict__['_height'] = height
+
+        #these create some padding.
+        self.__dict__['_leftPadding'] = leftPadding
+        self.__dict__['_bottomPadding'] = bottomPadding
+        self.__dict__['_rightPadding'] = rightPadding
+        self.__dict__['_topPadding'] = topPadding
+
+        # if we want a boundary to be shown
+        self.showBoundary = showBoundary
+
+        if overlapAttachedSpace is None: overlapAttachedSpace = rl_config.overlapAttachedSpace
+        self._oASpace = overlapAttachedSpace
+        self._geom()
+        self._reset()
+
+    def __getattr__(self,a):
+        if a in _geomAttr: return self.__dict__['_'+a]
+        raise AttributeError(a)
+
+    def __setattr__(self,a,v):
+        if a in _geomAttr:
+            self.__dict__['_'+a] = v
+            self._geom()
+        else:
+            self.__dict__[a] = v
+
+    def _saveGeom(self, **kwds):
+        if not self.__dict__.setdefault('_savedGeom',{}):
+            for ga in _geomAttr:
+                ga = '_'+ga
+                self.__dict__['_savedGeom'][ga] = self.__dict__[ga]
+        for k,v in kwds.items():
+            setattr(self,k,v)
+
+    def _restoreGeom(self):
+        if self.__dict__.get('_savedGeom',None):
+            for ga in _geomAttr:
+                ga = '_'+ga
+                self.__dict__[ga] = self.__dict__[ga]['_savedGeom']
+                del self.__dict__['_savedGeom']
+            self._geom()
+
+    def _geom(self):
+        self._x2 = self._x1 + self._width
+        self._y2 = self._y1 + self._height
+        #efficiency
+        self._y1p = self._y1 + self._bottomPadding
+        #work out the available space
+        self._aW = self._x2 - self._x1 - self._leftPadding - self._rightPadding
+        self._aH = self._y2 - self._y1p - self._topPadding
+
+    def _reset(self):
+        self._restoreGeom()
+        #drawing starts at top left
+        self._x = self._x1 + self._leftPadding
+        self._y = self._y2 - self._topPadding
+        self._atTop = 1
+        self._prevASpace = 0
+
+        # these two should NOT be set on a frame.
+        # they are used when Indenter flowables want
+        # to adjust edges e.g. to do nested lists
+        self._leftExtraIndent = 0.0
+        self._rightExtraIndent = 0.0
+
+    def _getAvailableWidth(self):
+        return self._aW - self._leftExtraIndent - self._rightExtraIndent
+
+    def _add(self, flowable, canv, trySplit=0):
+        """ Draws the flowable at the current position.
+        Returns 1 if successful, 0 if it would not fit.
+        Raises a LayoutError if the object is too wide,
+        or if it is too high for a totally empty frame,
+        to avoid infinite loops"""
+        flowable._frame = self
+        flowable.canv = canv #so they can use stringWidth etc
+        try:
+            if getattr(flowable,'frameAction',None):
+                flowable.frameAction(self)
+                return 1
+
+            y = self._y
+            p = self._y1p
+            s = 0
+            aW = self._getAvailableWidth()
+            if not self._atTop:
+                s =flowable.getSpaceBefore()
+                if self._oASpace:
+                    if getattr(flowable,'_SPACETRANSFER',False):
+                        s = self._prevASpace
+                    s = max(s-self._prevASpace,0)
+            h = y - p - s
+            if h>0:
+                w, h = flowable.wrap(aW, h)
+            else:
+                return 0
+
+            h += s
+            y -= h
+
+            if y < p-_FUZZ:
+                if not rl_config.allowTableBoundsErrors and ((h>self._aH or w>aW) and not trySplit):
+                    from reportlab.platypus.doctemplate import LayoutError
+                    raise LayoutError("Flowable %s (%sx%s points) too large for frame (%sx%s points)." % (
+                        flowable.__class__, w,h, aW,self._aH))
+                return 0
+            else:
+                #now we can draw it, and update the current point.
+                s = flowable.getSpaceAfter()
+                fbg = getattr(self,'_frameBGs',None)
+                if fbg:
+                    fbgl, fbgr, fbgc = fbg[-1]
+                    fbw = self._width-fbgl-fbgr
+                    fbh = y + h + s
+                    fby = max(p,y-s)
+                    fbh = max(0,fbh-fby)
+                    if abs(fbw)>_FUZZ and abs(fbh)>_FUZZ:
+                        canv.saveState()
+                        canv.setFillColor(fbgc)
+                        canv.rect(self._x1+fbgl,fby,fbw,fbh,stroke=0,fill=1)
+                        canv.restoreState()
+
+                flowable.drawOn(canv, self._x + self._leftExtraIndent, y, _sW=aW-w)
+                flowable.canv=canv
+                if self._debug: logger.debug('drew %s' % flowable.identity())
+                y -= s
+                if self._oASpace:
+                    if getattr(flowable,'_SPACETRANSFER',False):
+                        s = self._prevASpace
+                    self._prevASpace = s
+                if y!=self._y: self._atTop = 0
+                self._y = y
+                return 1
+        finally:
+            #sometimes canv/_frame aren't still on the flowable
+            for a in ('canv', '_frame'):
+                if hasattr(flowable,a):
+                    delattr(flowable,a)
+
+    add = _add
+
+    def split(self,flowable,canv):
+        '''Ask the flowable to split using up the available space.'''
+        y = self._y
+        p = self._y1p
+        s = 0
+        if not self._atTop:
+            s = flowable.getSpaceBefore()
+            if self._oASpace:
+                s = max(s-self._prevASpace,0)
+        flowable._frame = self                  #some flowables might need these
+        flowable.canv = canv        
+        try:
+            r = flowable.split(self._aW, y-p-s)
+        finally:
+            #sometimes canv/_frame aren't still on the flowable
+            for a in ('canv', '_frame'):
+                if hasattr(flowable,a):
+                    delattr(flowable,a)
+        return r
+
+
+    def drawBoundary(self,canv):
+        "draw the frame boundary as a rectangle (primarily for debugging)."
+        from reportlab.lib.colors import Color, toColor
+        sb = self.showBoundary
+        ss = isinstance(sb,(str,tuple,list)) or isinstance(sb,Color)
+        w = -1
+        if ss:
+            c = toColor(sb,self)
+            ss = c is not self
+        elif isinstance(sb,ShowBoundaryValue) and sb:
+            c = toColor(sb.color,self)
+            w = sb.width
+            ss = c is not self
+        if ss:
+            canv.saveState()
+            canv.setStrokeColor(c)
+            if w>=0:
+                canv.setLineWidth(w)
+        canv.rect(
+                self._x1,
+                self._y1,
+                self._x2 - self._x1,
+                self._y2 - self._y1
+                )
+        if ss: canv.restoreState()
+
+    def addFromList(self, drawlist, canv):
+        """Consumes objects from the front of the list until the
+        frame is full.  If it cannot fit one object, raises
+        an exception."""
+
+        if self._debug: logger.debug("enter Frame.addFromlist() for frame %s" % self.id)
+        if self.showBoundary:
+            self.drawBoundary(canv)
+
+        while len(drawlist) > 0:
+            head = drawlist[0]
+            if self.add(head,canv,trySplit=0):
+                del drawlist[0]
+            else:
+                #leave it in the list for later
+                break
+
+    def add_generated_content(self,*C):
+        self.__dict__.setdefault('_generated_content',[]).extend(C)
+
+    def _aSpaceString(self):
+        return '(%s x %s%s)' % (self._getAvailableWidth(),self._aH,self._atTop and '*' or '')
diff --git a/reportlab/platypus/para.py b/reportlab/platypus/para.py
new file mode 100644
index 00000000..898ff8a3
--- /dev/null
+++ b/reportlab/platypus/para.py
@@ -0,0 +1,2366 @@
+"""new experimental paragraph implementation
+
+Intended to allow support for paragraphs in paragraphs, hotlinks,
+embedded flowables, and underlining.  The main entry point is the
+function
+
+def Paragraph(text, style, bulletText=None, frags=None)
+
+Which is intended to be plug compatible with the "usual" platypus
+paragraph except that it supports more functionality.
+
+In this implementation you may embed paragraphs inside paragraphs
+to create hierarchically organized documents.
+
+This implementation adds the following paragraph-like tags (which
+support the same attributes as paragraphs, for font specification, etc).
+
+- Unnumberred lists (ala html)::
+
+    
    +
  • first one
  • +
  • second one
  • +
+ + +Also