Codebase list libpdf-builder-perl / 307e8d3
New upstream version 3.020 gregor herrmann 3 years ago
142 changed file(s) with 2289 addition(s) and 466 deletion(s). Raw diff Collapse all Expand all
00 See also INFO/Changes-ver_2 for changes released for PDF::API2, and
11 incorporated into PDF::Builder.
22 See also INFO/Changes_2019 for earlier version 3 release logs.
3
4 3.020 2020-11-29
5
6 lib/PDF/Builder/Content-Outline-NamedDestination.pm, INFO/DEPRECATED
7 Rename previously deprecated names "spline" (to "qbspline") and "pdfile"
8 (to "pdf_file").
9
10 examples/042_links
11 Add some examples showing non-default positioning (fit) on
12 target PDF's page.
13
14 lib/PDF/Builder/Basic/PDF/File.pm
15 Extend cross-reference stream handling (read-in PDFs) to cover field
16 widths of 5, 6, or 7 bytes (40-, 48-, or 56-bit integers). Special case
17 of 8 byte (64-bit integer) where top 32 bits are all 0, is treated as
18 32-bit integer to avoid requiring a 64-bit Perl build just for unpacking
19 this field.
20
21 lib/PDF/Builder.pm, lib/PDF/Builder/Docs.pm
22 Per [RT 130722, RT 133131, et al.] get any /Version override (in /Catalog)
23 and update the read-in PDF version (beyond 1.4, even if the PDF header
24 still claims 1.4). This minimizes extraneous warnings about having to
25 bump up the PDF version from what is claimed in the header.
26
27 Cross-check parent/kids links, report orphaned objects, report objects
28 referenced but not defined, report missing Info and Root objects, etc.
29 The input PDF file or string is not changed, but at least it can give
30 you an idea of why an error occurs, or the resulting PDF does not work
31 correctly.
32
33 lib/PDF/Builder/Basic/PDF/File.pm, INFO/RoadMap
34 Per [RT 133131, Vadim Repin's fix], change Quad int unpack code from Q
35 to Q> to indicate "Big-Endian" byte order (MSB at left) for incoming data
36 field in a cross-reference stream. Apparently, with just Q, Perl will
37 assume the doubleword int is native format (for instance, Little-Endian
38 on an Intel chip).
39 Note: This is a PDF 1.5+ feature (cross-reference streams) and has
40 no business being in a PDF 1.4 file (the original bug report).
41 Also add warning if imported file declared to be PDF 1.4 (or lower), as
42 cross-reference streams are a PDF 1.5 feature. Earlier fix had added
43 cross-reference stream support, but it really doesn't belong in PDF 1.4.
44
45 lib/PDF/Builder/Outline.pm, lib/PDF/Builder/Basic/PDF/Objind.pm
46 Per [RT 131657, Vadim Repin's fix] add weaken statements to eliminate
47 "Deep Recursion" error messages.
48
49 lib/PDF/Builder/Matrix.pm
50 Per latest changes to PDF::API2, some code cleanup in Matrix.pm (no
51 functional change except for adding some diagnostic carps).
52
53 lib/PDF/Builder.pm
54 Per [PR 139, by ppisar], replace some hard-coded checks for
55 Graphics::TIFF and Image::PNG::Libpng with calls to LA_GT() and LA_IPL().
56
57 docs/buildDoc.pl, lib/PDF/Builder/Basic/PDF.pm, MANIFEST
58 Add NAVIGATION LINKS section to go Up to parent(s), sideways to
59 Siblings, and Down to children. This enables you to get from any place
60 in the docs to any place else without (usually) having to go all the way
61 back up to index.html. PDF.pm added just for a place to put links (no
62 code).
63
64 lib/PDF/Builder.pm, INFO/RoadMap minor updates
65
66 lib/PDF/Builder.pm, README, INFO/LICENSE
67 Make license-related text more consistent, and attempt to clarify the
68 relationship between the LGPL 2.1 master license and the various other
69 licenses that some files are under, as well as the ability to
70 redistribute under a higher version of LGPL. ref [CTS 35]
71
72 Makefile.PL, t/author-critic.t, tools/1_pc.pl
73 Update to fix some perlcritic warnings, enable author-critic (not useful,
74 as tools/1_pc.pl does a better job of it). Suggested by 'carygravel',
75 but [PR 135] rejected, as 1_pc is a superset of author-critic function.
76 Can't change .perlcriticrc SEVERITY from 5 to 4, as the GitHub Actions
77 CI testing appears to be using it, leading to a lot of errors.
78
79 lib/PDF/Builder/Resource/XObject/Image/TIFF/File_GT.pm, t/tiff.t,
80 lib/PDF/Builder/Resource/XObject/Image/TIFF_GT.pm, Makefile.PL,
81 lib/PDF/Builder.pm, lib/PDF/Builder/Resource/XObject/Image/TIFF.pm,
82 Fix problem with reading colormap from TIFF [GH 133], by 'carygravel'.
83 Note that this requires upgrade of Graphics::TIFF from 6 to 7.
84
85 t/tiff.t upgrade so tests 10 and 11 are no longer always skipped. This
86 works only on a Linux system (definitely not on Windows), and makes use
87 of ImageMagick and Linux utilities 'convert' and 'tiffcp'. Graphics::TIFF
88 is needed for test 10, and test 9 (alpha layer) is still skipped. Thanks
89 to GitHub user 'carygravel' for the upgrade.
90
91 INFO/DEPRECATED add a couple long-deprecated items ("PDFStr" and
92 "PDFUtf") that were missing from this file.
93
94 INFO/RoadMap, lib/PDF/Builder/Docs.pm add discussion on why images
95 (especially JPEG) are sometimes rotated and/or flipped, and what can be
96 done about it.
97
98 t/fonts-synfont.t, t/fonts-ttf.t fix a couple paths to DejaVu fonts on
99 certain Linux boxes. From 'gregoa' at Debian Perl Group.
100
101 lib/PDF/Builder/Resource/XObject/Image/PNM.pm
102 Bi-level (1 bit per pixel) PNM/PBM image was not being handled
103 correctly if the row length (width) was not a multiple of 8. Not enough
104 data was copied over to the PDF. Continuation of [RT 132844].
105 Almost complete rewrite of PNM.pm to properly support all combinations
106 of comments in the header, and support "plain" (ASCII) image files
107 (P1..P3) and 16 bit samples for grayscale and RGB. Not yet supporting
108 multiple images per file, as I don't have any firm definition!
109
110 lib/PDF/Builder/Resource/XObject/Image/PNG_IPL.pm
111 Make use of the new 'split_alpha' call in new release 0.47 of
112 Image::PNG::Libpng (this version specified as minimum, for optional
113 library installation). This brings the speed for RGB and Gray scale
114 with Alpha channels up to reasonable levels, as the 'vec' call is no
115 longer called (4 or 8 times per pixel). Note that in contrast to
116 PDF::API2, both 8 and 16bps samples are supported, and Gray scale is
117 supported, at high speed; not just 8bps RGBA.
118
119 lib/PDF/Builder/Docs.pm, Makefile.PL, README, t/00-all-usable.t
120 PDF::Builder will (again) attempt to install or upgrade OPTIONAL
121 libraries (see README). Includes a warning in Makefile.PL not to be
122 unduly alarmed if an optional install should fail. The user is given
123 a choice of selecting none/all/specific optional libraries when
124 running Makefile.PL (default "all").
125
126 README add instructions for installing on pre-5.020 Perls, which may be
127 adaptable to other OS's and Perls. Note that there's no guarantee that
128 PDF::Builder will actually RUN on older Perls! (But you're welcome to
129 try.)
130
131 lib/PDF/Builder/Docs-Content.pm, lib/PDF/Builder/Content/Text.pm
132 Fix spelling errors/typos, per report by 'carygravel'.
133
134 lib/PDF/Builder/Resource/PaperSizes.pm
135 Fix a couple missized entries (B7 and jr-Legal), added a bunch more
136 sizes (mostly archaic American and British sizes): dbill, statement
137 (= student), half-letter (= student), old-paper, b-plus
138 (B+/Super-B/A3+/super-A3), arch-a, arch-b, arch-c, arch-d, arch-e,
139 arch-e1, pott, post, large-post, crown, large-crown, demy, small-demy,
140 medium, royal, small-royal, super-royal, imperial, a7, a8, a9, a10.
141
142 Note that some "standard" sizes, such as broadsheet and foolscap, seem
143 to have a different size specification depending on where you look. You
144 should check that the size used matches your actual paper supply, and to
145 either update PaperSizes.pm to match, or specify the MediaBox in points
146 instead of by name. This is probably a good idea with any unusual,
147 large, archaic, or special-order paper... you want to check what its
148 actual size is before going through a lot of expensive failed printing!
149
150 examples/HarfBuzz.pl, examples/resources/HarfBuzz_example.pdf
151 In the updated 3.019 example, note that the entire AdobeMingStd-Light.otf
152 font (ttfont call) appears to be embedded, rather than just the subset.
153 This resulted in 3.019 being about 8MB larger than 3.018's version! It may
154 be related to bug [RT 130041]. Use caution when embedding CJK fonts, even
155 when not using the cjkfont call, as at least some apparently don't subset.
156 I replaced the font with AdobeGothicStd-Light.otf, which appears to embed
157 just a subset of the font, greatly reducing the size of the PDF file.
3158
4159 3.019 2020-07-27
5160
26181
27182 examples/042_links, examples/README, examples/examples_output,
28183 tools/3_examples.pl, lib/PDF/Builder/Annotation.pm, MANIFEST
29 Improved documentation of annotation-based links: PDF links and targets.
184 Per [CTS 29], improved documentation of annotation-based links: PDF links
185 and targets.
30186
31187 lib/PDF/Builder/Content.pm, lib/PDF/Builder/Resource/XObject/Image/PNM.pm
32188 image() and form_image() calls default x,y to 0,0, so can call without
77 user in an emergency), but eventually they WILL be removed.
88
99 In order of scheduled removal date:
10
11 spline method in Content.pm
12 This functionality was renamed to qbspline() [quadratic Bezier spline].
13 Simply rename any call to "spline" to "qbspline". spline is scheduled to
14 be removed on or after June, 2020.
15
16 pdfile method in Outline.pm, NamedDestination.pm
17 This functionality was renamed to pdf_file(). Simply rename any call to
18 "pdfile" to "pdf_file". pdfile is scheduled to be removed on or after
19 October, 2020.
2010
2111 -slant option in Synfont.pm
2212 This option was renamed to -condense, as it is the factor to condense
3727 global and current page bounding boxes (media, crop, bleed, trim, art).
3828 The get routines are now obsolete, and may be removed on or after
3929 August, 2021.
30
31 PDFStr() method in Basic/PDF/Utils.pm
32 Use PDFString() instead. May be removed on or after October, 2022.
33
34 PDFUtf() method in Basic/PDF/Utils.pm
35 Use PDFString() instead. May be removed on or after October, 2022.
4036
4137 *** If I have missed any deprecated interfaces, please let me know! ***
4238
133129 "pdfile" to "pdf_file". pdfile is scheduled to be removed on or after
134130 November, 2019. [Removed November, 2019]
135131
132 spline method in Content.pm
133 This functionality was renamed to qbspline() [quadratic Bezier spline].
134 Simply rename any call to "spline" to "qbspline". spline is scheduled to
135 be removed on or after June, 2020. [Removed November, 2020]
136
137 pdfile method in Outline.pm, NamedDestination.pm
138 This functionality was renamed to pdf_file(). Simply rename any call to
139 "pdfile" to "pdf_file". pdfile is scheduled to be removed on or after
140 October, 2020. [Removed November, 2020]
141
0 This software is Copyright (c) 2017 by Phil M. Perry.
0 This software is Copyright (c) 2017-2020 by Phil M. Perry.
1 Previous copyrights are held by Steve Simms, Alfred Reibenschuh, et al.
2
3 Note that some files within this software are under DIFFERENT licenses (than
4 LGPL 2.1). These include (but are not necessarily limited to)
5 PDF::Builder::Matrix (same license as Perl itself), and
6 PDF::Builder::Basic::PDF files (except for the Filters and Literal.pm), which
7 are under the Perl Artistic License. If not otherwise stated in such a file,
8 the overall license is LGPL 2.1, and you may redistribute and/or modify this
9 software under the terms of the indicated license. For LGPL, you are permitted
10 to redistribute and/or modify the software under a version higher than 2.1,
11 at your option).
12
13 This library is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
15 PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
116
217 This is free software, licensed under:
318
419 The GNU Lesser General Public License, Version 2.1, February 1999
20
21 =============================================================================
22 == Original LGPL 2.1 license text ==
23 =============================================================================
524
625 The GNU Lesser General Public License (LGPL)
726 Version 2.1, February 1999
0 Road Map for Future Development of PDF::Builder 11 September 2019
0 Road Map for Future Development of PDF::Builder 22 November 2020
11
22 In order to encourage others to contribute code and/or algorithms to the
33 effort, I am publishing this road map of where I would like the product to go.
7575
7676 E. JPEG2000 image file support (CTS 12): I don't know if this is worth it, as
7777 there seems to be very little use of this, but if someone is interested,
78 have at it...
78 have at it... any other newish image formats that PDF can support?
7979
8080 F. Fix Bar Code generation (CTS 1): there seems to be something quite wrong
8181 with the current bar code generation, so it's possible that no one is using
129129 traditional way, e.g., to the next n8-th column) is useful only for
130130 monospaced fonts, and no changes in font size in the line. Thus, tab stops
131131 would be more useful when defined by some absolute dimension (e.g., inches
132 or ems) of column position. Second, tabbing is usually done to get text
132 or mms) of column position. Second, tabbing is usually done to get text
133133 columns (sub columns), which involves a lot of manual setup and twiddling of
134134 text. Consider using a TABLE within the column or page to get text organized
135135 into the desired format (see "tbl" addition in section II).
141141
142142 L. Determine what it is about "CJK" fonts (.ttf and .otf) that makes them
143143 incompatible with synfont [RT 130040] and embedding [RT 130041], and fix if
144 possible. Are separate CJK fonts even necessary these days?
144 possible. Are separate CJK fonts even necessary these days? Also note that
145 many CJK fonts refuse to "subset" when embedded (the entire font gets
146 embedded, even if you only use a handful of glyphs!).
145147
146148 M. Add decorative rectangular box effects around sections of text. With or
147149 without border (allow rounded corners) and background color, drop shadows
148150 (3D effect), etc. The box is drawn at given dimensions and location, and
149151 the text written over it in the usual manner. Content clipping might also
150 be supported.
151
152 I. Extend HarfBuzz::Shaper use (see A.) to flow paragraphs and sections (fill)
152 be supported. See PDF::Table for drawing rules (and borders) for ideas, as
153 well as block background colors (gfx_bg object before text object).
154
155 N. Extend HarfBuzz::Shaper use (see A.) to flow paragraphs and sections (fill)
153156 to match capability of existing text-fill calls. Architect so as to extend
154157 easily to full paragraph shaping and "pouring" text into arbitrary columns,
155158 with balancing. Justification to avoid ragged-left or -right needs to be
156159 handled carefully for connected glyphs (e.g., Arabic, Indic, cursive Latin).
160
161 Treat HarfBuzz::Shaper handled-fonts just like any other font when it comes
162 to various text-handling routines (including length, justifying and aligning
163 text, filling lines, paragraph, section, textlabel, etc.).
164
165 O. ## DONE ## release 3.020
166 Support for PNM and related graphics images. See RT 132844.
167
168 P. Look into using TeX::Hyphen or Text::Hyphen to split words properly. The
169 latter supports 3 languages besides English. Both use TeX (Knuth-Liang)
170 algorithms. Eventually need means to override built-in hyphenation (e.g.,
171 force 're-cord' or 'rec-ord', per context), similar to ligature control.
172 One way would be to insert soft-hypen ­, this might require all
173 syllable breaks to be so marked, since TH might not see it any more.
174 Use any place where a string is flowed into multiple lines, and eventually
175 for complete paragraph shaping. Retain camelCase and punctuation/numeric
176 splitting as fallback for non-words. Consider own built-in version of either
177 TH, using CTAN directly (would take rewrite of the Perl code?), if can't
178 get owner to upgrade it.
179
180 Q. ## DONE ## release 3.020
181 Look at Basic/PDF/File.pm 'Q>' unpack (ref RT 133131). Supposedly will not
182 run on a 32 bit platform -- will it work on such platform to check if high
183 33 bits are all 0, and convert the low 32 bits to a fullword integer?
157184
158185 =============================================================================
159186 II. Items to add to a separate area (new module or sub-module)
168195 paragraph shaping algorithms to flow text into a space in a visually
169196 pleasing manner, while obeying widows and orphans constraints (as well as
170197 not orphaning headings). Pango may help here with line and word splitting.
198 ** Look into item P in section I **
199 Text::KnuthPlass might be usable for general paragraph setup (allows non-
200 rectangular paragaph), uses Text::Hyphen internally, don't know yet if it
201 does the full Knuth-Plass "rivers of white" and "too many hyphens in a row"
202 bit. Interaction with Text::Layout stuff (font, size, changes)?
203
204 I've gotten Text::Hyphen and Text::KnuthPlass working, and tests suggest
205 that they (mostly) work great. Unfortunately, KP doesn't build on all
206 systems (a simple fix), so I may have to forcibly take it over if the owner
207 doesn't respond reasonably soon, or just take it into the product. Hyphen
208 could use some improvements for multilanguage support, also waiting for a
209 response. Some sort of "virtual printing (see 'B') would be necessary, as
210 dealing with widows and orphans would be much easier that way.
171211
172212 B. Virtual pages: this would be related to item (A) (paragraph shaping), where
173213 PDF code would not be immediately written to an output page, but would be
179219 virtuality (virtual line output) could be useful for resetting a baseline
180220 to accommodate a change in font size -- this might involve tagging a word or
181221 block of words of the same height.
222
223 PDF::Table product (or table functionality within Builder) could make use
224 of virtual printing to "print" to a mini-page within a cell (fixed width,
225 min/max height). If it doesn't fit on the page, decide where to split row
226 to avoid widows and orphans. Also knowing cell height and row height, can
227 vertically align a cell's contents.
182228
183229 C. General text flowing capability, to fill irregularly shaped columns (such
184230 as with intruding inserts or margin notes) in a balanced manner, including
234280
235281 Page background color or pattern should extend to the full size of the page
236282 and not end when content ends part way down the page. Remind users that
237 most printers will not print all the way to the edge.
283 most printers will not print all the way to the edge. See Boxes.pl example.
284
285 H. Incorporate PDF::Table into PDF::Builder::Table. Simplify it somewhat (e.g.,
286 instead of separate line-width and color settings, use a list: w (width in
287 points with default color and solid line), or [w, color, optional-dash-
288 pattern]. Use it for borders and rules, and possibly frames. A "frame" would
289 be the enclosure for the table, and would be either a line spec or a width
290 and pattern (3D raised, 3D sunken, sunken table, raised table, floating
291 table with shadow, etc.). A "rule" would be horizontal and vertical
292 divider lines, and a "border" would be cell dividers ([w, color, margin-to-
293 cell edge, optional-dash-pattern]). Other simplifications and consolidations
294 of settings as justified (do not have to maintain absolute compatibility
295 with existing PDF::Table). Tables continued to the next page would not get
296 a full frame at the bottom/top, but a heavy dashed line (if breaking in
297 middle of a cell) or heavy solid line (if breaking at a row boundary). It
298 might be good not to automatically create a next page and start outputting
299 the rest of the table, but hold the contents and alert the programmer that
300 at least one more call is needed to finish.
301
302 Currently, PDF::Table basically equalizes column widths as much as it can,
303 but consider a starting point of relative and/or absolute column widths,
304 like many other table implementations. Some columns absolute widths, and
305 remaining space divided up even among *'s (with a column N*), subject to
306 minimum and maximum widths.
307
308 Within a cell, ideally it would be treated as a mini-page, with all the
309 normal PDF construction capabilities including paragraph shaping, flow into
310 column(s), images, etc. This would be better than the "text_block" used in
311 PDF::Table (more uniform coding and treatment), although some ideas from
312 text_block might find a home. However, such complex treatment (a table
313 could embed a table) requires virtual pages to permit a lot of rearrangement.
314
315 I. Consider Optional Content Groups (Layers), per 32000-2008 section 8.11.
316 This permits drawings to be shown by layer, or a watermark/copyright layer
317 to show only on printing.
318
319 J. ## DONE ## release 3.020 (documentation improved)
320 Per wkHTMLtoPDF issue 4846, at least some phone cameras output "portrait"
321 mode photos in landscape mode (rotated), with an "orientation" tag. JPEG
322 (at least) image handling may need a rotation flag in the call, and/or
323 pay attention to the Exif orientation flag. Confirmed that
324 Builder JPEG support does NOT respect the orientation flag.
325 https://www.google.com/search?client=firefox-b-1-d&q=jpeg+orientation+metadata
326 Unfortunately, there are a number of ways to specify the orientation flag
327 including XML '<exif:Orientation>Top-left</exif::Orientation>' and buried
328 somewhere in the Exif or JFIF header of the file. It might be best to ask
329 the image what its orientation is, and leave translation and rotation of
330 the placed image to user code, rather than trying to flip the contents of
331 the image file directly. See writeup in Docs.pm.
332
333 K. A means to update PDF content already written to the $pdf data structure,
334 but not yet written to file. This could involve moving a text write (one
335 or more translates) to somewhere else on the page, or even moving from one
336 page to another. More general editing of material already "written" out,
337 such as changing a font size or a color -- would need a way to find the
338 desired content to be modified. Ability to erase content or move it from
339 page to page (e.g., started a table and then found it wouldn't fit on one
340 page -- move it to the top of the next page to allow display on a single
341 page). If virtual pages, design with all this in mind, so easy to update
342 content before being "written" out. If nothing is written to the PDF file
343 until the end (save or saveas), this might even supersede virtual pages.
344
345 L. (See B and H items above) Consider a $page->subpage(x, y, w, h, opts) to
346 subclass a page into a restricted area (not necessarily rectangular, or
347 bounded in height). Things like columns and table cells could then be
348 treated as normal pages (inherit text and graphics contexts?) and anything
349 could be put into them. May want to wait until have virtual write
350 capability rather than writing to file right away, for fitting table cells
351 into a page, and balancing columns. Once in, build-in PDF::Table capability
352 as PDF::Builder::Table, and can have arbitrary content in a table cell.
238353
239354 =============================================================================
7373 examples/Windows/027_winfont
7474 examples/Windows/Win32.pm
7575 lib/PDF/Builder.pm
76 lib/PDF/Builder/Basic/PDF.pm
7677 lib/PDF/Builder/Basic/PDF/Filter/ASCII85Decode.pm
7778 lib/PDF/Builder/Basic/PDF/Filter/ASCIIHexDecode.pm
7879 lib/PDF/Builder/Basic/PDF/Filter/FlateDecode.pm
33 "Phil Perry <phil4597@catskilltech.com>"
44 ],
55 "dynamic_config" : 1,
6 "generated_by" : "ExtUtils::MakeMaker version 7.46, CPAN::Meta::Converter version 2.150010",
6 "generated_by" : "ExtUtils::MakeMaker version 7.56, CPAN::Meta::Converter version 2.150010",
77 "license" : [
88 "open_source"
99 ],
5656 "web" : "https://github.com/PhilterPaper/Perl-PDF-Builder"
5757 }
5858 },
59 "version" : "3.019",
59 "version" : "3.020",
6060 "x_serialization_backend" : "JSON::PP version 4.05"
6161 }
88 configure_requires:
99 ExtUtils::MakeMaker: '6.5503'
1010 dynamic_config: 1
11 generated_by: 'ExtUtils::MakeMaker version 7.46, CPAN::Meta::Converter version 2.150010'
11 generated_by: 'ExtUtils::MakeMaker version 7.56, CPAN::Meta::Converter version 2.150010'
1212 license: open_source
1313 meta-spec:
1414 url: http://module-build.sourceforge.net/META-spec-v1.4.html
2626 bugtracker: https://github.com/PhilterPaper/Perl-PDF-Builder/issues
2727 homepage: https://www.catskilltech.com
2828 repository: git://github.com/PhilterPaper/Perl-PDF-Builder.git
29 version: '3.019'
29 version: '3.020'
3030 x_serialization_backend: 'CPAN::Meta::YAML version 0.018'
77 my $PERL_version = '5.020000'; # can't use in "use" statement above! eval?
88 # could read from .perl-version file otherwise
99 my $MakeMaker_version = '6.5503';
10 my $version = '3.019'; # PDFbuild.pl updates from 'version' file
10 my $version = '3.020'; # PDFbuild.pl updates from 'version' file
11
12 # optional libraries... prompt user whether or not to install
13 # nice to have but not vital for many users
14 # if one fails to install, it might alarm the user, but installation of
15 # PDF::Builder can still proceed
16 # user can remove any optional installed library if they don't need it
17 # and want to reclaim the space
18 # update t/00-all-usable.t to exclude modules using these libraries!
19 my @choice_list = ( # use array to guarantee order
20 # 'a' and 'n' are reserved, do not use as key [0]
21 # [1] is actual library name [2] is minimum version [3] description
22 ["t", "Graphics::TIFF", 7, "TIFF image support"],
23 # improved TIFF image processing
24 ["p", "Image::PNG::Libpng", 0.47, "PNG image support"],
25 # advanced/fast PNG image processing
26 ["h", "HarfBuzz::Shaper", 0.23, "complex script support"],
27 # text shaping for Latin script ligatures and kerning, and for
28 # many complex scripts both LTR and RTL directions.
29 );
1130
1231 # EVERY RELEASE: check https://www.cpan.org/src/ "First release in each branch
1332 # of Perl" (NOT "Latest releases in each branch of Perl"!) and subtract
2443 # for future consideration
2544 #my $master = 'lib/PDF/Builder.pm';
2645 #my $version = MM->parse_version($master);
46
47 # prompt routine lifted from IO::Socket::SSL, and modified to allow
48 # arbitrary choices (not just y and n). NOT checked: that default is
49 # among choices, and default is lowercase!
50 # for the original Y/n, choices 'yn' max 1 default 'y' or 'n'
51 local $| = 1;
52
53 my $make_choice = sub {
54 my ($msg, $choices, $max, $default) = @_;
55 return $default if defined $default && $ENV{PERL_MM_USE_DEFAULT};
56 # Taken from ExtUtils::MakeMaker 6.16 (Michael Schwern) so that
57 # the prompt() function can be emulated for older versions of ExtUtils::MakeMaker.
58 while ( -t STDIN && (-t STDOUT || !(-f STDOUT || -c STDOUT))) {
59 print "$msg ";
60 my $choice = <>;
61 $choice =~ s/\s//g; # strip off whitespace
62 if (length($choice) > $max) { next; } # too many entries?
63 $choice ||= $default;
64 next if $choice !~ m/^([$choices]+)$/i;
65 return lc($1);
66 }
67
68 return $default;
69 };
2770
2871 my %WriteMakefileArgs =
2972 (
4285 "ExtUtils::MakeMaker" => $MakeMaker_version,
4386 },
4487
45 # BUILD_REQUIRES => {
88 # BUILD_REQUIRES => { # mandatory prereqs listed here
4689 # },
4790
4891 TEST_REQUIRES => {
89132
90133 },
91134
92 # optional libraries -- nice to have but not vital for most users
93 # if one fails to install, it might alarm the user, but installation of
94 # PDF::Builder can still proceed
95 # user can remove any optional installed library if they don't need it
96 # and want to reclaim the space
97 # update t/00-all-usable.t to exclude modules using these libraries!
98 ## recommends => {
99 ## 'Graphics::TIFF' => 0, # TIFF image processing
100 ## 'Image::PNG::Libpng' => 0, # advanced/fast PNG image processing
101 ## 'HarfBuzz::Shaper' => 1.7.7, # text shaping for Latin script ligatures
102 ## # and kerning, and for many complex
103 ## # scripts both LTR and RTL directions.
104 ## },
135 # recommends (optional prereqs) goes here
105136
106137 },
107138
117148 # $WriteMakefileArgs{PREREQ_PM}{'MacPerl'} = '0';
118149 #}
119150
151 my ($prompt, $i, $c, $all_list);
152 my $list_len = scalar(@choice_list);
153 # build multi-line prompt and output it
154 if (scalar @choice_list > 0) { # in case all disabled!
155 $prompt = "Attempt to install or update optional prereq libraries?\n".
156 " a (default) = install all choices listed below\n".
157 " n = do NOT install any of them\n".
158 " or enter 1 to $list_len of the following choices:\n";
159 $all_list = '';
160 for ($i = 0; $i < $list_len; $i++) {
161 $all_list .= $choice_list[$i][0];
162 $prompt .= " $choice_list[$i][0] = install/update $choice_list[$i][1] ($choice_list[$i][3] support)";
163 if ($i < $list_len-1) { $prompt .= "\n"; }
164 }
165 $prompt .= " [A|n|{".join('|', split //,$all_list)."}]";
166
167 $c = $make_choice->( $prompt, 'an'.$all_list, $list_len, 'a' );
168 } else {
169 $c = 'n'; # default if nothing available
170 }
171 # $c should have one or more of a,n (contradictory!) t,p,h
172
173 if ($c !~ m/n/) { # remind user that librarie(s) to be installed/updated
174 print <<END;
175 ===========================================================================
176 The installation process will attempt to install or update several OPTIONAL
177 prerequisite packages. If one or more should fail to install, Don't Panic
178 -- you will still be able to run PDF::Builder, but may not be able to use
179 some advanced features. See the README file for more information.
180 ===========================================================================
181 END
182 if ($c =~ m/a/) { $c = $all_list; }
183
184 # $c is one or more choices (no 'a' or 'n')
185 # build 'recommends' entry into %WriteMakefileArgs
186 for ($i = 0; $i < $list_len; $i++) {
187 if (index($c, $choice_list[$i][0]) < 0) { next; }
188 $WriteMakefileArgs{'META_MERGE'}{'recommends'}{
189 "$choice_list[$i][1]"} = $choice_list[$i][2];
190 }
191 }
192
120193 WriteMakefile(%WriteMakefileArgs);
1212 Alternatively, you can obtain the full source files from
1313 https://github.com/PhilterPaper/Perl-PDF-Builder, where the ticket list (bugs,
1414 enhancement requests, etc.) is also kept. Unlike the installable CPAN version,
15 this will have to be manually installed (copy files).
15 this will have to be manually installed (copy files; there are no XS compiles
16 at this time).
1617
1718 Note that there are several "optional" libraries (Perl modules) used to extend
1819 and improve PDF::Builder. The installation process will not attempt to install
19 them if not present -- you need to do this manually (if you want to use them).
20 Read about the list of optional libraries in PDF::Builder::Docs, and decide
21 whether or not you want to manually install any of them.
20 them if not present -- you need to do this manually (if you want to use them),
21 or at least, give the go-ahead during the installation process to try
22 installing them. Read about the list of optional libraries in
23 PDF::Builder::Docs, and decide whether or not you want to install any of them.
2224
2325 REQUIREMENTS ======================================================
2426
2931 not supported. The intent is to not waste time and effort trying to fix bugs
3032 which are an artifact of old Perl releases.
3133
34 If you MUST install on an older (pre 5.20) Perl, you can try the following
35 for Strawberry Perl (Windows). NO PROMISES! Something similar MAY work for
36 other OS's and Perl installations:
37 Unpack installation file (.tar.gz, via a utility such as 7-Zip) into a
38 directory, and cd to that directory
39 Edit .perl-version and change 5.20.0 to 5.16.0 or whatever level desired
40 Edit Makefile.PL and change use 5.020000; to use 5.016000;
41 change $PERL_version from '5.020000' to '5.016000'
42 cpan .
43
44 Note that some Perl installers MAY have a means to override or suppress the
45 Perl version check. That may be easier to use. Or, you may have to repack
46 the edited directory back into a .tar.gz installable. YMMV.
47
48 If all goes well, PDF::Builder will be installed on your system. Whether or
49 not it will RUN is another matter. Please do NOT open a bug report (ticket)
50 unless you're absolutely sure that the problem is not a result of using an
51 old Perl release, e.g., PDF::Builder is using a feature introduced in Perl
52 5.008 and you're trying to run Perl 5.002!
53
3254 Libraries used, available from CPAN --
3355
3456 REQUIRED, should be automatically installed...
3759 Test::Exception (needed only for installation tests)
3860 Test::Memory::Cycle (needed only for installation tests)
3961
40 OPTIONAL, install manually if wanted...
41 Graphics::TIFF (recommended if using TIFF image functions)
42 Image::PNG::Libpng (recommended for enhanced PNG image function processing)
43 HarfBuzz::Shaper (recommended for Latin script ligatures and kerning, as
62 OPTIONAL, install manually if wanted AND they failed to install
63 automatically when requested...
64 Graphics::TIFF (recommended if using TIFF image functions)
65 Image::PNG::Libpng (recommended for enhanced PNG image function processing)
66 HarfBuzz::Shaper (recommended for Latin script ligatures and kerning, as
4467 well as for any complex script such as Arabic, Indic
4568 scripts, or Khmer)
4669
6083
6184 The GNU Lesser General Public License, Version 2.1, February 1999
6285
86 EXCEPT for some files which are explicitly under other licenses. You are
87 permitted (at your option) to redistribute and/or modify this software (those
88 portions under LGPL) at an LGPL version greater than 2.1. See INFO/LICENSE for
89 more information on the licenses and warranty statement.
90
6391 See INFO/RoadMap file for the PDF::Builder road map.
6492 See CONTRIBUTING file for how to contribute to the project.
6593 See INFO/SUPPORT file for information on reporting bugs, etc. via GitHub Issues
6896 See INFO/KNOWN_INCOMP file for known incompatibilities with PDF::API2.
6997 See INFO/Changes* files for older change logs.
7098 See INFO/PATENTS file for information on patents.
71 See INFO/LICENSE file for the license.
7299 See INFO/CONVERSION file for how to convert from PDF::API2 to PDF::Builder
73100
74101 INFO/old/ also has some build and test tool files that are not currently used.
22 use strict;
33 use warnings;
44
5 our $VERSION = '3.019'; # VERSION
5 our $VERSION = '3.020'; # VERSION
66 my $LAST_UPDATE = '2.029'; # manually update whenever code is changed
77
88 use PDF::Builder;
33
44 use PDF::Builder::Basic::PDF::File;
55
6 our $VERSION = '3.019'; # VERSION
6 our $VERSION = '3.020'; # VERSION
77 my $LAST_UPDATE = '3.010'; # manually update whenever code is changed
88
99 my $file = shift(@ARGV);
22 use strict;
33 use warnings;
44
5 our $VERSION = '3.019'; # VERSION
5 our $VERSION = '3.020'; # VERSION
66 my $LAST_UPDATE = '3.016'; # manually update whenever code is changed
77
88 use PDF::Builder::Basic::PDF::File;
22 use strict;
33 use warnings;
44
5 our $VERSION = '3.019'; # VERSION
5 our $VERSION = '3.020'; # VERSION
66 my $LAST_UPDATE = '3.016'; # manually update whenever code is changed
77
88 use PDF::Builder::Basic::PDF::File;
7171 use strict;
7272 use warnings;
7373
74 our $VERSION = '3.019'; # VERSION
74 our $VERSION = '3.020'; # VERSION
7575 my $LAST_UPDATE = '3.002'; # manually update whenever code is changed
7676
7777 use PDF::Builder;
11 # buildDoc.pl builds documentation tree from Perl .pod and .pm files (POD)
22 # in case of duplicate names, .pod is used in preference to .pm
33 #
4 # (c) copyright 2018 Catskill Technology Services, LLC
5 # licensed under license used in PDF::Builder package
4 # (c) copyright 2018-2020 Catskill Technology Services, LLC
5 # licensed under license used in PDF::Builder package (LGPL 2.1+)
66 #
77 # there is partial code to implement --all to build all PODs, or update an
88 # existing documentation tree with specific name(s), but the whole process
1515 use warnings;
1616 use Getopt::Long;
1717
18 our $VERSION = '3.019'; # VERSION
19 my $LAST_UPDATE = '3.011'; # manually update whenever code is changed
18 our $VERSION = '3.020'; # VERSION
19 my $LAST_UPDATE = '3.020'; # manually update whenever code is changed
2020
2121 # =============
2222 # CONFIGURATION these may be overridden by command-line flags. If reading from
7272 # be an .html file)
7373 # accessible => accessible (from root) flag 0=no 1=yes
7474 # abstract => text from NAME POD entry
75 # parents => [] build list of parent(s) chain
76 # siblings => [] build list of any siblings
77 # children => [] build list of any children
7578
7679 # command line flags and files
7780 if (scalar(@ARGV) == 0) { help(); exit(1); }
118121 if ($all) {
119122 # any stray stuff? ARGV should be empty by now
120123 foreach (@ARGV) {
121 print "$_ WARNING extra command line content ignored\n";
124 print "WARNING extra command line content '$_' ignored\n";
122125 }
123126
124127 # get complete list of filepaths in @file_list and initialize flags
181184 pmname=>toPM($_), # PM format name
182185 status=>-1, # status -1 ready to read
183186 accessible=>1, # root accessible yes
184 abstract=>'' }; # no abstract yet
187 abstract=>'', # no abstract yet
188 parents=>[], # no parents yet
189 siblings=>[], # no siblings yet
190 children=>[], # no children yet
191 depth=>0, # depth of directory
192 };
185193 }
186194
187195 if ($rootname eq '') {
228236 # need to swap records i and i+1
229237 # copying one hash to another can be tricky business, so
230238 # we'll do it the hard way
239 # parents, siblings, children arrays s/b empty
231240 my %temp;
232241 $temp{'pmname'} = $file_list[$i]{'pmname'};
233242 $temp{'fpname'} = $file_list[$i]{'fpname'};
234243 $temp{'status'} = $file_list[$i]{'status'};
235244 $temp{'accessible'} = $file_list[$i]{'accessible'};
236245 $temp{'abstract'} = $file_list[$i]{'abstract'};
246 $temp{'parents'} = $file_list[$i]{'parents'};
247 $temp{'siblings'} = $file_list[$i]{'siblings'};
248 $temp{'children'} = $file_list[$i]{'children'};
237249 $file_list[$i]{'pmname'} = $file_list[$i+1]{'pmname'};
238250 $file_list[$i]{'fpname'} = $file_list[$i+1]{'fpname'};
239251 $file_list[$i]{'status'} = $file_list[$i+1]{'status'};
240252 $file_list[$i]{'accessible'} = $file_list[$i+1]{'accessible'};
241253 $file_list[$i]{'abstract'} = $file_list[$i+1]{'abstract'};
254 $file_list[$i]{'parents'} = $file_list[$i+1]{'parents'};
255 $file_list[$i]{'siblings'} = $file_list[$i+1]{'siblings'};
256 $file_list[$i]{'children'} = $file_list[$i+1]{'children'};
242257 $file_list[$i+1]{'pmname'} = $temp{'pmname'};
243258 $file_list[$i+1]{'fpname'} = $temp{'fpname'};
244259 $file_list[$i+1]{'status'} = $temp{'status'};
245260 $file_list[$i+1]{'accessible'} = $temp{'accessible'};
246261 $file_list[$i+1]{'abstract'} = $temp{'abstract'};
262 $file_list[$i+1]{'parents'} = $temp{'parents'};
263 $file_list[$i+1]{'siblings'} = $temp{'siblings'};
264 $file_list[$i+1]{'children'} = $temp{'children'};
247265 $swap = 1;
248266 }
249267 }
431449
432450 # write $htmlfile back out to its .html file ($target)
433451 spew($htmlfile, $target);
452 $file_list[$i]{'htmlname'} = $target;
434453
435454 } # processed a .pod or .pm file into .html (was status -1)
436455 } # for loop through all entries, looking for status -1
484503 next;
485504 }
486505 # put 'X' at left margin if not accessible from root, else space
487 if ($file_list[$i]{'accessible'} == 1) {
506 ## with NAVIGATION LINKS, all should be accessible from within
507 #if ($file_list[$i]{'accessible'} == 1) {
488508 print $fh "<span class=\"fixedwidth\"> </span>";
489 } else {
490 print $fh "<span class=\"fixedwidth\">X</span>";
491 }
509 #} else {
510 # print $fh "<span class=\"fixedwidth\">X</span>";
511 #}
492512
493513 my $fname = $file_list[$i]{'fpname'};
494514 $fname =~ s#$libtop/$leading/##;
529549 # cleanup
530550 unlink "pod2htmd.tmp";
531551 unlink "pod2html.stderr";
552
553 # now that the individual HTML files and the master index are done,
554 # 1) generate pmnameA array for each entry in @file_list
555 # 2) generate children, siblings, and parents lists
556 # 3) go through all HTML files (ex master index) and update with NAVIGATION
557 if (scalar(@file_list) <= 1) {
558 print "Only 0 or 1 file_list entries. Do not create NAVIGATION LINKS.\n";
559 exit(0);
560 }
561 make_pmnameA();
562 my ($j, $ref);
563
564 process(0, scalar(@file_list));
565
566 # entire file_list should have been recursively processed
567 # we have filled in the 'children' of each node. now give each node its
568 # parent, and then siblings
569 do_parents();
570 # remove duplicate children (grandchildren) AFTER parents set, so that an
571 # element may have chain of parents all the way up to the root
572 remove_grandchildren();
573 do_siblings();
574
575 # update existing HTML files
576 update_HTML();
577 exit(0);
578
579 # ==================================
580 sub update_HTML{
581 my ($i, $fname, $string, @count, $ref, $pos, $newstring, @list);
582
583 for ($i=0; $i<scalar(@file_list); $i++) {
584 # read POD from file $file_list[$i]{'fpname'}
585 # wrote HTML to $file_list[$i]{'htmlname'}
586 $fname = $file_list[$i]{'htmlname'};
587 print "Updating NAVIGATION LINKS in $fname\n";
588
589 # print "file_list[$i]: $file_list[$i]{'pmname'} - $file_list[$i]{'abstract'}\n";
590 # read in HTML into $string, modify
591 $string = slurp($fname);
592 if (length $string == 0) {
593 print "ERROR: unable to read in file $fname for Navigation Links update!\n";
594 next;
595 }
596 @count = (0, 0, 0); # no parents, siblings, or children
597 # count of parents
598 $ref = $file_list[$i]{'parents'};
599 if (defined $ref) { $count[0] = scalar(@$ref); }
600 $count[0]++; # always the master index
601 # count of siblings
602 $ref = $file_list[$i]{'siblings'};
603 if (defined $ref) { $count[1] = scalar(@$ref); }
604 # count of children
605 $ref = $file_list[$i]{'children'};
606 if (defined $ref) { $count[2] = scalar(@$ref); }
607
608 # update link directory at top of file
609 # guaranteed there's at least one parent entry
610 $pos = index $string, '<ul id="index">';
611 if ($pos < 0) {
612 print "ERROR: can't find link index in file $fname.\n";
613 next;
614 }
615 $pos = index $string, "\n</ul>", $pos;
616 if ($pos < 0) {
617 print "ERROR: can't find end of link index in file $fname.\n";
618 next;
619 }
620 # split point is $pos+1 (just before </ul>)
621
622 $newstring = " <li><a href=\"#NAVIGATION-LINKS\">NAVIGATION LINKS</a>\n" .
623 " <ul>\n" .
624 " <li><a href=\"#Up-Parents\">Up (Parents)</a></li>\n";
625 if ($count[1]) {
626 $newstring .=
627 " <li><a href=\"#Siblings\">Siblings</a></li>\n";
628 }
629 if ($count[2]) {
630 $newstring .=
631 " <li><a href=\"#Down-Children\">Down (Children)</a></li>\n";
632 }
633 $newstring .= " </ul>\n" .
634 " </li>\n";
635 $string = substr($string, 0, $pos+1) . $newstring . substr($string, $pos+1);
636
637 # just before </body> will be location of new section
638 $pos = index $string, "\n</body>\n";
639
640 $newstring = "<h1 id=\"NAVIGATION-LINKS\">NAVIGATION LINKS</h1>\n";
641
642 # if parents (should be), output that section
643 $newstring .= "\n<h2 id=\"Up-Parents\">Up (Parents)</h2>\n";
644 # add ever-present master index entry at same level as [0] entry
645 # note: omitting id= because it's not used anywhere
646 $newstring .= "\n<dl>\n\n<dt>" .
647 "<a href=\"".go_up($file_list[$i]{'depth'}-1) .
648 "index.html\">Master Index</a>&nbsp;</dt>\n<dd>\n\n</dd>\n";
649
650 $ref = $file_list[$i]{'parents'};
651 if (defined $ref && scalar(@$ref)) {
652 # @$ref is an ordered array of @file_list indice(s)
653 # pointing back to any parents
654 @list = @$ref;
655 foreach (@list) {
656 $newstring .= "<a href=\"".go_up($file_list[$i]{'depth'}) .
657 "$file_list[$_]{'htmlname'}\">$file_list[$_]{'pmname'}</a> -- $file_list[$_]{'abstract'}</dt>\n<dd>\n\n</dd>\n";
658 }
659 }
660 $newstring .= "</dl>\n";
661
662 # if any siblings, output that section
663 if ($count[1]) {
664 $ref = $file_list[$i]{'siblings'};
665 if (defined $ref && scalar(@$ref)) {
666 $newstring .= "\n<h2 id=\"Siblings\">Siblings</h2>\n";
667 # @$ref is an ordered array of @file_list indice(s)
668 # pointing back to any siblings
669 @list = @$ref;
670 foreach (@list) {
671 $newstring .= "<a href=\"".go_up($file_list[$i]{'depth'}) .
672 "$file_list[$_]{'htmlname'}\">$file_list[$_]{'pmname'}</a> -- $file_list[$_]{'abstract'}</dt>\n<dd>\n\n</dd>\n";
673 }
674 $newstring .= "</dl>\n";
675 }
676 }
677
678 # if any children, output that section
679 if ($count[2]) {
680 $ref = $file_list[$i]{'children'};
681 if (defined $ref && scalar(@$ref)) {
682 $newstring .= "\n<h2 id=\"Down-Children\">Down (Children)</h2>\n";
683 # @$ref is an ordered array of @file_list indice(s)
684 # pointing back to any children
685 @list = @$ref;
686 foreach (@list) {
687 $newstring .= "<a href=\"".go_up($file_list[$i]{'depth'}) .
688 "$file_list[$_]{'htmlname'}\">$file_list[$_]{'pmname'}</a> -- $file_list[$_]{'abstract'}</dt>\n<dd>\n\n</dd>\n";
689 }
690 $newstring .= "</dl>\n";
691 }
692 }
693
694 # write file back out
695 $string = substr($string, 0, $pos+1) . $newstring . substr($string, $pos+1);
696 spew($string, $fname);
697 }
698 return;
699 }
700
701 sub go_up {
702 my $depth = shift;
703 if ($depth == 1) { return ''; }
704 return '../' x ($depth-1);
705 }
706
707 # ==================================
708 # recursively process this range of file_list rows, filling in children array
709 # handle a subset (initially the whole thing) of file_list
710 sub process {
711 my ($start, $len) = @_;
712 # starting element number in file_list, and count of rows
713
714 if ($len <= 1) { return; } # single element won't have any children
715
716 my ($i, $j, $dir);
717 my ($start2, $len2, $ref, $refc);
718
719 # if $start row's pmnameA is now empty, that means that $start is the
720 # parent of everything else below it
721 $ref = $file_list[$start]{'pmnameA'};
722 if (scalar(@$ref) == 0) {
723 # element $start is parent to all (1..$len-1) other elements
724 # we want only DIRECT children (leaves), not nodes (grandchildren),
725 # so later we will remove grandchildren (duplicates)
726 $refc = $file_list[$start]{'children'};
727 for ($j=1; $j<$len; $j++) {
728 push @$refc, $start+$j;
729 }
730 # remove first element (empty pmnameA) from further consideration
731 process($start+1, $len-1);
732 return;
733 }
734
735 # strip first element from each pmnameA if ALL are duplicates
736 LOOP: while (1) {
737 $ref = $file_list[$start]{'pmnameA'};
738 last if !scalar(@$ref[0]); # first element is empty?
739 $dir = @$ref[0];
740 for ($i=1; $i<$len; $i++) {
741 last LOOP if @{ $file_list[$start+$i]{'pmnameA'} }[0] ne $dir;
742 }
743 # if we got to here, entire section's [0] element is the same
744 # so remove it
745 for ($i=0; $i<$len; $i++) {
746 shift @{ $file_list[$start+$i]{'pmnameA'} };
747 }
748
749 process($start, $len);
750 return;
751 }
752
753 # now break up remainder into two subranges (first pmnameA element
754 # is NOT the same in all rows)
755 $len2 = 0;
756 for ($i=$start; $i<$start+$len; $i++) {
757 $ref = $file_list[$i]{'pmnameA'};
758 if ($len2 == 0) {
759 # should NOT see an empty pmnameA for element start!
760 $dir = @$ref[0];
761 $len2++;
762 next;
763 }
764
765 if (@$ref[0] eq $dir) {
766 # still a match
767 $len2++;
768 next;
769
770 } else {
771 # no longer a match. len2 always at least a run of 1
772 process($start, $len2);
773 # $len2 .. end is remainder, process it
774 process($start+$len2, $len-$len2);
775
776 return;
777 }
778 } # for loop through file_list section, first level of chunking
779
780 return; # probably never hit this
781 }
782
783 # ==================================
784 # remove an element's grandchildren from its children list
785 sub remove_grandchildren {
786 my ($start, $ref, $refs, $ele, $i, $j);
787
788 for ($start=1; $start<scalar(@file_list); $start++) {
789 # if this element has children, check 0..start-1 for duplicate
790 # children (who are actually grandchildren) and remove them from there
791 $refs = $file_list[$start]{'children'};
792 if (!defined $refs) { next; }
793 if (!scalar(@$refs)) { next; } # no children for this element
794
795 for ($ele=0; $ele<$start; $ele++) {
796 $ref = $file_list[$ele]{'children'};
797 if (!defined $ref) { next; }
798 if (!scalar(@$ref)) { next; } # no children for this element
799
800 # remove duplicates (grandchildren) from $ele's children
801 for ($i=0; $i<scalar(@$refs); $i++) {
802 for ($j=0; $j<scalar(@$ref); $j++) {
803 if (@$ref[$j] == @$refs[$i]) {
804 # $j is a grandchild, so remove it
805 splice(@$ref, $j, 1);
806 }
807 }
808 }
809 }
810 }
811
812 return;
813 }
814
815 # ==================================
816 # follow children links to set their parents
817 sub do_parents {
818 my ($i, @children, $child);
819 for ($i=0; $i<scalar(@file_list); $i++) {
820 if (!defined $file_list[$i]{'children'}) { next; }
821 @children = @{ $file_list[$i]{'children'} };
822 if (!scalar(@children)) { next; } # no children?
823
824 while (scalar(@children)) {
825 $child = shift @children;
826 push @{ $file_list[$child]{'parents'} }, $i;
827 }
828 }
829
830 return;
831 }
832
833 # ==================================
834 # find siblings from children of a given node
835 sub do_siblings {
836 my ($i, $j, $k, $refs, @children, $child);
837 for ($i=0; $i<scalar(@file_list); $i++) {
838 if (!defined $file_list[$i]{'children'}) { next; }
839 @children = @{ $file_list[$i]{'children'} };
840
841 # no children, or a lonely only child? it has no siblings
842 if (scalar(@children) <= 1) { next; }
843
844 for ($j=0; $j<scalar(@children); $j++) {
845 $child = $children[$j];
846 $refs = $file_list[$child]{'siblings'};
847 # this child's siblings is the entire children list except itself
848 for ($k=0; $k<scalar(@children); $k++) {
849 push @$refs, $children[$k] if $children[$k] != $child;
850 }
851 }
852 }
853
854 return;
855 }
856
857 # ==================================
858 # split up pmname into pmnameA, and while here, set depth
859 sub make_pmnameA {
860 my (@tempA, $i, $j);
861 for ($i=0; $i<scalar(@file_list); $i++) {
862 @tempA = split /::/, $file_list[$i]{'pmname'};
863 $file_list[$i]{'depth'} = scalar(@tempA);
864 $file_list[$i]{'pmnameA'} = [];
865 for ($j=0; $j<scalar(@tempA); $j++) {
866 @{$file_list[$i]{'pmnameA'}}[$j] = $tempA[$j];
867 }
868 }
869
870 return;
871 }
532872
533873 # ==================================
534874 # function to spew a one-string file out to the file
598938 }
599939 next;
600940 }
601 push @list, { fpname=>"$dirname/$direntry", pmname=>toPM("$dirname/$direntry"), status=>-2, accessible=>1, abstract=>'' };
941 push @list, { fpname=>"$dirname/$direntry", pmname=>toPM("$dirname/$direntry"), status=>-2, accessible=>1, abstract=>'', parents=>[], siblings=>[], children=>[], depth=>0 };
602942 } else {
603943 # it should be a directory. recursively process it
604944 if (!-d "$dirname/$direntry") { print "$dirname/$direntry WARNING is not a directory or file, ignored\n"; next; }
110110 $text->fillcolor('black');
111111 $text->text(" to go to Page 1.");
112112
113 # same, except position and zoom
114 $x = 100;
115 $y = 400;
116
117 $text->translate($x, $y);
118 $text->text("Click ");
119 $x += $text->advancewidth("Click ");
120
121 # x,y should be at LL corner of "here" (on baseline)
122 $text->fillcolor('blue');
123 $text->text("here");
124 $target_width = $text->advancewidth("here");
125
126 $annotation = $page->annotation();
127 $tgt_page = $pdf->openpage(1); # target page 1
128 $annotation->link($tgt_page,
129 -rect => [$x-1, $y-5, $x+1+$target_width, $y-5+1+$font_size],
130 # clickable area
131 -border => [0, 0, $border], # show border
132 -color => [$b_red, $b_green, $b_blue], # border color
133 -xyz => [ 200,550, 1.5 ], # new position, zoom factor 150%
134 );
135
136 # restore color and do rest of line
137 $text->fillcolor('black');
138 $text->text(" to go to Page 1 positioned/zoomed.");
139
140
113141 # ---------- go to a page in ANOTHER document
114142 $page = $pdf->page(); # page 3
115143 $text = $page->text();
144172 # restore color and do rest of line
145173 $text->fillcolor('black');
146174 $text->text(" to go to Page 1 of another PDF document.");
175
176 # same, except position and zoom
177 $x = 100;
178 $y = 400;
179
180 $text->translate($x, $y);
181 $text->text("Click ");
182 $x += $text->advancewidth("Click ");
183
184 # x,y should be at LL corner of "here" (on baseline)
185 $text->fillcolor('blue');
186 $text->text("here");
187 $target_width = $text->advancewidth("here");
188
189 $annotation = $page->annotation();
190 $annotation->pdf_file("resources/HarfBuzz_example.pdf",
191 1, # page number
192 -rect => [$x-1, $y-5, $x+1+$target_width, $y-5+1+$font_size],
193 # clickable area
194 -border => [0, 0, $border], # show border
195 -color => [$b_red, $b_green, $b_blue], # border color
196 -fitr => [100,350, 300,550], # new viewport
197 );
198
199 # restore color and do rest of line
200 $text->fillcolor('black');
201 $text->text(" to go to Page 1 of another PDF document, windowed.");
147202
148203 # ---------- launch (default OS action) another file
149204 $page = $pdf->page(); # page 4
88 use warnings;
99 use strict;
1010
11 our $VERSION = '3.019'; # VERSION
11 our $VERSION = '3.020'; # VERSION
1212 my $LAST_UPDATE = '3.013'; # manually update whenever code is changed
1313
1414 use Math::Trig;
2020 my $bleedbox_adj = 36/pt; # in from crop box on top and right for printer inst.
2121 my $cropbox_adj = 0.25/in; # in from media edge
2222
23 our $VERSION = '3.019'; # VERSION
23 our $VERSION = '3.020'; # VERSION
2424 my $LAST_UPDATE = '3.017'; # manually update whenever code is changed
2525
2626 my $PDFname = $0;
3232 use warnings;
3333 use strict;
3434
35 our $VERSION = '3.019'; # VERSION
35 our $VERSION = '3.020'; # VERSION
3636 my $LAST_UPDATE = '3.010'; # manually update whenever code is changed
3737
3838 use Math::Trig;
55 use warnings;
66 use strict;
77
8 our $VERSION = '3.019'; # VERSION
8 our $VERSION = '3.020'; # VERSION
99 my $LAST_UPDATE = '3.013'; # manually update whenever code is changed
1010
1111 use Math::Trig;
55 use warnings;
66 use strict;
77
8 our $VERSION = '3.019'; # VERSION
8 our $VERSION = '3.020'; # VERSION
99 my $LAST_UPDATE = '3.010'; # manually update whenever code is changed
1010
1111 use Math::Trig;
00 #!/usr/bin/perl
11 ##########################
2 # CAUTION: cannot merge until new HarfBuzz::Shaper released
3 # ditto for Content.pm changes
2 # NOTE: appears to bring in the entire Ming font (Chinese), rather than a
3 # subset. sorry about that! ref RT 130041
44 # Note to maintainer: don't forget to refresh HarfBuzz_example.pdf
55 ##########################
66 # demonstrate some usage of HarfBuzz::Shaper and related text calls
1010 use strict;
1111 use warnings;
1212
13 our $VERSION = '3.019'; # VERSION
13 our $VERSION = '3.020'; # VERSION
1414 my $LAST_UPDATE = '3.019'; # manually update whenever code is changed
1515
1616 my $PDFname = $0;
5959 # to be.
6060
6161 my $pdf = PDF::Builder->new(-compress => 'none');
62 #my $pdf = PDF::Builder->new();
63
6264 $pdf->mediabox('universal'); # narrower and shorter of US letter and A4, so
6365 # it should be printable on either paper
6466 my $labelFont = $pdf->corefont('Helvetica');
385387 # some random Chinese characters. most interested in what direction is
386388 # the default, and what is settable
387389 'TTBChinese' => { 'title' => 'TTBChinese',
388 'fontFile' => '/Program Files (x86)/Adobe/Acrobat Reader DC/Resource/CIDFont/AdobeMingStd-Light.otf',
390 # 'fontFile' => '/Program Files (x86)/Adobe/Acrobat Reader DC/Resource/CIDFont/AdobeMingStd-Light.otf',
391 'fontFile' => '/Program Files (x86)/Adobe/Acrobat Reader DC/Resource/CIDFont/AdobeGothicStd-Light.otf',
389392 'dir' => 'T',
390393 'script' => 'Chin',
391 'text' => ["\x{5A40}\x{5A41}\x{5A42}\x{5A43}", " PDF::Builder ", "\x{5A44}\x{5A45}"] },
394 # 'text' => ["\x{5A40}\x{5A41}\x{5A42}\x{5A43}", " PDF::Builder ", "\x{5A44}\x{5A45}"] },
395 'text' => ["\x{58D8}\x{5A41}\x{5C62}\x{6A13}", " PDF::Builder ", "\x{6DDA}\x{6F0F}"] },
392396
393397 # Languages which are normally RTL don't seem to behave with TTB.
394398 # I would expect them to be reversed, but they aren't. Maybe the direction
66 use warnings;
77 use strict;
88
9 our $VERSION = '3.019'; # VERSION
9 our $VERSION = '3.020'; # VERSION
1010 my $LAST_UPDATE = '3.017'; # manually update whenever code is changed
1111
1212 use PDF::Builder;
22 use strict;
33 no warnings qw[ deprecated recursion uninitialized ];
44
5 our $VERSION = '3.019'; # VERSION
5 our $VERSION = '3.020'; # VERSION
66 my $LAST_UPDATE = '3.010'; # manually update whenever code is changed
77
88 use Win32::TieRegistry qw( :KEY_ ); # creates $Registry, et al.
44 use strict;
55 use warnings;
66
7 our $VERSION = '3.019'; # VERSION
7 our $VERSION = '3.020'; # VERSION
88 my $LAST_UPDATE = '3.019'; # manually update whenever code is changed
99
1010 use PDF::Builder::Basic::PDF::Utils;
1616 use strict;
1717 use warnings;
1818
19 our $VERSION = '3.019'; # VERSION
19 our $VERSION = '3.020'; # VERSION
2020 my $LAST_UPDATE = '3.016'; # manually update whenever code is changed
2121
2222 =head1 NAME
1616 use strict;
1717 use warnings;
1818
19 our $VERSION = '3.019'; # VERSION
19 our $VERSION = '3.020'; # VERSION
2020 my $LAST_UPDATE = '3.010'; # manually update whenever code is changed
2121
2222 =head1 NAME
1616 use strict;
1717 no warnings qw[ deprecated recursion uninitialized ];
1818
19 our $VERSION = '3.019'; # VERSION
19 our $VERSION = '3.020'; # VERSION
2020 my $LAST_UPDATE = '3.016'; # manually update whenever code is changed
2121
2222 our $mincache = 16 * 1024 * 1024;
1616 use strict;
1717 no warnings qw[ deprecated recursion uninitialized ];
1818
19 our $VERSION = '3.019'; # VERSION
20 my $LAST_UPDATE = '3.018'; # manually update whenever code is changed
19 our $VERSION = '3.020'; # VERSION
20 my $LAST_UPDATE = '3.020'; # manually update whenever code is changed
2121
2222 =head1 NAME
2323
11671167 sub _unpack_xref_stream {
11681168 my ($self, $width, $data) = @_;
11691169
1170 return unpack('C', $data) if $width == 1;
1171 return unpack('n', $data) if $width == 2;
1172 return unpack('N', "\x00$data") if $width == 3;
1173 return unpack('N', $data) if $width == 4;
1174 return unpack('Q', $data) if $width == 8; # PDF 1.5+?
1175
1176 die "Invalid column width: $width";
1170 # handle some oddball cases
1171 if ($width == 3) {
1172 $data = "\x00$data";
1173 $width = 4;
1174 } elsif ($width == 5) {
1175 $data = "\x00\x00\x00$data";
1176 $width = 8;
1177 } elsif ($width == 6) {
1178 $data = "\x00\x00$data";
1179 $width = 8;
1180 } elsif ($width == 7) {
1181 $data = "\x00$data";
1182 $width = 8;
1183 }
1184 # in all cases, "Network" (Big-Endian) byte order assumed
1185 return unpack('C', $data) if $width == 1;
1186 return unpack('n', $data) if $width == 2;
1187 return unpack('N', $data) if $width == 4;
1188 if ($width == 8) {
1189 # Some ways other packages handle this, without Perl-64, according
1190 # to Vadim Repin. Possibly they end up converting the value to
1191 # "double" behind the scenes if on a 32-bit platform?
1192 # PDF::Tiny return hex unpack('H16', $data);
1193 # CAM::PDF my @b = unpack('C*', $data);
1194 # my $i=0; ($i <<= 8) += shift @b while @b; return $i;
1195
1196 if (substr($data, 0, 4) eq "\x00\x00\x00\x00") {
1197 # can treat as 32 bit unsigned int
1198 return unpack('N', substr($data, 4, 4));
1199 } else {
1200 # requires 64-bit platform (chip and Perl), else fatal error
1201 # it may blow up and produce a smoking crater if 32-bit Perl!
1202 # also note that Q needs Big-Endian flag (>) specified, else
1203 # it will use the native chip order (Big- or Little- Endian)
1204 return unpack('Q>', $data);
1205 }
1206 }
1207
1208 die "Unsupported field width: $width. 1-8 supported.";
11771209 }
11781210
11791211 sub readxrtr {
13841416 } elsif ($buf =~ m/^(\d+)\s+(\d+)\s+obj/i) {
13851417 my ($xref_obj, $xref_gen) = ($1, $2);
13861418
1419 PDF::Builder->verCheckOutput(1.5, "importing cross-reference stream");
13871420 # XRef streams
13881421 ($tdict, $buf) = $self->readval($buf);
13891422
44 use strict;
55 use warnings;
66
7 our $VERSION = '3.019'; # VERSION
7 our $VERSION = '3.020'; # VERSION
88 my $LAST_UPDATE = '3.010'; # manually update whenever code is changed
99
1010 =head1 NAME
44 use strict;
55 use warnings;
66
7 our $VERSION = '3.019'; # VERSION
7 our $VERSION = '3.020'; # VERSION
88 my $LAST_UPDATE = '2.029'; # manually update whenever code is changed
99
1010 =head1 NAME
44 use strict;
55 use warnings;
66
7 our $VERSION = '3.019'; # VERSION
7 our $VERSION = '3.020'; # VERSION
88 my $LAST_UPDATE = '3.016'; # manually update whenever code is changed
99
1010 use POSIX qw(ceil floor);
44 use strict;
55 no warnings qw[ deprecated recursion uninitialized ];
66
7 our $VERSION = '3.019'; # VERSION
7 our $VERSION = '3.020'; # VERSION
88 my $LAST_UPDATE = '2.029'; # manually update whenever code is changed
99
1010 =head1 NAME
44 use strict;
55 use warnings;
66
7 our $VERSION = '3.019'; # VERSION
7 our $VERSION = '3.020'; # VERSION
88 my $LAST_UPDATE = '2.029'; # manually update whenever code is changed
99
1010 =head1 NAME
1414 use strict;
1515 use warnings;
1616
17 our $VERSION = '3.019'; # VERSION
17 our $VERSION = '3.020'; # VERSION
1818 my $LAST_UPDATE = '3.016'; # manually update whenever code is changed
1919
2020 use PDF::Builder::Basic::PDF::Filter::ASCII85Decode;
44
55 use strict;
66
7 our $VERSION = '3.019'; # VERSION
7 our $VERSION = '3.020'; # VERSION
88 my $LAST_UPDATE = '3.016'; # manually update whenever code is changed
99
1010 use PDF::Builder::Basic::PDF::Filter;
1616 use strict;
1717 use warnings;
1818
19 our $VERSION = '3.019'; # VERSION
19 our $VERSION = '3.020'; # VERSION
2020 my $LAST_UPDATE = '3.011'; # manually update whenever code is changed
2121
2222 =head1 NAME
1616 use strict;
1717 use warnings;
1818
19 our $VERSION = '3.019'; # VERSION
19 our $VERSION = '3.020'; # VERSION
2020 my $LAST_UPDATE = '3.010'; # manually update whenever code is changed
2121
2222 =head1 NAME
1616 use strict;
1717 use warnings;
1818
19 our $VERSION = '3.019'; # VERSION
19 our $VERSION = '3.020'; # VERSION
2020 my $LAST_UPDATE = '2.029'; # manually update whenever code is changed
2121
2222 =head1 NAME
1313
1414 use strict;
1515 use warnings;
16
17 our $VERSION = '3.019'; # VERSION
18 my $LAST_UPDATE = '3.016'; # manually update whenever code is changed
16 use Scalar::Util 'isweak';
17
18 our $VERSION = '3.020'; # VERSION
19 my $LAST_UPDATE = '3.020'; # manually update whenever code is changed
1920
2021 =head1 NAME
2122
113114 sub release {
114115 my ($self) = @_;
115116
116 my @tofree = values %$self;
117 my @tofree = grep { !isweak $_ } values %$self;
117118 %$self = ();
118119
119120 while (my $item = shift @tofree) {
1616 use strict;
1717 use warnings;
1818
19 our $VERSION = '3.019'; # VERSION
19 our $VERSION = '3.020'; # VERSION
2020 my $LAST_UPDATE = '3.016'; # manually update whenever code is changed
2121
2222 use PDF::Builder::Basic::PDF::Dict;
1616
1717 use base 'PDF::Builder::Basic::PDF::Dict';
1818
19 our $VERSION = '3.019'; # VERSION
19 our $VERSION = '3.020'; # VERSION
2020 my $LAST_UPDATE = '3.017'; # manually update whenever code is changed
2121
2222 use PDF::Builder::Basic::PDF::Array;
1616 use strict;
1717 use warnings;
1818
19 our $VERSION = '3.019'; # VERSION
19 our $VERSION = '3.020'; # VERSION
2020 my $LAST_UPDATE = '3.016'; # manually update whenever code is changed
2121
2222 =head1 NAME
1414 use strict;
1515 use warnings;
1616
17 our $VERSION = '3.019'; # VERSION
17 our $VERSION = '3.020'; # VERSION
1818 my $LAST_UPDATE = '3.016'; # manually update whenever code is changed
1919
2020 =head1 NAME
0 package PDF::Builder::Basic::PDF;
1
2 use strict;
3 use warnings;
4
5 our $VERSION = '3.020'; # VERSION
6 my $LAST_UPDATE = '3.020'; # manually update whenever code is changed
7
8 =head1 NAME
9
10 PDF::Builder::Basic::PDF - Various utilities and support routines
11
12 =cut
13
14 1;
44 use strict;
55 use warnings;
66
7 our $VERSION = '3.019'; # VERSION
7 our $VERSION = '3.020'; # VERSION
88 my $LAST_UPDATE = '3.018'; # manually update whenever code is changed
99
1010 =head1 NAME
44 use strict;
55 use warnings;
66
7 our $VERSION = '3.019'; # VERSION
7 our $VERSION = '3.020'; # VERSION
88 my $LAST_UPDATE = '3.019'; # manually update whenever code is changed
99
1010 =head1 NAME
743743 B<Note:> if you need to change any text treatment I<within> a paragraph
744744 (B<bold> or I<italicized> text, for instance), this can not handle it. Only
745745 plain text (all the same font, size, etc.) can be typeset with C<paragraph()>.
746 Also, there is currently very limited line splitting (hypenation) to better
746 Also, there is currently very limited line splitting (hyphenation) to better
747747 fit to a given width, and nothing is done for "widows and orphans".
748748
749749 =back
44 use strict;
55 no warnings qw( deprecated recursion uninitialized );
66
7 our $VERSION = '3.019'; # VERSION
8 my $LAST_UPDATE = '3.019'; # manually update whenever code is changed
7 our $VERSION = '3.020'; # VERSION
8 my $LAST_UPDATE = '3.020'; # manually update whenever code is changed
99
1010 use Carp;
1111 use Compress::Zlib qw();
12701270 for excess data to a routine). There is no check for duplicate points or other
12711271 degeneracies.
12721272
1273 The former name of B<spline> has been deprecated and will be removed.
1274
1275 =cut
1276
1277 sub spline {
1278 warn "Use qbspline instead of spline";
1279 return qbspline(@_);
1280 }
1273 =cut
1274
12811275 sub qbspline {
12821276 my ($self) = shift;
12831277
35223516 Takes an array of hashes produced by HarfBuzz::Shaper and outputs them to the
35233517 PDF output file. HarfBuzz outputs glyph CIDs and positioning information.
35243518 It may rearrange and swap characters (glyphs), and the result may bear no
3525 resemblence to the original Unicode point list. You should see
3519 resemblance to the original Unicode point list. You should see
35263520 examples/HarfBuzz.pl, which shows a number of examples with Latin and non-Latin
35273521 text, as well as vertical writing.
35283522 examples/resources/HarfBuzz_example.pdf is available in case you want to see
22 use strict;
33 use warnings;
44
5 our $VERSION = '3.019'; # VERSION
6 my $LAST_UPDATE = '3.018'; # manually update whenever code is changed
5 our $VERSION = '3.020'; # VERSION
6 my $LAST_UPDATE = '3.020'; # manually update whenever code is changed
77
88 # originally part of Builder.pm, it was split out due to its length
99
7575 ability to read interlaced PNG files. See resolved bug report RT 124349, as well
7676 as C<image_png>, for more information.
7777
78 Note that the installation process will B<not> attempt to install these
79 libraries automatically. If you wish to use them, you will have to manually
80 initiate the installation of such modules (e.g., with "cpan install").
78 B<*> HarfBuzz::Shaper -- This library enables PDF::Builder to handle complex
79 scripts (Arabic, Devanagari, etc.) as well as non-LTR writing systems. It is
80 also useful for Latin and other simple scripts, for ligatures and improved
81 kerning. HarfBuzz::Shaper is based on a set of HarfBuzz libraries, which it
82 will attempt to build if they are not found. See C<textHS> for more
83 information.
84
85 Note that the installation process B<will> attempt to install these
86 libraries automatically. If you don't wish to use one or more of them, you are
87 free to uninstall the optional librarie(s). If one or more failed to install,
88 no need to panic -- you simply won't be able to use some advanced features,
89 unless you are able to manually install the modules (e.g., with "cpan install").
8190
8291 =head2 Strings (Character Text)
8392
506515 Perry's intent is to keep all internal methods as upwardly compatible with
507516 PDF::API2 as possible, although it is likely that there will be some drift
508517 (incompatibilities) over time. At least initially, any program written based on
509 PDF::API2 should be convertable to PDF::Builder simply by changing "API2"
518 PDF::API2 should be convertible to PDF::Builder simply by changing "API2"
510519 anywhere it occurs to "Builder". See the INFO/KNOWN_INCOMP known
511520 incompatibilities file for further information.
512521
520529 which make the object unusable for further operations. You will likely receive
521530 an error message about B<can't call method new_obj on an undefined value> if
522531 you try to keep using a PDF object.
532
533 =head2 IntegrityCheck
534
535 The PDF::Builder methods that open an existing PDF file, pass it by the
536 integrity checker method, C<$self-E<gt>IntegrityCheck(level, content)>. This method
537 servers two purposes: 1) to find any C</Version> settings that override the
538 PDF version found in the PDF heading, and 2) perform some basic validations on
539 the contents of the PDF.
540
541 The C<level> parameter accepts the following values:
542
543 =over
544
545 =item 0 = Do not output any diagnostic messages; just return any version override.
546
547 =item 1 = Output error-level (serious) diagnostic messages, as well as returning any version override.
548
549 Errors include, in no place was the /Root object specified, or if it was, the indicated object was not found. An object claims another object as its child (/Kids list), but another object has already claimed that child. An object claims a child, but that child does not list a Parent, or the child lists a different Parent.
550
551 =item 2 = Output error- (serious) and warning- (less serious) level diagnostic messages, as well as returning any version override. B<This is the default.>
552
553 =item 3 = Output error- (serious), warning- (less serious), and note- (informational) level diagnostic messages, as well as returning any version override.
554
555 Notes include, in no place was the (optional) /Info object specified, or if it was, the indicated object was not found. An object was referenced, but no entry for it was found among the objects. (This may be OK if the object is not defined, or is on the free list, as the reference will then be ignored.) An object is defined, but it appears that no other object is referencing it.
556
557 =item 4 = Output error-, warning-, and note-level diagnostic messages, as well as returning any version override. Also dump the diagnostic data structure.
558
559 =item 5 = Output error-, warning-, and note-level diagnostic messages, as well as returning any version override. Also dump the diagnostic data structure and the C<$self> data structure (generally useful only if you have already read in the PDF file).
560
561 =back
562
563 The version is a string (e.g., '1.5') if found, otherwise C<undef> (undefined value) is returned.
564
565 For controlling the "automatic" call to IntegrityCheck (via opens), the level
566 may be given with the option (flag) C<-diaglevel =E<gt> I<n>>, where C<n> is between 0 and 5.
523567
524568 =head2 Preferences - set user display preferences
525569
16161660 formats. In addition, see C<examples/Content.pl> for an example of placing an
16171661 image on a page, as well as using in a "Form".
16181662
1663 =head3 Why is my image flipped or rotated?
1664
1665 Something not uncommonly seen when using JPEG photos in a PDF is that the
1666 images will be rotated and/or mirrored (flipped). This may happen when using
1667 TIFF images too. What happens is that the camera stores an image just as it
1668 comes off the CCD sensor, regardless of the camera orientation, and does not
1669 rotate it to the correct orientation! It I<does> store a separate
1670 "orientation" flag to suggest how the image might be corrected, but not all
1671 image processing obeys this flag (PDF::Builder does B<not>.). For example, if
1672 you take a "portrait" (tall) photo of a tree (with the phone held vertically),
1673 and then use it in a PDF, the tree may appear to have been cut down! (appears
1674 in landscape mode)
1675
1676 I have found some code that should allow the C<image_jpeg> or C<image> routine
1677 to auto-rotate to (supposedly) the correct orientation, by looking for the Exif
1678 metadata "Orientation" tag in the file. However, three problems arise:
1679 B<1)> if a photo has been edited, and rotated or flipped in the process, there is no guarantee that the Orientation tag has been corrected.
1680 B<2)> more than one Orientation tag may exist (e.g., in the binary APP1/Exif header, I<and> in XML data), and they may not agree with each other -- which should be used?
1681 B<3)> the code would need to uncompress the raster data, swap and/or transpose rows and/or columns, and recompress the raster data for inclusion into the PDF. This is costly and error-prone.
1682 In any case, the user would need to be able to override any auto-rotate function.
1683
1684 For the time being, PDF::Builder will simply leave it up to the user of the
1685 library to take care of rotating and/or flipping an image which displays
1686 incorrectly. It is possible that we will consider adding some sort of query or warning that the image appears to I<not> be "normally" oriented (Orientation value 1 or "Top-left"), according to the Orientation flag. You can consider either (re-)saving the photo in an editor such as PhotoShop or GIMP, or using PDF::Builder code similar to the following (for images rotated 180 degrees):
1687
1688 $pW = 612; $pH = 792; # page dimensions (US Letter)
1689 my $img = $pdf->image_jpeg("AliceLake.jpeg");
1690 # raw size WxH 4032x3024, scaled down to 504x378
1691 $sW = 4032/8; $sH = 3024/8;
1692 # intent is to center on US Letter sized page (LL at 54,207)
1693 # Orientation flag on this image is 3 (rotated 180 degrees).
1694 # if naively displayed (just $gfx->image call), it will be upside down
1695
1696 $gfx->save();
1697
1698 ## method 0: simple display, is rotated 180 degrees!
1699 #$gfx->image($img, ($pW-$sW)/2,($pH-$sH)/2, $sW,$sH);
1700
1701 ## method 1: translate, then rotate
1702 #$gfx->translate($pW,$pH); # to new origin (media UR corner)
1703 #$gfx->rotate(180); # rotate around new origin
1704 #$gfx->image($img, ($pW-$sW)/2,($pH-$sH)/2, $sW,$sH);
1705 # image's UR corner, not LL
1706
1707 # method 2: rotate, then translate
1708 $gfx->rotate(180); # rotate around current origin
1709 $gfx->translate(-$sW,-$sH); # translate in rotated coordinates
1710 $gfx->image($img, -($pW-$sW)/2,-($pH-$sH)/2, $sW,$sH);
1711 # image's UR corner, not LL
1712
1713 ## method 3: flip (mirror) twice
1714 #$scale = 1; # not rescaling here
1715 #$size_page = $pH/$scale;
1716 #$invScale = 1.0/$scale;
1717 #$gfx->add("-$invScale 0 0 -$invScale 0 $size_page cm");
1718 #$gfx->image($img, -($pW-$sW)/2-$sW,($pH-$sH)/2, $sW,$sH);
1719
1720 $gfx->restore();
1721
1722 If your image is also mirrored (flipped about an axis), simple rotation will
1723 not suffice. You could do something with a reversal of the coordinate system, as in "method 3" above (see L<PDF::Builder::Content/Advanced Methods>). To mirror only left/right, the second C<$invScale> would be positive; to mirror only top/bottom, the first would be positive. If all else fails, you could save a mirrored copy in a photo editor.
1724 90 or 270 degree rotations will require a C<rotate> call, possibly with "cm" usage to reverse mirroring.
1725 Incidentally, do not confuse this issue with the coordinate flipping performed
1726 by some Chrome browsers when printing a page to PDF.
1727
1728 Note that TIFF images may have the same rotation/mirroring problems as JPEG,
1729 which is not surprising, as the Exif format was lifted from TIFF for use in
1730 JPEG. The cure will be similar to JPEG's.
1731
16191732 =head3 TIFF Images
16201733
16211734 Note that the Graphics::TIFF support library does B<not> currently permit a
17121825
17131826 =back
17141827
1715 =head2 Using Shaper
1828 =head2 USING SHAPER (HarfBuzz::Shaper library)
17161829
17171830 # if HarfBuzz::Shaper is not installed, either bail out, or try to
17181831 # use regular TTF calls instead
22 use strict;
33 no warnings qw[ deprecated recursion uninitialized ];
44
5 our $VERSION = '3.019'; # VERSION
5 our $VERSION = '3.020'; # VERSION
66 my $LAST_UPDATE = '3.016'; # manually update whenever code is changed
77
88 BEGIN {
22 # PDF::Builder::Matrix
33 # Original Copyright 1995-96 Ulrich Pfeifer.
44 # modified by Alfred Reibenschuh <areibens@cpan.org> for PDF::API2
5 #
6 # This library is free software; you can redistribute it
7 # and/or modify it under the same terms as Perl itself.
5 # rewritten by Steve Simms <steve@deefs.net> and licensed under the same
6 # terms as the rest of PDF::API2
87 #
98 #=======================================================================
109 package PDF::Builder::Matrix;
1110
1211 use strict;
1312 use warnings;
13 use Carp;
1414
15 our $VERSION = '3.019'; # VERSION
16 my $LAST_UPDATE = '3.011'; # manually update whenever code is changed
15 our $VERSION = '3.020'; # VERSION
16 my $LAST_UPDATE = '3.020'; # manually update whenever code is changed
1717
1818 =head1 NAME
1919
2222 =cut
2323
2424 sub new {
25 my $type = shift;
25 my $type = shift();
26
2627 my $self = [];
27 my $len = scalar(@{$_[0]});
28 for (@_) {
29 return if scalar(@{$_}) != $len;
30 push(@{$self}, [@{$_}]);
28 my $col_count = scalar(@{$_[0]});
29 foreach my $row (@_) {
30 unless (scalar(@$row) == $col_count) {
31 carp 'Inconsistent column count in matrix';
32 return;
33 }
34 push(@{$self}, [@$row]);
3135 }
32 bless $self, $type;
33 return $self;
36
37 return bless($self, $type);
3438 }
3539
3640 # internal routine
3741 sub transpose {
38 my $self = shift;
42 my $self = shift();
43
3944 my @result;
4045 my $m;
4146
4247 for my $col (@{$self->[0]}) {
4348 push @result, [];
4449 }
45 for my $row (@{$self}) {
50 for my $row (@$self) {
4651 $m = 0;
47 for my $col (@{$row}) {
48 push(@{$result[$m++]}, $col);
52 for my $col (@$row) {
53 push @{$result[$m++]}, $col;
4954 }
5055 }
56
5157 return PDF::Builder::Matrix->new(@result);
5258 }
5359
5460 # internal routine
55 sub vekpro {
61 sub vector_product {
5662 my ($a, $b) = @_;
5763 my $result = 0;
5864
5965 for my $i (0 .. $#{$a}) {
6066 $result += $a->[$i] * $b->[$i];
6167 }
68
6269 return $result;
6370 }
6471
6572 # used by Content.pm
6673 sub multiply {
67 my $self = shift;
74 my $self = shift();
6875 my $other = shift->transpose();
76
6977 my @result;
70 my $m;
7178
72 return if $#{$self->[0]} != $#{$other->[0]};
73 for my $row (@{$self}) {
74 my $rescol = [];
75 for my $col (@{$other}) {
76 push(@{$rescol}, vekpro($row,$col));
79 unless ($#{$self->[0]} == $#{$other->[0]}) {
80 carp 'Mismatched dimensions in matrix multiplication';
81 return;
82 }
83 for my $row (@$self) {
84 my $result_col = [];
85 for my $col (@$other) {
86 push @$result_col, vector_product($row,$col);
7787 }
78 push(@result, $rescol);
88 push @result, $result_col;
7989 }
90
8091 return PDF::Builder::Matrix->new(@result);
8192 }
8293
44 use strict;
55 no warnings qw[ recursion uninitialized ];
66
7 our $VERSION = '3.019'; # VERSION
8 my $LAST_UPDATE = '3.017'; # manually update whenever code is changed
7 our $VERSION = '3.020'; # VERSION
8 my $LAST_UPDATE = '3.020'; # manually update whenever code is changed
99
1010 # TBD: do -rect and -border apply to Named Destinations (link, url, file)?
1111 # There is nothing to implement these options. Perhaps the code was copied
114114 Defines the destination as a PDF-file with filepath C<$pdffile>, on page
115115 C<$pagenum>, and options %opts (same as dest()).
116116
117 The old name, I<pdfile>, is still available but is B<deprecated> and will be
118 removed at some time in the future.
119
120 =cut
121
122 # to be removed no earlier than October, 2020
123 sub pdfile {
124 my ($self, $url, $pnum, %opts) = @_;
125 warn "use pdf_file() method instead of pdfile()";
126 return $self->pdf_file($url, $pnum, %opts);
127 }
117 =cut
128118
129119 sub pdf_file {
130120 my ($self, $url, $pnum, %opts) = @_;
44 use strict;
55 use warnings;
66
7 our $VERSION = '3.019'; # VERSION
8 my $LAST_UPDATE = '3.016'; # manually update whenever code is changed
7 our $VERSION = '3.020'; # VERSION
8 my $LAST_UPDATE = '3.020'; # manually update whenever code is changed
99
1010 use Carp qw(croak);
1111 use PDF::Builder::Basic::PDF::Utils;
3333 $self->{'Prev'} = $prev if defined $prev;
3434 $self->{' api'} = $api;
3535 weaken $self->{' api'};
36 weaken $self->{'Parent'} if defined $parent;
37 weaken $self->{'Prev'} if defined $prev;
3638
3739 return $self;
3840 }
4143 sub parent {
4244 my $self = shift();
4345 $self->{'Parent'} = shift() if defined $_[0];
46 weaken $self->{'Parent'};
4447 return $self->{'Parent'};
4548 }
4649
4851 sub prev {
4952 my $self = shift();
5053 $self->{'Prev'} = shift() if defined $_[0];
54 weaken $self->{'Prev'};
5155 return $self->{'Prev'};
5256 }
5357
5559 sub next {
5660 my $self = shift();
5761 $self->{'Next'} = shift() if defined $_[0];
62 weaken $self->{'Next'};
5863 return $self->{'Next'};
5964 }
6065
6469
6570 $self->{'First'} = $self->{' children'}->[0]
6671 if defined $self->{' children'} and defined $self->{' children'}->[0];
72 weaken $self->{'First'};
6773 return $self->{'First'};
6874 }
6975
7379
7480 $self->{'Last'} = $self->{' children'}->[-1]
7581 if defined $self->{' children'} and defined $self->{' children'}->[-1];
82 weaken $self->{'Last'};
7683 return $self->{'Last'};
7784 }
7885
290297 C<$pdffile>, on page C<$pagenum> (default 0), and position C<%position>
291298 (same as dest()).
292299
293 The old name, I<pdfile>, is still available but is B<deprecated> and will be
294 removed at some time in the future.
295
296 =cut
297
298 # to be removed no earlier than October, 2020
299 sub pdfile {
300 my ($self, $file, $page_number, %position) = @_;
301 warn "use pdf_file() method instead of pdfile()";
302 return $self->pdf_file($file, $page_number, %position);
303 }
300 =cut
304301
305302 sub pdf_file {
306303 my ($self, $file, $page_number, %position) = @_;
44 use strict;
55 use warnings;
66
7 our $VERSION = '3.019'; # VERSION
7 our $VERSION = '3.020'; # VERSION
88 my $LAST_UPDATE = '2.029'; # manually update whenever code is changed
99
1010 use PDF::Builder::Basic::PDF::Utils;
44 use strict;
55 use warnings;
66
7 our $VERSION = '3.019'; # VERSION
7 our $VERSION = '3.020'; # VERSION
88 my $LAST_UPDATE = '3.017'; # manually update whenever code is changed
99
1010 use POSIX qw(floor);
44 use strict;
55 use warnings;
66
7 our $VERSION = '3.019'; # VERSION
7 our $VERSION = '3.020'; # VERSION
88 my $LAST_UPDATE = '3.018'; # manually update whenever code is changed
99
1010 use Compress::Zlib;
44 use strict;
55 no warnings qw[ deprecated recursion uninitialized ];
66
7 our $VERSION = '3.019'; # VERSION
7 our $VERSION = '3.020'; # VERSION
88 my $LAST_UPDATE = '3.016'; # manually update whenever code is changed
99
1010 use PDF::Builder::Util;
44 use strict;
55 no warnings qw[ recursion uninitialized ];
66
7 our $VERSION = '3.019'; # VERSION
7 our $VERSION = '3.020'; # VERSION
88 my $LAST_UPDATE = '3.016'; # manually update whenever code is changed
99
1010 use Carp;
44 use strict;
55 no warnings qw[ deprecated recursion uninitialized ];
66
7 our $VERSION = '3.019'; # VERSION
7 our $VERSION = '3.020'; # VERSION
88 my $LAST_UPDATE = '3.016'; # manually update whenever code is changed
99
1010 use PDF::Builder::Basic::PDF::Utils;
44 use strict;
55 no warnings qw[ deprecated recursion uninitialized ];
66
7 our $VERSION = '3.019'; # VERSION
7 our $VERSION = '3.020'; # VERSION
88 my $LAST_UPDATE = '3.018'; # manually update whenever code is changed
99
1010 use Encode qw(:all);
44 use strict;
55 no warnings qw[ deprecated recursion uninitialized ];
66
7 our $VERSION = '3.019'; # VERSION
7 our $VERSION = '3.020'; # VERSION
88 my $LAST_UPDATE = '3.010'; # manually update whenever code is changed
99
1010 use PDF::Builder::Basic::PDF::Utils;
44 use strict;
55 no warnings qw[ deprecated recursion uninitialized ];
66
7 our $VERSION = '3.019'; # VERSION
7 our $VERSION = '3.020'; # VERSION
88 my $LAST_UPDATE = '3.004'; # manually update whenever code is changed
99
1010 use PDF::Builder::Basic::PDF::Utils;
44 use strict;
55 no warnings qw[ deprecated recursion uninitialized ];
66
7 our $VERSION = '3.019'; # VERSION
7 our $VERSION = '3.020'; # VERSION
88 my $LAST_UPDATE = '3.004'; # manually update whenever code is changed
99
1010 use PDF::Builder::Basic::PDF::Utils;
44 use strict;
55 no warnings qw[ deprecated recursion uninitialized ];
66
7 our $VERSION = '3.019'; # VERSION
7 our $VERSION = '3.020'; # VERSION
88 my $LAST_UPDATE = '3.004'; # manually update whenever code is changed
99
1010 =head1 NAME
44 use strict;
55 no warnings qw[ deprecated recursion uninitialized ];
66
7 our $VERSION = '3.019'; # VERSION
7 our $VERSION = '3.020'; # VERSION
88 my $LAST_UPDATE = '3.004'; # manually update whenever code is changed
99
1010 use PDF::Builder::Basic::PDF::Utils;
44 use strict;
55 no warnings qw[ deprecated recursion uninitialized ];
66
7 our $VERSION = '3.019'; # VERSION
7 our $VERSION = '3.020'; # VERSION
88 my $LAST_UPDATE = '3.004'; # manually update whenever code is changed
99
1010 use PDF::Builder::Basic::PDF::Utils;
44 use strict;
55 no warnings qw[ deprecated recursion uninitialized ];
66
7 our $VERSION = '3.019'; # VERSION
7 our $VERSION = '3.020'; # VERSION
88 my $LAST_UPDATE = '3.016'; # manually update whenever code is changed
99
1010 use PDF::Builder::Basic::PDF::Utils;
22 use strict;
33 use warnings;
44
5 our $VERSION = '3.019'; # VERSION
5 our $VERSION = '3.020'; # VERSION
66 my $LAST_UPDATE = '2.029'; # manually update whenever code is changed
77
88 =head1 NAME
44 use strict;
55 no warnings qw[ deprecated recursion uninitialized ];
66
7 our $VERSION = '3.019'; # VERSION
7 our $VERSION = '3.020'; # VERSION
88 my $LAST_UPDATE = '3.017'; # manually update whenever code is changed
99
1010 use PDF::Builder::Basic::PDF::Utils;
44 use strict;
55 no warnings qw[ deprecated recursion uninitialized ];
66
7 our $VERSION = '3.019'; # VERSION
7 our $VERSION = '3.020'; # VERSION
88 my $LAST_UPDATE = '3.017'; # manually update whenever code is changed
99
1010 use PDF::Builder::Util;
22 use strict;
33 use warnings;
44
5 our $VERSION = '3.019'; # VERSION
5 our $VERSION = '3.020'; # VERSION
66 my $LAST_UPDATE = '3.013'; # manually update whenever code is changed
77
88 =head1 NAME
22 use strict;
33 use warnings;
44
5 our $VERSION = '3.019'; # VERSION
5 our $VERSION = '3.020'; # VERSION
66 my $LAST_UPDATE = '3.019'; # manually update whenever code is changed
77
88 =head1 NAME
22 use strict;
33 use warnings;
44
5 our $VERSION = '3.019'; # VERSION
5 our $VERSION = '3.020'; # VERSION
66 my $LAST_UPDATE = '3.019'; # manually update whenever code is changed
77
88 =head1 NAME
22 use strict;
33 use warnings;
44
5 our $VERSION = '3.019'; # VERSION
5 our $VERSION = '3.020'; # VERSION
66 my $LAST_UPDATE = '3.019'; # manually update whenever code is changed
77
88 =head1 NAME
22 use strict;
33 use warnings;
44
5 our $VERSION = '3.019'; # VERSION
5 our $VERSION = '3.020'; # VERSION
66 my $LAST_UPDATE = '3.019'; # manually update whenever code is changed
77
88 =head1 NAME
22 use strict;
33 use warnings;
44
5 our $VERSION = '3.019'; # VERSION
5 our $VERSION = '3.020'; # VERSION
66 my $LAST_UPDATE = '3.018'; # manually update whenever code is changed
77
88 =head1 NAME
22 use strict;
33 use warnings;
44
5 our $VERSION = '3.019'; # VERSION
5 our $VERSION = '3.020'; # VERSION
66 my $LAST_UPDATE = '3.018'; # manually update whenever code is changed
77
88 =head1 NAME
22 use strict;
33 use warnings;
44
5 our $VERSION = '3.019'; # VERSION
5 our $VERSION = '3.020'; # VERSION
66 my $LAST_UPDATE = '3.018'; # manually update whenever code is changed
77
88 =head1 NAME
22 use strict;
33 use warnings;
44
5 our $VERSION = '3.019'; # VERSION
5 our $VERSION = '3.020'; # VERSION
66 my $LAST_UPDATE = '3.018'; # manually update whenever code is changed
77
88 =head1 NAME
22 use strict;
33 use warnings;
44
5 our $VERSION = '3.019'; # VERSION
5 our $VERSION = '3.020'; # VERSION
66 my $LAST_UPDATE = '3.019'; # manually update whenever code is changed
77
88 =head1 NAME
22 use strict;
33 use warnings;
44
5 our $VERSION = '3.019'; # VERSION
5 our $VERSION = '3.020'; # VERSION
66 my $LAST_UPDATE = '3.019'; # manually update whenever code is changed
77
88 =head1 NAME
22 use strict;
33 use warnings;
44
5 our $VERSION = '3.019'; # VERSION
5 our $VERSION = '3.020'; # VERSION
66 my $LAST_UPDATE = '3.019'; # manually update whenever code is changed
77
88 =head1 NAME
22 use strict;
33 use warnings;
44
5 our $VERSION = '3.019'; # VERSION
5 our $VERSION = '3.020'; # VERSION
66 my $LAST_UPDATE = '3.019'; # manually update whenever code is changed
77
88 =head1 NAME
22 use strict;
33 use warnings;
44
5 our $VERSION = '3.019'; # VERSION
5 our $VERSION = '3.020'; # VERSION
66 my $LAST_UPDATE = '3.019'; # manually update whenever code is changed
77
88 =head1 NAME
22 use strict;
33 use warnings;
44
5 our $VERSION = '3.019'; # VERSION
5 our $VERSION = '3.020'; # VERSION
66 my $LAST_UPDATE = '3.019'; # manually update whenever code is changed
77
88 =head1 NAME
22 use strict;
33 use warnings;
44
5 our $VERSION = '3.019'; # VERSION
5 our $VERSION = '3.020'; # VERSION
66 my $LAST_UPDATE = '3.019'; # manually update whenever code is changed
77
88 =head1 NAME
22 use strict;
33 use warnings;
44
5 our $VERSION = '3.019'; # VERSION
5 our $VERSION = '3.020'; # VERSION
66 my $LAST_UPDATE = '3.019'; # manually update whenever code is changed
77
88 =head1 NAME
22 use strict;
33 use warnings;
44
5 our $VERSION = '3.019'; # VERSION
5 our $VERSION = '3.020'; # VERSION
66 my $LAST_UPDATE = '3.019'; # manually update whenever code is changed
77
88 =head1 NAME
22 use strict;
33 use warnings;
44
5 our $VERSION = '3.019'; # VERSION
5 our $VERSION = '3.020'; # VERSION
66 my $LAST_UPDATE = '3.018'; # manually update whenever code is changed
77
88 =head1 NAME
22 use strict;
33 use warnings;
44
5 our $VERSION = '3.019'; # VERSION
5 our $VERSION = '3.020'; # VERSION
66 my $LAST_UPDATE = '3.018'; # manually update whenever code is changed
77
88 =head1 NAME
22 use strict;
33 use warnings;
44
5 our $VERSION = '3.019'; # VERSION
5 our $VERSION = '3.020'; # VERSION
66 my $LAST_UPDATE = '3.018'; # manually update whenever code is changed
77
88 =head1 NAME
22 use strict;
33 use warnings;
44
5 our $VERSION = '3.019'; # VERSION
5 our $VERSION = '3.020'; # VERSION
66 my $LAST_UPDATE = '3.018'; # manually update whenever code is changed
77
88 =head1 NAME
22 use strict;
33 use warnings;
44
5 our $VERSION = '3.019'; # VERSION
5 our $VERSION = '3.020'; # VERSION
66 my $LAST_UPDATE = '3.018'; # manually update whenever code is changed
77
88 =head1 NAME
22 use strict;
33 use warnings;
44
5 our $VERSION = '3.019'; # VERSION
5 our $VERSION = '3.020'; # VERSION
66 my $LAST_UPDATE = '3.018'; # manually update whenever code is changed
77
88 =head1 NAME
22 use strict;
33 use warnings;
44
5 our $VERSION = '3.019'; # VERSION
5 our $VERSION = '3.020'; # VERSION
66 my $LAST_UPDATE = '3.018'; # manually update whenever code is changed
77
88 =head1 NAME
22 use strict;
33 use warnings;
44
5 our $VERSION = '3.019'; # VERSION
5 our $VERSION = '3.020'; # VERSION
66 my $LAST_UPDATE = '3.018'; # manually update whenever code is changed
77
88 =head1 NAME
22 use strict;
33 use warnings;
44
5 our $VERSION = '3.019'; # VERSION
5 our $VERSION = '3.020'; # VERSION
66 my $LAST_UPDATE = '2.029'; # manually update whenever code is changed
77
88 =head1 NAME
22 use strict;
33 use warnings;
44
5 our $VERSION = '3.019'; # VERSION
5 our $VERSION = '3.020'; # VERSION
66 my $LAST_UPDATE = '2.029'; # manually update whenever code is changed
77
88 =head1 NAME
22 use strict;
33 use warnings;
44
5 our $VERSION = '3.019'; # VERSION
5 our $VERSION = '3.020'; # VERSION
66 my $LAST_UPDATE = '3.019'; # manually update whenever code is changed
77
88 =head1 NAME
44 use strict;
55 no warnings qw[ deprecated recursion uninitialized ];
66
7 our $VERSION = '3.019'; # VERSION
7 our $VERSION = '3.020'; # VERSION
88 my $LAST_UPDATE = '3.017'; # manually update whenever code is changed
99
1010 use File::Basename;
44 use strict;
55 no warnings qw[ deprecated recursion uninitialized ];
66
7 our $VERSION = '3.019'; # VERSION
7 our $VERSION = '3.020'; # VERSION
88 my $LAST_UPDATE = '3.017'; # manually update whenever code is changed
99
1010 use Encode qw(:all);
44 use strict;
55 no warnings qw[ deprecated recursion uninitialized ];
66
7 our $VERSION = '3.019'; # VERSION
7 our $VERSION = '3.020'; # VERSION
88 my $LAST_UPDATE = '3.017'; # manually update whenever code is changed
99
1010 use Math::Trig; # CAUTION: deg2rad(0) = deg2rad(360) = 0!
44 use strict;
55 no warnings qw[ deprecated recursion uninitialized ];
66
7 our $VERSION = '3.019'; # VERSION
7 our $VERSION = '3.020'; # VERSION
88 my $LAST_UPDATE = '3.006'; # manually update whenever code is changed
99
1010 use Encode qw(:all);
22 use strict;
33 use warnings;
44
5 our $VERSION = '3.019'; # VERSION
5 our $VERSION = '3.020'; # VERSION
66 my $LAST_UPDATE = '3.013'; # manually update whenever code is changed
77
88 =head1 NAME
22 use strict;
33 use warnings;
44
5 our $VERSION = '3.019'; # VERSION
6 my $LAST_UPDATE = '3.017'; # manually update whenever code is changed
5 our $VERSION = '3.020'; # VERSION
6 my $LAST_UPDATE = '3.020'; # manually update whenever code is changed
77
88 =head1 NAME
99
1010 PDF::Builder::Resource::PaperSizes - list of standard paper sizes and their dimensions
1111
12 =head2 Information and Usage
13
14 This is a list of standard page (media) sizes by I<name> (e.g., 'A4' or
15 'Legal'), given by width and height in Big Points (72 per inch). See the code
16 in PaperSizes.pm for the actual entries. You do B<not> have to use these names;
17 they are merely provided as convenient shortcuts. You can always specify the
18 desired dimensions (in points) yourself.
19
20 The PDF specification (and PDF readers) default to US Letter size (portrait
21 orientation, 8.5 inches wide by 11 inches high). If you want to use anything
22 else, you will have to make a C<mediabox()> call to specify the media (paper)
23 size. For named sizes, capitalization doesn't matter (all entries are folded
24 to lower case, so 'A4' and 'a4' work the same).
25
26 Different sources give somewhat different paper dimensions, especially for
27 archaic or unusual sizes, so take care and measure your actual paper before
28 printing, so you can avoid wasting paper and time printing to the wrong
29 mediabox! Also keep in mind that many printers cannot print all the way to the
30 edge (don't want to get ink or toner on the paper rollers), so set your margins
31 accordingly.
32
1233 =cut
1334
35 # see sites such as https://www.papersizes.org/ for all the paper size
36 # information you would ever want to know
37 # http://tug.ctan.org/macros/latex/contrib/memoir/memman.pdf pg 39
38
1439 sub get_paper_sizes {
15 # dimensions are in Big Points
40
41 # dimensions are Width and Height in Big Points. divide by 72 to get
42 # inches, or divide by 2.83 (72/25.4) to get mm. use page and coordinate
43 # rotations to rotate into landscape mode and vice-versa.
44
1645 return (
1746 # Metric sizes
1847 # non-standard names 4a, 2a, 4b, 2b have been removed
2655 'a4' => [ 595, 842 ],
2756 'a5' => [ 421, 595 ],
2857 'a6' => [ 297, 421 ],
58 'a7' => [ 210, 297 ],
59 'a8' => [ 147, 210 ],
60 'a9' => [ 105, 147 ],
61 'a10' => [ 74, 105 ],
2962 '4b0' => [ 5656, 8000 ],
3063 '2b0' => [ 4000, 5656 ],
3164 'b0' => [ 2828, 4000 ],
3568 'b4' => [ 707, 1000 ],
3669 'b5' => [ 500, 707 ],
3770 'b6' => [ 353, 500 ],
38 'b7' => [ 250, 500 ],
71 'b7' => [ 250, 353 ],
3972 'b8' => [ 176, 250 ],
4073 'b9' => [ 125, 176 ],
4174 'b10' => [ 88, 125 ],
42 'c0' => [ 2600, 3677 ],
75 'c0' => [ 2600, 3677 ], # C series envelopes
4376 'c1' => [ 1837, 2600 ],
4477 'c2' => [ 1298, 1837 ],
4578 'c3' => [ 918, 1298 ],
70103 'p6' => [ 303, 397 ],
71104
72105 # mixed
73 'universal' => [ 595, 792 ], # smaller of A4 and Letter
106 'universal' => [ 595, 792 ], # smaller of A4 and US Letter,
107 # will print on either paper size
74108
75109 # US sizes
76 'broadsheet' => [ 1296, 1584 ],
110 'broadsheet' => [ 1296, 1584 ], # varies, sometimes 1224 x 1584
77111 'executive' => [ 522, 756 ],
78 'foolscap' => [ 576, 936 ],
112 'foolscap' => [ 576, 936 ], # also listed as 360x486
79113 'gov-legal' => [ 612, 936 ],
80114 'gov-letter' => [ 576, 756 ],
81 'jr-legal' => [ 576, 360 ],
115 'jr-legal' => [ 360, 576 ],
82116 'ledger' => [ 1224, 792 ], # = tabloid in landscape orientation
83117 'legal' => [ 612, 1008 ],
84118 'letter' => [ 612, 792 ],
87121 'student' => [ 396, 612 ],
88122 'tabloid' => [ 792, 1224 ],
89123 '36x36' => [ 2592, 2592 ],
124 'dbill' => [ 216, 504 ],
125 'statement' => [ 396, 612 ], # = student
126 'old-paper' => [ 648, 864 ],
127 'half-letter' => [ 396, 612 ], # = student
90128 'env-10' => [ 297, 684 ],
91129 'env-monarch' => [ 279, 540 ],
92130 'a' => [ 612, 791 ], # ANSI technical drawing paper
95133 'd' => [ 1585, 2449 ],
96134 'e' => [ 2449, 3169 ],
97135 'f' => [ 2016, 2880 ],
136 'b-plus' => [ 936, 1368 ], # aka super-B, A3+, super-A3
137 'arch-a' => [ 648, 864 ],
138 'arch-b' => [ 864, 1296 ],
139 'arch-c' => [ 1296, 1728 ],
140 'arch-d' => [ 1728, 2592 ],
141 'arch-e' => [ 2592, 3456 ],
142 'arch-e1' => [ 2160, 3024 ],
143 'pott' => [ 288, 450 ], # British sizes
144 'post' => [ 360, 576 ],
145 'large-post' => [ 378, 594 ],
146 'crown' => [ 360, 540 ],
147 'large-crown' => [ 378, 576 ],
148 'demy' => [ 409, 630 ],
149 'small-demy' => [ 409, 612 ],
150 'medium' => [ 414, 648 ],
151 'royal' => [ 450, 720 ],
152 'small-royal' => [ 445, 666 ],
153 'super-royal' => [ 486, 738 ],
154 'imperial' => [ 540, 792 ],
98155 );
99156 }
100157
44 use strict;
55 use warnings;
66
7 our $VERSION = '3.019'; # VERSION
7 our $VERSION = '3.020'; # VERSION
88 my $LAST_UPDATE = '2.031'; # manually update whenever code is changed
99
1010 =head1 NAME
44 use strict;
55 use warnings;
66
7 our $VERSION = '3.019'; # VERSION
7 our $VERSION = '3.020'; # VERSION
88 my $LAST_UPDATE = '2.029'; # manually update whenever code is changed
99
1010 =head1 NAME
22 use strict;
33 use warnings;
44
5 our $VERSION = '3.019'; # VERSION
5 our $VERSION = '3.020'; # VERSION
66 my $LAST_UPDATE = '3.016'; # manually update whenever code is changed
77
88 use Carp;
44 use strict;
55 use warnings;
66
7 our $VERSION = '3.019'; # VERSION
7 our $VERSION = '3.020'; # VERSION
88 my $LAST_UPDATE = '2.029'; # manually update whenever code is changed
99
1010 =head1 NAME
44 use strict;
55 use warnings;
66
7 our $VERSION = '3.019'; # VERSION
7 our $VERSION = '3.020'; # VERSION
88 my $LAST_UPDATE = '3.004'; # manually update whenever code is changed
99
1010 =head1 NAME
44 use strict;
55 use warnings;
66
7 our $VERSION = '3.019'; # VERSION
7 our $VERSION = '3.020'; # VERSION
88 my $LAST_UPDATE = '3.017'; # manually update whenever code is changed
99
1010 =head1 NAME
44 use strict;
55 use warnings;
66
7 our $VERSION = '3.019'; # VERSION
7 our $VERSION = '3.020'; # VERSION
88 my $LAST_UPDATE = '3.004'; # manually update whenever code is changed
99
1010 =head1 NAME
44 use strict;
55 use warnings;
66
7 our $VERSION = '3.019'; # VERSION
7 our $VERSION = '3.020'; # VERSION
88 my $LAST_UPDATE = '3.004'; # manually update whenever code is changed
99
1010 =head1 NAME
44 use strict;
55 use warnings;
66
7 our $VERSION = '3.019'; # VERSION
7 our $VERSION = '3.020'; # VERSION
88 my $LAST_UPDATE = '3.010'; # manually update whenever code is changed
99
1010 use PDF::Builder::Util;
44 use strict;
55 use warnings;
66
7 our $VERSION = '3.019'; # VERSION
7 our $VERSION = '3.020'; # VERSION
88 my $LAST_UPDATE = '3.016'; # manually update whenever code is changed
99
1010 use PDF::Builder::Basic::PDF::Dict;
44 use strict;
55 use warnings;
66
7 our $VERSION = '3.019'; # VERSION
7 our $VERSION = '3.020'; # VERSION
88 my $LAST_UPDATE = '2.031'; # manually update whenever code is changed
99
1010 use PDF::Builder::Basic::PDF::Utils;
44 use strict;
55 no warnings qw[ deprecated recursion uninitialized ];
66
7 our $VERSION = '3.019'; # VERSION
7 our $VERSION = '3.020'; # VERSION
88 my $LAST_UPDATE = '3.004'; # manually update whenever code is changed
99
1010 use PDF::Builder::Util;
44 use strict;
55 no warnings qw[ deprecated recursion uninitialized ];
66
7 our $VERSION = '3.019'; # VERSION
7 our $VERSION = '3.020'; # VERSION
88 my $LAST_UPDATE = '3.013'; # manually update whenever code is changed
99
1010 use IO::File;
44 use strict;
55 use warnings;
66
7 our $VERSION = '3.019'; # VERSION
7 our $VERSION = '3.020'; # VERSION
88 my $LAST_UPDATE = '3.017'; # manually update whenever code is changed
99
1010 use IO::File;
44 use strict;
55 use warnings;
66
7 our $VERSION = '3.019'; # VERSION
7 our $VERSION = '3.020'; # VERSION
88 my $LAST_UPDATE = '3.019'; # manually update whenever code is changed
99
1010 use Compress::Zlib;
44 use strict;
55 use warnings;
66
7 our $VERSION = '3.019'; # VERSION
8 my $LAST_UPDATE = '3.019'; # manually update whenever code is changed
7 our $VERSION = '3.020'; # VERSION
8 my $LAST_UPDATE = '3.020'; # manually update whenever code is changed
99
1010 use Compress::Zlib;
1111 use POSIX qw(ceil floor);
247247
248248 # transfer over the unpacked (uncompressed, unfiltered) data rows (IDAT)
249249 # to self->{' stream'}. stream is already initialized to empty
250 my $rows = $png->get_rows();
251 for (my $row = 0; $row < @{$rows}; $row++) {
252 $self->{' stream'} .= $rows->[$row];
250 # note that this loop is eliminated for RGBA and GA, as they
251 # are read directly from $png via split_alpha
252 if ($cs != PNG_COLOR_TYPE_GRAY_ALPHA &&
253 $cs != PNG_COLOR_TYPE_RGB_ALPHA) {
254 my $rows = $png->get_rows();
255 for (my $row = 0; $row < @{$rows}; $row++) {
256 $self->{' stream'} .= $rows->[$row];
257 }
253258 }
254259
255260 $self->width($w);
448453 # (1 or 2 bytes) to self->stream, and the second half (1 or
449454 # 2 bytes) into dict->stream as the Alpha SMask. delete
450455 # leftover self->stream.
451 my $clearstream = $self->{' stream'}; # s/b uncompressed, unfiltered
452456 delete $self->{' nofilt'};
453 #delete $self->{' stream'}; # will reduce size 50% when Alpha removed
454457 $dict->{' stream'} = '';
455458 $self->{' stream'} = '';
456 # TBD: the following pixel-by-pixel manipulation is SLOW as
457 # molasses, but I haven't found anything faster. pack(unpack(..))
458 # is about 3x slower, and self->stream .= doesn't work (corrupts).
459 # have requested that it be built into libpng.a.
460 foreach my $n (0 .. $h*$w-1) {
461 # pull out Alpha from pixel into separate Mask area
462 vec($dict->{' stream'}, $n, $bpc) = vec($clearstream, $n*2+1, $bpc);
463 # consolidate remaining 1 sample into self->stream
464 vec($self->{' stream'}, $n, $bpc) = vec($clearstream, $n*2, $bpc);
465 }
466 }
459 # high-speed splitting out of alpha channel
460 my $split = split_alpha($png);
461 $self->{' stream'} = $split->{'data'};
462 $dict->{' stream'} = $split->{'alpha'};
463 }
467464 # compress all but short streams
468465 if (length($self->{' stream'}) > 32) {
469466 $self->{' stream'} = Compress::Zlib::compress($self->{' stream'});
522519 # (1 or 2 bytes) to dict->stream as the Alpha SMask, and the
523520 # first 3/4 (3 * 1 or 2 bytes) into self->stream as the image.
524521 # delete leftover self->stream.
525 my $clearstream = $self->{' stream'}; # s/b uncompressed, unfiltered
526522 delete $self->{' nofilt'};
527 #delete $self->{' stream'}; # will reduce size 25% when Alpha removed
528523 $dict->{' stream'} = '';
529524 $self->{' stream'} = '';
530 # TBD: the following pixel-by-pixel manipulation is SLOW as
531 # molasses, but I haven't found anything faster. pack(unpack(..))
532 # is about 3x slower, and self->stream .= doesn't work (corrupts).
533 # have requested that it be built into libpng.a.
534 foreach my $n (0 .. $h*$w-1) {
535 # pull out Alpha from pixel into separate Mask area
536 vec($dict->{' stream'}, $n, $bpc) = vec($clearstream, $n*4+3, $bpc);
537 # close up remaining 3 samples into self->stream
538 vec($self->{' stream'}, $n*3, $bpc) = vec($clearstream, $n*4, $bpc);
539 vec($self->{' stream'}, $n*3+1, $bpc) = vec($clearstream, $n*4+1, $bpc);
540 vec($self->{' stream'}, $n*3+2, $bpc) = vec($clearstream, $n*4+2, $bpc);
541 }
525 # high-speed splitting out of alpha channel
526 my $split = split_alpha($png);
527 $self->{' stream'} = $split->{'data'};
528 $dict->{' stream'} = $split->{'alpha'};
542529 }
543530 # compress all but short streams
544531 if (length($self->{' stream'}) > 32) {
00 package PDF::Builder::Resource::XObject::Image::PNM;
11
2 # For spec details, see man pages pam(5), pbm(5), pgm(5), pnm(5),
3 # ppm(5), which were pasted into the __END__ of this file in an
4 # earlier revision.
2 # For spec details, see man pages pam(5), pbm(5), pgm(5), pnm(5), ppm(5)
53
64 use base 'PDF::Builder::Resource::XObject::Image';
75
86 use strict;
97 no warnings qw[ deprecated recursion uninitialized ];
108
11 our $VERSION = '3.019'; # VERSION
12 my $LAST_UPDATE = '3.019'; # manually update whenever code is changed
9 our $VERSION = '3.020'; # VERSION
10 my $LAST_UPDATE = '3.020'; # manually update whenever code is changed
1311
1412 use IO::File;
1513 use PDF::Builder::Util;
2018
2119 PDF::Builder::Resource::XObject::Image::PNM - support routines for PNM (Portable aNy Map) image library. Inherits from L<PDF::Builder::Resource::XObject::Image>
2220
21 =head2 METHODS
22
23 =over
24
25 =new($pdf, $file, $name)
26
27 Returns an image in the PDF. PNM types 1 (ASCII/plain bi-level/PBM),
28 2 (ASCII/plain grayscale/PGM), 3 (ASCII/plain RGB/PPM),
29 4 (binary/raw bi-level/PBM), 5 (binary/raw grayscale/PGM), and
30 6 (binary/raw RGB/PPM) are supported.
31
32 For bi-level, only values 0/1 (white/black) are supported. For grayscale, the
33 maximum sample (full white) may be anything from 1 to 65535, with 0 being full
34 black. If the maximum sample value is 255 or smaller, one byte of raw binary
35 data per pixel, otherwise two bytes. For RGB, each sample (full-on of that
36 color) may be anything from 1 to 65535 (the same maximum for all three colors),
37 with 0 being full black. If the maximum sample value is 255 or smaller, three
38 bytes of raw binary data per pixel, otherwise six bytes.
39
40 =back
41
2342 =cut
2443
44 # -------------------------------------------------------------------
2545 sub new {
2646 my ($class, $pdf, $file, $name) = @_;
2747
4060 return $self;
4161 }
4262
63 # -------------------------------------------------------------------
4364 # READPPMHEADER
4465 # taken from Image::PBMLib
4566 # Copyright by Benjamin Elijah Griffin (28 Feb 2003)
67 # extensively modified by Phil M Perry, copyright 2020
4668 #
4769 sub readppmheader {
48 my $gr = shift; # input file glob ref
49 my $in = '';
50 my $no_comments;
51 my %info;
52 my $rc;
53 $info{'error'} = undef;
54
55 $rc = read($gr, $in, 3);
56
57 if (!defined($rc) || $rc != 3) {
58 $info{'error'} = 'Read error or EOF';
59 return \%info;
60 }
61
62 if ($in =~ /^P([1-6])\s/) {
63 $info{'type'} = $1;
64 if ($info{'type'} > 3) {
65 $info{'raw'} = 1;
70 my ($gr, $buffer) = @_; # already-opened input file's filehandle
71 my %info;
72 $info{'error'} = undef;
73 my ($width, $height, $max, $comment, $content);
74
75 # extension: allow whitespace BEFORE the magic number (usually none)
76 # read Px magic number
77 ($buffer, $comment) = eat_whitespace($gr, $buffer, 0);
78 ($buffer, $content) = read_content($gr, $buffer);
79
80 if (length($content) != 2) {
81 $info{'error'} = 'Read error or EOF';
82 return (\%info, $buffer);
83 }
84
85 if ($content =~ /^P([1-6])/) {
86 $info{'type'} = $1;
87 if ($info{'type'} > 3) {
88 $info{'raw'} = 1; # P4-6 is raw (binary)
89 } else {
90 $info{'raw'} = 0; # P1-3 is plain (ASCII)
91 }
6692 } else {
67 $info{'raw'} = 0;
93 $info{'error'} = 'Unrecognized magic number, not 1..6';
94 return (\%info, $buffer);
6895 }
6996
7097 if ($info{'type'} == 1 or $info{'type'} == 4) {
71 $info{'max'} = 1;
72 $info{'bgp'} = 'b';
98 $max = 1;
99 $info{'bgp'} = 'b';
73100 } elsif ($info{'type'} == 2 or $info{'type'} == 5) {
74 $info{'bgp'} = 'g';
101 # need to read and validate 'max'
102 $info{'bgp'} = 'g';
103 } else { # 3 or 6
104 # need to read and validate 'max'
105 $info{'bgp'} = 'p';
106 }
107
108 # expect width as unsigned integer > 0
109 ($buffer, $comment) = eat_whitespace($gr, $buffer, 0);
110 ($buffer, $content) = read_content($gr, $buffer);
111 if (length($content) == 0) {
112 $info{'error'} = 'Read error or EOF on width';
113 return (\%info, $buffer);
114 }
115 if ($content =~ m/(^\d+)$/) {
116 $width = $1;
75117 } else {
76 $info{'bgp'} = 'p';
77 }
78
118 $info{'error'} = 'Invalid width value '.$1;
119 return (\%info, $buffer);
120 }
121 if ($width < 1) {
122 $info{'error'} = 'Invalid width value '.$width;
123 return (\%info, $buffer);
124 }
125
126 # expect height as unsigned integer > 0
127 ($buffer, $comment) = eat_whitespace($gr, $buffer, 0);
128 ($buffer, $content) = read_content($gr, $buffer);
129 if (length($content) == 0) {
130 $info{'error'} = 'Read error or EOF on height';
131 return (\%info, $buffer);
132 }
133 if ($content =~ m/(^\d+)$/) {
134 $height = $1;
135 } else {
136 $info{'error'} = 'Invalid height value '.$1;
137 return (\%info, $buffer);
138 }
139 if ($height < 1) {
140 $info{'error'} = 'Invalid height value '.$height;
141 return (\%info, $buffer);
142 }
143
144 # expect max sample value as unsigned integer > 0 & < 65536
145 # IF grayscale or pixmap (RGB). already set to 1 for bi-level
146 if ($info{'bgp'} =~ m/^[gp]$/) {
147 ($buffer, $comment) = eat_whitespace($gr, $buffer, 0);
148 ($buffer, $content) = read_content($gr, $buffer);
149 if (length($content) == 0) {
150 $info{'error'} = 'Read error or EOF on max';
151 return (\%info, $buffer);
152 }
153 if ($content =~ m/(^\d+)$/) {
154 $max = $1;
155 } else {
156 $info{'error'} = 'Invalid max value '.$1;
157 return (\%info, $buffer);
158 }
159 if ($max < 1 || $max > 65535) {
160 $info{'error'} = 'Invalid max value '.$max;
161 return (\%info, $buffer);
162 }
163 }
164
165 $info{'width'} = $width;
166 $info{'height'} = $height;
167 $info{'max'} = $max;
168
169 # for binary (raw) files, a single whitespace character should be seen.
170 # for ASCII (plain) files, extend to allow arbitrary whitespace
171 if ($info{'raw'}) {
172 # The buffer should have a single ws char in it already, left over from
173 # the previous content read. We don't want to read anything beyond that
174 # in case a byte value happens to be a valid whitespace character! If
175 # the file format is botched and there is additional whitespace, it
176 # will unfortunately be read as binary data.
177 if ($buffer =~ m/^\s/) {
178 $buffer = substr($buffer, 1); # discard first character
179 } else {
180 $info{'error'} = 'Expected single whitespace before raster data';
181 return (\%info, $buffer);
182 }
183 } else {
184 # As an extension, for plain (ASCII) format we allow arbitrary
185 # whitespace (including comments) after the max value and before the
186 # raster data, not just one whitespace.
187 ($buffer, $comment) = eat_whitespace($gr, $buffer, 0);
188 }
189
190 return (\%info, $buffer);
191 } # end of readppmheader()
192
193 # -------------------------------------------------------------------
194 # eat and discard whitespace stream, but return any comment(s) found
195 # within the header, cannot have an EOF during whitespace read
196 sub eat_whitespace {
197 my ($gr, $buffer, $qflag) = @_;
198 # qflag = 0 if OK to read more from file (don't expect an EOF)
199 # = 1 eating ws at end of image, might hit EOF here
200
201 my ($count, $buf, @comment);
202 # first see if enough material is already in the buffer. if not, read some
203 my $in_comment = 0; # not currently processing a comment, just ws.
79204 while (1) {
80 $rc = read($gr, $in, 1, length($in));
81 if (!defined($rc) || $rc != 1) {
82 $info{'error'} = 'Read error or EOF';
83 return \%info;
84 }
85
86 $no_comments = $in;
87 $info{'comments'} = '';
88 while ($no_comments =~ /#.*\n/) {
89 $no_comments =~ s/#(.*\n)/ /;
90 $info{'comments'} .= $1;
91 }
92
93 if ($info{'bgp'} eq 'b') {
94 if ($no_comments =~ /^P\d\s+(\d+)\s+(\d+)\s/) {
95 $info{'width'} = $1;
96 $info{'height'} = $2;
97 last;
98 }
99 } else {
100 if ($no_comments =~ /^P\d\s+(\d+)\s+(\d+)\s+(\d+)\s/) {
101 $info{'width'} = $1;
102 $info{'height'} = $2;
103 $info{'max'} = $3;
104 last;
105 }
106 }
107 } # while reading header
108
109 $info{'fullheader'} = $in;
110
111 } else {
112 $info{'error'} = 'Wrong magic number';
113 }
114
115 return \%info;
116 }
117
205 # is buffer empty? if so, read some content
206 if (length($buffer) == 0) {
207 $count = read($gr, $buffer, 50); # chunk of up to 50 bytes (could be 0)
208 if ($count == 0 && (!$qflag || $in_comment)) {
209 # EOF or read error, is bad thing here
210 print STDERR "EOF or read error reading whitespace.\n";
211 return ($buffer, '');
212 }
213 }
214 # if buffer is still empty (qflag == 1), will exit cleanly
215
216 if (!$in_comment) { $buffer =~ s/^\s+//; }
217 # a bunch of whitespace may have been discarded. if buffer now starts
218 # with a #, it is a comment to be read to EOL. otherwise we're done.
219 if (length($buffer) > 0) {
220 # buffer still has stuff in it (starts with non-ws)
221 if ($buffer =~ m/^#/) {
222 $in_comment = 1;
223 # at start of comment. discard up through \n
224 # (\n might not yet be in buffer!)
225 # special case: #\n
226 if ($buffer =~ s/^#\n//) {
227 # special empty case
228 $in_comment = 0;
229 } elsif ($buffer =~ s/^#\s*([^\n]*)\n//) {
230 push @comment, $1; # has been removed from buffer
231 $in_comment = 0;
232 } else {
233 # haven't gotten to end of comment (\n) yet
234 $count = read($gr, $buf, 50);
235 if ($count == 0) {
236 # EOF or read error, is bad thing here
237 print STDERR "EOF or read error reading whitespace in pixel data\n";
238 return ($buffer, '');
239 }
240 $buffer .= $buf;
241 next;
242 }
243 } else {
244 # non-whitespace, not #. content to be left in buffer
245 $in_comment = 0;
246 last;
247 }
248 } else {
249 # empty buffer, need to read some more
250 if ($qflag && !$in_comment) { last; }
251 next;
252 }
253 } # while(1) until run out of whitespace
254
255 my $comments = '';
256 if (scalar(@comment) > 0) { $comments = join("\n", @comment); }
257 return ($buffer, $comments);
258 } # end of eat_whitespace()
259
260 # -------------------------------------------------------------------
261 # eat a non-whitespace stream, returning the content up until whitespace
262 # should not see an EOF during this (at least one ws after this stream)
263 sub read_content {
264 my ($gr, $buffer) = @_;
265
266 my ($count, $content);
267 $content = '';
268 # first see if enough material is already in the buffer. if not, read some
269 while (1) {
270 # is buffer empty? if so, read some content
271 if (length($buffer) == 0) {
272 $count = read($gr, $buffer, 50); # chunk of up to 50 bytes (could be 0)
273 if ($count == 0) {
274 # EOF or read error, is bad thing here
275 print STDERR "EOF or read error reading content in pixel data\n";
276 return ($buffer, '');
277 }
278 }
279
280 # should always be non-ws content here
281 $buffer =~ s/^([^\s]+)//;
282 $content .= $1; # has been removed from buffer (now possibly empty)
283 # if buffer now empty (didn't see ws char), need to read more
284 if (length($buffer) == 0) { next; }
285 last; # non-empty buffer means it starts with a ws char
286
287 # this function is used for header fields and non-raw pixel data, so
288 # we don't expect to have an EOF immediately after a data item (must
289 # be a \n after it at the last data item).
290
291 } # while(1) until run out of non-whitespace
292
293 return ($buffer, $content);
294 } # end of read_content()
295
296 # -------------------------------------------------------------------
118297 sub read_pnm {
119298 my $self = shift;
120299 my $pdf = shift;
121300 my $file = shift;
122301
123 my ($buf, $t, $s, $line);
302 my ($rc, $buf, $buf2, $s, $pix, $max);
303 # $s is a scale factor for sample not full 8 or 16 bits.
304 # it should scale the input to 0..255 or 0..65535, so final value
305 # will be a full 8 or 16 bits per channel (bpc)
124306 my ($w,$h, $bpc, $cs, $img, @img) = (0,0, '', '', '');
307 my ($info, $buffer, $content, $comment, $sample, $gr);
125308 my $inf;
126309 if (ref($file)) {
127310 $inf = $file;
130313 }
131314 binmode($inf,':raw');
132315 $inf->seek(0, 0);
133 my $info = readppmheader($inf);
134 if ($info->{'type'} == 4) {
135 $bpc = 1;
136 read($inf, $self->{' stream'}, ($info->{'width'}*$info->{'height'}/8));
316 $buffer = ''; # initialize
317 ($info, $buffer) = readppmheader($inf, $buffer);
318 # info (hashref) fields:
319 # error undef or an error description
320 # type magic number 1-6
321 # raw 0 if plain/ASCII, 1 if raw/binary
322 # bgp b=bi-level (1,4) g=grayscale (2,5), p=pixmap/RGB (3,6)
323 # width width (row length/horizontal) in pixels
324 # height height (row count/vertical) in pixels
325 # max sample max value 1 for bi-level, 1-65535 for grayscale/RGB
326 # comments comment line(s), if any (else '')
327 if (defined $info->{'error'}) {
328 print STDERR "Error reported during PNM file header read:\n".($info->{'error'}).".\n";
329 return $self;
330 }
331
332 $w = $info->{'width'};
333 $h = $info->{'height'};
334 $max = $info->{'max'};
335
336 my $bytes_per_sample = 1;
337 if ($max > 255) { $bytes_per_sample = 2; }
338
339 # ------------------------------
340 if ($info->{'type'} == 1) {
341 # plain (ASCII) PBM bi-level, each pixel 0..1, ws between is optional
342
343 $bpc = 1; # one bit per channel/sample/pixel
344 # pack 8 pixels (possibly with don't-care at end of row) to a byte
345 my ($row, $col, $bits); # need to handle rows separately for d/c bits
346 my $qflag;
347 $content = '';
348 for ($row = 0; $row < $h; $row++) {
349 $bits = '';
350 for ($col = 0; $col < $w; $col++) {
351 # could be a single 0 or 1, or a whole bunch lumped together
352 # in one or more groups
353 # buffer has 0 or more entries. handle just one in this loop,
354 # reading in new buffer if necessary
355 if (length($content) == 0) {
356 $qflag = 0;
357 if ($row == $h-1 && $col == $w-1) { $qflag = 1; }
358 ($buffer, $comment) = eat_whitespace($inf, $buffer, $qflag);
359 ($buffer, $content) = read_content($inf, $buffer);
360 if (length($content) == 0) {
361 print STDERR "Unexpected EOF or read error reading pixel data.\n";
362 return $self;
363 }
364 }
365 $sample = substr($content, 0, 1);
366 $content = substr($content, 1);
367 if ($sample ne '0' && $sample ne '1') {
368 print STDERR "Invalid bit value '$sample' in pixel data.\n";
369 return $self;
370 }
371 $bits .= $sample;
372 if (length($bits) == 8) {
373 $self->{' stream'} .= pack('B8', $bits);
374 $bits = '';
375 }
376
377 } # end of cols in row. partial $bits to finish?
378 if ($bits ne '') {
379 while (length($bits) < 8) {
380 $bits .= '0'; # don't care, but must be 0 or 1
381 }
382 $self->{' stream'} .= pack('B8', $bits);
383 }
384 } # end of rows
385
386 $cs = 'DeviceGray'; # at 1 bit per pixel
387 $self->{'Decode'} = PDFArray(PDFNum(1), PDFNum(0));
388
389 # ------------------------------
390 } elsif ($info->{'type'} == 2) {
391 # plain (ASCII) PGM grayscale, each pixel 0..max (1 or 2 bytes)
392
393 # get scale factor $s to fully fill 8 or 16 bit sample (channel)
394 if ($max == 255 || $max == 65535) {
395 $s = 0; # flag: no scaling
396 } elsif ($max > 255) {
397 $s = 65535/$max;
398 } else {
399 $s = 255/$max;
400 }
401 $bpc = 8 * $bytes_per_sample;
402 my $format = 'C';
403 if ($bytes_per_sample == 2) { $format = 'S>'; }
404 my $sample;
405
406 for ($pix=($w*$h); $pix>0; $pix--) {
407 ($buffer, $content) = read_content($inf, $buffer);
408 if (length($content) == 0) {
409 print STDERR "Unexpected EOF or read error reading pixel data.\n";
410 return $self;
411 }
412 ($buffer, $comment) = eat_whitespace($inf, $buffer, $pix==1);
413
414 if ($content =~ m/^\d+$/) {
415 if ($content > $max) {
416 print STDERR "Pixel data entry '$content' higher than $max. Value changed to $max.\n";
417 $content = $max;
418 }
419 } else {
420 print STDERR "Invalid pixel data entry '$content'.\n";
421 return $self;
422 }
423 $sample = $content;
424
425 if ($s > 0) {
426 # scaling needed
427 $sample = int($sample*$s + 0.5); # must not exceed 255/65535
428 }
429 $self->{' stream'} .= pack($format, $sample);
430 } # loop through all pixels
137431 $cs = 'DeviceGray';
432
433 # ------------------------------
434 } elsif ($info->{'type'} == 3) {
435 # plain (ASCII) PPM rgb, each pixel 0..max for R, G, B (1 or 2 bytes)
436
437 # get scale factor $s to fully fill 8 or 16 bit sample (channel)
438 if ($max == 255 || $max == 65535) {
439 $s = 0; # flag: no scaling
440 } elsif ($max > 255) {
441 $s = 65535/$max;
442 } else {
443 $s = 255/$max;
444 }
445 $bpc = 8 * $bytes_per_sample;
446 my $format = 'C';
447 if ($bytes_per_sample == 2) { $format = 'S>'; }
448 my ($sample, $rgb);
449
450 for ($pix=($w*$h); $pix>0; $pix--) {
451 for ($rgb = 0; $rgb < 3; $rgb++) { # R, G, and B values
452 ($buffer, $comment) = eat_whitespace($inf, $buffer, $pix==1);
453 ($buffer, $content) = read_content($inf, $buffer);
454 if (length($content) == 0) {
455 print STDERR "Unexpected EOF or read error reading pixel data.\n";
456 return $self;
457 }
458
459 if ($content =~ m/^\d+$/) {
460 if ($content > $max) {
461 # remember, $pix counts DOWN from w x h
462 print STDERR "Pixel $pix data entry '$content' higher than $max. Value changed to $max.\n";
463 $content = $max;
464 }
465 } else {
466 print STDERR "Invalid pixel data entry '$content'.\n";
467 return $self;
468 }
469 $sample = $content;
470
471 if ($s > 0) {
472 # scaling needed
473 $sample = int($sample*$s + 0.5); # must not exceed 255/65535
474 }
475 $self->{' stream'} .= pack($format, $sample);
476 } # R G B loop
477 } # loop through all pixels
478 $cs = 'DeviceRGB';
479
480 # ------------------------------
481 } elsif ($info->{'type'} == 4) {
482 # raw (binary) PBM bi-level, each pixel 0..1, row packed 8 pixel/byte
483 $bpc = 1; # one bit per channel/sample/pixel
484 # round up for don't care bits at end of row
485 my $bytes = int(($w+7)/8) * $h;
486 $bytes -= length($buffer); # some already read from file!
487 $rc = read($inf, $buf2, $bytes);
488 if ($rc != $bytes) {
489 print STDERR "Unexpected EOF or read error while reading PNM binary pixel data.\n";
490 return $self;
491 }
492 $self->{' stream'} = $buffer.$buf2;
493 $cs = 'DeviceGray'; # at 1 bit per pixel
138494 $self->{'Decode'} = PDFArray(PDFNum(1), PDFNum(0));
495
496 # ------------------------------
139497 } elsif ($info->{'type'} == 5) {
140 $buf .= <$inf>;
141 if ($info->{'max'} == 255) {
142 $s = 0;
143 } else {
144 $s = 255/$info->{'max'};
145 }
146 $bpc = 8;
147 if ($s > 0) {
148 for ($line=($info->{'width'}*$info->{'height'}); $line>0; $line--) {
149 read($inf, $buf, 1);
150 $self->{' stream'} .= pack('C', (unpack('C', $buf)*$s));
498 # raw (binary) PGM grayscale, each pixel 0..max (1 or 2 bytes)
499
500 # get scale factor $s to fully fill 8 or 16 bit sample (channel)
501 if ($max == 255 || $max == 65535) {
502 $s = 0; # flag: no scaling
503 } elsif ($max > 255) {
504 $s = 65535/$max;
505 } else {
506 $s = 255/$max;
507 }
508 $bpc = 8 * $bytes_per_sample;
509 my $format = 'C';
510 if ($bytes_per_sample == 2) { $format = 'S>'; }
511 my ($buf, $sample);
512
513 my $bytes = $w * $h * $bytes_per_sample;
514 $bytes -= length($buffer); # some already read from file!
515 $rc = read($inf, $buf, $bytes);
516 if ($rc != $bytes) {
517 print STDERR "Unexpected EOF or read error reading pixel data.\n";
518 return $self;
519 }
520 $buf = $buffer . $buf;
521 if ($s > 0) {
522 # scaling needed
523 for ($pix=($w*$h); $pix>0; $pix--) {
524 $buf2 = substr($buf, 0, $bytes_per_sample);
525 $buf = substr($buf, $bytes_per_sample);
526 $sample = unpack($format, $buf2);
527 $sample = int($sample*$s + 0.5); # must not exceed 255/65535
528 $self->{' stream'} .= pack($format, $sample);
151529 }
152530 } else {
153 read($inf, $self->{' stream'}, $info->{'width'}*$info->{'height'});
154 # part of file was already read into $buf but not otherwise used
155 $self->{' stream'} = $buf . $self->{' stream'};
531 # no scaling needed
532 $self->{' stream'} = $buf;
156533 }
157534 $cs = 'DeviceGray';
535
536 # ------------------------------
158537 } elsif ($info->{'type'} == 6) {
159 if ($info->{'max'} == 255) {
160 $s = 0;
161 } else {
162 $s = 255/$info->{'max'};
163 }
164 $bpc = 8;
165 if ($s > 0) {
166 for ($line=($info->{'width'}*$info->{'height'}); $line>0; $line--) {
167 read($inf, $buf, 1);
168 $self->{' stream'} .= pack('C', (unpack('C', $buf)*$s));
169 read($inf, $buf, 1);
170 $self->{' stream'} .= pack('C', (unpack('C', $buf)*$s));
171 read($inf, $buf, 1);
172 $self->{' stream'} .= pack('C', (unpack('C', $buf)*$s));
538 # raw (binary) PPM rgb, each pixel 0..max for R, G, B (3 or 6 bytes)
539
540 # get scale factor $s to fully fill 8 or 16 bit sample (channel)
541 if ($max == 255 || $max == 65535) {
542 $s = 0; # flag: no scaling
543 } elsif ($max > 255) {
544 $s = 65535/$max;
545 } else {
546 $s = 255/$max;
547 }
548 $bpc = 8 * $bytes_per_sample;
549 my $format = 'C';
550 if ($bytes_per_sample == 2) { $format = 'S>'; }
551 my ($buf, $sample);
552
553 my $bytes = $w * $h * $bytes_per_sample * 3;
554 $bytes -= length($buffer); # some already read from file!
555 $rc = read($inf, $buf, $bytes);
556 if ($rc != $bytes) {
557 print STDERR "Unexpected EOF or read error reading pixel data.\n";
558 return $self;
559 }
560 $buf = $buffer . $buf;
561 if ($s > 0) {
562 # scaling needed
563 for ($pix=($w*$h); $pix>0; $pix--) {
564 # Red
565 $buf2 = substr($buf, 0, $bytes_per_sample);
566 $sample = unpack($format, $buf2);
567 $sample = int($sample*$s + 0.5); # must not exceed 255/65535
568 $self->{' stream'} .= pack($format, $sample);
569 # Green
570 $buf2 = substr($buf, $bytes_per_sample, $bytes_per_sample);
571 $sample = unpack($format, $buf2);
572 $sample = int($sample*$s + 0.5); # must not exceed 255/65535
573 $self->{' stream'} .= pack($format, $sample);
574 # Blue
575 $buf2 = substr($buf, 2*$bytes_per_sample, $bytes_per_sample);
576 $sample = unpack($format, $buf2);
577 $sample = int($sample*$s + 0.5); # must not exceed 255/65535
578 $self->{' stream'} .= pack($format, $sample);
579
580 $buf = substr($buf, $bytes_per_sample*3);
173581 }
174582 } else {
175 read($inf, $self->{' stream'}, $info->{'width'}*$info->{'height'}*3);
583 # no scaling needed
584 $self->{' stream'} = $buf;
176585 }
177586 $cs = 'DeviceRGB';
178587 }
179588 close($inf);
180589
181 $self->width($info->{'width'});
182 $self->height($info->{'height'});
590 $self->width($w);
591 $self->height($h);
183592
184593 $self->bits_per_component($bpc);
185594
188597 $self->colorspace($cs);
189598
190599 return $self;
191 }
600 } # end of read_pnm()
192601
193602 1;
22 use strict;
33 use warnings;
44
5 our $VERSION = '3.019'; # VERSION
5 our $VERSION = '3.020'; # VERSION
66 my $LAST_UPDATE = '3.001'; # manually update whenever code is changed
77
88 use IO::File;
22 use strict;
33 use warnings;
44
5 our $VERSION = '3.019'; # VERSION
6 my $LAST_UPDATE = '3.010'; # manually update whenever code is changed
5 our $VERSION = '3.020'; # VERSION
6 my $LAST_UPDATE = '3.020'; # manually update whenever code is changed
77
88 use IO::File;
9 use Graphics::TIFF ':all'; # already confirmed to be installed
9 use Graphics::TIFF 7 ':all'; # already confirmed to be installed
1010
1111 =head1 NAME
1212
149149 # TIFFTAG_CELLWIDTH dithering or halftoning matrix cell width
150150 # TIFFTAG_CELLLENGTH dithering or halftoning matrix cell height
151151 # palette RGB table definition
152 $self->{'colorMapOffset'} = $self->{'object'}->GetField(TIFFTAG_COLORMAP);
153 $self->{'colorMapSamples'} = $#{$self->{'colorMapOffset'}}+1;
154 $self->{'colorMapLength'} = $self->{'colorMapSamples'}*2; # shorts!
152 $self->{'colorMap'} = [ $self->{'object'}->GetField(TIFFTAG_COLORMAP) ];
155153 # TIFFTAG_GRAYRESPONSEUNIT describe integer->float mapping
156154 # TIFFTAG_GRAYRESPONSECURVE optical density of Gray curve at each point
157155
66
77 no warnings 'uninitialized';
88
9 our $VERSION = '3.019'; # VERSION
10 my $LAST_UPDATE = '3.011'; # manually update whenever code is changed
9 our $VERSION = '3.020'; # VERSION
10 my $LAST_UPDATE = '3.020'; # manually update whenever code is changed
1111
1212 use Compress::Zlib;
1313
251251 if ($tif->{'colorSpace'} eq 'Indexed') {
252252 my $dict = PDFDict();
253253 $pdf->new_obj($dict);
254 $self->colorspace(PDFArray(PDFName($tif->{'colorSpace'}), PDFName('DeviceRGB'), PDFNum(255), $dict));
254 $self->colorspace(PDFArray(PDFName($tif->{'colorSpace'}), PDFName('DeviceRGB'), PDFNum(2**$tif->{'bitsPerSample'}-1), $dict));
255255 $dict->{'Filter'} = PDFArray(PDFName('FlateDecode'));
256256 $tif->{'fh'}->seek($tif->{'colorMapOffset'}, 0);
257257 my $colormap;
66
77 no warnings 'uninitialized';
88
9 our $VERSION = '3.019'; # VERSION
10 my $LAST_UPDATE = '3.011'; # manually update whenever code is changed
9 our $VERSION = '3.020'; # VERSION
10 my $LAST_UPDATE = '3.020'; # manually update whenever code is changed
1111
1212 use Compress::Zlib;
1313
1515 use PDF::Builder::Resource::XObject::Image::TIFF::File_GT;
1616 use PDF::Builder::Util;
1717 use Scalar::Util qw(weaken);
18 use Graphics::TIFF ':all'; # have already confirmed that this exists
18 use Graphics::TIFF 7 ':all'; # have already confirmed that this exists
1919
2020 =head1 NAME
2121
185185 if ($tif->{'colorSpace'} eq 'Indexed') {
186186 my $dict = PDFDict();
187187 $pdf->new_obj($dict);
188 $self->colorspace(PDFArray(PDFName($tif->{'colorSpace'}), PDFName('DeviceRGB'), PDFNum(255), $dict));
188 $self->colorspace(PDFArray(PDFName($tif->{'colorSpace'}), PDFName('DeviceRGB'), PDFNum(2**$tif->{'bitsPerSample'}-1), $dict));
189189 $dict->{'Filter'} = PDFArray(PDFName('FlateDecode'));
190 $tif->{'fh'}->seek($tif->{'colorMapOffset'}, 0);
191 my $colormap;
192 my $straight;
193 $tif->{'fh'}->read($colormap, $tif->{'colorMapLength'});
190 my ($red, $green, $blue) = @{$tif->{'colorMap'}};
194191 $dict->{' stream'} = '';
195 $straight .= pack('C', ($_/256)) for unpack($tif->{'short'} . '*', $colormap);
196 foreach my $c (0 .. (($tif->{'colorMapSamples'}/3)-1)) {
197 $dict->{' stream'} .= substr($straight, $c, 1);
198 $dict->{' stream'} .= substr($straight, $c + ($tif->{'colorMapSamples'}/3), 1);
199 $dict->{' stream'} .= substr($straight, $c + ($tif->{'colorMapSamples'}/3)*2, 1);
192 for my $i (0 .. $#{$red}) {
193 $dict->{' stream'} .= pack('C', ($red->[$i]/256));
194 $dict->{' stream'} .= pack('C', ($green->[$i]/256));
195 $dict->{' stream'} .= pack('C', ($blue->[$i]/256));
200196 }
201197 } else {
202198 $self->colorspace($tif->{'colorSpace'});
44 use strict;
55 use warnings;
66
7 our $VERSION = '3.019'; # VERSION
7 our $VERSION = '3.020'; # VERSION
88 my $LAST_UPDATE = '3.017'; # manually update whenever code is changed
99
1010 use PDF::Builder::Basic::PDF::Utils;
44 use strict;
55 use warnings;
66
7 our $VERSION = '3.019'; # VERSION
7 our $VERSION = '3.020'; # VERSION
88 my $LAST_UPDATE = '2.031'; # manually update whenever code is changed
99
1010 use PDF::Builder::Basic::PDF::Utils;
44 use strict;
55 use warnings;
66
7 our $VERSION = '3.019'; # VERSION
7 our $VERSION = '3.020'; # VERSION
88 my $LAST_UPDATE = '3.017'; # manually update whenever code is changed
99
1010 use PDF::Builder::Util qw(pdfkey);
22 use strict;
33 no warnings qw[ deprecated recursion uninitialized ];
44
5 our $VERSION = '3.019'; # VERSION
5 our $VERSION = '3.020'; # VERSION
66 my $LAST_UPDATE = '3.010'; # manually update whenever code is changed
77
88 =head1 NAME
22 use strict;
33 no warnings qw[ recursion uninitialized ];
44
5 our $VERSION = '3.019'; # VERSION
5 our $VERSION = '3.020'; # VERSION
66 my $LAST_UPDATE = '3.016'; # manually update whenever code is changed
77
88 # note: $a and $b are "Magic variables" according to perlcritic, and so it
44
55 # $VERSION defined here so developers can run PDF::Builder from git.
66 # it should be automatically updated as part of the CPAN build.
7 our $VERSION = '3.019'; # VERSION
8 my $LAST_UPDATE = '3.017'; # manually update whenever code is changed
7 our $VERSION = '3.020'; # VERSION
8 my $LAST_UPDATE = '3.020'; # manually update whenever code is changed
99
1010 use Carp;
1111 use Encode qw(:all);
170170 The GNU Lesser General Public License (LGPL) Version 2.1, February 1999
171171
172172 (The master copy of this license lives on the GNU website.)
173
174 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 59
175 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
176
177 I<Please see the> INFO/LICENSE I<file in the distribution root for full
178 details.>
173 (A copy is provided in the INFO/LICENSE file for your convenience.)
174
175 This section of Builder.pm is intended only as a very brief summary
176 of the license; please consider INFO/LICENSE to be the controlling version,
177 if there is any conflict or ambiguity between the two.
179178
180179 This program is free software; you can redistribute it and/or modify it under
181180 the terms of the GNU Lesser General Public License, as published by the Free
182181 Software Foundation, either version 2.1 of the License, or (at your option) any
183 later version.
182 later version of this license.
183
184 NOTE: there are several files in this distribution which were incorporated from
185 outside sources and carry different licenses. If a file states that it is under
186 a license different than LGPL 2.1, that license and its terms will apply to
187 that file, and not LGPL 2.1.
184188
185189 This library is distributed in the hope that it will be useful, but WITHOUT ANY
186190 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
225229 '-outver' PDF level has to be bumped up due to either a higher PDF level file
226230 being read in, or a higher level feature was requested. A value of 0
227231 suppresses the warning message.
232
233 =item -diaglevel
234
235 The '-diaglevel' option can be
236 given to specify the level of diagnostics given by IntegrityCheck(). The
237 default is level 2 (errors and warnings).
238 See L<PDF::Builder::Docs/IntegrityCheck> for more information.
228239
229240 =back
230241
280291 # code should also allow integers 0 (= 'none') and >0 (= 'flate')
281292 # for compatibility with old usage where forcecompress is directly set.
282293 }
294 if (exists $options{'-diaglevel'}) {
295 my $diaglevel = $options{'-diaglevel'};
296 if ($diaglevel < 0 || $diaglevel > 5) {
297 print "-diaglevel must be in range 0-5. using 2\n";
298 $diaglevel = 2;
299 }
300 $self->{'diaglevel'} = $diaglevel;
301 } else {
302 $self->{'diaglevel'} = 2; # default: errors and warnings
303 }
304
283305 $self->preferences(%options);
284306 if (defined $options{'-outver'}) {
285307 if ($options{'-outver'} >= 1.4) {
448470
449471 =cut
450472
451 # Note: openScalar() renamed to open_scalar()
452
453473 sub open_scalar {
454474 my ($class, $content, %options) = @_;
455475
460480 }
461481
462482 $self->{'content_ref'} = \$content;
483 my $diaglevel = 2;
484 if (defined $self->{'diaglevel'}) { $diaglevel = $self->{'diaglevel'}; }
485 if ($diaglevel < 0 || $diaglevel > 5) { $diaglevel = 2; }
486 my $newVer = $self->IntegrityCheck($diaglevel, $content);
487 # if Version override defined in PDF, need to overwrite the %PDF-x.y
488 # statement with the new (if higher) value. it's too late to wait until
489 # after File->open, as it's already complained about some >1.4 features.
490 if (defined $newVer) {
491 my ($verStr, $currentVer, $pos);
492 $pos = index $content, "%PDF-";
493 if ($pos < 0) { die "no PDF version found in PDF input!\n"; }
494 # assume major and minor PDF version numbers max 2 digits each for now
495 # (are 1 or 2 and 0-7 at this writing)
496 $verStr = substr($content, $pos, 10);
497 if ($verStr =~ m#^%PDF-(\d+)\.(\d+)#) {
498 $currentVer = "$1.$2";
499 } else {
500 die "unable to get PDF input's version number.\n";
501 }
502 if ($newVer > $currentVer) {
503 if (length($newVer) > length($currentVer)) {
504 print STDERR "Unable to update 'content' version because override '$newVer' is longer than header version '$currentVer'.\nYou may receive warnings about features that bump up the PDF level.\n";
505 } else {
506 if (length($newVer) < length($currentVer)) {
507 # unlikely, but cover all the bases
508 $newVer = substr($newVer, 0, length($currentVer));
509 }
510 substr($content, $pos+5, length($newVer)) = $newVer;
511 $outVer = $newVer;
512 }
513 }
514 }
515
463516 my $fh;
464517 CORE::open($fh, '+<', \$content) or die "Can't begin scalar IO";
465518
488541 $self->{'forcecompress'} = 'flate';
489542 # code should also allow integers 0 (= 'none') and >0 (= 'flate')
490543 # for compatibility with old usage where forcecompress is directly set.
544 }
545 if (exists $options{'-diaglevel'}) {
546 $self->{'diaglevel'} = $options{'-diaglevel'};
547 if ($self->{'diaglevel'} < 0 || $self->{'diaglevel'} > 5) {
548 $self->{'diaglevel'} = 2;
549 }
550 } else {
551 $self->{'diaglevel'} = 2;
491552 }
492553 $self->{'fonts'} = {};
493554 $self->{'infoMeta'} = [qw(Author CreationDate ModDate Creator Producer Title Subject Keywords)];
14511512 =item $page = $pdf->import_page($source_pdf, $source_page_number)
14521513
14531514 =item $page = $pdf->import_page($source_pdf, $source_page_number, $target_page_number)
1515
1516 =item $page = $pdf->import_page($source_pdf, $source_page_number, $target_page_object)
14541517
14551518 Imports a page from $source_pdf and adds it to the specified position
14561519 in $pdf.
21172180 my ($self, $file, %opts) = @_;
21182181
21192182 my ($rc, $obj);
2120 $rc = eval {
2121 require Graphics::TIFF;
2122 1;
2123 };
2124 if (!defined $rc) { $rc = 0; } # else is 1
2183 $rc = $self->LA_GT();
21252184 if ($rc) {
21262185 # Graphics::TIFF available
21272186 if (defined $opts{'-nouseGT'} && $opts{'-nouseGT'} == 1) {
21402199 $self->{'pdf'}->out_obj($self->{'pages'});
21412200
21422201 if ($rc == 0 && $MSG_COUNT[0]++ == 0) {
2143 # TBD give warning message once, unless silenced (-silent) or
2202 # give warning message once, unless silenced (-silent) or
21442203 # deliberately not using Graphics::TIFF (rc == -1)
21452204 if (!defined $opts{'-silent'} || $opts{'-silent'} == 0) {
21462205 print STDERR "Your system does not have Graphics::TIFF installed, so some\nTIFF functions may not run correctly.\n";
22292288 my ($self, $file, %opts) = @_;
22302289
22312290 my ($rc, $obj);
2232 $rc = eval {
2233 require Image::PNG::Libpng;
2234 1;
2235 };
2236 if (!defined $rc) { $rc = 0; } # else is 1
2291 $rc = $self->LA_IPL();
22372292 if ($rc) {
22382293 # Image::PNG::Libpng available
22392294 if (defined $opts{'-nouseIPL'} && $opts{'-nouseIPL'} == 1) {
22522307 $self->{'pdf'}->out_obj($self->{'pages'});
22532308
22542309 if ($rc == 0 && $MSG_COUNT[1]++ == 0) {
2255 # TBD give warning message once, unless silenced (-silent) or
2310 # give warning message once, unless silenced (-silent) or
22562311 # deliberately not using Image::PNG::Libpng (rc == -1)
22572312 if (!defined $opts{'-silent'} || $opts{'-silent'} == 0) {
22582313 print STDERR "Your system does not have Image::PNG::Libpng installed, so some\nPNG functions may not run correctly.\n";
26882743 return $obj;
26892744 } # end of named_destination()
26902745
2746 # ==================================================
2747 # input: level of checking, PDF as a string
2748 # level: 0 just return with any version override
2749 # 1 return version override, and errors
2750 # 2 return version override, and errors and warnings
2751 # 3 return version override, plus errors, warnings, notes
2752 # 4 like (3), plus dump analysis data
2753 # 5 like (4), plus dump $self (PDF) contents
2754 # returns any /Version value found in Catalog, last one if multiple ones found,
2755 # else undefined
2756
2757 sub IntegrityCheck {
2758 my ($self, $level, $string) = @_;
2759
2760 my $level_nodiag = 0;
2761 my $level_error = 1;
2762 my $level_warning = 2;
2763 my $level_note = 3;
2764 my $level_dump = 4;
2765 my $level_dumpself = 5;
2766
2767 my $IC = "PDF Integrity Check:";
2768
2769 #print "$IC level $level\n" if $level >= $level_error;
2770 my $Version = undef;
2771 my ($Info, $Root, $str, $pos, $Parent, @Kids, @others);
2772
2773 my $idx_defined = 0; # has this object been explicitly defined?
2774 my $idx_refcount = 1; # count of all pointing to this obj except as Kid
2775 my $idx_par_clmd = 2; # other object claiming this object as Kid
2776 my $idx_parent = 3; # this object's /Parent entry
2777 my $idx_kid_cnt = 4; # size of kid_list
2778 my $idx_kid_list = 5; # this object's /Kids list
2779 # intialize each element to [ 0 0 -1 -1 -1 [] ]
2780
2781 return $Version if !length($string); # nothing to examine?
2782 # even if $level 0, still want to get any higher /Version
2783 # build analysis data and issue errors/warnings at appropriate $level
2784 my @major = split /%%EOF/, $string; # typically [0] entire PDF [1] empty
2785 my %objList;
2786 my $update = -1;
2787 foreach (@major) {
2788 # update section number 0, 1, 2... with %%EOF in-between
2789 $update++;
2790 next if !length($_);
2791
2792 # split on "endobj"
2793 my @rawObjects = split /endobj/, $_;
2794 # each element contains an object plus leading stuff, not incl endobj
2795
2796 foreach my $rawObject (@rawObjects) {
2797 next if !length($rawObject);
2798
2799 # remove bulky and unwanted stream...endstream
2800 if ($rawObject =~ m/^(.*)stream\s.*\sendstream(.*)$/s) {
2801 $rawObject = $1.$2;
2802 }
2803
2804 # trim off anything before obj clause. endobj already gone.
2805 if ($rawObject =~ m/^(.*?)\s?(\d+) (\d+) obj\s(.*)$/s ||
2806 $rawObject =~ m/^(.*?)\s?(\d+) (\d+) obj(.*)$/s) {
2807 $rawObject = $4;
2808
2809 # found an obj, full string is $rawObject. parse into
2810 # selected fields, build $objList{key} entry.
2811 my $objKey = "$2.$3"; # e.g., 4 0 obj -> 4.0
2812 # if this is a replacement object in an update, clear Parent
2813 # and Kids
2814 if (defined $objList{$objKey} && $update > 0) {
2815 $objList{$objKey}->[$idx_parent] = -1;
2816 $objList{$objKey}->[$idx_kid_cnt] = -1;
2817 $objList{$objKey}->[$idx_kid_list] = [];
2818 }
2819 # might have already created this object element as target
2820 # from another object
2821 if (!defined $objList{$objKey}) {
2822 $objList{$objKey} = [0, 0, -1, -1, -1, []];
2823 }
2824 # mark object as defined
2825 $objList{$objKey}->[$idx_defined] = 1;
2826
2827 # found an object
2828 # looking for /Parent x y R
2829 # /Kids [ x y R ]
2830 # /Type = /Catalog -> /Version /x.y
2831 # for now, ignoring any /BaseVersion
2832 # all other x y R
2833 # remove from $rawObject as we find a match
2834
2835 # /Parent x y R -> $Parent
2836 if ($rawObject =~ m#/Parent(\s+)(\d+)(\s+)(\d+)(\s+)R#) {
2837 $Parent = "$2.$4";
2838 $str = "/Parent$1$2$3$4$5R";
2839 $pos = index $rawObject, $str;
2840 substr($rawObject, $pos, length($str)) = '';
2841 # TBD realistically, do we need to check for >1 /Parent ?
2842 #if ($objList{$objKey}->[$idx_parent] == -1) {
2843 # first /Parent (should not be more)
2844 $objList{$objKey}->[$idx_parent] = $Parent;
2845 #} else {
2846 # print STDERR "$IC Additional Parent ($Parent) in object $objKey, already list $objList{$objKey}->[$idx_parent] as Parent.\n" if $level >= $level_error;
2847 #}
2848 }
2849
2850 # /Kids [ x y R ] -> @Kids
2851 # should we check for multiple Kids arrays in one object (error)?
2852 if ($rawObject =~ m#/Kids(\s+)\[(.*)\]#) {
2853 $str = "/Kids$1\[$2\]";
2854 $pos = index $rawObject, $str;
2855 substr($rawObject, $pos, length($str)) = '';
2856
2857 my $str2 = " $2"; # guarantee a leading \s
2858 @Kids = ();
2859 while (1) {
2860 if ($str2 =~ m#(\s+)(\d+)(\s+)(\d+)(\s+)R#) {
2861 $str = "$1$2$3$4$5R";
2862 push @Kids, "$2.$4";
2863 $pos = index $str2, $str;
2864 substr($str2, $pos, length($str)) = '';
2865 } else {
2866 last;
2867 }
2868 }
2869 # TBD: realistically, any need to check for >1 /Kids?
2870 #if (!scalar(@{$objList{$objKey}->[$idx_kid_list]})) {
2871 # first /Kids (should not be more)
2872 @{$objList{$objKey}->[$idx_kid_list]} = @Kids;
2873 $objList{$objKey}->[$idx_kid_cnt] = scalar(@Kids);
2874 #} else {
2875 # print STDERR "$IC Multiple Kids lists in object $objKey, already list @{$objList{$objKey}->[$idx_kid_list]} as Kids.\n" if $level >= $level_error;
2876 #}
2877 }
2878
2879 # /Type /Catalog -> /Version /x.y -> $Version
2880 # both x and y are normally single digits, but allow room
2881 # just global $Version, assuming that each one physically
2882 # later overrides any earlier ones
2883 if ($rawObject =~ m#/Type(\s+)/Catalog#) {
2884 my $sp1 = $1;
2885 if ($rawObject =~ m#/Version /(\d+)\.(\d+)#) {
2886 $Version = "$1.$2";
2887 $str = "/Version$sp1/$Version";
2888 $pos = index $rawObject, $str;
2889 substr($rawObject, $pos, length($str)) = '';
2890 }
2891 }
2892
2893 # if using cross-reference stream, will find /Root x y R
2894 # and /Info x y R entries in an object of /Type /Xref
2895 # it looks like last ones will win
2896 if ($rawObject =~ m#/Type(\s+)/XRef# ||
2897 $rawObject =~ m#/Type/XRef#) {
2898 if ($rawObject =~ m#/Root(\s+)(\d+)(\s+)(\d+)(\s+)R#) {
2899 $Root = "$2.$4";
2900 $str = "/Root$1$2$3$4$5R";
2901 $pos = index $rawObject, $str;
2902 substr($rawObject, $pos, length($str)) = '';
2903 }
2904 if ($rawObject =~ m#/Info(\s+)(\d+)(\s+)(\d+)(\s+)R#) {
2905 $Info = "$2.$4";
2906 $str = "/Info$1$2$3$4$5R";
2907 $pos = index $rawObject, $str;
2908 substr($rawObject, $pos, length($str)) = '';
2909 }
2910 }
2911
2912 # all other x y R -> @others
2913 @others = ();
2914 while (1) {
2915 if ($rawObject =~ m#(\d+)(\s+)(\d+)(\s+)R#) {
2916 $str = "$1$2$3$4R";
2917 push @others, "$1.$3";
2918 $pos = index $rawObject, $str;
2919 substr($rawObject, $pos, length($str)) = '';
2920 } else {
2921 last;
2922 }
2923 }
2924 # go through all other refs and create element if necessary,
2925 # then increment its refcnt array element
2926 foreach (@others) {
2927 if (!defined $objList{$_}) {
2928 $objList{$_} = [0, 0, -1, -1, -1, []];
2929 }
2930 $objList{$_}->[$idx_refcount]++;
2931 }
2932 foreach (@Kids) {
2933 if (!defined $objList{$_}) {
2934 $objList{$_} = [0, 0, -1, -1, -1, []];
2935 }
2936 $objList{$_}->[$idx_refcount]++;
2937 }
2938
2939 } else {
2940 # not an object, but could be other stuff of interest
2941 # looking for trailer -> /Root x y R & /Info x y R
2942 if ($rawObject =~ m/trailer/) {
2943 if ($rawObject =~ m#trailer(.*)/Info(\s+)(\d+)(\s+)(\d+)(\s+)R#s) {
2944 $Info = "$3.$5";
2945 }
2946 if ($rawObject =~ m#trailer(.*)/Root(\s+)(\d+)(\s+)(\d+)(\s+)R#s) {
2947 $Root = "$3.$5";
2948 }
2949 }
2950 }
2951 }
2952 }
2953
2954 # increment Root and Info objects reference counts
2955 # they probably SHOULD already be defined (issue warning if not)
2956 if (!defined $Root) {
2957 print STDERR "$IC No Root object defined!\n" if $level >= $level_error;
2958 } else {
2959 if (!defined $objList{$Root}) {
2960 $objList{$Root} = [1, 0, -1, -1, -1, []];
2961 print STDERR "$IC Root object $Root not found!\n" if $level >= $level_error;
2962 }
2963 $objList{$Root}->[$idx_refcount]++;
2964 }
2965
2966 # Info is optional
2967 if (!defined $Info) {
2968 print STDERR "$IC No Info object defined!\n" if $level >= $level_note;
2969 } else {
2970 if (!defined $objList{$Info}) {
2971 $objList{$Info} = [1, 0, -1, -1, -1, []];
2972 print STDERR "$IC Info object $Info not found!\n" if $level >= $level_note;
2973 # possibly in a deleted object (on free list)
2974 }
2975 $objList{$Info}->[$idx_refcount]++;
2976 }
2977
2978 # revisit each element in objList
2979 # visit each Kid, their $idx_par_clmd should be -1 (set to this object)
2980 # (if not -1, is on multiple Kids lists)
2981 # their $idx_parent should be this object
2982 # they should have a Parent declared
2983 # any element with ref count of 0 and no Parent give warning unreachable
2984 # TBD: anything else to add to things to check?
2985 foreach my $thisObj (sort keys %objList) {
2986
2987 # was an object actually defined for this entry?
2988 # missing Info and Root messages already given, so flag is 1 ("defined")
2989 if ($objList{$thisObj}->[$idx_defined] == 0) {
2990 print STDERR "$IC object $thisObj referenced, but no entry found.\n" if $level >= $level_note;
2991 # it's apparently OK if the missing object is on the free list --
2992 # it will just be ignored
2993 }
2994
2995 # check any Kids
2996 if ($objList{$thisObj}[$idx_kid_cnt] > 0) {
2997 # this object has children (/Kids), so explore them one level deep
2998 for (my $kidObj=0; $kidObj<$objList{$thisObj}[$idx_kid_cnt]; $kidObj++) {
2999 my $child = $objList{$thisObj}[$idx_kid_list]->[$kidObj];
3000 # child's claimed parent should be -1, set to thisObj
3001 if ($objList{$child}[$idx_par_clmd] == -1) {
3002 # no one has claimed to be parent, so set to thisObj
3003 $objList{$child}[$idx_par_clmd] = $thisObj;
3004 } else {
3005 # someone else has already claimed to be parent
3006 print STDERR "$IC object $thisObj wants to claim object $child as its child, but $objList{$child}[$idx_par_clmd] already has!\nPossibly $child is on more than one /Kids list?\n" if $level >= $level_error;
3007 }
3008 # if no object defined for child, already flagged as missing
3009 if ($objList{$child}[$idx_defined] == 1) {
3010 # child should list thisObj as its Parent
3011 if ($objList{$child}[$idx_parent] == -1) {
3012 print STDERR "$IC object $thisObj claims $child as a child (/Kids), but $child claims no Parent!\n" if $level >= $level_error;
3013 $objList{$child}[$idx_parent] = $thisObj;
3014 } elsif ($objList{$child}[$idx_parent] != $thisObj) {
3015 print STDERR "$IC object $thisObj claims $child as a child (/Kids), but $child claims $objList{$child}[$idx_parent] as its parent!\n" if $level >= $level_error;
3016 }
3017 }
3018 }
3019 }
3020
3021 if ($objList{$thisObj}[$idx_parent] == -1 &&
3022 $objList{$thisObj}[$idx_refcount] == 0) {
3023 print STDERR "$IC Warning: object $thisObj appears to be unreachable.\n" if $level >= $level_note;
3024 }
3025 }
3026
3027 if ($level >= $level_dump) {
3028 # dump analysis data
3029 use Data::Dumper;
3030 my $d = Data::Dumper->new([\%objList]);
3031 print "========= dump of $IC analysis data ===========\n";
3032 print $d->Dump();
3033 }
3034
3035 # if have entire processed PDF in $self
3036 if ($level >= $level_dumpself) {
3037 # dump whole data
3038 use Data::Dumper;
3039 my $d = Data::Dumper->new([$self]);
3040 print "========= dump of $IC PDF (self) data ===========\n";
3041 print $d->Dump();
3042 }
3043
3044 return $Version;
3045 }
3046
26913047 1;
26923048
26933049 __END__
6262 next;
6363 }
6464 }
65 # HarfBuzz::Shaper is built into Content.pm, doesn't have its own module
6566 use_ok($file);
6667 }
6768
11 use strict;
22 use warnings;
33
4
4 # Windows: SET AUTHOR_TESTING=1
5 # this test is a subset of tools/1_pc.pl
56 BEGIN {
67 unless ($ENV{'AUTHOR_TESTING'}) {
78 print qq{1..0 # SKIP these tests are for testing by the author\n};
910 }
1011 }
1112
12 use Test::Perl::Critic (-profile => "perlcritic.rc") x!! -e "perlcritic.rc";
13 use Test::Perl::Critic (-profile => "..\.perlcriticrc") x!! -e "..\.perlcriticrc";
1314 all_critic_ok();
88
99 my @possible_locations = (
1010 '/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf',
11 '/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf',
1112 '/var/lib/defoma/gs.d/dirs/fonts/DejaVuSans.ttf',
1213 'C:/Windows/fonts/DejaVuSans.ttf',
1314 );
88
99 my @possible_locations = (
1010 '/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf',
11 '/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf',
11 '/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf',
1212 'C:/Windows/fonts/DejaVuSans.ttf',
1313 );
1414
00 #!/usr/bin/perl
11 use warnings;
22 use strict;
3
4 use Test::More tests => 11;
3 use English qw' -no_match_vars ';
4 use IPC::Cmd qw(can_run);
5 use Test::More tests => 12;
56
67 use PDF::Builder;
78
1011 # usable, otherwise they will display just TIFF. you can use this information
1112 # if you are not sure about the status of Graphics::TIFF.
1213
13 my $pdf = PDF::Builder->new('-compress' => 'none');
14 my $pdf = PDF::Builder->new('-compress' => 'none'); # common $pdf all tests
15 my $has_GT = 0; # global flag for all tests that need to know if Graphics::TIFF
1416
1517 # -silent shuts off one-time warning for rest of run
1618 my $tiff = $pdf->image_tiff('t/resources/1x1.tif', -silent => 1);
1719 if ($tiff->usesLib() == 1) {
20 $has_GT = 1;
1821 isa_ok($tiff, 'PDF::Builder::Resource::XObject::Image::TIFF_GT',
1922 q{$pdf->image_tiff(filename)});
2023 } else {
6972 ok($@, q{Fail fast if the requested file doesn't exist});
7073
7174 ##############################################################
72 # tiff2pdf and convert not available on all systems. 1 test skipped
73
75 # common data for remaining tests
7476 my $width = 568;
7577 my $height = 1000;
7678 $tiff = 'test.tif';
7779 my $pdfout = 'test.pdf';
7880
79 SKIP: {
80 skip "tiff2pdf doesn't deal with the alpha layer properly either, in this case", 1;
81 # WARNING: do not attempt to run the following 3 tests on a
82 # Windows system. Windows has a 'convert' utility to convert
83 # a filesystem from FAT32 to NTFS, and you don't want to
84 # accidentally run that one! The test ($OSNAME) is for 'linux'
85 # but testing for 'not windows' might do just as well. Even
86 # better might be to see if 'convert' and 'tiffcp' are the
87 # right utilties, if found. Otherwise, the OS is irrelevant.
88 #
89 # NOTE: following 3 tests use Linux/TIFF utilities convert
90 # and tiffcp. They may require software installation on
91 # your Linux system, and will be skipped if the necessary
92 # software is not found.
93
94 ##############################################################
95 # convert not available on all systems. PDF::Builder itself
96 # doesn't seem to work well with this, so skip for time being.
97
98 SKIP: {
99 skip "Further work is needed on PDF::Builder and the test process to handle the alpha layer properly.", 1;
100 # skip "Non-Linux system, or no 'convert' utility", !(
101 # $OSNAME eq 'linux'
102 # and can_run('convert')
103 # );
104 # ----------
81105 system(sprintf"convert -depth 1 -gravity center -pointsize 78 -size %dx%d caption:'Lorem ipsum etc etc' %s", $width, $height, $tiff);
106 # ----------
82107 $pdf = PDF::Builder->new(-file => $pdfout);
83108 my $page = $pdf->page();
84109 $page->mediabox($width, $height);
88113 $pdf->save();
89114 $pdf->end();
90115
116 # ----------
91117 my $example = `convert $pdfout -depth 1 -resize 1x1 txt:-`;
92118 my $expected = `convert $tiff -depth 1 -resize 1x1 txt:-`;
119 # ----------
93120
94121 is($example, $expected, 'alpha');
95122 }
96123
97124 ##############################################################
98 # tiffcp and convert not available on all systems. 1 test skipped
99
100 SKIP: {
101 skip "Files created with tiffcp -c g3 previously produced the message 'Chunked CCITT G4 TIFF not supported'", 1;
125 # tiffcp, convert and Graphics::TIFF not available on all systems.
126 # Graphics::TIFF needed or you get message "Chunked CCITT G4 TIFF not supported"
127 # from PDF::Builder's TIFF processing library.
128
129 SKIP: {
130 skip "Non-Linux system, or no 'convert' or no 'tiffcp'", 1 unless
131 $has_GT and $OSNAME eq 'linux'
132 and can_run('convert')
133 and can_run('tiffcp');
134 # ----------
102135 system(sprintf "convert -depth 1 -gravity center -pointsize 78 -size %dx%d caption:'Lorem ipsum etc etc' -background white -alpha off %s", $width, $height, $tiff);
103136 system("tiffcp -c g3 $tiff tmp.tif && mv tmp.tif $tiff");
137 # ----------
104138 $pdf = PDF::Builder->new(-file => $pdfout);
105139 my $page = $pdf->page();
106140 $page->mediabox($width, $height);
110144 $pdf->save();
111145 $pdf->end();
112146
113 my $example = `convert $pdfout -depth 1 -resize 1x1 txt:-`;
147 # ----------
148 my $example = `convert $pdfout -depth 1 -colorspace gray -alpha off -resize 1x1 txt:-`;
114149 my $expected = `convert $tiff -depth 1 -resize 1x1 txt:-`;
150 # ----------
115151
116152 is($example, $expected, 'G3 (not converted to flate)');
117153 }
118154
119155 ##############################################################
120 # tiffcp and convert not available on all systems. 1 test skipped
121
122 SKIP: {
123 skip "convert and tiffcp utilities not available on all systems", 1;
156 # tiffcp and convert not available on all systems.
157 # Graphics::TIFF not needed for this test
158
159 SKIP: {
160 skip "Non-Linux system, or no 'convert' or no 'tiffcp'", 1 unless
161 $OSNAME eq 'linux'
162 and can_run('convert')
163 and can_run('tiffcp');
164 # ----------
124165 system(sprintf"convert -depth 1 -gravity center -pointsize 78 -size %dx%d caption:'Lorem ipsum etc etc' -background white -alpha off %s", $width, $height, $tiff);
125166 system("tiffcp -c lzw $tiff tmp.tif && mv tmp.tif $tiff");
167 # ----------
126168 $pdf = PDF::Builder->new(-file => $pdfout);
127169 my $page = $pdf->page;
128170 $page->mediabox( $width, $height );
132174 $pdf->save();
133175 $pdf->end();
134176
177 # ----------
135178 my $example = `convert $pdfout -depth 1 -colorspace gray -alpha off -resize 1x1 txt:-`;
136179 my $expected = `convert $tiff -depth 1 -resize 1x1 txt:-`;
180 # ----------
137181
138182 is($example, $expected, 'lzw (converted to flate)');
139183 }
140184
141185 ##############################################################
186 # convert not available on all systems.
187 # Graphics::TIFF needed for this test
188
189 SKIP: {
190 skip "Non-Linux system, or no 'convert'", 1 unless
191 $has_GT and $OSNAME eq 'linux'
192 and can_run('convert');
193 # .png file is temporary file (output, input, erased)
194 system("convert rose: -type palette -depth 2 colormap.png && convert colormap.png $tiff && rm colormap.png");
195 $pdf = PDF::Builder->new(-file => $pdfout);
196 my $page = $pdf->page;
197 $page->mediabox( $width, $height );
198 $gfx = $page->gfx();
199 my $img = $pdf->image_tiff($tiff);
200 $gfx->image( $img, 0, 0, $width, $height );
201 $pdf->save();
202 $pdf->end();
203 pass 'successfully read TIFF with colormap';
204 }
205
206 ##############################################################
142207 # cleanup. all tests involving these files skipped?
143208
144209 unlink $pdfout, $tiff;
66 use strict;
77 use warnings;
88
9 our $VERSION = '3.019'; # VERSION
9 our $VERSION = '3.020'; # VERSION
1010 my $LAST_UPDATE = '3.016'; # manually update whenever code is changed
1111
1212 # command line:
2727 # output <source name> OK is always ignored
2828 my @ignore_list = (
2929 # should not ignore any level 5 warnings
30 "Use IO::Interactive::is_interactive",
31 # not a core module!
3032 # common level 4 warnings to ignore
3133 "Code before warnings", # due to use of "no warnings" pragma
3234 "Warnings disabled at", # due to use of "no warnings" pragma
66 use strict;
77 use warnings;
88
9 our $VERSION = '3.019'; # VERSION
9 our $VERSION = '3.020'; # VERSION
1010 my $LAST_UPDATE = '3.016'; # manually update whenever code is changed
1111
1212 # command line flags, mutually exclusive:
66 use strict;
77 use warnings;
88
9 our $VERSION = '3.019'; # VERSION
9 our $VERSION = '3.020'; # VERSION
1010 my $LAST_UPDATE = '3.018'; # manually update whenever code is changed
1111
1212 # dependent on optional packages:
66 use strict;
77 use warnings;
88
9 our $VERSION = '3.019'; # VERSION
9 our $VERSION = '3.020'; # VERSION
1010 my $LAST_UPDATE = '3.013'; # manually update whenever code is changed
1111
1212 # command line: