PDF-Builder-3.026/0000755000000000000000000000000014534467632012235 5ustar rootrootPDF-Builder-3.026/INFO/0000755000000000000000000000000014534671356012770 5ustar rootrootPDF-Builder-3.026/INFO/Changes_20170000644000000000000000000006636513320701033014726 0ustar rootrootSee also Changes_2018 (and beyond) and Changes files for further change logs. See also Changes-ver_2 for changes released for PDF::API2, and incorporated into PDF::Builder. 3.009 2017-11-27 lib/PDF/Builder.pm fix minor POD glitches, t/00-all-usable.t fix behavior when Graphics::TIFF not installed (skip *_GT use tests). 3.008 2017-11-26 examples/ShowFont.pl added to list out many font file glyphs. examples.bat, examples/README, examples/examples.output updated. lib/PDF/Builder.pm [ref RT 121912/#67 and also RT 41971/#5] fix outlines method (thanks to "futuramedium"). Update test case into an example, and add to examples.bat, MANIFEST, examples/README, examples/examples.output, and (new) examples/055_outlines and examples/resources/samples_55.pdf. lib/PDF/Builder.pm, lib/PDF/Builder/Resource/BaseFont.pm, lib/PDF/Builder/Resource/Font/SynFont.pm, examples/021_synfonts [ref RT 120048/#47] fixes for synthetic fonts (via "futuramedium"). Some items carried over to new issues #79 and #81, and this one closed. 021_synfonts make cleaner selection of what to run (which font types, which fonts within a type, which variants). lib/PDF/Builder.pm [ref RT 122393/#72] further work on diagnosing reported problem. If this was actually a PDF::API2/Builder problem at one time, and not simply a corrupted local font issue, it has apparently been cleared up. Documented supported CJK names and aliases in Builder's POD. lib/PDF/Builder/Annotation.pm, examples/040_annotation, examples/041_annot_fileattach (new), examples/resources/pod2htmd.temp (new), examples/resources/sample.txt (new), MANIFEST, DEPRECATED, examples.bat, examples/README, examples/examples.output, t/annotate.t [ref RT 117942/#41] (thanks to Johan Vromans). Extensions to annotation methods plus new file attachment annotation code contributed by Johan. There are still some minor glitches in the behavior, including the "border" specification not working, and inconsistent icon size, so I'm leaving the issue open for now. Also, the annotation pdfile() method has been deprecated and replaced by pdf_file(). lib/PDF/Builder.pm, lib/PDF/Builder/Resource/XObject/Image/TIFF_GT.pm (new), lib/PDF/Builder/Resource/XObject/Image/TIFF/File_GT.pm (new), MANIFEST, KNOWN_INCOMP, t/tiff.t, lib/PDF/Builder/Resource/XObject/Image/TIFF.pm, lib/PDF/Builder/Lite.pm [ref RT 118047/#42] (thanks to Jeffrey Ratcliffe). Use Jeffrey's Graphics::TIFF wrapper around libtiff.a to simplify and correct many bugs in TIFF support. As libtiff.a is not available on all systems, add this as an extension (_GT modules) and have Builder.pm select which one to use (preferably the new Graphics::TIFF-using version, with fallback to the old pure Perl version, which has not been fixed). This can be overridden (force old version) with the -nouseGT option (see t/tiff.t). lib/PDF/Builder.pm, lib/PDF/Builder/Resource/XObject/Image/TIFF_GT.pm, lib/PDF/Builder/Resource/XObject/Image/TIFF/File_GT.pm, lib/PDF/Builder/Basic/PDF/File.pm [ref RT 84665/#2] updates and fixes while working on TIFF G3/G4 compression bug. 3.007 2017-09-26 Makefile.PL add missing prerequisite Test::Memory::Cycle. 3.006 2017-09-23 lib/PDF/Builder/Page.pm POD glitch reported by Kwalitee fixed. lib/PDF/Builder.pm update history to mention Text::PDF origin (requested by SPROUT) lib/PDF/Builder/Win32.pm, examples/027_winfont moved to examples/Windows. examples/README, examples/examples.output, examples.bat, Makefile.PL, MANIFEST updated. The Windows-specific code in Win32.pm has not worked since at least Windows 7, and the demo doesn't do anything particularly useful. Rather than erasing the code, it is still available if you actually use it (move Win32.pm back to Builder/ and install Win32::Tie::Registry), and you can look at it for examples of Windows Registry access. Makefile.PL cleanup and rearrangement (thanks to Johan Vromans). Note that the Perl minimum has been upped from 5.8.5 to 5.8.6, for better UTF-8 support, and a number of prereqs found in CORE have been removed. Still unresolved is the best way (and whether) to put $VERSION in all .pl and .pm files, or just Builder.pm, and the associated build process. Also under discussion is how to indicate when a file was last updated -- is there a better way than $LAST_UPDATE? It is provided as a local variable in case anyone wants to access it in their code. examples/020_corefonts and examples/021_synfonts [ref #68, CTS 9] updated "@fonts" list to "@planes" to clarify that these fonts are 256 character planes of part of a font's glyph list. Also updated lib/PDF/Builder/Resource/Font.pm to document the automap() method, and lib/PDF/Builder.pm to mention that UTF-8 cannot be used in corefonts and psfonts (at least, non-CID fonts). PS (Type 1) fonts may use automap(), although such fonts are usually (non-CID) limited to 256 glyphs. In that case, automap() will return nothing for the extended planes. lib/PDF/Builder.pm and lib/PDF/Builder/Resource/Font.pm update comments (POD) on character encoding (per Johan Vromans). lib/PDF/Builder/Content/Hyphenate_basic.pm in basic hyphenation, split word with SHY (soft hyphen) instead of -, so a screen reader or other text scraper or resizable display knows it can omit the hyphen when gluing a word back together. A SHY is supposed to display as a normal hyphen -. lib/PDF/Builder/Resource/XObject/Image/TIFF.pm (reported by Ivan Middleton) [ref RT 15730, Rejected] the BlackIs1 DecodeParm hash member was misspelled as Blackls1 (el instead of EYE). BlackIs1 has been added, and Blackls1 is now DEPRECATED. It will be removed some time after July 2018, so please update your code if you use it. The original bug report also stated that the value of this member /may/ be the reverse of what it should be, so further corrections to the code /may/ be necessary in the future. lib/PDF/Builder.pm (per Johan Vromans) add $VERSION to Builder.pm so that a developer can run PDF::Builder directly from git. Please read the DEPRECATED file (new) for a list of deprecated names and interfaces which will disappear at some time in the future! The build process has been modified to ensure that all text (non-binary) files are now "Unix style" (LF for end-of-line) per Jeffrey Ratcliffe. Before, some text files were "DOS style" (CRLF for end-of-line), which caused problems for tools used by some Linux-based developers. DOS-only files, such as .bat files, have been left in DOS style. lib/PDF/Builder.pm the default /Producer PDF tag had the producer's operating system in the string, which led to different PDF file lengths depending on which OS a PDF was produced on. This has been changed to a URL for the support area for this product. Of course, you can always override the Producer (and Creator) tags with whatever strings you want (see the info() call). t-tests.bat (per Johan Vromans and Jeffrey Ratcliffe) add some comments on ways to run t tests in various situations. examples/012_pages insert pages i-iii in front of other pages, to show how (for instance) a Table of Contents could be inserted after writing the rest of the document. examples/ font display utilities change Unicode formatting to U+nnnn and align character description text under character box. examples/021_psfonts added to display Type1 fonts (.pfa, .pfb glyph files and .afm, .pfm metrics files). 3.005 2017-07-16 Some minor POD cleanups (missing > brackets) and fix VERSION in .pm files. Otherwise no code changes. Some build cleanup. 3.004 2017-07-12 updates to official CPAN release (2.033) included: - [RT #120756] Eliminate a warning for an ambiguous call to CORE::open (first reported by Abdelbaki Brahmia). fix already in lib/PDF/Builder/Basic/PDF/File.pm - [RT #121832] fix t/resources/sample-xrefstm.pdf NOTE: STILL DOES NOT SEEM TO WORK Hyphenate_en.pm changed to Hyphenate_basic.pm, and scope of built-in hyphenation reduced somewhat. Prepare for release as PDF::Builder on GitHub and CPAN. All modules restore VERSION line to library format, and add $LAST_UPDATE to show when last time the module was manually edited. The $VERSION seen in a CPAN distribution will be the normal overall version, while $LAST_UPDATE will be the last time that the module was touched (changed). Many modules not previously updated with Perl formatting and POD cleanup were cleaned up, and given $LAST_UPDATE of 3.004. The change of API2 to Builder and the addition of $LAST_UPDATE by themselves did not change $LAST_UPDATE to 3.004. 3.003 2017-05-01 (revised: change API2 references to Builder) updates to official CPAN release (currently 2.032 in-progress) included no updates to official CPAN release since 2.031 (in 3.001) There are a number of changes to code, which /may/ have a negative effect on poorly written code (i.e., produce different results), but are believed not to affect properly written code. These are the removal of "~time()" from resource names, the enabling of save() and restore() for "text" objects, and settings being returned by certain text and graphics calls during a setting call. See additional information below. lib/PDF/Builder/Resource/CIDFont/TrueType.pm lib/PDF/Builder/Resource/Font/BdFont.pm lib/PDF/Builder/Resource/Font/CoreFont.pm lib/PDF/Builder/Resource/Font/Postscript.pm [ref RT #105579 and #113084 (were open)] remove ~time() from font resource names. It appears to be unnecessary, and made PDFs non-deterministic (two runs with the same input had different output), making output comparisons difficult for developers. Commented out lines containing ~time(), so they can be restored easily. **Please report any problems which appear to be resource name collisions** General syntax and POD cleanup of those modules, including in BdFont.pm giving a better prefix than "pdfkey()pdfkey()". lib/PDF/Builder/Content.pm general code cleanup, some POD improvements. Cleaned up advancewidth() method (redundant code) and clarified options. Split out methods text_center(), text_right(), text_justified(), text_fill_left(), text_fill_center(), text_fill_right(), text_fill_justified(), paragraph(), section(), and textlabel() into lib/PDF/Builder/Content/Text.pm. This was an already-existing stub with only a new() method [ref RT #98540 (was rejected)]. lib/PDF/Builder/Resource/XObject/Form/Hybrid.pm needed to add Content::Text to the "use base" list. lib/PDF/Builder/Content/Text.pm Document (in the POD) paragraph(), section(), and textlabel(). These were undocumented "developer methods". Also improve the code and add options to indent/outdent paragraphs and add space between them. Authors were already using at least the textlabel() method, and some may have already been using paragraph() and section(). Method text_left() added as an alias for Content.pm's text(), and text_fill() added as alias for text_fill_left(). [ref RT #98546 (was open)] text_fill_justified() add option -last_align => 'left' (default), 'center', or 'right' to not stretch last line. [ref RT #98546 (was open)] general improvements to justified text. Instead of stretching/squeezing with hscale(), wordspace() and charspace() are used to fit the line. If this isn't enough, hscale() will be used as a last resort (as it severely distorts the characters). [ref RT #98548 (was rejected)] added preliminary code for line splitting (word hyphenation). This currently splits on soft hyphens, after runs of digits or ASCII letters, after certain punctuation, and within camelCase text. It does NOT yet split up normal words (still looking for a good algorithm to do that). /lib/PDF/Builder/Content/Hyphenate_en.pm added, is intended for English language line splitting (other languages could be added, including specific versions of English). THIS CODE, IN ITS CURRENT STATE, IS EXPERIMENTAL AND SHOULD NOT BE USED FOR PRODUCTION. IT MAY CHANGE CONSIDERABLY OVER TIME. examples/Content.pl split out examples/ContentText.pl to reflect change in organization. Update ContentText.pl to reflect new material. examples/BarCode.pl added to print out the eleven 1D barcodes supported by PDF::Builder. There are many more out there (especially UPC variants) that it would be nice to add. Plus, there are 2D and QR codes to do. Two (currently empty) subdirectories added under PDF::Builder::Resource::XObject::Form for future 2D and QR additions. We would appreciate if someone could check that the produced barcodes are correct, and if there are limits on the character set and length of the data that should be implemented in the code. For example, the samples for code 3 of 9 and code 3 of 9 with full ASCII and check digit look like they might be the same, and EAN-128's text is left justified rather than centered. CODE 128 C doesn't seem to work with all numbers (count 2n). All in all, we would advise against using the barcodes until they have been verified. Their behavior is just too odd to be comfortable that they are correctly drawn, particularly adjacent bars apparently merging (and separating) as you zoom in and out. lib/PDF/Builder/Page.pm [ref RT #98576 (was rejected), CTS 7] clarify the interactions among multiple graphics and/or multiple text objects on one page. While PDF::Builder does keep the settings separate (e.g., one object's linewidth does not affect another object's linewidth), output (to a stream) is for an entire object at a time (in the order that the graphics and text objects were defined). PDF, in turn, has essentially one graphics + text state, and the state at the end of one stream becomes the entry state for the next stream. Also, many graphics attributes affect text output. See the updated POD for more information. lib/PDF/Builder/Content.pm [ref CTS 7] clarify what is saved and restored in the graphics state with the save() and restore() methods. Note that even though the text state uses many graphics attributes (linewidth, linedash, etc.), the save() and restore() methods /were/ ignored (no-ops) on text objects. Now save() and restore() are enabled for "text" objects. See the updated POD for more information. lib/PDF/Builder/Content.pm lib/PDF/Builder/Util.pm lib/PDF/Builder/Resource/Font/SynFont.pm [ref RT #98576 (was rejected)] add caution that Math::Trig::deg2rad() treats 360 degrees as 0! It cannot be used for closed loops such as circles and ellipses (sweep 0 to 360). lib/PDF/Builder/Basic/PDF/File.pm minor code cleanup (adding parens to fns). lib/PDF/Builder.pm lib/PDF/Builder/Content.pm lib/PDF/Builder/Resource/ExtGState.pm lib/PDF/Builder/Resource/XObject/Image.pm lib/PDF/Builder/Resource/XObject/Form/BarCode/code3of9.pm deprecated methods (renamed or absorbed into other methods) get warning messages output. General syntax and POD cleanup of those modules. lib/PDF/Builder/Resource/XObject/Image.pm lib/PDF/Builder/Resource/XObject/Image/GD.pm lib/PDF/Builder/Resource/XObject/Image/GIF.pm lib/PDF/Builder/Resource/XObject/Image/JPEG.pm lib/PDF/Builder/Resource/XObject/Image/PNG.pm lib/PDF/Builder/Resource/XObject/Image/PNM.pm lib/PDF/Builder/Resource/XObject/Image/TIFF.pm update to remove use of deprecated methods. General syntax and POD cleanup of those modules. t/content.t remove meterlimit and hspace tests to avoid deprecated messages lib/PDF/Builder/Content.pm lib/PDF/Builder/Content/Text.pm [ref RT #98543 (was rejected)] clarify that most public methods now (if they didn't already) return $self, permitting chaining of calls and more consistent behavior. There are some 37 calls which return specified values (other than the content object) under at least some circumstances. The POD has been updated to reflect these changes. * linewidth(), linecap(), linejoin(), miterlimit(), and flatness() now return the current setting if called with no arguments, and continue to return $self otherwise, permitting chaining. * Since linedash() is a legal call (for a solid line), linedash(-1) is used to return the current setting (array of a dash pattern anonymous array and the offset). $self is returned otherwise, permitting chaining. * strokecolor() and fillcolor() return the current setting (array) if called with no arguments, otherwise return $self (to permit chaining). This is a minor change from old usage, if you were /setting/ a fill or stroke color and immediately reading back the result /in the same call/. There does not appear to be a consistent way to synchronize settings changes between ExtGState and Content. Line width, line cap style, line join style, miter limit, dash pattern, and flatness can be set in both Content and ExtGState, but since they affect different contexts, there is no apparent way to transfer a setting from Content to ExtGState or vice-versa. Anyway, be careful about mixing ways of making settings changes. Keep in mind the way that graphical and text operations are output to PDF, and how PDF in turn processes these streams. Anything that returns the "current graphics state" (including text state) may not quite match up with what PDF's rendering engine is actually using at that moment, due to the exact order of operations (as well as Content vs. ExtGState changes). All changes to one object (text or graphics) should be processed in order, but remember that all of one object will be output first, and then all of the next object, and so on. Finally, I decided that it was important to have the value-returning text functions (charspace, wordspace, hspace, lead, render, rise) behave in a similar manner to the value-returning graphics functions. Therefore, these functions have been changed to only return their current value when no argument is given, and to return $self when they are used to set the value. The (new) value is no longer returned when it is set, but that is not expected to be a major use of the functions. lib/PDF/Builder/Content.pm Document discrepancy in formimage(), where the scale(s) needed are quite different for images (e.g., JPEG) and barcodes. Images are scaled in pixels, and naturally display as approximately 1 point square, while barcodes are already scaled in points, so you want a scale of approximately 1. Multiplying by the "image" width and height within formimage() works great for true images, but way overscales barcodes, requiring them to be manually scaled down by 1/width and 1/height. So, formimage() does not multiply by the original image height and width, leaving that to the user to do in the call (no code change). Fix bug in advancewidth(), where %opts were not being handled correctly. examples/* add use strict and warnings, minor code cleanup. Change graphics context calls to textlabel() to text context. In most examples, needed to check for undefined Unicode points so as not to get "undefined value" errors. 021_synfonts fix to page titles (fix font name). two examples (022 truefonts with UTF-8 diacritic and 023 CJK fonts) are now considered to be working properly (see README). / add examples.bat (Windows) to run everything in the examples/ directory. Note this is a HUGE amount of output! add contrib.bat (Windows) to run everything in the contrib/ directory. This needs to be run after examples.bat, as it uses several PDFs from examples run. 3.002 2017-03-21 (revised: change API2 references to Builder) updates to official CPAN release (currently 2.032 in-progress) included no updates to official CPAN release since 2.031 (in 3.001) lib/PDF/Builder.pm lib/PDF/Builder/Page.pm [ref RT #98547] (was open) add %option -compress to new() call: $pdf = PDF::Builder->new(-compress => 'none');. This is the equivalent of the old $pdf = PDF::Builder->new(); and $pdf->{'forcecompress'} = 0; calls. This turns off "compressFlate" for debugging purposes, so you can edit the PDF file and see the actual output (uncompressed form). The default value is 'flate'. The internal value (forcecompress) is now 'none' or 'flate', so any code accessing this value should be updated. 0 and >0 values are still handled by PDF::Builder (as none or flate). open_scalar() call can also use -compress option. t/*.t tests that set 'forcecompress' to 0 have been updated to the new -compress flag. lib/PDF/Builder/Basic/PDF/Pages.pm Where is the code for rebuild_tree()? It appears to be a dummy stub. Added warning in POD not to use, and opened bug CTS 3. examples/* have been updated and the code cleaned up. Several broken examples have been fixed. 024_bmpfonts has been renamed to 024_bdffonts (bitmap distribution format) to better reflect its purpose and reduce confusion about what it does. All examples retested with 3.002. All font listings should now be ordered top to bottom 0x to Fx. lib/PDF/Builder/Win32.pm enumwinfonts() not working (CTS 4). contrib/text2pdf.pl [ref RT #87859] (was open) "hankivy"'s updated text2pdf utility further enhanced and added to the distribution. lib/PDF/Builder/Basic/PDF/File.pm open() call changed to CORE::open() to stop error during certain operations. lib/PDF/Builder.pm method synfont() was missing $basefont parameter lib/PDF/Builder/Resource/Font/CoreFont/bankgothic.pm incorrectly named method fontdata() renamed to data() for code consistency. lib/PDF/Builder.pm lib/PDF/Builder/Basic/PDF/File.pm lib/PDF/Builder/Basic/PDF/Pages.pm lib/PDF/Builder/Resource/Font/SynFont.pm minor code style and POD cleanup. t-tests.bat added (Windows) to run all t tests for mass testing lib/PDF/Builder/Util.pm documented paper_size() call, add str2dim(), did some general cleanup of POD 3.001 2017-01-30 (revised: change API2 references to Builder) based on CPAN release 2.029 2016-10-09 updated to CPAN release 2.030 2016-10-13, but VERSION left at 2.029 in files (it's questionable whether it's good to bump up the VERSION in a file unless the file has changed -- you can argue it both ways: show that a file has NOT missed an update, versus last version that the file changed at; I prefer the latter) updated to CPAN release 2.031 2016-01-26 Content: t/content.t [ref RT #98574] (was resolved) add some comments, pie() test that depends on fixes to Content.pm, correct Bogen comment. Add many more fillcolor() and strokecolor() tests. Add nl(0) and nl(width) tests. Add linedash test for hash argument list. examples/ restore old set of examples. These were internal developer test cases, and provide some useful sample code, even though some of them are not currently operational (it's on my to-do list). See the README file for the status of known problems. Also include my demo program Content.pl, to demonstrate the calls in the Content.pm module. lib/PDF/Builder/Resource/PaperSizes.pm [ref RT #98551] (was resolved) add many more useful sizes (see code for full list). These additional paper sizes were removed by the version 2 maintainer. additional syntax cleanup: lib/PDF/Builder.pm lib/PDF/Builder/Win32.pm lib/PDF/Builder/Basic/PDF/File.pm lib/PDF/Builder/Resource/XObject/Image/TIFF.pm and TIFF/File.pm lib/PDF/Builder/Resource/Font/BdFont.pm fix typo in error message. additional syntax cleanup. lib/PDF/Builder/Util.pm *HexValues() calls, pad with '0' to minimum length (silent error). Document that if wrong number of hex digits, silently ignore the extra digits. Correct grammar in a comment. Additional syntax cleanup. lib/PDF/Builder/Content.pm extensively updated: [ref RT #98545] (was rejected) formimage() permit 0, 1, or 2 scale factors (add separate X and Y scales) [ref RT #98572] (was rejected) render() restrict argument to 0..7 (int) arctocurve() renamed to _arctocurve() add POD for many calls, especially text_* methods general reordering of sections (POD) fontset() renamed to _fontset() textpos2() renamed to _textpos2() metaStart() renamed to _metaStart() metaEnd() renamed to _metaEnd() rearrange tests in _makecolor() to clarify and prevent certain errors, add _clamp() to silently force numeric values to be within a given range (e.g., gray value 0.0 .. 1.0). [ref RT #98541] (was open) if bogen() is given a radius that is too small, silently increase to minimum size (half the distance between the points). Also check that the two points are distinct and that the initial radius size is positive. Clarify the POD as to which arc is drawn and where its endpoint is. Fix many edge case bugs. [ref RT #98538] (was open) arc/pie couldn't cross 0 degrees. gave _arctocurve() an optional direction parameter (default: 0=counterclockwise sweep) and split the arc at 0 degrees. Also add detection of 0 or negative length radii for curves, or 0 degrees of sweep (start angle = end angle). Restrict angles to 0..360 range. *** NOTE *** These functions have always been ambiguous in their definition. If you gave an arc or pie sweep from 60 to 30, did you mean a clockwise 30 degree arc, or a counterclockwise 330 degree arc? The addition of a direction parameter (pie, arc) clarifies your intent, but may result in different arcs than before (requiring an explicit 1). I considered setting the default direction based on the shorter arc length probably intended, and whether it crossed the 0 degree line, but adding a parameter was much simpler and easier to understand. [ref RT #98576] (was rejected) comments on "spline" nomenclature legacy grayscale, RGB, CMYK (1, 3, or 4 numbers 0-1 range) now checks that these are numbers between 0 and 1 (no message if changed). [ref RT #98535] (was rejected) restore nl(width) capability. This was recently removed (approximately 2.026) because it had never been properly implemented (was treated as nl(0)). [ref RT #98550] (was rejected) update cr()'s POD to better explain how it works. [ref RT #98544] (resolved) Update POD for linedash() to clarify how to use a hash pattern. Note that arbitrary dash/gap pattern lengths are permitted, as is an offset into the pattern. (see Changes-ver_2 for changes to PDF::API2 up through 2.031) PDF-Builder-3.026/INFO/Changes_20210000644000000000000000000002416114165463423014725 0ustar rootrootSee also INFO/Changes-ver_2 for changes released for PDF::API2, and incorporated into PDF::Builder. See also INFO/Changes_2020 for earlier version 3 release logs. 3.023 2021-07-15 lib/PDF/Builder.pm, INFO/DEPRECATED FUTURE: Builder.pm's "default()" method may need to be renamed. Some time after Perl 5.26, Perl::Critic started flagging "default" as a reserved keyword. This needs to be further investigated. .github/workflows/test.yml Update PATH for new ImageMagick level. lib/PDF/Builder/Resource/XObject/Image/TIFF_GT.pm, t/tiff.t Fix for ticket #154 by @carygravel, and add a test for bilevel+alpha where rows are not filling out a full array of bytes. version (for distribution build), README.md, lib/PDF/Builder.pm, t/00-all-usable.t, .gitignore Modified to prereq Perl 5.22 instead of 5.20 (is 6 years old now). Also Graphics::TIFF minimum upped to 16 and Image::PNG::Libpng to 0.57 due to changes. Keep files up to date on GitHub so can successfully run without full build. Put "version" in GitHub as it's now fairly involved and I don't want to accidentally lose it! Makefile.PL, MANIFEST, META.json (add), META.yml (add), .perl-version (deleted), optional_update.pl (add), README.md Modify build process to have optional prereqs properly installed. Also ensure that mandatory and optional prereqs are consistently updated and handled. Since the vast majority of users will use the default of installing all optional prereqs, the selection process has been moved from Makefile.PL to optional_update.pl (for those manually running Makefile.PL). optional_update.pl updates Makefile.PL, META.json, and META.yml upon selection of which (if any) optional prerequisites are to be installed on a manual run of Makefile.PL. I don't want to risk getting META.json and META.yml (needed for properly installing the "recommends" optionals) out of sync by failing to update them at install from Makefile.PL, so all are now shipped with all optionals selected. .gitattributes, .github/workflows/test.yml Added .gitattributes to stop certain line-end changes that were causing CI tests to fail, add Windows tests to CI. From @carygravel. lib/PDF/Builder/Content.pm Problem with use of "pi" constant caused a warning on compile in one CPAN smoke test (Perl 5.20 for one tester). Changed "-pi" in one expression to "-1*pi" and hopefully that will silence the messages. lib/PDF/Builder.pm, lib/PDF/Builder/Page.pm, INFO/DEPRECATED, t/annotate-deprecations.t Per PDF::API2, simplify Builder's ' fixed' to ' opened'. Rename 'openpage()' to 'open_page()' and deprecate old name. INFO/Changes-ver_2, t/pdf.t Per changes in PDF::API2, sync up with 2.040 release. There are still a small number of changes not implemented (yet) in PDF::Builder, which either appear to be unnecessary, or the underlying code has changed too much to cleanly port the changes without a massive rewrite. t/deprecations.t Update for new PDF::API2 t-tests and a number of other deprecated items. Test both deprecated interfaces and their replacements. lib/PDF/Builder/Content/Text.pm, examples/BarCode-Boxes-Content- ContentText-Rotated.pl, examples/021_synfonts-022_truefonts- 022_truefonts_diacrits_utf8-023_cjkfonts-024_bdffonts-040_annotation Per 3.022 change of lead() to leading(), update examples to use leading() instead of lead(). In releases 3.020 through 3.022, INFO/DEPRECATED erroneously listed PDFStr() and PDFUtf() as being scheduled for removal after October 2022. These two routines ARE deprecated (use PDFString() instead), but there are currently no plans to REMOVE them. .gitignore, lib/PDF/Builder.pm, lib/PDF/Builder/Basic/PDF/File.pm, t/tiff.t Some minor cleanup, fix TIFF tests because grouped skips don't seem to work properly on Strawberry Perl, initialize $xmin in File.pm to prevent error message. lib/PDF/Builder/Basic/PDF/Filter/LZWDecode.pm, lib/PDF/Builder.pm, lib/PDF/Builder/Resource/XObject/Image/TIFF-TIFF_GT.pm, lib/PDF/Builder/Resource/XObject/Image/TIFF/File-File_GT.pm, t/filter-lzwdecode.t, t/tiff.t, t/00-all-usable.t, Makefile.PL Further improvements to TIFF LZW file handling [ref GH 151 and PR 156] for single and multi-strip, and horizontal predictor. Continuation of work to stop converting LZW-compressed TIFF to Flate. Code by @carygravel. Increase required Graphics::TIFF version to 10 due to fix in GT. examples/README, examples/examples.output Discuss the issue of close, heavy lines in the example bar codes appearing to merge or "blot" together. This is at least partially a consequence of lower resolution display screens (rounding errors), and although the bars separate when printed, I'm still concerned that they will not be reliably scannable. All files (.pm and .pl) containing $LAST_UPDATE can now access this string from outside the file, in the same manner as $VERSION. The variable declarator has been changed from 'my' to 'our' during package build. INFO/Changes-ver_2, /lib/PDF/Builder/Basic/PDF/String.pm, t/string.t Per PDF::API2 changes related to [RT 134957], change some regex flags to fix encoding of \n in a PDF string. t/tiff.t add version check (not just if installed) for ImageMagick and Ghostscript. Some smoke tests apparently blew up for using too low level versions. If too low version, or any problems determining the version, tiff.t fails gracefully by skipping those tests. From @carygravel. t/tiff.t use a temporary directory for various test files, enabling use from a Read-Only directory and/or running tests in parallel (from @ppisar, #153). 3.022 2021-03-27 docs/buildDoc.pl add "end of page" (###) marker to make it clear that you're seeing the bottom of the HTML page. Update build process to ensure consistent "unix" formatting of most human-readable files (#150). Some non-CPAN builds were complaining about MS-DOS format (CRLF line ends) on some files. t/tiff.t, lib/PDF/Builder/Resource/XObject/Image/TIFF-TIFF_GT.pm Per #148, update by carygravel to stop converting LZW-compressed TIFFs to Flate compression (unnecessary, as PDF directly supports LZW, and there were supposedly some edge-case bugs in the code). == REMOVED == still problems, development under way t/tiff.t per #143, update by carygravel to enable proper TIFF testing on all platforms including Windows. lib/PDF/Builder/Content-Lite.pm, INFO/DEPRECATED, t/content.t Per PDF::API2, deprecated lead() and replace by leading(). Lite's textlead() deprecated and replaced by textleading(). t/text.t Per PDF::API2 add two tests for charspace and wordspace override, and 18 more tests for basic text calls. lib/PDF/Builder/Content/Text.pm, INFO/KNOWN_INCOMP Per PDF::API2, add paragraphs() as an alias for section(). Document some minor inconsistencies in option names and behavior introduced with these changes. lib/PDF/Builder/Annotation.pm, lib/PDF/Builder/Basic/PDF/Dict-File.pm, lib/PDF/Builder/Resource/Font/SynFont.pm, examples/041_annot_fileattach, examples/060_transparency, examples/resources/sample_55.pdf, examples/resources/HarfBuzz_example.pdf Output 'endobj' starting its own line. Some PDF validators raise a stink if endobj continues a line with other commands on it. While we're at it, put 'stream' starting its own line, too. Fix two examples that failed to validate. There is a third failure, but it appears to be an issue with PDF/A disallowed content (embedded files), not a bug in PDF production here. lib/PDF/Builder/Resource/Font/SynFont.pm, INFO/DEPRECATED, examples/025_unifonts, lib/PDF/Builder/Docs.pm Fix uninitialized value (missingwidth), remove -slant (deprecated). lib/PDF/Builder/Resource/XObject/Image/TIFF.pm Corrected some bilevel color inverts. lib/PDF/Builder/Resource/XObject/Image/TIFF/File_GT.pm, lib/PDF/Builder/Resource/XObject/Image/TIFF_GT.pm Some improvements to deal with inverted colors (black/white) on certain TIFF images. Now G3 and G4 (CCITT Fax) get flipped to the correct colors, as does uncompressed bilevel. There are still some TIFF cases which are not fully properly dealt with; we are still working on them. lib/PDF/Builder/Annotation.pm, examples/040_annotation, examples/041_annot_fileattach Add "-opacity" option to control the opacity (opaqueness) of the icon, where the default of 1.0 is fully opaque, and 0.0 is fully transparent. Add "markup" method to implement "highlighted" text annotations, per [GitHub #142]. These include "Highlight" (in the manner of a highlighter marker), "Squiggly" (squiggly underline), "Underline", and "StrikeOut". These behave like a "text" annotation, but instead of an icon, the document text is highlighted. lib/PDF/Builder/Content.pm improve -strikethru placement INFO/LICENSE, README.md, lib/PDF/Builder/Basic/PDF/Array-Bool-Dict- File-Filter-Name-Null-Number-Objind-Page-Pages-String-Utils.pm Update file headers on code originally written by Martin Hosken to reflect that he has granted permission to use the MIT license instead of the Perl Artistic License on his code. This change was made so that Red Hat could have licensing compatible with LGPL for releasing PDF::Builder as part of Fedora. INFO/Changes_2020, Changes, MANIFEST, lib/PDF/Builder.pm, README.md, INFO/LICENSE 2021 copyright, archive 2020 changes. (see INFO/Changes_2020 for earlier changes) (see INFO/Changes-ver_2 for changes to PDF::API2 up through 2.033) PDF-Builder-3.026/INFO/SPONSORS0000644000000000000000000000244514356336604014202 0ustar rootrootS P O N S O R S H I P S We would like to thank the following individuals and organizations for sponsoring new features in PDF::Builder: Amtivo Group, Kings Hill, Kent, England -- FontManager and Column with MD and HTML markup. Also support added to PDF::Table to use these new features with PDF::Builder. If you would like to see new features for PDF::Builder on an accelerated schedule, please feel free to contact us (via catskilltech.com Contact page) to discuss scope, schedule, and cost. Please keep in mind that such a sponsorship does NOT create any exclusive intellectual property belonging to the sponsor! Rather, all results go into the public code repository for all to use immediately. You simply get the features sooner, and your name engraved on a plaque in this file (OK, just listed above). If you wish to purchase new features for PDF::Builder (and/or PDF::Table or any other open source product we provide) that are NOT released to the public, that is, are your exclusive intellectual property, feel free to contact us for a discussion of scope, schedule, and cost. Note that the cost will be higher, as the world doesn't get to share in the benefits of this work! Please consider a sponsorship for work that will be released to the public, and benefit it. PDF-Builder-3.026/INFO/old/0000755000000000000000000000000014534671356013546 5ustar rootrootPDF-Builder-3.026/INFO/old/dist.ini.old0000644000000000000000000000165014534467462015772 0ustar rootrootname = PDF-Builder author = Phil Perry license = LGPL_2_1 copyright_holder = Phil Perry [MetaResources] repository.url = git://github.com/PhilterPaper/pdfbuilder.git repository.web = https://github.com/PhilterPaper/pdfbuilder repository.type = git [NextRelease] format = %-9v %{yyyy-MM-dd}d [Prereqs] perl = v5.20.0 Compress::Zlib = 1.0 Font::TTF = 1.06 [Prereqs / TestRequires] Test::Exception = 0 Test::Memory::Cycle = 1.0 #[OSPrereqs / MSWin32] #Win32::TieRegistry = 0 #MacPerl = 0 [Git::Check] [Git::Commit] [Git::NextVersion] version_regexp = ^([0-9]+\.[0-9]{3})$ [Git::Tag] tag_format = %v [Git::GatherDir] include_dotfiles = 1 exclude_match = ^\.(?!perlcriticrc$) [PruneCruft] except = \.perlcriticrc [MetaYAML] [MetaJSON] [License] [Readme] [ExtraTests] [MakeMaker] [Manifest] [OurPkgVersion] [PodSyntaxTests] [Test::Perl::Critic] [TestRelease] [ConfirmRelease] [UploadToCPAN] [Git::Push] PDF-Builder-3.026/INFO/old/pc.bat0000755000000000000000000000372314534467462014651 0ustar rootrootecho off REM This should be simple enough to convert to a bash script (don't name it just REM "perlcritic", as this will conflict with the Perl command "perlcritic"!). REM You may need to install the Perl module Perl::Critic if you don't already REM have it. Windows users will probably have to install the very useful utility REM "grep" in order to run this batch file. REM REM Perl::Critic should pass level 5 (least strict) without errors. There are a REM number of errors at level 4 that still need to be fixed, but can be REM suppressed for now via "grep -v". REM REM Messages being ignored: REM source OK = nothing to report at this level (passes) REM Code before warnings = due to use of "no warnings" pragma REM Warnings disabled at = due to use of "no warnings" pragma REM Close filehandles as soon as possible = it thinks there is no "close" REM on an open filehandle, due to either too many lines for it to buffer REM or use of other code to close REM Always upack @_ first = not using @_ or $_[n] directly is good REM practice, but it doesn't seem to recognize legitimate uses REM Subroutine name is a homonym for builtin function = e.g., we REM define "open" when there is already a system (CORE::) open (ambiguous REM unless CORE:: added) REM Symbols are exported by default = it doesn't like something about REM our use of @EXPORT and @EXPORT_OK REM REM Note that level 4 includes any level 5 errors, etc. REM Don't even *try* to use levels 3, 2, or 1 unless you're morbidly curious! echo on REM level 5 should run clean REM perlcritic -5 . REM level 4 expect lots of repeated errors REM perlcritic -4 . REM level 4 suppress common warnings perlcritic -4 . |grep -v "source OK" |grep -v "Code before warnings" |grep -v "Warnings disabled at" |grep -v "Close filehandles as soon as possible" |grep -v "Always unpack @_ first" |grep -v "Subroutine name is a homonym for builtin function" |grep -v "Symbols are exported by default" PDF-Builder-3.026/INFO/old/t-tests.bat0000755000000000000000000000273714534467462015656 0ustar rootrootecho off REM This should be simple enough to convert to a bash script. Or, you can REM run Makefile.PL to create the Makefile, and do a "make test" to run all REM these tests (you may even be able to do this without having yet installed REM PDF::Builder!). You can also look at ways (such as with the "prove" command) REM to run arbitrary versions of the product. Most often, you would run the t REM tests as a regression bucket after making any changes to PDF::Builder REM itself (in development). To each his own! echo "=== use |more filter to page through test results" echo "=== or |grep -v \"^ok\" |more to catch failing results. " echo on perl t\00-all-usable.t perl t\01-basic.t perl t\02-xrefstm.t perl t\03-xrefstm-index.t perl t\annotate.t perl t\author-critic.t perl t\author-pod-syntax.t perl t\barcode.t perl t\bbox.t perl t\circular-references.t perl t\cmap.t perl t\content.t perl t\cs-webcolor.t perl t\deprecations.t perl t\extgstate.t perl t\filter-ascii85decode.t perl t\filter-asciihexdecode.t REM perl t\filter-ccittfaxdecode.t # add when TIFF changes go in perl t\filter-runlengthdecode.t perl t\font-corefont.t perl t\font-synfont.t perl t\font-ttf.t perl t\font-type1.t perl t\gd.t perl t\gif.t perl t\jpg.t perl t\lite.t perl t\outline.t perl t\page.t perl t\papersizes.t perl t\pdf.t perl t\png.t perl t\pnm.t perl t\rt67767.t perl t\rt69503.t perl t\rt120397.t perl t\rt120450.t perl t\rt126274.t perl t\string.t perl t\text.t perl t\tiff.t perl t\viewer-preferences.t PDF-Builder-3.026/INFO/old/contrib.bat0000755000000000000000000000256314534467462015710 0ustar rootrootREM this should be simple enough to convert to a bash script echo off echo === do not erase examples/ PDF files yet... they are used here echo == combine_pdfs.pl contrib\combine_pdfs.pl examples\011_open_update.BASE.pdf examples\012_pages.pdf examples\011_open_update.UPDATED.pdf ./combined.pdf echo === output to combined.pdf 15 pages: Hello World, sequence i ii iii 1 9 2..8 pages, echo === Hello World and Hello World (2) echo === note different page sizes used echo == pdf-debug.pl contrib\pdf-debug.pl combined.pdf echo === lists version, some other information contrib\pdf-debug.pl combined.pdf obj 2 echo === describes a Pages type object contrib\pdf-debug.pl combined.pdf xref echo === lists the cross reference echo == pdf-deoptimize.pl contrib\pdf-deoptimize.pl combined.pdf combined.deopt.pdf echo === outputs combined.deopt.pdf, PDF v1.2 and smaller than original echo === no idea what "de-optimize" does, only that it produces a working PDF echo == pdf-optimize.pl contrib\pdf-optimize.pl combined.pdf combined.opt.pdf echo === outputs combined.opt.pdf, PDF v1.2 and same size as original echo === no idea what "optimize" does, only that it produces a working PDF echo == text2pdf.pl contrib\text2pdf.pl contrib\text2pdf.pl echo === output to text2pdf.pl.pdf paginated listing of program echo === now you can erase the examples/ output files PDF-Builder-3.026/INFO/old/examples.bat0000755000000000000000000000332614534467462016064 0ustar rootrootecho off echo "=== examples >logfile 2>&1 to preserve all output for inspection" echo "=== follow along with examples.output to check output PDF files" echo on perl examples\011_open_update perl examples\012_pages perl examples\020_corefonts perl examples\020_textrise perl examples\020_textunderline echo off echo === 021_psfonts needs T1 glyph and metrics files (not included) echo here, assuming metrics file (.afm or .pfm) is in same directory echo on perl examples\021_psfonts \Users\Phil\fonts\T1fonts\URWPalladioL-Roma.pfb perl examples\021_synfonts perl examples\022_truefonts C:\WINDOWS\fonts\times.ttf perl examples\022_truefonts_diacrits_utf8 C:\WINDOWS\fonts\tahoma.ttf echo off echo === 023 to display the PDFs, you may need to install East Asian fonts echo === for your browser echo on perl examples\023_cjkfonts echo off echo === 024 needs a sample BDF font (not included with distribution) echo on perl examples\024_bdffonts \Users\Phil\fonts\BDFfonts\codec\codec.bdf perl examples\025_unifonts perl examples\026_unifont2 REM perl examples\027_winfont perl examples\030_colorspecs perl examples\031_color_hsv perl examples\032_separation perl examples\040_annotation perl examples\041_annot_fileattach perl examples\050_pagelabels perl examples\055_outlines perl examples\060_transparency perl examples\BarCode.pl perl examples\Boxes.pl perl examples\Bspline.pl perl examples\Content.pl perl examples\ContentText.pl REM disable next line if HarfBuzz::Shaper is not installed, REM and you will need to update font file paths perl examples\HarfBuzz.pl perl examples\RMtutorial.pl perl examples\Rotated.pl perl examples\ShowFont.pl Helvetica echo off echo === do not erase files if you are going to run "contrib.bat" echo on PDF-Builder-3.026/INFO/KNOWN_INCOMP0000644000000000000000000002643014515000564014643 0ustar rootrootA list of known incompatibilities with PDF::API2. Most are very minor, as we have attempted to maintain as much compatibility with the older product (PDF::API2) as possible. This list is believed to be complete, although unexpected incompatibilities cannot be ruled out. Bug fixes to PDF::API2 (in PDF::Builder) are not mentioned if they correct an error (that produces an error message and/or incorrect output) and do not affect the operation or results of otherwise correct code. ==== A VERY IMPORTANT NOTE ================================================= These notes describe ONLY function known to differ from behavior found in PDF::API2. That is, you may well see (somewhat) different behavior or output converting over a program that runs on PDF::API2, to PDF::Builder. It does NOT cover new function such as extended splines, HTML and Markdown formatting of columns, etc. Be aware that using such new function in PDF::Builder may make your code NOT portable to PDF::API2 (i.e., you are now locked in to PDF::Builder). The documentation may or may not mention that this is new functionality exclusive to PDF::Builder, so be sure to test on PDF::API2 if you have a package or library intended to run on both! ============================================================================ 3.024 2022-09-12 PDF::API2 now initializes page display to a fairly tightly zoomed-in (approx. 115%) scale, while PDF::Builder continues to initialize to the entire page being displayed (zoomed-out at less than 100% scale). PDF::API2 added a bar code convenience function "barcode()", which is not in PDF::Builder. Something like this might be added in the future. PDF::API2 formerly (and PDF::Builder still does) define "fit" (destination) elements as hash elements (e.g., 'fitb'=> 1) for NamedDestination, Outline, selected Annotation entries, and startup preferences; while it now names the destination as a location string (e.g., 'fitb') and an array of data (e.g., [ 1 ]). Staying with the old system permits the continued use an options hash, which PDF::API2 no longer supports. PDF::API2 allows a GIF version of 00 to 99, a to z, while PDF::Builder permits 00 to 99, a to b. I am not aware of any GIF versions other than GIF87a and GIF89a, so what is intended is not clear. 3.022 2021-03-03 PDF::API2 "exposed" paragraph() and paragraphs() and documented them. paragraphs() is implemented in PDF::Builder as an alias for section(). The -spillover option has been removed in PDF::API2 (behavior is the PDF::Builder default of "0", which is to prevent a word overflowing). PDF::Builder's paragraph() still has the $continue parameter. text_fill_justified() in PDF::API2 adds -align-last option to left/right/center/justify the last line, similar to PDF::Builder's -last_align option l/r/c (PDF::Builder accepts the full names, but permits shortening to the first letter). Unlike PDF::API2, PDF::Builder does not support a justified last line. 3.017 2019-12-31 See INFO/DEPRECATED for a list of deprecated methods and other items that have been removed from PDF::Builder (or will be, at some future date). Everything to be removed gets at least TWO years' notice in that file. If you are still using deprecated methods, you may experience errors in your code (even if they still work in PDF::API2), and need to change some calls. The fixes should be minor. There are a large number of deprecated items removed in this release, because many have been deprecated since PDF::API2's days. A quick summary: meterlimit(), hspace(), linedash() -full and -clear options, new_api(), nonstandard paper sizes, encode_3of9_string_w_chk(), encode_3of9_w_chk(), encode_3of9_ext(), encode_3of9_ext_w_chk(), imask(), bpc(), openScalar(), importpage(), pdfile(). 3.016 2019-08-03 RT #130039 PDF::API2 returns $self on 'set' operation, while PDF::Builder always returns the current (possibly just-set) corners of the box. This permits your using a named page size, while getting back the actual page bounds without having to make a separate query (get) call. RT #33497 and RT #117031 fixed differently in PDF::API2 2.034 (June 2019) than in PDF::Builder 3.013 (December 2018). In some cases with UTF-8 character data, PDF::API2 will now display as (text display) rather than in <16 bit hex Unicode values> still shown by PDF::Builder. This may lead to differences in PDFs produced by the two products, but should be invisible to the end user. lib/PDF/Builder/Basic/PDF/Pages.pm old code for the add_font() method documented the call as $p->add_font($pdf, $font), but implemented the code as $p->add_font($font, $pdf). Older user code may have swapped the order of arguments on an ad-hoc basis, to get it to work. The new code uses the same order as the documentation ($pdf, $font), which might require code to be swapped back. In PDF::API2 2.034, a note in the code mentions the order difference, but the code was not changed. 3.013 2018-12-27 lib/PDF/Builder/Basic/PDF/Utils.pm Instead of constantly explicitly checking for UTF-8 strings, and calling PDFUtf() instead of PDFStr() as appropriate in many routines, PDFString() has been added to Utils to accept a string and call PDFUtf() or PDFStr() internally, according to the passed "usage" code. This may result in slightly different behavior of PDF::Builder, compared to PDF::API2, as the code was implemented in different ways in different routines. 3.008 2017-11-26 lib/PDF/Builder.pm [ref RT #118047] now uses the Graphics::TIFF package by default for TIFF functionality. See the POD for image_tiff() for details, including forcing the use of the old (buggy) code. The new code does not permit filehandles to be passed to image_tiff() (use the old code via -nouseGT => 1 option). 3.003 2017-05-01 lib/PDF/Builder/Resource/CIDFont/TrueType.pm lib/PDF/Builder/Resource/Font/BdFont.pm lib/PDF/Builder/Resource/Font/CoreFont.pm lib/PDF/Builder/Resource/Font/Postscript.pm [ref RT #105579 and #113084 (were open)] remove ~time() from font resource names. It appears to be unnecessary, and made PDFs non-deterministic (two runs with the same input had different output), making output comparisons difficult for developers. Commented out lines containing ~time(), so they can be restored easily. **Please report any problems which appear to be resource name collisions** This is a change that MAY produce incompatibilities, so heads up! lib/PDF/Builder/Content.pm split out methods text_center(), text_right(), text_justified(), text_fill_left(), text_fill_center(), text_fill_right(), text_fill_justified(), paragraph(), section(), and textlabel() into lib/PDF/Builder/Content/Text.pm. lib/PDF/Builder/Resource/XObject/Form/Hybrid.pm needed to add Content::Text to the "use base" list, and it is possible that other programs may need to do so. In many cases $grfxobj->textlabel() had to be changed to $textobj->textlabel(), and it is possible that other calls to text methods may be similarly affected. lib/PDF/Builder/Content/Text.pm [ref RT #98546 (was open)] text justification will now attempt to use wordspace() and charspace() to fit a line to its alloted space, rather than simply scaling it with hscale(). This should result in much nicer looking output, though it will not be identical to PDF::API2's output. lib/PDF/Builder/Content.pm [ref CTS 7] $text->save() and restore() are no longer no-ops, if you had them in your code. They issue the same q and Q commands as a graphics save() and restore(). *** Removed in release 3.26. save/restore are only for graphics context *** and should not be used in text context (will see a one-time warning, *** and the calls are now no-ops) lib/PDF/Builder.pm lib/PDF/Builder/Content.pm lib/PDF/Builder/Resource/ExtGState.pm lib/PDF/Builder/Resource/XObject/Image.pm lib/PDF/Builder/Resource/XObject/Form/BarCode/code3of9.pm deprecated methods (renamed or absorbed into other methods) now get get warning messages output, in addition to (the PDF::API2 practice) of calling their replacements. If these new warnings are a problem, your code should be changed to no longer use the deprecated methods. It was felt to be not worthwhile to try to add some kind of global switch to suppress the warnings -- it's also too easy to forget to get around to updating your code! lib/PDF/Builder/Content.pm lib/PDF/Builder/Content/Text.pm [ref RT #98543 (was rejected)] most methods did not have consistent return values. Some returned $self, others returned their old settings, and still others returned nothing. When called without parameters (setting routines, such as linewidth()), the current settings are returned. linedash(-1) may now be used to query the current dash pattern setting. Some methods in PDF::API2 which returned nothing, now return a setting, but this is unlikely to cause problems in existing code. Some methods which returned the new value on a setting call (a value was given) now consistently return $self, permitting chaining of setting calls. It is possible, though unlikely, that existing code was depending on the new value being returned; these calls will have to be updated. Read the updated POD to clarify what is returned by a method call. 3.001 2017-01-30 lib/PDF/Builder/Util.pm *HexValues() calls, pad with '0' to minimum length (silent error). Document that if wrong number of hex digits, silently ignore the extra digits. PDF::API2 could produce unexpected results if the wrong number of hex digits were given, or input values which should be in the range 0 to 1 were not (they are now clamped to that range). This may result in different colors being set than in PDF::API2, even though the original colors were erroneously specified! lib/PDF/Builder/Content.pm updates: arctocurve() renamed to _arctocurve() fontset() renamed to _fontset() textpos2() renamed to _textpos2() metaStart() renamed to _metaStart() metaEnd() renamed to _metaEnd() It is unlikely that anyone was using these internal routines, but in case they are... [ref RT #98538 (was open)] arc/pie couldn't cross 0 degrees. gave _arctocurve() an optional direction parameter (default: 0=counterclockwise sweep) and split the arc at 0 degrees. *** NOTE *** These functions have always been ambiguous in PDF::API2 in their definition. If you gave an arc or pie sweep from 60 to 30, did you mean a clockwise 30 degree arc, or a counterclockwise 330 degree arc? The addition of a direction parameter (pie, arc) clarifies your intent, but may result in different arcs being drawn than before (requiring an explicit 1 in the argument list to set a clockwise sweep). [ref RT #98535 (was rejected)] restore nl(width) capability. PDF::API2 cannot specify a width (amount of indent); it was treated as nl(0). PDF-Builder-3.026/INFO/PATENTS0000644000000000000000000000341214231635745014025 0ustar rootrootPATENT CLARIFICATION NOTE Adobe has a number of patents covering technology that is disclosed in the Portable Document Format (PDF) Specification, version 1.3 and later, as documented in PDF Reference and associated Technical Notes (the Specification). Adobe desires to promote the use of PDF for information interchange among diverse products and applications. Accordingly, the following patents are licensed on a royalty-free, non-exclusive basis for the term of each patent and for the sole purpose of developing software that produces, consumes, and interprets PDF files that are compliant with the Specification: U.S. Patent Numbers: 5,634,064 (expired) 5,737,599 (expired) 5,781,785 (expired) 5,819,301 (expired) 6,028,583 (expired) In addition, the following patent is licensed on a royalty-free, non- exclusive basis for its term and for the sole purpose of developing software that produces PDF files that are compliant with the Specification (specifically excluding, however, software that consumes and/or interprets PDF files): U.S. Patent Number: 5,860,074 (expired) The above licenses are limited to only those rights required to implement the Specification and no others. That is to say, Adobe grants only those rights in the above patent(s) necessarily practiced to implement the Specification, and does not grant any rights not required to implement the Specification. The licenses do not grant the right to practice any patent covering other technologies, such as implementation techniques that are not explicitly disclosed in the Specification, nor does it allow the use of any patented feature for any purpose other than as set forth in the applicable license grant. Adobe has other patents in various fields, none of which are hereby licensed. PDF-Builder-3.026/INFO/SUPPORT0000644000000000000000000000314113771462227014063 0ustar rootroot PDF::Builder is a fork (July, 2017) of the popular PDF::API2 Perl software for PDF creation and manipulation. Why does it start with version 3.004? The owner of PDF::API2 requested that the name of the fork be changed from API2 to something else to avoid confusion. The author of Builder had originally offered this software as another version of API2, and had already jumped the version from 2.xxx (API2) to 3.xxx (now Builder) and had made three releases (served from the catskilltech.com website). Rather than reset to 1.000, it seemed cleaner just to continue with the 3.xxx version. PDF::Builder source is hosted on GitHub (https://github.com/PhilterPaper/Perl-PDF-Builder), with the Perl installable module download offered on CPAN (PDF::Builder). Many users can directly install using a CPAN-compatible installer (e.g., 'cpan' on Strawberry Perl, or 'cpanm'). Please raise issues (bug reports, etc.) on GitHub, under the "issues" tab, with label "bugs". Feature Requests should be labeled "enhancement". The maintainer will close (and tag as appropriate) resolved or rejected issues. General discussions not pertaining to a specific issue (bug) may be conducted on GitHub "issues", labeled with the "general discussion" label. Do NOT under ANY circumstances open a PR (Pull Request) to report a bug. It is a waste of both your and our time and effort. Open a regular ticket (issue), and attach a Perl (.pl) program illustrating the problem, if possible. If you believe that you have a program patch, and offer to share it as a PR, we may give the go-ahead. Unsolicited PRs may be closed without further action. PDF-Builder-3.026/INFO/CONVERSION0000644000000000000000000000325414534467462014405 0ustar rootrootConverting from PDF::API2 to PDF::Builder If you have been running PDF-creation code under PDF::API2, and wish to give PDF::Builder a try, for the most part it should be quite compatible. It is a superset of PDF::API2 functionality, but there could be some "gotchas" if your code made use of certain obsolete things. For most code, simply changing all occurences of "PDF::API2" to "PDF::Builder" in the code should be sufficient to start running under PDF::Builder. If you get errors reported by Perl, check the following two files: * INFO/DEPRECATED is a list of DEPRECATED method names, etc. that have been removed or changed, or will be in the future. We give at least 2 years' notice of such items, as well as how to change your code to avoid problems. Whether or not you have used PDF::API2, you should periodically check in with this file to see if there are any upcoming changes you need to prepare for. * INFO/KNOWN_INCOMPAT is a list of known incompatibilities between PDF::API2 and PDF::Builder. Most are minor differences in behavior introduced as bugs were fixed over time. A few times, code was changed to match the documentation (such as order of arguments). We try hard to avoid changing existing code behavior, but sometimes it's just not possible, particularly if the old behavior was actually in error! Note that PDF::Builder is *NOT* a layer over PDF::API2 (i.e., does not require that PDF::API2 be installed). It is a totally independent installation. It is quite possible to install *BOTH* at the same time; they will not interfere with each other's operation. This allows PDF::API2 users to avoid going offline while testing a switchover to PDF::Builder. PDF-Builder-3.026/INFO/RoadMap0000644000000000000000000010216514534467462014244 0ustar rootrootRoad Map for Future Development of PDF::Builder 01 Apr 2023 In order to encourage others to contribute code and/or algorithms to the effort, I am publishing this road map of where I would like the product to go. Please, no copyrighted code or patented algorithms, unless the owner releases them under an Open Source license! The content of this road map is open to discussion, too, on the GitHub bugs list (feature requests with the "enhancement" label or "general discussion" label). If you have a one-off suggestion, there is a contact page on my site, so you don't have to sign up for GitHub to be heard. If there are no contributions on something, I reserve the right to write my own modules (dependent on PDF::Builder) and sell them. I make no promises that any of the following items will be implemented; it depends on how much free time I can come up with, and how many people chip in to help with code and algorithms. I'll be happy to discuss coding specific requirements for money/donations (but the result is still free software). The assignment to section I or II is somewhat arbitrary, and an item could move from one to the other. Some of these items are already listed in bug reports, or as feature requests. There is no particular order to these items (i.e., they are not ranked by priority). ============================================================================= I. Items to add to the core product These are things that should be in the base PDF::Builder product, as everyone will need them (or, it would be cleaner to have it in the base rather than as an add-on separate module). A. ## DONE ## release 3.018 Proper TTF/OTF support (RT 113700), especially ligature replacement and complex script alphabets using GSUB and GPOS information. I've been looking at Pango and directly using HarfBuzz, but both look to be a lot of work. I know of a developer tinkering with an add-on layer using Pango for both PDF::API2 and Builder, but it's not clear to me how far he intends to go beyond simple markup to change fonts (a la HTML presentation tags). If it uses Pango, hopefully the other stuff will come along for free. We'll see. For Western (simple) scripts, automatic ligature support would be wonderful, but we need to be able to suppress selected ligatures (e.g., 'ff' in the English word 'shelfful'). Support for swashes and alternate glyph choices would be very nice to have (embedded markup language?). For complex scripts like Arabic family and southern/southeastern Asian families, proper support (Pango?) is vital. UPDATE: See Text::Layout and HarfBuzz::Shaper packages. Layout is usable with Builder (but no explicit support yet). Shaper is supported by Builder for ligatures and complex scripts. Need to see if it supports true small and petite capitals (included with font) as a sort of alternate glyphs. It's probably not feasible to decompose outline fonts and shrink them down nonlinearly (stroke widths reduced less than overall height/width) and recreate the new outlines as synthetic small/petite caps. (A1.) Look at examples/HarfBuzz.pl to see some problems with ligatures. In some cases, such as "waffle", a PDF Reader can search for and find it even if "ffl" has been replaced by a ligature (single glyph). However, in other cases, such as "strasse", the Reader can NOT find the word when "ss" has been replaced by an eszet. My keyboard doesn't have an eszet, so I can't easily test if it can be searched for. I don't think there's anything in the PDF::Builder code which is substituting eszet for "ss". Interestingly, the "st" ligature in the same word does not present any problem. B. Unification of font support: including character set and encoding support improvements [see CTS 16 and CTS 23] to make more commonality between using UTF-8 and single byte encodings, across all the font types (core, TrueType, Type1/PS, etc.). One problem with core fonts is, even though most core fonts are already TrueType, that only the Latin-1 glyph set has widths defined, and only single byte encodings are possible (similar for Type1/PS fonts). To support UTF-8 for core and PS, the font might have to be built on the fly for a page (like a synthetic font), with translations to single bytes for all glyphs. If the resulting font exceeds 256 characters, something would have to be done to split the page internally into two or more sections, each with their own embedded virtual font. Glyph widths would have to be available for all characters. Add: start a subfont with the ASCII set and empty top 128. Add new chars to it (from x80 to xFF) as single byte glyphs (not matching any standard encoding) and use this new subfont. When it fills up and more characters are needed on a page, start another subfont. C. Improved documentation, possibly even a book giving detailed explanations and examples, as both a reference and a tutorial. Needless to say, there would have to be sufficient interest to warrant the time and expense of writing/editing and publishing (in any format) a book to be sold! D. PDF/A (archival document management, RT 120375): this might be more than throwing a few flags/overriding flags to force font embedding and no encryption/ passwords. There may be other stuff that needs to be done to achieve recognition as a proper archival format (and there are apparently several archival formats). E. JPEG2000 image file support (CTS 12): I don't know if this is worth it, as there seems to be very little use of this, but if someone is interested, have at it... any other newish image formats that PDF can support? F. Fix Bar Code generation (CTS 1): there seems to be something quite wrong with the current bar code generation, so it's possible that no one is using it in real documents yet. It's also possible that I'm not writing my test cases properly -- does anyone know if they work? I suspect that the use of XForms (relocatable text and graphics) for the bar image is not scaling nicely, and may have to be replaced by drawn graphics primitives (text and graphics drawn in their final place). Many other 1D and 2D bar codes (including QR) would be good, but perhaps the bar codes should go into a separate module, due to their potentially large code size and use of "new" Perl modules. Even the existing 5 or so formats could be moved out, as presumably no one is using them yet (if they are, in fact, broken). This is in section I, as bar codes are already implemented in the base, but it's possible that bar codes could be removed and reimplemented in section II as a separate library or module. Update: Actually printing out the example bar codes separates the "merged" blobs into discrete lines. This may indicate rounding errors when presenting on a low-to-medium resolution computer screen. However, on a consumer-grade laser printer, the lines are still so close that I fear most scanners would hae trouble reading the bar codes. I may have to do something with reducing bar widths a little to allow for irregular edges ("blotting"). Take a look at package PDF::QRCode. It uses Text::QRCode internally, but the interesting feature is using a code monkey to integrate itself (like a retrovirus) into PDF::Builder, and can be called $gfx->qrcode(parms). Long term: consider a new package that generates an output-agnostic generic graphics list, along with sample GD, PS, PDF::Builder drivers; as well as PDF::Builder generic barcode. Grab all sorts of Perl and non-Perl open source generators and snag their algorithms to incorporate into the library. incl PHP tecnickcom/tc-lib/barcode, Perl PDF::QRCode, etc. Allow qw/code1 code2/ in use BarCodes statement, as most users will just want to import a very small subset of available codes. G. Fix Small Caps (and capitalization in general) for ligatures (CTS 13): some ligatures given in Unicode or single byte encodings don't get properly uppercased. The probable solution would be to decompose ligatures to their individual letters before capitalization or Small/Petite Caps (if an uppercase version doesn't exist in the font, or use GSUB processing to recreate a ligature from the capital letters). As Perl doesn't seem to handle capitalizing ligatures properly, a "capitals" function would need to be offered, as well as improvements to the Small Caps in "synfonts". Various non-Latin single characters (e.g., Greek terminal/nonterminal sigma, German eszett, long s) also may need proper handling for capitalization. UPDATE: It may be better to use individual letters (rather than ligature Unicode points), allowing easy capitalization and small caps. Then use HarfBuzz::Shaper to replace lowercase letter sequences with true ligatures on the fly. H. Fallback glyphs (CTS 5) when a desired glyph is not found in one font, but can be found in another. This is similar to HTML when you give a font family list in CSS. Pango might help with this. UPDATE: This is being considered for Text::Layout, but nothing scheduled yet. I. Support for tagged structure (CTS 17 and RT 120375). At least, don't corrupt an existing tagged PDF file when extracting pages. J. Adding comment fields to any object (and possibly standalone comments as their own objects). An example would be an image object with a comment giving the source image file, for debugging purposes). K. Text method to move to arbitrary points: relative or absolute movement horizontally and vertically (a range of units), including tab support (including \t and \v embedded in text), and maybe \n while we're at it. Note that tabs bring up some issues. First, a tab by character count (the traditional way, e.g., to the next n8-th column) is useful only for monospaced fonts, and no changes in font size in the line. Thus, tab stops would be more useful when defined by some absolute dimension (e.g., inches or mms) of column position. Second, tabbing is usually done to get text columns (sub columns), which involves a lot of manual setup and twiddling of text. Consider using a TABLE within the column or page to get text organized into the desired format (see "tbl" addition in section II). UPDATE: The $text->distance() call permits arbitrary delta-x and delta-y (in points) of text movement. It's not hard to convert non-points to points, such as distance(2.4/in, -1.23/cm). For tables, take a look at the PDF::Table package for now. L. Determine what it is about "CJK" fonts (.ttf and .otf) that makes them incompatible with synfont [RT 130040] and embedding [RT 130041], and fix if possible. Are separate CJK fonts even necessary these days? Also note that many CJK fonts refuse to "subset" when embedded (the entire font gets embedded, even if you only use a handful of glyphs!). M. Add decorative rectangular box effects around sections of text. With or without border (allow rounded corners) and background color, drop shadows (3D effect), etc. The box is drawn at given dimensions and location, and the text written over it in the usual manner. Content clipping might also be supported. See PDF::Table for drawing rules (and borders) for ideas, as well as block background colors (gfx_bg object before text object). N. Extend HarfBuzz::Shaper use (see A.) to flow paragraphs and sections (fill) to match capability of existing text-fill calls. Architect so as to extend easily to full paragraph shaping and "pouring" text into arbitrary columns, with balancing. Justification to avoid ragged-left or -right needs to be handled carefully for connected glyphs (e.g., Arabic, Indic, cursive Latin). Treat HarfBuzz::Shaper handled-fonts just like any other font when it comes to various text-handling routines (including length, justifying and aligning text, filling lines, paragraph, section, textlabel, etc.). O. ## DONE ## release 3.020 Support for PNM and related graphics images. See RT 132844. P. Look into using TeX::Hyphen or Text::Hyphen to split words properly. The latter supports 3 languages besides English. Both use TeX (Knuth-Liang) algorithms. Eventually need means to override built-in hyphenation (e.g., force 're-cord' or 'rec-ord', per context), similar to ligature control. One way would be to insert soft-hypen &SHY;, this might require all syllable breaks to be so marked, since TH might not see it any more. Use any place where a string is flowed into multiple lines, and eventually for complete paragraph shaping. Retain camelCase and punctuation/numeric splitting as fallback for non-words. Consider own built-in version of either TH, using CTAN directly (would take rewrite of the Perl code?), if can't get owner to upgrade it. Q. ## DONE ## release 3.020 Look at Basic/PDF/File.pm 'Q>' unpack (ref RT 133131). Supposedly will not run on a 32 bit platform -- will it work on such platform to check if high 33 bits are all 0, and convert the low 32 bits to a fullword integer? R. TTF/OTF font embedding: consider -forceASCII and -forceLatin1 options to make the entire ASCII alphabet (or the entire Latin-1 alphabet) embedded, not just what subset of characters (and glyphs) were used in text. This might be useful in fillable forms and any other situation where an end user gets to type in text. There is already the ability to embed the entire font, but that's often overkill. S. Many requests in wkHTMLtoPDF to output an entire web page into a single PDF page. This is not as ridiculous as it sounds, as there are roll printers that effectively have no fixed page height. For Builder, this would mean outputting to a page of indefinite height, which in turn means that Y-coordinate values as input would have to be updated to the new, extended page. Many calls to Builder routines involve x-y coordinates on the (fixed size) page, as opposed to a continuous print-at-the-bottom model. Perhaps start with a normal fixed size (minimum) page and allow Y-coordinates to go negative, and fix them all up at the end before or during render to the file? Another possibility is to use a negative Y-coordinate to mean "place me at the bottom". Also remember that beyond 200 inches in height, support in readers and tools will vary. T. Extend the pageLabel() call to not only label the reader's thumb, but also place the SAME page label text somewhere on the page. This might be combined with header() and footer() calls, possibly to call pageLabel() when the page numbering field is encountered (if flag set to do both). The idea is to minimize labor and ensure a consistent page numbering between the paper and the reader's thumb. header() and footer() might be placed in the top and bottom margins, leaving it to the user not to write into these areas. See #171 for pageLabel() enhancements. Also, page label for outlines/bookmarks should be consistent with the thumb and what's printed on the page. A manual page number call to put the page label on an arbitrary place (such as centered in the outside margin) would be good. U. Consider PCF (bitmapped font format) font support, in a manner similar to the more primitive BDF support. PCF fonts are common on some systems (X11 used them extensively), but it's unlikely that there would be much interest to widely use them today. See https://fontforge.org/docs/techref/pcf-format.html V. Add calls to insert Javascript actions for various objects. Not all Readers may support the same Javascript level, so be careful. There are many actions and many triggers that are supported. There may be some overlap with annotation links (such as opening files or links on a click). W. Per #187, some PDF Writers produce PDFs with /StructTreeRoot. Check to see if this item is properly handled (not lost or corrupted) by Builder. Issue was PDF::API2 accused of producing bad PDF, but turned out to be referencing a /StructTreeRoot but that object was missing (so apparently not a bug in API2 or Builder). See if newly-created PDF should include a STR, or at least check if it is referenced but not present (in general, check if any referenced object does not exist). ============================================================================= II. Items to add to a separate area (new module or sub-module) These are things that not everyone will require, and so should be split out into possibly a separate module (dependent on PDF::Builder). Some of these things are getting into the realm of support for markup languages and word processing. A. Hyphenation and paragraph shaping: including CTS 20 (Hyphenation) and CTS 24 (pseudo page objects). The idea is to use Knuth et al.'s line-splitting and paragraph shaping algorithms to flow text into a space in a visually pleasing manner, while obeying widows and orphans constraints (as well as not orphaning headings). Pango may help here with line and word splitting. ** Look into item P in section I ** Text::KnuthPlass might be usable for general paragraph setup (allows non- rectangular paragaph), uses Text::Hyphen internally, don't know yet if it does the full Knuth-Plass "rivers of white" and "too many hyphens in a row" bit. Interaction with Text::Layout stuff (font, size, changes)? I've gotten Text::Hyphen and Text::KnuthPlass working, and tests suggest that they (mostly) work great. Unfortunately, KP doesn't build on all systems (a simple fix), so I may have to forcibly take it over if the owner doesn't respond reasonably soon, or just take it into the product. Hyphen could use some improvements for multilanguage support, also waiting for a response. Some sort of "virtual printing (see 'B') would be necessary, as dealing with widows and orphans would be much easier that way. B. Virtual pages: this would be related to item (A) (paragraph shaping), where PDF code would not be immediately written to an output page, but would be buffered, and output only later. This permits easier paragraph shaping and other rearrangements across columns and pages, where the starting location of a line of text is in the buffer, and it can be updated when moving the line around. Even individual words might be tagged (location and hyphenation points) so that lines could be broken at will. Even a limited amount of virtuality (virtual line output) could be useful for resetting a baseline to accommodate a change in font size -- this might involve tagging a word or block of words of the same height. PDF::Table product (or table functionality within Builder) could make use of virtual printing to "print" to a mini-page within a cell (fixed width, min/max height). If it doesn't fit on the page, decide where to split row to avoid widows and orphans. Also knowing cell height and row height, can vertically align a cell's contents. C. General text flowing capability, to fill irregularly shaped columns (such as with intruding inserts or margin notes) in a balanced manner, including spanning headings across all columns, where appropriate. This would also include flowing text around images, tables, or other inserts to avoid leaving large empty sections of pages (e.g., have a large table that floats to the next page, with text after it that could easily come before it on the original page). Something to handle cross references would be handy here, to output "see table X above" or "below", "on the previous page"/"on the next page", "on page X", etc. in a prescribed and consistent manner. Note that it might be good to notify the user during processing that such a move has been done, so that it can be inspected. UPDATE: Columns could be any shape, drawn with lines, polylines, arcs, circles, splines, etc. Text baselines don't necessarily have to be horizontal. Clip baselines to the "column" shape to get the line length and starting point for each line of text. There may have to be some iterations to reshape a line if its height results in a shift of the baseline into a wider or narrower area. D. Font Families: per CTS 22, make it easier to deal with switching fonts and variations within a font (bold, italic, size, color, underline, small caps, etc.), possibly with HTML tags inlined. The idea would be to only have to specify a typeface and initial size, and then switch in and out of variants (bold, italic, etc.) without having to call all the font routines yourself. Perhaps several formats of markup could be supported (HTML, Markdown, troff), driven by a definition file? Pango may help with this, at least with font-specification markup. UPDATE: Text::Layout package may prove very useful here, although it needs some enhancements (a new "back end" to return text for shaping, rather than directly outputting it). E. Continuing (D), eventually much of HTML and other common markups (headings, quotes, HTML entities, tables, lists, etc.) supported. One goal would be to eventually support enough of each markup to have a separate converter product (HTMLtoPDF, troffToPDF, etc.), but support for full Javascript and CSS (for HTML pages) will be a bear! Some level of macros (predefined strings) would be useful. Non-HTML might be converted to HTML or Pango format first. F. Support for SVG graphics (drawing), support for troff's eqn, pic, and tbl markup languages to make it easier to do anything other than plain text. LaTeX equation and table handling would be good to have, too, to avoid having to rewrite marked up text. Also provide a full graphing functions library (stacked/unstacked line, bar, scatter plots etc. in 2D and 3D). eqn might be done with something based on (translated from) the MathJax Javascript package (TypeScript source). There doesn't appear to be a Perl implementation, and supposedly MathJax is highly dependent on the browser DOM, which could be a problem. However, it might be easier than starting from scratch (with all due credit and links to the MathJax authors/site). I won't know unless I take a deep dive into the MathJax source. G. Prepress production markup: convenience functions to place a watermark or draft notice on all (or selected) pages, crop marks (based on trimbox), temporarily draw page bounding boxes, temporarily draw object limit boxes, color dots/bars for color printing alignment, instructions to the (human) printer. Page background color or pattern should extend to the full size of the page and not end when content ends part way down the page. Remind users that most printers will not print all the way to the edge. See Boxes.pl example. H. Incorporate PDF::Table into PDF::Builder::Table. Simplify it somewhat (e.g., instead of separate line-width and color settings, use a list: w (width in points with default color and solid line), or [w, color, optional-dash- pattern]. Use it for borders and rules, and possibly frames. A "frame" would be the enclosure for the table, and would be either a line spec or a width and pattern (3D raised, 3D sunken, sunken table, raised table, floating table with shadow, etc.). A "rule" would be horizontal and vertical divider lines, and a "border" would be cell dividers ([w, color, margin-to- cell edge, optional-dash-pattern]). Other simplifications and consolidations of settings as justified (do not have to maintain absolute compatibility with existing PDF::Table). Tables continued to the next page would not get a full frame at the bottom/top, but a heavy dashed line (if breaking in middle of a cell) or heavy solid line (if breaking at a row boundary). It might be good not to automatically create a next page and start outputting the rest of the table, but hold the contents and alert the programmer that at least one more call is needed to finish. Currently, PDF::Table basically equalizes column widths as much as it can, but consider a starting point of relative and/or absolute column widths, like many other table implementations. Some columns absolute widths, and remaining space divided up even among *'s (with a column N*), subject to minimum and maximum widths. Within a cell, ideally it would be treated as a mini-page, with all the normal PDF construction capabilities including paragraph shaping, flow into column(s), images, etc. This would be better than the "text_block" used in PDF::Table (more uniform coding and treatment), although some ideas from text_block might find a home. However, such complex treatment (a table could embed a table) requires virtual pages to permit a lot of rearrangement. I. Consider Optional Content Groups (Layers), per 32000-2008 section 8.11. This permits drawings to be shown by layer, or a watermark/copyright layer to show only on printing. J. ## DONE ## release 3.020 (documentation improved) Per wkHTMLtoPDF issue 4846, at least some phone cameras output "portrait" mode photos in landscape mode (rotated), with an "orientation" tag. JPEG (at least) image handling may need a rotation flag in the call, and/or pay attention to the Exif orientation flag. Confirmed that Builder JPEG support does NOT respect the orientation flag. https://www.google.com/search?client=firefox-b-1-d&q=jpeg+orientation+metadata Unfortunately, there are a number of ways to specify the orientation flag including XML 'Top-left' and buried somewhere in the Exif or JFIF header of the file. It might be best to ask the image what its orientation is, and leave translation and rotation of the placed image to user code, rather than trying to flip the contents of the image file directly. See writeup in Docs.pm. Supposedly CSS img { image-orientation: from-image; } will get from EXIF, although this may have been deprecated. K. A means to update PDF content already written to the $pdf data structure, but not yet written to file. This could involve moving a text write (one or more translates) to somewhere else on the page, or even moving from one page to another. More general editing of material already "written" out, such as changing a font size or a color -- would need a way to find the desired content to be modified. Ability to erase content or move it from page to page (e.g., started a table and then found it wouldn't fit on one page -- move it to the top of the next page to allow display on a single page). If virtual pages, design with all this in mind, so easy to update content before being "written" out. If nothing is written to the PDF file until the end (save or saveas), this might even supersede virtual pages. L. (See B and H items above) Consider a $page->subpage(x, y, w, h, opts) to subclass a page into a restricted area (not necessarily rectangular, or bounded in height). Things like columns and table cells could then be treated as normal pages (inherit text and graphics contexts?) and anything could be put into them. May want to wait until have virtual write capability rather than writing to file right away, for fitting table cells into a page, and balancing columns. Once in, build-in PDF::Table capability as PDF::Builder::Table, and can have arbitrary content in a table cell. ============================================================================= III. A new architecture, in a new package These are things that would be useful in being able to handle page design in a higher-level manner. This would almost certainly be another package, such as PDF::Builder::Environments. A. Introduce the concept of environments, which take care of handling much of the busy-work of laying out a page. page -- including margins (define the work area); page numbering, outline, and slider thumb consistent page numbers; headings/footings. also odd/even page layouts, odd-only, or single page (roll printer) layout column(s) -- define single or multiple columns, not necessarily of rectangular outline or of the same width or height. lower level environments can modify the initial outline (eat away at it). balanced columns could be done heading -- per column or per page, keep together along with first two lines of following paragraph footnote -- per column or per page, grows up from the bottom and can spill to the next page. mostly for keeping track of the bottom of the usable area margin note -- a minipage eating into a column and margin, limited to column height. must be defined before filling column inset -- usually rectangular (but could be any shape) that eats into the space for one or two columns floats -- per column or per page, for images, etc., may float left or right (but not cause a hole in the middle of a column) table -- per column or per page, somewhat like PDF::Table, but probably only fixed width columns, and content fill left to author list -- per column or per page; sl, ul, ol, dl; content fill left to author span all or selected columns heading footnote floats -- may be centered here table list The idea is that you start an environment (either implicitly or explicitly) and are responsible for all the content. At the start, you are told the position of the upper left corner (not necessarily a baseline), the allowed width, and the maximum height on this page. You fill in the content as you wish. At the end, you close the environment. The current PDF::Builder is only used for low-level stuff (primitives); the higher-level structure is in this package. The purpose is to allow you to put any kind of content anywhere, such as another list within a list item, or another table within a table cell (as well as a table within a list or a list within a table cell). The current PDF::Table severely limits your content to (currently) simple text of constant font, font size, color, etc. It is up to you to obey the limits of the extent of your content (no checks for overflow). Some environments (e.g., insets) will eat into the real estate defined for their parents, so they will have to be fully defined and filled before you start filling their parents. A table row would need to be defined (filled) before ink can be put down, so there may also need to be a table row environment. To handle vertical alignment, or decide where to split a row across a page break, the table environment needs to know the height of each row. This may need a means of tentatively writing a virtual row, moving part to a new page (or down their cell) if necessary, and commanding that the ink be put down. It may even be necessary to move the entire row to the next page (e.g., a cell's content is an image). Note that a new page is handled by the top-level program, rather than having one automatically created -- unlike PDF::Table, permitting more control over the layout and appearance. Balanced columns could be done. If the columns are purely rectangular (no insets, floats, etc.) and of the same width (not necessarily the same height), we could fill in the same order as they are read and if not completely filled, move already-formatted lines one at a time until balanced. Columns which do not meet these criteria would be more difficult. An estimate could be made of where to cut the columns by tracking the "area" used by the longer column(s), and redistributing it to the short column(s), then refilling the columns to the new height limit. This would be expensive, particularly if using Knuth-Plass paragraph shaping, as it might have to be done several times per page. Likewise, fixing widows and orphans by changing leading would be much more expensive in non-rectangular columns. Lists are vertical, and include unordered lists (you select marker), simple lists (like unordered, but no marker), ordered list (decimal, lc roman, UC Roman, lc alpha, UC Alpha) with selectable starting value (default 1). For unordered and ordered lists, the marker is right justified in a specified width, with a specified gutter before the content (and specified prefix and suffix strings around the marker). The marker can be specified to be 'inside' or 'outside' the content (if inside, the content is indented). The content area coordinates are returned to the user, who fills it in with whatever they want, obeying the size limits and any indentation. Reasonable defaults can be used for all these settings. Definition lists would have the term(s) by default bold, and always break and indent for the content, or only if the term exceeds some maximum width. Again, the content is the responsibility of the user, so any kind of content can be given. Each list item is handled separately, although a wrapper could be written to do multiple items at once (simple text only). B. Before implementing any of "A", see how a RTL language should be handled. PDF-Builder-3.026/INFO/DEPRECATED0000644000000000000000000002046214506572626014316 0ustar rootrootA list of DEPRECATED names and interfaces in PDF::Builder. These are sometimes misspellings that have been corrected at some point in the past (in PDF::API2), although some are interfaces that have been removed. Rather than keeping the old names around forever, they will be sunset and removed in due time. Please periodically check this list and make sure you have plans to change or remove these deprecated usages before they disappear from PDF::Builder. Initially, the deprecated items MAY only be commented out (so they can be restored by a user in an emergency), but eventually they WILL be removed. CAUTION for maintainer: minimum 24 months after next RELEASE, not edit date! NOTE for maintainer: update t/deprecations.t with tests for both old (deprecated) and new interfaces. when REMOVE deprecated, move to "done" section here AND comment out that test in t/deprecations.t (but leave replacement interface's test active). In order of scheduled removal date: PDFStr() method in Basic/PDF/Utils.pm NOT scheduled to be removed, but use PDFString() instead. PDFUtf() method in Basic/PDF/Utils.pm NOT scheduled to be removed, but use PDFString() instead. openpage() method in Builder.pm Use open_page() instead. May be removed on or after June, 2023. default() method in Builder.pm May be renamed in the future, as is flagged by Perl::Critic as reserved. Use with caution. width(w),height(h) methods in Resource/XObject/Image.pm The ability to SET an image's width and/or height is scheduled to be removed after October 2025. This setting ability appears not to work, but in case someone IS using it in some manner, it has not been immediately removed. *** If I have missed any deprecated interfaces, please let me know! *** ======= Deprecated items that already have been removed ====================== Blackls1 DecodeParms hash element in Resource/XObject/Image/TIFF.pm Misspelling of "BlackIs1" (EYE instead of el) PDF flag. It was reported in PDF::API2 bug RT 15730, but rejected. BlackIs1 has been added, and Blackls1 deprecated. Blackls1 will be removed (no longer set) on or after August, 2018. [Removed September, 2018] meterlimit method in Content.pm and Resource/ExtGState.pm Misspelling, corrected to miterlimit. Use "miterlimit()" instead. A warning message is currently given. Scheduled to be removed on or after August, 2019. [Removed November, 2019] hspace method in Content.pm Misnamed, as it not an amount of horizontal space, but is a horizontal scaling factor. Use "hscale()" instead. A warning message is currently given. Scheduled to be removed on or after August, 2019. [Removed November, 2019] It is POSSIBLE that after hspace() is removed, a NEW hspace() might appear for the purpose of adding some amount of horizontal space to a line of text, but there are no firm plans at this point. If such a method is added before the old hspace() is cold and dead, it would have to get a different name. linedash -full and -clear options method in Content.pm The dash pattern setting hash options "-full" and "-clear" are deprecated in favor of the "-pattern" array. A warning message is currently given. They are scheduled to be removed on or after August, 2019. [Removed November, 2019] new_api method in modules NamedDestination.pm and Resource.pm Also in t/deprecations.t This method was dropped in favor of using "new(PDF_object, options)". A warning message is currently given. new_api() is scheduled to be removed on or after August, 2019. [Removed November, 2019] paper sizes 4a, 2a, 4b, 2b in Resource/PaperSizes.pm Non-standard paper size names. Use 4a0, 2a0, 4b0, and 2b0 instead. Scheduled to be removed on or after August, 2019. [Removed November, 2019] encode_3of9_string_w_chk method in Resource/XObject/Form/BarCode/code3of9.pm This was rolled into encode_3of9_string() with a parameter some time ago. Use encode_3of9_string(*, 1) instead. A warning message is currently given. encode_3of9_string_w_chk is scheduled to be removed on or after August, 2019. [Removed November, 2019] encode_3of9_w_chk method in Resource/XObject/Form/BarCode/code3of9.pm This was rolled into encode_3of9() with a parameter some time ago. Use encode_3of9(*, 1, 0) instead. A warning message is currently given. encode_3of9_w_chk is scheduled to be removed on or after August, 2019. [Removed November, 2019] encode_3of9_ext method in Resource/XObject/Form/BarCode/code3of9.pm This was rolled into encode_3of9() with a parameter some time ago. Use encode_3of9(*, 0, 1) instead. A warning message is currently given. encode_3of9_ext is scheduled to be removed on or after August, 2019. [Removed November, 2019] encode_3of9_ext_w_chk method in Resource/XObject/Form/BarCode/code3of9.pm This was rolled into encode_3of9() with a parameter some time ago. Use encode_3of9(*, 1, 1) instead. A warning message is currently given. encode_3of9_ext_w_chk is scheduled to be removed on or after August, 2019. [Removed November, 2019] imask method in Resource/XObject/Image.pm This functionality was rolled into mask() some time ago. Simply rename any call to "imask" to "mask". A warning message is currently given. imask is scheduled to be removed on or after August, 2019. [Removed November, 2019] bpc method in Resource/XObject/Image.pm This functionality was renamed to bits_per_component() some time ago. Simply rename any call to "bpc" to "bits_per_component". A warning message is currently given. bpc is scheduled to be removed on or after August, 2019. [Removed November, 2019] openScalar method in Builder.pm This functionality was renamed to open_scalar() some time ago. Simply rename any call to "openScalar" to "open_scalar". A warning message is currently given. openScalar is scheduled to be removed on or after August, 2019. [Removed November, 2019] importpage method in Builder.pm This functionality was renamed to import_page() some time ago. Simply rename any call to "importpage" to "import_page". A warning message is currently given. importpage is scheduled to be removed on or after August, 2019. [Removed November, 2019] pdfile method in Annotation.pm This functionality was renamed to pdf_file(). Simply rename any call to "pdfile" to "pdf_file". pdfile is scheduled to be removed on or after November, 2019. [Removed November, 2019] spline method in Content.pm This functionality was renamed to qbspline() [quadratic Bezier spline]. Simply rename any call to "spline" to "qbspline". spline is scheduled to be removed on or after June, 2020. [Removed November, 2020] pdfile method in Outline.pm, NamedDestination.pm This functionality was renamed to pdf_file(). Simply rename any call to "pdfile" to "pdf_file". pdfile is scheduled to be removed on or after October, 2020. [Removed November, 2020] -slant option in Synfont.pm This option was renamed to -condense, as it is the factor to condense (multiply width by < 1) or expand (multiply width by > 1) text characters. Use "-condense" instead. -slant is scheduled to be removed on or after January, 2021. [Removed February, 2021] lead() method in Content.pm Use leading() instead. lead is scheduled to be removed on or after March, 2023. Notice that the associated global variable 'lead' has also been changed to 'leading'. [Removed September, 2023] textlead() method in Lite.pm Use textleading() instead. textlead is scheduled to be removed on or after March, 2023. [Removed September, 2023] elementsof() method in a number of Basic/PDF/ routines This method was renamed to elements(). elementsof() is scheduled to be removed on or after August, 2021. [Removed September, 2023] removeobj() method in Array.pm Not used internally and not documented. To be removed on or after August, 2021. Replaced by remove_element(). [Removed September, 2023] get_*box() methods in Page.pm now *box() methods (both $pdf and $page) with no arguments return the global and current page bounding boxes (media, crop, bleed, trim, art). The get routines are now obsolete, and may be removed on or after August, 2021. [Removed October, 2023] PDF-Builder-3.026/INFO/Changes-ver_20000644000000000000000000041370514263571106015277 0ustar rootrootChange log for PDF::API2 version 2.xxx (predecessor to PDF::Builder) {{$NEXT}} - [GH-44] The X coordinate returned by $text->position() or (deprecated) $text->textpos() was incorrect when read after being set twice (report by Johan Vromans). - [GH-45] Renamed transform's "relative" option to "repeat" and fixed the documentation describing what it does (report by Johan Vromans). - Minor doc clarifications and improved error messages. 2.043 2021-12-07 - Restores backward compatibility (with a warning) when the deprecated $pdf->pageLabel is given an invalid -style option starting with "a" or "r" (report by Johan Vromans). - Fix incorrect default in documentation for annotation borders (report and patch by Johan Vromans). 2.042 2021-09-16 - This release includes many changes to method names, options, and documentation aimed at improving approachability, but existing code should continue to work. See the new Backward Compatibility section in the main PDF::API2 documentation for details about deprecation timelines and a suggested workflow for handling upgrades. See the new Migration section for a consolidated list of deprecated methods/options and their replacements. - Renamed several methods in the PDF::API2 base class: - end -> close - open_scalar -> from_string - stringify -> to_string - pages -> page_count - importPageIntoForm -> embed_page - isEncrypted -> is_encrypted - xmpMetadata -> xml_metadata - outlines -> outline * PDF::Builder: offer new names while keeping old (as aliases) - Merged saveas into save. - Added individual accessors for PDF metadata (title, author, producer, etc.). Replaced info and infoMetaAttributes with info_metadata for custom metadata. - Renamed the following methods in the PDF::API2::Page class: - gfx -> graphics - rotate -> rotation - Added $page->boundaries() and $pdf->default_page_boundaries() to replace the separate methods for the various page boundaries. The supported arguments are slightly different; some edge cases have been removed and new options have been added. See below and the PDF::API2::Page documentation for details. - Added $page->size() and $pdf->default_page_size() as a shortcut for setting the media box. - Both $page->size() and $page->boundaries() (and their $pdf default equivalents) now accept "WxH" page sizes in inches (e.g. 11x17 or 8.5x11). This does not apply to the deprecated versions of these methods. - Both $page->size() and $page->boundaries() (and their $pdf default equivalents) now accept a single number for page boundaries other than the media box, representing an amount in points to shrink the next larger box. This does not apply to the deprecated versions of these methods. - Replaced pageLabel with page_labels. The option syntax is slightly different (pass options as a hash instead of a hashref; remove hyphens from option names). - Replaced image_jpeg, image_tiff, image_pnm, image_png, image_gif, and image_gd with $pdf->image. - Replaced the individual barcode methods with $pdf->barcode, which is fully documented and includes reasonable defaults based on the chosen barcode format. - Improved spacing between barcodes and labels when both bar_extend (formerly -lmzn) and font_size (formerly -fnsz) are set and the font size is larger than the bar extension. - Replaced corefont, ttfont, psfont, and bdfont with $pdf->font. Unlike corefont, font requires the exact name of one of the standard fonts. Kerning is on by default (vs. off by default in the type-specific methods). - Renamed synfont to synthetic_font. Renamed and documented the options. The new hscale option (formerly -slant) now takes a percentage (100 = no change, vs. 1 = no change for -slant) to match the hscale method in Content. The new "bold" option is in thousandths of a text unit, vs. hundredths for "-bold", so multiply the old value by 10 when migrating. - Replaced the individual colorspace methods with $pdf->colorspace. Added documentation and examples for the various colorspace types except for the former colorspace_hue, because I couldn't find the standard that it implements (if one exists). - Renamed several methods in PDF::API2::Content: - linewidth -> line_width - linecap -> line_cap - linejoin -> line_join - miterlimit -> miter_limit - flatness -> flatness_tolerance - endpath -> end - rectxy -> rectangle - fillstroke -> paint - charspace -> character_spacing - wordspace -> word_spacing - nl -> crlf - advancewidth -> text_width * PDF::Builder: accept new names but keep old as aliases - In PDF::API2::Content, replaced image and formimage with object. Added a $page->object() convenience method that is equivalent to $page->graphics->object(). - In PDF::API2::Content, merged text_center and text_right into text. Use the "align" option to set alignment to "center" or "right". - In PDF::API2::Content, merged paragraphs into paragraph. - In PDF::API2::Content, deprecated poly and added polyline. poly was the only path-drawing method that took a starting position as its first two arguments. These should be passed to a move call instead, with the remaining arguments passed to the new polyline method. - In PDF::API2::Content, added position, which combines the functionality of distance and textpos2 (which was undocumented). Deprecated textpos, which attempted to return the position of the "cursor" after taking into account coordinate transformations. textpos2 and the new position method return the text position before any coordinate transformations are applied, which is consistent with how the other methods in this class behave. - In PDF::API2::Content, deprecated bogen. Recreate using arc, if feasible. If not, I'm likely to leave the code in place indefinitely as an undocumented method. PDF::Builder: leave bogen alone - In PDF::API2::Content, deprecated cr. Replace with either position (if called with arguments) or crlf (if called without arguments). - Tentatively deprecated $pdf->cjkfont. If you're successfully using this method for CJK font support, read PDF::API2::Resource::CIDFont::CJKFont and contact me to discuss your use case. PDF::Builder: suggest using ttfont instead - Tentatively deprecated $pdf->unifont. If you're successfully using this method for Unicode support, please contact me to discuss your use case. PDF::Builder: suggest using ttfont instead - Replaced $pdf->preferences() with separate page_mode, page_layout, viewer_preferences, and open_action methods, all of which are now fully documented. - Added font_path and set_font_path accessors for the font search path (the list of directories searched when a font name is included without its full path). Renamed addFontDirs to add_to_font_path. - Removed C:/WinNT/Fonts from the default font search path. PDF::Builder: add C:/Windows/Fonts, leave in /WinNT/Fonts - Named Destinations are now fully documented, with updated method names and arguments. - Outlines are now fully documented, with additional methods for examining and modifying the outline tree. Existing method names and arguments have been updated to match those used in Named Destinations. Various bugs have been fixed when reading or modifying outlines in existing PDFs. - Updated annotation documentation. Revised methods and arguments to match those used in Named Destinations and Outlines. - A PDF version number specified in the document catalog is now respected by $pdf->version(). - Fixed space calculation between words in justified text (report and fix by Vladislav Glinsky). 2.041 2021-07-27 - Renamed openpage to open_page in PDF::API2. The old name is deprecated. - [RT #136648] Fix when writing PDFs containing cross-reference streams (reported by Chris Papademetrious, fix by Vadim Repin from RT #117184). - [RT #44877] GIFs containing comments or plain-text representations will no longer result in an error (reported by Chris Czub). - [RT #132844] Fix corruption when a PGM image is included (reported by Jeff Ratcliffe, fix by Vadim Repin). - Expand PNM support to include all image types. Already in PDF::Builder. - [RT #131657] Disable recursion warnings while releasing (destroying) PDF indirect objects, which can be highly-interconnected (reported by Leon Winter). - [RT #41971] Fix when attempting to read an existing PDF's outlines (reported by Damyan Ivanov, fix based on a patch by Vadim Repin). Already in PDF::Builder. 2.040 2021-04-13 - Fix open() followed by stringify() resulting in a corrupt (mostly-empty) PDF, which was broken by changes in 2.039 (reported by Gareth Tunley). (NOT fixed in Builder, code looks like something similiar had been done some time ago, and new t-tests run fine on existing Builder code) - [RT #134993] Calling open($filename) followed by saveas($same_filename) instead of update() resulted in a corrupt PDF in 2.039, which no longer reads the entire file into memory on open (reported by Marco Pessotto). (NOT yet implemented, sounds like RT #113516 enhancement of not reading whole file had a bug). - [RT #134957] Fix encoding of \n in a PDF string containing non-printable characters (reported by Stuart Henderson). - [RT #133131] Fix endianness of 64-bit numbers in cross-reference stream widths array (reported by Christopher Papademetrious, fix by Vadim Repin). 2.039 2021-03-04 - PDF::API2->open($filename) no longer reads the entire file into memory before working on it, instead reading from the file as needed. This results in a substantial reduction in memory usage and start-up time for large PDF files, particularly in cases where the calling script doesn't need to access all of the contents of the PDF. (RT 113516) (not yet implemented in PDF::Builder, want to gain some experience with PDF::API2 first. if implement, also fix introduced bug 134993) - PDF files containing cross-reference streams can now be modified and saved normally. Previously, they were read-only. (not yet done in PDF::Builder) - $text->paragraph(...) and $text->paragraphs(...) (formerly "section") are no longer undocumented and experimental. If you were previously using them at your own risk, note that "-spillover" is no longer an option (text will always wrap inside the specified width if possible). In addition, paragraphs(...) no longer collapses consecutive newlines. (still 'section' with 'paragraphs' alias in PDF::Builder, -spillover still in Builder) - [RT #98546] There is now an -align-last option for justified text to specify how the final line should be justified. Left is still the default. (still -last_align in PDF::Builder) - Added a -compress option (on by default) to PDF::API2->new(), open(), and open_scalar(). If disabled, most streams won't be compressed, which can simplify debugging. (slightly different syntax in PDF::Builder) - Code in the PDF::API2::Basic::PDF namespace was originally licensed under the Perl Artistic License, which has been determined to not be (L)GPL-compatible. Martin Hosken has graciously granted an MIT license for use of his code contained in PDF::API2, so the distribution may now be used solely under the terms of the LGPL rather than requiring both licenses simultaneously. Many thanks to Petr Pisar for his help in working through the licensing issues. (slightly different wording in PDF::Builder, approved by Pisar and Hoskens) - Renamed $text->lead(...) to $text->leading(...). The old name is deprecated but will continue to work. If you're modifying PDF::API2 objects by editing their hash values instead of using these accessors, you'll need to update your code. (in PDF::Builder) - Added a -compress option (on by default) to PDF::API2->new(), open(), and open_scalar(). If disabled, most streams won't be compressed, which can simplify debugging. (new() long in PDF::Builder, may need to add to open() and open_scalar() [ ]) - add missing trailing commas in Content.pm (not done in PDF::Builder) - update code style in Resource/Font/CoreFont.pm (not worth doing in PDF::Builder) - expression form of grep changed in Basic/PDF/File.pm 2.038 2020-08-31 - Use libpng.a PNG processing to speed up (already in PDF::Builder) 2.037 2020-02-05 - Allow PDF 2.0 files to be opened. [already in PDF::Builder] - [RT #131147] Ignore dictionary entries with null values (reported by Klaus Ethgen, fix by Vadim Repin). [already in PDF::Builder] 2.036 2019-09-17 - Eliminate another uninitialized value warning in BaseFont.pm. 2.035 2019-08-09 - The bounding box methods (mediabox, cropbox, bleedbox, trimbox, and artbox) now return their values when called without arguments. The get_[media|crop|bleed|trim|art]box page methods have been deprecated since they're now redundant, but they continue to work. - [RT #130074] Remove unneeded (and newly-broken) calls to is_utf8 in Annotation.pm and NamedDestination.pm (reported by Mathieu Arnold). - Eliminate some uninitialized value warnings in BaseFont.pm 2.034 2019-06-29 - support last 6 years of Perl initial (.0) releases, plus one major release, which is currently 5.18 as the minimum. - Add support for cross-reference streams using 64-bit field widths. - When the utf8 flag is set for a PDF string, automatically encode it as UCS-16BE instead of requiring a separate flag to be set in the PDF object. This resolves [RT #33497] and [RT #117031] in addition to making the code easier to maintain. - [RT #126274] Fix alignment when using UniFont with text_center or text_right when all characters are in the same block. - [RT #121911] Fix adding pages to a document structure with nested Pages elements. This included a fairly substantial rewrite of the relevant code, so please report any new bugs related to adding pages (report and troubleshooting by Vadim Repin). - Renamed pdfile() to pdf_file() in PDF::API2::Annotation and PDF::API2::Outline. The old name continues to work, but is deprecated. - Use confess instead of die (Carp.pm) in FontFile.pm - (perlcritic) Add explicit return statements to all routines, including those that have a return value such as "$self;" and all that return nothing. - (perlcritic) API2.pm stringify() make sure return value has at least empty string for content. Several cases of -unicodemap check for true, not 1. - (perlcritic) Content.pm outobjdeep() check -docompress is true, not 1. bogen() clarify move, larger, reverse parameter defaults. isvirtual(), ' apiistext' check for true, not 1. - Add additional author and license information to lib/PDF/API2.pm 2.033 2017-07-10 - [RT #122371] Remove a couple of improperly-placed weaken statements (reported by Phil Perry). - [RT #122372] Fix weakening when a page is added to the end of a multiple page document (reported by Phil Perry). - Fix Bank Gothic core font (reported by Phil Perry). 2.032 2017-07-06 - PDF::API2 has many circular references, and the end() method doesn't clear them all, so memory is leaked. This release uses Scalar::Util's weaken() function to improve garbage collection. A significant number of circular references have been weakened, though many likely still remain. - [RT #120756] Eliminate a warning for an ambiguous call to CORE::open (first reported by Abdelbaki Brahmia). - $text->text_justified() and $text->text_fill_justified() now adjust the space between words rather than stretching individual characters in order to get the text to fit. [IMPLEMENTED IN A DIFFERENT MANNER for PDF::API2 v3 and PDF::Builder] - [RT #120397] Indirect references and indirect objects can have comments embedded in their whitespace, and their object number and generation may be split across multiple lines, which may not all be buffered (reported by SPROUT). - [RT #120450] Fix PDF::API2->open($filename)->stringify() (reported by SPROUT). - Fix an off-by-one error when calculating text width while charspace is non-zero. - [RT #120048] Fix PDF::API2->synfont() (broken in 2.029, fixed by Vadim Repin) and add basic testing. 2.031 2017-01-26 - Fix use of cache files when reading streams: temp files will now be used any time a stream is larger than 16MB (by default). Formerly, due to a bug, they would only be created when a 4kB chunk of a stream increased to 16kB or more after being decompressed. - Numbers, booleans, and null values can now be read from object streams. - Update to [RT #113290]: Objects inside a large object stream are now read without loading the entire object stream into memory. - DEPRECATION: The low-level new_api methods have been deprecated in favor of calling new directly. If your code uses new_api($api2, ...), replace it with new($api2->{'pdf'}, ...). - [RT #118352] Don't crash when adding an annotation to a page that has an existing annotations array stored as an indirect object (reported by Johan Vromans). - [RT #118717] Die with an informative error if a file can't be opened during open() or saveas() (reported by Johan Vromans). 2.030 2016-10-13 - Fix a font naming issue introduced while satisfying Perl::Critic. 2.029 2016-10-10 - [RT #113293] Files with cross-reference streams weren't correctly setting the max object number (report and troubleshooting by Marco Pessotto). - Handle TIFF images with strips that are wider than the image (report and patch by Jeffrey Ratcliffe). - [RT #98574] Increase test coverage of PDF::API2::Content (tests by Phil Perry). - A bunch of code cleanup and documentation updates by Paul Cochrane. - Add a missing prereq on Win32 systems (patch by Michiel Beijen). - [RT #113514, #98552] Fix the dash() and renderingintent() methods in ExtGState (reported by Vadim Repin and Phil Perry). - Satisfy all Perl::Critic severity 5 policies. - [RT #117940] Allow PNG, GIF, and PNM files to be opened from filehandles in addition to filenames (patch by Johan Vromans). - [RT #33970] Fail fast when a referenced file can't be opened (requested by Barrie Slaymaker a mere 8.5 years ago). - Add -simplex, -duplexfliplongedge and -duplexflipshortedge as options to $pdf->preferences() (requested by Doug Poulin). 2.028 2016-06-08 - [RT #113290] Fix for reading objects inside an object stream in a large PDF (patch by Marco Pessotto). - Eliminate an infinite loop when reading a corrupt dictionary. 2.027 2016-03-11 - This release contains seven fixes for parsing PDFs. They mostly affect files using cross-reference streams, which were first supported in the previous release. Thanks to Marco Pessotto and Stuart Henderson for their help identifying and troubleshooting bugs. - Added contrib/pdf-debug.pl to help track down issues related to opening and parsing PDFs. 2.026 2016-02-24 - [RT #48683] Add support for PDFs with cross-reference streams and object streams (patch by Don Huettl of Grant Street Group). - [RT #107333] Accept an empty string as a valid Name, per PDF spec 1.7 section 7.3.5 (patch by Mark Balitsky). - [RT #98551] Rename aliases 2A, 4A, 2B, and 4B to 2A0, 4A0, 2B0, and 4B0. The old names will continue to work, but are now undocumented (patch by Phil Perry). - Add -mils and -color as options for barcodes. Reset linedash so that barcodes are always solid lines (patch by Erelen). - [RT #98549] Rename meterlimit to miterlimit (patch by Phil Perry). - [RT #98534] Rename hspace to hscale (patch by Phil Perry). - Fixed an infinite loop when RunLengthDecode is used for output. - [RT #65582] Fix embedding of OpenType fonts (fix by Simon Cozens). - [RT #67767] Allow an empty page to be imported into a PDF using importPageIntoForm (reported by Antti Lankila). - [RT #66341] Various fixes for ASCII85Decode and LZWDecode. 2.025 2015-09-23 - The previous release included a patch that broke compatibility with Perl 5.8.x. The minimum supported version is now Perl 5.8.5, and there is a .perl-version file to facilitate testing using plenv. 2.024 2015-09-18 - [RT #104133] Include all bounding boxes when importing a page (patch by Don Huettl of Grant Street Group). - Barcodes now take an optional -caption argument that will be printed beneath the barcode. This can replace or be used in conjunction with the text representation of the barcode (requested by Gareth Tunley). - [RT #105581] Calls to width() in BaseFont are now significantly faster (patch by Dmitri Tikhonov). 2.023 2014-09-12 - The fix for [RT #69503] broke a previously-working case where a page object could be passed (and was expected). The -firstpage option now accepts a page object or a page number. Thanks to Marco Pessotto for the bug report and test. 2.022 2014-07-04 - Added $pdf->version() get/set method. When opening an existing PDF, the existing version number will now be retained. - Renamed the following in PDF::API2: - importpage to import_page - openScalar to open_scalar The old names are deprecated. - [RT #69503] Fix the -firstpage option to $pdf->preferences() so that it doesn't always lead to a crash (reported by Dietrich Streifert). - [RT #47974] Accept malformed xref subsections (with a warning) that have extraneous spaces on the first line (reported by Abhinav Kaushik). - [RT #94505] For Code128 barcodes, the initial character set is now optional (defaults to B or C depending on the content to be encoded). The initial character set can be passed as a capital letter, and the program will die if an invalid character set is requested (requested by Andrea Nall). - Interleaved 2 of 5 barcodes now prepend a zero when an odd number of digits is specified, which is standard behavior. Previously, a zero was appended instead. - $page->rotate(0) now sets rotation to 0 degrees rather than deleting an existing page rotation command. Page rotation is inherited, so this is necessary to undo any inherited page rotation. - Fix: Attempts to use EAN-128 barcodes resulted in an error. - Add a more informative error when text() is called without first setting a font(), and when font() is called without including a font size. 2.021 2014-02-20 - Fixed numerous bugs in the string parsing code, including the one reported in [RT #63918] by Frank Doepper. - [RT #41049] Rewrote literal string parsing to prevent a stack overflow due to an inefficient regex (reported by Sergei Fetisov). - [RT #91822] Fix compression of GIF images to ensure that output codes don't exceed 12 bits (reported by Vadim Repin). - The RunLengthDecode filter didn't actually work. Its code has been rewritten and now passes basic encoding and decoding tests. - Fix Code128 barcode switching from Code C to Code B in certain cases (reported by Doru Petrescu). 2.020 2013-01-20 - Give a more informative error message when a PDF file using a cross-reference stream is encountered. The Known Issues section of the documentation includes pointers on how to add support in case someone else can get to this before I do. - Text using TrueType fonts is now searchable again. In version 0.61, an undocumented -unicodemap option was added to nearly all of the font resource methods, which only included a ToUnicode CMap if it was set (and it's required in order for PDF readers to be able to identify individual characters if BaseEncoding isn't present, which it isn't for TrueType fonts). I've left the -unicodemap option in place, and it's still undocumented (except here), but it's now on by default. Call $pdf->ttfont($fontfile, -unicodemap => 0) if you want to disable it for performance or file size reasons. - Add a note to the stringify method's documentation saying that it's a destructive operation. - The various filter types have their own classes in the PDF::API2::Basic::PDF::Filter namespace now, rather than having all of the packages in Filter.pm. - To facilitate testing and ensure that identically-generated PDFs have identical output in Perl 5.17.5 or later, PDF dictionary keys are now sorted during output. 2.019 2011-03-10 - [RT #66167] Fix a typo in the require statement for code128 barcodes (TC Kuan). - Numerous modules are now only loaded when they're needed, which should help speed up the load time and reduce the memory footprint. - Test coverage is up to about 45% of the codebase. 2.018 2011-02-23 - The tests in 2.017 exposed a floating point issue where some computers give more trailing zeros than others. It doesn't affect the output, but it does break the tests on those computers, since the PDFs are slightly different. This version modifies the float() method to remove trailing zeros, which should fix the test breakage and give consistent PDFs. 2.017 2011-02-22 - The DejaVu fonts have been removed from the distribution, since they were only used by one example script. If you need them for your project, you can download them from http://dejavu-fonts.org - Fix: Content->bogen() didn't behave as documented if $move was set (it started drawing from the center of the circle rather than [x1, y1]). - The undocumented nettfont method has been removed, along with the supporting PDF::API2::Resource::Font::neTrueType module. - The undocumented save_xml method has been removed, along with the supporting functions in PDF::API2::Basic::*. - The undocumented textstate2 method has been removed from PDF::API2::Content. - [RT #58386] Fix create_egs call in Lite.pm (J Greely) - [RT #62922] Fix string interpolation in pdf-merge.pl (Guillaume Rousse and Jerome Quelin) - [RT #65458] Fix an error in the synopsis (Frank Ammeter) - [RT #66054] Fix rename of .cmap files so that they actually work now. (cnhacktnt) - The test suite has grown to nearly 200 tests, covering about 40% of the codebase. There's still plenty of room for improvement. 2.016 2011-01-24 - New Maintainer: Steve Simms (http://deefs.net) - This release jumps from version 0.73 to 2.016 in order to provide a consistent version number across all modules in the distribution without breaking any existing code or going backwards. - Lots of updates to the documentation, particularly in PDF::API2::Content, which was almost completely rewritten and reorganized. - Font::TTF has been added as a dependency instead of being embedded in the distribution. - Everything that worked in 0.73 should work unmodified in 2.016, at least if it used the published documentation, and most everything should still work even if it didn't. - PDF::API2 used to read and parse three text files, one of which was over 500kB, on every load. These files have been turned into modules, and while I haven't done any performance testing, I'd have a hard time believing that it isn't faster now. - There are now a few tests forming the beginning of a test suite. Contributions of tests would be most welcome! ====================================================================== Changes below this point are from PDF::API2 0.73 and earlier, generated from the CVS logs. ====================================================================== 2009-03-20 09:54 fredo * lib/PDF/API2/Resource/CIDFont/TrueType.pm: rt.cpan.org #42524: strange space size after update on 0.72.003 from 0.71 2008-11-20 19:51 fredo * lib/PDF/API2/Resource/CIDFont/TrueType.pm: perf henning.just@datagraf.dk 2008-11-05 00:05 fredo * lib/PDF/API2/Version.pm: *** empty log message *** 2008-11-04 23:54 fredo * lib/PDF/API2/Basic/PDF/Dict.pm lib/PDF/API2/Resource/Font.pm: fixed [rt.cpan.org #40648] Unicode text prints text on top of text before it 2008-08-10 15:06 fredo * examples/021_synfonts: added relative use lib 2008-08-10 14:57 fredo * lib/PDF/API2/Version.pm: *** empty log message *** 2008-08-10 14:43 fredo * examples/021_syntruefonts lib/PDF/API2/Resource/Font/SynFont.pm lib/PDF/API2/fonts/AUTHORS.txt lib/PDF/API2/fonts/DejaVuSans-Bold.ttf lib/PDF/API2/fonts/DejaVuSans-BoldOblique.ttf lib/PDF/API2/fonts/DejaVuSans-ExtraLight.ttf lib/PDF/API2/fonts/DejaVuSans-Oblique.ttf lib/PDF/API2/fonts/DejaVuSans.ttf lib/PDF/API2/fonts/DejaVuSansCondensed-Bold.ttf lib/PDF/API2/fonts/DejaVuSansCondensed-BoldOblique.ttf lib/PDF/API2/fonts/DejaVuSansCondensed-Oblique.ttf lib/PDF/API2/fonts/DejaVuSansCondensed.ttf lib/PDF/API2/fonts/DejaVuSansMono-Bold.ttf lib/PDF/API2/fonts/DejaVuSansMono-BoldOblique.ttf lib/PDF/API2/fonts/DejaVuSansMono-Oblique.ttf lib/PDF/API2/fonts/DejaVuSansMono.ttf lib/PDF/API2/fonts/DejaVuSerif-Bold.ttf lib/PDF/API2/fonts/DejaVuSerif-BoldItalic.ttf lib/PDF/API2/fonts/DejaVuSerif-Italic.ttf lib/PDF/API2/fonts/DejaVuSerif.ttf lib/PDF/API2/fonts/DejaVuSerifCondensed-Bold.ttf lib/PDF/API2/fonts/DejaVuSerifCondensed-BoldItalic.ttf lib/PDF/API2/fonts/DejaVuSerifCondensed-Italic.ttf lib/PDF/API2/fonts/DejaVuSerifCondensed.ttf lib/PDF/API2/fonts/LICENSE.txt lib/PDF/API2/fonts/NEWS.txt lib/PDF/API2/fonts/README.txt lib/PDF/API2/fonts/langcover.txt lib/PDF/API2/fonts/status.txt lib/PDF/API2/fonts/unicover.txt: to 2.25 2008-03-10 21:38 fredo * examples/060_transparency: genesis 2008-03-10 21:23 fredo * examples/012_pages: genesis 2008-02-15 15:22 fredo * lib/PDF/API2/Content.pm: added -spillover param to paragraph and sub-methods 2008-01-18 00:11 fredo * lib/PDF/API2.pm: fixed catalog update and infohash utf16 from http://bugs.debian.org/461167 2008-01-04 08:10 fredo * lib/PDF/API2/Resource/Font/neTrueType.pm: flag fixes 2008-01-04 08:08 fredo * lib/PDF/API2/Resource/CIDFont/TrueType/FontFile.pm: apiname fix 2007-11-16 19:30 fredo * lib/PDF/API2.pm: added -noembed option 2007-11-16 19:27 fredo * lib/PDF/API2/Resource/CIDFont/TrueType.pm lib/PDF/API2/Resource/CIDFont/TrueType/FontFile.pm: fixed -noembed option 2007-11-16 19:03 fredo * MANIFEST: added non-embedded truetype 2007-11-14 23:01 fredo * lib/PDF/API2.pm: fixed relative page insert 2007-11-14 22:49 fredo * lib/PDF/API2.pm: added non-embedded truetype font (8-bit only) support 2007-11-14 22:47 fredo * lib/PDF/API2/Resource/Font/neTrueType.pm: genesis 2007-11-14 20:46 fredo * lib/PDF/API2/Resource/CIDFont/TrueType/FontFile.pm: added noembed option 2007-11-03 20:31 fredo * lib/PDF/API2/Basic/PDF/File.pm: make startxref detection more tolerant 2007-10-23 07:49 fredo * MANIFEST: added 022_truefonts_diacrits_utf8 2007-10-23 07:48 fredo * examples/022_truefonts_diacrits_utf8: genesis 2007-10-23 07:46 fredo * examples/020_textunderline: new 2007-10-23 07:45 fredo * lib/PDF/API2/Resource/CIDFont/TrueType.pm: fixed width encoding for wrong advance codes 2007-10-16 20:08 fredo * lib/PDF/API2/Resource/BaseFont.pm: changed undef safeguards for wx* methods 2007-10-10 06:18 fredo * lib/PDF/API2/Content.pm lib/PDF/API2/Resource/BaseFont.pm lib/PDF/API2/Version.pm: fixed noisy undef handling of isvirtual 2007-10-02 19:59 fredo * lib/PDF/API2/Annotation.pm: added movie annotation 2007-09-26 19:50 fredo * lib/PDF/API2/Basic/PDF/File.pm: make trailer detection more tolerant for reported ghostscript and swets formats 2007-09-18 22:29 fredo * lib/PDF/API2.pm: added -printscalingnone option 2007-09-17 16:03 fredo * lib/PDF/API2/Resource/XObject/Image/TIFF.pm: update docs for tiffTag 2007-09-14 15:36 fredo * lib/PDF/API2/Resource/XObject/Image/TIFF.pm: also read Tiff Tag 296 and make it available as resUnit 2007-08-27 20:06 fredo * lib/PDF/API2/Basic/TTF/Cmap.pm: updated ms_table election algo to support newer apple and m$ unicode 3.1+ glyph cmaps 2007-08-07 20:40 fredo * examples/020_corefonts: added use lib 2007-08-07 20:23 fredo * lib/PDF/API2/Content.pm: added wantarray choice for paragraph, 2007-08-01 23:12 fredo * lib/PDF/API2.pm: fix BOM in info strings 2007-07-01 20:32 fredo * lib/PDF/API2/fonts/DejaVuSerif-BoldOblique.ttf lib/PDF/API2/fonts/DejaVuSerif-Oblique.ttf lib/PDF/API2/fonts/DejaVuSerifCondensed-BoldOblique.ttf lib/PDF/API2/fonts/DejaVuSerifCondensed-Oblique.ttf: sync with dejavu 2.18 2007-07-01 20:30 fredo * lib/PDF/API2/fonts/AUTHORS.txt lib/PDF/API2/fonts/DejaVuSans-Bold.ttf lib/PDF/API2/fonts/DejaVuSans-BoldOblique.ttf lib/PDF/API2/fonts/DejaVuSans-ExtraLight.ttf lib/PDF/API2/fonts/DejaVuSans-Oblique.ttf lib/PDF/API2/fonts/DejaVuSans.ttf lib/PDF/API2/fonts/DejaVuSansCondensed-Bold.ttf lib/PDF/API2/fonts/DejaVuSansCondensed-BoldOblique.ttf lib/PDF/API2/fonts/DejaVuSansCondensed-Oblique.ttf lib/PDF/API2/fonts/DejaVuSansCondensed.ttf lib/PDF/API2/fonts/DejaVuSansMono-Bold.ttf lib/PDF/API2/fonts/DejaVuSansMono-BoldOblique.ttf lib/PDF/API2/fonts/DejaVuSansMono-Oblique.ttf lib/PDF/API2/fonts/DejaVuSansMono.ttf lib/PDF/API2/fonts/DejaVuSerif-Bold.ttf lib/PDF/API2/fonts/DejaVuSerif-BoldItalic.ttf lib/PDF/API2/fonts/DejaVuSerif-BoldOblique.ttf lib/PDF/API2/fonts/DejaVuSerif-Italic.ttf lib/PDF/API2/fonts/DejaVuSerif-Oblique.ttf lib/PDF/API2/fonts/DejaVuSerif.ttf lib/PDF/API2/fonts/DejaVuSerifCondensed-Bold.ttf lib/PDF/API2/fonts/DejaVuSerifCondensed-BoldItalic.ttf lib/PDF/API2/fonts/DejaVuSerifCondensed-BoldOblique.ttf lib/PDF/API2/fonts/DejaVuSerifCondensed-Italic.ttf lib/PDF/API2/fonts/DejaVuSerifCondensed-Oblique.ttf lib/PDF/API2/fonts/DejaVuSerifCondensed.ttf lib/PDF/API2/fonts/NEWS.txt lib/PDF/API2/fonts/README.txt lib/PDF/API2/fonts/langcover.txt lib/PDF/API2/fonts/status.txt lib/PDF/API2/fonts/unicover.txt: avu 2.18 2007-06-27 20:54 fredo * lib/PDF/API2/Resource/Font/Postscript.pm: fix exporter warnings of IO::File 2007-06-23 09:48 fredo * contrib/text2pdf.pl: added contributor email 2007-06-23 09:43 fredo * MANIFEST: added text2pdf.pl 2007-06-23 09:42 fredo * contrib/text2pdf.pl: genesis from contribution 2007-06-07 10:43 fredo * lib/PDF/API2/Basic/PDF/File.pm: fixed %%EOF/startxref detection to be done in chunks 2007-05-27 09:46 fredo * lib/PDF/API2/Basic/PDF/File.pm: preparations for abbyy finereader fix 2007-05-24 19:29 fredo * lib/PDF/API2/Resource/XObject/Image/PNM.pm: fixed pnm bitmap decoding 2007-05-16 21:45 fredo * lib/PDF/API2.pm: fixed importpage doku bug http://rt.cpan.org/Ticket/Display.html?id=27152 2007-05-10 23:38 fredo * lib/PDF/API2.pm: added note on importintoform and importpage for existing pdf-file 2007-05-10 06:44 fredo * lib/PDF/API2/Basic/PDF/Pages.pm: fixed page insert with upstream text-pdf 0.29a version 2007-05-08 18:32 fredo * lib/PDF/API2.pm lib/PDF/API2/Content.pm lib/PDF/API2/Lite.pm lib/PDF/API2/Page.pm lib/PDF/API2/Resource/XObject/Form/Hybrid.pm: renamed compress to compressFlate 2007-05-08 18:11 fredo * lib/PDF/API2/Content.pm: fixed bogen 2007-05-08 17:58 fredo * MANIFEST: removed changelog 2007-05-07 20:33 fredo * lib/PDF/API2.pm: fix tounicode option 2007-05-07 20:31 fredo * lib/PDF/API2/Resource/CIDFont/TrueType/FontFile.pm: fix subsetting 2007-04-25 18:04 fredo * lib/PDF/API2/Version.pm: tag release 0.60 2007-04-25 17:58 fredo * lib/PDF/API2/Basic/TTF/Name.pm: added upstream fix for 5.8.7 bugs 2007-04-18 05:26 fredo * lib/PDF/API2/Resource/Font/SynFont.pm: fixed unicode caos handling for some broken fonts having no unicode for a glyph 2007-04-07 10:28 fredo * examples/023_cjkfonts: added lorem ipsum page 2007-04-07 10:26 fredo * examples/022_truefonts: added lorem ipsum page 2007-04-07 10:25 fredo * lib/PDF/API2/Resource/BaseFont.pm: fixed fix for wxByGlyph not honoring cidfont width arrays 2007-04-07 09:51 fredo * lib/PDF/API2/Resource/BaseFont.pm: fix for wxByGlyph not honoring cidfont width arrays 2007-03-17 22:41 fredo * Makefile.PL: fixed version print 2007-03-17 20:38 fredo * lib/PDF/API2/IOString.pm lib/PDF/API2/Resource/CIDFont.pm lib/PDF/API2/Resource/CIDFont/CJKFont.pm lib/PDF/API2/Resource/CIDFont/TrueType.pm lib/PDF/API2/Resource/CIDFont/TrueType/FontFile.pm lib/PDF/API2/Resource/XObject/Image/JPEG.pm lib/PDF/API2/Resource/XObject/Image/TIFF.pm: replaced IOString dep. with scalar IO. 2007-03-17 20:15 fredo * lib/PDF/API2/Version.pm: release sync 2007-03-17 20:07 fredo * lib/PDF/API2.pm: fixed open to CORE::open 2007-03-16 15:48 fredo * lib/PDF/API2/Version.pm: release sync 2007-03-16 15:39 fredo * make_release.pl: fixed build/release versioning 2007-03-16 15:35 fredo * lib/PDF/API2/fonts/AUTHORS.txt lib/PDF/API2/fonts/BUGS.txt lib/PDF/API2/fonts/DejaVuSans-Bold.ttf lib/PDF/API2/fonts/DejaVuSans-BoldOblique.ttf lib/PDF/API2/fonts/DejaVuSans-ExtraLight.ttf lib/PDF/API2/fonts/DejaVuSans-Oblique.ttf lib/PDF/API2/fonts/DejaVuSans.ttf lib/PDF/API2/fonts/DejaVuSansCondensed-Bold.ttf lib/PDF/API2/fonts/DejaVuSansCondensed-BoldOblique.ttf lib/PDF/API2/fonts/DejaVuSansCondensed-Oblique.ttf lib/PDF/API2/fonts/DejaVuSansCondensed.ttf lib/PDF/API2/fonts/DejaVuSansMono-Bold.ttf lib/PDF/API2/fonts/DejaVuSansMono-BoldOblique.ttf lib/PDF/API2/fonts/DejaVuSansMono-Oblique.ttf lib/PDF/API2/fonts/DejaVuSansMono.ttf lib/PDF/API2/fonts/DejaVuSerif-Bold.ttf lib/PDF/API2/fonts/DejaVuSerif-BoldOblique.ttf lib/PDF/API2/fonts/DejaVuSerif-Oblique.ttf lib/PDF/API2/fonts/DejaVuSerif.ttf lib/PDF/API2/fonts/DejaVuSerifCondensed-Bold.ttf lib/PDF/API2/fonts/DejaVuSerifCondensed-BoldOblique.ttf lib/PDF/API2/fonts/DejaVuSerifCondensed-Oblique.ttf lib/PDF/API2/fonts/DejaVuSerifCondensed.ttf lib/PDF/API2/fonts/LICENSE.txt lib/PDF/API2/fonts/NEWS.txt lib/PDF/API2/fonts/README.txt lib/PDF/API2/fonts/langcover.txt lib/PDF/API2/fonts/status.txt lib/PDF/API2/fonts/unicover.txt: 2007-03-16 15:28 fredo * lib/PDF/API2.pm: replaced IOString dep. with scalar IO. 2007-03-16 15:27 fredo * lib/PDF/API2/Version.pm: release update 2007-03-16 15:26 fredo * lib/PDF/API2/Content.pm: removed silly grey-level handling 2007-03-16 15:25 fredo * lib/PDF/API2/Basic/PDF/File.pm: removed open_swallowed since it is not nedded anymore 2007-03-16 15:20 fredo * examples/011_open_update: genesis 2007-03-15 16:41 fredo * make_release.pl: genesis 2007-03-15 16:02 fredo * examples/040_annotation examples/050_pagelabels: update copyright 2007-03-15 15:58 fredo * examples/040_annotation: genesis 2007-03-15 14:15 fredo * lib/PDF/API2.pm: added pageLabel method 2007-03-14 19:30 fredo * lib/PDF/API2.pm: fixed -twocolumnright option typo 2007-03-12 16:24 fredo * lib/PDF/API2/Content.pm: removed eval from state calls 2007-03-10 12:18 fredo * lib/PDF/API2/Basic/PDF/Objind.pm: applied improvements to release proposed by alankila@bel.fi 2007-03-10 12:05 fredo * lib/PDF/API2/Resource/Font.pm: applied improvements to encodeByData proposed by alankila@bel.fi 2007-03-10 11:10 fredo * lib/PDF/API2/Basic/PDF/File.pm: fixed trailer detection to be more tolerant (towards pdf-spec 1.7) 2007-02-22 08:00 fredo * lib/PDF/API2.pm: changed import* methods to check its first arg -- thanks alankila2@yahoo.ca 2007-02-14 20:29 fredo * lib/PDF/API2/Resource/Font/CoreFont/courier.pm: fixed default encoding with bold 2007-02-14 11:44 fredo * lib/PDF/API2/Resource/Font/CoreFont/timesroman.pm: updated default encoding to that used by bold 2007-02-14 11:26 fredo * lib/PDF/API2/Content.pm: fixed advancewidth for space calculation 2007-02-14 11:22 fredo * lib/PDF/API2/Basic/PDF/File.pm: updated versioning to PDF::API2 2007-02-14 11:19 fredo * lib/PDF/API2/Basic/PDF/File.pm: fixed version update for interoperability 2007-01-04 17:39 fredo * lib/PDF/API2/Resource/CIDFont/TrueType/FontFile.pm: fixed [rt.cpan.org #24203] Incompatibility in Wide character handling 2007-01-04 16:33 fredo * lib/PDF/API2/Resource/BaseFont.pm: fix acro 8 fix 2007-01-04 16:02 fredo * .project lib/PDF/API2/Content.pm lib/PDF/API2/Resource/BaseFont.pm lib/PDF/API2/Resource/CIDFont.pm lib/PDF/API2/Resource/UniFont.pm: applied untested fix for acrobat 8 " TJ" bug 2006-08-14 18:11 fredo * lib/PDF/API2/Resource/BaseFont.pm: fixed wxByGlyph 2006-08-14 18:08 fredo * lib/PDF/API2/Resource/Font/Postscript.pm: moved "use io-file" to begin section 2006-08-01 19:45 fredo * MANIFEST: added dejavu fonts 2006-06-25 20:31 fredo * lib/PDF/API2/Version.pm: prepairing dejavu font inclusion 2006-06-19 19:25 fredo * lib/PDF/API2/Content.pm: fixed compress vs. Compress::ZLib subs 2006-06-19 19:22 fredo * lib/PDF/API2/Resource/CIDFont.pm: removed dup sub 2006-06-19 19:20 fredo * examples/022_truefonts: added details 2006-06-16 01:56 fredo * lib/PDF/API2/Version.pm: version 0.52 2006-06-15 21:12 fredo * examples/027_winfont: added cid map 2006-06-15 20:27 fredo * lib/PDF/API2/Basic/PDF/String.pm: modified escaped string conversion 2006-06-15 20:15 fredo * lib/PDF/API2/Basic/PDF/File.pm: beautification 2006-06-14 16:57 fredo * lib/PDF/API2/Resource/BaseFont.pm: fixed ToUnicode cmap greneration to use actual encoden rather than the default 2006-06-14 16:53 fredo * lib/PDF/API2/Resource/BaseFont.pm: fixed unicode lookup to use actual encoding rather than default 2005-11-16 02:52 fredo * META.yml Makefile.PL lib/PDF/API2/Version.pm: fix for 0.51 2005-11-02 19:21 fredo * lib/PDF/API2/Resource/CIDFont/TrueType/FontFile.pm: added kerning lookup strategy 2005-11-02 19:18 fredo * lib/PDF/API2/Page.pm: added get_(crop/bleed/trim/art)box methods 2005-10-22 21:56 fredo * lib/PDF/API2/Resource/CIDFont/TrueType/FontFile.pm: added mor agressive kerning strategy 2005-10-21 23:42 fredo * lib/PDF/API2/Basic/PDF/File.pm: speedup reading large dictionaries/structs 2005-10-21 23:42 fredo * lib/PDF/API2/IOString.pm: fixed tell tier 2005-10-21 21:52 fredo * lib/PDF/API2/Basic/PDF/File.pm: fixed readxrtr to be more strict to the latest pdf-spec 2005-10-21 21:51 fredo * lib/PDF/API2.pm: fixed proc_pages 2005-10-20 23:06 fredo * lib/PDF/API2.pm: documented '-dokern' option for ttfonts 2005-10-20 23:04 fredo * lib/PDF/API2/Resource/: CIDFont/TrueType.pm, CIDFont.pm, CIDFont/TrueType/FontFile.pm: added handling of optional kerning 2005-10-20 01:05 fredo * lib/PDF/API2/Resource/Font/Postscript.pm: silenced 'cannot parse' since it is usually no error 2005-10-19 23:23 fredo * lib/PDF/API2.pm: documented '-dokern' option for core- and psfonts 2005-10-19 21:12 fredo * lib/PDF/API2/Resource/Font/: Postscript.pm, CoreFont.pm: added handling of optional kerning 2005-10-19 21:08 fredo * lib/PDF/API2/Resource/UniFont.pm: added extended typographic text handling call 2005-10-19 21:07 fredo * lib/PDF/API2/Resource/Font.pm: added handling of composites in automap 2005-10-19 21:06 fredo * lib/PDF/API2/Resource/BaseFont.pm: added handling of kerning 2005-10-19 21:05 fredo * lib/PDF/API2/IOString.pm: ... 2005-10-19 21:04 fredo * lib/PDF/API2/Content.pm: added extended typographic text handling call 2005-10-02 01:38 fredo * lib/PDF/API2/Resource/Font/Postscript.pm: added kerning+composite parsing added nonembedding check 2005-10-02 00:41 fredo * lib/PDF/API2/Resource/Font/: BdFont.pm, CoreFont.pm, Postscript.pm: fixed font-naming race condition for multiple document updates 2005-10-02 00:30 fredo * lib/PDF/API2/Resource/CIDFont/TrueType.pm: fixed font-naming race condition for multiple document updates 2005-10-02 00:10 fredo * lib/PDF/API2/Content.pm: added more docs for textlabel 2005-09-28 19:02 fredo * lib/PDF/API2/Resource/XObject/Image/JPEG.pm: fixed iostring handling 2005-09-28 19:00 fredo * lib/PDF/API2/Resource/Font/CoreFont/courier.pm: added composites 2005-09-28 19:00 fredo * lib/PDF/API2/Resource/uniglyph.txt: added combiners 2005-09-26 22:07 fredo * lib/PDF/API2/Resource/Font/CoreFont.pm: added fontmetric stub 2005-09-26 22:06 fredo * lib/PDF/API2/Resource/Font.pm: removed composite glyphs from automap 2005-09-26 21:28 fredo * lib/PDF/API2/Resource/Font/CoreFont/courier.pm: no message 2005-09-12 18:56 fredo * lib/PDF/API2/Resource/Font/: CoreFont.pm, CoreFont/bankgothic.pm, CoreFont/courier.pm, CoreFont/courierbold.pm, CoreFont/courierboldoblique.pm, CoreFont/courieroblique.pm, CoreFont/georgia.pm, CoreFont/georgiabold.pm, CoreFont/georgiabolditalic.pm, CoreFont/georgiaitalic.pm, CoreFont/helvetica.pm, CoreFont/helveticabold.pm, CoreFont/helveticaboldoblique.pm, CoreFont/helveticaoblique.pm, CoreFont/symbol.pm, CoreFont/timesbold.pm, CoreFont/timesbolditalic.pm, CoreFont/timesitalic.pm, CoreFont/timesroman.pm, CoreFont/trebuchet.pm, CoreFont/trebuchetbold.pm, CoreFont/trebuchetbolditalic.pm, CoreFont/trebuchetitalic.pm, CoreFont/verdana.pm, CoreFont/verdanabold.pm, CoreFont/verdanabolditalic.pm, CoreFont/verdanaitalic.pm, CoreFont/webdings.pm, CoreFont/wingdings.pm, CoreFont/zapfdingbats.pm: applied mod_perl patch by Paul Schilling 2005-09-12 18:55 fredo * MANIFEST: added META.yml 2005-09-12 18:55 fredo * examples/: 020_corefonts, 022_truefonts, 023_cjkfonts, 025_unifonts, 027_winfont: various updates 2005-09-12 18:53 fredo * lib/PDF/: API2/Resource/CIDFont/TrueType.pm, API2/Basic/TTF/Cmap.pm, API2.pm: added -isocmap option 2005-09-12 18:52 fredo * lib/PDF/API2/Resource/CIDFont/TrueType/FontFile.pm: added -isocmap option; fixed cmap handling for fallback entries 2005-08-07 04:14 fredo * Makefile.PL: upd 2005-08-06 22:59 fredo * lib/PDF/API2/Page.pm: fixed anotation pdf-array again for other braindead softs 2005-06-17 21:43 fredo * lib/PDF/: API2.pm, API2/Annotation.pm, API2/Content.pm, API2/IOString.pm, API2/Lite.pm, API2/Matrix.pm, API2/NamedDestination.pm, API2/Outline.pm, API2/Outlines.pm, API2/Page.pm, API2/Resource.pm, API2/Shape.pm, API2/UniWrap.pm, API2/Util.pm, API2/Content/Text.pm, API2/Resource/BaseFont.pm, API2/Resource/CIDFont.pm, API2/Resource/ColorSpace.pm, API2/Resource/ExtGState.pm, API2/Resource/Font.pm, API2/Resource/Pattern.pm, API2/Resource/Shading.pm, API2/Resource/UniFont.pm, API2/Resource/XObject.pm, API2/Resource/CIDFont/CJKFont.pm, API2/Resource/CIDFont/TrueType.pm, API2/Resource/CIDFont/TrueType/FontFile.pm, API2/Resource/ColorSpace/DeviceN.pm, API2/Resource/ColorSpace/Indexed.pm, API2/Resource/ColorSpace/Separation.pm, API2/Resource/ColorSpace/Indexed/ACTFile.pm, API2/Resource/ColorSpace/Indexed/Hue.pm, API2/Resource/ColorSpace/Indexed/WebColor.pm, API2/Resource/Font/BdFont.pm, API2/Resource/Font/CoreFont.pm, API2/Resource/Font/Postscript.pm, API2/Resource/Font/SynFont.pm, API2/Resource/Shading/axial.pm, API2/Resource/XObject/Form.pm, API2/Resource/XObject/Image.pm, API2/Resource/XObject/Form/BarCode.pm, API2/Resource/XObject/Form/Hybrid.pm, API2/Resource/XObject/Form/BarCode/codabar.pm, API2/Resource/XObject/Form/BarCode/code128.pm, API2/Resource/XObject/Form/BarCode/code3of9.pm, API2/Resource/XObject/Form/BarCode/ean13.pm, API2/Resource/XObject/Form/BarCode/int2of5.pm, API2/Resource/XObject/Image/GD.pm, API2/Resource/XObject/Image/GIF.pm, API2/Resource/XObject/Image/JPEG.pm, API2/Resource/XObject/Image/PNG.pm, API2/Resource/XObject/Image/PNM.pm, API2/Resource/XObject/Image/TIFF.pm: fixed CPAN modulefile versioning (again) 2005-06-17 20:53 fredo * lib/PDF/: API2.pm, API2/Annotation.pm, API2/Content.pm, API2/IOString.pm, API2/Lite.pm, API2/Matrix.pm, API2/NamedDestination.pm, API2/Outline.pm, API2/Outlines.pm, API2/Page.pm, API2/Resource.pm, API2/Shape.pm, API2/UniWrap.pm, API2/Util.pm, API2/Version.pm, API2/Content/Text.pm, API2/Resource/BaseFont.pm, API2/Resource/CIDFont.pm, API2/Resource/ColorSpace.pm, API2/Resource/ExtGState.pm, API2/Resource/Font.pm, API2/Resource/Pattern.pm, API2/Resource/Shading.pm, API2/Resource/UniFont.pm, API2/Resource/XObject.pm, API2/Resource/CIDFont/CJKFont.pm, API2/Resource/CIDFont/TrueType.pm, API2/Resource/CIDFont/TrueType/FontFile.pm, API2/Resource/ColorSpace/DeviceN.pm, API2/Resource/ColorSpace/Indexed.pm, API2/Resource/ColorSpace/Separation.pm, API2/Resource/ColorSpace/Indexed/ACTFile.pm, API2/Resource/ColorSpace/Indexed/Hue.pm, API2/Resource/ColorSpace/Indexed/WebColor.pm, API2/Resource/Font/BdFont.pm, API2/Resource/Font/CoreFont.pm, API2/Resource/Font/Postscript.pm, API2/Resource/Font/SynFont.pm, API2/Resource/Shading/axial.pm, API2/Resource/XObject/Form.pm, API2/Resource/XObject/Image.pm, API2/Resource/XObject/Form/BarCode.pm, API2/Resource/XObject/Form/Hybrid.pm, API2/Resource/XObject/Form/BarCode/codabar.pm, API2/Resource/XObject/Form/BarCode/code128.pm, API2/Resource/XObject/Form/BarCode/code3of9.pm, API2/Resource/XObject/Form/BarCode/ean13.pm, API2/Resource/XObject/Form/BarCode/int2of5.pm, API2/Resource/XObject/Image/GD.pm, API2/Resource/XObject/Image/GIF.pm, API2/Resource/XObject/Image/JPEG.pm, API2/Resource/XObject/Image/PNG.pm, API2/Resource/XObject/Image/PNM.pm, API2/Resource/XObject/Image/TIFF.pm: fixed CPAN modulefile versioning (dislikes cvs) 2005-06-17 20:37 fredo * lib/PDF/API2/Basic/PDF/Pages.pm: added find_prop undef fix 2005-06-14 14:55 fredo * lib/PDF/API2/Annotation.pm: fixed typo for text annotation leaving it empty 2005-06-14 14:54 fredo * lib/PDF/API2/Page.pm: fix for existing annotation dictionary (ex. ScanSoft PDF) 2005-06-10 18:12 fredo * lib/PDF/API2.pm: documentation update 2005-06-08 01:21 fredo * lib/PDF/API2/Resource/Font/CoreFont/: bankgothic.pm, courier.pm, courierbold.pm, courierboldoblique.pm, courieroblique.pm, georgia.pm, georgiabold.pm, georgiabolditalic.pm, georgiaitalic.pm, helvetica.pm, helveticabold.pm, helveticaboldoblique.pm, helveticaoblique.pm, timesbold.pm, timesbolditalic.pm, timesitalic.pm, timesroman.pm, trebuchet.pm, trebuchetbold.pm, trebuchetbolditalic.pm, trebuchetitalic.pm, verdana.pm, verdanabold.pm, verdanabolditalic.pm, verdanaitalic.pm, wingdings.pm: fontkey correction 2005-06-02 14:59 fredo * lib/PDF/API2/Basic/PDF/File.pm: relaxed pdf-header detection 2005-05-29 11:48 fredo * lib/PDF/API2/Content.pm: added conditional textstate2 method 2005-05-29 11:47 fredo * lib/PDF/API2/Resource/Font/CoreFont.pm: cosmetic changes 2005-05-28 18:13 fredo * MANIFEST: added unicolor/unipaper.txt 2005-05-28 17:58 fredo * lib/PDF/API2/Resource/: unicolor.txt, unipaper.txt: genesis 2005-05-28 17:58 fredo * lib/PDF/API2/Util.pm: added xmldecl for markup code moved colors/pagesizes to separate files 2005-03-25 14:30 fredo * Makefile.PL: changed release level versioning vs. maintainance level 2005-03-25 14:19 fredo * lib/PDF/API2/Basic/PDF/File.pm: fixed string exhaustion in array reading 2005-03-23 17:42 fredo * lib/PDF/API2.pm: fixed typo in infoMetaAttributes 2005-03-21 23:36 fredo * lib/PDF/API2.pm: fix for landscape imports 2005-03-21 18:31 fredo * lib/PDF/API2/Resource/CIDFont/TrueType.pm: cleanup 2005-03-21 00:24 fredo * lib/PDF/API2/Resource/CIDFont/TrueType/FontFile.pm: added workaround for broken truetype naming-tables 2005-03-16 20:40 fredo * lib/PDF/API2/Resource/CIDFont/: CJKFont/adobesongstdlightacro.pm, CMap/simplified.pm: updated to latest spec (gb1-4) 2005-03-16 19:27 fredo * lib/PDF/API2/Resource/CIDFont/CJKFont/adobemingstdlightacro.pm: updated to latest spec 2005-03-16 19:27 fredo * lib/PDF/API2/Resource/CIDFont/CMap/traditional.pm: added ccs 2005-03-16 18:59 fredo * lib/PDF/API2/Resource/CIDFont/CMap/traditional.pm: updated to adobe cmap cns-1-4 2005-03-16 03:27 fredo * CONTACT: updated website and twiki 2005-03-15 18:31 fredo * lib/PDF/API2.pm: corrected utf8 handling in info tags 2005-03-15 18:29 fredo * Makefile.PL: fixed ppm creation 2005-03-15 03:20 fredo * lib/PDF/API2/Content.pm: added metadata stubs 2005-03-15 01:59 fredo * lib/PDF/API2/Util.pm: cleanup 2005-03-15 00:53 fredo * lib/PDF/API2.pm: added xmpMetadata method to get/set XMP document data 2005-03-15 00:51 fredo * lib/PDF/API2/Util.pm: beatification 2005-03-14 23:05 fredo * release.sh: genesis 2005-03-14 23:01 fredo * Makefile.PL, lib/PDF/API2.pm, lib/PDF/API2/Annotation.pm, lib/PDF/API2/Content.pm, lib/PDF/API2/HOWTO.pod, lib/PDF/API2/IOString.pm, lib/PDF/API2/Lite.pm, lib/PDF/API2/NamedDestination.pm, lib/PDF/API2/Outline.pm, lib/PDF/API2/Outlines.pm, lib/PDF/API2/Page.pm, lib/PDF/API2/Resource.pm, lib/PDF/API2/Shape.pm, lib/PDF/API2/UniWrap.pm, lib/PDF/API2/Util.pm, lib/PDF/API2/Version.pm, lib/PDF/API2/Win32.pm, lib/PDF/API2/Basic/PDF/Literal.pm, lib/PDF/API2/Content/Text.pm, lib/PDF/API2/Content/symbols.pm, lib/PDF/API2/Content/Text/Markup.pm, lib/PDF/API2/Resource/BaseFont.pm, lib/PDF/API2/Resource/CIDFont.pm, lib/PDF/API2/Resource/ColorSpace.pm, lib/PDF/API2/Resource/ExtGState.pm, lib/PDF/API2/Resource/Font.pm, lib/PDF/API2/Resource/Pattern.pm, lib/PDF/API2/Resource/Shading.pm, lib/PDF/API2/Resource/UniFont.pm, lib/PDF/API2/Resource/XObject.pm, lib/PDF/API2/Resource/CIDFont/CJKFont.pm, lib/PDF/API2/Resource/CIDFont/TrueType.pm, lib/PDF/API2/Resource/CIDFont/CJKFont/adobemingstdlightacro.pm, lib/PDF/API2/Resource/CIDFont/CJKFont/adobemyungjostdmediumacro.pm, lib/PDF/API2/Resource/CIDFont/CJKFont/adobesongstdlightacro.pm, lib/PDF/API2/Resource/CIDFont/CJKFont/kozgopromediumacro.pm, lib/PDF/API2/Resource/CIDFont/CJKFont/kozminproregularacro.pm, lib/PDF/API2/Resource/CIDFont/CMap/japanese.pm, lib/PDF/API2/Resource/CIDFont/CMap/korean.pm, lib/PDF/API2/Resource/CIDFont/CMap/simplified.pm, lib/PDF/API2/Resource/CIDFont/CMap/traditional.pm, lib/PDF/API2/Resource/CIDFont/TrueType/FontFile.pm, lib/PDF/API2/Resource/ColorSpace/DeviceN.pm, lib/PDF/API2/Resource/ColorSpace/Indexed.pm, lib/PDF/API2/Resource/ColorSpace/Separation.pm, lib/PDF/API2/Resource/ColorSpace/Indexed/ACTFile.pm, lib/PDF/API2/Resource/ColorSpace/Indexed/Hue.pm, lib/PDF/API2/Resource/ColorSpace/Indexed/WebColor.pm, lib/PDF/API2/Resource/Font/BdFont.pm, lib/PDF/API2/Resource/Font/CoreFont.pm, lib/PDF/API2/Resource/Font/Postscript.pm, lib/PDF/API2/Resource/Font/SynFont.pm, lib/PDF/API2/Resource/Font/CoreFont/bankgothic.pm, lib/PDF/API2/Resource/Font/CoreFont/courier.pm, lib/PDF/API2/Resource/Font/CoreFont/courierbold.pm, lib/PDF/API2/Resource/Font/CoreFont/courierboldoblique.pm, lib/PDF/API2/Resource/Font/CoreFont/courieroblique.pm, lib/PDF/API2/Resource/Font/CoreFont/georgia.pm, lib/PDF/API2/Resource/Font/CoreFont/georgiabold.pm, lib/PDF/API2/Resource/Font/CoreFont/georgiabolditalic.pm, lib/PDF/API2/Resource/Font/CoreFont/georgiaitalic.pm, lib/PDF/API2/Resource/Font/CoreFont/helvetica.pm, lib/PDF/API2/Resource/Font/CoreFont/helveticabold.pm, lib/PDF/API2/Resource/Font/CoreFont/helveticaboldoblique.pm, lib/PDF/API2/Resource/Font/CoreFont/helveticaoblique.pm, lib/PDF/API2/Resource/Font/CoreFont/symbol.pm, lib/PDF/API2/Resource/Font/CoreFont/timesbold.pm, lib/PDF/API2/Resource/Font/CoreFont/timesbolditalic.pm, lib/PDF/API2/Resource/Font/CoreFont/timesitalic.pm, lib/PDF/API2/Resource/Font/CoreFont/timesroman.pm, lib/PDF/API2/Resource/Font/CoreFont/trebuchet.pm, lib/PDF/API2/Resource/Font/CoreFont/trebuchetbold.pm, lib/PDF/API2/Resource/Font/CoreFont/trebuchetbolditalic.pm, lib/PDF/API2/Resource/Font/CoreFont/trebuchetitalic.pm, lib/PDF/API2/Resource/Font/CoreFont/verdana.pm, lib/PDF/API2/Resource/Font/CoreFont/verdanabold.pm, lib/PDF/API2/Resource/Font/CoreFont/verdanabolditalic.pm, lib/PDF/API2/Resource/Font/CoreFont/verdanaitalic.pm, lib/PDF/API2/Resource/Font/CoreFont/webdings.pm, lib/PDF/API2/Resource/Font/CoreFont/wingdings.pm, lib/PDF/API2/Resource/Font/CoreFont/zapfdingbats.pm, lib/PDF/API2/Resource/Shading/axial.pm, lib/PDF/API2/Resource/XObject/Form.pm, lib/PDF/API2/Resource/XObject/Image.pm, lib/PDF/API2/Resource/XObject/Form/BarCode.pm, lib/PDF/API2/Resource/XObject/Form/Hybrid.pm, lib/PDF/API2/Resource/XObject/Form/BarCode/codabar.pm, lib/PDF/API2/Resource/XObject/Form/BarCode/code128.pm, lib/PDF/API2/Resource/XObject/Form/BarCode/code3of9.pm, lib/PDF/API2/Resource/XObject/Form/BarCode/ean13.pm, lib/PDF/API2/Resource/XObject/Form/BarCode/int2of5.pm, lib/PDF/API2/Resource/XObject/Image/GD.pm, lib/PDF/API2/Resource/XObject/Image/GIF.pm, lib/PDF/API2/Resource/XObject/Image/JPEG.pm, lib/PDF/API2/Resource/XObject/Image/PNG.pm, lib/PDF/API2/Resource/XObject/Image/PNM.pm, lib/PDF/API2/Resource/XObject/Image/TIFF.pm, lib/PDF/API2/Shape/line.pm, lib/PDF/API2/Shape/polygon.pm, lib/PDF/API2/Shape/polyline.pm, lib/PDF/API2/Shape/sline.pm: upd 2005 2005-03-14 22:49 fredo * LICENSE: upd 2005 2005-03-14 22:48 fredo * Makefile.PL: merged manify patch by gunnar wolf 2005-03-14 21:26 fredo * lib/PDF/API2/Content.pm: added 'auto' value for -underline parameter in text fixed text line construction to to work under width==0 conditions 2005-02-28 19:00 fredo * lib/PDF/API2/Lite.pm: removed color method since businesscolor is not available anymore in PDF::API2 2005-02-25 19:07 fredo * lib/PDF/API2.pm: no message 2005-02-24 00:11 fredo * lib/PDF/API2/Basic/PDF/File.pm: workaround for illustrator/enfocus bug to import objects 2005-02-22 23:59 fredo * lib/PDF/API2/Content.pm: fixed infinite loop in paragraph if words longer than a paragraph are present. 2005-02-21 23:15 fredo * lib/PDF/API2/Basic/: PDF/Bool.pm, PDF/Filter.pm, TTF/Bsln.pm, TTF/Fdsc.pm, TTF/GDEF.pm, TTF/Hhea.pm, TTF/PCLT.pm, TTF/Ttopen.pm, TTF/Vhea.pm, TTF/Kern/CompactClassArray.pm: correcting NAME section, thanks to SAPER 2005-02-17 15:50 fredo * Makefile: some 2005-02-17 08:03 fredo * lib/PDF/API2.pm: added 'pageencaps' default option to fix unusual styled content streams 2005-02-14 21:09 fredo * lib/PDF/API2.pm: fixed an openpage recompression bug / thanks to steve_wu@iinet.net.au 2005-02-11 20:11 fredo * lib/PDF/API2/IOString.pm: added binmode hack 2005-02-11 19:48 fredo * lib/PDF/API2/Util.pm: added getPaperSizes method to help fix PDF::Report. 2005-02-07 20:34 fredo * Makefile.PL: added ppmdist target for our windows friends 2005-02-07 20:31 fredo * lib/PDF/API2/Content.pm: fixed reset of textlinematrix on textmatrix set/resets 2005-01-24 12:46 fredo * lib/PDF/API2/Basic/PDF/File.pm: fixed rt.cpan.org: Ticket #11137 Error in File.pm & FileAPI.pm 2005-01-21 11:19 fredo * lib/PDF/API2/Content.pm: added spline operator 2005-01-21 11:04 fredo * lib/PDF/API2/Resource/Font/CoreFont.pm: rewrite fontproxy comment 2005-01-21 11:03 fredo * lib/PDF/API2/Resource/BaseFont.pm: added object saver for cmap 2005-01-21 11:01 fredo * lib/PDF/API2/Resource/CIDFont/TrueType.pm: added -nosubset option 2005-01-21 11:00 fredo * lib/PDF/API2/Resource/CIDFont/TrueType/FontFile.pm: added handling of nosubset option 2005-01-21 02:27 fredo * lib/PDF/API2/Basic/PDF/Dict.pm: added object saver for prepared stream+filter 2005-01-20 20:58 fredo * lib/PDF/API2/Resource/XObject/Image/TIFF.pm: cleaned up handler and ccitt mode 2005-01-03 06:01 fredo * examples/040_named_dest: genesis 2005-01-03 06:00 fredo * lib/PDF/API2/Annotation.pm: changed default behavior of border 2005-01-03 05:17 fredo * lib/PDF/API2/NamedDestination.pm: fixed dict creation 2005-01-03 05:17 fredo * lib/PDF/API2/Annotation.pm: fixed link bug 2005-01-03 04:47 fredo * lib/PDF/API2.pm: fixed use named destination 2005-01-03 04:46 fredo * lib/PDF/API2.pm: added named destination support 2005-01-03 04:34 fredo * MANIFEST: added NamedDestination.pm 2005-01-03 04:31 fredo * lib/PDF/API2/NamedDestination.pm: genesis 2005-01-03 04:29 fredo * lib/PDF/API2/Annotation.pm: removed code duplication 2005-01-03 02:16 fredo * lib/PDF/API2/Content.pm: fixed textpos tracking in nl method 2005-01-03 01:33 fredo * lib/PDF/API2/Outline.pm: added named destination support 2005-01-03 01:30 fredo * lib/PDF/API2/Annotation.pm: added named destination support 2004-12-31 04:59 fredo * lib/PDF/API2/Content.pm: fixed paragraph and text_fill_* methods (thanks to Shawn Corey ) 2004-12-31 04:12 fredo * lib/PDF/: API2.pm, API2/Util.pm: no message 2004-12-31 04:08 fredo * MANIFEST: added new examples 2004-12-31 04:04 fredo * examples/: 024_bmpfonts, 025_unifonts, 026_unifont2, 027_winfont, 020_textrise, 020_textunderline: genesis 2004-12-31 03:58 fredo * examples/: 021_synfonts, 022_truefonts, 023_cjkfonts: no message 2004-12-31 03:53 fredo * lib/PDF/API2/Content.pm: minor code corrections 2004-12-31 03:06 fredo * lib/PDF/API2/Content.pm: fixed textpos calculation, added underline capability (thanks to Shawn Corey ) 2004-12-29 23:01 fredo * lib/PDF/API2/Content.pm: advancewidth now can take a virtual textstate 2004-12-29 02:48 fredo * lib/PDF/API2/Content.pm: fixed _font method 2004-12-29 02:45 fredo * lib/PDF/API2/Win32.pm: fixed no warn for recursion 2004-12-29 02:16 fredo * Makefile.PL: added version pod 2004-12-29 02:14 fredo * lib/PDF/API2/Content.pm: added virtual attribute support 2004-12-29 02:13 fredo * lib/PDF/API2/Resource/Font/SynFont.pm: documented -caps option 2004-12-29 02:12 fredo * lib/PDF/API2/: Resource/CIDFont/TrueType/FontFile.pm, Util.pm: fixed no warn for recursion 2004-12-29 01:53 fredo * lib/PDF/API2/Resource/uniglyph.txt: fixed .notdef glyph 2004-12-28 18:23 fredo * lib/PDF/API2/Resource/Font/CoreFont/: timesroman.pm, zapfdingbats.pm: updated to new adobe afm 2004-12-28 18:23 fredo * lib/PDF/API2/Resource/Font/CoreFont/bankgothic.pm: added new 'Euro' glyph 2004-12-20 13:11 fredo * lib/PDF/API2/Content.pm: added fontset method to not set via 'Tf' 2004-12-17 19:35 fredo * lib/PDF/API2/Resource/uniglyph.txt: added adobe combining characters 2004-12-16 02:09 fredo * lib/PDF/API2/Resource/Font/CoreFont/: courier.pm, zapfdingbats.pm: updated to new adobe afm 2004-12-16 01:43 fredo * examples/020_corefonts: added full list of fonts and encoding latin1-10 2004-12-16 01:30 fredo * lib/PDF/: API2.pm, API2/Annotation.pm, API2/Content.pm, API2/IOString.pm, API2/Lite.pm, API2/Matrix.pm, API2/Outline.pm, API2/Outlines.pm, API2/Page.pm, API2/Resource.pm, API2/Shape.pm, API2/UniWrap.pm, API2/Util.pm, API2/Version.pm, API2/Win32.pm, API2/Basic/PDF/Array.pm, API2/Basic/PDF/Bool.pm, API2/Basic/PDF/Dict.pm, API2/Basic/PDF/File.pm, API2/Basic/PDF/Filter.pm, API2/Basic/PDF/Literal.pm, API2/Basic/PDF/Name.pm, API2/Basic/PDF/Null.pm, API2/Basic/PDF/Number.pm, API2/Basic/PDF/Objind.pm, API2/Basic/PDF/Page.pm, API2/Basic/PDF/Pages.pm, API2/Basic/PDF/String.pm, API2/Basic/PDF/Utils.pm, API2/Content/Text.pm, API2/Resource/BaseFont.pm, API2/Resource/CIDFont.pm, API2/Resource/ColorSpace.pm, API2/Resource/ExtGState.pm, API2/Resource/Font.pm, API2/Resource/Pattern.pm, API2/Resource/Shading.pm, API2/Resource/UniFont.pm, API2/Resource/XObject.pm, API2/Resource/CIDFont/CJKFont.pm, API2/Resource/CIDFont/TrueType.pm, API2/Resource/CIDFont/TrueType/FontFile.pm, API2/Resource/ColorSpace/DeviceN.pm, API2/Resource/ColorSpace/Indexed.pm, API2/Resource/ColorSpace/Separation.pm, API2/Resource/ColorSpace/Indexed/ACTFile.pm, API2/Resource/ColorSpace/Indexed/Hue.pm, API2/Resource/ColorSpace/Indexed/WebColor.pm, API2/Resource/Font/BdFont.pm, API2/Resource/Font/CoreFont.pm, API2/Resource/Font/Postscript.pm, API2/Resource/Font/SynFont.pm, API2/Resource/XObject/Form.pm, API2/Resource/XObject/Image.pm, API2/Resource/XObject/Form/BarCode.pm, API2/Resource/XObject/Form/Hybrid.pm, API2/Resource/XObject/Form/BarCode/codabar.pm, API2/Resource/XObject/Form/BarCode/code128.pm, API2/Resource/XObject/Form/BarCode/code3of9.pm, API2/Resource/XObject/Form/BarCode/ean13.pm, API2/Resource/XObject/Form/BarCode/int2of5.pm, API2/Resource/XObject/Image/GD.pm, API2/Resource/XObject/Image/GIF.pm, API2/Resource/XObject/Image/JPEG.pm, API2/Resource/XObject/Image/PNG.pm, API2/Resource/XObject/Image/PNM.pm, API2/Resource/XObject/Image/TIFF.pm: added no warn for recursion 2004-12-15 17:44 fredo * lib/PDF/API2/Content.pm: added condition to apply font (Tf) only when needed 2004-11-29 16:57 fredo * lib/PDF/API2/Resource/UniFont.pm: added docs for unifont 2004-11-29 16:19 fredo * lib/PDF/API2.pm: added docs for bdfont, synfont and unifont 2004-11-29 11:00 fredo * lib/PDF/API2/Resource/Font/SynFont.pm: added charspacer docs 2004-11-26 16:14 fredo * lib/PDF/API2/Resource/Font/SynFont.pm: fixed docs 2004-11-26 16:10 fredo * lib/PDF/API2/Resource/Font/SynFont.pm: added spacer mod option 2004-11-26 02:25 fredo * lib/PDF/API2/Resource/Font.pm: added unicode block mapping 2004-11-26 02:24 fredo * lib/PDF/API2/Resource/Font/CoreFont/webdings.pm: fixed unicode mapping 2004-11-26 00:51 fredo * lib/PDF/API2/Resource/UniFont.pm: added -encode option and handling 2004-11-26 00:50 fredo * lib/PDF/API2/Resource/Font.pm: fixed unicode maps for unmapped corefonts 2004-11-25 21:53 fredo * lib/PDF/API2/Content.pm: fixed unifont registration 2004-11-25 20:56 fredo * lib/PDF/API2/UniWrap.pm: genesis 2004-11-25 20:55 fredo * MANIFEST: added uniwrap 2004-11-25 16:30 fredo * lib/PDF/API2/Basic/: PDF/File.pm, PDF/Filter.pm, PDF/Objind.pm, TTF/Coverage.pm, TTF/Font.pm, TTF/Table.pm: fixed explicit release on scalar 2004-11-25 16:07 fredo * lib/PDF/API2/Resource/CIDFont/CJKFont.pm: fixed prototype warning 2004-11-24 21:13 fredo * MANIFEST: added unifont 2004-11-24 21:12 fredo * TODO: update 2004-11-24 21:11 fredo * lib/PDF/API2/Resource/UniFont.pm: genesis 2004-11-24 21:10 fredo * lib/PDF/API2/Resource/: BaseFont.pm, CIDFont.pm, Font.pm: added virtual font handling 2004-11-24 21:10 fredo * lib/PDF/API2/Content.pm: added virtual font handling, fixed var shadow bug 2004-11-24 21:09 fredo * lib/PDF/API2.pm: added unifont 2004-11-22 22:07 fredo * lib/PDF/API2/Resource/: CIDFont.pm, CIDFont/CJKFont.pm, CIDFont/TrueType.pm, CIDFont/TrueType/FontFile.pm: fixed multibyte-encoding support to work consistently acress cjk/ttf/otf 2004-11-22 17:07 fredo * MANIFEST: added TODO + uniglyph.txt 2004-11-22 17:07 fredo * TODO: genesis 2004-11-22 03:34 fredo * lib/PDF/API2/Util.pm: moved unicode+glyphs to better maintainable uniglyph.txt 2004-11-22 03:31 fredo * lib/PDF/API2/Basic/PDF/Utils.pm: added hexstring shortcut 2004-11-22 03:31 fredo * lib/PDF/API2/Basic/PDF/String.pm: speed fix 2004-11-22 03:25 fredo * lib/PDF/API2/Resource/CIDFont/TrueType/FontFile.pm: added advanced attributes 2004-11-22 03:08 fredo * lib/PDF/API2/Resource/Font/CoreFont.pm: aaa 2004-11-22 03:05 fredo * lib/PDF/API2/Resource/BaseFont.pm: added pdf-1.5 font param specs 2004-11-22 03:04 fredo * lib/PDF/API2/Resource/CIDFont/CJKFont.pm: added missing substitutes 2004-11-22 03:02 fredo * lib/PDF/API2/Resource/CIDFont/CJKFont/: kozminproregularacro.pm, kozgopromediumacro.pm: deleted obsolete character widths 2004-11-22 02:05 fredo * lib/PDF/API2/Resource/CIDFont/CMap/korean.pm: updated to korea1-2 spec 2004-11-22 02:04 fredo * lib/PDF/API2/Resource/CIDFont/CJKFont/: adobemyungjostdmediumacro.pm, kozminproregularacro.pm: added advanced attributes 2004-11-22 02:03 fredo * lib/PDF/API2/Resource/CIDFont/CJKFont.pm: fixed supplement set, added substitute handling 2004-11-21 04:20 fredo * lib/PDF/API2/Resource/CIDFont/CMap/japanese.pm: fixed cidmap to adobe japan1 supl 6 2004-11-21 03:58 fredo * lib/PDF/API2/Resource/CIDFont/CJKFont.pm: fixed multibyte encoding issues 2004-11-21 03:58 fredo * lib/PDF/API2/Resource/uniglyph.txt: genesis 2004-11-21 03:57 fredo * lib/PDF/API2/Resource/CIDFont.pm: cosmetic change 2004-10-26 16:46 fredo * lib/PDF/API2/Resource/CIDFont/CJKFont/: adobemingstdlightacro.pm, adobemyungjostdmediumacro.pm, adobesongstdlightacro.pm, kozgopromediumacro.pm, kozminproregularacro.pm: added alternative glyph-width storage 2004-10-26 16:42 fredo * lib/PDF/API2/Resource/: CIDFont.pm, CIDFont/CJKFont.pm: added alternative glyph-width storage/retrieval 2004-10-26 16:41 fredo * lib/PDF/API2/Resource/BaseFont.pm: added panose identification style entry 2004-10-26 13:34 fredo * lib/PDF/API2/Content.pm: reworked text_fill for paragraph, but still being development 2004-10-24 22:31 fredo * lib/PDF/API2/Resource/CIDFont/CMap/japanese.pm: updated to Adobe-Japan1 rev 4 2004-10-17 06:07 fredo * Makefile.PL: added option shorts and usage 2004-10-17 05:58 fredo * Makefile.PL: removed version fuss 2004-10-17 05:57 fredo * lib/PDF/API2.pm: added ToUnicode call for supported fonts 2004-10-17 05:55 fredo * lib/PDF/API2/Resource/BaseFont.pm: simplified ToUnicode associated CMap for single-byte fonts 2004-10-17 05:47 fredo * lib/PDF/API2/Resource/BaseFont.pm: fixed inclusion of ToUnicode compatible key and associated CMap 2004-10-17 05:46 fredo * lib/PDF/API2/Resource/Font.pm: restructured encoding vs. unicode vs. glyph-name lookup 2004-10-13 20:30 fredo * lib/PDF/API2/Annotation.pm: fixed pdfile method from utf8 back to ascii 2004-10-11 09:54 fredo * lib/PDF/API2/Annotation.pm: fixed file method from utf8 back to ascii 2004-10-01 03:39 fredo * lib/PDF/API2.pm: reverted annotations import fix 2004-10-01 03:20 fredo * lib/PDF/API2/Annotation.pm: fixed url link annotation to 7-bit ascii as per pdf-spec-1.5 2004-10-01 03:06 fredo * Makefile.PL: fixed versioning 2004-10-01 02:37 fredo * Makefile.PL: modded version hex schema 2004-10-01 01:57 fredo * Makefile.PL: implemented devel options 2004-10-01 01:57 fredo * lib/PDF/API2.pm: versioning beautify 2004-10-01 00:41 fredo * lib/PDF/API2/Version.pm: updated to current state 2004-10-01 00:40 fredo * lib/PDF/API2.pm: fixed pdf-producer to include OS 2004-10-01 00:37 fredo * MANIFEST: added back Version.pm removed tests 2004-10-01 00:36 fredo * Makefile.PL: changed versioning back to version.pm 2004-09-30 23:18 fredo * lib/PDF/API2.pm: changed file version back to cvs 2004-09-22 16:12 fredo * lib/PDF/API2/Basic/PDF/Dict.pm: fixed stream length calculation for acrobat 6 2004-09-20 14:01 fredo * lib/PDF/API2/Basic/PDF/File.pm: worked around broken dict-key by acrobat 5 2004-09-20 13:22 fredo * lib/PDF/API2.pm: added default param to fix import-rotation added default param to fix annotation-import 2004-09-13 17:30 fredo * examples/032_separation: added All/None Separation CS 2004-09-13 17:27 fredo * lib/PDF/API2/Page.pm: added rotate for acrobat-wise pdf-creators 2004-09-03 14:35 fredo * lib/PDF/API2.pm: pop'd to new version 2004-09-03 14:33 fredo * lib/PDF/API2/Basic/PDF/File.pm: fixed binary stream reading by update method 2004-08-31 15:50 fredo * lib/PDF/API2/Content.pm: fixed space vs. whitespace split bug 2004-08-25 05:03 fredo * lib/PDF/API2/Resource/CIDFont/TrueType/FontFile.pm: removed fuss 2004-08-25 04:59 fredo * lib/PDF/API2.pm: disabled memoize since long-running scripts bug from reused adresses 2004-07-29 13:06 fredo * lib/PDF/API2/Resource/XObject/Form/BarCode/int2of5.pm: fixed encode 2004-07-29 12:48 fredo * lib/PDF/API2/Basic/PDF/Utils.pm: added PDFLiteral and PDFNull methods 2004-07-29 12:47 fredo * lib/PDF/API2/Outline.pm: fixed "null vs. 0" bug of -xyz option 2004-07-29 12:46 fredo * lib/PDF/API2/Content.pm: added new text_fill_* methods and a simple paragraph 2004-07-25 01:38 fredo * lib/PDF/API2/Resource/XObject/Image/PNM.pm: added new headerparser and simplified loading 2004-07-25 01:38 fredo * lib/PDF/API2/Basic/PDF/Filter.pm: some 2004-07-25 01:33 fredo * lib/PDF/API2/Resource/Font/BdFont.pm: added compression 2004-07-25 01:10 fredo * lib/PDF/API2.pm: fixed memoize bug for bdf fonts 2004-07-25 01:09 fredo * lib/PDF/API2.pm: added bdf fonts 2004-07-25 01:08 fredo * lib/PDF/API2/Resource/Font/BdFont.pm: genesis 2004-07-23 15:41 fredo * lib/PDF/API2.pm: fixed in decoding info dictionary 2004-07-21 10:07 fredo * lib/PDF/API2.pm: added devicen colorspace 2004-07-20 22:31 fredo * MANIFEST: deleted changelog.pre added devicen.pm 2004-07-20 22:28 fredo * lib/PDF/API2/Resource/ColorSpace/Separation.pm: added tintname accessor 2004-07-20 22:27 fredo * lib/PDF/API2/Resource/ColorSpace/DeviceN.pm, examples/033_deviceN: genesis 2004-07-15 16:35 fredo * lib/PDF/API2/Resource/ColorSpace.pm: added type accessor 2004-07-15 16:28 fredo * lib/PDF/API2.pm: added devicen colorspace 2004-07-15 16:14 fredo * lib/PDF/API2/Resource/ColorSpace/Separation.pm: added type and color accessor 2004-07-15 16:13 fredo * lib/PDF/API2/Resource/ColorSpace/Indexed.pm: added type accessor 2004-07-13 20:09 fredo * t/020corecoit.t, t/020corecour.t, t/020coreheit.t, t/020coretiro.t, t/020corevebi.t, t/020coreverd.t, t/022core____.t, t/028psf_all.t, .cvsignore, .project, Makefile, t/020corecobi.t, t/020corecobo.t, t/020corehebi.t, t/020corehebo.t, t/020corehelv.t, t/020coretibi.t, t/020coretibo.t, t/020coretiit.t, t/020coretrbi.t, t/020coretrbo.t, t/020coretreb.t, t/020coretrit.t, t/020corevebo.t, t/020coreveit.t, t/029ttf_all.t: genesis 2004-06-22 03:33 fredo * lib/PDF/API2.pm: corrected spelling 2004-06-22 02:38 fredo * lib/PDF/API2/Resource/: Pattern.pm, Shading.pm: fixed ISA 2004-06-22 00:40 fredo * MANIFEST: added pattern/shading 2004-06-22 00:33 fredo * lib/PDF/: API2.pm, API2/Content.pm, API2/Util.pm, API2/Resource/Pattern.pm, API2/Resource/Shading.pm: added basic pattern/shading handling 2004-06-22 00:25 fredo * lib/PDF/API2/Resource/Font/CoreFont.pm: added custom corefont handling 2004-06-15 18:48 fredo * MANIFEST: removed shapes 2004-06-15 18:44 fredo * lib/PDF/API2/Basic/PDF/File.pm: jaws import workaround fix for broken xrefs 2004-06-15 11:16 fredo * MANIFEST: removed Version.pm 2004-06-15 11:14 fredo * lib/PDF/API2/: Basic/TTF/Maxp.pm, Basic/TTF/Mort.pm, Basic/TTF/Name.pm, Basic/TTF/OS_2.pm, Basic/TTF/OldCmap.pm, Basic/TTF/OldMort.pm, Basic/TTF/PCLT.pm, Basic/TTF/PSNames.pm, Basic/TTF/Post.pm, Basic/TTF/Prep.pm, Basic/TTF/Prop.pm, Basic/TTF/Segarr.pm, Basic/TTF/Table.pm, Basic/TTF/Ttc.pm, Basic/TTF/Ttopen.pm, Basic/TTF/Useall.pm, Basic/TTF/Utils.pm, Basic/TTF/Vhea.pm, Basic/TTF/Vmtx.pm, Basic/TTF/Win32.pm, Basic/TTF/XMLparse.pm, Basic/TTF/Kern/ClassArray.pm, Basic/TTF/Kern/CompactClassArray.pm, Basic/TTF/Kern/OrderedList.pm, Basic/TTF/Kern/StateTable.pm, Basic/TTF/Kern/Subtable.pm, Basic/TTF/Mort/Chain.pm, Basic/TTF/Mort/Contextual.pm, Basic/TTF/Mort/Insertion.pm, Basic/TTF/Mort/Ligature.pm, Basic/TTF/Mort/Noncontextual.pm, Basic/TTF/Mort/Rearrangement.pm, Basic/TTF/Mort/Subtable.pm, Content/Text.pm, Content/symbols.pm, Content/Text/Markup.pm, Resource/BaseFont.pm, Resource/CIDFont.pm, Resource/ColorSpace.pm, Resource/ExtGState.pm, Resource/Font.pm, Resource/Shading.pm, Resource/XObject.pm, Resource/CIDFont/CJKFont.pm, Resource/CIDFont/TrueType.pm, Resource/CIDFont/CJKFont/adobemingstdlightacro.pm, Resource/CIDFont/CJKFont/adobemyungjostdmediumacro.pm, Resource/CIDFont/CJKFont/adobesongstdlightacro.pm, Resource/CIDFont/CJKFont/kozgopromediumacro.pm, Resource/CIDFont/CJKFont/kozminproregularacro.pm, Resource/CIDFont/CMap/japanese.pm, Resource/CIDFont/CMap/korean.pm, Resource/CIDFont/CMap/simplified.pm, Resource/CIDFont/CMap/traditional.pm, Resource/CIDFont/TrueType/FontFile.pm, Resource/ColorSpace/Indexed.pm, Resource/ColorSpace/Separation.pm, Resource/ColorSpace/Indexed/ACTFile.pm, Resource/ColorSpace/Indexed/Hue.pm, Resource/ColorSpace/Indexed/WebColor.pm, Resource/Font/CoreFont.pm, Resource/Font/Postscript.pm, Resource/Font/SynFont.pm, Resource/Font/CoreFont/bankgothic.pm, Resource/Font/CoreFont/courier.pm, Resource/Font/CoreFont/courierbold.pm, Resource/Font/CoreFont/courierboldoblique.pm, Resource/Font/CoreFont/courieroblique.pm, Resource/Font/CoreFont/georgia.pm, Resource/Font/CoreFont/georgiabold.pm, Resource/Font/CoreFont/georgiabolditalic.pm, Resource/Font/CoreFont/georgiaitalic.pm, Resource/Font/CoreFont/helvetica.pm, Resource/Font/CoreFont/helveticabold.pm, Resource/Font/CoreFont/helveticaboldoblique.pm, Resource/Font/CoreFont/helveticaoblique.pm, Resource/Font/CoreFont/symbol.pm, Resource/Font/CoreFont/timesbold.pm, Resource/Font/CoreFont/timesbolditalic.pm, Resource/Font/CoreFont/timesitalic.pm, Resource/Font/CoreFont/timesroman.pm, Resource/Font/CoreFont/trebuchet.pm, Resource/Font/CoreFont/trebuchetbold.pm, Resource/Font/CoreFont/trebuchetbolditalic.pm, Resource/Font/CoreFont/trebuchetitalic.pm, Resource/Font/CoreFont/verdana.pm, Resource/Font/CoreFont/verdanabold.pm, Resource/Font/CoreFont/verdanabolditalic.pm, Resource/Font/CoreFont/verdanaitalic.pm, Resource/Font/CoreFont/webdings.pm, Resource/Font/CoreFont/wingdings.pm, Resource/Font/CoreFont/zapfdingbats.pm, Resource/Shading/axial.pm, Resource/XObject/Form.pm, Resource/XObject/Image.pm, Resource/XObject/Form/BarCode.pm, Resource/XObject/Form/Hybrid.pm, Resource/XObject/Form/BarCode/codabar.pm, Resource/XObject/Form/BarCode/code128.pm, Resource/XObject/Form/BarCode/code3of9.pm, Resource/XObject/Form/BarCode/ean13.pm, Resource/XObject/Form/BarCode/int2of5.pm, Resource/XObject/Image/GD.pm, Resource/XObject/Image/GIF.pm, Resource/XObject/Image/JPEG.pm, Resource/XObject/Image/PNG.pm, Resource/XObject/Image/PNM.pm, Resource/XObject/Image/TIFF.pm, Shape/line.pm, Shape/polygon.pm, Shape/polyline.pm, Shape/sline.pm: removed cr+lf 2004-06-15 11:11 fredo * lib/PDF/API2/: Annotation.pm, Content.pm, IOString.pm, Lite.pm, Matrix.pm, Outline.pm, Outlines.pm, Page.pm, Resource.pm, Shape.pm, Util.pm, Win32.pm, Basic/PDF/Array.pm, Basic/PDF/Bool.pm, Basic/PDF/Dict.pm, Basic/PDF/File.pm, Basic/PDF/Filter.pm, Basic/PDF/Literal.pm, Basic/PDF/Name.pm, Basic/PDF/Null.pm, Basic/PDF/Number.pm, Basic/PDF/Objind.pm, Basic/PDF/Page.pm, Basic/PDF/Pages.pm, Basic/PDF/String.pm, Basic/PDF/Utils.pm, Basic/TTF/AATKern.pm, Basic/TTF/AATutils.pm, Basic/TTF/Anchor.pm, Basic/TTF/Bsln.pm, Basic/TTF/Cmap.pm, Basic/TTF/Coverage.pm, Basic/TTF/Cvt_.pm, Basic/TTF/Delta.pm, Basic/TTF/Fdsc.pm, Basic/TTF/Feat.pm, Basic/TTF/Fmtx.pm, Basic/TTF/Font.pm, Basic/TTF/Fpgm.pm, Basic/TTF/GDEF.pm, Basic/TTF/GPOS.pm, Basic/TTF/GSUB.pm, Basic/TTF/Glyf.pm, Basic/TTF/Glyph.pm, Basic/TTF/Hdmx.pm, Basic/TTF/Head.pm, Basic/TTF/Hhea.pm, Basic/TTF/Hmtx.pm, Basic/TTF/Kern.pm, Basic/TTF/LTSH.pm, Basic/TTF/Loca.pm: removed cr+lf 2004-06-15 11:06 fredo * lib/PDF/API2.pm: forced version to 1.50 for beta state 2004-06-15 11:03 fredo * lib/PDF/: API2.pm: changed versioning back to API.pm 2004-06-15 11:00 fredo * Makefile.PL: changed versioning to API.pm 2004-06-15 10:09 fredo * lib/PDF/API2.pm: fixed memoized bug 2004-06-11 14:56 fredo * lib/PDF/API2/Resource/XObject/Form/BarCode/code128.pm: fixed encode bug 2004-06-09 18:30 fredo * lib/PDF/API2/Version.pm: release 0.40_22 2004-06-09 18:29 fredo * lib/PDF/API2/Page.pm: fixed named page size handling for *box methods 2004-06-07 21:43 fredo * lib/PDF/API2/Annotation.pm, lib/PDF/API2/Content.pm, lib/PDF/API2/HOWTO.pod, lib/PDF/API2/IOString.pm, lib/PDF/API2/Lite.pm, lib/PDF/API2/Matrix.pm, lib/PDF/API2/Outline.pm, lib/PDF/API2/Outlines.pm, lib/PDF/API2/Page.pm, lib/PDF/API2/Resource.pm, lib/PDF/API2/Shape.pm, lib/PDF/API2/Util.pm, lib/PDF/API2/Version.pm, lib/PDF/API2/Win32.pm, lib/PDF/API2/Basic/PDF/Array.pm, lib/PDF/API2/Basic/PDF/Bool.pm, lib/PDF/API2/Basic/PDF/Dict.pm, lib/PDF/API2/Basic/PDF/File.pm, lib/PDF/API2/Basic/PDF/Filter.pm, lib/PDF/API2/Basic/PDF/Literal.pm, lib/PDF/API2/Basic/PDF/Name.pm, lib/PDF/API2/Basic/PDF/Null.pm, lib/PDF/API2/Basic/PDF/Number.pm, lib/PDF/API2/Basic/PDF/Objind.pm, lib/PDF/API2/Basic/PDF/Page.pm, lib/PDF/API2/Basic/PDF/Pages.pm, lib/PDF/API2/Basic/PDF/String.pm, lib/PDF/API2/Basic/PDF/Utils.pm, lib/PDF/API2/Basic/TTF/AATKern.pm, lib/PDF/API2/Basic/TTF/AATutils.pm, lib/PDF/API2/Basic/TTF/Anchor.pm, lib/PDF/API2/Basic/TTF/Bsln.pm, lib/PDF/API2/Basic/TTF/Changes, lib/PDF/API2/Basic/TTF/Cmap.pm, lib/PDF/API2/Basic/TTF/Coverage.pm, lib/PDF/API2/Basic/TTF/Cvt_.pm, lib/PDF/API2/Basic/TTF/Delta.pm, lib/PDF/API2/Basic/TTF/Fdsc.pm, lib/PDF/API2/Basic/TTF/Feat.pm, lib/PDF/API2/Basic/TTF/Fmtx.pm, lib/PDF/API2/Basic/TTF/Font.pm, lib/PDF/API2/Basic/TTF/Fpgm.pm, lib/PDF/API2/Basic/TTF/GDEF.pm, lib/PDF/API2/Basic/TTF/GPOS.pm, lib/PDF/API2/Basic/TTF/GSUB.pm, lib/PDF/API2/Basic/TTF/Glyf.pm, lib/PDF/API2/Basic/TTF/Glyph.pm, lib/PDF/API2/Basic/TTF/Hdmx.pm, lib/PDF/API2/Basic/TTF/Head.pm, lib/PDF/API2/Basic/TTF/Hhea.pm, lib/PDF/API2/Basic/TTF/Hmtx.pm, lib/PDF/API2/Basic/TTF/Kern.pm, lib/PDF/API2/Basic/TTF/LTSH.pm, lib/PDF/API2/Basic/TTF/Loca.pm, lib/PDF/API2/Basic/TTF/Manual.pod, lib/PDF/API2/Basic/TTF/Maxp.pm, lib/PDF/API2/Basic/TTF/Mort.pm, lib/PDF/API2/Basic/TTF/Name.pm, lib/PDF/API2/Basic/TTF/OS_2.pm, lib/PDF/API2/Basic/TTF/OldCmap.pm, lib/PDF/API2/Basic/TTF/OldMort.pm, lib/PDF/API2/Basic/TTF/PCLT.pm, lib/PDF/API2/Basic/TTF/PSNames.pm, lib/PDF/API2/Basic/TTF/Post.pm, lib/PDF/API2/Basic/TTF/Prep.pm, lib/PDF/API2/Basic/TTF/Prop.pm, lib/PDF/API2/Basic/TTF/Segarr.pm, lib/PDF/API2/Basic/TTF/Table.pm, lib/PDF/API2/Basic/TTF/Ttc.pm, lib/PDF/API2/Basic/TTF/Ttopen.pm, lib/PDF/API2/Basic/TTF/Useall.pm, lib/PDF/API2/Basic/TTF/Utils.pm, lib/PDF/API2/Basic/TTF/Vhea.pm, lib/PDF/API2/Basic/TTF/Vmtx.pm, lib/PDF/API2/Basic/TTF/Win32.pm, lib/PDF/API2/Basic/TTF/XMLparse.pm, lib/PDF/API2/Basic/TTF/Kern/ClassArray.pm, lib/PDF/API2/Basic/TTF/Kern/CompactClassArray.pm, lib/PDF/API2/Basic/TTF/Kern/OrderedList.pm, lib/PDF/API2/Basic/TTF/Kern/StateTable.pm, lib/PDF/API2/Basic/TTF/Kern/Subtable.pm, lib/PDF/API2/Basic/TTF/Mort/Chain.pm, lib/PDF/API2/Basic/TTF/Mort/Contextual.pm, lib/PDF/API2/Basic/TTF/Mort/Insertion.pm, lib/PDF/API2/Basic/TTF/Mort/Ligature.pm, lib/PDF/API2/Basic/TTF/Mort/Noncontextual.pm, lib/PDF/API2/Basic/TTF/Mort/Rearrangement.pm, lib/PDF/API2/Basic/TTF/Mort/Subtable.pm, lib/PDF/API2/Content/Text.pm, lib/PDF/API2/Content/symbols.pm, lib/PDF/API2/Content/Text/Markup.pm, lib/PDF/API2/Resource/BaseFont.pm, lib/PDF/API2/Resource/CIDFont.pm, lib/PDF/API2/Resource/ColorSpace.pm, lib/PDF/API2/Resource/ExtGState.pm, lib/PDF/API2/Resource/Font.pm, lib/PDF/API2/Resource/Shading.pm, lib/PDF/API2/Resource/XObject.pm, lib/PDF/API2/Resource/CIDFont/CJKFont.pm, lib/PDF/API2/Resource/CIDFont/TrueType.pm, lib/PDF/API2/Resource/CIDFont/CJKFont/adobemingstdlightacro.pm, lib/PDF/API2/Resource/CIDFont/CJKFont/adobemyungjostdmediumacro.pm, lib/PDF/API2/Resource/CIDFont/CJKFont/adobesongstdlightacro.pm, lib/PDF/API2/Resource/CIDFont/CJKFont/kozgopromediumacro.pm, lib/PDF/API2/Resource/CIDFont/CJKFont/kozminproregularacro.pm, lib/PDF/API2/Resource/CIDFont/CMap/japanese.pm, lib/PDF/API2/Resource/CIDFont/CMap/korean.pm, lib/PDF/API2/Resource/CIDFont/CMap/simplified.pm, lib/PDF/API2/Resource/CIDFont/CMap/traditional.pm, lib/PDF/API2/Resource/CIDFont/TrueType/FontFile.pm, lib/PDF/API2/Resource/ColorSpace/Indexed.pm, lib/PDF/API2/Resource/ColorSpace/Separation.pm, lib/PDF/API2/Resource/ColorSpace/Indexed/ACTFile.pm, lib/PDF/API2/Resource/ColorSpace/Indexed/Hue.pm, lib/PDF/API2/Resource/ColorSpace/Indexed/WebColor.pm, lib/PDF/API2/Resource/Font/CoreFont.pm, lib/PDF/API2/Resource/Font/Postscript.pm, lib/PDF/API2/Resource/Font/SynFont.pm, lib/PDF/API2/Resource/Font/CoreFont/bankgothic.pm, lib/PDF/API2/Resource/Font/CoreFont/courier.pm, lib/PDF/API2/Resource/Font/CoreFont/courierbold.pm, lib/PDF/API2/Resource/Font/CoreFont/courierboldoblique.pm, lib/PDF/API2/Resource/Font/CoreFont/courieroblique.pm, lib/PDF/API2/Resource/Font/CoreFont/georgia.pm, lib/PDF/API2/Resource/Font/CoreFont/georgiabold.pm, lib/PDF/API2/Resource/Font/CoreFont/georgiabolditalic.pm, lib/PDF/API2/Resource/Font/CoreFont/georgiaitalic.pm, lib/PDF/API2/Resource/Font/CoreFont/helvetica.pm, lib/PDF/API2/Resource/Font/CoreFont/helveticabold.pm, lib/PDF/API2/Resource/Font/CoreFont/helveticaboldoblique.pm, lib/PDF/API2/Resource/Font/CoreFont/helveticaoblique.pm, lib/PDF/API2/Resource/Font/CoreFont/symbol.pm, lib/PDF/API2/Resource/Font/CoreFont/timesbold.pm, lib/PDF/API2/Resource/Font/CoreFont/timesbolditalic.pm, lib/PDF/API2/Resource/Font/CoreFont/timesitalic.pm, lib/PDF/API2/Resource/Font/CoreFont/timesroman.pm, lib/PDF/API2/Resource/Font/CoreFont/trebuchet.pm, lib/PDF/API2/Resource/Font/CoreFont/trebuchetbold.pm, lib/PDF/API2/Resource/Font/CoreFont/trebuchetbolditalic.pm, lib/PDF/API2/Resource/Font/CoreFont/trebuchetitalic.pm, lib/PDF/API2/Resource/Font/CoreFont/verdana.pm, lib/PDF/API2/Resource/Font/CoreFont/verdanabold.pm, lib/PDF/API2/Resource/Font/CoreFont/verdanabolditalic.pm, lib/PDF/API2/Resource/Font/CoreFont/verdanaitalic.pm, lib/PDF/API2/Resource/Font/CoreFont/webdings.pm, lib/PDF/API2/Resource/Font/CoreFont/wingdings.pm, lib/PDF/API2/Resource/Font/CoreFont/zapfdingbats.pm, lib/PDF/API2/Resource/Shading/axial.pm, lib/PDF/API2/Resource/XObject/Form.pm, lib/PDF/API2/Resource/XObject/Image.pm, lib/PDF/API2/Resource/XObject/Form/BarCode.pm, lib/PDF/API2/Resource/XObject/Form/Hybrid.pm, lib/PDF/API2/Resource/XObject/Form/BarCode/codabar.pm, lib/PDF/API2/Resource/XObject/Form/BarCode/code128.pm, lib/PDF/API2/Resource/XObject/Form/BarCode/code3of9.pm, lib/PDF/API2/Resource/XObject/Form/BarCode/ean13.pm, lib/PDF/API2/Resource/XObject/Form/BarCode/int2of5.pm, lib/PDF/API2/Resource/XObject/Image/GD.pm, lib/PDF/API2/Resource/XObject/Image/GIF.pm, lib/PDF/API2/Resource/XObject/Image/JPEG.pm, lib/PDF/API2/Resource/XObject/Image/PNG.pm, lib/PDF/API2/Resource/XObject/Image/PNM.pm, lib/PDF/API2/Resource/XObject/Image/TIFF.pm, lib/PDF/API2/Shape/line.pm, lib/PDF/API2/Shape/polygon.pm, lib/PDF/API2/Shape/polyline.pm, lib/PDF/API2/Shape/sline.pm, contrib/pdf-deoptimize.pl, MANIFEST, LICENSE: cleaned out cr+lf for lf 2004-06-01 02:17 fredo * contrib/pdf-merge.pl: genesis 2004-06-01 02:14 fredo * README: fixed spelling errors added Memoize as req. module 2004-06-01 02:09 fredo * lib/PDF/API2.pm: memoized *font methods for braindead invokers 2004-06-01 01:20 fredo * lib/PDF/API2/Content.pm: added basic platform encoding independency 2004-05-28 13:33 fredo * MANIFEST: added test scripts for corefonts: helvetica, times, courior 2004-05-28 13:30 fredo * lib/PDF/API2/Version.pm: update to 0.40_21 2004-05-28 13:29 fredo * lib/PDF/: API2.pm, API2/Resource/XObject/Image/GD.pm: added -lossless param to gd images 2004-05-21 18:36 fredo * lib/PDF/API2/Version.pm: update to 0.40_20 2004-05-21 17:10 fredo * lib/PDF/API2/Resource/Font.pm: worked around some unicode probs 2004-05-21 17:04 fredo * lib/PDF/API2/Lite.pm: fixed NAME pod bug for cpan indexer 2004-05-21 12:12 fredo * lib/PDF/API2.pm: fixed slight importpage quirk 2004-04-20 11:47 fredo * lib/PDF/API2/Resource/BaseFont.pm: fixed unicode to font-encoding-vector conversion 2004-04-20 11:46 fredo * lib/PDF/API2/Resource/CIDFont/TrueType/FontFile.pm: added glyph->read fix for subset-vector 2004-04-20 00:01 fredo * lib/PDF/API2/Resource/XObject/Image/TIFF.pm: additional tag handling and tag-accessor 2004-04-18 20:07 fredo * lib/PDF/API2.pm: fixed _findFont method 2004-04-18 19:56 fredo * lib/PDF/API2/Basic/TTF/Glyph.pm: fixed processing unusual/broken ttfs 2004-04-18 17:51 fredo * t/022corefunc.t: genesis 2004-04-18 16:11 fredo * t/020coreuse.t: fixed test for symbol fonts 2004-04-18 16:01 fredo * t/020coreuse.t: added defined/undefined test 2004-04-18 15:54 fredo * t/020coreuse.t: genesis 2004-04-18 15:46 fredo * t/021corebyte.t: added cvs-log tag 2004-04-18 15:43 fredo * t/021corebyte.t: genesis 2004-04-07 19:39 fredo * lib/PDF/API2/Shape/sline.pm: genesis 2004-04-07 19:38 fredo * lib/PDF/API2.pm: added infoMetaAttributes and support code 2004-04-07 12:51 fredo * lib/PDF/API2/Version.pm: updated to 0.40_18b quick-fix release 2004-04-07 12:50 fredo * lib/PDF/API2/Resource/ColorSpace/Separation.pm: fixed RGB semantics to match CMYK "tint" behaviour 2004-04-07 12:49 fredo * lib/PDF/API2/Content.pm: fixed handling of colorSpaces for fill/strokecolor 2004-04-07 12:48 fredo * lib/PDF/API2.pm: fixed handling of ColorSpace/Separation 2004-04-07 12:48 fredo * examples/032_separation: genesis 2004-04-07 12:47 fredo * MANIFEST: added examples/032_separation 2004-04-07 01:09 fredo * MANIFEST: added missing examples/023_cjkfonts 2004-04-07 01:08 fredo * examples/023_cjkfonts: genesis 2004-04-07 01:05 fredo * MANIFEST: added missing examples/022_truefonts 2004-04-07 01:04 fredo * examples/022_truefonts: genesis 2004-04-07 00:59 fredo * MANIFEST: added missing examples/031_color_hsv 2004-04-06 23:08 fredo * MANIFEST: added .../Resource/ColorSpace/Separation 2004-04-06 23:00 fredo * lib/PDF/API2.pm: separation colorspace now a full resource 2004-04-06 22:57 fredo * lib/PDF/API2/Resource/ColorSpace/Separation.pm: separation colorspace promoted to full object 2004-04-05 01:52 fredo * lib/PDF/API2/Version.pm: updated for release 0.40_18 2004-04-05 01:44 fredo * lib/PDF/API2/Shape/: polygon.pm, polyline.pm: updated stroke/fill behaviour 2004-04-05 01:42 fredo * lib/PDF/API2.pm: fixed 270 degree rotation in openpage 2004-04-05 01:36 fredo * lib/PDF/API2.pm: added simple separation colorspace 2004-03-20 10:11 fredo * lib/PDF/API2.pm: modified font search path methodname 2004-03-20 09:38 fredo * lib/PDF/API2.pm: added isEncrypted determinator 2004-03-20 09:37 fredo * lib/PDF/API2/Resource/XObject/Image/GIF.pm: added de-interlacing 2004-03-18 10:43 fredo * lib/PDF/API2.pm: added font search path handling 2004-03-18 07:47 fredo * lib/PDF/API2/Outline.pm: fixed yank/paste error in dest method with -xyz parameter 2004-03-02 22:55 fredo * lib/PDF/API2/Resource/XObject/Image/JPEG.pm: fixed reading jpeg image info marker according to ITU-T T.81 spec 2004-03-02 20:22 fredo * lib/PDF/API2/Basic/PDF/Literal.pm: added missing 'use vars' and fixed xmlexport method 2004-03-02 20:21 fredo * MANIFEST: added missing Version.pm definition 2004-02-24 03:09 fredo * lib/PDF/API2/Basic/PDF/Literal.pm: added initializer code 2004-02-24 03:08 fredo * lib/PDF/API2/Basic/PDF/Utils.pm, MANIFEST: added literal 2004-02-24 02:59 fredo * lib/PDF/API2/Basic/PDF/Literal.pm: genesis 2004-02-24 01:08 fredo * lib/PDF/API2/Resource/CIDFont/CJKFont.pm: added utf8 fallback for encoding 2004-02-24 01:07 fredo * lib/PDF/API2/Resource/CIDFont/CMap/: simplified.pm, traditional.pm: fixed unicode mapping based on adobe's utf32/utf16 specification 2004-02-24 00:34 fredo * lib/PDF/API2/Resource/CIDFont/CMap/korean.pm: fixed unicode mapping based on adobe's utf32/utf16 specification 2004-02-24 00:19 fredo * lib/PDF/API2/Resource/CIDFont/CMap/japanese.pm: fixed unicode mapping based on adobe's ucs2 specification with added vertical encoding 2004-02-23 00:55 fredo * lib/PDF/API2/Annotation.pm: full utf8 awareness 2004-02-23 00:49 fredo * lib/PDF/API2/Resource/CIDFont/CMap/japanese.pm: fixed unicode mapping based on adobe's ucs2 specification 2004-02-23 00:45 fredo * lib/PDF/API2/HOWTO.pod: added pdftk tool comment 2004-02-19 03:07 fredo * lib/PDF/API2/Resource/CIDFont/CJKFont/: adobemingstdlightacro.pm, adobemyungjostdmediumacro.pm, adobesongstdlightacro.pm: updated to acrobat 6 standard 2004-02-19 01:37 fredo * lib/PDF/API2/HOWTO.pod: added interoperability section 2004-02-18 15:05 fredo * lib/PDF/API2/Basic/PDF/Filter.pm: updated lzwdecode with code take from the gif module 2004-02-18 15:04 fredo * lib/PDF/API2/Basic/PDF/: Dict.pm, Name.pm: fixed name/key encoding regardless of pdf-version (who uses ancient but conforming pdf 1.0/1.1 anymore?) 2004-02-13 11:56 fredo * lib/PDF/API2/HOWTO.pod: added hello world example 2004-02-12 21:33 fredo * MANIFEST: added shapes: line, polyline, polygon 2004-02-12 21:26 fredo * lib/PDF/API2/Shape/polygon.pm: initial import 2004-02-12 21:20 fredo * lib/PDF/API2/: Shape.pm, Shape/line.pm, Shape/polyline.pm: updated new method for options 2004-02-12 21:10 fredo * lib/PDF/API2/Shape/: line.pm, polyline.pm: initial import 2004-02-12 17:55 fredo * lib/PDF/API2/Shape.pm: added release method, fixed render methods 2004-02-12 17:40 fredo * lib/PDF/API2/Shape.pm: initial import 2004-02-12 15:48 fredo * lib/PDF/API2/Resource/XObject/Image/: PNG.pm, GIF.pm: removed duplicate definition of $fh 2004-02-12 15:46 fredo * lib/PDF/API2/Content.pm: removed duplicate definition of egstate method 2004-02-12 15:41 fredo * examples/031_color_hsv: initial import 2004-02-12 15:40 fredo * examples/030_colorspecs: moved HSV to own example 2004-02-12 15:39 fredo * lib/PDF/API2/Util.pm: start work on better HSV code 2004-02-12 15:38 fredo * lib/PDF/API2.pm: added openScalar method 2004-02-12 15:38 fredo * lib/PDF/API2/IOString.pm: added import_from_scalar method 2004-02-10 16:55 fredo * lib/PDF/API2/Resource/Font/SynFont.pm: fixed glyph generation for .notdef glyphs 2004-02-10 16:54 fredo * examples/021_synfonts: modified to use all corefonts 2004-02-10 16:53 fredo * lib/PDF/API2/Util.pm: corrected pdfkeys 2004-02-06 03:01 fredo * lib/PDF/API2/Content.pm: added save/restore around textlabel 2004-02-06 00:24 fredo * lib/PDF/API2/Content.pm: fixed lab behavior 2004-02-05 23:35 fredo * examples/030_colorspecs: added rgb gamma 2004-02-05 23:21 fredo * lib/PDF/API2/Util.pm: fixed lab behavior 2004-02-05 23:17 fredo * examples/030_colorspecs: initial import 2004-02-05 17:13 fredo * lib/PDF/API2/Util.pm: fixed namecolor methods 2004-02-05 14:33 fredo * lib/PDF/API2/Annotation.pm: added unicode handling to strings 2004-02-05 14:27 fredo * lib/PDF/API2/Basic/PDF/String.pm: corrected utf8 behavior according to '3.8.1 Text Strings', U+FEFF indicating UTF-16BE (big-endian) 2004-02-05 14:18 fredo * lib/PDF/API2.pm: corrected info hash utf8 usage 2004-02-05 13:28 fredo * MANIFEST: added colorspecs example 2004-02-05 13:26 fredo * lib/PDF/API2/Content.pm: revised '_makecolor' to use Lab for hsv/hsl, added textlabel method 2004-02-05 12:28 fredo * lib/PDF/API2/Util.pm: simplified namecolor, added *_lab/*_cmyk methods, corrected rgb->cmyk conversion to practical parameters 2004-02-05 01:54 fredo * lib/PDF/API2/Basic/PDF/Utils.pm: added "PDFUtf" util method 2004-02-05 01:52 fredo * lib/PDF/API2/Basic/PDF/String.pm: added utf output capability 2004-02-05 00:43 fredo * lib/PDF/API2.pm: pdf info method now properly recognized utf8 parameters 2004-02-02 01:25 fredo * examples/021_synfonts: added caps example 2004-02-01 23:06 fredo * lib/PDF/API2/Resource/Font/SynFont.pm: beautified caps generation 2004-02-01 22:34 fredo * MANIFEST: added PDF::API2::Content::Text::Markup 2004-02-01 22:32 fredo * lib/PDF/API2/Content/Text/Markup.pm: added basic (yet unfinished) parsing code 2004-02-01 20:27 fredo * lib/PDF/API2/Resource/Font/SynFont.pm: fixed width calc for caps 2004-02-01 20:04 fredo * lib/PDF/API2/Resource/Font/SynFont.pm: added caps capability 2004-01-29 10:03 fredo * lib/PDF/API2/Content/Text/Markup.pm: genesis 2004-01-29 09:37 fredo * lib/PDF/API2/Content/symbols.pm: updated comments, added symbol aliases 2004-01-28 15:12 fredo * contrib/: pdf-deoptimize.pl, pdf-optimize.pl: updated licence statement 2004-01-22 15:19 fredo * Makefile.PL: final versioning update for 0.40_17 and beyond 2004-01-22 15:17 fredo * lib/PDF/API2/Basic/PDF/File.pm: added internal object comments feature for future debugging 2004-01-22 00:21 fredo * Makefile.PL: updated logo string 2004-01-21 14:24 fredo * lib/PDF/API2/Version.pm: fixed errorneous use/require behaviour 2004-01-21 13:44 fredo * Makefile.PL: fixed MakeMaker VERSION_FROM parameter 2004-01-21 13:35 fredo * MANIFEST: added changelog.pre 2004-01-21 13:29 fredo * Makefile.PL, lib/PDF/API2.pm, lib/PDF/API2/Version.pm: moved release versioning to PDF::API2::Version 2004-01-21 13:18 fredo * MANIFEST: added full changelog 2004-01-19 21:02 fredo * MANIFEST: added contrib pdf optimize/deoptimize 2004-01-19 20:59 fredo * contrib/: pdf-deoptimize.pl, pdf-optimize.pl: initial import 2004-01-19 15:16 fredo * Makefile.PL, lib/PDF/API2.pm: update for 0.40_16 2004-01-19 15:09 fredo * lib/PDF/API2/Basic/PDF/File.pm: fixed odd ends commenting practice import 2004-01-19 13:51 fredo * lib/PDF/API2/Basic/PDF/File.pm: fix for reportlab's starnge commenting -- removed 2004-01-19 13:47 fredo * lib/PDF/API2/Basic/PDF/File.pm: fix for reportlab's starnge commenting -- ad 1 2004-01-19 13:34 fredo * lib/PDF/API2/Basic/PDF/File.pm: fix for reportlab's starnge commenting 2004-01-15 22:26 fredo * lib/PDF/API2.pm: docbug: fixed inconsistent links 2004-01-14 19:25 fredo * Makefile.PL, lib/PDF/API2.pm: release update 0.40_15 2004-01-14 19:24 fredo * MANIFEST: added missing code128.pm entry 2004-01-12 14:52 fredo * Makefile.PL, lib/PDF/API2.pm: update for 0.40_14 2004-01-09 00:56 fredo * lib/PDF/API2.pm: corrected producer tag versioning, updated to release 0.40_13 2004-01-09 00:54 fredo * lib/PDF/API2/Basic/PDF/String.pm: corrected hex-string import/export with looser spec. 2004-01-08 13:00 fredo * LICENSE: patent statement reformatted 2003-12-08 23:46 Administrator * MANIFEST: added howto and examples: corefont, synfont 2003-12-08 23:42 Administrator * lib/PDF/API2/HOWTO.pod: rudimentary skeleton 2003-12-08 23:12 Administrator * examples/: 020_corefonts, 021_synfonts: inital import 2003-12-08 22:37 Administrator * Makefile.PL: updated copyright date 2003-12-08 14:51 Administrator * README: updated general changelog for 0.40_13 2003-12-08 14:20 Administrator * Makefile: makefile autogen update 2003-12-08 14:15 Administrator * MANIFEST: deleted obsolete docs-dir; added t/00use.t 2003-12-08 14:13 Administrator * t/00use.t: added Log tag 2003-12-08 14:11 Administrator * t/00use.t: new import with proper licencing statement 2003-12-08 14:05 Administrator * lib/PDF/: API2.pm, API2/Annotation.pm, API2/Content.pm, API2/IOString.pm, API2/Lite.pm, API2/Matrix.pm, API2/Outline.pm, API2/Outlines.pm, API2/Page.pm, API2/Resource.pm, API2/Util.pm, API2/Win32.pm, API2/Basic/PDF/Array.pm, API2/Basic/PDF/Bool.pm, API2/Basic/PDF/Dict.pm, API2/Basic/PDF/File.pm, API2/Basic/PDF/Filter.pm, API2/Basic/PDF/Name.pm, API2/Basic/PDF/Null.pm, API2/Basic/PDF/Number.pm, API2/Basic/PDF/Objind.pm, API2/Basic/PDF/Page.pm, API2/Basic/PDF/Pages.pm, API2/Basic/PDF/String.pm, API2/Basic/PDF/Utils.pm, API2/Basic/TTF/AATKern.pm, API2/Basic/TTF/AATutils.pm, API2/Basic/TTF/Anchor.pm, API2/Basic/TTF/Bsln.pm, API2/Basic/TTF/Cmap.pm, API2/Basic/TTF/Coverage.pm, API2/Basic/TTF/Cvt_.pm, API2/Basic/TTF/Delta.pm, API2/Basic/TTF/Fdsc.pm, API2/Basic/TTF/Feat.pm, API2/Basic/TTF/Fmtx.pm, API2/Basic/TTF/Font.pm, API2/Basic/TTF/Fpgm.pm, API2/Basic/TTF/GDEF.pm, API2/Basic/TTF/GPOS.pm, API2/Basic/TTF/GSUB.pm, API2/Basic/TTF/Glyf.pm, API2/Basic/TTF/Glyph.pm, API2/Basic/TTF/Hdmx.pm, API2/Basic/TTF/Head.pm, API2/Basic/TTF/Hhea.pm, API2/Basic/TTF/Hmtx.pm, API2/Basic/TTF/Kern.pm, API2/Basic/TTF/LTSH.pm, API2/Basic/TTF/Loca.pm, API2/Basic/TTF/Manual.pod, API2/Basic/TTF/Maxp.pm, API2/Basic/TTF/Mort.pm, API2/Basic/TTF/Name.pm, API2/Basic/TTF/OS_2.pm, API2/Basic/TTF/OldCmap.pm, API2/Basic/TTF/OldMort.pm, API2/Basic/TTF/PCLT.pm, API2/Basic/TTF/Post.pm, API2/Basic/TTF/PSNames.pm, API2/Basic/TTF/Prep.pm, API2/Basic/TTF/Prop.pm, API2/Basic/TTF/Segarr.pm, API2/Basic/TTF/Table.pm, API2/Basic/TTF/Ttc.pm, API2/Basic/TTF/Ttopen.pm, API2/Basic/TTF/Utils.pm, API2/Basic/TTF/Vhea.pm, API2/Basic/TTF/Vmtx.pm, API2/Basic/TTF/Win32.pm, API2/Basic/TTF/XMLparse.pm, API2/Basic/TTF/Kern/ClassArray.pm, API2/Basic/TTF/Kern/CompactClassArray.pm, API2/Basic/TTF/Kern/OrderedList.pm, API2/Basic/TTF/Kern/StateTable.pm, API2/Basic/TTF/Kern/Subtable.pm, API2/Basic/TTF/Mort/Chain.pm, API2/Basic/TTF/Mort/Contextual.pm, API2/Basic/TTF/Mort/Insertion.pm, API2/Basic/TTF/Mort/Ligature.pm, API2/Basic/TTF/Mort/Noncontextual.pm, API2/Basic/TTF/Mort/Rearrangement.pm, API2/Basic/TTF/Mort/Subtable.pm, API2/Content/symbols.pm, API2/Content/Text.pm, API2/Resource/BaseFont.pm, API2/Resource/CIDFont.pm, API2/Resource/ColorSpace.pm, API2/Resource/ExtGState.pm, API2/Resource/Font.pm, API2/Resource/Shading.pm, API2/Resource/XObject.pm, API2/Resource/CIDFont/CJKFont.pm, API2/Resource/CIDFont/TrueType.pm, API2/Resource/CIDFont/CJKFont/adobemingstdlightacro.pm, API2/Resource/CIDFont/CJKFont/adobemyungjostdmediumacro.pm, API2/Resource/CIDFont/CJKFont/adobesongstdlightacro.pm, API2/Resource/CIDFont/CJKFont/kozgopromediumacro.pm, API2/Resource/CIDFont/CJKFont/kozminproregularacro.pm, API2/Resource/CIDFont/CMap/japanese.pm, API2/Resource/CIDFont/CMap/korean.pm, API2/Resource/CIDFont/CMap/simplified.pm, API2/Resource/CIDFont/CMap/traditional.pm, API2/Resource/CIDFont/TrueType/FontFile.pm, API2/Resource/ColorSpace/Indexed.pm, API2/Resource/ColorSpace/Indexed/ACTFile.pm, API2/Resource/ColorSpace/Indexed/Hue.pm, API2/Resource/ColorSpace/Indexed/WebColor.pm, API2/Resource/Font/CoreFont.pm, API2/Resource/Font/Postscript.pm, API2/Resource/Font/SynFont.pm, API2/Resource/Font/CoreFont/bankgothic.pm, API2/Resource/Font/CoreFont/courier.pm, API2/Resource/Font/CoreFont/courierbold.pm, API2/Resource/Font/CoreFont/courierboldoblique.pm, API2/Resource/Font/CoreFont/courieroblique.pm, API2/Resource/Font/CoreFont/georgia.pm, API2/Resource/Font/CoreFont/georgiabold.pm, API2/Resource/Font/CoreFont/georgiabolditalic.pm, API2/Resource/Font/CoreFont/georgiaitalic.pm, API2/Resource/Font/CoreFont/helvetica.pm, API2/Resource/Font/CoreFont/helveticabold.pm, API2/Resource/Font/CoreFont/helveticaboldoblique.pm, API2/Resource/Font/CoreFont/helveticaoblique.pm, API2/Resource/Font/CoreFont/symbol.pm, API2/Resource/Font/CoreFont/timesbold.pm, API2/Resource/Font/CoreFont/timesbolditalic.pm, API2/Resource/Font/CoreFont/timesitalic.pm, API2/Resource/Font/CoreFont/timesroman.pm, API2/Resource/Font/CoreFont/trebuchet.pm, API2/Resource/Font/CoreFont/trebuchetbold.pm, API2/Resource/Font/CoreFont/trebuchetbolditalic.pm, API2/Resource/Font/CoreFont/trebuchetitalic.pm, API2/Resource/Font/CoreFont/verdana.pm, API2/Resource/Font/CoreFont/verdanabold.pm, API2/Resource/Font/CoreFont/verdanabolditalic.pm, API2/Resource/Font/CoreFont/verdanaitalic.pm, API2/Resource/Font/CoreFont/webdings.pm, API2/Resource/Font/CoreFont/wingdings.pm, API2/Resource/Font/CoreFont/zapfdingbats.pm, API2/Resource/Shading/axial.pm, API2/Resource/XObject/Form.pm, API2/Resource/XObject/Image.pm, API2/Resource/XObject/Form/BarCode.pm, API2/Resource/XObject/Form/Hybrid.pm, API2/Resource/XObject/Form/BarCode/codabar.pm, API2/Resource/XObject/Form/BarCode/code128.pm, API2/Resource/XObject/Form/BarCode/code3of9.pm, API2/Resource/XObject/Form/BarCode/ean13.pm, API2/Resource/XObject/Form/BarCode/int2of5.pm, API2/Resource/XObject/Image/GD.pm, API2/Resource/XObject/Image/GIF.pm, API2/Resource/XObject/Image/JPEG.pm, API2/Resource/XObject/Image/PNG.pm, API2/Resource/XObject/Image/PNM.pm, API2/Resource/XObject/Image/TIFF.pm: corrected to proper licencing statement 2003-12-08 12:55 Administrator * lib/PDF/API2/Annotation.pm: change for proper module versioning 2003-12-08 12:47 Administrator * lib/PDF/API2.pm: change step 3 for proper module versioning 2003-12-08 12:46 Administrator * lib/PDF/API2.pm: change step 2 for proper module versioning 2003-12-08 12:43 Administrator * lib/PDF/API2.pm: change step 1 for proper module versioning 2003-12-08 12:39 Administrator * Makefile.PL: updated for req. perl >= 5.8 of 0.40_13 release 2003-11-30 20:00 Administrator * lib/PDF/API2.pm: added Code128/EAN128 2003-11-30 19:55 Administrator * lib/PDF/API2/Resource/XObject/Form/BarCode/code128.pm: added EAN128 2003-11-30 19:53 Administrator * lib/PDF/API2/Resource/XObject/Form/BarCode/code128.pm: inital import 2003-11-30 19:16 Administrator * AUTHORS: added fredo as default author 2003-11-30 18:36 Administrator * lib/PDF/API2/Resource/XObject/: Form/BarCode/codabar.pm, Form/BarCode/code3of9.pm, Form/BarCode/ean13.pm, Form/BarCode/int2of5.pm, Image/GD.pm, Image/GIF.pm, Image/JPEG.pm, Image/PNG.pm, Image/PNM.pm, Image/TIFF.pm: merged into default 2003-11-30 18:32 Administrator * lib/PDF/API2/Resource/: ColorSpace/Indexed.pm, ColorSpace/Indexed/ACTFile.pm, ColorSpace/Indexed/Hue.pm, ColorSpace/Indexed/WebColor.pm, Font/CoreFont.pm, Font/Postscript.pm, Font/SynFont.pm, Font/CoreFont/bankgothic.pm, Font/CoreFont/courier.pm, Font/CoreFont/courierbold.pm, Font/CoreFont/courierboldoblique.pm, Font/CoreFont/courieroblique.pm, Font/CoreFont/georgia.pm, Font/CoreFont/georgiabold.pm, Font/CoreFont/georgiabolditalic.pm, Font/CoreFont/georgiaitalic.pm, Font/CoreFont/helvetica.pm, Font/CoreFont/helveticabold.pm, Font/CoreFont/helveticaboldoblique.pm, Font/CoreFont/helveticaoblique.pm, Font/CoreFont/symbol.pm, Font/CoreFont/timesbold.pm, Font/CoreFont/timesbolditalic.pm, Font/CoreFont/timesitalic.pm, Font/CoreFont/timesroman.pm, Font/CoreFont/trebuchet.pm, Font/CoreFont/trebuchetbold.pm, Font/CoreFont/trebuchetbolditalic.pm, Font/CoreFont/trebuchetitalic.pm, Font/CoreFont/verdana.pm, Font/CoreFont/verdanabold.pm, Font/CoreFont/verdanabolditalic.pm, Font/CoreFont/verdanaitalic.pm, Font/CoreFont/webdings.pm, Font/CoreFont/wingdings.pm, Font/CoreFont/zapfdingbats.pm, Shading/axial.pm, XObject/Form.pm, XObject/Image.pm, XObject/Form/BarCode.pm, XObject/Form/Hybrid.pm: merged into default 2003-11-30 18:28 Administrator * lib/PDF/API2/Resource/: BaseFont.pm, CIDFont.pm, ColorSpace.pm, ExtGState.pm, Font.pm, Shading.pm, XObject.pm, CIDFont/CJKFont.pm, CIDFont/TrueType.pm, CIDFont/CJKFont/adobemingstdlightacro.pm, CIDFont/CJKFont/adobemyungjostdmediumacro.pm, CIDFont/CJKFont/adobesongstdlightacro.pm, CIDFont/CJKFont/kozgopromediumacro.pm, CIDFont/CJKFont/kozminproregularacro.pm, CIDFont/CMap/japanese.pm, CIDFont/CMap/korean.pm, CIDFont/CMap/simplified.pm, CIDFont/CMap/traditional.pm, CIDFont/TrueType/FontFile.pm: merged into default 2003-11-30 18:23 Administrator * lib/PDF/API2/: Basic/TTF/Mort/Chain.pm, Basic/TTF/Mort/Contextual.pm, Basic/TTF/Mort/Insertion.pm, Basic/TTF/Mort/Ligature.pm, Basic/TTF/Mort/Noncontextual.pm, Basic/TTF/Mort/Rearrangement.pm, Basic/TTF/Mort/Subtable.pm, Content/Text.pm, Content/symbols.pm: merged into default 2003-11-30 18:20 Administrator * lib/PDF/API2/: Util.pm, Win32.pm, Basic/PDF/Array.pm, Basic/PDF/Bool.pm, Basic/PDF/Dict.pm, Basic/PDF/File.pm, Basic/PDF/Filter.pm, Basic/PDF/Name.pm, Basic/PDF/Null.pm, Basic/PDF/Number.pm, Basic/PDF/Objind.pm, Basic/PDF/Page.pm, Basic/PDF/Pages.pm, Basic/PDF/String.pm, Basic/PDF/Utils.pm, Basic/TTF/AATKern.pm, Basic/TTF/AATutils.pm, Basic/TTF/Anchor.pm, Basic/TTF/Bsln.pm, Basic/TTF/Changes, Basic/TTF/Cmap.pm, Basic/TTF/Coverage.pm, Basic/TTF/Cvt_.pm, Basic/TTF/Delta.pm, Basic/TTF/Fdsc.pm, Basic/TTF/Feat.pm, Basic/TTF/Fmtx.pm, Basic/TTF/Font.pm, Basic/TTF/Fpgm.pm, Basic/TTF/GDEF.pm, Basic/TTF/GPOS.pm, Basic/TTF/GSUB.pm, Basic/TTF/Glyf.pm, Basic/TTF/Glyph.pm, Basic/TTF/Hdmx.pm, Basic/TTF/Head.pm, Basic/TTF/Hhea.pm, Basic/TTF/Hmtx.pm, Basic/TTF/Kern.pm, Basic/TTF/LTSH.pm, Basic/TTF/Loca.pm, Basic/TTF/Manual.pod, Basic/TTF/Maxp.pm, Basic/TTF/Mort.pm, Basic/TTF/Name.pm, Basic/TTF/OS_2.pm, Basic/TTF/OldCmap.pm, Basic/TTF/OldMort.pm, Basic/TTF/PCLT.pm, Basic/TTF/PSNames.pm, Basic/TTF/Post.pm, Basic/TTF/Prep.pm, Basic/TTF/Prop.pm, Basic/TTF/Segarr.pm, Basic/TTF/Table.pm, Basic/TTF/Ttc.pm, Basic/TTF/Ttopen.pm, Basic/TTF/Useall.pm, Basic/TTF/Utils.pm, Basic/TTF/Vhea.pm, Basic/TTF/Vmtx.pm, Basic/TTF/Win32.pm, Basic/TTF/XMLparse.pm, Basic/TTF/Kern/ClassArray.pm, Basic/TTF/Kern/CompactClassArray.pm, Basic/TTF/Kern/OrderedList.pm, Basic/TTF/Kern/StateTable.pm, Basic/TTF/Kern/Subtable.pm: merged into default 2003-11-30 18:16 Administrator * lib/PDF/API2/: Outlines.pm, Page.pm, Resource.pm: merged into default 2003-11-30 18:11 Administrator * lib/PDF/API2/: Lite.pm, Matrix.pm, Outline.pm: merged into default 2003-11-30 18:08 Administrator * lib/PDF/API2/: Annotation.pm, Content.pm, IOString.pm: merged into default 2003-11-30 18:05 Administrator * INSTALL: added cvs id 2003-11-30 18:04 Administrator * README, VERSION, lib/PDF/API2.pm: merged into default 2003-11-30 18:01 Administrator * AUTHORS, CONTACT, COPYING, INSTALL, LICENSE, Makefile, Makefile.PL, MANIFEST: merged into default 2003-11-30 17:56 Administrator * AUTHORS, CONTACT, COPYING, INSTALL, LICENSE, MANIFEST, Makefile, Makefile.PL, README, VERSION, lib/PDF/API2.pm, lib/PDF/API2/Annotation.pm, lib/PDF/API2/Content.pm, lib/PDF/API2/IOString.pm, lib/PDF/API2/Lite.pm, lib/PDF/API2/Matrix.pm, lib/PDF/API2/Outline.pm, lib/PDF/API2/Outlines.pm, lib/PDF/API2/Page.pm, lib/PDF/API2/Resource.pm, lib/PDF/API2/Util.pm, lib/PDF/API2/Win32.pm, lib/PDF/API2/Basic/PDF/Array.pm, lib/PDF/API2/Basic/PDF/Bool.pm, lib/PDF/API2/Basic/PDF/Dict.pm, lib/PDF/API2/Basic/PDF/File.pm, lib/PDF/API2/Basic/PDF/Filter.pm, lib/PDF/API2/Basic/PDF/Name.pm, lib/PDF/API2/Basic/PDF/Null.pm, lib/PDF/API2/Basic/PDF/Number.pm, lib/PDF/API2/Basic/PDF/Objind.pm, lib/PDF/API2/Basic/PDF/Page.pm, lib/PDF/API2/Basic/PDF/Pages.pm, lib/PDF/API2/Basic/PDF/String.pm, lib/PDF/API2/Basic/PDF/Utils.pm, lib/PDF/API2/Basic/TTF/AATKern.pm, lib/PDF/API2/Basic/TTF/AATutils.pm, lib/PDF/API2/Basic/TTF/Anchor.pm, lib/PDF/API2/Basic/TTF/Bsln.pm, lib/PDF/API2/Basic/TTF/Changes, lib/PDF/API2/Basic/TTF/Cmap.pm, lib/PDF/API2/Basic/TTF/Coverage.pm, lib/PDF/API2/Basic/TTF/Cvt_.pm, lib/PDF/API2/Basic/TTF/Delta.pm, lib/PDF/API2/Basic/TTF/Fdsc.pm, lib/PDF/API2/Basic/TTF/Feat.pm, lib/PDF/API2/Basic/TTF/Fmtx.pm, lib/PDF/API2/Basic/TTF/Font.pm, lib/PDF/API2/Basic/TTF/Fpgm.pm, lib/PDF/API2/Basic/TTF/GDEF.pm, lib/PDF/API2/Basic/TTF/GPOS.pm, lib/PDF/API2/Basic/TTF/GSUB.pm, lib/PDF/API2/Basic/TTF/Glyf.pm, lib/PDF/API2/Basic/TTF/Glyph.pm, lib/PDF/API2/Basic/TTF/Hdmx.pm, lib/PDF/API2/Basic/TTF/Head.pm, lib/PDF/API2/Basic/TTF/Hhea.pm, lib/PDF/API2/Basic/TTF/Hmtx.pm, lib/PDF/API2/Basic/TTF/Kern.pm, lib/PDF/API2/Basic/TTF/LTSH.pm, lib/PDF/API2/Basic/TTF/Loca.pm, lib/PDF/API2/Basic/TTF/Manual.pod, lib/PDF/API2/Basic/TTF/Maxp.pm, lib/PDF/API2/Basic/TTF/Mort.pm, lib/PDF/API2/Basic/TTF/Name.pm, lib/PDF/API2/Basic/TTF/OS_2.pm, lib/PDF/API2/Basic/TTF/OldCmap.pm, lib/PDF/API2/Basic/TTF/OldMort.pm, lib/PDF/API2/Basic/TTF/PCLT.pm, lib/PDF/API2/Basic/TTF/PSNames.pm, lib/PDF/API2/Basic/TTF/Post.pm, lib/PDF/API2/Basic/TTF/Prep.pm, lib/PDF/API2/Basic/TTF/Prop.pm, lib/PDF/API2/Basic/TTF/Segarr.pm, lib/PDF/API2/Basic/TTF/Table.pm, lib/PDF/API2/Basic/TTF/Ttc.pm, lib/PDF/API2/Basic/TTF/Ttopen.pm, lib/PDF/API2/Basic/TTF/Useall.pm, lib/PDF/API2/Basic/TTF/Utils.pm, lib/PDF/API2/Basic/TTF/Vhea.pm, lib/PDF/API2/Basic/TTF/Vmtx.pm, lib/PDF/API2/Basic/TTF/Win32.pm, lib/PDF/API2/Basic/TTF/XMLparse.pm, lib/PDF/API2/Basic/TTF/Kern/ClassArray.pm, lib/PDF/API2/Basic/TTF/Kern/CompactClassArray.pm, lib/PDF/API2/Basic/TTF/Kern/OrderedList.pm, lib/PDF/API2/Basic/TTF/Kern/StateTable.pm, lib/PDF/API2/Basic/TTF/Kern/Subtable.pm, lib/PDF/API2/Basic/TTF/Mort/Chain.pm, lib/PDF/API2/Basic/TTF/Mort/Contextual.pm, lib/PDF/API2/Basic/TTF/Mort/Insertion.pm, lib/PDF/API2/Basic/TTF/Mort/Ligature.pm, lib/PDF/API2/Basic/TTF/Mort/Noncontextual.pm, lib/PDF/API2/Basic/TTF/Mort/Rearrangement.pm, lib/PDF/API2/Basic/TTF/Mort/Subtable.pm, lib/PDF/API2/Content/Text.pm, lib/PDF/API2/Content/symbols.pm, lib/PDF/API2/Resource/BaseFont.pm, lib/PDF/API2/Resource/CIDFont.pm, lib/PDF/API2/Resource/ColorSpace.pm, lib/PDF/API2/Resource/ExtGState.pm, lib/PDF/API2/Resource/Font.pm, lib/PDF/API2/Resource/Shading.pm, lib/PDF/API2/Resource/XObject.pm, lib/PDF/API2/Resource/CIDFont/CJKFont.pm, lib/PDF/API2/Resource/CIDFont/TrueType.pm, lib/PDF/API2/Resource/CIDFont/CJKFont/adobemingstdlightacro.pm, lib/PDF/API2/Resource/CIDFont/CJKFont/adobemyungjostdmediumacro.pm, lib/PDF/API2/Resource/CIDFont/CJKFont/adobesongstdlightacro.pm, lib/PDF/API2/Resource/CIDFont/CJKFont/kozgopromediumacro.pm, lib/PDF/API2/Resource/CIDFont/CJKFont/kozminproregularacro.pm, lib/PDF/API2/Resource/CIDFont/CMap/japanese.pm, lib/PDF/API2/Resource/CIDFont/CMap/korean.pm, lib/PDF/API2/Resource/CIDFont/CMap/simplified.pm, lib/PDF/API2/Resource/CIDFont/CMap/traditional.pm, lib/PDF/API2/Resource/CIDFont/TrueType/FontFile.pm, lib/PDF/API2/Resource/ColorSpace/Indexed.pm, lib/PDF/API2/Resource/ColorSpace/Indexed/ACTFile.pm, lib/PDF/API2/Resource/ColorSpace/Indexed/Hue.pm, lib/PDF/API2/Resource/ColorSpace/Indexed/WebColor.pm, lib/PDF/API2/Resource/Font/CoreFont.pm, lib/PDF/API2/Resource/Font/Postscript.pm, lib/PDF/API2/Resource/Font/SynFont.pm, lib/PDF/API2/Resource/Font/CoreFont/bankgothic.pm, lib/PDF/API2/Resource/Font/CoreFont/courier.pm, lib/PDF/API2/Resource/Font/CoreFont/courierbold.pm, lib/PDF/API2/Resource/Font/CoreFont/courierboldoblique.pm, lib/PDF/API2/Resource/Font/CoreFont/courieroblique.pm, lib/PDF/API2/Resource/Font/CoreFont/georgia.pm, lib/PDF/API2/Resource/Font/CoreFont/georgiabold.pm, lib/PDF/API2/Resource/Font/CoreFont/georgiabolditalic.pm, lib/PDF/API2/Resource/Font/CoreFont/georgiaitalic.pm, lib/PDF/API2/Resource/Font/CoreFont/helvetica.pm, lib/PDF/API2/Resource/Font/CoreFont/helveticabold.pm, lib/PDF/API2/Resource/Font/CoreFont/helveticaboldoblique.pm, lib/PDF/API2/Resource/Font/CoreFont/helveticaoblique.pm, lib/PDF/API2/Resource/Font/CoreFont/symbol.pm, lib/PDF/API2/Resource/Font/CoreFont/timesbold.pm, lib/PDF/API2/Resource/Font/CoreFont/timesbolditalic.pm, lib/PDF/API2/Resource/Font/CoreFont/timesitalic.pm, lib/PDF/API2/Resource/Font/CoreFont/timesroman.pm, lib/PDF/API2/Resource/Font/CoreFont/trebuchet.pm, lib/PDF/API2/Resource/Font/CoreFont/trebuchetbold.pm, lib/PDF/API2/Resource/Font/CoreFont/trebuchetbolditalic.pm, lib/PDF/API2/Resource/Font/CoreFont/trebuchetitalic.pm, lib/PDF/API2/Resource/Font/CoreFont/verdana.pm, lib/PDF/API2/Resource/Font/CoreFont/verdanabold.pm, lib/PDF/API2/Resource/Font/CoreFont/verdanabolditalic.pm, lib/PDF/API2/Resource/Font/CoreFont/verdanaitalic.pm, lib/PDF/API2/Resource/Font/CoreFont/webdings.pm, lib/PDF/API2/Resource/Font/CoreFont/wingdings.pm, lib/PDF/API2/Resource/Font/CoreFont/zapfdingbats.pm, lib/PDF/API2/Resource/Shading/axial.pm, lib/PDF/API2/Resource/XObject/Form.pm, lib/PDF/API2/Resource/XObject/Image.pm, lib/PDF/API2/Resource/XObject/Form/BarCode.pm, lib/PDF/API2/Resource/XObject/Form/Hybrid.pm, lib/PDF/API2/Resource/XObject/Form/BarCode/codabar.pm, lib/PDF/API2/Resource/XObject/Form/BarCode/code3of9.pm, lib/PDF/API2/Resource/XObject/Form/BarCode/ean13.pm, lib/PDF/API2/Resource/XObject/Form/BarCode/int2of5.pm, lib/PDF/API2/Resource/XObject/Image/GD.pm, lib/PDF/API2/Resource/XObject/Image/GIF.pm, lib/PDF/API2/Resource/XObject/Image/JPEG.pm, lib/PDF/API2/Resource/XObject/Image/PNG.pm, lib/PDF/API2/Resource/XObject/Image/PNM.pm, lib/PDF/API2/Resource/XObject/Image/TIFF.pm: merged into default 2003-11-30 17:47 Administrator * COPYING, LICENSE, lib/PDF/API2.pm: merged into default 2003-11-30 17:00 Administrator * lib/PDF/API2/Resource/XObject/Image/: GD.pm, GIF.pm, JPEG.pm, PNG.pm, PNM.pm, TIFF.pm: added CVS id/log 2003-11-30 16:55 Administrator * lib/PDF/API2/Resource/Shading/axial.pm: added CVS id/log 2003-11-30 16:52 Administrator * lib/PDF/API2/Resource/Font/CoreFont/: bankgothic.pm, courier.pm, courierbold.pm, courierboldoblique.pm, courieroblique.pm, georgia.pm, georgiabold.pm, georgiabolditalic.pm, georgiaitalic.pm, helvetica.pm, helveticabold.pm, helveticaboldoblique.pm, helveticaoblique.pm, symbol.pm, timesbold.pm, timesbolditalic.pm, timesitalic.pm, timesroman.pm, trebuchet.pm, trebuchetbold.pm, trebuchetbolditalic.pm, trebuchetitalic.pm, verdana.pm, verdanabold.pm, verdanabolditalic.pm, verdanaitalic.pm, webdings.pm, wingdings.pm, zapfdingbats.pm: added CVS id/log 2003-11-30 15:45 Administrator * lib/PDF/API2/Resource/Font/: CoreFont.pm, Postscript.pm, SynFont.pm: added CVS id/log 2003-11-30 15:31 Administrator * lib/PDF/API2/Resource/ColorSpace/Indexed/: ACTFile.pm, Hue.pm, WebColor.pm: added CVS id/log 2003-11-30 15:27 Administrator * lib/PDF/API2/Resource/: CIDFont/CJKFont/adobemingstdlightacro.pm, CIDFont/CJKFont/adobemyungjostdmediumacro.pm, CIDFont/CJKFont/adobesongstdlightacro.pm, CIDFont/CJKFont/kozgopromediumacro.pm, CIDFont/CJKFont/kozminproregularacro.pm, ColorSpace/Indexed.pm: added CVS id/log 2003-11-30 15:21 Administrator * lib/PDF/API2/Resource/CIDFont/CMap/: japanese.pm, korean.pm, simplified.pm, traditional.pm: added CVS id/log 2003-11-30 15:16 Administrator * lib/PDF/API2/Resource/CIDFont/TrueType/FontFile.pm: added CVS id/log 2003-11-30 15:13 Administrator * lib/PDF/API2/Resource/CIDFont/: CJKFont.pm, TrueType.pm: added CVS id/log 2003-11-30 14:57 Administrator * README: updated reqirements and support statement 2003-11-30 12:50 Administrator * lib/PDF/API2/Resource/XObject/Form/: BarCode.pm, Hybrid.pm, BarCode/codabar.pm, BarCode/code3of9.pm, BarCode/ean13.pm, BarCode/int2of5.pm: added CVS id/log 2003-11-30 12:44 Administrator * lib/PDF/API2/Resource/: BaseFont.pm, CIDFont.pm, ColorSpace.pm, ExtGState.pm, Font.pm, Shading.pm, XObject.pm, XObject/Form.pm, XObject/Image.pm: added CVS id/log 2003-11-30 12:32 Administrator * lib/PDF/API2/: Util.pm, Page.pm, Outline.pm, Matrix.pm, Lite.pm, IOString.pm, Annotation.pm, Content.pm: added CVS id/log 2003-11-30 00:31 Administrator * lib/PDF/API2/: Outlines.pm, Resource.pm, Win32.pm: added CVS id/log 2003-11-30 00:22 Administrator * MANIFEST: added symbols.pm 2003-11-30 00:20 Administrator * COPYING: removed adobe patent clarification 2003-11-30 00:20 Administrator * LICENSE: addedd CVS Id/Log adobe patent clarification 2003-11-30 00:16 Administrator * README: addedd CVS Id/Log 2003-11-30 00:12 Administrator * lib/PDF/: API2/Content/Text.pm, API2.pm: addedd CVS Id/Log 2003-11-30 00:08 Administrator * lib/PDF/API2/Content/symbols.pm: added arrow and arrowfull definitions 2003-11-29 23:27 Administrator * lib/PDF/API2/Content/symbols.pm: Added CVS Id/Log 2003-11-29 23:26 Administrator * Makefile.PL: Added CVS Id 2003-11-29 23:20 Administrator * Makefile.PL: Added CVS log 2003-11-29 23:17 Administrator * Makefile.PL: Compress::Zlib prereq. downgraded to 1.0 2003-11-16 23:24 Administrator * lib/PDF/API2/Resource/Shading/axial.pm: Initial revision 2003-11-16 23:24 Administrator * lib/PDF/API2/Resource/Shading/axial.pm: no message 2003-11-16 22:55 Administrator * lib/PDF/API2/Resource/Shading.pm: Initial revision 2003-11-16 22:55 Administrator * lib/PDF/API2/Resource/Shading.pm: no message 2003-11-16 05:01 Administrator * lib/PDF/API2/Resource/Font/SynFont.pm: Initial revision 2003-11-16 05:01 Administrator * lib/PDF/API2/Resource/Font/SynFont.pm: no message 2003-11-16 04:05 Administrator * MANIFEST, lib/PDF/API2.pm, Makefile: Initial revision 2003-11-16 04:05 Administrator * MANIFEST, lib/PDF/API2.pm, Makefile: no message 2003-11-16 01:45 Administrator * lib/PDF/API2/Resource/ColorSpace.pm: Initial revision 2003-11-16 01:45 Administrator * lib/PDF/API2/Resource/ColorSpace.pm: no message 2003-11-16 00:57 Administrator * Makefile.PL: Initial revision 2003-11-16 00:57 Administrator * Makefile.PL: no message 2003-11-16 00:41 Administrator * lib/PDF/API2/Resource/Font/CoreFont.pm: Initial revision 2003-11-16 00:41 Administrator * lib/PDF/API2/Resource/Font/CoreFont.pm: no message 2003-11-15 19:51 Administrator * lib/PDF/API2/Resource/XObject/Form/BarCode/: ean13.pm, code3of9.pm: Initial revision 2003-11-15 19:51 Administrator * lib/PDF/API2/Resource/XObject/Form/BarCode/: ean13.pm, code3of9.pm: no message 2003-11-15 19:46 Administrator * AUTHORS: Initial revision 2003-11-15 19:46 Administrator * AUTHORS: no message 2003-11-15 02:45 Administrator * INSTALL, CONTACT, VERSION: Initial revision 2003-11-15 02:45 Administrator * INSTALL, CONTACT, VERSION: no message 2003-11-15 02:41 Administrator * README, LICENSE: Initial revision 2003-11-15 02:41 Administrator * README, LICENSE: no message 2003-11-01 01:36 Administrator * lib/PDF/API2/Content.pm: Initial revision 2003-11-01 01:36 Administrator * lib/PDF/API2/Content.pm: no message 2003-11-01 01:21 Administrator * lib/PDF/API2/Resource/XObject/Form/BarCode/int2of5.pm: Initial revision 2003-11-01 01:21 Administrator * lib/PDF/API2/Resource/XObject/Form/BarCode/int2of5.pm: no message 2003-11-01 00:59 Administrator * lib/PDF/API2/Resource/XObject/Form/BarCode.pm: Initial revision 2003-11-01 00:59 Administrator * lib/PDF/API2/Resource/XObject/Form/BarCode.pm: no message 2003-11-01 00:50 Administrator * lib/PDF/API2/Resource/BaseFont.pm: Initial revision 2003-11-01 00:50 Administrator * lib/PDF/API2/Resource/BaseFont.pm: no message 2003-11-01 00:06 Administrator * lib/PDF/API2/Resource/XObject/Form/BarCode/codabar.pm: Initial revision 2003-11-01 00:06 Administrator * lib/PDF/API2/Resource/XObject/Form/BarCode/codabar.pm: no message 2003-10-08 17:02 Administrator * lib/PDF/API2/Resource/XObject/Image/GD.pm: Initial revision 2003-10-08 17:02 Administrator * lib/PDF/API2/Resource/XObject/Image/GD.pm: no message 2003-10-06 19:39 Administrator * lib/PDF/API2/: Annotation.pm, Basic/PDF/Array.pm, Basic/PDF/Bool.pm, Basic/PDF/Dict.pm, Basic/PDF/File.pm, Basic/PDF/Filter.pm, Basic/PDF/Name.pm, Basic/PDF/Null.pm, Basic/PDF/Number.pm, Basic/PDF/Objind.pm, Basic/PDF/Page.pm, Basic/PDF/Pages.pm, Basic/PDF/String.pm, Basic/PDF/Utils.pm, Basic/TTF/AATKern.pm, Basic/TTF/AATutils.pm, Basic/TTF/Anchor.pm, Basic/TTF/Bsln.pm, Basic/TTF/Cmap.pm, Basic/TTF/Coverage.pm, Basic/TTF/Cvt_.pm, Basic/TTF/Delta.pm, Basic/TTF/Fdsc.pm, Basic/TTF/Feat.pm, Basic/TTF/Fmtx.pm, Basic/TTF/Font.pm, Basic/TTF/Fpgm.pm, Basic/TTF/GDEF.pm, Basic/TTF/GPOS.pm, Basic/TTF/GSUB.pm, Basic/TTF/Glyf.pm, Basic/TTF/Glyph.pm, Basic/TTF/Hdmx.pm, Basic/TTF/Head.pm, Basic/TTF/Hhea.pm, Basic/TTF/Hmtx.pm, Basic/TTF/Kern.pm, Basic/TTF/LTSH.pm, Basic/TTF/Loca.pm, Basic/TTF/Maxp.pm, Basic/TTF/Kern/ClassArray.pm, Basic/TTF/Kern/CompactClassArray.pm, Basic/TTF/Kern/OrderedList.pm, Basic/TTF/Kern/StateTable.pm, Basic/TTF/Kern/Subtable.pm, Basic/TTF/Mort/Chain.pm, Basic/TTF/Mort/Contextual.pm, Basic/TTF/Mort/Insertion.pm, IOString.pm, Lite.pm, Matrix.pm, Outline.pm, Outlines.pm, Page.pm, Basic/TTF/Mort.pm, Basic/TTF/Name.pm, Basic/TTF/OS_2.pm, Basic/TTF/OldCmap.pm, Basic/TTF/OldMort.pm, Basic/TTF/PCLT.pm, Basic/TTF/PSNames.pm, Basic/TTF/Post.pm, Basic/TTF/Prep.pm, Basic/TTF/Prop.pm, Basic/TTF/Segarr.pm, Basic/TTF/Table.pm, Basic/TTF/Ttc.pm, Basic/TTF/Ttopen.pm, Basic/TTF/Useall.pm, Basic/TTF/Utils.pm, Basic/TTF/Vhea.pm, Basic/TTF/Vmtx.pm, Basic/TTF/Win32.pm, Basic/TTF/XMLparse.pm, Basic/TTF/Mort/Ligature.pm, Basic/TTF/Mort/Noncontextual.pm, Basic/TTF/Mort/Rearrangement.pm, Basic/TTF/Mort/Subtable.pm, Content/Text.pm, Resource/CIDFont/CJKFont/adobemingstdlightacro.pm, Resource/CIDFont/CJKFont/adobemyungjostdmediumacro.pm, Resource/CIDFont/CJKFont/adobesongstdlightacro.pm, Resource/CIDFont/CJKFont/kozgopromediumacro.pm, Resource/CIDFont/CJKFont.pm, Resource/CIDFont/CJKFont/kozminproregularacro.pm, Resource/CIDFont/CMap/japanese.pm, Resource/CIDFont/CMap/korean.pm, Resource/CIDFont/CMap/simplified.pm, Resource/CIDFont.pm, Resource/ExtGState.pm, Resource/CIDFont/TrueType.pm, Resource/CIDFont/CMap/traditional.pm, Resource/CIDFont/TrueType/FontFile.pm, Resource/ColorSpace/Indexed.pm, Resource/ColorSpace/Indexed/ACTFile.pm, Resource/ColorSpace/Indexed/Hue.pm, Resource/ColorSpace/Indexed/WebColor.pm, Resource/Font/CoreFont/bankgothic.pm, Resource/Font/CoreFont/courier.pm, Resource/Font/CoreFont/courierbold.pm, Resource/Font/CoreFont/courierboldoblique.pm, Resource/Font/CoreFont/courieroblique.pm, Resource/Font/CoreFont/georgia.pm, Resource/Font/CoreFont/georgiabold.pm, Resource/Font/CoreFont/georgiabolditalic.pm, Resource/Font/CoreFont/georgiaitalic.pm, Resource/Font/CoreFont/helvetica.pm, Resource/Font/CoreFont/helveticabold.pm, Resource/Font/CoreFont/helveticaboldoblique.pm, Resource/Font/CoreFont/helveticaoblique.pm, Resource/Font/CoreFont/symbol.pm, Resource/Font/CoreFont/timesbold.pm, Resource/Font/CoreFont/timesbolditalic.pm, Resource/Font/CoreFont/timesitalic.pm, Resource/Font/CoreFont/timesroman.pm, Resource/Font/CoreFont/trebuchet.pm, Resource/Font/CoreFont/trebuchetbold.pm, Resource/Font/CoreFont/trebuchetbolditalic.pm, Resource/Font/CoreFont/trebuchetitalic.pm, Resource.pm, Util.pm, Win32.pm, Resource/Font.pm, Resource/XObject.pm, Resource/Font/Postscript.pm, Resource/Font/CoreFont/verdana.pm, Resource/Font/CoreFont/verdanabold.pm, Resource/Font/CoreFont/verdanabolditalic.pm, Resource/Font/CoreFont/verdanaitalic.pm, Resource/Font/CoreFont/webdings.pm, Resource/Font/CoreFont/wingdings.pm, Resource/Font/CoreFont/zapfdingbats.pm, Resource/XObject/Form.pm, Resource/XObject/Image.pm, Resource/XObject/Form/Hybrid.pm, Resource/XObject/Image/GIF.pm, Resource/XObject/Image/JPEG.pm, Resource/XObject/Image/PNG.pm, Resource/XObject/Image/PNM.pm, Resource/XObject/Image/TIFF.pm: Initial revision 2003-10-06 19:39 Administrator * lib/PDF/API2/: Annotation.pm, Basic/PDF/Array.pm, Basic/PDF/Bool.pm, Basic/PDF/Dict.pm, Basic/PDF/File.pm, Basic/PDF/Filter.pm, Basic/PDF/Name.pm, Basic/PDF/Null.pm, Basic/PDF/Number.pm, Basic/PDF/Objind.pm, Basic/PDF/Page.pm, Basic/PDF/Pages.pm, Basic/PDF/String.pm, Basic/PDF/Utils.pm, Basic/TTF/AATKern.pm, Basic/TTF/AATutils.pm, Basic/TTF/Anchor.pm, Basic/TTF/Bsln.pm, Basic/TTF/Cmap.pm, Basic/TTF/Coverage.pm, Basic/TTF/Cvt_.pm, Basic/TTF/Delta.pm, Basic/TTF/Fdsc.pm, Basic/TTF/Feat.pm, Basic/TTF/Fmtx.pm, Basic/TTF/Font.pm, Basic/TTF/Fpgm.pm, Basic/TTF/GDEF.pm, Basic/TTF/GPOS.pm, Basic/TTF/GSUB.pm, Basic/TTF/Glyf.pm, Basic/TTF/Glyph.pm, Basic/TTF/Hdmx.pm, Basic/TTF/Head.pm, Basic/TTF/Hhea.pm, Basic/TTF/Hmtx.pm, Basic/TTF/Kern.pm, Basic/TTF/LTSH.pm, Basic/TTF/Loca.pm, Basic/TTF/Maxp.pm, Basic/TTF/Kern/ClassArray.pm, Basic/TTF/Kern/CompactClassArray.pm, Basic/TTF/Kern/OrderedList.pm, Basic/TTF/Kern/StateTable.pm, Basic/TTF/Kern/Subtable.pm, Basic/TTF/Mort/Chain.pm, Basic/TTF/Mort/Contextual.pm, Basic/TTF/Mort/Insertion.pm, IOString.pm, Lite.pm, Matrix.pm, Outline.pm, Outlines.pm, Page.pm, Basic/TTF/Mort.pm, Basic/TTF/Name.pm, Basic/TTF/OS_2.pm, Basic/TTF/OldCmap.pm, Basic/TTF/OldMort.pm, Basic/TTF/PCLT.pm, Basic/TTF/PSNames.pm, Basic/TTF/Post.pm, Basic/TTF/Prep.pm, Basic/TTF/Prop.pm, Basic/TTF/Segarr.pm, Basic/TTF/Table.pm, Basic/TTF/Ttc.pm, Basic/TTF/Ttopen.pm, Basic/TTF/Useall.pm, Basic/TTF/Utils.pm, Basic/TTF/Vhea.pm, Basic/TTF/Vmtx.pm, Basic/TTF/Win32.pm, Basic/TTF/XMLparse.pm, Basic/TTF/Mort/Ligature.pm, Basic/TTF/Mort/Noncontextual.pm, Basic/TTF/Mort/Rearrangement.pm, Basic/TTF/Mort/Subtable.pm, Content/Text.pm, Resource/CIDFont/CJKFont/adobemingstdlightacro.pm, Resource/CIDFont/CJKFont/adobemyungjostdmediumacro.pm, Resource/CIDFont/CJKFont/adobesongstdlightacro.pm, Resource/CIDFont/CJKFont/kozgopromediumacro.pm, Resource/CIDFont/CJKFont.pm, Resource/CIDFont/CJKFont/kozminproregularacro.pm, Resource/CIDFont/CMap/japanese.pm, Resource/CIDFont/CMap/korean.pm, Resource/CIDFont/CMap/simplified.pm, Resource/CIDFont.pm, Resource/ExtGState.pm, Resource/CIDFont/TrueType.pm, Resource/CIDFont/CMap/traditional.pm, Resource/CIDFont/TrueType/FontFile.pm, Resource/ColorSpace/Indexed.pm, Resource/ColorSpace/Indexed/ACTFile.pm, Resource/ColorSpace/Indexed/Hue.pm, Resource/ColorSpace/Indexed/WebColor.pm, Resource/Font/CoreFont/bankgothic.pm, Resource/Font/CoreFont/courier.pm, Resource/Font/CoreFont/courierbold.pm, Resource/Font/CoreFont/courierboldoblique.pm, Resource/Font/CoreFont/courieroblique.pm, Resource/Font/CoreFont/georgia.pm, Resource/Font/CoreFont/georgiabold.pm, Resource/Font/CoreFont/georgiabolditalic.pm, Resource/Font/CoreFont/georgiaitalic.pm, Resource/Font/CoreFont/helvetica.pm, Resource/Font/CoreFont/helveticabold.pm, Resource/Font/CoreFont/helveticaboldoblique.pm, Resource/Font/CoreFont/helveticaoblique.pm, Resource/Font/CoreFont/symbol.pm, Resource/Font/CoreFont/timesbold.pm, Resource/Font/CoreFont/timesbolditalic.pm, Resource/Font/CoreFont/timesitalic.pm, Resource/Font/CoreFont/timesroman.pm, Resource/Font/CoreFont/trebuchet.pm, Resource/Font/CoreFont/trebuchetbold.pm, Resource/Font/CoreFont/trebuchetbolditalic.pm, Resource/Font/CoreFont/trebuchetitalic.pm, Resource.pm, Util.pm, Win32.pm, Resource/Font.pm, Resource/XObject.pm, Resource/Font/Postscript.pm, Resource/Font/CoreFont/verdana.pm, Resource/Font/CoreFont/verdanabold.pm, Resource/Font/CoreFont/verdanabolditalic.pm, Resource/Font/CoreFont/verdanaitalic.pm, Resource/Font/CoreFont/webdings.pm, Resource/Font/CoreFont/wingdings.pm, Resource/Font/CoreFont/zapfdingbats.pm, Resource/XObject/Form.pm, Resource/XObject/Image.pm, Resource/XObject/Form/Hybrid.pm, Resource/XObject/Image/GIF.pm, Resource/XObject/Image/JPEG.pm, Resource/XObject/Image/PNG.pm, Resource/XObject/Image/PNM.pm, Resource/XObject/Image/TIFF.pm: no message 2003-09-13 20:37 Administrator * COPYING: Initial revision 2003-09-13 20:37 Administrator * COPYING: no message 2003-07-16 17:51 Administrator * lib/PDF/API2/Basic/TTF/Manual.pod: Initial revision 2003-07-16 17:51 Administrator * lib/PDF/API2/Basic/TTF/Manual.pod: no message 2003-04-09 13:13 fredo * lib/PDF/API2/Resource/CIDFont/CJKFont.pm: added/fixed proper alias/substitutions 2003-04-09 13:12 fredo * lib/PDF/API2/Content.pm: documented form-image 2002-10-02 18:47 Administrator * lib/PDF/API2/Basic/TTF/Changes: Initial revision 2002-10-02 18:47 Administrator * lib/PDF/API2/Basic/TTF/Changes: no message PDF-Builder-3.026/INFO/Changes_20200000644000000000000000000004620113772427036014726 0ustar rootrootSee also INFO/Changes-ver_2 for changes released for PDF::API2, and incorporated into PDF::Builder. See also INFO/Changes_2019 for earlier version 3 release logs. 3.021 2020-12-28 Makefile.PL, CONTRIBUTING, INFO/SUPPORT, INFO/old/dist.ini.old, README.md Some cleanup of email addresses and obsolete support venues. Makefile.PL, lib/PDF/Builder.pm, t/00-all-usable.t New minimum version for Image::PNG::Libpng is now 0.56. There was a change introduced in 0.53 that broke PDF::Builder, but has now been fixed. As far as we know, versions 0.47 through 0.52 should still work, if you happen to have that installed, but for automated install/upgrade, the new minimum is now 0.56. lib/PDF/Builder/Resource/XObject/Image/TIFF_GT.pm Added some support for TIFF with alpha channel display [CTS 33, with some help from 'carygravel']. Limited testing due to lack of sample .tif files, and currently not doing anything about transparency mask type or any higher-numbered PhotometricInterpretation types. tools/1_pc.pl, lib/PDF/Builder/Resource/Glyphs.pm, t/gif-png-pnm-rt120397-tiff.t Clean up a few things Perl Critic doesn't like, and exclude a few more frivolous things (in the exclusion list). lib/PDF/Builder.pm, t/00-all-usable.t Consolidate "optional" library versions to make update easier. lib/PDF/Builder/Basic/PDF/File.pm Change grep from expression format to { }, per PDF::API2 change. README.md (added), README (removed), MANIFEST Replace the plain text README with a markdown-formatted README.md lib/PDF/Builder.pm, lib/PDF/Builder/Content-Lite-NamedDestination-UniWrap- Util.pm, lib/PDF/Builder/Basic/PDF/Dict-File-Literal.pm, lib/PDF/Builder/Basic/PDF/Filter/LZWDecode.pm, lib/PDF/Builder/Resource/CIDFont-ColorSpace-ExtGState-Font.pm, lib/PDF/Builder/Resource/CIDFont/CJKFont-TrueType.pm, lib/PDF/Builder/Resource/CIDFont/TrueType/FontFile.pm, lib/PDF/Builder/Resource/ColorSpace/DeviceN-Indexed-Separation.pm, lib/PDF/Builder/Resource/ColorSpace/Indexed/ACTFile-Hue-WebColor.pm, lib/PDF/Builder/Resource/Font/BDFont-CoreFont-Postscript-SynFont.pm, lib/PDF/Builder/Resource/XObject/Image/GD-GIF-PNM-TIFF-TIFF_GT.pm, examples/Windows/Win32.pm, examples/Content-ContentText.pl, examples/021_synfonts-023_cjkfonts-025_unifonts, tools/1_pc.pl, tools/3_examples.pl, t/deprecations.t Change any "no warnings" directive to "use warnings", and fix any resulting issues. This makes perlcritic and CPAN kwalitee a bit happier. For now, just commented out "no warnings". If no reports of problems, will physically remove commented-out lines in 3.022 or later. If you encounter Perl warnings from specific routines, you can uncomment the "no warnings" and comment out "use warnings", to get past the warnings, but please also file a bug report! t/00-all-usable.t, Makefile.PL, lib/PDF/Builder.pm, lib/PDF/Builder/Resource/XObject/Image/TIFF_GT.pm Make both t-tests and runtime a bit more robust if an optional library (Graphics::TIFF and/or Image::PNG::Libpng) is installed, but back-level. 3.020 2020-11-29 lib/PDF/Builder/Content-Outline-NamedDestination.pm, INFO/DEPRECATED Rename previously deprecated names "spline" (to "qbspline") and "pdfile" (to "pdf_file"). examples/042_links Add some examples showing non-default positioning (fit) on target PDF's page. lib/PDF/Builder/Basic/PDF/File.pm Extend cross-reference stream handling (read-in PDFs) to cover field widths of 5, 6, or 7 bytes (40-, 48-, or 56-bit integers). Special case of 8 byte (64-bit integer) where top 32 bits are all 0, is treated as 32-bit integer to avoid requiring a 64-bit Perl build just for unpacking this field. lib/PDF/Builder.pm, lib/PDF/Builder/Docs.pm Per [RT 130722, RT 133131, et al.] get any /Version override (in /Catalog) and update the read-in PDF version (beyond 1.4, even if the PDF header still claims 1.4). This minimizes extraneous warnings about having to bump up the PDF version from what is claimed in the header. Cross-check parent/kids links, report orphaned objects, report objects referenced but not defined, report missing Info and Root objects, etc. The input PDF file or string is not changed, but at least it can give you an idea of why an error occurs, or the resulting PDF does not work correctly. lib/PDF/Builder/Basic/PDF/File.pm, INFO/RoadMap Per [RT 133131, Vadim Repin's fix], change Quad int unpack code from Q to Q> to indicate "Big-Endian" byte order (MSB at left) for incoming data field in a cross-reference stream. Apparently, with just Q, Perl will assume the doubleword int is native format (for instance, Little-Endian on an Intel chip). Note: This is a PDF 1.5+ feature (cross-reference streams) and has no business being in a PDF 1.4 file (the original bug report). Also add warning if imported file declared to be PDF 1.4 (or lower), as cross-reference streams are a PDF 1.5 feature. Earlier fix had added cross-reference stream support, but it really doesn't belong in PDF 1.4. lib/PDF/Builder/Outline.pm, lib/PDF/Builder/Basic/PDF/Objind.pm Per [RT 131657, Vadim Repin's fix] add weaken statements to eliminate "Deep Recursion" error messages. lib/PDF/Builder/Matrix.pm Per latest changes to PDF::API2, some code cleanup in Matrix.pm (no functional change except for adding some diagnostic carps). lib/PDF/Builder.pm Per [PR 139, by ppisar], replace some hard-coded checks for Graphics::TIFF and Image::PNG::Libpng with calls to LA_GT() and LA_IPL(). docs/buildDoc.pl, lib/PDF/Builder/Basic/PDF.pm, MANIFEST Add NAVIGATION LINKS section to go Up to parent(s), sideways to Siblings, and Down to children. This enables you to get from any place in the docs to any place else without (usually) having to go all the way back up to index.html. PDF.pm added just for a place to put links (no code). lib/PDF/Builder.pm, INFO/RoadMap minor updates lib/PDF/Builder.pm, README, INFO/LICENSE Make license-related text more consistent, and attempt to clarify the relationship between the LGPL 2.1 master license and the various other licenses that some files are under, as well as the ability to redistribute under a higher version of LGPL. ref [CTS 35] Makefile.PL, t/author-critic.t, tools/1_pc.pl Update to fix some perlcritic warnings, enable author-critic (not useful, as tools/1_pc.pl does a better job of it). Suggested by 'carygravel', but [PR 135] rejected, as 1_pc is a superset of author-critic function. Can't change .perlcriticrc SEVERITY from 5 to 4, as the GitHub Actions CI testing appears to be using it, leading to a lot of errors. lib/PDF/Builder/Resource/XObject/Image/TIFF/File_GT.pm, t/tiff.t, lib/PDF/Builder/Resource/XObject/Image/TIFF_GT.pm, Makefile.PL, lib/PDF/Builder.pm, lib/PDF/Builder/Resource/XObject/Image/TIFF.pm, Fix problem with reading colormap from TIFF [GH 133], by 'carygravel'. Note that this requires upgrade of Graphics::TIFF from 6 to 7. t/tiff.t upgrade so tests 10 and 11 are no longer always skipped. This works only on a Linux system (definitely not on Windows), and makes use of ImageMagick and Linux utilities 'convert' and 'tiffcp'. Graphics::TIFF is needed for test 10, and test 9 (alpha layer) is still skipped. Thanks to GitHub user 'carygravel' for the upgrade. INFO/DEPRECATED add a couple long-deprecated items ("PDFStr" and "PDFUtf") that were missing from this file. INFO/RoadMap, lib/PDF/Builder/Docs.pm add discussion on why images (especially JPEG) are sometimes rotated and/or flipped, and what can be done about it. t/fonts-synfont.t, t/fonts-ttf.t fix a couple paths to DejaVu fonts on certain Linux boxes. From 'gregoa' at Debian Perl Group. lib/PDF/Builder/Resource/XObject/Image/PNM.pm Bi-level (1 bit per pixel) PNM/PBM image was not being handled correctly if the row length (width) was not a multiple of 8. Not enough data was copied over to the PDF. Continuation of [RT 132844]. Almost complete rewrite of PNM.pm to properly support all combinations of comments in the header, and support "plain" (ASCII) image files (P1..P3) and 16 bit samples for grayscale and RGB. Not yet supporting multiple images per file, as I don't have any firm definition! lib/PDF/Builder/Resource/XObject/Image/PNG_IPL.pm Make use of the new 'split_alpha' call in new release 0.47 of Image::PNG::Libpng (this version specified as minimum, for optional library installation). This brings the speed for RGB and Gray scale with Alpha channels up to reasonable levels, as the 'vec' call is no longer called (4 or 8 times per pixel). Note that in contrast to PDF::API2, both 8 and 16bps samples are supported, and Gray scale is supported, at high speed; not just 8bps RGBA. lib/PDF/Builder/Docs.pm, Makefile.PL, README, t/00-all-usable.t PDF::Builder will (again) attempt to install or upgrade OPTIONAL libraries (see README). Includes a warning in Makefile.PL not to be unduly alarmed if an optional install should fail. The user is given a choice of selecting none/all/specific optional libraries when running Makefile.PL (default "all"). README add instructions for installing on pre-5.020 Perls, which may be adaptable to other OS's and Perls. Note that there's no guarantee that PDF::Builder will actually RUN on older Perls! (But you're welcome to try.) lib/PDF/Builder/Docs-Content.pm, lib/PDF/Builder/Content/Text.pm Fix spelling errors/typos, per report by 'carygravel'. lib/PDF/Builder/Resource/PaperSizes.pm Fix a couple missized entries (B7 and jr-Legal), added a bunch more sizes (mostly archaic American and British sizes): dbill, statement (= student), half-letter (= student), old-paper, b-plus (B+/Super-B/A3+/super-A3), arch-a, arch-b, arch-c, arch-d, arch-e, arch-e1, pott, post, large-post, crown, large-crown, demy, small-demy, medium, royal, small-royal, super-royal, imperial, a7, a8, a9, a10. Note that some "standard" sizes, such as broadsheet and foolscap, seem to have a different size specification depending on where you look. You should check that the size used matches your actual paper supply, and to either update PaperSizes.pm to match, or specify the MediaBox in points instead of by name. This is probably a good idea with any unusual, large, archaic, or special-order paper... you want to check what its actual size is before going through a lot of expensive failed printing! examples/HarfBuzz.pl, examples/resources/HarfBuzz_example.pdf In the updated 3.019 example, note that the entire AdobeMingStd-Light.otf font (ttfont call) appears to be embedded, rather than just the subset. This resulted in 3.019 being about 8MB larger than 3.018's version! It may be related to bug [RT 130041]. Use caution when embedding CJK fonts, even when not using the cjkfont call, as at least some apparently don't subset. I replaced the font with AdobeGothicStd-Light.otf, which appears to embed just a subset of the font, greatly reducing the size of the PDF file. 3.019 2020-07-27 lib/PDF/Builder/Content/Text.pm Per [CTS 31], expand documentation of textlabel() call to emphasize that it is a standalone call, and doesn't play nicely with other text-output calls (such as not leaving a current position for the next write). It is intended for one-off labels, etc. lib/PDF/Builder/Content.pm, examples/HarfBuzz.pl, examples/resources/HarfBuzz_example.pdf Support TTB (top to bottom) and BTT (bottom to top) vertical text in textHS(), now that HarfBuzz::Shaper supports these modes. Requires HarfBuzz::Shaper 0.23 or higher for TTB and BTT support, 0.21 for just LTR and RTL support. The "example" PDF is provided in case you don't yet have HarfBuzz::Shaper installed, and want to see what it does. TTB is recommended for both normally RTL (bidirectional) and LTR languages. Vertical writing is most often used with East Asian languages. .perl-version, Makefile.PL, README New minimum Perl version 5.20, which is already 6 years old, so we don't waste a lot of time chasing down bugs due to ancient Perl versions. PDF::Builder will likely work with older Perl versions, but your installer (e.g., cpan or cpanm) might refuse to install it. examples/042_links, examples/README, examples/examples_output, tools/3_examples.pl, lib/PDF/Builder/Annotation.pm, MANIFEST Per [CTS 29], improved documentation of annotation-based links: PDF links and targets. lib/PDF/Builder/Content.pm, lib/PDF/Builder/Resource/XObject/Image/PNM.pm image() and form_image() calls default x,y to 0,0, so can call without lower left corner x,y. PNM processing [RT 132844] fix routine forgetting where it is in the PNM file and failing to read part of it. Note that 132844 is still open, as PNM handling has not yet been thoroughly checked. lib/PDF/Builder/Resource/XObject/Image/PNG-PNG_IPL.pm ref PR #25 for PDF::API2. Some have reported that apparently there can be some cases where the deletion of some streams may cause errors in the vec() calls. This may be dependent on the Perl version, use of nonstandard flags (such as -e), or other unusual usage. lib/PDF/Builder/Resource/Font/CoreFont/courier-courierbold-courieroblique- courierboldoblique-helvetica-helveticabold-helveticaoblique- helveticaboldoblique-timesroman-timesbold-timesitalic-timesbolditalic- symbol-zapfdingbats.pm, t/text.t In 3.018, the Core Font metrics (in particular, the 'wx' character widths) were changed to use the values in the TTF files actually used (at least, on Windows systems). Per [CTS 27] et al., I received complaints about 3.018 not using the exact Adobe font metrics for Core Fonts as before. I have gone back to using the canonical Adobe metrics, even though (for core fonts) this is likely to result in a small mismatch between the indicated glyph width and the actual glyph displayed. In most cases it's just one glyph grid unit wider (e.g., 667 instead of 666), which should have no visible effect in any real document. However, there were a handful of (rather esoteric) glyphs where the difference was considerable. I compared the claimed widths for both Adobe metrics and the TTF metrics, and picked one or the other, or even devised a new width. These are documented in the .pm files under 'wx' (widths). Note that these are only the base 14 core fonts. The 15 Windows fonts were not changed, as there is no Adobe AFM standard for them. INFO/CONVERSION, MANIFEST, README add conversion info for going from PDF::API2 to PDF::Builder. INFO/RoadMap minor updates 3.018 2020-04-24 lib/PDF/Builder/Content.pm-Page.pm [RT 132403] clarify documentation on the two different rotate() methods. lib/PDF/Builder/Content/Hyphenate_basic.pm, lib/PDF/Builder/Content.pm- Docs.pm, lib/PDF/Builder/Resource/BaseFont.pm, examples/HarfBuzz.pl, examples/resources/HarfBuzz_example.pdf, examples/examples.output, examples/README, tools/3_examples.pl, INFO/old/examples.bat, Makefile.PL, README, MANIFEST Implement support for use of HarfBuzz::Shaper (to shape chunks of text). [RT 113700] This is an optional installation (manually done). examples/HarfBuzz.pl will not run if you do not have HarfBuzz::Shaper installed. HarfBuzz_example.pdf is provided in examples/resources/ in case you can't (yet) run HarfBuzz.pl. It demonstrates the use of HarfBuzz::Shaper for a variety of Western (ligatures and kerning), Middle Eastern (script and RTL), and South and Southeast Asian scripts. lib/PDF/Builder/Content.pm Add 'none' option to text underline and strikethrough options. This was added to permit the option (underline or strikethrough) to be given in the code, but allow a 'none' value in those cases where drawing an underline or strikethrough is not desired. This is still the default. examples/021_synfonts, examples/examples.output, examples/README The synthetic font example only showed for regular BankGothic font. Added bold, bold-italic, and italic cases. Note that there is something a bit odd about Bank Gothic -- it looks like it may only have regular weight (no bold) and the italic is questionable. tools/TTFdump.pl, MANIFEST, lib/PDF/Builder/Resource/Font/CoreFont.pm, lib/PDF/Builder/Resource/BaseFont.pm, examples/022_truefonts, lib/PDF/Builder/Resource/Font/CoreFont/courier*.pm- helvetica*.pm-times*.pm-georgia*.pm-trebuchet*.pm-verdana*.pm Add full set of glyph widths to core font metrics files [RT 57248]. This is intended to allow correct rendering of non-Latin-1 single byte fonts, by expanding the width listing beyond Latin-1. A utility is provided to read a TTF/OTF font and return glyph lists in a format that can be dropped into a [typeface].pm file. Only glyph widths table was changed (no other metrics). Arial was used for Helvetica metrics, BankGothic could not be found (not sure what's being substituted for it), and various symbology fonts were not changed. Courier "missing width" updated to reflect the character used to indicate a missing glyph. INFO/RoadMap Update some items. Mention other packages PDF::Table, Text::Layout, and HarfBuzz::Shaper that may be useful. lib/PDF/Builder/Resource/CIDFont.pm For TTF (ttfont) fix improper ToUnicode cmap so that a PDF may be searched (was broken in 3.016). lib/PDF/Builder/Content.pm Add example of using add() function to cancel Chrome browser scaling and Y-axis flip before new content is added to an existing PDF. lib/PDF/Builder/Content.pm, lib/PDF/Builder/Content/Text.pm Remind users not to use charspace() when working with a connected (script) font such as Arabic, Devanagari, cursive handwriting, etc. Add -nocs option to text line fill (justified) routines to not use any charspace() values when expanding or shrinking text content to fit. lib/PDF/Builder/Basic/PDF/File.pm. The earlier fix for corrupted xref table only ran under diagnostics. Now only the warning message is under the diagnostics flag (-diags), and the fixup attempt is always run. INFO/Changes_2019, Changes, MANIFEST, lib/PDF/Builder.pm, README, Makefile.PL, INFO/KNOWN_INCOMP 3.017 build/release, 2020 copyright, archive 2019 changes. (see INFO/Changes_2019 for earlier changes) (see INFO/Changes-ver_2 for changes to PDF::API2 up through 2.033) PDF-Builder-3.026/INFO/Changes_20180000644000000000000000000005056013412033451014721 0ustar rootrootSee also Changes-ver_2 for changes released for PDF::API2, and incorporated into PDF::Builder. See also Changes_2017 for earlier version 3 release logs. 3.013 2018-12-27 examples/022_truefonts-022_truefonts_diacrits_utf8-023_cjkfonts- 024_bdffonts-026_unifont2 Minor cleanup to end "dot" line. 3_examples.pl, 4_contrib.pl Minor cleanup to contrib tests, examples -step and -cont command line flag to stop after each test to allow tester to read expected results description (new) and look at PDF file(s) before going on to next test, or run them all in one fell swoop. Note that the failure in 025_unifonts is probably reading the data line right after __END__ (there is no __DATA__). MANIFEST, 1_pc.pl, 2_t-tests.pl, 3_examples.pl, 4_contrib.pl, INFO/old/pc.bat, INFO/old/t-tests.bat, INFO/old/examples.bat, INFO/old/contrib.bat Convert the various test suites from Windows .bat files to Perl .pl files, so that they may be used on any system. Some configuration may need to be adjusted for Linux or Unix systems (such as directory separators and available font file names). The old .bat files have been moved to INFO/old, in case you'd rather use them (they would need to first either be moved back to the root, or their internal paths updated, and checked to see if they need updating). The Perl replacements are numbered in the suggested order for running them (only 3 and 4 are critical to use in that order). examples/BarCode.pl Clean up by consolidating Helvetica font declaration into one place, rather than once per barcode Xobject (much smaller output PDF file). Note that barcodes still appear to have some problems with bars merging with each other. examples/Content.pl Add a sample showing the use of multiple text and graphics objects to have some text under a graphic, and other over it, and change one image to show it rotated and clipped. Makefile.PL Try a different format for bugtracker entry, to point to GitHub issues rather than the default RT ticket system. t/00-all-usable.t Check for optional libraries and do auto-OK only if missing. If an optional library is present, do the normal "use" test. README, MANIFEST Moved README back to the root to shut up Kwalitee's complaint about no README file. lib/PDF/Builder.pm, lib/PDF/Builder/Annotation.pm-NamedDestination.pm- Outline.pm, lib/PDF/Builder/Basic/PDF/Utils.pm, lib/PDF/Builder/Resource/BaseFont.pm-CIDFont.pm, lib/PDF/Builder/Resource/CIDFont/CJKFont.pm, lib/PDF/Builder/Resource/Font/BdFont.pm, t/annotate.t [ref RT 33497, RT 117031] Consolidate PDFStr() and PDFUtf() calls (and associated is_utf() etc. checks) into new function PDFString(), which is given the string and usage code, and returns either PDFStr() or PDFUtf(), based on the usage and whether UTF-8 is permitted for that usage, and what the original string encoding was. This fixes RT 33497, and appears to fix RT 117031 too, as I have not seen any documentation that forbids UTF-8 characters in metadata (PDFString usage 'm'). If such turns up, I will update PDF::Builder::Basic::PDF::Utils to move metadata usage from UTF-8 permitted to disallowed. Various Annotation titles and labels now permit UTF-8 text. Named Destinations currently permit UTF-8, as I have not seen any restrictions against this. Outline titles permit UTF-8. The annotate t-test was updated because PDFUtf() format is no longer forced for annotations. lib/PDF/Builder/Resource/XObject/Image/GIF.pm [ref RT 44877] Fixed library to process GIFs with 3 more types of extension blocks, and updated the POD. The new extension blocks are read, but ignored, so they no longer produce an error. lib/PDF/Builder/Annotation.pm [ref RT 117942] Do some more cleanup of annotations. Unable to get same icon behavior between text and file_attachment, even though the same code is produced. lib/PDF/Builder/Resource/Font/CoreFont/verdana*.pm change "gimel" width from 0 to 620 (but still doesn't show up, gets "invalid character" box marker) lib/PDF/Builder/Resource/Font/CoreFont/times*.pm change "macron" width from 333 to 520 (width was too narrow) lib/PDF/Builder/Resource/Font/CoreFont/helvetica*.pm change "macron" width from 333 to 580 (width was too narrow) lib/PDF/Builder/Resource/Glyphs.pm, uniglyph.txt change character 'dblgrave' (U+F6D6) to 'dblgravecmb' (U+030F) and add width to all CoreFont/*.pm. 020_corefonts, etc. now shows a double grave accent at x0E (where available in a typeface). lib/PDF/Builder/Resource/Glyphs.pm, uniglyph.txt change dotlessj from U+F6BE to U+0237; still not displaying at x1F with my font collection. lib/PDF/Builder/Resource/Font/CoreFont.pm, lib/PDF/examples/020_corefonts, lib/PDF/Builder/Resource/Font/CoreFont/bankgothic.pm enable full bankgothic (not just regular). Unfortunately, this appears to be the older Bank Gothic (not "Pro"), which has only medium weight (bold, bolditalic are no different than regular and italic). Corrected widths on 'mu' (increased from missing/300 to 689) and 'germandbls' (reduced from 1327 to 847). bankgothic.pm is used by all four variants, so at this time there appears to be no need to create bold, italic, and bolditalic versions. (other fonts have different widths for some glyphs in different variants) lib/PDF/Builder/Resource/Font/CoreFont/bankgothic.pm remove 'euro', as the only entry in the font is named 'Euro'. add 'macron' with width. lib/PDF/examples/020_corefonts-ShowFont.pl, lib/PDF/Builder/Resource/Font/BaseFont.pm core fonts with no assigned width, show background of light red to flag them. Add method 'wxMissingByEnc()' to flag a missing core font width. lib/PDF/Builder/Annotation.pm enable dash pattern in -border option. lib/PDF/Builder/NamedDestination.pm remove -border and -rect options from POD, as there seems to be no code to implement them. A link (with -rect and -border) to a Named Destination should be taken care of in the Annotation module. 3.012 2018-10-26 new PNG_IPL module got caught by t/00-all-usable.t on test systems that did not have Image::PNG::Libpng installed. Exclude from test, and add reminder in Makefile.PL to update 00-all-usable.t. 3.011 2018-10-25 move .travis.yml.HOLD and dist.ini.old from the root to INFO/old/, to unclutter the root. It is unknown when and if they will ever be used. lib/PDF/Builder/Annotation.pm [ref RT 125917] minor fix to properly implement a default target page fit (-xyz), otherwise the link() method would not go to the desired target page. Some minor POD updates to indicate that some functionality depends on the PDF reader (e.g., mouseover text on a link). lib/PDF/Builder/Resource/XObject/Image/PNG.pm-PNG_IPL.pm minor POD updates lib/PDF/Builder/Resource/XObject/Image/PNG-PNG_IPL-TIFF-TIFF_GT.pm, Makefile.PL, MANIFEST, lib/PDF/Builder.pm, lib/PDF/Builder/Docs.pm, t/png.t [ref RT 124349] If libpng.a and its wrapper, Image::PNG::Libpng are installed, use them to process PNG files for inclusion into a PDF document. If this library is not installed, or the user directs that it is not be used via the -nouseIPL option, the existing pure Perl PNG library (PNG.pm) will be used. The new library (PNG_IPL.pm) is considerably faster than the old one and offers support for 16 bits per sample and interlaced images*. Documentation has been updated in TIFF and TIFF_GT, and functions LA_GT() and LA_IPL() have been added to Builder to check LibraryAvailability (package availability) for Graphics::TIFF and Image::PNG::Libpng, so you can know in advance whether it is safe to try to use certain image functionality. * interlacing is removed during processing, so it is irrelevant to PDF, and 16bps channels (force PDF 1.5) can be reduced to 8bps, permitting PDF 1.4 output, by use of the -force8bps option. Makefile.PL try directing support issues to GitHub rather than CPAN RT lib/PDF/Builder.pm while working on 124349, I noticed that a partially transparent RGBA PNG file (white background made transparent) with -notrans option was showing as transparent. The problem was found to be that no options given in the image_png() call, such as -notrans, were being passed to the PNG image processing routine. This has been fixed. docs/buildDoc.pl modified to first look for .pod files, and then .pm files for producing documentation .html files. It still has some issues with finding too much input, but is generally workable. The POD search path needs further work, as references to other packages often don't work (don't produce a working link, but a severe error message). lib/PDF/Builder.pm internal routine proc_pages() renamed _proc_pages(), walk_obj() renamed _walk_obj(), and add POD for save() method. There is a release() method that is undocumented but it's not clear whether it's internal. Improve documentation of mediabox and other *box methods. lib/PDF/Builder/Annotation.pm-Matrix.pm-Outline.pm-Page.pm minor POD fixes. There are a lot of low level calls (e.g., Array.pm) that perhaps should not be considered as part of the User API (i.e., remove from POD). lib/PDF/Builder/Outline.pm-NamedDestination.pm-Annotation.pm, INFO/DEPRECATED deprecate pdfile() method and replace by pdf_file() (same as done earlier for Annotation.pm). pdfile() will be removed on or after October, 2020. lib/PDF/Builder/Resource/XObject/Image/TIFF_GT.pm-TIFF.pm, INFO/DEPRECATED remove warning and support for Blackls1 (should be BlackIs1). lib/PDF/Builder/Content.pm, examples/Content.pl [ref RT 124218] add -strikethru text capability similar to -underline. New example of strike-through in Content.pl examples. lib/PDF/Builder.pm [ref #93] Bringing PDF::Builder into the 21st century add -outver option (default: 1.4) to new() as output PDF version. It will be increased by any PDF file read in with a higher PDF level (with message) or by a call to version(). add -msgver option (default: 1) to output (value 1) a warning message when the PDF output version is increased by verCheckInput() or verCheckOutput(). A value of 0 suppresses the warning messages. add verCheckInput(version) to give warning if PDF just read in is of higher PDF version than the current version, and to increase the current version to that level. Implemented for reading of PDF files. WARNING: just because the PDF output version has been increased does NOT guarantee that any particular content will be handled correctly! There are many known cases of PDF 1.5 and up files being read in, that have content that PDF::Builder does not handle correctly, corrupting the resulting PDF. Pay attention to run-time warning messages that the PDF output level has been increased due to a PDF file being read in, and check the resulting file carefully. add verCheckOutput(version, description) to increase the output PDF version if a PDF feature that requires a higher PDF version is requested. At this time, there are no output features higher than 1.4. in version(), give warning if LOWERING the output PDF version (not suppressed by -msgver). lib/PDF/Builder.pm, lib/PDF/Builder/Basic/PDF/File.pm-Name.pm internally store PDF version as full number (e.g., 1.4) instead of just the minor version (e.g., 4), as PDF 2.0 has been announced. t/02-xrefstm.t, t/03-xrefstm-index.t both t-tests read in a PDF-1.5 file, so add a call to new(-outver=>1.5) to silence the warning message that the maximum version is being increased. lib/PDF/Builder/Resource/Basefont.pm-CIDFont.pm-UniFont.pm fix typo variable name $ident to $indent (indentation) lib/PDF/Builder/Resource/UniFont.pm [ref RT 126274/#96] (reporter: fcc_del) by adding missing indentation value to recursive text() call (rather than reporter's more complex fix). lib/PDF/Builder/Content.pm [ref RT 98539] (need to verify flatness function) close. According to PDF spec, there's no real way to tell by eye whether it's within tolerance, and results are unpredictable if you try to force visible line segments with a higher tolerance. Also update POD to clarify the range of permissible tolerance values, and silently clamp the input value to be in that range. 3.010 2018-08-20 .gitignore, Changes, docs/buildDoc.pl, lib/PDF/Builder/Content.pm, lib/PDF/Builder/Resource/XObject/Image/PNG.com fix some minor glitches discovered in final testing lib/PDF/Builder/Basic/PDF/Array.pm-Bool.pm-Dict.pm, lib/PDF/Builder/Content.pm, lib/PDF/Builder/Resource/ColorSpace/DeviceN.pm, lib/PDF/Builder/Resource/XObject/Image/PNG.pm fix some minor POD errors Changes_2017, Changes-ver_2, DEPRECATED, KNOWN_INCOMP, LICENSE, PATENTS, README, SUPPORT move to new INFO/ directory, as things were starting to get a little crowded in the root directory. Changes and MANIFEST are used by the system and can not be moved. MANIFEST updated to reflect new structure. Changes, Changes_2017, MANIFEST split up Change logs by year, to make them easier to handle. docs/, docs/buildDoc.pl, MANIFEST provide a tool and place to build the HTML pages from PODs in the PDF::Builder module sources. The .html files are NOT shipped with either the Perl build or on GitHub. lib/PDF/Builder/Resource/XObject/Image/PNG.pm [ref RT 124349] code cleanup while looking at issue of why PNG RGBA processing is so incredibly slow. Suspect that the heavy use of the Perl vec() call may have something to do with it. To be continued... lib/PDF/Builder/Content.pm, examples/Content.pl, examples/Bspline.pl, t/content.t, MANIFEST, examples.bat [ref CTS 8] add "bspline" method to draw a smoothly continuous curve (using blended cubic Bezier curves) through all the given points. In addition, the first and/or last points may be specified as visible or invisible straight line or curved segments in order to constrain the spline's behavior at the endpoints. lib/PDF/Builder/Content.pm, examples/Content.pl, t/content.t, DEPRECATED [ref CTS 8] change "spline" method name to "qbspline", and deprecate "spline". This is to reflect that this method is actually a piecewise (non-continuous) series of quadratic Bezier curves, and not a true spline. lib/PDF/Builder.pm, lib/PDF/Builder/Docs.pm, MANIFEST Add POD commentary on input and output PDF version supported. Move POD function details out of Builder.pm to a lower level "Docs" routine, in order to reduce the POD clutter. .perl-version, dist.ini.old, .travis.yml.HOLD, Makefile.PL, lib/PDF/Builder.pm, lib/PDF/Builder/UniWrap.pm, MANIFEST change minimum Perl release level from 5.8.6 to Perl 5.16.0, per PDF::API2. The intent is to "support major Perl versions released in the past six years, plus one major release before that one. This should provide backward compatibility for the life of most LTS server distributions, while eliminating the need to troubleshoot warnings and bugs that only show up in increasingly-ancient versions of Perl." For this release, it means that the minimum supported Perl is 5.16 (first released 2012-05-20... see https://www.cpan.org/src/ "First release in each branch of Perl" for dates, NOT "Latest releases in each branch of Perl"!). The next version bump (to 5.18) should be after 2019-05-18. lib/PDF/Builder/Resource/CIDFont/TrueType/FontFile.pm use confess (Carp.pm) rather than die, per PDF::API2. examples/*, examples.bat moved output PDFs for several examples from the current directory to the examples directory, in the same style as the rest of the example outputs. Note that contrib.bat still outputs in the current directory. contrib/text2pdf.pl, examples/020_corefonts--021_psfonts--021_synfonts-- 022_truefonts--022_truefonts_diacrits_utf8--023_cjkfonts--026_unifont2-- ShowFont.pl, examples/Windows/Win32.pm, lib/PDF/Builder.pm, lib/PDF/Builder/Annotation.pm--Content.pm--Lite.pm--Page.pm, lib/PDF/Builder/Basic/PDF/Page.pm--Pages.pm, lib/PDF/Builder/Resource/CIDFont/TrueType/FontFile.pm, lib/PDF/Builder/Resource/XObject/Image/TIFF_GT.pm, t/author-critic.t-- author-pod-syntax.t--font-synfont.t--font-ttf.t--font-type1.t-- rt120397.t--rt120450.t minor code styling changes to make perlcritic (level 5) happy. Some changes from PDF::API2 for level 4/5. t/*, contrib/pdf-debug.pl--text2pdf.pl, examples/012_pages--021_psfonts-- 030_colorspecs--BarCode.pl--Content.pl--ContentText.pl--ShowFont.pl, lib/PDF/Builder/Annotation.pm--Content.pm--Lite.pm--Matrix.pm--Outline.pm-- Page.pm--Resource.pm--UniWrap.pm--Util.pm, lib/PDF/Builder/Content/Text.pm, lib/PDF/Builder/Basic/PDF/Array.pm--Dict.pm--File.pm--Filter.pm-- Literal.pm--Null.pm--Objind.pm--Pages.pm--String.pm, lib/PDF/Builder/Basic/PDF/Filter/FlateDecode.pm--ASCII85Decode.pm, lib/PDF/Builder/Resource/CIDFont.pm--ColorSpace.pm--ExtGState.pm-- Glyphs.pm, lib/PDF/Builder/Resource/CIDFont/CJKFont.pm--TrueType.pm, lib/PDF/Builder/Resource/CIDFont/TrueType/FontFile.pm, lib/PDF/Builder/Resource/Font/CoreFont.pm, lib/PDF/Builder/Resource/XObject/Form/BarCode.pm, lib/PDF/Builder/Resource/XObject/Image/GIF.pm minor code styling changes to make perlcritic (level 4) happy, including adding explicit "return" on all routines where missing, and not using variables $a and $b ("magic" according to perlcritic). Some changes suggested by PDF::API2 for this. There are many other level 4 errors yet to be gotten rid of: "Code before warnings" and "Warnings disabled at" due to use of "no warnings", "Close filehandles as soon as possible" due to too many lines between "open" and "close" calls, "Always unpack @_ first" (perlcritic doesn't like much about using the @_ array), "Subroutine name is a homonym for a builtin function" (e.g., our own "open" in contrast to CORE::open), "Symbols are exported by default" (doesn't like @EXPORT_OK usage). Most other perlcritic level 4 complaints were permanently fixed, but a few, such as "grep" and "map" formats, have been suppressed with "no critic" statements. Those might be revisited later. pc.bat add batch file to run perlcritic lib/PDF/Builder/Page.pm a few minor code styling changes, per PDF::API2. Most of the PDF::API2 changes were already in PDF::Builder, and some I declined because the style was not consistent. examples.bat, examples/024_bdffonts, examples/examples.output some minor improvements to bitmapped (BDF) display output. Bitmap font support is still _very_ buggy! Does anyone actually _use_ bitmapped fonts? lib/PDF/Builder.pm stringify() make sure return value has at least empty string for content. Several cases of -unicodemap check for true, not 1. After PDF::API2 changes for perlcritic. lib/PDF/Builder/Content.pm outobjdeep() check -docompress is true, not 1. bogen() explicitly default move, larger, reverse to "false" (0). isvirtual(), ' apiistext' check for true, not 1. After PDF::API2 changes for perlcritic. lib/PDF/Builder/Basic/PDF/File.pm add support for cross-reference streams (PDF 1.5) using 64-bit field widths, per PDF::API2 changes. .travis.yml.HOLD, MANIFEST name restore (from .tgravis.yml). May attempt at some point to make use of Travis for testing. Currently my system seems to not be supportive of Travis modules, and I don't have a Travis account. I vaguely recall the CPAN system trying to use .travis.yml in my first release, and requiring an immediate release update, so I'm not using the name .travis.yml for now. (see Changes_2017 for earlier changes) (see Changes-ver_2 for changes to PDF::API2 up through 2.033) PDF-Builder-3.026/INFO/ACKNOWLEDGE.md0000644000000000000000000000631514434154226015031 0ustar rootroot# Acknowledgements and Thanks _PDF::Builder_ did not spring fully formed from the forehead of the current maintainer, ready for use. It is the product of many dozens, if not hundreds, of people working on many projects over many years. _PDF::Builder_ makes use of many Perl libraries and packages, as well as (in many cases) underlying open source libraries -- too many to list here (but you can follow the trail of all the `use XXX` entries in the code, if you are so inclined). - Starting with the origins of the package, **Alfred Reibenschuh** built the original _PDF::API2_ library, drawing on work by **Martin Hosken** (_Text::PDF_, via the _Text::PDF::API_ wrapper). - **Steve Simms** took over _PDF::API2_ and has continued to maintain it and extend its functionality. Much of his work is incorporated into _PDF::Builder_ after the latter was forked from the former. - **Cary Gravel** (_Graphics::TIFF_ package) and **Jeffrey Ratcliffe** contributed much work to TIFF image support. - **Ben Bullock** added features to the PNG library to support the needs of this package. - **Johan Vromans** wrote a number of packages, which, while not used by (or directly contributing code to) _PDF::Builder_, did inspire the Font Manager and some aspects of markup language support. His _HarfBuzz::Shaper_ can be used by _PDF::Builder_ applications to support many text shaping features. He also has discussed with us many aspects of text processing that may prove useful in future code and may show up later. - **Vadim Repin** contributed a number of fixes and minor enhancements. - **Davide Cervone** contributed support for allowing _PDF::Builder_ to interface with _MathJax_ (NodeJS) for equation support `(upcoming feature)`. And of course, many thanks to those who reported bugs and requested needed enhancements, sometimes even contributing some code and test cases. These people are usually listed in the `Changes` file, or in the GitHub bug report ticket. A special shout-out goes to **Gregor Herrmann** and **Petr Pisar** for working with us to report and fix problems discovered during packaging of their _Linux_ distributions (which redistribute _PDF::Builder_). ## Sponsorships Thanks also go out to **Andy Beverley** of _Amtivo Group_ for financial sponsorship of the Markdown and HTML formatted input. See also _INFO/SPONSORS_. ## Carrying On... _PDF::Builder_ is Open Source software, built upon the efforts not only of the current maintainer, but also of many people before me. Therefore, it's perfectly fair to make use of the algorithms and even code (within the terms of the LICENSE) for other projects, and even to port them to other languages and platforms (Java, Rust, Python, Typescript, etc.), as well as package _PDF::Builder_ into Linux and other OS distributions. That's how the State of the Art progresses! Just please be considerate and acknowledge the work of others that you are building on, as well as pointing back to this package. Drop us a note with news of your project (if based on the code and algorithms in _PDF::Builder_, or even just heavily inspired by it) and we'll be happy to make a pointer to your work. The more cross-pollination, the better! PDF-Builder-3.026/INFO/Changes_20190000644000000000000000000005146413602677417014747 0ustar rootrootSee also INFO/Changes-ver_2 for changes released for PDF::API2, and incorporated into PDF::Builder. See also INFO/Changes_2018 for earlier version 3 release logs. 3.017 2019-12-31 examples/RMtutorial.pl, examples/Boxes.pl, examples/README, examples/examples.output, MANIFEST, tools/3_examples.pl, INFO/old/examples.bat Rich Measham's tutorial on using PDF::API2, adapted for PDF::Builder. Also a demonstration of the interaction of PDF boxes (media, crop, bleed, trim, art). lib/PDF/Builder/Basic/PDF/File-Pages.pm [RT 131147] fix problem with Null object bubbling up and forcing an improper method invocation. Fix used (by Vadim Repin) is in File.pm, while a narrower scope (and presumably a bit safer) fix (by Klaus Ethgen) is on standby in Pages.pm. examples/Rotated.pl, examples/ShowFont.pl minor cleanup examples/Rotated.pl, examples/README, examples/examples.output, examples/ContentText.pl, MANIFEST, tools/3_examples.pl, INFO/old/examples.bat Demonstrate how to embed rotated pages within a document. CONTRIBUTING, README minor updates INFO/KNOWN_INCOMP general statement about large batch of removals INFO/DEPRECATED, t/content.t, lib/PDF/Builder/Content.pm, lib/PDF/Builder/Resource/ExtGState.pm Remove deprecated method meterlimit() (use correct spelling miterlimit). INFO/DEPRECATED, t/content.t, lib/PDF/Builder/Content.pm Remove deprecated method hspace() (use corrected name hscale). INFO/DEPRECATED, lib/PDF/Builder/Content.pm Remove deprecated dash pattern options -full and -clear (replaced by -pattern option). INFO/DEPRECATED, t/deprecations.t, lib/PDF/Builder/NamedDestination.pm, lib/PDF/Builder/Resource.pm Remove deprecated method new_api() (use new instead). INFO/DEPRECATED, t/papersizes.t, lib/PDF/Builder/Resource/PaperSizes.pm Remove deprecated non-standard paper sizes 4a, 2a, 4b, 2b (use 4a0, 2a0, 4b0, 2b0 standard sizes instead). INFO/DEPRECATED, lib/PDF/Builder/Resource/XObject/Form/BarCode/code3of9.pm Remove deprecated method encode_3of9_string_w_chk() (use encode_3of9_string(*, 1) instead). INFO/DEPRECATED, lib/PDF/Builder/Resource/XObject/Form/BarCode/code3of9.pm Remove deprecated method encode_3of9_w_chk() (use encode_3of9(*, 1, 0) instead). INFO/DEPRECATED, lib/PDF/Builder/Resource/XObject/Form/BarCode/code3of9.pm Remove deprecated method encode_3of9_ext() (use encode_3of9(*, 0, 1) instead). INFO/DEPRECATED, lib/PDF/Builder/Resource/XObject/Form/BarCode/code3of9.pm Remove deprecated method encode_3of9_ext_w_chk() (use encode_3of9(*, 1, 1) instead). INFO/DEPRECATED, lib/PDF/Builder/Resource/XObject/Image.pm Rename deprecated methods imask() to mask() and bpc() to bits_per_component(). INFO/DEPRECATED, lib/PDF/Builder.pm Rename deprecated methods openScalar() to open_scalar() and importpage() to import_page(). INFO/DEPRECATED, lib/PDF/Builder/Annotation.pm Rename deprecated method pdfile() to pdf_file(). lib/PDF/Builder/Resource/XObject/Image/JPEG.pm check for uninitialized var per API2 2.037 Makefile.PL, lib/PDF/Builder/Docs.pm, README Remove "optional" libraries from attempt to install. It was not clear whether they would actually be installed or how users would react to failures to install them. Most of all, there was no information passed to owners of these optional libraries that their efforts were bearing fruit! Just leave them to be manually installed, if desired. lib/PDF/Builder/Resource/Font/Corefont-Postscript-SynFont-BdFont.pm Check -encode for (invalid) multibyte encodings such as UTF*. There are probably more encoding names to be added later (East Asian alphabets, in particular). Bitmapped distribution fonts (BdFont) doesn't appear to support -encode, so remove it from the POD. TrueType fonts (alone) /do/ support multibyte encodings (as do CJK). Ref PDF::API2 PR 20 https://github.com/ssimms/pdfapi2/pull/20. lib/PDF/Builder.pm, lib/PDF/Builder/Page.pm restrict rotate() method to multiple of 90 degrees. Also swap 'Rotate' property test order so that find_prop() not called unnecessariy (ref RT 130722). Clarify in the POD that a positive rotation is clockwise. lib/PDF/Builder/Resource/BaseFont.pm per PDF::API2, default value for returned UniByCId value (when undef), preventing undefined errors. 3.016 2019-08-16 INFO/RoadMap, CONTRIBUTING, MANIFEST, README Add a road map describing where we'd like to take PDF::Builder. examples/024_bdffonts-README-examples.output, lib/PDF/Builder.pm, lib/PDF/Builder/Resource/BaseFont.pm, lib/PDF/Builder/Resource/Font/BdFont.pm, tools/3_examples.pl, INFO/old/examples.bat BDF (bitmapped fonts) now working properly, provided you have a good .bdf file as your starting point. They're ugly enough not to be all that useful, but might be used to decorative effect in chapter titles and major headings (not suitable for body text!). lib/PDF/Builder/Docs.pm, lib/PDF/Builder/Resource/CIDFont/TrueType.pm Improve documentation of ttfont's -nosubset and -noembed flags. lib/PDF/Builder.pm, lib/PDF/Builder/Docs.pm, lib/PDF/Builder/Resource/Font/Postscript.pm [RT 130038] Improve documentation for putting an image on the page, pointing to other sources of information. There are undoubtedly many other "how to do" tasks that need upgraded documentation, and we will attend to them over time. In the meantime, be sure to check out the examples/ Perl programs for numerous examples of how to use calls, and even the t-tests in t/ might prove useful as examples. examples/021_psfonts, lib/PDF/Builder/Docs.com, lib/PDF/Builder.com, lib/PDF/Builder/Resource/Font/SynFont.pm [RT 130040] Confirm that the "synfont" method to modify a font does not seem to work with "CJK" fonts (created by the "cjkfont" method), due to internal font file format differences. Also add "Ipsum Lorem" sample text to 021_psfonts output. docs/buildDoc.pl, lib/PDF/Builder.pm, lib/PDF/Builder/Content.pm- Docs.pm-Page.pm Improvement to documentation generation utility to handle pod2html upgrade to specify URLs with targets (#name), and update some POD that refers to specific targets on a page. It's possible that if you have an earlier Perl level, this might not work properly. lib/PDF/Builder/Resource/CIDFont/TrueType/FontFile.pm, lib/PDF/Builder/Docs.pm, examples/022_truefonts [RT 130041] OTF and TTF "CFF" files were getting the font file embedded in them (by ttfont method), even though there was no link to use that large stream, when -noembed=>1. This has been fixed. Also, the documentation (Docs.pm) has been upgraded to clarify when and how font file embedding is done (especially that it's NOT done for cjkfont). The TrueType example has had a flag added to specify embedding control. lib/PDF/Builder/Resource/BaseFont.pm-CIDFont.pm-UniFont.pm [RT 130074] clarify remaining uses of is_utf8() call that it's utf8::is_utf8(). lib/PDF/Builder.pm, lib/PDF/Builder/Page.pm, lib/PDF/Builder/Docs.pm, INFO/DEPRECATED, INFO/KNOWN_INCOMP, MANIFEST, t/bbox.t, tools/2_t-tests.pl, INFO/old/t-tests.bat [RT 130039] add "get" capability to both global and page bounding box calls, obsoleting the get_* calls for the page. $pdf->mediabox() will return the global media box, $page->mediabox() will return the current page's media box, and so on for bleed, crop, trim, and art boxes. lib/PDF/Builder.pm, lib/PDF/Builder/Basic/PDF/File.pm [GH 101] permit out-of-spec PDF structures that were formerly fatal errors. -diags flag to enable reporting of suspicious structures, otherwise silent. There are many PDFs "in the wild" that do not conform to Adobe PDF standards, yet many Readers are happy to accept them. docs/buildDoc.pl output module (.pm or .pod) being processed, so user won't be worried about how long it's taking. lib/PDF/Builder.pm, lib/PDF/Builder/Resource/UniFont.pm-BaseFont.pm, lib/PDF/Builder/Basic/PDF/Array.pm-Dict.pm-File.pm-Filter.pm-Literal.pm- Objind.pm-Page.pm-Pages.pm-String.pm-Utils.pm, lib/PDF/Builder/Basic/PDF/Filter/FlateDecode.pm, lib/PDF/Builder/Resource/CIDFont/CJKFont.pm-TrueType.pm, lib/PDF/Builder/Resource/CIDFont/TrueType/FontFile.pm, lib/PDF/Builder/Lite.pm-Page.pm-Resource.pm, t/author-critic.t--author-pod-syntax.t--rt126274.t (new), MANIFEST per PDF::API2 changes, code style cleanup (including some minor changes to outobjdeep(), such as removing %options), and some bug fixes not already in PDF::Builder. Also some Perl Critic cleanup and removal of unused routines. contrib/pdf-deoptimize.pl--pdf-optimize.pl, lib/PDF/Builder.pm, lib/PDF/Builder/Basic/PDF/Array.pm-Dict.pm-Objind.pm-Page.pm-Pages.pm, lib/PDF/Builder/Util.pm, INFO/DEPRECATED per PDF::API2 changes, elementsof() changed to elements(). lib/PDF/Builder/Annotation.pm-Content.pm-Outline.pm-Page.pm-Resource.pm, lib/PDF/Builder/Resource/CIDFont.pm-ColorSpace.pm-ExtGState.pm, lib/PDF/Builder/Resource/XObject/Form/Hybrid.pm per PDF::API2 changes, outobjdeep() is no longer destructive (content is no longer removed). Some outobjdeep() calls removed, others simplified. lib/PDF/Builder/Resource/CIDFonts/CMap/*.cmap finish work on [RT 128674] by updating .cmap files to latest. This is difficult because Adobe provides poor documentation, moved to GitHub a couple years back and did not provide good snapshots of previous releases (to see exactly what changed over time), and provides differing levels of up-to-dateness depending on when someone last updated on GitHub (including older supplements!). It's not clear exactly what Adobe version the existing (older) PDF::Builder .cmap files correspond to. In some cases, it appears that they were incomplete at the claimed supplement level. It's not possible to map the cid2code.txt files to PDF::Builder .cmap files in an automated manner because it's not clear which Unicode is to be used in the g2u array when multiple Unicode codepoints map to a given CID. There are some inconsistencies of what CIDs are defined, between the Adobe documentation, what's in the cid2code.txt files, and what's available in Unicode. Suggestions on how to automate cid2code.txt usage would be appreciated. Anyway, this is my best attempt, and corrections accepted! tools/1_pc.pl, 2_t-tests.pl clean up minor bugs, improve diagnostics. 3.015 2019-05-19 The keepers of CPAN declined to re-index PDF::Builder 3.014, which had many reported problems with its load, so I'll kick out 3.015 earlier than I normally would. Hopefully, with a good load, "Testers" will show passed/ failed/other on the Meta page, and PDF::Builder will show up in the reverse dependencies of other products. Perl 5.18 now required minimum level. lib/PDF/Builder.pm, lib/PDF/Builder/Page.pm-Docs.pm [ref CTS 2] allow User Unit specification for PDF (globally) and page. This permits (with suitable Readers) document sizes in excess of 200 inches. lib/PDF/Builder.pm, lib/PDF/Builder/Page.pm-Docs.pm [ref CTS 2] clean up and extend documentation on "box" methods. Allow -orient option on "box" methods to name a page's media, but present in Landscape orientation. Default Media Box of US Letter (8.5in x 11in). lib/PDF/Builder.pm [ref RT 117184] in open(), if read-in PDF is missing an EOL after the final %%EOF, add one so that material added after isn't run-on in comment (most readers can handle this, but better to be clear). lib/PDF/Builder/Basic/PDF/File.pm [ref RT 117184] an empty xref (0 0) is now allowed to go through without tripping the fatal Malformed message. I don't think it's legal PDF, but Acrobat Reader passes it without comment, so I'll let it go (still may produce warning messages). Late add of 'hybrid.pdf' to RT 117184 has a number of problems reported as warnings in PDF::Builder (Acrobat Reader is silent on them), but seems to produce an acceptable PDF. Also don't add an EOL after overwriting the PDF version -- there should already be one there. Finally, there doesn't seem to be any point in explicitly handling a "run-on" header comment as described in RT 117210, as we merely copy the old file to the output (with version updated if necessary). If any Readers have trouble with such and need the comment stripped out, it might be done (1. don't change object offsets, and 2. put the new comment AFTER any binary comment). lib/PDF/Builder/Basic/PDF/Pages.pm [ref CTS 3] remove rebuild_tree() for now, as it has never been properly implemented. Add some comments to CONTRIBUTING pointing to the Software Development Kit. 3.014 2019-04-26 MANIFEST, tools/*.pl move four developmental test .pl files from root into new tools directory. They were not intended to be installed into the Perl lib/PDF/ production directory, but for some reason that's where they were ending up. This change should keep them out of lib/PDF/ when installed via CPAN and the like. lib/PDF/Builder/Basic/PDF/File.pm [ref RT 117184] fix contributed by Vadim Repin to allow PDF::Builder to write out a cross reference stream, if one was read in with an existing PDF (forcing a PDF 1.5 output level). This does not (yet) create an XRef stream from scratch. lib/PDF/Builder.pm, lib/PDF/Builder/Docs.pm update documentation for save(), saveas(), and stringify() to reinforce that the $pdf object is unusable after calling these methods. lib/PDF/Builder/Resource/CIDFont/TrueType/FontFile.pm [ref RT 128674] rewrite CMap handling, with contributions by Alfred Reibenschuh (original PDF::API2 author) and Bob Hallissy (TTF::Font author). Only attempt to use the original four .cmap files, and now only if -usecmf flag set to 1. Otherwise -cmaps flag can set a list of Platform/Encoding pairs in priority order to look for a match in the font's internal cmap tables, or use the default set, or force a lookup with the find_ms() method. In all cases, either one list can be given, and will be used for both Windows and non-Windows platforms, or two lists can be given, separated by a semicolon, with the first one being for a Windows platform and the second for non-Windows. A debug flag -debug may be set to 1 to show various diagnostic information while processing the CMap/.cmap section. Now the default processing is to use the default list of internal cmaps, and if no match is found, call find_ms(), and as a last resort, if there is a .cmap file found, use that. To emulate the old CID mapping, set -usecmf=>1 and -cmaps=>'find_ms'. Various random documentation updates made, particularly regarding the use of "core" fonts, and recommending using TTF/OTF instead. Have not yet found a good data source to generate updated .cmap files for FontFile's use -- still TBD. Could not generate a generic "Adobe:Identity" .cmap file. The ticket is being held open for now as a reminder to deal with .cmap updates. lib/PDF/Builder/Resource/CIDFont/CJKFont.pm notes added as to why FontFile changes not made here (.data and .cmap files are required, no searching of internal cmaps). lib/PDF/Builder/Basic/PDF/File.pm-Objind.pm-Pages.pm [ref RT 121911] fixes contributed by Vadim Repin to deal with the failure of adding new pages to an existing document. This apparently had something to do with circular references, improper 'realise' of objects, and other things. There were three other issues raised in this ticket: rebuild_tree didn't work (already dealt with in PDF::Builder), a useless line of code (already removed from PDF::API2 and PDF::Builder), and LZWDecode/ FlateDecode optimizations (maybe look at again later). lib/PDF/Builder.pm, lib/PDF/Builder/Docs.pm add documentation (POD) explaining how the interaction between text objects and graphics objects may result in (apparently wrong) unexpected order of output (rendering order). lib/PDF/Builder/Content.pm-Docs.pm, examples/Content.pl further explanation (mostly POD) on text and graphics object interactions, and especially the effect on clipping, particularly of text glyphs. examples/022_truefonts add a flag --full (or -f) to force 65536 characters to be output, rather than whatever the count of CIDs is reported in the font. This may be useful for seeing all the defined glyphs if there are gaps in the CID sequence. Makefile.PL, README, lib/PDF/Builder/Docs.pm Move "optional" libraries (modules), currently Graphics::TIFF and Image::PNG::Libpng, to new "recommends" section in Makefile.PL. Your installer MAY attempt to automatically install these as prerequisites. If it does, and fails, no need to panic: they aren't vital to the operation of PDF::Builder, and should NOT cause an overall installation failure! You are free to remove these optional libraries from your Perl installation if you do not plan to use them. More information is in PDF::Builder::Docs. PDF::Builder is now expected to show up in CPAN's listing of "Reverse dependencies" for these libraries. lib/PDF/Builder/Resource/Font/SynFont.pm, lib/PDF/Builder/Docs.pm, lib/PDF/Builder.pm, DEPRECATED, examples/021_synfonts, examples/README, examples/example.output Deprecate -slant option, replacing by -condense, for the option to condense or expand character widths in a synthetic font. Expand and clarify documentation. 021_synfonts add a page of text showing all the options in use together, and command-line type. There is still much to be done to make synthetic fonts completely usable, and I am exploring some alternatives. Fonts are limited to single byte encoding (you may wish to select an alternate plane as a font and run that through synfont()). A major problem I have not been able to solve is the expansion of Latin alphabet ligatures to multiletter capital strings (e.g., ffi to F+F+I) for small-caps usage, as well as small-caps for things like "long s" which are not in the base plane, because the ASCII letters do not appear to be available in other planes. lib/PDF/Builder/Basic/PDF/File.pm [ref RT 106020 and RT 117210] add some tolerance for out-of-spec PDF files. Initially this is permitting a comment between the PDF version number in the header and the EOL, and extra whitespace in the cross reference listing and some other wigglies (e.g., starting object 1, not 0, 0 entries per subsection, lots of warnings). These files don't strictly meet the PDF formatting spec, but many readers seem to tolerate them (fix them up), so PDF::Builder should, too. Note that PDF::Builder already is happy to read a Mac-style PDF using only CR for an EOL (one byte, not the required two). There is one more that I haven't added yet: there are reports of sightings "in the wild" (e.g., RT 106020) of a PDF version header followed by a comment followed by the first object (n 0 obj) before encountering the first $cr. If I can come up with or obtain a "working" PDF like this, I will look into adding tolerance code for it. For future consideration: save header comments (in-line and after header) for output at overall header. Should coordinate with being able to specify a header comment (in .pl code) and possibly comments within objects. Other out-of-spec conditions that most readers tolerate will be added over time. CONTRIBUTING, MANIFEST Add file (at CPAN's request) suggesting how best to contribute to the project. examples/025_unifonts, 3_examples.pl, INFO/old/examples.bat The data used by 025_unifonts (attached PDF-J document) is encoded in SJIS. This is invalid UTF-8 and caused the script to blow up. The fix is to inform Perl that the DATA being read is SJIS, so it can be encoded on the fly to UTF-8. INFO/Changes_2018, Changes, MANIFEST, lib/PDF/Builder.pm, README 2019 copyright, archive 2018 changes. (see INFO/Changes_2018 for earlier changes) (see INFO/Changes-ver_2 for changes to PDF::API2 up through 2.033) PDF-Builder-3.026/docs/0000755000000000000000000000000014534671356013165 5ustar rootrootPDF-Builder-3.026/docs/buildDoc.pl0000644000000000000000000014673014534467445015264 0ustar rootroot#!/usr/bin/perl # buildDoc.pl builds documentation tree from Perl .pod and .pm files (POD) # in case of duplicate names, .pod is used in preference to .pm # # (c) copyright 2018-2022 Catskill Technology Services, LLC # licensed under license used in PDF::Builder package (LGPL 2.1+) # # there is partial code to implement --all to build all PODs, or update an # existing documentation tree with specific name(s), but the whole process # is fast enough that it didn't seem worthwhile to do anything but --all # # -h or --help or (nothing) for help # --all if you have no other command line parameters use strict; use warnings; use Getopt::Long; use Pod::Simple::XHTML; our $VERSION = '3.026'; # VERSION our $LAST_UPDATE = '3.026'; # manually update whenever code is changed # ============= # CONFIGURATION these may be overridden by command-line flags. If reading from # an existing index.html TOC file, the stored values will be # used. # The default settings assume running buildDoc.pl in the docs/ # directory of the product. # --all my $all = ''; # doing --all by default, but still need in command line (else # thinks it's a help request) if no other flag # --libtop=s my $libtop = "../lib"; # source .pm tree e.g., PDF/Builder.pm -> # ../lib/PDF/Builder.pm # assuming run from within docs/ (current directory) # --leading=s my $leading = "PDF"; # optional level(s) below $libtop # / or :: divider between directories # set to '' to omit # --rootname=s my $rootname = "Builder"; # e.g., for PDF::Builder, specify Builder.pm as root file # and Builder/ as top directory, in case there are # other PDF:: entries present. $rootname must NOT # be '' # --output=s my $output = "."; # top of tree where outputting .html files to # $output/$leading/ created under current directory # unless $leading is empty (in which case just use $output) # --toc=s my $TOC = ""; # $output/$TOC is table of contents file (set default once # $rootname is determined) # # --dirsep=s my $dirsep = '/'; # also works for Windows (but not on command line) # --absep=s my $abstract_sep = ' - '; # PDF::Builder style separator between PM name and # the abstract description in NAME entry # --flagorphans to set to 1 my $no_root_link = '0'; # if 1, output info message that no link path from root # very common, and flagged in TOC index.html # --noignore to set to 1 my $not_pm = '0'; # if 1, output info message that non-.pm file ignored # -h or --help to ask for help my $help = '0'; # ============= my ($i, $fname, $bname, $filename, $dirname); my @filelist; # ignored if --all, else is list of files to update existing # doc tree. may be in file path format or PM format my @file_list; # complete list of files (in filepath format). array of hashes # fpname => filepath-format name # ofname => output filepath and name # pmname => PM format name # status => status flag -2 = not processed yet # -1 = scheduled for processing # 0 = no POD (empty .html) # 1 = good .html from POD # 2 = POD errors reported in .html # 3 = errors to stderr (may or may not # be an .html file) # accessible => accessible (from root) flag 0=no 1=yes # abstract => text from NAME POD entry # parents => [] build list of parent(s) chain # siblings => [] build list of any siblings # children => [] build list of any children # command line flags and files if (scalar(@ARGV) == 0) { help(); exit(1); } GetOptions( 'all' => \$all, 'help' => \$help, 'h' => \$help, 'dirsep=s' => \$dirsep, 'absep=s' => \$abstract_sep, 'flagorphans' => \$no_root_link, 'noignore' => \$not_pm, 'libtop=s' => \$libtop, 'leading=s' => \$leading, 'rootname=s' => \$rootname, 'output=s' =>\$output, 'toc=s' => \$TOC, ); # force --all for time being $all = 1; # asked for help? if ($help) { help(); exit(2); } if ($leading eq '""' || $leading eq "''") { $leading = ''; } if ($leading ne '') { $leading =~ s#::#/#g; } if ($rootname eq '""' || $rootname eq "''") { $rootname = ''; } ##print "all='$all', help='$help', dirsep='$dirsep', absep='$abstract_sep',\n"; ##print " flagorphans='$no_root_link', noignore='$not_pm', libtop='$libtop',\n"; ##print " leading='$leading', rootname='$rootname', output='$output', toc='$TOC'\n\n"; if ($rootname eq '') { die "ERROR --rootname must not be empty!\n"; } if ($TOC eq '') { $TOC = $rootname . "_index.html"; } # TBD material for processing individual modules to update docs if (!$all && scalar(@ARGV) >= 1) { while ($fname = $ARGV[0]) { if ($fname =~ m#^-#) { # an UNKNOWN flag to skip over print "$fname WARNING unknown flag skipped\n"; next; } if (index($fname, '::') > -1) { # Perl format dir::dir::dir::module $filename = toFP($fname); } else { # OS format dir/dir/dir/module.pm $filename = $fname; } push @filelist, $filename; } } if ($all) { # any stray stuff? ARGV should be empty by now foreach (@ARGV) { print "WARNING extra command line content '$_' ignored\n"; } # get complete list of filepaths in @file_list and initialize flags @file_list = (); # top level name and dir are the start, then everything in that dir # $libtop/$leading/$rootname.pm may exist, and be first entry # if doesn't exist, all .pm files in that directory are root # then $libtop/$leading/$rootname/ follow all the way down if $rootname # not empty. if it is, all directories in top directory are followed $fname = "$libtop/"; if ($leading ne '') { $fname .= "$leading/"; } $fname .= $rootname; if (-f "$fname.pod" && -r "$fname.pod") { $fname = "$fname.pod"; } else { $fname = "$fname.pm"; } if (!-f $fname) { die "$fname ERROR no $rootname .pod or .pm files found\n"; ## all top-level .pod, .pm files mark as status -1 (.pod has priority over .pm) #@filelist = (); #$dirname = $libtop; #if ($leading ne '') { $dirname .= "/$leading"; } #opendir my $dh, $dirname or die "$dirname ERROR can't open and read directory\n"; #while (my $direntry = readdir $dh) { # if ($direntry eq '.' || $direntry eq '..') { next; } # $fname = "$dirname/$direntry"; # # if it's .pm, check to see if there is a readable .pod of the same name, and if so, # # ignore the .pm file # if (-f $fname) { # # it's a file. readable if .pod or .pm? # if ($fname =~ m#\.pm$#) { # $bname = $fname; # $bname =~ s#\.pm$#.pod#; # if (-f $bname && -r $bname) { next; } # use .pod instead # # if (!-r $fname) { # print "$fname WARNING top-level .pm file not readable\n"; # } else { # push @filelist, $fname; # } # } # if ($fname =~ m#\.pod$#) { # if (!-r $fname) { # print "$fname WARNING top-level .pod file not readable\n"; # } else { # push @filelist, $fname; # } # } # } #} #closedir $dh; } else { if (!-r $fname) { die "$fname ERROR $rootname .pod or .pm file not readable\n"; } # just $rootname.pm is starting point @filelist = ( $fname ); } foreach (@filelist) { push @file_list, { fpname=>$_, # filepath name (full filepath to # .pm/.pod source) ofname=>toOF($_), # output filepath name pmname=>toPM($_), # PM format name e.g., PDF::Builder status=>-1, # status -1 ready to read accessible=>1, # root accessible yes abstract=>'', # no abstract yet parents=>[], # no parents yet siblings=>[], # no siblings yet children=>[], # no children yet depth=>0, # depth of directory }; } if ($rootname eq '') { # should NOT see this # all subdirectories under $libtop/$leading are to be followed @filelist = (); $dirname = $libtop; if ($leading ne '') { $dirname .= "/$leading"; } opendir my $dh, $dirname or die "$dirname ERROR can't open and read directory\n"; while (my $direntry = readdir $dh) { if ($direntry eq '.' || $direntry eq '..') { next; } $fname = "$dirname/$direntry"; if (-d $fname) { # it's a directory, so use it push @filelist, $fname; } } closedir $dh; } else { # only $libtop/$leading/$rootname is to be followed, if exists $dirname = $libtop; if ($leading ne '') { $dirname .= "/$leading"; } if (-d "$dirname/$rootname") { @filelist = ( "$dirname/$rootname" ); } else { @filelist = (); } } # build list of the remaining files foreach (@filelist) { push @file_list, buildList($_, toPM($_)); } } else { # read in existing index.html, add or reset entries in @file_list # as found in @filelist. flags from index.html. if (scalar @filelist == 0) { die "no files given to update\n"; } # TBD ============ not for now } # sort @file_list on hash pmname entry. # just a simple bubble sort (list shouldn't be that long). # sorting after build list, because update might have added a new entry at end for (my $max_i=$#file_list; $max_i>0; $max_i--) { my $swap = 0; # no swaps seen for (my $i=0; $i<$max_i; $i++) { if ($file_list[$i]{'pmname'} gt $file_list[$i+1]{'pmname'}) { # need to swap records i and i+1 # copying one hash to another can be tricky business, so # we'll do it the hard way # parents, siblings, children arrays s/b empty my %temp; $temp{'pmname'} = $file_list[$i]{'pmname'}; $temp{'fpname'} = $file_list[$i]{'fpname'}; $temp{'ofname'} = $file_list[$i]{'ofname'}; $temp{'status'} = $file_list[$i]{'status'}; $temp{'accessible'} = $file_list[$i]{'accessible'}; $temp{'abstract'} = $file_list[$i]{'abstract'}; $temp{'parents'} = $file_list[$i]{'parents'}; $temp{'siblings'} = $file_list[$i]{'siblings'}; $temp{'children'} = $file_list[$i]{'children'}; $temp{'depth'} = $file_list[$i]{'depth'}; $file_list[$i]{'pmname'} = $file_list[$i+1]{'pmname'}; $file_list[$i]{'fpname'} = $file_list[$i+1]{'fpname'}; $file_list[$i]{'ofname'} = $file_list[$i+1]{'ofname'}; $file_list[$i]{'status'} = $file_list[$i+1]{'status'}; $file_list[$i]{'accessible'} = $file_list[$i+1]{'accessible'}; $file_list[$i]{'abstract'} = $file_list[$i+1]{'abstract'}; $file_list[$i]{'parents'} = $file_list[$i+1]{'parents'}; $file_list[$i]{'siblings'} = $file_list[$i+1]{'siblings'}; $file_list[$i]{'children'} = $file_list[$i+1]{'children'}; $file_list[$i]{'depth'} = $file_list[$i+1]{'depth'}; $file_list[$i+1]{'pmname'} = $temp{'pmname'}; $file_list[$i+1]{'fpname'} = $temp{'fpname'}; $file_list[$i+1]{'ofname'} = $temp{'ofname'}; $file_list[$i+1]{'status'} = $temp{'status'}; $file_list[$i+1]{'accessible'} = $temp{'accessible'}; $file_list[$i+1]{'abstract'} = $temp{'abstract'}; $file_list[$i+1]{'parents'} = $temp{'parents'}; $file_list[$i+1]{'siblings'} = $temp{'siblings'}; $file_list[$i+1]{'children'} = $temp{'children'}; $file_list[$i+1]{'depth'} = $temp{'depth'}; $swap = 1; } } if (!$swap) { last; } } # now we have an up-to-date and sorted @file_list of files to process # loop twice: 1. process all status=-1 and their descendants # 2. any status=-2 that are left, warn and change to -1 and repeat my ($any_minus1, $source, $target, $htmlfile, $errorfile); do { $any_minus1 = 0; # haven't set any status -1 this pass for (my $i=0; $inew(); # output to $htmlfile variable, later to $target file my $htmlfile; $p->output_string(\$htmlfile); $p->html_charset('UTF-8'); $p->html_encode_chars(q{&<>'"}); $p->html_doctype(''); # want an index at the top $p->index(1); # parse the file containing POD $p->parse_file($source); # if errors, a section "POD errors" is inserted at the end (also index) # $htmlfile is a string containing output HTML, including errors # no separate .stderr file #if ($target =~ m/Issue155/) { spew($htmlfile, "raw.html"); } # also if only invalid POD if ($htmlfile eq '') { print "$source INFO no POD content\n"; $file_list[$i]{'status'} = 0; $htmlfile = "\n\n$source\n\n"; $htmlfile .= "\nNo documentation (POD) in this module\n\n"; } else { # possibly a good run (OK so far) $file_list[$i]{'status'} = 1; # always put in a title $htmlfile =~ s##$file_list[$i]{'pmname'}#; # add lang="en" to html tag $htmlfile =~ s###; } # POD conversion errors reported? already in index section # empty string if no valid POD at all if ($htmlfile =~ m#id="POD_ERRORS"#) { print "$source ERROR POD errors reported\n"; $file_list[$i]{'status'} = 3; } # examine and modify $htmlfile contents: # # update links (fix href path) # prepare pwd's list of directories, as is reused my $pwd = $target; $pwd =~ s#^$output/##; my @pwd_dirs = split /[\\\/]/, $pwd; # last one is filename, not needed here pop @pwd_dirs; # if first one is empty (was absolute path), discard if (scalar @pwd_dirs > 0 && $pwd_dirs[0] eq '') { shift @pwd_dirs; } # if first one is . discard if (scalar @pwd_dirs > 0 && $pwd_dirs[0] eq '.') { shift @pwd_dirs; } # go through all links in .html that are not #name # format & set any that are still status -2 to -1 for # processing in next loop (also set $any_minus1 = 1) while ($htmlfile =~ m#([^<]+)#g) { my $href = $1; my $linkname = $2; # discard if href is just #name # (an internal link to a heading) or an # external link (http[s]:// ftp:// etc.) if ($href =~ m/^#/) { next; } if ($href =~ m#^[a-z]+://#i) { next; } # strip off /$libtop/ $href =~ s#^/$libtop/##; # make list of dirs in target ($href) my ($path, $target) = split /#/, $href; if (!defined $target) { $target = ''; } my @target_dirs = split /[\\\/]/, $path; # last one is filename, save my $newhref = pop @target_dirs; # if first one is empty (was absolute path), discard if (scalar @target_dirs > 0 && $target_dirs[0] eq '') { shift @target_dirs; } # if first one is . discard if (scalar @target_dirs > 0 && $target_dirs[0] eq '.') { shift @target_dirs; } # now we have two arrays. discard matching # elements until mismatch or one or both empty. # for each element remaining in pwd_dirs, add # a ../ to the front of remaining elements of # target_dirs and form newhref. my @copy_pwd_dirs = @pwd_dirs; while (scalar @copy_pwd_dirs > 0 && scalar @target_dirs > 0) { if ($copy_pwd_dirs[0] eq $target_dirs[0]) { shift @copy_pwd_dirs; shift @target_dirs; } else { last; } } if (scalar @target_dirs > 0) { # something left of target dir (href) $newhref = join($dirsep, @target_dirs).$dirsep.$newhref; } if (scalar @copy_pwd_dirs > 0) { # something left of pwd dir for (my $i=0; $iNAME.*?

(.*?)

#s) { # chop off pmname and any " - " my $abstract = $1; $abstract =~ s#^[^ ]*##; $abstract =~ s#^$abstract_sep##; ## kill any links in the abstract #$abstract =~ s###s; #$abstract =~ s###s; $file_list[$i]{'abstract'} = $abstract; } # write $htmlfile back out to its .html file ($target) spew($htmlfile, $target); $file_list[$i]{'htmlname'} = $target; } # processed a .pod or .pm file into .html (was status -1) } # for loop through all entries, looking for status -1 $any_minus1 = 0; # if there are any -2 status left, warn that they are not reachable # from the root, change them all to -1 and their accessible flag to 0, # set $any_minus1 to 1, and go back to process them for (my $i=0; $i', "$fname/$TOC" or die "$fname/$TOC ERROR unable to open output index file\n"; print $fh "\n"; print $fh "\n\nMaster index for $file_list[0]{'pmname'}"; print $fh "\n\n"; print $fh "\n"; print $fh "\n\n"; print $fh "

T A B L E   O F   C O N T E N T S

\n"; print $fh "X = not accessible from root via chain of links
\n"; print $fh "ERROR = POD errors of some sort reported
\n"; print $fh "(no link) = no POD, so empty .html file generated
\n"; print $fh "
\n"; for (my $i=0; $i "; #} else { # print $fh "X"; #} $fname = $file_list[$i]{'ofname'}; # strip off ./$leading/ if ($leading ne '') { $fname =~ s#\./$leading/##; } if ($file_list[$i]{'status'} == 0) { # no POD at all, empty file. dummy link print $fh ""; print $fh $file_list[$i]{'pmname'}.""; } elsif ($file_list[$i]{'status'} == 1) { # normal, error-free .html output (link) print $fh "$file_list[$i]{'pmname'}"; } else { # 2 or 3 # errors reported, output link + ERROR flag print $fh "$file_list[$i]{'pmname'} - ERROR"; } if ($file_list[$i]{'abstract'} ne '') { # would like to have a
to right side with wrapped content, # rather than one long line that wraps to left side. div with # display:inline-block almost does it, but if too long doesn't # wrap, but puts entire div onto next line # # Pod::Simple::XHTML has expanded L<> to metacpan URL, want our own # # change links to https://metacpan.org/pod/PDF::Builder::... to # ../.. etc. /PDF/Builder/... .html # don't forget some will have #id anchor on the end my $string = $file_list[$i]{'abstract'}; my $pos = 0; while ($pos > -1) { $pos = index $string, "href=\"https://metacpan.org/pod/PDF::"; if ($pos < 0) { last; } $pos += 6; # $pos points to start of a link to metacpan https://... my $pos2 = index $string, "\">", $pos; # $pos2 points to closing "> (which we'll keep) my $strLink = substr($string, $pos+25, $pos2-$pos-25); # $strLink should contain something like "PDF::Builder::Content" # if it contains an anchor (#), split off #anchor_id move $pos2 my $pos3 = index $strLink, "#"; if ($pos3 >= 0) { $pos2 -= length($strLink)-$pos3; # should start at # now $strLink = substr($strLink, 0, $pos3); } # change :: to directory structure $strLink =~ s#::#/#g; # go up by one level, leading PDF/ not needed at this level $strLink = go_up($file_list[$i]{'depth'}) . "../$strLink.html"; $string = substr($string, 0, $pos) . $strLink . substr($string, $pos2); } #print $fh "   -  
$string
"; print $fh "   -   $string"; } print $fh "
\n"; } print $fh "

###

\n"; # TBD within a huge comment write out all the global settings and # the @file_list data. if implement running just a few .pod/.pm's rather than # --all, would read in global settings and @file_list up at the top to # initialize to the point where only revised .pod/.pm's being run get -1 status # and are run normally print $fh "\n\n"; close $fh; # cleanup # now that the individual HTML files and the master index are done, # 1) generate pmnameA array for each entry in @file_list # 2) generate children, siblings, and parents lists # 3) go through all HTML files (ex master index) and update with NAVIGATION if (scalar(@file_list) <= 1) { print "Only 0 or 1 file_list entries. Do not create NAVIGATION LINKS.\n"; exit(0); } make_pmnameA(); my ($j, $ref); process(0, scalar(@file_list)); # entire file_list should have been recursively processed # we have filled in the 'children' of each node. now give each node its # parent, and then siblings do_parents(); # remove duplicate children (grandchildren) AFTER parents set, so that an # element may have chain of parents all the way up to the root remove_grandchildren(); do_siblings(); # update existing HTML files update_HTML(); exit(0); # ================================== sub update_HTML{ my ($i, $fname, $string, @count, $ref, $pos, $newstring, @list); for ($i=0; $i_index.html # count of siblings $ref = $file_list[$i]{'siblings'}; if (defined $ref) { $count[1] = scalar(@$ref); } # count of children $ref = $file_list[$i]{'children'}; if (defined $ref) { $count[2] = scalar(@$ref); } # update link directory at top of file # guaranteed there's at least one parent entry # TBD shouldn't there be at end of indexItem li's? # if empty index list, replace by a real one $pos = index $string, "
"; if ($pos > 0) { # is empty, replace with skeleton of real one $newstring = "
\n" . "
    \n" . "
\n
"; $string = substr($string, 0, $pos) . $newstring . substr($string, $pos+36); } $pos = index $string, "

"; if ($pos < 0) { print "ERROR: can't find link index in file $fname.\n"; next; } $pos -= 8; # new last item in top level list $newstring = "
  • NAVIGATION LINKS\n" . " \n" . "
  • \n"; $string = substr($string, 0, $pos+1) . $newstring . substr($string, $pos+1); # just before will be location of new section $pos = index $string, ""; $pos--; $newstring = "

    NAVIGATION LINKS

    \n"; # if parents (should be), output that section $newstring .= "\n

    Up (Parents)

    \n"; # add ever-present master index entry at same level as [0] entry # note: omitting id= because it's not used anywhere # just a paragraph with each line ending in a break $newstring .= "\n

    " . "Master Index
    \n"; $ref = $file_list[$i]{'parents'}; if (defined $ref && scalar(@$ref)) { # @$ref is an ordered array of @file_list indice(s) # pointing back to any parents @list = @$ref; foreach (@list) { $newstring .= "$file_list[$_]{'pmname'} -- $file_list[$_]{'abstract'}
    \n"; } } $newstring .= "

    \n"; # if any siblings, output that section if ($count[1]) { $ref = $file_list[$i]{'siblings'}; if (defined $ref && scalar(@$ref)) { $newstring .= "\n

    Siblings

    \n

    \n"; # @$ref is an ordered array of @file_list indice(s) # pointing back to any siblings @list = @$ref; foreach (@list) { $newstring .= "$file_list[$_]{'pmname'} -- $file_list[$_]{'abstract'}
    \n"; } $newstring .= "

    \n"; } } # if any children, output that section if ($count[2]) { $ref = $file_list[$i]{'children'}; if (defined $ref && scalar(@$ref)) { $newstring .= "\n

    Down (Children)

    \n

    \n"; # @$ref is an ordered array of @file_list indice(s) # pointing back to any children @list = @$ref; foreach (@list) { $newstring .= "$file_list[$_]{'pmname'} -- $file_list[$_]{'abstract'}
    \n"; } $newstring .= "

    \n"; } } # bottom of page mark $newstring .= "

    ###

    \n"; # write file back out $string = substr($string, 0, $pos+1) . $newstring . substr($string, $pos+1); # change links to https://metacpan.org/pod/PDF::Builder::... to # ../.. etc. /PDF/Builder/... .html # don't forget some will have #id anchor on the end $pos = 0; while ($pos > -1) { $pos = index $string, "href=\"https://metacpan.org/pod/PDF::"; if ($pos < 0) { last; } $pos += 6; # $pos points to start of a link to metacpan https://... my $pos2 = index $string, "\">", $pos; # $pos2 points to closing "> (which we'll keep) my $strLink = substr($string, $pos+25, $pos2-$pos-25); # $strLink should contain something like "PDF::Builder::Content" # if it contains an anchor (#), split off #anchor_id move $pos2 my $pos3 = index $strLink, "#"; if ($pos3 >= 0) { $pos2 -= length($strLink)-$pos3; # should start at # now $strLink = substr($strLink, 0, $pos3); } # change :: to directory structure $strLink =~ s#::#/#g; $strLink = go_up($file_list[$i]{'depth'}) . "$strLink.html"; $string = substr($string, 0, $pos) . $strLink . substr($string, $pos2); } # FIXUP of Pod::Simple::XHTML problems # self-closing tags disallowed in HTML 5 $string =~ s# />#>#g; # current bug: indented paragraphs are

    under

      , which the # validator dislikes. remove
        and change

        to

        # (other solutions would be preferable, but PSX owner has # indicated he plans to do this) $pos = 0; while (1) { $pos = index($string, "
          \n\n

          ", $pos); if ($pos < 0) { last; } # $pos marks beginning of problem section my $pos2 = index($string, "\n

        \n", $pos); if ($pos2 < 0) { last; } # SHOULDN'T happen! # $pos2 marks end of problem section $newstring = substr($string, $pos+6, $pos2-$pos-7); # should be

        through last

        of section $newstring =~ s#

        #

        #gs; $newstring =~ s#

        #
        #gs; # put it back together, omitting the
          and
        tags $string = substr($string, 0, $pos) . $newstring . substr($string, $pos2+6); } spew($string, $fname); } return; } sub go_up { my $depth = shift; # take care of pathological cases where unexpected inputs lead to $depth # being less than 1 (produces Perl error) if ($depth < 1) { return ''; } if ($depth == 1) { return ''; } return '../' x ($depth-1); } # ================================== # recursively process this range of file_list rows, filling in children array # handle a subset (initially the whole thing) of file_list sub process { my ($start, $len) = @_; # starting element number in file_list, and count of rows if ($len <= 1) { return; } # single element won't have any children my ($i, $j, $dir); my ($len2, $ref, $refc); # if $start row's pmnameA is now empty, that means that $start is the # parent of everything else below it $ref = $file_list[$start]{'pmnameA'}; if (scalar(@$ref) == 0) { # element $start is parent to all (1..$len-1) other elements # we want only DIRECT children (leaves), not nodes (grandchildren), # so later we will remove grandchildren (duplicates) $refc = $file_list[$start]{'children'}; for ($j=1; $j<$len; $j++) { push @$refc, $start+$j; } # remove first element (empty pmnameA) from further consideration process($start+1, $len-1); return; } # strip first element from each pmnameA if ALL are duplicates LOOP: while (1) { $ref = $file_list[$start]{'pmnameA'}; last if !scalar(@$ref[0]); # first element is empty? $dir = @$ref[0]; for ($i=1; $i<$len; $i++) { last LOOP if @{ $file_list[$start+$i]{'pmnameA'} }[0] ne $dir; } # if we got to here, entire section's [0] element is the same # so remove it for ($i=0; $i<$len; $i++) { shift @{ $file_list[$start+$i]{'pmnameA'} }; } process($start, $len); return; } # now break up remainder into two subranges (first pmnameA element # is NOT the same in all rows) $len2 = 0; for ($i=$start; $i<$start+$len; $i++) { $ref = $file_list[$i]{'pmnameA'}; if ($len2 == 0) { # should NOT see an empty pmnameA for element start! $dir = @$ref[0]; $len2++; next; } if (@$ref[0] eq $dir) { # still a match $len2++; next; } else { # no longer a match. len2 always at least a run of 1 process($start, $len2); # $len2 .. end is remainder, process it process($start+$len2, $len-$len2); return; } } # for loop through file_list section, first level of chunking return; # probably never hit this } # ================================== # remove an element's grandchildren from its children list sub remove_grandchildren { my ($start, $ref, $refs, $ele, $i, $j); for ($start=1; $start', $fname) or die "$fname ERROR can't open file for output\n"; # warn if a wide character and give string and offset my $first = 1; # only one dump of string for (my $i=0; $i 127) { if ($first) { print "String: '$string'\n"; $first = 0; } print "Wide character ".ord(substr($string, $i, 1))." found at $i\n"; } } print $fh $string; close $fh; return; } # ================================== # function to slurp file into a string, after https://perlmaven.com/slurp sub slurp { my $file = shift; open(my $fh, '<', $file) or die "$file ERROR can't open file for input\n"; local $/ = undef; my $cont = <$fh>; close $fh; return $cont; } # ================================== # create (for .html output files) the chain of directories sub mkdir_list { my $target = $_[0]; my @dirlist = split /[\\\/]/, $target; my $dirstring = ''; for (my $i=0; $i<$#dirlist; $i++) { # note skips last element, which is filename.html # build cumulative string, one directory at a time if ($dirstring eq '') { $dirstring = $dirlist[$i]; } else { $dirstring .= '/'.$dirlist[$i]; } if ($dirlist[$i] eq '.' || $dirlist[$i] eq '..') { next; } # assume exist if (!-d $dirstring) { # doesn't exist yet mkdir $dirstring; } } return; # directory string should exist now for output tree } # ================================== # return list of hashes of filepath name, PM format name, status -2, # accessible yes (so far), abstract '' (so far) # for input directory plus recursively built list for all subdirectories sub buildList { my ($dirname, $PMname) = @_; my @list; # list of hashes to return # build list of files in this directory in @list # explore each subdirectory and append its returned list to @list opendir my $dh, $dirname or die "$dirname ERROR can't open and read directory\n"; while (my $direntry = readdir $dh) { # one child directory, or file, at a time if ($direntry eq '.' || $direntry eq '..') { next; } if (-f "$dirname/$direntry") { # it's a file. readable? if (!-r "$dirname/$direntry") { die "$dirname/$direntry ERROR unreadable file\n"; } if ($direntry !~ m#\.pm$# && $direntry !~ m#\.pod$#) { if ($not_pm) { print "$dirname/$direntry INFO not .pod or .pm, ignored\n"; } next; } push @list, { fpname=>"$dirname/$direntry", ofname=>toOF("$dirname/$direntry"), pmname=>toPM("$dirname/$direntry"), status=>-2, accessible=>1, abstract=>'', parents=>[], siblings=>[], children=>[], depth=>0 }; } else { # it should be a directory. recursively process it if (!-d "$dirname/$direntry") { print "$dirname/$direntry WARNING is not a directory or file, ignored\n"; next; } push @list, buildList("$dirname/$direntry", "$PMname${direntry}::"); } } closedir $dh; return @list; # unsorted } # ================================== # toPM(filepath name) convert name (as filepath) to a PM string # e.g. ../lib/PDF/Builder/Content.pm to PDF::Builder::Content sub toPM { my $fname = $_[0]; # strip off .pod or .pm $fname =~ s#\.pod$##; $fname =~ s#\.pm$##; # strip off $libtop + / e.g. ../lib/ $fname =~ s#^$libtop/##; # convert dir separator \ or / to :: $fname =~ s#[\\/]#::#g; return $fname; } # ================================== # toOF(filename) convert raw input .pm or .pod input filepath and name # e.g. $libtop/PDF/Builder/Content.pod to $output/PDF/Builder/Content.html sub toOF { my $fname = $_[0]; $fname =~ s#$libtop#$output#; $fname =~ s#\.(pm|pod)$#.html#; return $fname; } # ================================== # toFP(PM name) convert name (as PM string) to a filepath # e.g. PDF::Builder::Content to ../lib/PDF/Builder/Content.pm # preferably a .pod instead of a .pm for a given entry sub toFP { my $fname = $_[0]; my $filename; # strip off $leading substr($fname, 0, length($leading)+2) = ''; # convert :: to / $filename = $fname; $filename =~ s/::/$dirsep/g; # append .pod (if file exists), else .pm if (-f "$filename.pod" && -r "$filename.pod") { $filename .= ".pod"; } else { $filename .= '.pm'; } return $filename; } # ================================== sub help { my $message = <<"END_OF_TEXT"; buildDoc.pl: build, using the Pod::Simple::XHTML utility, all the .html documentation files for a package, from all the .pm (or .pod) files in the package. Using buildDoc.pl input files from //.pm /*.pm may be empty string output files to //*.html buildDoc.pl -h **NOTE** When running on Windows, it is possible in some cases for a directory separator / on the command line to be mistaken for an option (flag). In such cases, surround the term with quotation marks ". --help this help text --all process all .pod and .pm files at and below current directory. this is the default, but is needed if no other command line options are given --dirsep=string default: "/" directory separator. As Windows accepts the Unixy /, you should not have to change this (except on the command line, where / means "option") --absep=string default: " - ", the abstract separator found between the module name and its abstract (description) in the POD NAME section (as implemented for PDF::Builder) --flagorphans default: off. If 'on', a warning will be given during processing that the module appears to be unreachable from the "root" .pod or .pm file. However, it can always be accessed from the TOC index file --noignore default: off. If 'on', a warning is given when a file without a .pod or .pm filetype is encountered (and skipped). This can help you to clean out junk like editor backup files. --libtop=string default: "../lib". This is the directory path to get to the top of the .pod/.pm source tree from wherever you are running this documentation program. For PDF::Builder, the default is that you are running this program in docs/, which is a sibling to the lib/PDF/ tree. --leading=string default: "PDF" for PDF::Builder. This is the OPTIONAL top module (and directory) name. It will be omitted (= '') if there is only one name of interest for some package, or it is the top part of a multipart name (e.g., PDF for PDF::Builder). For example, there are several PDF:: products and --rootname is used to distinguish among them. If a package name includes three or more parts (A::B::C, etc.), give --leading either in the form of Perl style (A::B) or as directories (A/B, in this case). Note that "leading" is pronounced "leeding", as in "up front". Do not confuse it with typographic leading, pronounced "ledding", which is the space between text baselines. --rootname=string default: "Builder" for PDF::Builder. --rootname must be given (not an empty string). For example, there are also PDF::API2 and PDF::Report, among others. --output=string default: "." for PDF::Builder. It is the location of the new / directory, under docs/ in this case (./PDF/) as this program is typically run under docs/. All HTML files will be in the // directory, unless leading is empty '', in which case output is to //. --toc=string default: "_index.html" for most applications. This is the name of the master index (table of contents) file that will be written to with links to all modules, in the top level output directory (e.g., PDF/). EXAMPLES: To build PDF::Builder's documentation, in Builder/docs just run buildDoc.pl --all All the defaults are set up for building PDF::Builder's documentation from docs/. '-all' is the default, but no entries at all is interpreted as a request for help. To build the documentation directory 'SVG' under docs, from an installation in Strawberry Perl, with the .pm/.pod files under lib/. Naturally, if you are building from an installed Perl package, your --libtop would point to the directory /Strawberry/perl/site/lib/SVG/lib (or wherever): buildDoc.pl --leading='' --libtop=/Strawberry/perl/site/lib -rootname=SVG **CAUTION** If there are multiple packages under SVG (e.g., not only ./SVG.pm and its children under SVG/, but also SVG::Parser and SVG::Reader packages), buildDoc may become confused and attempt to build all of them under SVG, resulting in spurious error messages and misorganized .html files (as it processes everything under SVG/). In this care, it is better to either manually copy just SVG's .pm and .pod file structure to a temporary directory, or obtain a temporary copy of just the desired package from a repository such as CPAN or GitHub. See the following example: To build package SVG's documentation, from a Desktop directory 'SVG-2.87', in Builder/docs (also on the Desktop), run buildDoc.pl --leading='' --libtop=../../SVG-2.87/lib -rootname=SVG The .pod or .pm file(s) are fed to Pod::Simple::XHTML utility to produce .html files stored in the current directory or below (see configuration section). .html files with any links in them (L<> tag) are fixed up to correct the href (path) to the referenced HTML files. If there are both .pod and .pm versions of a given filename, the .pod version will be preferably used. Presumably it has the documentation in it. If the resulting .html file has no content, it has a line added to inform anyone looking at it that there is no documentation for that module (rather than a blank page). If all .pod and .pm files are being processed, an attempt will be made to check that .html target files actually exist (cross reference check). In addition, a check will be made that some other file links to this one so that there is a chain of links from the root. References to other packages via L<> may result in error messages ("does not appear to exist" or even a Severe Error), and will have to be manually cleaned up to either eliminate the bogus links (Bad::Package) or point them to the correct place. Messages: INFO no link from root for this HTML file There does not appear to be a chain of links from the root down to this file. It is still usable and can be accessed explicitly, and possibly via other non-root paths, but it may be an orphan. You might want to add an L<> link from another module. All HTML files are still accessible from the master Table of Contents (docs/index.html). As this is such a common event, by default the message is suppressed. The --flagorphans flag will show it during processing. INFO no POD content There was no POD content in the .pod or .pm input file, so there is no documentation in the file. A grayed-out dummy link will be given in the master index file. INFO not .pod or .pm, ignored The file found is not a Perl Documentation (.pod) or Module (.pm) file, so it is ignored. This message is suppressed by the --noignore flag. WARNING extra command line content ignored The indicated item was on the command line, but its purpose is not known, and it has been skipped over. Invalid flags or options get their own error message: Unknown option: . WARNING unknown flag skipped A flag (command line item) starting with - or -- was seen, but not recognized as a valid flag. It is skipped over. WARNING top-level .pod or .pm file not readable One or more of the top level .pod or .pm files ( .pod or .pm) was missing or not readable. WARNING internal POD errors reported by Pod::Simple::XHTML At the end of the .html file, problems are listed. You should examine them and attempt to correct the issue(s). Usually these are formatting issues. WARNING is not a directory or file, ignored This program tried to process a directory entry that wasn't a regular file or a subdirectory. It is skipped over. ERROR --rootname must not be empty! The is the top level name of the package being documented, and cannot be an empty string. It must be a name. ERROR no .pod or .pm files found The specified file(s) were not found. ERROR POD errors reported by Pod::Simple::XHTML One or more error messages were written to STDERR. You should examine them and attempt to correct the issue(s). ERROR does not appear to exist, called from You have a L<> link to a target .html file that does not appear to exist. ERROR .pod or .pm file not readable The input file could not be read, the output file could not be created or written, the output directory could not be created, etc. Check for filesystem (disk) full, and incorrectly set permissions. ERROR still has status at output! A .pod or .pm file got through the process and to the point of output to the TOC (index.html) file still having a status of -2 or -1, when it should be 0 or higher by this point. ERROR unable to open output index file There was an error trying to open the output .html to write out the master index page. ERROR can't open file for output Can't open the file to write it out. This is usually seen with an .html file to be written back out after modifications. Check permissions. ERROR can't open file for input Can't open the file to read it in. This is usually seen with an .html file to be read in for modifications. Check permissions. ERROR can't open and read directory While exploring the file tree, the program was unable to open a directory in order to read its contents (files and subdirectories). Check permissions. ERROR unreadable file While exploring the file tree, the program found a file that it wants to read, but is unable to do so. Check permissions. END_OF_TEXT # TBD later, if implement individual file builds # OR # path/filename.pod/.pm or path::filename native directory/filename or Perl-style name print $message; return; } # ================ # empty HTML file (no POD in a module) sub empty { my $content = <<"END_OF_TEXT"; END_OF_TEXT return $content; } PDF-Builder-3.026/.perlcriticrc0000644000000000000000000000013713747321542014716 0ustar rootrootseverity = 5 [Perl::Critic::Policy::BuiltinFunctions::ProhibitStringyEval] allow_includes = 1 PDF-Builder-3.026/examples/0000755000000000000000000000000014534671356014053 5ustar rootrootPDF-Builder-3.026/examples/Windows/0000755000000000000000000000000014534467617015510 5ustar rootrootPDF-Builder-3.026/examples/Windows/Win32.pm0000644000000000000000000000617014534467462016752 0ustar rootrootpackage PDF::Builder::Win32; ## no critic use strict; use warnings; #no warnings qw[ deprecated recursion uninitialized ]; our $VERSION = '3.026'; # VERSION our $LAST_UPDATE = '3.021'; # manually update whenever code is changed use Win32::TieRegistry qw( :KEY_ ); # creates $Registry, et al. =head1 NAME PDF::Builder::Win32 - font file- and registry-related support routines for Windows operating system =cut our $wf = {}; $Registry->Delimiter('/'); # e.g., "C:\Windows\Fonts". $Registry->{} is a hash reference to Fonts element my $fontdir = $Registry->{'HKEY_CURRENT_USER/Software/Microsoft/Windows/CurrentVersion/Explorer/Shell Folders/Fonts'}; # $Registry->{} should be a hash reference containing elements which are the # names of .ttf etc. files found in $fontdir. # E.g., $Registry->{'Arial (TrueType)'} = 'arial.ttf' my $subKey = $Registry->Open('LMachine', {Access=>KEY_READ(), Delimiter=>'/'}) or die "error opening LMachine: $^E\n"; $subKey = $subKey->Open('SOFTWARE/Microsoft/Windows NT/CurrentVersion/Fonts/') or die "error accessing Fonts entry: $^E\n"; foreach my $k (sort keys %{$subKey}) { # $k should be something like 'Arial (TrueType)' # $subKey->{$k} would then be 'arial.ttf' next unless $subKey->{$k} =~ /\.[ot]tf$/i; my $kk = lc($k); $kk =~ s|^/||; $kk =~ s|\s+\(truetype\).*$||g; $kk =~ s|\s+\(opentype\).*$||g; $kk =~ s/[^a-z0-9]+//g; $wf->{$kk} = {}; $wf->{$kk}->{'display'} = $k; $wf->{$kk}->{'display'} =~ s|^/||; if (-e "$fontdir/$subKey->{$k}") { $wf->{$kk}->{'ttfile'} = "$fontdir/$subKey->{$k}"; } else { $wf->{$kk}->{'ttfile'} = $subKey->{$k}; } } # this one seems to be optional (often missing) $subKey = $Registry->Open('LMachine', {Access=>KEY_READ(), Delimiter=>'/'}) or die "error opening LMachine for T1 fonts: $^E\n"; $subKey = $subKey->Open('SOFTWARE/Microsoft/Windows NT/CurrentVersion/Type 1 Installer/Type 1 Fonts/') or die "error accessing T1 Fonts entry: $^E\n"; foreach my $k (sort keys %{$subKey}) { my $kk = lc($k); $kk =~ s|^/||; $kk =~ s/[^a-z0-9]+//g; $wf->{$kk} = {}; $wf->{$kk}->{'display'} = $k; $wf->{$kk}->{'display'} =~ s|^/||; my $t; ($t, $wf->{$kk}->{'pfmfile'}, $wf->{$kk}->{'pfbfile'}) = split(/\0/, $subKey->{$k}); if (-e "$fontdir/" . $wf->{$kk}->{'pfmfile'}) { $wf->{$kk}->{'pfmfile'} = "$fontdir/" . $wf->{$kk}->{'pfmfile'}; $wf->{$kk}->{'pfbfile'} = "$fontdir/" . $wf->{$kk}->{'pfbfile'}; } } # return hash of fonts, key=lc name w/o fileext, value=full name # e.g., {'arial'} = 'Arial (TrueType)' sub enumwinfonts { my $self = shift; return map { $_ => $wf->{$_}->{'display'} } keys %$wf; } sub winfont { my $self = shift; my $key = lc(shift()); my %opts = @_; $key =~ s/[^a-z0-9]+//g; # $wf is hash reference return unless defined $wf and defined $wf->{$key}; # ttfile is complete path and name of a file if (defined $wf->{$key}->{'ttfile'}) { return $self->ttfont($wf->{$key}->{'ttfile'}, @_); } else { return $self->psfont($wf->{$key}->{'pfbfile'}, -pfmfile => $wf->{$key}->{'pfmfile'}, @_); } } 1; PDF-Builder-3.026/examples/Windows/027_winfont0000644000000000000000000001174614534467462017516 0ustar rootroot#!/usr/bin/perl use strict; use warnings; use File::Basename; use PDF::Builder; use PDF::Builder::Util; use PDF::Builder::Win32; use Unicode::UCD 'charinfo'; use Encode qw[:all]; use Getopt::Long; #use Data::Dumper; use utf8; #my $compress = 'none'; # uncompressed streams my $compress = 'flate'; # compressed streams my %wxf = PDF::Builder::Win32->enumwinfonts(); foreach my $k (sort keys %wxf) { print "font '$wxf{$k}' has key '$k'\n"; my $api = PDF::Builder->new(-compress => $compress); $api->mediabox(595,842); my $helv = $api->corefont('Helvetica-Bold', -encode=>'latin1'); my $sx = 33; my $sy = 45; my $fx = 20; # my $xf = $api->winfont($k, -encode=>'latin1'); my $xf = PDF::Builder::Win32->winfont($k, -encode=>'latin1'); my $page = $api->page(); $page->mediabox(595,842); my $gfx = $page->gfx(); my $text = $page->text(); $text->textlabel(50,800, $helv,20, $wxf{$k}); # row number yp foreach my $yp (0 .. 15) { my $y = 15 - $yp; # row location top to bottom # column number x left to right foreach my $x (0 .. 15) { my $c = $yp*16 + $x; $text->textlabel(50+($sx*$x),50+($sy*$y), $xf,$fx, pack('C',$c)); $text->textlabel(50+($sx*$x),50+($sy*$y)-6, $helv,6, nameByUni($c), -color=>'#a00000', -hscale=>80, -rotate=>-15); } } if ($xf->can('uniByCId') and $xf->can('glyphNum')) { my @cids = (0 .. $xf->glyphNum()-1); my @fbbx = $xf->fontbbox(); my $xw = int(($fbbx[2] - $fbbx[0])/20)*20; my $yw = int(($fbbx[3] - $fbbx[1])/20)*20; my $fw = $xw>$yw? $yw: $xw; my $mw = 800/$fw; my $y0 = int((20 - $fbbx[1])/20)*20*$mw; # create pages until run out of cids while (scalar @cids>0) { $page = $api->page(); $page->mediabox(595,842); $gfx = $page->gfx(); $text = $page->text(); my $scale = 0.045; # row positions (y value) foreach my $y (750,700,650,600,550,500,450,400,350,300,250,200,150,100,50) { # column positions (x value) foreach my $x (50,100,150,200,250,300,350,400,450,500) { my $xo = shift(@cids); $gfx->save(); $gfx->fillcolor('black'); $gfx->transform(-translate => [$x, $y], -scale => [0.045, 0.045]); $gfx->linewidth(10); $gfx->rect(0,0, 1000,1000); $gfx->stroke(); my $wx = $xf->wxByCId($xo)*$mw; my $x0 = (1000-$wx)/2; $gfx->linedash(10,20); $gfx->linewidth(0.5); $gfx->move($x0,0); $gfx->line($x0,1000); $gfx->move($x0+$wx,1000); $gfx->line($x0+$wx,0); $gfx->move(0,$y0); $gfx->line(1000,$y0); $gfx->stroke(); $text->font($xf, 1000*$mw*$scale); $text->translate($x+$x0*$scale,$y+$y0*$scale); $text->add($xf->text_cid(pack('n',$xo)), 'Tj'); $text->font($helv, 100*$scale); $text->hscale(80); $text->translate($x+25*$scale,$y+860*$scale); $text->text("G+$xo"); $text->translate($x+25*$scale,$y+10*$scale); $text->text(sprintf('U+%04X', $xf->uniByCId($xo))); my $name = $xf->glyphByCId($xo); if ($name eq '') { $text->fillcolor('red'); $name = "NONE"; } else { $text->fillcolor('blue'); } $text->hscale(70); $text->translate($x+975*$scale,$y+860*$scale); $text->text_right($name); $text->fillcolor('black'); $text->translate($x+975*$scale,$y+10*$scale); $text->text_right('wx='.$xf->wxByCId($xo)); $text->fillcolor('#008000'); $text->translate($x+500*$scale,$y+950*$scale); $text->hscale(70); my $ci = charinfo($xf->uniByCId($xo) || 0); $text->font($helv,50*$scale); $text->text_center($ci->{'name'}); # restore $text->fillcolor('black'); $text->hscale(100); $gfx->restore(); last unless scalar @cids>0; } # next column in row (x pos) last unless scalar @cids>0; } # next row (y pos) print STDERR "."; ## $api->finishobjects($page,$gfx); } # loop through cids } # both uniByCId and glyphNum OK $api->saveas("$0.$k.pdf"); $api->end(); } # loop through keys of %wxf #print Dumper($PDF::Builder::wf); __END__ PDF-Builder-3.026/examples/RMtutorial.pl0000644000000000000000000003061514534467462016520 0ustar rootroot#!/usr/bin/perl # adapted from Rich Measham's tutorial http://rick.measham.id.au/pdf-api2/ # PDF::API2 changed to PDF::Builder, generalized image used, strip .pl from $0 # note the widespread use of convenient (inch, mm) dimensions rather than points # some annotations added to explain code use strict; use warnings; use PDF::Builder; my $the_image = # adjust as needed to find an image to show #'./Portrait.jpg' './examples/resources/aptfrontview.jpg' ; my $output_name = $0; $output_name =~ s/\.pl$//; # in case (e.g., Windows), there's an extension use constant mm => 25.4 / 72; use constant in => 1 / 72; use constant pt => 1; my ( $paragraph1, $paragraph2, $picture ) = get_data(); my $pdf = PDF::Builder->new( -file => "$output_name.pdf" ); my $page = $pdf->page; $page->mediabox (105/mm, 148/mm); # 1/4 (1/2 each dimension) A4 paper size # (normally 210/mm by 297/mm), presumably sized to just fill with # available text. it also sets the coordinate system for all dimensions # used thereafter on this page. $page->cropbox (7.5/mm, 7.5/mm, 97.5/mm, 140.5/mm); # default: mediabox # this is the viewable area in a reader (90/mm by 133/mm) and # output (ink) is limited to this area (unless smaller bleedbox). this # page should be printed with a 7.5/mm margin all around the media. note # that use of the cropbox is NOT a good idea to define where you're going # to TRIM the paper after printing, as it will be difficult to avoid # getting a little white edge. it's better to bleed just beyond any Trim # Box. #$page->bleedbox( 5/mm, 5/mm, 100/mm, 143/mm); # default: cropbox # this is the limit of printing, including bleed-over, crop marks, # color alignment marks, and instructions to the printer. #$page->trimbox(); # default: cropbox # this is where the finished page is cut, instructions to the printer # may be outside the trimbox. #$page->artbox ( 10/mm, 10/mm, 95/mm, 138/mm); # default: cropbox # "meaniningful content" found within this box (should be kept, for # example, when printing N-up pages on one sheet). # keep all available (opened) fonts in one place, with consistent access and # naming. don't open anything that you don't plan to use, as it wastes space! # note that only ttfont() can handle multibyte encodings such as UTF-8. my %font = ( Helvetica => { Bold => $pdf->corefont( 'Helvetica-Bold', -encoding => 'latin1' ), # Roman => $pdf->corefont( 'Helvetica', -encoding => 'latin1' ), # Italic => $pdf->corefont( 'Helvetica-Oblique', -encoding => 'latin1' ), }, Times => { # Bold => $pdf->corefont( 'Times-Bold', -encoding => 'latin1' ), Roman => $pdf->corefont( 'Times', -encoding => 'latin1' ), # Italic => $pdf->corefont( 'Times-Italic', -encoding => 'latin1' ), }, ); # in real life, you would probably want this box to bleed over the trimbox # line, to ensure that no white edge accidentally shows around it. my $blue_box = $page->gfx; $blue_box->fillcolor('darkblue'); # note that box extends 2.5/mm past the cropbox on three sides, giving another # way to bleed to the edge. $blue_box->rect( 5/mm, 125/mm, 95/mm, 18/mm ); $blue_box->fill; # the red line should also extend past the trimbox line. like the blue_box, # it extends 2.5/mm past the cropbox line on both ends, and bleeds to the edge. my $red_line = $page->gfx; $red_line->strokecolor('red'); $red_line->move( 5/mm, 125/mm ); $red_line->line( 100/mm, 125/mm ); $red_line->stroke; # headline printed in blue box. note that text colors are normally given as # fill color (glyphs are normally not stroked). my $headline_text = $page->text; $headline_text->font( $font{'Helvetica'}{'Bold'}, 18/pt ); $headline_text->fillcolor('white'); $headline_text->translate( 95/mm, 131/mm ); $headline_text->text_right('USING PDF::Builder'); my $background = $page->gfx; $background->strokecolor('lightgrey'); $background->circle( 20/mm, 45/mm, 45/mm ); $background->circle( 18/mm, 48/mm, 43/mm ); $background->circle( 19/mm, 40/mm, 46/mm ); $background->stroke; my $left_column_text = $page->text; $left_column_text->font( $font{'Times'}{'Roman'}, 6/pt ); $left_column_text->fillcolor('black'); my ( $endw, $ypos, $paragraph ) = text_block( $left_column_text, $paragraph1, -x => 10/mm, -y => 119/mm, -w => 41.5/mm, -h => 110/mm - 7/pt, -lead => 7/pt, -parspace => 0/pt, -align => 'justify', ); $left_column_text->font( $font{'Helvetica'}{'Bold'}, 6/pt ); $left_column_text->fillcolor('darkblue'); ( $endw, $ypos, $paragraph ) = text_block( $left_column_text, 'Enim eugiamc ommodolor sendre feum zzrit at. Ut prat. Ut lum quisi.', -x => 10/mm, -y => $ypos - 7/pt, -w => 41.5/mm, -h => 110/mm - ( 119/mm - $ypos ), -lead => 7/pt, -parspace => 0/pt, -align => 'center', ); $left_column_text->font( $font{'Times'}{'Roman'}, 6/pt ); $left_column_text->fillcolor('black'); ( $endw, $ypos, $paragraph ) = text_block( $left_column_text, $paragraph2, -x => 10/mm, -y => $ypos, -w => 41.5/mm, -h => 110/mm - ( 119/mm - $ypos ), -lead => 7/pt, -parspace => 0/pt, -align => 'justify', ); my $photo = $page->gfx; die("Unable to find image file: $!") unless -e $picture; my $photo_file = $pdf->image_jpeg($picture); $photo->image( $photo_file, 54/mm, 66/mm, 41/mm, 55/mm ); my $right_column_text = $page->text; $right_column_text->font( $font{'Times'}{'Roman'}, 6/pt ); $right_column_text->fillcolor('black'); ( $endw, $ypos, $paragraph ) = text_block( $right_column_text, $paragraph, -x => 54/mm, -y => 62/mm, -w => 41.5/mm, -h => 54/mm, -lead => 7/pt, -parspace => 0/pt, -align => 'justify', -hang => "\xB7 ", ); $pdf->save; $pdf->end(); sub text_block { my $text_object = shift; my $text = shift; my %arg = @_; # Get the text in paragraphs my @paragraphs = split( /\n/, $text ); # calculate width of all words my $space_width = $text_object->advancewidth(' '); my @words = split( /\s+/, $text ); my %width = (); foreach (@words) { next if exists $width{$_}; $width{$_} = $text_object->advancewidth($_); } $ypos = $arg{'-y'}; my @paragraph = split( / /, shift(@paragraphs) ); my $first_line = 1; my $first_paragraph = 1; # while we can add another line while ( $ypos >= $arg{'-y'} - $arg{'-h'} + $arg{'-lead'} ) { unless (@paragraph) { last unless scalar @paragraphs; @paragraph = split( / /, shift(@paragraphs) ); $ypos -= $arg{'-parspace'} if $arg{'-parspace'}; last unless $ypos >= $arg{'-y'} - $arg{'-h'}; $first_line = 1; $first_paragraph = 0; } my $xpos = $arg{'-x'}; # while there's room on the line, add another word my @line = (); my $line_width = 0; if ( $first_line && exists $arg{'-hang'} ) { my $hang_width = $text_object->advancewidth( $arg{'-hang'} ); $text_object->translate( $xpos, $ypos ); $text_object->text( $arg{'-hang'} ); $xpos += $hang_width; $line_width += $hang_width; $arg{'-indent'} += $hang_width if $first_paragraph; } elsif ( $first_line && exists $arg{'-flindent'} ) { $xpos += $arg{'-flindent'}; $line_width += $arg{'-flindent'}; } elsif ( $first_paragraph && exists $arg{'-fpindent'} ) { $xpos += $arg{'-fpindent'}; $line_width += $arg{'-fpindent'}; } elsif ( exists $arg{'-indent'} ) { $xpos += $arg{'-indent'}; $line_width += $arg{'-indent'}; } while ( @paragraph and $line_width + ( scalar(@line) * $space_width ) + $width{ $paragraph[0] } < $arg{'-w'} ) { $line_width += $width{ $paragraph[0] }; push( @line, shift(@paragraph) ); } # calculate the space width my ( $wordspace, $align ); if ( $arg{'-align'} eq 'fulljustify' or ( $arg{'-align'} eq 'justify' and @paragraph ) ) { if ( scalar(@line) == 1 ) { @line = split( //, $line[0] ); } $wordspace = ( $arg{'-w'} - $line_width ) / ( scalar(@line) - 1 ); $align = 'justify'; } else { $align = ( $arg{'-align'} eq 'justify' ) ? 'left' : $arg{'-align'}; $wordspace = $space_width; } $line_width += $wordspace * ( scalar(@line) - 1 ); if ( $align eq 'justify' ) { foreach my $word (@line) { $text_object->translate( $xpos, $ypos ); $text_object->text($word); $xpos += ( $width{$word} + $wordspace ) if (@line); } $endw = $arg{'-w'}; } else { # calculate the left hand position of the line if ( $align eq 'right' ) { $xpos += $arg{'-w'} - $line_width; } elsif ( $align eq 'center' ) { $xpos += ( $arg{'-w'} / 2 ) - ( $line_width / 2 ); } # render the line $text_object->translate( $xpos, $ypos ); $endw = $text_object->text( join( ' ', @line ) ); } $ypos -= $arg{'-lead'}; $first_line = 0; } unshift( @paragraphs, join( ' ', @paragraph ) ) if scalar(@paragraph); return ( $endw, $ypos, join( "\n", @paragraphs ) ) } ### SAVE ROOM AT THE TOP ### sub get_data { return ( qq|Perci ent ulluptat vel eum zzriure feuguero core consenis adignim irilluptat praessit la con henit velis dio ex enim ex ex euguercilit il enismol eseniam, suscing essequis nit iliquip erci blam dolutpatisi. Orpero do odipit ercilis ad er augait ing ex elit autatio od minisis amconsequam, quis am il do consenim esequi eui blamcorer adiat. Ut prat la facip ercip eugiamconsed tio do exero ea consequis do odolor il dolut wisim adit, susciniscing et adit num num vel ip ercilit alismolorem zzril ute dolendre ming eu feui bla feugait il illa facin eu feugiam conseniam eliquisl et luptat la feu feugait, volore euguerc incillu msandigna feuipisl iriuscilit velit wisl utem veros ad min velit laor iuscilit veliquis ad tie endignim dignisl et, qui bla feugue mod enibh esendiam, si blaor si blaore te min vel utpat nonsequ issequis dolorperosto dolobore ex erit, vel in utating etum ad dolutatet la feugiatue mod euisci blandre tat iurem eum velit prat nosting essim ver aliscil dolortie cor alisit wisl delesti sciduisci ting eu feu facidunt autat. Duipis amcommy non er sit, commy numsand ionsequam, commy num alisim euis dio eu faciduisit ate moloreet, quam zzrillaore magnit eum dolor ipsum dunt dolor sequatie dolor iustrud te molum dolore velit la faccum zzriuscil utpat irit nummod magna alis eu faccum inibh erosto ea ad magniamet vel esto dipsusto elesting eugiam, commolobore deliquat praessenim et, vel ut et nibh et adit lortisi.|, qq|It augait ate magniametum irit, venim doloreet augiamet ilit alis nonse dolore delessit volor susto od ming eugiam voloborem ip ea faciduisis alit, vent nim nulput utat endre dolum quissit atem nim dolorperci tat dunt veliquat ipis acip elenit lum dunt luptat. Ut luptat nulla feu facin hent dolobore vulput augait, quamet vent non utpat nulput nonsed doloreetum dio estis eum aut accummy nos nisi. Orpero do odipit ercilis ad er augait ing ex elit autatio od minisis amconsequam, quis am il do consenim esequi eui blamcorer adiat. Ut prat la facip ercip eugiamconsed tio do exero ea consequis do odolor il dolut wisim adit, susciniscing et adit num num vel ip ercilit alismolorem zzril ute dolendre ming eu feui bla feugait il illa facin eu feugiam. Conseniam eliquisl et luptat la feu feugait, volore euguerc incillu msandigna feuipisl iriuscilit velit wisl utem veros ad min velit laor iuscilit veliquis ad tie endignim dignisl et, qui bla feugue mod enibh esendiam, si blaor si blaore te min vel utpat nonsequ issequis dolorperosto. Dolobore ex erit, vel in utating etum ad dolutatet la feugiatue mod euisci blandre tat iurem eum velit prat nosting essim ver aliscil dolortie cor alisit wisl delesti sciduisci ting eu feu facidunt autat. Duipis amcommy non er sit, commy numsand ionsequam.|, $the_image ); } PDF-Builder-3.026/examples/Rotated.pl0000644000000000000000000001710614534467462016020 0ustar rootroot#!/usr/bin/perl # demonstrate a page of portrait-mode text, followed by a two-page spread # rotated content, and finally back to portrait mode for a last page. # outputs Rotated.pdf # author: Phil M Perry use warnings; use strict; our $VERSION = '3.026'; # VERSION our $LAST_UPDATE = '3.023'; # manually update whenever code is changed use PDF::Builder; my $PDFname = $0; $PDFname =~ s/\..*$//; # remove extension $PDFname .= '.pdf'; # add new extension my $pgsize = 'letter'; # A4, universal also good choices my $marginTop = 72; # points my $marginBot = 72; my $outerMargin = 72; my $innerMargin = 144; # includes binding area my $gutter = 54; # for rotated two column my $fontsize = 15; # Lorem Ipsum text, borrowed from examples/ContentText.pl, including newlines # to mark end of paragraphs. my $LoremIpsum = "Sed ut perspiciatis, unde omnis iste natus error sit ". "voluptatem accusantium doloremque laudantium, totam rem aperiam eaque ipsa, ". "quae ab illo inventore veritatis et quasi architecto beatae vitae dicta ". "sunt, explicabo. Nemo enim ipsam voluptatem, quia voluptas sit, aspernatur ". "aut odit aut fugit, sed quia consequuntur magni dolores eos, qui ratione ". "dolor sit, voluptatem sequi nesciunt, neque porro quisquam est, qui dolorem ". "ipsum, quia amet, consectetur, adipisci velit, sed quia non numquam eius ". "modi tempora incidunt, ut labore et dolore magnam aliquam quaerat ". "voluptatem.\nUt enim ad minima veniam, quis nostrum exercitationem ullam ". "corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? ". "Quis autem vel eum iure reprehenderit, qui in ea voluptate velit esse, quam ". "nihil molestiae consequatur, vel illum, qui dolorem eum fugiat, quo voluptas ". "nulla pariatur? At vero eos et accusamus et iusto odio dignissimos ducimus, ". "qui blanditiis praesentium voluptatum deleniti atque corrupti, quos dolores ". "et quas molestias excepturi sint, obcaecati cupiditate non provident, ". "similique sunt in culpa, qui officia deserunt mollitia animi, id est laborum ". "et dolorum fuga.\nEt harum quidem rerum facilis est et expedita distinctio. ". "Nam libero tempore, cum soluta nobis est eligendi optio, cumque nihil ". "impedit, quo minus id, quod maxime placeat, facere possimus, omnis voluptas ". "assumenda est, omnis dolor repellendus.\nTemporibus autem quibusdam et aut ". "officiis debitis aut rerum necessitatibus saepe eveniet, ut et voluptates ". "repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur ". "a sapiente delectus, ut aut reiciendis voluptatibus maiores alias ". "consequatur aut perferendis doloribus asperiores repellat."; my ($page, $text, $width, $height, $unused, $cont, $contR, $txt, $txtR, %margins); $txtR = $txt = "$LoremIpsum\n$LoremIpsum"; # ensure plenty of text my $pdf = PDF::Builder->new(); $pdf->mediabox($pgsize); my @pageDim = $pdf->mediabox(); my $font = $pdf->corefont('Times-Roman'); # page 1 (portrait, right hand) ===================================== $page = $pdf->page(); $text = $page->text(); $text->font($font, $fontsize); $text->leading($fontsize*1.25); $width = $pageDim[2]; $height = $pageDim[3]; $margins{'T'} = $marginTop; $margins{'B'} = $marginBot; $margins{'L'} = $innerMargin; $margins{'R'} = $outerMargin; $cont = 0; # single column, full width of page $text->translate($margins{'L'}, $height-$margins{'T'}-$fontsize); ($txt, $cont, $unused) = $text->section($txt, $width-$margins{'L'}-$margins{'R'}, $height-$margins{'T'}-$margins{'B'}, $cont, -spillover=>0, -align => 'justify', -pndnt => 2, -pvgap => 4 ); # expect $txt to have around a page left over (for page 4) # heading, footing $text->translate(($width+$margins{'L'}-$margins{'R'})/2, $height-$margins{'T'}/2); $text->text_center('Lorem Ipsum'); $text->translate(($width+$margins{'L'}-$margins{'R'})/2, ($margins{'B'}-$fontsize)/2); $text->text_center('-- 1 --'); # page 2 landscape, top ===================================== $page = $pdf->page(); $width = $pageDim[3]; $height = $pageDim[2]; $page->mediabox(0,0, $width,$height); # landscape $margins{'T'} = $outerMargin; $margins{'B'} = $innerMargin; $margins{'L'} = $marginBot; $margins{'R'} = $marginTop; $text = $page->text(); $text->font($font, $fontsize); $text->leading($fontsize*1.25); $contR = 0; # two columns, half width of page $text->translate($margins{'L'}, $height-$margins{'T'}-$fontsize); ($txtR, $contR, $unused) = $text->section($txtR, ($width-$margins{'L'}-$margins{'R'}-$gutter)/2, $height-$margins{'T'}-$margins{'B'}, $contR, -spillover=>0, -align => 'justify', -pndnt => 2, -pvgap => 4 ); $text->translate(($width+$margins{'L'}-$margins{'R'}+$gutter)/2, $height-$margins{'T'}-$fontsize); ($txtR, $contR, $unused) = $text->section($txtR, ($width-$margins{'L'}-$margins{'R'}-$gutter)/2, $height-$margins{'T'}-$margins{'B'}, $contR, -spillover=>0, -align => 'justify', -pndnt => 2, -pvgap => 4 ); # heading, footing (unrotated) $text->transform(-translate => [$width-$margins{'R'}/2-$fontsize, 0.5*($height-$margins{'T'}+$margins{'B'})], -rotate => -90); $text->text_center('The Sequel'); $text->transform(-translate => [$margins{'L'}/2, 0.5*($height-$margins{'T'}+$margins{'B'})], -rotate => -90); $text->text_center('-- 2 --'); # page 3 landscape, bottom ===================================== $page = $pdf->page(); $width = $pageDim[3]; $height = $pageDim[2]; $page->mediabox(0,0, $width,$height); # landscape $margins{'T'} = $innerMargin; $margins{'B'} = $outerMargin; $margins{'L'} = $marginBot; $margins{'R'} = $marginTop; $text = $page->text(); $text->font($font, $fontsize); $text->leading($fontsize*1.25); # two columns, half width of page $text->translate($margins{'L'}, $height-$margins{'T'}-$fontsize); ($txtR, $contR, $unused) = $text->section($txtR, ($width-$margins{'L'}-$margins{'R'}-$gutter)/2, $height-$margins{'T'}-$margins{'B'}, $contR, -spillover=>0, -align => 'justify', -pndnt => 2, -pvgap => 4 ); $text->translate(($width+$margins{'L'}-$margins{'R'}+$gutter)/2, $height-$margins{'T'}-$fontsize); ($txtR, $contR, $unused) = $text->section($txtR, ($width-$margins{'L'}-$margins{'R'}-$gutter)/2, $height-$margins{'T'}-$margins{'B'}, $contR, -spillover=>0, -align => 'justify', -pndnt => 2, -pvgap => 4 ); # heading, footing (unrotated) $text->transform(-translate => [$width-$margins{'R'}/2-$fontsize, 0.5*($height-$margins{'T'}+$margins{'B'})], -rotate => -90); $text->text_center('Lorem Ipsum'); $text->transform(-translate => [$margins{'L'}/2, 0.5*($height-$margins{'T'}+$margins{'B'})], -rotate => -90); $text->text_center('-- 3 --'); # page 4 (portrait, left hand) ===================================== $page = $pdf->page(); $text = $page->text(); $text->font($font, $fontsize); $text->leading($fontsize*1.25); $width = $pageDim[2]; $height = $pageDim[3]; $margins{'T'} = $marginTop; $margins{'B'} = $marginBot; $margins{'L'} = $outerMargin; $margins{'R'} = $innerMargin; # single column, full width of page $text->translate($margins{'L'}, $height-$margins{'T'}-$fontsize); ($txt, $cont, $unused) = $text->section($txt, $width-$margins{'L'}-$margins{'R'}, $height-$margins{'T'}-$margins{'B'}, $cont, -spillover=>0, -align => 'justify', -pndnt => 2, -pvgap => 4 ); # heading, footing $text->translate(($width+$margins{'L'}-$margins{'R'})/2, $height-$margins{'T'}/2); $text->text_center('The Sequel'); $text->translate(($width+$margins{'L'}-$margins{'R'})/2, ($margins{'B'}-$fontsize)/2); $text->text_center('-- 4 --'); # ======================== $pdf->saveas($PDFname); PDF-Builder-3.026/examples/022_truefonts0000644000000000000000000002552114534467462016420 0ustar rootroot#!/usr/bin/perl # given one or more .TTF files on the command line, display their contents: # 256 bytes in one single-byte encoding, plus all glyphs in font by CId, # and some sample ASCII text. # -e encoding (default is latin1) SINGLE BYTE ONLY! use strict; use warnings; use lib qw{ ../lib }; use File::Basename; use PDF::Builder; use PDF::Builder::Util; use Unicode::UCD 'charinfo'; use Getopt::Long; my $compress = 'none'; # uncompressed streams #my $compress = 'flate'; # compressed streams my $noembed = 0; # 0 = allow embedding, 1 = don't allow my $sx = 33; my $sy = 45; my $fx = 20; my ($gfx, $tx, $pdf, $page, $f1, $f2, $y); my $LoremIpsum=q|Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam eaque ipsa, quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt, explicabo. Nemo enim ipsam voluptatem, quia voluptas sit, aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos, qui ratione voluptatem sequi nesciunt, neque porro quisquam est, qui dolorem ipsum, quia dolor sit, amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt, ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit, qui in ea voluptate velit esse, quam nihil molestiae consequatur, vel illum, qui dolorem eum fugiat, quo voluptas nulla pariatur? At vero eos et accusamus et iusto odio dignissimos ducimus, qui blanditiis praesentium voluptatum deleniti atque corrupti, quos dolores et quas molestias excepturi sint, obcaecati cupiditate non provident, similique sunt in culpa, qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio, cumque nihil impedit, quo minus id, quod maxime placeat, facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet, ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat.|; my $encoding='latin1'; my $forceFull = ''; # use only CIDs indicated GetOptions( "encode|e=s" => \$encoding, "full|f" => \$forceFull, ); # loop through command line list of font file names die "Need at least one TTF file name on command line!\n" if !scalar(@ARGV); foreach my $fn (@ARGV) { if (!-r $fn) { print "$fn cannot be read. Skipping...\n\n"; next; } my $myName = basename($fn); $myName =~ s/\.[to]tf$//i; # remove .ttf/.otf (any case) $pdf = PDF::Builder->new(-compress => $compress, -file => $0.'.'.$myName.".pdf"); $f1 = $pdf->corefont('Helvetica', -encode => 'latin1'); $f2 = $pdf->corefont('Helvetica-Bold', -encode => 'latin1'); print STDERR "\n$myName\n"; my $font = $pdf->ttfont($fn, -encode => $encoding, -noembed => $noembed); $font->data()->{'nosubset'} = 1; # produce a page with dump of font # single byte encoding (16 rows x 16 columns) if ($encoding =~ m/^utf/i || $encoding =~ m/^ucs/i) { print STDERR "can't display page for multibyte encoding.\n"; } else { my $page = $pdf->page(); $page->mediabox(595,842); # A4 my $gfx = $page->gfx(); my $txt = $page->text(); $txt->font($font, $fx); my $txt2 = $page->text(); #delete $txt->{'Filter'}; #delete $txt2->{'Filter'}; $txt2->textlabel(50,800, $f1,20, "font='".$font->fontname()."'"); $txt2->textlabel(50,780, $f1,20, "encoding='$encoding'"); $txt2->font($f1, 5); $txt2->hscale(80); my $u = $font->underlineposition()*$fx/1000; # loop through rows (yp growing from bottom) foreach my $yp (0..15) { $y = 15 - $yp; # grow y from top to bottom instead print STDERR "."; # loop through columns left to right foreach my $x (0..15) { $txt->translate(50+($sx*$x),50+($sy*$y)); my $ci = $yp*16 + $x; my $c = chr($ci); $txt->text($c); my $wx = $font->width($c)*$fx; # draw cell box $gfx->strokecolor('lightblue'); $gfx->move(50+($sx*$x),50+($sy*$y)+$fx); $gfx->line(50+($sx*$x),50+($sy*$y)+$u); $gfx->line(50+($sx*$x)+$wx,50+($sy*$y)+$u); $gfx->line(50+($sx*$x)+$wx,50+($sy*$y)+$fx); $gfx->close(); $gfx->stroke(); $gfx->strokecolor('gray'); $gfx->move(50+($sx*$x),50+($sy*$y)); $gfx->line(50+($sx*$x)+$wx,50+($sy*$y)); $gfx->stroke(); $txt2->translate(50+($sx*$x)+$wx,50+($sy*$y)-6); $txt2->text_right($ci); $txt2->translate(50+($sx*$x)+$wx,50+($sy*$y)-11); if (defined $font->uniByEnc($ci)) { $txt2->text_right(sprintf('U+%04X', $font->uniByEnc($ci))); } else { $txt2->text_right('U+????'); } $txt2->translate(50+($sx*$x)+$wx,50+($sy*$y)-16); $txt2->text_right($font->glyphByEnc($ci)); $txt2->translate(50+($sx*$x)+$wx,50+($sy*$y)-21); $txt2->text_right(sprintf('wx=%i',$font->wxByEnc($ci))); } # loop x L to R along row } # loop yp B to T along column and y T to B } # single byte encoding display chars my @cids = (0 .. $font->glyphNum()-1); # alternate: force all G+0000 through G+65535 if ($forceFull) { @cids = ( 0 .. 0xFFFF ); } # warning: apparently not all fonts have fontbbox my @fbbx = $font->fontbbox(); my $xw = int(($fbbx[2] - $fbbx[0])/20)*20; my $yw = int(($fbbx[3] - $fbbx[1])/20)*20; my $fw = $xw>$yw? $yw: $xw; my $mw = 800/$fw; #my $y0 = int((20 - $fbbx[1])/20)*20*$mw; my $y0 = ($fbbx[1] < 0)? -$fbbx[1]: $fbbx[1]; $y0 = int($y0/$yw*1000); if ($y0 < 0 || $y0 > 325) { print STDERR "\nFont bounding box baseline at $y0/1000,"; if ($y0 < 0) { $y0 = 0; } if ($y0 > 325) { $y0 = 325; } print STDERR " display baseline moved to $y0\n"; } my $sX = 0.045; my $sY = 0.045; # one or more pages to display all the cids, 10 col/x x 15 rows/y per page # CId list is simply 0..number of glyphs in font-1 while (scalar @cids>0) { $page = $pdf->page(); $page->mediabox(595,842); # A4 $gfx = $page->gfx(); $tx = $page->text(); #delete $gfx->{'Filter'}; # loop through y coordinates of rows 15 rows of 10 columns) foreach my $yp (0 .. 14) { my $y = 750 - $yp*50; # loop through x coordinates of columns foreach my $xp (1 .. 10) { my $x = $xp * 50; my $xo = shift(@cids); # 0, 1, 2,... $gfx->save(); $gfx->fillcolor('black'); $gfx->transform(-translate => [$x, $y], -scale => [0.045, 0.045]); # heavy, solid box for cell (user coordinates 1000x1000) $gfx->linewidth(10); $gfx->rect(0,0, 1000,1000); $gfx->stroke(); my $wx = $font->wxByCId($xo)*$mw; # actual width of character my $x0 = (1000-$wx)/2; # left offset (centered) # light, dashed baseline and centered horizontal extents $gfx->linedash(10,20); $gfx->linewidth(0.5); $gfx->move($x0,0); $gfx->line($x0,1000); # left limit $gfx->move($x0+$wx,1000); $gfx->line($x0+$wx,0); # right limit $gfx->move(0,$y0); $gfx->line(1000,$y0); # baseline $gfx->stroke(); # draw the character $tx->font($font, 1000*$mw*$sX); $tx->translate($x+$x0*$sX,$y+$y0*$sY); $tx->add($font->text_cid(pack('n',$xo)),'Tj'); # information about the character $tx->font($f1, 100*$sX); $tx->hscale(80); $tx->translate($x+25*$sX,$y+860*$sY); $tx->text("G+$xo"); $tx->translate($x+25*$sX,$y+10*$sY); if (defined $font->uniByCId($xo)) { $tx->text(sprintf('U+%04X', $font->uniByCId($xo))); } else { $tx->text('U+????'); } my $name = $font->glyphByCId($xo); if (!defined $name || $name eq '') { $tx->fillcolor('red'); $name="NONE"; } else { $tx->fillcolor('blue'); } $tx->hscale(70); $tx->translate($x+975*$sX,$y+860*$sY); $tx->text_right($name); $tx->fillcolor('black'); $tx->translate($x+975*$sX,$y+10*$sY); $tx->text_right('wx='.$font->wxByCId($xo)); $tx->fillcolor('#008000'); $tx->translate($x+500*$sX,$y+950*$sY); $tx->hscale(70); my $ci = charinfo($font->uniByCId($xo) || 0); $tx->font($f2, 50*$sX); $tx->text_center($ci->{'name'}); # restore $tx->fillcolor('black'); $tx->hscale(100); $gfx->restore(); last unless scalar @cids>0; } # loop through x coordinates of columns last unless scalar @cids>0; } # loop through y coordinates of rows print STDERR "."; } # loop through cids of font # print out some text in this font on next page my $textL = $LoremIpsum; $page = $pdf->page(); $page->mediabox(595,842); # A4 $tx = $page->text(); $tx->transform(-translate => [50, 800]); $tx->fillcolor('black'); $tx->font($font, 18); $tx->leading(18*1.25); my $toprint; while ($textL ne '') { ($toprint, $textL) = $tx->_text_fill_line($textL, 500, 0); $tx->text($toprint); $tx->nl(); } $pdf->save(); $pdf->end(); } # loop through a font name. go to next command line name. print STDERR "\n"; exit; __END__ =head1 HISTORY $Log$ Revision 2.2 2007/04/07 10:26:23 areibens added lorem ipsum page Revision 2.1 2006/06/19 19:20:13 areibens added details Revision 2.0 2005/11/16 02:16:00 areibens revision workaround for SF cvs import not to screw up CPAN Revision 1.2 2005/11/16 01:27:48 areibens genesis2 Revision 1.1 2005/11/16 01:19:24 areibens genesis Revision 1.3 2005/09/12 16:55:05 fredo various updates Revision 1.2 2004/12/31 02:58:49 fredo no message Revision 1.1 2004/04/06 23:04:06 fredo genesis =cut PDF-Builder-3.026/examples/resources/0000755000000000000000000000000014534671356016065 5ustar rootrootPDF-Builder-3.026/examples/resources/sample.txt0000644000000000000000000000012714534467462020110 0ustar rootrootThis is a three line file. Let's see how line endings work on other operating systems. PDF-Builder-3.026/examples/resources/sample_55.pdf0000644000000000000000000001732714017067517020356 0ustar rootroot%PDF-1.4 %ÆÍ͵ 1 0 obj << /Type /Catalog /PageLayout /SinglePage /PageMode /UseNone /Pages 2 0 R /ViewerPreferences << /NonFullScreenPageMode /UseNone >> >> endobj 2 0 obj << /Type /Pages /Count 12 /Kids [ 24 0 R 26 0 R 28 0 R 6 0 R 22 0 R 8 0 R 10 0 R 12 0 R 14 0 R 16 0 R 18 0 R 20 0 R ] /MediaBox [ 0 0 612 792 ] /Resources 3 0 R >> endobj 3 0 obj << /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> endobj 4 0 obj << /Producer (PDF::Builder 3.021 [see https://github.com/PhilterPaper/Perl-PDF-Builder/blob/master/INFO/SUPPORT]) >> endobj 5 0 obj << /Type /Font /Subtype /Type1 /BaseFont /Helvetica-Bold /Encoding << /Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences [ 0 /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /space /exclam /quotedbl /numbersign /dollar /percent /ampersand /quotesingle /parenleft /parenright /asterisk /plus /comma /hyphen /period /slash /zero /one /two /three /four /five /six /seven /eight /nine /colon /semicolon /less /equal /greater /question /at /A /B /C /D /E /F /G /H /I /J /K /L /M /N /O /P /Q /R /S /T /U /V /W /X /Y /Z /bracketleft /backslash /bracketright /asciicircum /underscore /grave /a /b /c /d /e /f /g /h /i /j /k /l /m /n /o /p /q /r /s /t /u /v /w /x /y /z /braceleft /bar /braceright /asciitilde /bullet /Euro /bullet /quotesinglbase /florin /quotedblbase /ellipsis /dagger /daggerdbl /circumflex /perthousand /Scaron /guilsinglleft /OE /bullet /Zcaron /bullet /bullet /quoteleft /quoteright /quotedblleft /quotedblright /bullet /endash /emdash /tilde /trademark /scaron /guilsinglright /oe /bullet /zcaron /Ydieresis /space /exclamdown /cent /sterling /currency /yen /brokenbar /section /dieresis /copyright /ordfeminine /guillemotleft /logicalnot /hyphen /registered /macron /degree /plusminus /twosuperior /threesuperior /acute /mu /paragraph /periodcentered /cedilla /onesuperior /ordmasculine /guillemotright /onequarter /onehalf /threequarters /questiondown /Agrave /Aacute /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla /Egrave /Eacute /Ecircumflex /Edieresis /Igrave /Iacute /Icircumflex /Idieresis /Eth /Ntilde /Ograve /Oacute /Ocircumflex /Otilde /Odieresis /multiply /Oslash /Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn /germandbls /agrave /aacute /acircumflex /atilde /adieresis /aring /ae /ccedilla /egrave /eacute /ecircumflex /edieresis /igrave /iacute /icircumflex /idieresis /eth /ntilde /ograve /oacute /ocircumflex /otilde /odieresis /divide /oslash /ugrave /uacute /ucircumflex /udieresis /yacute /thorn /ydieresis ] >> /FirstChar 32 /LastChar 255 /Name /HeBoCBA /Widths [ 278 333 474 556 556 889 722 238 333 333 389 584 278 333 278 278 556 556 556 556 556 556 556 556 556 556 333 333 584 584 584 611 975 722 722 722 722 667 611 778 722 278 556 722 611 833 722 778 667 778 722 667 611 722 667 944 667 667 611 333 278 333 584 556 333 556 611 556 611 556 333 611 611 278 278 556 278 889 611 611 611 611 389 556 333 611 556 778 556 556 500 389 280 389 584 350 556 350 278 556 500 1000 556 556 333 1000 667 333 1000 350 611 350 350 278 278 500 500 350 556 1000 333 1000 556 333 944 350 500 667 278 333 556 556 556 556 280 556 333 737 370 556 584 333 737 552 400 548 333 333 333 611 556 278 333 333 365 556 834 834 834 611 722 722 722 722 722 722 1000 722 667 667 667 667 278 278 278 278 722 722 778 778 778 778 778 584 778 722 722 722 722 667 667 611 556 556 556 556 556 556 889 556 556 556 556 556 278 278 278 278 611 611 611 611 611 611 611 548 611 611 611 611 611 556 611 556 ] >> endobj 6 0 obj << /Type /Page /Contents [ 7 0 R ] /Parent 2 0 R /Resources << /Font << /HeBoCBA 5 0 R >> /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> >> endobj 7 0 obj << /Filter [ /FlateDecode ] /Length 54 >> stream xœSPp QPÐ÷HuÊwvrT02PIS0T0BCÏÜ(’« a¨©’¥ à T¬'p Û endstream endobj 8 0 obj << /Type /Page /Contents [ 9 0 R ] /Parent 2 0 R /Resources << /Font << /HeBoCBA 5 0 R >> /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> >> endobj 9 0 obj << /Filter [ /FlateDecode ] /Length 54 >> stream xœSPp QPÐ÷HuÊwvrT02PIS0T0BCÏÜ(’« a¤©’¥ à T¬'| Ü endstream endobj 10 0 obj << /Type /Page /Contents [ 11 0 R ] /Parent 2 0 R /Resources << /Font << /HeBoCBA 5 0 R >> /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> >> endobj 11 0 obj << /Filter [ /FlateDecode ] /Length 54 >> stream xœSPp QPÐ÷HuÊwvrT02PIS0T0BCÏÜ(’« a¬©’¥ à T¬'ˆ Ý endstream endobj 12 0 obj << /Type /Page /Contents [ 13 0 R ] /Parent 2 0 R /Resources << /Font << /HeBoCBA 5 0 R >> /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> >> endobj 13 0 obj << /Filter [ /FlateDecode ] /Length 54 >> stream xœSPp QPÐ÷HuÊwvrT02PIS0T0BCÏÜ(’« a¢©’¥ à T¬'” Þ endstream endobj 14 0 obj << /Type /Page /Contents [ 15 0 R ] /Parent 2 0 R /Resources << /Font << /HeBoCBA 5 0 R >> /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> >> endobj 15 0 obj << /Filter [ /FlateDecode ] /Length 54 >> stream xœSPp QPÐ÷HuÊwvrT02PIS0T0BCÏÜ(’« aª©’¥ à T¬'  ß endstream endobj 16 0 obj << /Type /Page /Contents [ 17 0 R ] /Parent 2 0 R /Resources << /Font << /HeBoCBA 5 0 R >> /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> >> endobj 17 0 obj << /Filter [ /FlateDecode ] /Length 54 >> stream xœSPp QPÐ÷HuÊwvrT02PIS0T0BCÏÜ(’« a¦©’¥ à T¬'¬ à endstream endobj 18 0 obj << /Type /Page /Contents [ 19 0 R ] /Parent 2 0 R /Resources << /Font << /HeBoCBA 5 0 R >> /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> >> endobj 19 0 obj << /Filter [ /FlateDecode ] /Length 54 >> stream xœSPp QPÐ÷HuÊwvrT02PIS0T0BCÏÜ(’« a®©’¥ à T¬'¸ á endstream endobj 20 0 obj << /Type /Page /Contents [ 21 0 R ] /Parent 2 0 R /Resources << /Font << /HeBoCBA 5 0 R >> /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> >> endobj 21 0 obj << /Filter [ /FlateDecode ] /Length 54 >> stream xœSPp QPÐ÷HuÊwvrT02PIS0T0BCÏÜ(’« a¡©’¥ à T¬'Ä â endstream endobj 22 0 obj << /Type /Page /Contents [ 23 0 R ] /Parent 2 0 R /Resources << /Font << /HeBoCBA 5 0 R >> /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> >> endobj 23 0 obj << /Filter [ /FlateDecode ] /Length 54 >> stream xœSPp QPÐ÷HuÊwvrT02PIS0T0BCÏÜ(’« a©©’¥ à T¬'Ð ã endstream endobj 24 0 obj << /Type /Page /Contents [ 25 0 R ] /Parent 2 0 R /Resources << /Font << /HeBoCBA 5 0 R >> /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> >> endobj 25 0 obj << /Filter [ /FlateDecode ] /Length 54 >> stream xœSPp QPÐ÷HuÊwvrT02PIS0T0BCÏÜ(’« ‘©©’¥ à T¬*  endstream endobj 26 0 obj << /Type /Page /Contents [ 27 0 R ] /Parent 2 0 R /Resources << /Font << /HeBoCBA 5 0 R >> /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> >> endobj 27 0 obj << /Filter [ /FlateDecode ] /Length 55 >> stream xœSPp QPÐ÷HuÊwvrT02PIS0T0BCÏÜ(’« ‘™©©’¥ à T­7Ï | endstream endobj 28 0 obj << /Type /Page /Contents [ 29 0 R ] /Parent 2 0 R /Resources << /Font << /HeBoCBA 5 0 R >> /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> >> endobj 29 0 obj << /Filter [ /FlateDecode ] /Length 56 >> stream xœSPp QPÐ÷HuÊwvrT02PIS0T0BCÏÜ(’« ‘™™©©’¥ à T®E÷ å endstream endobj xref 0 30 0000000000 65535 f 0000000015 00000 n 0000000164 00000 n 0000000343 00000 n 0000000412 00000 n 0000000544 00000 n 0000003728 00000 n 0000003887 00000 n 0000004016 00000 n 0000004175 00000 n 0000004304 00000 n 0000004465 00000 n 0000004595 00000 n 0000004756 00000 n 0000004886 00000 n 0000005047 00000 n 0000005177 00000 n 0000005338 00000 n 0000005468 00000 n 0000005629 00000 n 0000005759 00000 n 0000005920 00000 n 0000006050 00000 n 0000006211 00000 n 0000006341 00000 n 0000006502 00000 n 0000006632 00000 n 0000006793 00000 n 0000006924 00000 n 0000007085 00000 n trailer << /Info 4 0 R /Root 1 0 R /Size 30 >> startxref 7217 %%EOF PDF-Builder-3.026/examples/resources/aptfrontview.jpg0000644000000000000000000024771212105540660021315 0ustar rootrootÿØÿáb´ExifMM* † Ž˜ (1¨‡i¾Ä¥®zSAMSUNGSCH-U360HHDE30FPrintIM0300‚šü‚ˆ"0220  ‘’4’ <’D’’ L 0100  € à \££¤¤¤¤T¤¤ ¤  2013:02:09 08:32:112013:02:09 08:32:11  èdR980100ÈÐ(Ø_ÔHHÿØÿÛ„        ÿÄ¢ }!1AQa"q2‘¡#B±ÁRÑð$3br‚ %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚáâãäåæçèéêñòóôõö÷øùú w!1AQaq"2B‘¡±Á #3RðbrÑ $4á%ñ&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz‚ƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚâãäåæçèéêòóôõö÷øùúÿÀð@!ÿÚ ?¹gãjl¾‡>øÇó|i^ÕÆóÎîµsŠ™SRÔ猜tc'øa Þ` 5CÙ¢$sþMdÏð7M3$¶·7ʹÃÝGNÕ—$£ð³W+îŒø>Keâ&Ô"ºIâùYatÁ Ï>œ¦*ø[{Bd±–¶@cc•$óÛéZF¬¢ýâ5-„ð6“âßYÅ Þ•º58aÓ#9ýßÊ»ÿ°õHü½Fßû:à6]È\ž ã¿ZJn«•5¡¿´™·=¥Ó«L£xWPÄÃd^k†OÙžÿK×n¯ì5x¥Ž{‡™c•J˜Õˆ%GPFEg'R–ÊåÅÆz3’ðwìýã >¥ÜQÜÚ˹¡0ϸÆå¸ cœ§N† ¾ø©éþ*ÒžöÂðZHÆ)]ã,ØNN=Jòj}¼¤ÛjÈÓ‘%£Óæ_-ÚÇ´˜ä’ §åP ž˜Ï­:ÇP’ÏÄW7ƒdW#t¥ÜmÝž z•Öª.†<š›>,3^Cq*ÈæHÚÝâN‡çáöž˜éŸ¯¥vþ )¶÷Sº?énÛ’vƉ v瓟zÕJæN=NŠßÅftC.n%uŒ+yävÀÅn]ëfÓOyóædÛÛ¯^j®O.šœ—ö͵޳5Ãî/šÑ»œyg'õ9Zê<'¯Mzñ%̦(ãPvöcŒ•çÓ#ó¤Ý˶‡j'Œ b@f¤‚E¦=+1œ fœ cÔT•n¢*‚{FãœúRÈÿiO_xWÁ–wVÇjN§kò(¸»»K›Xõs’ùg‰íËž*ÖÜ˪ vìz\®L}+™×|y¢øt²\^#Ì?åŒ{~?Â;žs¯~Є›oC´’íùækÌøªÝU¥ß:çï&Öý©s5­bï¥Î¯Lý©n­ÕVîÁ$ÆAý+­Òÿiíä=¯”Ù~QG,e¹£o¡ÓÚ|rð­òãíf?ÞÇäk‡øÅâí+Yð…ÑÑîb¸¹ÆÒÑœ:.y`\UB‹Z™Êíèx$_¼Aá½…µ‚ŠHPÒ¹?†+¶Òþ8øÓNŠ'bóÀÃ!÷ä0üj¥RÚ±BÍèuÚíA¨ZÅßX¬™8 ÅÏêEuZWíA ^m[«6·ÏS»ò"³÷j/x×UðŸÄßx€fO-w³B§ƒî3Uõ¿xÆׂËQ‚Æâå<³ÕZM¡±ÉÒ¡«w(x²âù­â{+Ÿ!">d¨¨ •q÷rz}•y~¡ñsQð5Œ²_³]Üy–%]¡"…'¡>¸ïR§Êìö/6Çñçã$ZÿïêL‹mg«Dí¨YLÙòÜ.<¢¸É!øÎ8ÏlמxwâoмcðøcD¶‹JÒ­”Â’ð0Ë“Á;‰À'Ò‰¸ÃšÃŒ\¬ž‡oû$$çÆþ$ñ_‰%ŽÎâHÚ–p÷¯³$ÈùTõ®ßö°ñ˜ðǃí.c–Öv3 ›”l)ÛMÀäñùÑ'ÍIIlµGä‹Ï]xªâ8…ëÙ<÷PùY—lqÄÇ 8'=±ï^åᯌúOÁÙO¶Ï öÏ=.Dá1朌…ÿÀzV—.„»ØÖÔþ"x“ÅQn3K»Ž™òÐgØ\תj¶63I£¨µÄè~k{o˜©ààöXɹ>^†‰û·0|%®Éª|CÔ´–#´¶]È»NÿõhÃqÏ\·j½ñz‡ÁZã`-ÛÓµED”bÉÆÑÃÛßé:†ôQx'’aå`„Ü<Á’Xôü»ÖçŒ.mü <úU¬íÐ'üõc¸rÝøãµKk#+7dfhƒ[Ö§žêñÓ|òS>YÇëŠè> i—Ö~™ï ’Ýä1•YŒÔ©«ÛÈ|š|͘×g“ëKåîb?•uhqOÅu)áy™x;ÓÚ©ð^âçþ†e˜©7Œï›?*úþ«iI/3jQ½ÎêÝÞææÞ) ·EV;6œÏOj­©X@·r$V+Šn$RrêzøW,b­s^g{WÄ^ÃÖWŸa‘ÍÅÃ@ë¼.ÝÙµ« Y}½,o-çž8¦O3ÊvÈÆÒqùŠÓÙZ*IîO;Wgñº‡-qÉûRsêpkÖ>¢ŸxyáѾÇÐ6?‰»QU>X¡RÚçIŸòÊÊñ„1¼± ‚[ž˜íY׺¢ˆÄ¶HÂI2ñ9r@ÎGz×doÎÖÇ’ü=׿á2ŸQ†KQk=“^2@˜¨ã·Jî`¶½²qö{눦ü×g.ºîVf½‡Š|M¦gìú›ý[?Ò´®þ%kÚ­‘²Õ-`Õ­›’p’ ÀàäŸjžÌ¨É7t}ðóÃ:~¥¡XßE©,7÷6êÆ.îCv9ÁØ©üUð¢ûXÓç·‡SϘ S™x"KÎw\I*n•ÀàŸ1þ†½Kà׋´KŸxSA°¶I¥HšIÃE÷fÜw¹ÈÁŸLS„rMŽMèÏ7øßª\^ø²Ö}?P/:Ê#ž6—(Ùbmî”ÿŒŸµÏxOÐuÖˆêÌŠVÒÕ˜êŒ0\ã#t\t£™û7JÚ£y©_Áï øsÄúåÆâ!<,¿ÑÕdØÞyo½×²Žé^ÙÁoøÃßÛv†kÝFÝâoX6×jÁ â²-Ó5ŒìÜYÍI~fÝwªêH|ÆóTK ƒÓbJûâ¹/x‡GÓ¼]­*Çqrn(…ùiÆîKqì+{lž† êìOðþQqñsXtÝrƒ¢þæ"9ük±ø¯¥ÞjÞÕ­¬íÞâêhJ¤KÕT½šHªlç4…Ëy£é'X3%Í´rFð)Ã}ï»]?Ãv§ 8m#0y‚_Þä°šÊZ²ÖÅãn#pƒÓ°¦HQ†$uéJ*Ä3”N€œàÓ•³3^¥22Ðâ~-ÆòxRm¡˜å8ý¡Xþ »¼Óü hÐK,,odݳŽ6µ5ZåŠ}Κ{6޳Ã(ÔÛ\°†K*<È™Ï$wÆjmCÇ7vš¾ oÈ·2¨ê§ˆë×+-­N/âÖ°º×„ô‰„&]E•”¶ìþèœô鞈/‡tP Ú“ŸøV—÷có3–‘gñ‹Ãú†±áûD²µ’êTÄJIÆZµaáýAü9áó¤¾l6>LƒøÕ„ŽpG^„~udô±t­Ë©³¥\k>ñ’kÈJ[ÀÑ–-ò°™yP{ã"—Iñ¦¬ú® ó%Är\ÅÄ3ËœŒzÔs]\ÒÊìâ~ !ñJp$`?ïëW±ùcž?:莭œÕwB˜Ðúâ‘¡Ë8>µ«Ìz˜k.­iy+YêsB d)9Qô®£Jø£ã]/‘©@~éb¹úŒâ¡¹DêRRGY¦~Ô^%Ó™VþÎ;¥dª·øë`ý¦ô[ëhƳ£×Œ`þ ÖrQ¨­#TÚÖ%(5߆ú¶©u¦êiwp$¡¢eMÅ2=··#Ö¯i¶š d–1]Ã}+:_ 1,¬}s‚C1ì+aȹSº4ö­êÑÈx~Ây¼Eu‹øâ³œËæ9#l…sêUYÈõuµÓÚiútšÑÎÉàGÚYÛs<¤‰Áà(ˆ÷\Ri·äUôÐôˆµ…›tVª±(€˜ãUú €>µã^9Ô-îuKµ ,]Î’ 0ýÌr˜³g2?•&’VUäy ‹éw>Ô¤–Ý7â8¼ùQ£# FT+~UçÚÌIá­>õ´ÈeÓõKK¡/m1d‘07"·WÈ-ìki5.¨ÚZ+ø›áÙ|?•¿ÙV+÷R˜6L°©B³dää¯bk×®Ö÷SY¦i–ç`¼ÆsŽÇj¥-Z!ìmÙͣŞ]ä¶Ö#¸V‘ãr7EÆåÏfëÏA^™ãïjþ;ÓîM»X,í³k(Rñ0”9〧‘Z?v …i"—…< q¯X[jo:[Å1 #Á$(`ztèk®o…ú5η©Ü,·’]Í瀋òªãÙ}k)>m•}'šfªÞj6ÖÂ;»’7ÈXñò…Âú (­\wô½G÷ *¸cÖ¸êrzñOÌ™ rNj•ÍÜP™Àöè‰ œ ƒøÔÑ®;òx¯S¡æExUð¬7:‘ùSmà[`V$XÕŽJ À'Ö±œTÒ¹²n:!ñB‘̲ˆ"2! ¬ct==ª½Î…a}póMf†YIfe,¹cÔõ¨öI+íw0TÏO𠺧‰f¼´µ‰."ûlrCzàðBª0yÉoLòAéô}·…ltw’DŽg–yœõbzo@›×Dt'e©âxOÓ£O«$×pÑXáÉéÆzžµ[Y†ËÆš5œú¦”`·V2ÅgpçtŠ@ÃH2÷O^ù§*k”›»˜þ*’âó—öW¶bðÞD·DÈãÙê}²=+ç„Ú>œ5ÍXj“Ãswá–“ËŠLvî{ìà}sY$ù¬RÒ$:íæ—ñ3ûAïsÇy·„Ò*w>ÄRrI!†3Žç°¯9ø‰q£ø‚îÚ}>ÜÙïÊ0£·¯NµÊüCø¡â‹íóSÕõ9¥··Ìû,-µ~€t¤Ÿ³÷Q«W÷™RÇPþÎÛu ”?ºš%in›x ¸Ýœà3Ö½ÖßÇ_oñ`~Ñ4L®ÖþfˆÚJ’:/=ÎsÍTUÓ%6ÝÙÊøïÇçTñRè­ªC¢Z¡òä–HØ<ŽŒ×Ö¾añM•æñ+VÒb˜Ú™Le‚1;•†rÇ©'’~µ“½âѽ—+GÓ¾øMá™-ç}OO‹Wkøüó#¦!€ ª` òÙÆz׈þп í|1ªÍ­é…“O} ÛF¼BGSÇ;Hü±\Õ ã%4Í#.h¸´aܶž-gÔà>Lš•±ŠYS— $p¿ž+øw{u&£äÚirk„ŠÀ[Èw(v\däs[Y)ô=³Âþ+›L𽕮¤TIhŸdT# …8*GQøÑuãæ“å·óÛþ´¤ùÇkneK¬ê7²¯˜i‘̧©¨þ'Ä âÈ"$ëÇj‡~[’Ÿ¼yÿ‡õÖ¸Öï,¯˜¶Ð<¿|‚ûW8ö®ª릳Ôe[[¤62ÌŒ>r®£åÉôÉôô¦Öˆ‡­Ì_êZ¶³©ÎnîgÊr EŸ,GnÜV/ÃÛWû}©¸dó DiCHNÎã×5i6Õ»ÊÉ;w%Gi ‡rˆÝNà1ž;W-×q&Rg{šé“÷bsGݹkJñ Σ|--¯Kž~L€xúý+ Kýz?tÌ ê¹Éüc&Ö†É]]’'‰µK}Â[gÏrGøŠ|~<š/õ–äP?ýUJh|¶ÿâïÛ±çüæµ<%ãH¼C¨Km E!wÜz+DôÔÉ¥#Íþ ñ\:—ÚWi´)·Ê=AfçÓÜÛx5I7’ÄÉ›;O@FpAëȬ*KßgDb”R$O j>hX5BÎs´9aÐgÓ)‚Û^·]ÑÜÇ2cp ¯?Lõ¥·¥„ãmL½;Ç÷‘™-&†uAÏ—G×Ò?Ä‹ûwÈ\“Ô·ÿZºS¶†O]ÏPÐb½Õ´kk…U’Y#@¤. ôj[;¨¢>lúgkí5±›…ч¼o~™«)Ó§_ZÕ³&‹0·Ì9õ§°Üý2>”–¬vv± /×J„[E H‘†É!F2}ñYJ*÷oDV[tnö®kâE¬·žÕa·‰æ–HY#RY ų;oЦž »Õ ž-Nñ¿y,n6â¡X69àg®çáþ“ÃíjçS–YÙ.£÷`cå ~¼Õ)´îW/CÎõí7Xø§ñ&m.ÃM”…w›l'a^Foº¹tŸ¾ ? "×ÄZ~¢Ú¦« /ö“Ì»’,™ç ïÉ•a)J×Fê׳¦~Ó†ÇN°²KhˆŠßcyUL.yÏ_Jâõoˆúïˆ%¸–O² d '*Bòí‚rzõÀ®‰ÚhÏcðD–zæ½g¥ÝµÛhòÜ!‹œžúžŸzN·¬i>Ô–‘áѤjPj MÍ%à$ðI㨨µ”dZwºãÛêÆ™aˆÞ̯-Ò˜Àq7 <Ìz÷zü úU=RòøØiM´&Q0“ÈL•” ŸÄÒ²½ṳ̈´±GÄ1"ëºX¸¸VÅœ¼×,NKä•5ÝüBµ]ÛÊNG¦Úu»o3:kUèxÞŸ!²ñ?‰d1YLB¸àþíx?tÖo¯tŸá=.s”€8úÔ-—¡¤–â|5е»½Bò[ˆ/±¸@Òä)&3´sï]OÁŸƒš–‡5¾¯­[­ºA1[1 ò¾ïMNÍ5Ø™Fé¡Þ8µs r:}+–$ð9®©|*Çž§'ðö0>$ ‘‚ª´Ä“ÀF¯O¶½±žtº361Èò5•DÝFÑÓ²Fƺ Rhij&Ò¤˜É|¢ym*ÊG“a—ÎÊž{äT´7cÏ>'î°ð³]Û˜üÔž!æ¤`1®xéSüin®ÚâN^KY²qQÛéU´/©Î|%Õ_G°ñèÛ|*C Œ?­z‡†¼qæÿjI%˜Ÿ4ÊNn:Q;s3Mmr÷…µÃx£ÂúŸÃÝyt+är—DtŠBܧ°=ppqüêpš‹ZI-7!¼ðÐÑ ‡T¶¿’-'rÅJÃrÊ}@è8ëG‹|ouãi76‘ªO ¸·>RŸÞm?.IëÜûfµNë•÷&ÚÜô kLÓgðÖ›4ÚD‹âk0D&Ï«‚rD‡Œþ<â³õoø“Ä¶Ú Ÿf‘æÛp× +…ØÍ"•'Ž¥uì+6’gQ/Àm{ĺå…Ú©ñZ[Àá"có.ws€1Ï­z–¹ðƒZÖî·mŠði\ƒÐdÔºŽjÖêR‚Z™šì»m§ê·z…Ýô3Ëv¥d‰Ô¼{H¸àz×_iðrm9LvFÎ8HÁòcØqèF?­dù´ì=l|>]1w]rxÂò r:‘Zi6qÄdfV 0[<(¨Z™ZÎâk¾ð¾ºŒ—:rFì?ÖÄåHýqúW‹øÛà÷‡á’çLêvc$áq"qÜ{Òºaî´ˆ”y•Ïðþ…£ø®[»‹9€ç§Ì¬?\´ðN¦òFb…fPGÝ‘I?†iV¦ËŒtLÕñ¿‡u{Ÿê6¶sËo'–UáRÊp€žâŸ¯.µmá? ûlL­s挰+ÈÆ”Ôþ%•‘Èø‚êòçÁšš]Ë,».-ЉI8Ë7zî¾ÛŸ.É€µ¼Ãõ4÷ŠŽèßÐ>Ï£i÷ šCIk|Uw3å<޵£ká]4Ý¡Ing·’ÙòÌWÆqœóÅ&“we]ÚÝ´?éÚ·o¨Â÷á߈ÚE*Û¯÷}ꆗðæ "îÆâ;é^;I#}¦—AÆwwÅ;;=AÊïcáç€õ/ Hß$GíJyoœ ÌyüÅt_b+ö¥Ùó˜ÈQÖº"Ó9ÝÜRðv™q>›fèU`n=N8ü+±Ó´h“í-.Ù@øöâ¹æÛŽ„’F$º%®­aii:FkwRXùg=ý+εZƇ<6ñ=ÂÈ §Ù®•CÜ`²žÁüi= Nľ$øtÞ„éöcu…ªy0ÜM*†9,À1Î[ ;‚çNñ07 $vr_ÃjŸäÂáqï‚qõ¤´-ÙžgâMnkÏêS €ì–ÆE‘J’§ÌE©­…в–Só½¸cõ ÞëÐΦ©mþ±o§4k<É “;w¾ }?:⣭dôÔÕ+ZûêR[³¾ä* üõ¯±þxa-¾iwv÷±êq]¹¸ŽàX0pʇ³ëÆqN;6R<ïã׈u­OR:”&ÒÆ(¸òŸ Ð`#¯Jù¤ÀÌ#dŠ7kÄ€€T8£98&²NìÚÚhz¯‚ãÕ‡ÀÅ… l Më#_Ãz‡„|S|, ²{I™r¾lq…b;¤ó×®+¦ ôëa!µ‚5w'hÏÓ44Õ®8ÉKcŸÓôVðÆ—µÆG•#”x”ÝOáë\®«ñ“ÃÔn4ýN=@^2…ßl‘ºa×;úñÒ›Õ‰.…#â§#¼¶fÖo­Ö%)²æÔí`T¯;Xúçð«öÿ¼'¥]ÈöºÈ¹²“ "Ž”bz…Æîr8ç§é8»ÞãQMtäÕìZÖC$k$‰ Ù€qŒŽ × ¯øZ5Ó®¯„²"jÂì®ÐAÆÃnr:æªÊÄí¹â÷ îô­Q†Öu¾š{cÆcÙÖD$䓨Üð¾Ÿ=®sD~ж†=£ïnیƮ [1Ió$ÐùDz³>YbÌë/;Bõ$þ¾„ø+¥Écá{k[Ý>ïIKxBÜ[^!V’\rüö#®8é[EÛî3jïæaøÓOÓàñt0n³Õoc2£ÃÌC1ž„vé^“©x²=*ÒY¾o"ÝHù³ÈT­"\·±Å]|cvÝäÄÄDÿX·¿¯æÿUíôfù m·¦‡;}ãýRvÚ%HÁ'‚I5gDÖ54Id{œ¿@$”~5PŽ™JWÐÚÄË*»´I?Ú¶pñÖÿrÚiÒù–w"Îìt!Œ2~3øf£‘©s"”ú2×µX~é²Þ5Û\K.DJàÕãºGÇÍrûĺ}…´ks’¬eJᘞâ*Üm6kÊV>³tVQ£s+ 2뎕•yd ØI'$W,5‚e5fixb²iILŠÍ>_oóë[öÚ%Å®ºunؤPÛäaü@õçÒ´Z¹SÆ,º­…ܱ\KasŽ{dF9¡  þuàÿںljníôéÞ{¹Ë°ýß´žÀ莑½ÌÚWµŒÿh:Ÿ‚4Û{ÍF¤^Ý2¢±{€FFr=+#þ_ ·U’7æY!~BÏ5<ÏFŠpV/_jº>›©\Ø\jö°]Á"0c‚W#œc¡®ÃÃÿäñ]”†Êþ¸’ßí6P ÿ´ëò‘þzV’’0TîîÌ_ü7ñÃ+m3V½QöIʫ씻[³tI==€xÍ1¾*kšz•†öåI9ŸqüÙMRJQ»CO’Gñ#ãg‹Î¬µ ä|?œ±ÈÝ HAÖ¸í7Q¼ñ ºj¤íszìUä`àtzsXUÒ6:i»«’Ý"y‡i þYÓkQéWpJe14n® uÈ Žpk–(Øè$ø¥â=Nìj‘ê­$·Ï´Â²nhvó·oeÉϦ}9¯w±Ñ~&\|3þݽÖ-DekÛ++ë5LŠ7[iHû¹ë[óyËÕ³žø]ñ?ØÝ]km”΢6’‡ƒœ€¼ž•ÞxsáÝ¿Ä\ÜÛκmª@ Ãü®IÈ €^£üó´v¿SžI'khz5¿À¯ $LºŒ÷WÄŽˆÂ .ZÛÒ|à? ö_iÈ@{ %o®_5ÏìîjªYYGÅÚ]šlŠ{hx •sŸ5·ŸÃM}myå Fe|¬zIìMiËË Ní\ð†ßÄ¿-¿ ­¬Zd¼nÅ|§—€¬§» ·çžÕÑøÃ:—Š%™<*ÐG8ó¶Ã*’ÉÇ¡ëUnh¦‡³±é¾ ø_áχÅZÎÆ ½a•MƧ,`»¸Pì^¸ŸRj玴‰5>h ¸6wL¤ £õ÷õk9E4ο¼!ñÀúì±éòI§yæk‰QÑLßí(?{ŽÃÖ»]G⯈ü%¼N°Ï2\•+ŒýïC‘È4s9G•ô+–Îèñ{?j·!±¹bÓ[AºX¼˜ÙòØê¸^„Íi|Dø›=ÿ†-fÓ­&7FeWÓnß\çüý)Íû‰µ¹À[ê^2Õ†m´÷žæ@ðæ¤ øæé±Š¤’äãòÍg)ò»48Å5tbYèZÌ÷±ý£Sãp ´uçÖ½Ä Ž°6ìã•ö+²?ÃQ®rÏÞÇF‹$~B£hb“hÌ“ÆïÝæˆ®ä¶¬e||×mu]5¬:ÜÀRx»‚G­pÿþë~!ñž¬ñµ¥´Ë)º‘6‚Aèž§é\Õ¥jJ=NêQjìû/Þ(eÈ^Ù§lÇüë8{±H]F=ÏÙœ`óÜÖí¥üˆŠÅ»V„ÞÚ–aH¯$V±œüÊÝ [Ò<3¡øjòãS´†?í+”̧*rW= Ï'½ÞÐǘ|rÐ`ñ=­„—ÚÝ]ÌÎi؈Òqó&â;d{õ¯oÙ?Æ·7nÉy¥C‰2äÎÄ œœœÓ«4’EÒ‹4µïÙgÆïˆïu#}¥5ÆÐíœáBçîñ^ñð¿áûø+KÓÛX’ÞK‹£Ž3 þív.7`Žy5’©Ìì\ãdOãCIñ߇µ}=B Úê&‰U$ wÿ=Ãø×‡Ëð'ÆÒÙÇ!Òã.ê F."ܧŒ®Å=,rJgœøëöøƒ-²›o\Êèû‡É!÷É5WÃß|gi¥Æ—~Õ#1-ºÒNçéXTm³¢ )$‰õOkð)y4køÛ¦ZÙÇóæþ'Ð5X/Ä c9™£2yM ݰ Æ=HçÜW72¹»S¡ø3ö¯x¿N¾špyžá Xâ+†|{Oá^¥¦|gñ3øRëÂ’la‡ ï½JÚ™JÆñ+c*¨@Ç9^Ù®˜IGs'-S3¼'m‡-5»7I59,¥X£’ÐûC(mûAêsùâ½óöWÕ¿µ.¼opmZ(t™a²oùhì»ù^ÅGQô­á/tçœnî`|yø‰©x+_²óÜKøœª¡RD##>á³öMxýßÇ+—c¾ Ù›®Ô= */dG.¥}?âF·®\ˆìü?u6zùÌp}G¢øbo|%ÒßSytÛÓ Y-£!•eb‡o÷ŽzÐÓE¥ÊÓ<ÇŸ µÛ§ºTº¹Ñc*¤¾Ò ƒœ`cû}k诃v-¥|;Ò§¹œÜjЛ¦‘úǤcØ.9îMM-‰­KhÑÐY³µë>2 óTµ{Â'r}}id\kPÛÁ/œûzr}?øóã7„üu«XÙG*Cxìò6|ÝF:‘Ÿrk Ý4ÍàìšfŸu]vÆÞÒþUf ýö1Àt¬ûË›»ýNæS ¦Úì‹•’P£`+/¡è9•³|Íy5h³µð½À¶·ò².ær9Ú3É>‚ºËؤŠ)£tp*ÃÆ®¢!²§§ãiÒG9ÚI#€}+Þ4ψ–þ+Ñ£µÐ¼¹5!b² \v ¯:ZÔS}F_*=7LŠh´«XîY^éb_5—…/›+Ê‘¡c€@ç5Óus.§7­øŽ +s;d¬n¢N’?mé(²žäÚ,›daôïëíIÉ!ò_CrÒRüƒœVŒR<\ñU¹Hõ]2ÞþÚ6¸…e¸‘7Œ:ùšlz„¨ìÛXŒóJÝ@´º«ã£gžÜI¯Â•`Ø dþqVÄÙF-:Ú9–u…ç¨Nki5M‡ãÞ¦*Úƒw'MLc9ÔŸÚÀ¿‘Z\–º_kæÂÎY‚<ŰŽ!–lvŠðmgÃß´+–øÏ}ák˜ü5l­n->Wò­$•2¯;þb,àW'ðê<±½ÝŽì6URmÚǽéÞ$µÖ´»]BÞŽÚê%™#¸k…a­IqwmtTÏ 2•D Tzjì²’Ôä»[ ³Ú"Œ[À=«O4& „·EµiÛ|¦ dlc-ާsG,VÂm½Ìhtm:çæÔ,íõ b'Ëk¨ÖSG;wgüê¥Çƒ¼-3³6¦‡n¥mQIü@¥b´D:gƒü)£_5äLȪGÛO9äg¹ˆ_-¼,d…í“ì®ñ xF<ÿ<;âœU´ç¬ÚmoØ´öè²ÞEçå 6vƒø`þ5âs6«¢ë1ߨj1jWv²<0éj…¤ ÃXù€ÆÀàt«—»; Ž±³=fKË7F†K”H/Jo’=àª7¡#ŠåÄÖ×öK{6¥läùps‚A§zRo]–šžeâ?ˆ6— ©Í1ž&³¡W‡b»ŽG’­xůˆµøªÚî[KxÚñV7¶{äàŸçY­d“.ÖLÒ¿Ñ^çÇ—úW›$,Á>Ê`Œ¼j}# ~Üêš\Z©¦èÇO·Ú„‚(îdle?Ý=©­˜J×=kFðÔ>ðûE{%¼·.A.£!qÎ=ÿ•c½Ô^/ÐäÕÕ¡+rÎÍ B@bc“ÇÓž=k*ºÉ®ÄF6D^ øS¢ëj”¼×*Žo›@É8ÁçØWG§øgEð}Ã^]]™_Ío) €ªØîéëéV¦â•„à›ÔóŸèövZ¥åí´{{朵¹Î0G_é^mâá=Å£Gg gïù.ù#ÜdÔÂÊŸ+“öŠGŒøgÂþ$ñ°t[;‰.dpCò‹ÓõÏÃ/ƒšÃeº¸”^ëoÙ&?r<õUÖ¢¼S©ì㱤ehów;ü[¦ÛBâkÈ!d8!˜j¾ûY+#ù8Îåã5m¨û¤ÆûŽÖlÞ›-¸ ¼ˆV@Ã9ô¯>²5Äc–.$U%ÉÎþŸÒ¢TÓV4„µ={÷Föù =V·AÀ^Ý«HìdôeÕf6Îä€J¯Ó𝶖‘ábt¶ “É­«¢:•]4‚Guܳ‘€y#¿<ŽOj‚ëE¹Ô5ž=`ÙÅä5¿Ù —sĹ?ĸ Ž™j…Ø áØ>R_¿5*é..g‘®ˆ¢ £ ÀgpïϹ¦´Ø-Ô°ºdœm›z1¹Fs·>˜¦e\lR·i’ÃCê3ëøPbÿf̱.ùÕËC,{qÆ@ëÚ¼ÎãâõMàÕ/A»ŒJ–ÆB ,‘þñ›œO”畳©F5Ro¦§E:Î=M:â°Ú›t† ª¡Áh8©`²ŸËf™¡ÏDdŸc𵡋îRT¿%÷En¨…ÎYxçØõãØU‹H¥ye±ª"‚¥$÷Ý©Þâ{δö:ˆ· 7ÎâÄctŠ?Õ+O}ªcn!X~óÕ"oOújáWm Rm–C¾¢›R œõ­h5 {ŸØø6ãJ´˜£Ë<Ñ[¨Í'c¨½h±W:½fö+娲ÎpG9í^Aoà›£ãi¼K¦Kl’Ú—ÊÄTí@ëÿë¢Ú¦RvÐóüdñgúw†¤µ´“W·wy]˜åbÉ#’@û½ rþñ=ÕÅÃkQ,7úœE\ež1´‚Ldz*c+»•ËʬzN—ãOÙ__ê·*uBO:2ÉÊB¼(#œ “Ͻ|ûâ›ëoøÂç\†ðÛLX2ÛŽXu9Ç~(’NKȴ쟙ëVÿ´ox~ÂEíêeÚi9`ÍÉ9üqŠë¼'âeñV·¥\Ǧ]T„€‚9=…h­)\ÊÖ‰Ö뺔w¨ÐÇ"J@û§9Qƒ§ã^gá ?Q²ð>›gÈ ó\¬‹)ÆÅ9BO\9çŠäzÊF‰èíOÂrÛh–ÓÁæI2I$I PŽ -éÇOʽ7Á‰¥ø;CœÝêêrÏ3LÒl®ÐzžIÁ5tÝÓ"dµ³XðΙâ­.â{QÒ&øî#M„±rp¾kÍ.>C‰6¿â5HT’ÐZĹ`}OAÛ±©Qå•Å{« øOñBE9KD‚ìŒHèKúšïnË´dž¸àjié&‡%±áž.ø_}â?H–¶òÙ¥ÓyÏt€4c[ž Àü«×|?¤ èÚó Jö«¨¹ªGÈ£ <)âí‹FÉ®i!q²@6€os‘Ú¼çâ_€¼[e¬é×E½Æ§ÕËy»+lw<æª-s8°}yð^4oYÛ<±ÍtyÍùww8­™cÀàsß54ôZŠ[èMe1GÁÇ_Ò©|4ø‡¦ÚkÞ%ðÖµj±_YÜ/•#)‘e…†èÛ|¹Þ@=ö‘Ú® *:³¿—DðäÒ¼‹d–Ó4b#$.@Àã©?s_ðª­.oáÖ…â¸B’Å–Yø ŽßNýjþ$fõ:ï‡é{¤±üêÀìô9õ¬)¾GlŠÐjË$êÉŸ1N ¬¦Lu÷#4쉵ˆô ßh÷DÊ(·1 „O˜ìäÀT–ºXF ³¹˜ú±К‹E°ð¹Sž™Ï*IþB¾l°Óõ$ý¬¬`}D›sn÷%Šà*®y'v2;gŽ*ãuqŸGÉmæÊÀ–°«6º,óÈVÚ)eìXåºJÄ‘ª<{,jûQIçk75V_ _é°ÈΊêWªžÔ5¡VÐóMvÂKß´kò40G1$g K’?ñÚÈ´²—L’ y$ ØBËöT#óVüé­,JÜôŸ‡~ybMJò2–ª` 4ílÕíWIÒgÖ!Ôf²†+›]þUÒ®Æ]À‚2:‚ àÕ¾ãŠ<ûHðÙ™.-u©–Îid{e8aÜwcp=ÁéWíu3I[ÍÝ«ü-ÄÊ£t²gåݵyäñ€(]Šg›üSøchu8õËHV-r2«&òJÌ£øzÓó¯ñ¯jÚ¼ú¶‘áÔÓáU-åZ:¨lç–'Ðuö¬mg¡­î‘ZËAñŠ´¸/d–d|±¹B·—Ü`Ž:tÏjöOü7Ñ—DŸEº…öæÇqb©ãp=»V–M?25G-ð÷ᦢx¾çLÔ§²YÈq±‘ÕXóÉÇ·­}i,pA¼*±D6' #ð!¿‰žQ«Á¨Øx«XÓ¬­‘škµ[\ÎBzydО¹æ®é¿õh4!p÷+§$;¤HËya±ÊŒž{×*ŽŒ¾§wð«Äž Ô`LV¬@O¨Ý¶À\c )䎽zÚи¶2¯îÊgù¤p‚íýÂýp+ã™mgoÛÎÆ4B®örˆ8ÿRüV¶asë=Âò<’Ísã*##†é[ÿg¾†0Ä‘ <"c Ú5ÇÍ7®jHoç•Õ^sìj€ÊÕ|§êR] '·º’?)åÊ9þ$Öÿ íæž âUHæŽR¥Ì•Šç=öQ`ÜìbŠÚ’¬Q€©áT€ Ëñ6›i¯éSX]DÚdhÊ©ÚpFä~Úºt±âþ+øc®]XAáè.Y¼9kSÇ1ŠêÕT ¶9#{®Msž0ñ¯…¼â? Á:ùºö òÎ͸.ÝŽ]²I$×#<ö¥~[ýãŒø“ñu”ê;"c«GÕ’ZC Ëu…¢•Ô¿ÚaЪ0/Ž9ã54þ˜ZÆ2x–{?éšTñ7a°èÙè¹$ƒÛ·Ö»iðAïÇzÑü ¶—»]Y•²Uj_í&eéÍ$M„“.NÀESOL/Œ2[ùpä*Ê\e³ÜLñ@X‘µÈÚg…_÷Švœ~lg•Všw”c$Ю”ñÈ÷©vy™ôÅE%‘ ‚+Ã~2ü ŸÄRO­h66óø€[µº4ϰ$g‘Û¸©jåEØðý#ö6ø…:Ius¥é0¿úÈüÂÍëü*A=;×¶|4ý™nü þÿ´¯¨ ],6Ê»ûcs{ö­Y-î_Ôÿf-P†ÍQ¿µ’Ön&Ô3¡ç ò㯦)5¿ÙëCÕ¼5‹¬ê7v²º‰\#¼¯#Ò£¥Š[ÜÏÓüðÿᔉkeø3LA{“ÔWãÏÚ_CÑ VR-ÃB6EohHÀè8à+9ÔoDh¡wvx‹¾:xŸÅFH­dk+v= Îì{·øV•à‹ÛýGA“Z¼û ž¶\Á{#È_¼HÎG#â³Q¿¼k{htpø{I³øky}JÚÝ¿ˆRÖ+’ä3Z«)b8ägš»®Ïï‹|HŒÃv¥oî>‹U-]‰½‘nßXŽ-_FPÛ^ëJh#9'¥s3ñGøXgo'ôÝk«Æã[žÙ«x¢M_PF²Y"¸¸ ™³å¨nOÖ»ý+°é–È­$“>Ifç$úÿõ¨µš“ÚçxÚüø;â¯êwpÇ¥%»Å ¾ò’8ǧS‘]³ãËh4È.a“ÌûF A%³ÐcúVõ¥UŒ¯ øêÛÆ:…Å£Ù0½±_ß”Çòœð:ñÓµvþ ›OTkkO1] .³1g\±ëí‘Xs]´[‹;rçÎEW°Ô䙜QÊŒö÷®‡±oŠ­ ñn‹5´mzˆŒùèU9ƒëÛ­s³Î³®ê6S¦« ÐÙê±Ü©ÊûYWÕr_Z™ë£k3Þ4Ç1Ê={b·B¥Âà0ôašÑµrÑ,ã‘œÙÆÒ2?JGÓ ¹V1lÇV/"x´$äù½ØsR&„Ü|¹”n ¡Ñz0}kå¯hB×öäðEÃ0Uš7wØÁÿ¾¿J6¹q>°R’pÀÓÿ²X¯  úšhƒ/Å› h¬Õ䟠¦Ç_X[\4²BI!× ØÎ8ü~” ]?H‰ ºhÊÍ;‰˜ŽvmÁ¦ò§0‰bžNdÛ&ÅFNvƒùÓ!Ño-5õº{6Co'’Ó. –†Qî kI4ì7¶%–V,Üÿ:㉻~”й CŒÿ:ÇÕüEa¤!ó$´›²y7>8iú"H÷±ZF½‹OÓÖ¾xñçí]öñhÑ=Ëtó¥%WòêJçrmÙ‡VxÖ­âŸøúú$¹º˜¬î#HÁÙãÀŸoi_äž/°ÖîZÏRðþž/ž(°á÷}ÕÝÓ±Í5 jiÍtb\ÙÅà}BÒÙòÒOh’ÈàýÂàöªÞ-šk[ K™ll¡h-ýS$’?úôÓæüÄôz-i®…¬9r·ê¡aÎq¹cbq×9$V’¹ÔµÇÔf£®Œ%ÇNYd…T•›0Nå])¤}KÂHè|Ƴ”tô<ÈWskðs^ø…á 4%µ”jd–îá¶"‚¸ÈOà*Õ58ûÂu9%¡ßü;Ó­nuÍOZRg”F ·çïíÇõ®ÚïÄ6’ȱŠôÏojů}±[DŽkâ€ô_øpCªNÖ¢'Ìd¿Ò¾~øƒ§\éúü6ú Ôú„66ñù-ªNüààâþU§74{!%g¡ê~kÞ“R×5«“%³Û–·ƒ$¼ò0Ë;¼t÷®Óá/‡gŽ-CÄ7³Ë%Ω hÑÔ¢Çû«´÷É'>õËÍûš¹XôõˆÍ|sãëëâ’xî-%hÞ;¿Ì=q]I.Vdž¦?Éw:@/gÉRìp¿&½KÃ?4â»áÝvHo›OÒF ²1hÑ‹pœ`ÖñJwmhLº˜Ô>ø ?)Væ?DÎë€Hó»ãÓÞ»mMDþ,ùÅÒtx–2FC`qÍC~õûÿ-šþ·;?³Ü…Œ3ßž? ôO ü×µ½Zy¯Óôó¥­ºÞÌ6«±V ÔðßýzêInÎii±èºƒ¼ðÖÎÅðºÎ­e•öÛ¬`w;S ä{Ÿzàþ(þÐ˦ºÇ}£w#8TQXÔªÛI 5fkÂζԴk˜ô ÃDÃ÷*"–<“’©&¸?xúîïÂðŧ%µÖ¨×'ØÉ!O$zýjvß¡š×Cñ'Ä-zIÔ®~Ðãå’5|*æ´}jh6òÜï$Æ«ÎÃêsõ¬¥¤li¯1ïþøÝ¨On×V2.›fˆ¬àn‘Àà¶é]÷†~$Yø‹íO¦ÝáaÃgxÆXã¶8ýjaîFÅÊ:ÜYêLjÒÖS´ ’†8ߑӦk)ÊèÕ.‡Ø>·þÉÒ,lW„¶…bP: b»;-Hl°ýkxhŒY³k©Æ@†jêj1)åÆ}ëTJu˜#É.¸öæ›ÿ ¾8læ˜!â[p„ ù[Ç—°ÛáÝîà2P®pÝzŸjk©ksêñ^÷;@çÖš5——¾©[Oó7äun9wR P=}3V@#Ò˜¬L‘äqJcQ×·­/1Ø£s¨Gùh2þ¢¾mý©¼-÷…µ=TjWV1¢y—I ½8ê?ŠÂ®ŠæÔ´‘ñ&àæ½5õÉ1éÚ¥çÙb æE=rGÒ½#ÂÚn‰áx¦Æ8c¼´‡N /‘ÖRy##‡Ó51|©XÞ^öŒÊ²¾)ðÇÂðH²$Qêk3HêvœH§ú èfb»ÒÖxýh}¿­„ôW9>êò×Ãñ•TûœÙ‡ø·Ò»—ñL·ß渘í›Q¶Xœ€HuÇò4–®!§+<ëâmÃGñ#Qeí³Œ{à†¯]ð‡ÁOÇ~ð|ñ_¦•eiù.œeˆÃcb÷<ŒŽ8&¶¢—+}™z#Õ´ýÂ? c¹–ÂØ\ÝÊÛæ¼»Ã±`:¨<«É|uûJÛG+ÅjÏxêØ%N}3Ö³«UÔ’V"²»©¥Xiz:µµæo®$ضñ°Wø‰í'OÄÑ >7’ìDLžk qéÅCáqÚÏB­ä¤.Ÿ"Þ†ecŒzÕVMPº’)ÄdG#WCòäôõ¢ÉY÷-jRÿf]ÜÙÞ[F·Ö’*/– È'¸Çë[¶>)¿».ãÚ]’(HÈU+Ž}zž=«9t¹³¥øØxao¦1B«/$cýŸz÷¿€–žu­ÓÜ®ÛÔeS 2'lþ óU%xó ñiØ”~µ§þ¹®Ä`=¡Þ>é¦5›€N0(Z’fÞ£$ls€8JÞåœçM脵%’í#…‰`ª;“^ ñPïøÿð¶æYeœF[øy‘Gùª‰HúŠ#…T+u­H-Î4·B.yb$.HFMX‰„‘£/ÌŒ ‚:`ô MÉóÇjD”ç‘DÉp=)'ºLsZlqsø*Àx¾_.£~…à˧ ¿Ñœ†È}¤pÝFAç_´Ðøá¾¿l¯¶Ý“nH~¢±«¬lkMÚIŸkZÙ¶ð?‡Õäh”_;̨0r¨pGÐÓ<-âÑì²Ê ›È¼µy‡ÞÈ|¬ma©YDyž¹]Ù?LVMô‹|Ö à™ÊƒÙr¼V‰]܆ô4,tÍsSñ¥œf{†G+8,H½;À/&—FÔ/¥{ ¬‡ü{2'æÎr´ceÌÌ›¾‡}©üÐÜñ^‹¥~Î6‰§[ÛßÞ<²[»4S@ pH<ƒô®»(XÁ»èwzW­#NrðÙ•²ZBp_¿5Ò.‰,$Œ‘úЉ;»‰i¢5ìm œvâ°üd­R•>QçoCÚ²›²5†ç‚xv6·Ò~-Nì¬cÒrHëÛë]Ï»Ÿ¼9¹@?hs·èþb¢+Ý~‹ó4“׿[Öu‹é«s œ·Gz©òÇÝãqö¹àOXø¿[ÔtÈá–ÚêÕ<в®7§Ÿl*àï>SžwµÏ ñwÃßÿÂG$í§ÉqnÀ¨û)ÆW²‘ÚªÛÇ}©Ó|I§$æ`Dæ5è?LS«M;J/aEÝYž«áoƒšæž“ýíÁéqzêá.";P7rp+Topå2×à‚÷i¶ÞÙÈÉÈü¨Ö?g½U¶eŽÜ[̓¶Hø#ð®•;;’ã¡äZ—ìãã-A’Ö[i¬Éâ@p@÷½zoÃ/€ãÃs¥íë nû1ä-c^=B2gµiÚ,vèQôÇZܵ¶ Ž3XùhÄ<±žÂµ-œpvã=¨¾ µ/)õÒà’8ü]ÉØ‘b=y’XR»ŽqÎïLkPbp°¯žþ0ü?ñˆ¾)øKĺM²]äê0NÈÎj«‚ÇŸ½Ç8­ +Øú6;õ¸ ïÆ'$Té6@‘íQk­>ÑþGídÉ!#o8ëÖ‹¡(»ì:úTR]Ðu  ^«:âRÂE·2~‡Ö¸‰1Egà­uîîÚÜæIŠÎ_ 5†èðŸ…? %ñ‡t Bg0Ågq2É‚L€pö<õë_‡VI#ˆ‹n'†9ÛœwüoqX™I¶oiú6¬Pı 9 £“Ïë[6öATp*^¢è[K`>ðz d>Ð1R»‰ê{%Ƨk¤ª)`¡ŽÐßÞ5ÊxªæÎÓGÕÒ&K†š3s 1lŠ@*;Œðqìj%vîf—si¼Pêã¦:ÓÓuÏ´HÀñX7 Ò:(ãÚ¤òÁ#ð¡>¤’$`g‰§¬Y=>•wd±ÅíœTâ=تZa8ö©•0z}i‚ŠÆ¤ƒÜšóOˆŸ!ðv±e§\E*}¥—ˆÂ†%ºp9ÇZq\ÚǘhŸµMkÆ·z%½³]‰­¼Ÿ»9å¦ïl×ÐvÒ2 œœr}hQkr¬JdÇ~*5½òØp «¹ cF9âÊFáïU–ì#rF=èLwLQy™vNhE!*i€ðsÔ•ïšk Z6®{Q¶Å³·Œžž´Ñì~tŠ-ÉíÅXKO—æËÐp9ê*„¶fVcšÆg¤MÏ$w4ï cŒtý(½ÀAoá"Ú˰Ú‹‚"{Hp 9繬MgÃV· ¥í´sÆãißÎE8½à׆µëZ@ŠKKmX¡ºh$;˜§Ý<ç”ý3D‡ÁÞ°Òmåi£³ˆB²°˜qŸÎ‰MÙÛ¨rÝ"™‚;æŒÍrŽ$]ÿÞ ×1ã{?ìÏ´_ÙD²Üîó¦‰ù†ù}:vÖrÙêgkm'æúý+SA×âh†Q×5ÇѰ[žÁ¢CêãS«)³N›¼P=Ç#;Ôɯ¥l»‹È\mÁ©¼ÕQÓ5vÅYp÷©EÆŠ=Dˆä”°íŠÃ×¼3aâk'¶ÔmÒæà«vúÕq|º¡Úú~øs¡x+Îþ˳Xe“ïÊÌ]ϧDÜ?‹°Ï­Tì‘(„Æý _Ò-•¯âÈ<¸æ¼öRzŸBYÀÑ[Ç©ÀP=úU”V ZÒKÙ —ÄH7ŒõíRÈ+E©$ŠÄý)àóžþ•B¾£”’)êßSQ <ŽèÁ'…˜Ðåˆ6qÎ*@Çô£¡6"0·|éQÏeöˆÙ1œŒsÞ­Z;xçàw‹¤ñ—üS°ÂšáÏ“ËT—ÌGpsÚ»ôÖÛá´ÚµïÚYAw_•#jû}}kYÁ4¦·$ÞŒY>5èkt¨.щѶì«ìe õ‡ìºÇö®›kv‘g‰d† ägŸÎ¹¡ÌõhÒVZ#Y-Ž9ç*Ûç¨éÒ¶!"T€‚©Á¡¤;´ª:Žj6˜9ëšClaEsÎ~ž´æ+çS=ë9] Ób'UãBrõæ i7})¡VAóƒÁñL–q"áÆ=ñO #*êÌÌÞ¾õÏ_ÚÊ ’¼Ò°ÑÌjŠè¹ÌOu†9<ŠKAG„uqökˆ² R UmâÔìî-œíIT©+Ô{z&®‰LñØÇLZš7ü„ íç\ è(î}jsoÿdvö©LjÀpj¨ë܈G·½ ê=«k(A€x§¨ÈÁ^E?@dŠžF¥=SJW¸ÑRKŒò\Ìàд/4g×5 Ž8ÈæÑT¾ÓP¼×çª#PÒ`ºVy#Šð¯¿¢C¡¤îkRá.J®Z0xôõüêeìRc¾mUÖK¿´ê%‹rW ž;ôÿw—›š&a‘Çj¹êBW<ÁI8Çگ钄¿„†æ×e°–éŸBA¬F–Ðÿº? A®dòr:QKáE½Å]m XMEuÇÒº-Ô’ôR,ŠHjž%'“Ó¶iÇÌ:“$[ŽOARˆöŸ›¥4Æ<¤ÓЮG¥S «"g¨#õ©>ЋÆqEúŠ]LFÕÉéÅT}Rg p*’b ÙÏ £Ú­$®ØÊ縪jÀÁ¤“< bž­&G¥$+#`tÿëT†RqUä!ÊùßN¾õéé§MöÛ[æîqR]\(“h8ãúÕ;yƒGå»à’Hlry5­Í"ÄY;sÔsýE+ƒŠè.©<Áçòä0Êe~¿ýjd¶¢òÑ­¤˜¬eIvÉéƒéõ¬­vðÙéQ#÷p6%²ó“úµ¤^Å-…ÅÆó™ˆ€ŸâèÇñ~”ù™Iº~¦ Y'8lqÔñÒ´tû‰ndåp£§NkŽ‚)|ˆí‘¼©$,íßjå—é]^™zžFíÇ#¯'ž”›[hÀÀíÎ)qÒ¢…÷)ñÏ)`#ßÉ8À<þ•1ã‚1õïJœ¥W¶˜H¹ì9«8ü)ŽÂãŒþx¤ÀÏQùRœ`ÒdsÖ¤-pÏJvÜútô¡H<Ž(ãÒ˜Ò°Ò9âŒR“ŸAÅ8m¡Í&sŒdt¥”î^qŠ2[æïüè’… Iü…ygŽügeaã»G 3\£³±n HëŠõ9ñ†8ÀÇô¯Ÿ¾/L¶,5+Ë&šÚÞ óµwy'ðoÊ’’OQÚýM™o-.îLžj–i^»O?ãTm/4$ß_ìóng`7¸ÎÀ:cŒ¦³ü¢¦©m}®XJ^å$«òAªø—BÖl­®.íîVådùD!9_¦zž”T©N/P…9=˜¾ñ¥¾…ñûb<ËÔ&—ÈÂ`’WÑ}Õ¾£§ÅhÁ¢™rZøÿO·q«}šú3©Ä ŒêúKáWˆâÕa-µ›$V°nYîaùñ]Tå ´ì‘H¸Êìì›8®CÆ·X7ÚqRs×ò?Jë¤9NOç^AñŸ^}çÙÐ’ï뎹®I;3hÙ¢ ø¦vúîÙ!Sö~¹{9üºë­ã¶•xT;W¨þžÕáš®«ge&­§¿Í9/7<·Ò»ÿêòÚé¦mFEófû©ÝWòë[Úœ×f+Î;lhÛø±¬´½§aJ)êhËy<­„;O\…Gi;á¶±Sß_ÃZÕ¥ãÌÂ"±Â›Øž½··éUõ™>kX»àžœÔÊ3ê ¦´6àÒ£ÁiK ðúÕõ͆—&×!\€6÷#Ò¹ë[ÛÛ­BØ<®ª]K.#<ŠocÏŠ-×qÚÃn3œðqý)8(êÝÂîZ®|N¡˜ZÄ€Oo­gßÞOw ÝÜ£ 08ö§éº=äò?•nØÆ>u5.³`tÿÞ¤³”áÂ/?‡éS:µAœg†×uݱÂàœ}kÓ™2{ò;W›x[-unÛvÈqï‘^£0É?6Ñœ}+x¿p™/|ã’Þò…`\•$þ¢ž·œ8¶ß ÇøÖ К5nqÀíE™<öEDÖïÔ"Ü ÐUÈ|Ou2Žž¤·?Ê£xwuÇ4Ñl„r‹÷G?¥ë`çLܲñ¬Ña3fçÿeÅm[xî]ÜN˜œ¯ÿZ¸Y,b$6¿ôª³El9R}OJWot5#Ö­¼zß}‘ çãåÅiÛxÖ<öýGçâðZ‡9·”7psŸèje‹Q ÙÏP‡Ê…(®…«>§¼Øø§K•G˜ÅHëxü1ZVúÞ™0ù.wdð¯ÖòþµÕ‰ë–_ñs.¹þ•ÊÍ!¸rzt¬¹o¬!»û,²*È0JãœU9ÊöDÞ=OZ°ñüÁWtèùõ_þµmYøíhhÃìÇå¶¼†×L7p탪qúŽk7Qm$j’±ï¾0Ó¥QæFéŸ|úV•®¿¤Ì~K¥LŽŒ•|ý§Ë} ¸2o^Àþµ(Öu(Ÿ•lè8üqB”_Aê£ášÚeýÔŠþ¸ýj”Æ®yE<÷AŸå_;[xžõ0^ ¸çvÐò­;ÇE‚ÒÈ1Øóý):P{‡5gŸIµ“‰-#9ÿ`…S›Ã:cF#Û@9RÿZ¸ˆ—&0LèFxƒŸÈ Þ³ø‚…ÍŽ6Ï£ý*>©ª°ý³¹>½à[mJ4ŒÝHŠÂä¼ýk’ñ§†µ[}*wµµc4\Äè¹Lk»ƒÆZlΑ´[½Hÿ Ћ[Ò'ù~ÓcÙÿ —‡œuOõ/Û'£ÿ#Ã5hî´O ëÔݹNä~ OÊ·¬¬åÒt÷–rP2–Þ{‚Iþµéú¾…áýrÙ¢º‚„ ôQþÏø«Á·šdv¶Sƒl£SóŒtÝÚ¥NqÒhmFKÝ3<§H-d.Þs;ê3ž?#ÀÖκ¦Bñ)ÚÙ<( äô¨ôèïm¯¦7ùX ·‚9‹ñZ0ôZ[†Ùç«áý}…o Tz3',UÖîžþçìñÆÞM¸ýÌ¡FÜóƯxnÖಈá8üÉýI©¼;¼®B"\ä÷-Î\þUÓ鑳}ªvÄéJnIÙ¶ÔŠhÒ¹²¤tàuö¬ûï"xâg 6ìÏ^¼~uQ2™¥IÈȑϷë\¶±/‘c§M–¶¸¸?|áˆ÷íI ¹oÅkzd»ÙZˆ‡pÁÖ²tY-ôm29Ë/••Ýȉ8Î=ê_ˆ+,ú«n²²buñü7ÿZªë–×^°³œfFXqûÀÇ¿'ôªJÅ#BËP̒ݲ†VTz('ÛÜþU>µªIºÚÎÚ@%s¸° àwê+JšÞ? ùúŽažxîô^¸=;ÿZ£séò®µs–yĶp¹$>”ÓKpjýOF±Ô$–°¨òÀùŸ9ÏéP¾ n'šÉœFpóƒžÕÍéÚ°µˆ¬nY Æ6ä“ÔŒ¾´Û[öûeË)C&3?uzä“øÑ£%Ýê]An‰ áÆAoÌV¬Rוöç½rpûK-ÑÁH“å õl0<~5§5þ-cžOË8Ü3ŸåN׳,ê¹ÝÇaŸ_Ê«ý°B’JêB–?äVn¡tª¥3– DZÆ==뛹Ԛ}j]«$31ÀäààÄT8±ÝåÂ\(18Á–íŽ}ªÐ+ÎÓ‘X B¬h¸ åqyÇô­U1€†…rÓ° I«•5Ö¯-Œ0?“É™†oAÇÖº_ta(N+[€5³Jб¶x!G¡?Ò¥·†’fe¯ŠUõÿì´ d±îŽzþFºõ¨’cŒ1ú*âå‰ôã%ìp}¦ñ£!œ/ðäœb¸oj×‚Æædiâ! ""œ±æ­N}’}yóÖ{O:Ý–Dõ^™ô¯ñŽ©ˆõ ‹ôàºòX†#ä8äWCðCX¸ƒÀ·þԙ㾂ifŒ3e¼¶$‚Oԟʼ{YÔ¬ôÝ[QŽ{¥ºrË>ðvŸOÃ¥*ŠjÚ„[[îzµž¥£øKD]!§Hüâ]ç'$ŸJ¥ÿ v’æ~ƒ‘ü«È·_ëiÙ'Ê<¤EÉlzW¡¯ÃÄo [ßOs$Ò¦ánßÀ:àñÔÔÍÂ+ÞÔ¨A¾¶9Ÿkðêþ"·¼¶B"„UxÜ0z×Ñ?¬>Áðê‰bÙqy+ÍÏP¥›éƒ_:è~»:ݼWÑÉo ¬G˜TãŒÿ<~¢¾”Ò5Ý*ÓH³ÓZl"ƒv7`}*è88ûˆUc(½Y·pá#.Þ¹þuâ¾*Õô›íKP°Ô4>v¿'±ú“^Áu˜¯˜þ5êúv±â[)t¤)ä1JN7àœ€?1YÍ;ûÈ"ï³/júäö÷¶Öú/—¼Ê"9ŒÜÃõ®sZ¾Ô,5ÏìÒíq+Ë"•¸ÏOËó¬ó<†ÐÞœùQ¶çï6Oʵôf°—Åžlû„’p§¨ÁÈÏåW>õ;]M¾³m/Ä–×K»aóC·Tƒ»ŸÇùW³Aâ-6îÁo 2e‰ÏâzWŒêþ"ŠÖÙbŠâ%Vp kÜÏl\­¿Œï¡Ôîíí’BDqƒ“žÜö­TÛÒD>éçãEÆ, -ƒ÷ß~X®[Tñ-ÝÐ"K¬¯÷cGò®zÊ;Ë´BûòËœm«©§*:‹™<¼ÿåXÊ|º"ãv®Ñ ·ó9o-[Ô·_éQ­µÝÉ µŽ{íþ½*]NÿJÒeŽeyA1£ub'¥¬i]Ä€®ÁŽ+‡ø 45 <žüöü«Ð.”SÛ®â¹Æ‚>A¸É€@í\ïFi‹1_1MÅ­Ê”ÿ¾±ýitÍ"îâÝ|¨¶¦öùÜqÔÒx6åí£¿¸Ú0–ùQŽüÿeO¯ê7ö‹#O")ÎÕbºg­Œ£u}ÃN°Óí/ {½ALÇì*?x–ÊÇZØ–(×,2¥‡ÝµÌh„>¡hÎK2ÜçuIñ Þ1 ìˆù Š–ŠWÔQM±÷ž(Ôî²<Ï,î€*[$ŸÃú”×ÎS€[œ÷'ùVmŽqtÁa…˜ž„+¢¶Ò®m|5©C>CÍ÷S¿aCœTF¢Û9 Îê܃ÿ-Á…z³ƒÆ}ojóÏøkQŒ[Oq@¬¦;çü+ÑçùŸ'®8É8 Åó\ÂAž)áHàÒ)à ⵱Ìü†²ŽÔñÛéOe³N+†…n¡r W=+…ñÓº^Ńƒ¸ŒƒÔs]ë´ú à¼zƒíž0\‘ÇükJI_@¶¤þ¹™µër%n ܹà­ýq^‘=þ'’7µ´‘£œ~æ ÔÂGn6çqÁ?ÿô™•MËä­rÕiÎÌéå¶Ã’ãO~òÜ'6ÿ€¥Š×Nº¸&Àíëç§ ªûœ9ô6•ÿi@ºÇ’xåHþµ<±ì'; 6‹içH›2`¦?ªÏìú„0¢nVc»#¶Nhkyº³Kµ@îÏ\äÕv·ÆH޼Տ¤ wDz;ÈÌñ+ O^åY_dmÄE(;zŒ’Gé[ÖosÚD®B>AFzòvæX¼Y¨¬R«6Üâª>n¶%Ë[$w& J.Ud ô8ÏócLžìÍ,w¸1¦s°^?JƒÂ²Is£«ÌÛ™[{õ­Ë8”Çs•pÀ÷©å—{ƒ–߉D®Qf¼ËÆ$ÈÜçËzWªÌ€¡AÀ=ëʼhx•°1”óÚ¶¦™”u‘èÿ eðÍàNò¤œó“þó® Iuå0FÁxÁ@I÷èkšøY2¯…î˶ݲãŸOòk«‘ÔCcÚ¹^ìèÙ•ež%æk(Õ@ûúö©µ6Ù`r|ﻎp*KøØÆCFpTôZÑÔR?*ÕNvä)ìyâœb˜ÜÚ0²íem«s·=9þUú|ƒ§+ý+lÁFT~‚³Ö³la ,ŒUÏ Á8üÀ¤“nÀæ¬r6òØ]»Ç Ã|M±Æy ùU¥·™9IJcÔõ«ËïhüC©b­ö‡éÆy8¯bÓ×~›9^ &ºRØÍ·mJI&¡ùdb:‚1VíõNY íÒ¦hT/L~i©ŸJIJÂæ³¹fßű°.’ Ý=ÿ.+^ÛÇSBÖ°#¨##õÏ4ŒqØc8¤kXʀѩÀù⫚h9¢÷;«O´©‰ŒOÇ!¢ëúU-qô/Éló[=³ùˆñÊx'ƒòãÜ×öH{~¥ ÓºˆÞDlpI©nû«ze£=+I°šå…¾x€±'cƒÉäðqÅtV–zÖŸeå=²»$•Ç9éz§ð×PÒm<1½ìñ¥÷˜ä³òHÜØÇ„Wkm-•×ÍäqÿUCO³±|ñ{œ\òßGp%¸…ãP…ù;úç¥r^-™ZÎÐìÒàJÌ9Ïç^ÊöÊç†8ùúÕJïH³¹GŠ{HäVa°…G4×Bíɘçñ®u|mgv÷VR2±çc3Î8Þ—Ö$œ P‹_§ëk2êºu’mky}±Ú9ÿÒ®øÝ&û%¸‰KÉ,¡J÷ζ5? _éö— —SM+H]%;àóֲ泹†]>é\Îò2ÊcÙ‚6óý)ªÑ–—%Á­ÃÄ–m¤›kDÜ –@gb>áÚýñì?:ŠÒÏìóJ^]ÑK)Ke#æd¹cK¸0wzþ9®óÁ×Þ´—)d}H'ô­åI5tf¥"?Iy{jaµEAü?(#8éô¯"´×nÛVšÛPšT{f üñŸO½'ÆzŬA­Úp$ÎØÔzò?­y«ØÚ>µ-žÓ%ÍÁÞe'íúÖtå*Nñ@Ò–ç¼xsÇúEÿ‡–Úä5`„r\~§=ëÆ~0^Iªj\-”vqA•RÞçZÜÓ´Û/ YO{váÝ"àÏáí\N­qqâY–[5ÚŠ ØxÏ^¿¥:ÒW{j:iÇK™öÉ·L’ñä!"r ã¾3ýk­Ó~kW^Mr)”€tˆgyy=r71\ÚéòApæ8\üê=¯fð‰!›Ãöúp”mÜ2@R'R>ä¬ÁË‘êŽGð7‰nˆY´ùc$FÀùÕi^µð–£—Ò ‘(•Pþ?ν#JbúrÞ°î.9#Þ¹¿ˆ‚6ÒZS¼DæBxÁÁç?LÖ-UOÞw4N/ecš¿×®ïuc„\Þ3ôÅF‰#Éæ\JÍÏÌi–«„\¬±Aj§nOçÍ$úÆ‘n¥½aË6¡ˆÍtFéhŒ¥b—"ßâ]%RHÞYÚçåÃu©-ô{’Ë$Å-Pž®pqPü@ñ&¡c¬XÁg²/:"Klô= r²]Ý]±3Ï#œ­I&ôlWÐÐøŽuMco9V#‡†®ÃáùÝ£y˜ÇÎG›˜pþ4—køwoñÙîúü§ük¸ø~„ø|¾8ó ëîßýjºQI2'wczó÷’(Î0ƒùšóߊíÿD ØAÍzèÛ”¶x^íÉ®KÇ^»×,ÒÕ•O˜‰Ï¹®Zˆèàÿ6kH|Ä›rÏÌ*=ÃZÅ„˜š>¨9ë]‡…4FÐÖF2¬*…ÄW]ˆ¸Ú3Üuàçô­KøåÖôoõ‡¯QŸóù×#³›¹Ñ+«‘x†Læ[ecžÇ¦+cÃú½µÞ¡bŒ÷ù³ØûWÀã8ëí[ ý³mGÎAçý“F‹ µ6umRÅ5Û˜$”ÆêwG$ÒÇwg"·QõÇ9ÿ çÔ’qÐzTò‚f=ZÞæ •p*Å¿Šo `dFVè1ò“úQr€¸ àv¤Xœ•ÆzÒ|é›)«Xè4ÿÜ[¸ýìªèÇ#ùWE§|J›wïgŒ¨L`Ì óϲDäî?ï‘þiñ¸~?ýjIuC÷f²øƒjãlð«´®þU³iâÍaûÉ gXñü«ç™,Ý9Ž]Œy$çô¥ŠçP…³Àb:{þ”œ úèÏ¥ Ôt«‘ò\BàöýqQÜhö„ȱ¡“aPê á^a«êq©Y7úƒŠ·Œ¯me´ŸPOòÅD©QŸQª“‰Ü|@øpÚ¿‡¥²±••·]ÄûñÓÔÓ.a¿K2º…«G2Ç0Ž3ƒŒ{f±l~$ΛGš>Ž ÿJÛ²ø‰Äl·Ã"÷úTª!ðKï)ÖOxýÅ/ i“K¨Ë&­˜nÄnDMÚ=ÄÇrœV–£¤íFšÊEVA‚ÈqùS/µýV…£Øöìイ6xú{Õ—ÔížÁaK´•üÝÒ¸8äã§ÐStæ÷´]Äcj6zm³¹PfºPpVÔþ|V¾ª¾¯n.-‡ú*& *H#§¨Æj¼Ïj5]væÜ"ê„)r0Ï–€œz“[^ŽÇOÒÖÉ!…ºì‰]Aç¹éÔšiXjÛŒm*êøærÑăæ¢Ž¼šnekªl¹Y ³·s¤|à œ÷èEK®_Çös¥Åp‘^]EÇl©ÉÇÓ'ð­ WŠÆÚÞÎÙ ÛÂ0À®7rFÖ¦1ovˡӤV¶V¹¶‰É;F[ß8¦ËuéælðÉ•ú`óYOrd¤*J…;OO_j³ }¯K#.ÊFÏAÈÇòªPQ}Ì‹ëqdf„ïJ|dä*ãÿáÒ£Ö#Ô¯³û¼¸Œ¾±ì:Û×b»EhaGFÜHTROëŠå- Ôš•Çöº°Óã>Zù±íÃóÜõš‰r½ÙQM+£ ÅګŬR4޵Bª£içv8•»Võ)|ØwÈÊOÊ; ×-©˜-|Cq%™&Ô3Û'ÿ­^¥{¤ÿÂ9àÃuu\jrEºE”çÈ\™ïŽ+Ënl¿ÐàÔ„ÃuËä‡8Ú3Å^ðÖÅÝ~âòòÆ5 åÛ²€W'Ÿ|W? ´E .Ûxϵh]=íº)iF Sè>•J–(mã#kžOð«æ»Ñ‘¢FÞ‘¥ ZD·iH‘²Ò§Yê:g‰cÒb“mÄ™‡ .2Oê* +ÖÒe‹kM·ïŸá©-õ¡s˲Ã26Zg<ã<ãü)¤ù¯8Úǵê:õŽšl¼üH Àè{å^G¬ø¦÷Q·þȸw‰ *ÒöaÛ…\¸¿›\Õí¡Ó-e#3„ã<ã¿Z›Å–šªÉ£[Ë`€móœÿžÔªIÞℌ™6¼–Ñ[6ûu‹œŽTóÿÖ«(Ï2€ `Ö—€4è¯-Ì÷c2)ÿV==ÿ_Ê»¬í#}ñÛ"6;?@)9µÐSÒçã½PÔ¼M¦5­³4QÛ!ÇCŠžÇÁnOútºªžEv¥ÚVÜçqϱþußFV–µŽCÄ>}ORÓä†eŽÒÊ,Œžãó®—G±‹L±öìØ'-»½X ’8ý)ÜqšIÊ=AÛ°Ù$¶8¤rväQ)ÿHUÈÎÌþ¦Ÿ·“O}@b zûÓ Á©d‘ÍFʸÎhµÂÝ…ÎOËKƒœç¥;r?Æ›ÍÄnNây¤> b”‘ž”Ö~0p£ÜÒjÃX§Þ›’O<ŽÔ’ÈrÇðÅU–싟­Z&æbN)Ô%súâŒçŒ ê^gAÎ8©6Ò(èE8rH&“)!9#sÅG$ÈvͰ Tä|„`çúR/*x• b×2Õ"²µŠa4Q*2ô!FJ·¼0;Ò6Ï÷IŽOúR¨'·¿"²öQìRœº²&·´máÏ| ùT¶pXÚÜGp–쌜‚ë‚3úÐFO÷>”¡x?.qG°€ý¤ÊÚ¾›k%ïšÉ#õÀ8ïþ5Lø}H&;Ä'° ÿ…k*´ª3ÀãŽâœ ÚÜQ©äeišMÍ­ôS–¢F%ˆÎqƒí\‰ ‘¼U.ÆØÒdqדþꌣ¸^=ª'¶†BáSôàš œ<Ç)¦îfxjé0çq~=t¶oˆ®p?ƒ$zõªvñ¤(Â(Ú8ýZ´ÀŽôœŒÁŽoš”bú“)_bsÈ#ž¸§”Èñ@,H¹Î~5dd/åìqZZÆhfÏ—äð¥P¤Œä{ÒŒ×÷¹N›I#ÓŠV.ã‘Ì|†çéS½ì’cÌÛ ^™AÇéU˜ÃûSGÌüàzñO‘1)X”ýžU"[8Ÿ¿Ü~”È Óm§Žî+?ßFr§=8ǧ¹ïJBôéƒK†ÆED¨C±n£}O7Ô¼ªI¬^^BÊÂá˦3‘’zþuè:drÃ¥[ÛÌf`GŽß¯åVŸ FOªŒÔKÜãéB„¯¾*šZÃ×ù‡çÅ8ç ¥'Ì@fP[·hÍ«!Bq’?JUÉÀ'¯¥4ãŒÃ4­ž©+¡+Ž g z…Îi²Ž~ƒŒf…cíøŠG<|ÙÏzvîVJR.$?JTàzšGݼ㎧ð1ÅW¨h<`²ÓÑA‘ÍGŽ88ç5:•ˆnÓ ÍÀÎ@ú×ø>êèø¡yœ#_¢('=XËè×NUp2§ý yׄö~ †mR0=Àuþ™üª$ÚØÒšOS×õÔgì(ʧoôZ;}:Y–aòÙΟþµ^¿‘TºHÞ7*pT‘U¤†_í3övH¹8ã¿ëXXÕM”n´k{%©ž5’>H+Ûòª×~QôrÄž0qý+WS5‹á€NügÛ-Çó¬éÂ¥õ«! ZU¯4Ü-°”›ÜçÔ¡¸x­ïšŸ+¨nAô5vÔá`Á* *àtæcñ ðe°×¤Þâ½7S HøÈ\œtÈÅh“¶Œ‰5±-¾¨£Ä¶6WcŽXKHJò@?O¥nêV0êö7]ݤ»¥*pv·ë“\S´ºžµ§]X ÷ œŒÛFA'>§åé^‹áŸƲÃVxU÷I,7‚sõÅFÛ£hØÛ¶ðÙ—]}nò-Jí¶‰¿„rÇŽrJØûa¹ùØ Ø{ŠÔ¾ód‡÷k渧O«GŽ0÷²-ª'8fÔ=^¬wò#’Õ%€ˆÑå¶ã®*;gÛB21“ßëüꮥãNˆ¬S —=—§Ó8®?Qøu*hQ˜’Ýy>Ø5£}6rF0O¥D¢º=F®º.¥lº¾žª©#‚"ˆ`ü JÅø“§ÚjºDÖÒ0¢|¤0Î0EjÙY}–âmH|ÓÊ¡ã…^O^?*Ã×moõDi°ØmÇŒw©—-µÞú5áûæ]Ú_+}¢À‘óv>õÛü7ðÜqñ·–ñÜn†6èÜðÄ~5Çxµìô¯Ú[C&V"ä/ÛóþUê—:µ¤Þ‹Qb"ŽE§Òª”n‡'gc/ÅKâKÙ,ãÿQ$ƒÌ8í߸/x~I|ecgn6ÁåXר&£¬_Þj–Âݶùs®ô<ãŸóÚº©n4Í"[«ù5E—UhöeÀ*y*¶zRöwÔ9”t(ë¾²]ZB‹æ$xÔð=q^]öi-Ÿì²F|åᙺ×_6±{<ÓÏ<Â&$Ï>¸[}j›eRâ@“8 {‘øÿ:âï/®mu™t½2m’ÞI™@ǾÏj‹]¸W¶–ËÌ•IRÌÙ#Œuÿ=(’Œƒ™§ävþÒ °žææÖo1.þ Æ{Ÿå[¡~R[#Ò°ür“èÄCË%YÈ$Þo›sD×(¢î4”ÎP`}sJrG#>”¸ãwzÊ7dzÔ8Ï8íÆ(8'§áBåºtÝ) Nd8êi4+XW_Þ)ÀÀ^§ñ¥(ëPê7qÚ¢É&ò¬0 â²[^…“1¨\ž¤ä*ô Í wp “éŒÒLÛ~ú‘Žx®~m`:.@Ï$úb¢mNx.ÀŽÔX{#}§@ °>•—Šx :†ë\ûjMƒ±y=óš¯%Ô¬ÛeÏ5ZdtxTÌޤХ5ò`ƒ!8è5“ûÙ[åÜIô¥û-ÎÜùoR)7Ðjìµ-þG³ÛŠ«5ì˜!N8ô¡á4×  úcùæ¡w²u•m¤i&HËàóÐ}({­{èxÁR601ÁÍFíŽAüB÷°Æqó–ôÆúß­v&rXº6ðÍêqŠ]¼ÅTŽê,ýüqŸéS$é'FúRl¾VJIP{ŒT¯’3Ïâ*ª°n†Ç¥L®G8'èiè4žÌ Ã#ð§ }à3@mÇo#Ó½/ÍžGJºÍÇzS·¸üE"ž{Ó‡ €¸ühr ¾â ä\‘MÝÇèiÞÝéG`>¢„ŒÈ9§`ŒS)SÇ=餘8è.A\`Õ‹B|‹ÁÓ÷=¨1•N¸©¡ ÚÝ)Æ d7Ó¤Яï·‰ù ¨ÃÇÒ¥)ús\®²‘É$I&#ŽBªqüŽ+J×Uò$Šå½òEÌ¥csiÉ9Î)@Ýëžüt¬ô¾“i;rc¿×2Þ+0WQŸlŠ#%ÑÙȸph#¾9¦ŒŸÎ¢ûTy©R:ÙÇè)Þz2ŸìGøS¿R\ÉŠ¸lœwëHÊG=)hÎ1"dŽp1N,2Ÿ?ÓœU « ¬¬£æSÖˆÃ6ï— ~”§pS@¸ïH6–UoN1M2X§Ï­&Ñž?ZEß ×¯'öËc†i °ŠA;ýiÌ#ŸÃÒšGñ|½{.3NÀÇ\ž´Çv.SŽO×ùS\a0AÏZ' þ´2¿xëŒQaèRœ‚ü qëÅQü¨”Ÿ3žžÃ½ FHÜì(±:’¯#¦OÖ‚ “Æ)qZvNIÈ©Iƒ!¹À·}§ ´óøWŸxFmúä1 E@ÿlW£Kï”ô#±¬¼'kk}í¿œž]ÀŸÔ18©›±µ=V¥-[ â­_xÏ’sÁëSi——±ëzlqLʯwºú®k¡½²Óîo%»kVI¦mÎÁúŸÊ£µÑ¬’þÚëÎxÌ2¬€úàÖÒ]¯¹mÌí{Y¾·ñn­2 …$ ªP699ëøS,§¡½Þ¹¨jÝ&ˉ7(*r9?ãUí|?u­eq¸´PÎ’9 ÐÍk¨’O¯âpÚJ3|B¹q|özõ=JÝ®^H‚’Ï3êF?­yvŽÅ¾ \¶Óµ¯7üz½^æàÁ9•T¿”Áð1ÎÞ*Ö­ŸÄYðO€õeÓ ¶¥Ø¢†øÜ‰e`<ÐNz}¹ÅwpêÞðöž¶Ít.™ $FH$äçù×—ë&Õµvóžg9à aT8b²D7¾é¥Ïs’k4”]å+šµ#Ñuߊm)§D±. Á?ʸ­SÄZ®£#I4®wwn•^+(‘AÚ {×9ñW´ÐÁ·b…˜)#ŒƒUí:%byRó:X¬%xÖK‰HïŸåŠÑÓ$Ñìum>ÖéÒS<«ƒ‚Iíìk ¡3I³I±cQŒœŠŸRŠmJÁ¦"H!À$óÐÿM×6®áÌÚÐ÷=ZãÌE0á¢+ˆÈô®e`’çY'ŸÉ³@Í*ã™:ü ö+ƒÆjd¶³žéV-‚;)¶8¹®ÃI¶Å„BdhB‚Å‹ä°ãùU¸½Ð'¦¦Î©}mod'%:žÒ¼æÿÅ?ÚRJšSgËc’äŸaŠŸâ=íÀ³Ê[`®C{ÕCÃ>(Ñ »–ØÛCk$©Ë޾ãõ 7²-Yny×ÄVÞúÚ[—2^Ýáœte_N½*™Ö/gµ¯)2}±JÞøÏa Œ6÷ñ²™Qœ–£ð¬_ Æ$¸dd <:zŠnIÙŽi5sªþÀ¸Õµý>ÏH´kh%tÒ¹,I?^ÕÞ\ü-Ðæ´MÝÌ×çp@ì0*÷†Þ¤ÜHцˆ@ÉzÖþçÁ£ÃÁ- Éqß×çM½· ãQ­‘âü*t;d¹°†IíÚA<§¿gò®$ñK¾Qd#i+Á¢¾”×ÄW1IøòØçšðoØÍ¦^*„ÿF€Ïe_òsEN”·º.MM#ÑΦêò‡H! TsŽŸÊ–ü´>°¹±¶N?ÅêI©<;~¦ÿf"¡óN×$äôÏç½Sº¹û4Wº<ÑnH‰KtSÓÜþU¼ãÕ£Ÿµ{«›Å’0Á88àuÛhVúbè—÷Zƒ$“²¥€àö*¥yì/-²ˆQÜH8=yÕøsÃ:ž¾B[D`¹Žßj¥n]Aîv?5¨cð´vE *“ŸVl’;u®’GE‹ã'þÄh6£NÕfÒõm¥ƒ‘ƒ÷½ÿ:»6«ƒ€ªÇ¦ï_ÈPå´AÊú#ÜÄ ‘ #àj´—å~d·R®fMF鿈/°QP–žl)% ˜ìº×¯Ë†.áØã?•Q7ÑÉ 9Ü{Õk>A`ÇÔœœ}jX`‚7ÿI¹HÁ÷ÇQz‰ÞÚ›Þ#ô¨Ð€ALçß§ùú× r ±ü¹®÷^$é6ÃnÐ@õ5Ãê!rHlœúqQ%­ÐAÝÖEA‘‚еiéÑ ˜^D™V48,}}¿:â¼F1q3‚¼ŒýúÕÐèÐ´Þ ¼;ðVsÎqÇ?ýjÒ)5r[i›r5Œ ‰.lg‚?•:îêÊßC—TŠ6xã$ǯP{{ˆÊ?)A”6c®qïš¹«C¿ÃË­àÉÌØ9ÿx‘ùæ³÷Z»ROs ø®æESi q£ o˜dó[ZÕÕׄµ;«–>l{‚61Šã`†B©äCòÁO—‚>µÛøzÞqàÝUgÄNIØÿ²:µnA5g¹ÀX¼ó[E%Ä…¤ÉÎ[Ü×Wá¨ÔÙßc’!lyïÅs:u•´0 º¿‹r’ß!ÜO'µu¾{Vµ»†RZ&áÀô<ñN)¸ |ªFÕìAc9=F+’ÖÆ£û³€ŸÎºoO>c`1'’8ïÛð®kP˜¶Ü0qßÞ·¦ì®Ì9}í"¹@㿬G¨NârsÔ Ut^œSÞ-£ž¸È+6îÍ‹«©¹ÆS?ÿZ¥T äFOŽkœŸR‚6VV΃¾¨²ä*QAç§z€›‘¦ººpÎ̾F@«êêÇä™~›sý*Ñä?vD?\ÿ…0i7JÅ+ýÜÿ…G:+èk&¦²6â#Ôu«ýJƒåî÷ŠçdÓnÓ„žÜLkK”Îa”vÉCWλ’Û£¨K؉!”Ž3÷¹þU(»ˆÊøã¸É¥q¥gP@=¹§‹¥8,ÀûŠ|²ìvFâ"7yƒž~éÿ Q*8Üc× âÚúä.7óßù…õ€0J¶=E ±5ºY$.÷Ãt«1¾Ë¢W#Ë={ךɪL@\sêô®çÃleÐn]Ébb+“øŠ¶Ñ<šyi{k$ÓDfÃùÍÁúÖúé—eUÄ/´Ž¸àþU磋»£ÿMòæ½¢U& WFãÉŒwæ³­+Zư…–¬åšÒê6Ï–F8éÒœ¦ê#ò;ñøÊºG2,˜ÈéVãÃè©vöèeTŒuÁ#úTs2¬ºœ ½½_âüÐ…Hš•ÒJ·ÔW@ÐÛ³nk%'¯ ô¤ƒO°¹IÉ·hü”Þ~lñ‚}?Ù4)>Âp[ÜÅMb@ÜÄ?Šž-n0@’&ÎAþ•`i¶&èšERqÛ¯åPˤCåŸ*à4Š3³oÍT¤ßBvÙ’¦¯lïëÁÿ š ^=¸¡_þ½qÚÝŒÆEmñ•r¼ûVœ‘ƒ#ŽÆ´WH—®èêF¦ŒÜqÛþª¯ ’Hqœ×:r3U@&Aœ‘õ¦¦Åh¾‡¦i×qÞ@ÓD„*¶ÓógŸÊ¬3£Œzð+;Â(£LHr4œœg¹­öÒ ¸hçÓ‚2*œí¸”o±G<=‡ZI8éÎzU¡¤ÜÄÛ|Å`;súŠŠx&@KÂê|qMT‹ØNœ–ætŸë;p?:=9¦LBÎ9àçN-“ò޽ªÝ‰D«»ïqùS¸ÇÌM4ûÁã4£þºŸA1üã‘Ú¤Œ“òãŠXg§ãO^ †sô£r–¹ÇëM ž¿ÊœÌ~´GðóéM$+\dƒÅ²>nF8©_ï”™ü£KˆEØ© …¢Kæ d¸£?ʦºùÑàó{Ôƒ¯ãLb Æ£‘G¡JM²¢[®p«Æ}*DéRcœM·àŒV-ÝÊ9é\gÄþt0£3õɮѰIãËxóN¼Ôlµœ[å.áBv È.õK¹%Hc`ˆŠ`zzÔZõ•åΫ¦cyÙÎöã<×Eežk£32Àž‡ò­(ÑAAÓµÍì;E.½§ÝµºDÍ/«éÿêÍ{W…¥œ¢’Ø#!†:¶k·²“ìòܬ"ýò{PšŒÖ°#ÀíµùÀãpª…F´aÊŠ><¸³‹Ucsx`º¨î=?y„êý¯n"‰Â#–#®¹­ÏÇ'ý¡tB«ð§vy?äWIðãÀ:®¥jòÞ3Yis6™J´ÃÑO§JŽe{ÜÒÚ•·†üCâ=5a–òÖʶ>U°«>Ôìô¨æ†ê6}Æs_ç_D´VZv—™§Á­œ ±T ZðŸ‹ÚRÙ_jÞ=ªüH‹ü}yö¬Üê)]ꆔ·SÑ<«é1h0ÁlÊ Ÿ2AßsrRkLëГdŠUi ô5à6zð³³–8à̤˜ñôÛRâ‹S,n[s¶sŽ‚º}Ç©hô?ŠzëC¥"ÚHI›÷n[œã¨®;[¶½Ô4»w™àtêç“Xšåôz„öˆ!1Am…E œñë]i¸¸“Ã_m_.! á7.CqšÊQºÑ…Úg'k5Æ™{Åz9Pxÿ=ëOMÒµOêÃÊUY\ï=‚óÖ¹—¸šîsu!,Ç€Iíší>ÞßGªÇoi´Íqû±¸dž´é§%f ÙÜݶøo¦Ú_G¯­Dîäa#$ýOøU¸g´ðÇŠÚÆÙ›È ^0ǧԞµKÆÖ÷Úv¿ Î¥"<üÁƒmØ®DÝß^k.°¡id|DdŸÏéS'¹rÕlz•ܶåuû¸ fÝJŒÈç<~uÆ=ͬóÜ]9d·2,áç?M{â¢i—jLÓ\„) ¹ˆäŸjåü#;OºÞuiK³;€r2ONÏÜbÝÑ ™+3±Ó¦³¹‚o*"̈X£·n•ŠºÝÔÀùQ¢Ä—$`âµ¼1Iõü–Ú6óý?ZÀ°†àFLŠ#RïË| üÇŸzR–Ä;´jjS]ÍૉšVY|«—œtúV>É7—3‚¤Üu­ÝtB¾‘n.©“’£9àãô¬m>êÎ;Àc†YH=X€?Æ´_‘ {§¡ë‰&Ñvàlç·5ÆßÆsŒd]¶¸iöuAšäî×ç'o~•ŒÝåcZkC‰ñHÛyl?ÙécÿÖ­Ý1­£ð-ã]ÈÑÄnFIÿõÖ?ŒÉ¶cº‘«’'ü[ÛƒÎ>Ò{ýiÁû¬&µ..¯i"–—v ÕÖ¯šßáÌ·ð"!œŒ22sÉç½r¼awcµu:â<¿ ›lnI”ü ½Í ' ŠZJÇ#ý§ X¼âª…>P=¸í]†‚ÓÏà-XÊäùm³“袹»?ê³ì+i&|Wy¢è76þ¾²›å’fÈ®H¦¦¹,Šæ½%ÒÓý,žçùšõ/†Z»Isp…-R&ó$n˜î¿Î›á†àB‚öì ‡s•§¦k¼0Eo¦>Ê%ŠR˜îÜu4S¨£Mslr:ÌHÁ ?þºåï“÷ÇŽ+®ÕPlS€yëžk˜¿\LyÍtA.SüE4@@4é”m ÷©#8#8#¬­©Lⵜ ù”„óøšë~®ô¼nþPÇþ=\®¸¡u'“ù×[ðÚH¢³Ô^LXFO Éÿuþk„Ûk`WæÏàiÑDñœ¬Œxà1&¨.¥i"–[ØNã‘ÔJµcr³H#Yâcœ}ášÍ&–¢Mš²Ióã¯øU×Â]ŠcmÃ9Ø0?JÕñ¦5·XÊÃŽzþ•æÌ î‰¹ÿgª²hq¿Bý€3¬¿iTb‰œŽ¯Ò³æeù‡Ø„ƒÔ?¥kx}L‘ÌÄF9c‘ýk=®d”4gˆ\TòÅôi\¤RÒ\y¶›;p8üýUÈø¢èiÚ²ÛÇ1²îäó]»Xÿ*®mÁ`@<ž+JHùèqOš5ŽÄH[>œŽ þ”íØÎ&ŽŸ¨Iacna·3»L>]ØÇ'Ú¯ø—SÕí¯àžÄ;ÂñåÑ@8ltþThv±ËmõÝ™:`q]„‰<½ªp£ªƒÅDÜ‘pK©Ëk>%Ô´Û‹X¦%–nø—ßFjèìekÝây#"°ç¡8<Ô³[©ˆ“dÆPsQÙ(]"øóÕ°¾œTÂOªÒZ¦b‹O´bQ0ˆÁÐûT—0l…°ÁˆôôüEV¾›PŠÊ9¬lÞç.Clþzô5jiŶ…<·ò…eÏ,€¯«›N×W»{ÍÖ©ö[ÃAMßxOñ© Ö#Ä Ù”Ÿ×™©*Ü]ý¡X8dÀ pA¬Ëû¨ìQd™°¤âœ›î%èv)¬G# ËÇ€?«K~ó++A\΋juky&µt)ßÎx©ßG¿_¹|s•¨sQ+–û£§Žî"†-œþ˜§,ѸÉp=ˆ5Ê5–¡¤Š½¹8¦y÷±pÌÃÓ+OÚùƒØcêqÇãúR¦â~éÅqÃQ½¿ÜƒX•x‘sî0?¥W>„ò#²,1ŸéQ1 â›\¸ßˆÆxæº] YgÓL×y…ÏnƒŸð«VhMY—sÇ4€ž¤Ús×µ#qX3TÅ,)‡²i¬O9 ¿àëI' zÕ»$ÜãÐOà+8J½86›ªCo8v*ÄvÆh[•²=^=:ÓOÒ`¶hÐË*æF<ž{Vv«à‹K³òLêTõëíWômBÓXÓ¢¿WˡٌýÓÈéZ?o‚K•²óWÌÁùG'Ž´§I1F£9X¾h2¾¡]¢0mŽÇ…u:‹T)ĸBª1PÉ©G3*oHÎì? å<{©È|=àvµWʃŒ¶zT((êiÍÍ¡ÈüAñÓÙk±èÖXœ²’aÑ+”ñ^£©êzBˆ 2[í -ÃãÿרÕ-þ°[Ë”3H¯‡.Ùg^¼úSoµåx]m òà•òGQÓ·µV­ E¹ÏÃd¢EŒ–*‚1Ü`RÎÿ'ÊŒ0x=«Õü+¡h—:2>§jÒ]œ+ctâ»?GÐíàTƒM· F~âŸæ*%Çeq§»>u³ <±™c=[€}«JòîK­Ö.Ĉó²(ÏÊ ô®ëâgƒ%–ÊKý%£;ÈNO~æšÊ×̱ó2çz¿^3Ö•:—v–ŒrU°³ZjzTKq"´NèiúeÝÔ8œ ‡#¡Á®ªÄ.¹³¿•0üñÓ·jÈ×ÛFÖ¿²Ý [¢o“ÇüM_3‹%¥$w%Ô4»ï;™CHP·‘Çÿ^¼ÃEÔäI"2.~Pèк›´7ID‰IÚ û‹ÿצèº|·/å  ŽäÕJÒŸ0’´lzg…ô}YÓ.­¯1<×@‘3rcl?ƹŸøEµ/ ß¹¸d6ŠÜLOÞ'ðþu¿¢ZÿcÑ—sËÖ¨øˆëô ,r4 S´väôS拱Prµ¥©>‘¨O¨ÝjF&Þ+FÚÀÝÈÏé\$“ w‘˜—lœŸïô hw6V·ËtʆxLj3žN}>µSFð’‚)®Ká‰ùW®NjÜÒ’h…£3Ää†û²éø#ñ¬M*&»X† gëiáU¹ÒâÓ?³gžmØ*zþ«[KðD°Ê¤YÅmƒžqþÒ§Úû÷+Ùû¶2õ€~É {8Ø=«™¹€»÷½Z ý ¨–è=?áI„´•É”I#Ž˜8-¹;Øj**×< ÄZ¡¨j6ÆÚdE!› ñÓè¾´4íU9}ˆÄzö+} HˆdYîã’͜՘­,"â+8Tw;øP¹’²@ÔzžWi¡é6À*Zq…Ï*¢œva£èxUÞwi3Eso$.§èEV‘pÓ$W¼êVvŒ&»h'B0–¹à‘‘^yâOhd¸³c4œmË/ä+X;½H”-±â:Ð?Ú3d÷þ¦ºý“©ÐÛg½j KÃwSÜ4ˆèIÎrçߊ±¥XÜXC43®UÙ>¹íïN¼•áÕŒUV Œ⦵”ÄpzjÜ]Úf9»ޏaVaðË3ï†î 8ëŽëU4_+Z ø—•m(Çò±voóšæÖy@À–Aôc]¯Œ4™uU²kGŒ´ <À}}« ¼/ª.OÙ÷¼Ò´Œ×)”ag±µà »–{µy™‘`Ê‚rsóõ«—ZÔÚ[÷âfQò)àtí]g‚4Ûë6»1íó"Â~¿ýjäH½·–ོ€4Ìà ÀˆM]Ý”âîLºåòXC&9ÆÌgòªÆívѺ·ûSä¶™‘±ÚpëMø‹ók6=rmFAíÅ8I7¡2˜xMCGp?ºƒ­zG…BÿcNÃÎHôɯ<ðjÉ çË×ükÒ<+þʸÿ–mÈúšOqÍ\ó3áišæåÄëµÝ¶ðs]¦£¦Á©%“›¯&ha°*H8Ðé>7¤òN9NWæŸ/†¯àv ‰*ƒÁVê?%$Þã\Élr_ðá/â?U *Ó:\ëàIô¸)nÞw—jž çÌV›iב$µ™8äí¦˜ŠpQ¹ã;M$µ½ÂR¿CŽ—Ãš¸`ÙŸÝ=«À:}í£kBîÝãY, ÆHê~~?QZl£¿ÊE9ç '=Æúv¨ß@sIZÇYÙ]AlX$\;õ^¿1­o '´Œ©ÜyÇÊÆ»-Î݆Õç€ãI#΋¹Víû±‘úS’ÅÌ­±â ?âg{“ÿ-¤çñ5êËð«Êç'µgé›ä™CJÅ›$÷ë[¿eÚ¡ABÀÎr*ºêˆœ®´2¦ŒtéR\¢®–/;±×§áþzÔוlã"–XÚ{-¡d¡ùϦx­,DnÍ(·CpÙéÐóÍmZN·S8‹;“†Ï¬ÿ [ Ë¡F]œ’=ºK[8’NT`Ž@P3úVUdúÆ=Ê[L˜ ç¦+E,#E”ãç•°Ý8"¤)µBãÑ@«rmþÈ'ïçP›{¢öZ:t 0¤UŽ@ý1YZƑ֗¨[ ”5Š1*~ZÜÓý‹œgk~'q&”mÚN[û¸¤;Ë0$ôªh„yÊxnäB‰,«ª â°|[á-næVÚÅä%Á0kÔ­àÓof7v¥ž Ö3†ÊœÙªêžŽö8£ŽæXJ•n õÀ#5ÓÖö9 B½ÐôKËmVÑà’YÔ2Ë·Øû[Õhí£“c$}q^‘ã.+ù"Û'”â 3ŒŽÿã\n¯¦A½¤÷Ö¾{©Ø”ÝÇn ;¿‘O^’x.ì’ ’[e†IõþTí)¥’é ”+RÛY}9«~%ÒÌš•YâŒI‰C0q=¯QYºrÿdü@Mè2ζ’JF8#ô4î¯bm¡B=HÈeYmcÊÈÊ£p;ô¬/Ý}›K¶¼¶yJ0õÆ*m6îmöØ…Ì€g ÿ*Ïñ·Éá}<3ovºœzgÓr¤Ê[jÆiïçªN«·wëë]öŒ¤i+õ#¯=ëˆÑ! cÇ;Î1õ8®ãO!tåv<ÖÑ–†2Z“Œž9ü)…ˆ9­6OºIäc5‹·bÒ’aËm$sYØÚÖ,_j±ÚÍåH¤’3œñYÍ­HVý:~b“]D–S,Oæ! ޵ˆbdoð¨¸õ5û0Á$Ÿ\Ðg•È Gå\î¡q$RAgå°yÆ@ÿÚ´‘žU À 1Í…ŸS¿ølº×öŒsZC$ðFÀÌ«ƒ…ïø×¤Ý®uª"yj/&?»BH“8ÉÇ~9¬ŸÚðÝÕ„,Ÿkk†w$uÔj–vñ²_yh.*Ž{Ÿñ­%tµØ˜¥Ð««\ÚhúÙ×büÇ$žýkÄüeâëÓ!fg$¨Ç@2Gç]ïÄ›V{UØîÛG-Ï^¼â-ÖÜÇ3+¡bì’~£éX¹¤kœ¨òcfŽÙŒÈêKí๨ÅÄ×—v–í°@…QQF8ì?•[€¢ßÝmT0§Ê·LúŸ¦?:lgŠæÚKxßhl®?Z¤ÛާK’çLÕ¤&Bј2rTœWoðîãO¼Ñ\Iþ³{™©éù ó/ÞNöáíb0©;pIõ­‡±[jq%ÔŒ·Ó­a+»39GK£Ù5Û„‡${psŒwëþ{WÏú屓Ƕ”¾It'Ì«Nÿ¥{nµ47÷Z8pF8=}ëÊ|c£jZ-Ä·7SÃ/Ÿ-€Xzz×=d”)ÞÇ%;ê:Eʼ€«»oVìÇ×ߥS¾¼›P¸k«é “Ý? ¿,³_*5Ón¸\ö…ñÀ©ªMìõˆÓðÖŸ-ö§µ¤BId`?ν§DøS¬jÔuÄ€1Š8ó©#Þ¹¿‚–Út:À¼ºI‘…vçç9çò¯a»»Ëä×ïZÊŸ»s54Ùæž Ðît0÷Éö»l`2)VÏ¡NõkÃZÆœ,dŽ&(D€Á=‰ºwS²Ú-åLD\c'wÖ¼ÛÅ–š>·‘ ³ ;¶ó$u~…¿ŸZÁ^.ÒÕról{‘¢hÍH°Ï ­hí,íð°ÛC|ªŽJâ>XêD\\ÜÎñÙÆBÂù›¯<öéùíeqøÖ³¥±”e$õ%–8àÀ)„óô¨^påš…®\çö©Ñ¹g~2Ja|“Œry9éTwf'8ü* žZN§§­ >bn<ð:Õiï Œ ¿Nô¬éV"FJŸNj&hÕ°qÏ4®,ßx†ÒÅ >ìà—Iñ†“y'–&U|ñå\ö³Ë"¨É·®Üަ«®‘lö…dŒòÇ#éBŸtGÌôT¸G#qéD°Ãsæ¼¢õ};þ!ð½¬ï%ݬŸgr>hÿ„ý8¯>Ô£xãl°© Ò½wTäÄC5BÿA¶»ˆÉ³Ê~…äþ•R—º8E-O&´f¸”©AƒÓã[W6F+hVÙ”í|žƒúÖÞ«áb–BÞÆo,!/ƒ’Nj#D¸Šu{©Ä…>ïS\n:ÜÚ÷D÷~X¬âžÅæ—pÉGÿÎ–Þæ"RHäFCpZï bȰúv™|¹¾±ŠW ·{¸~5µ6Öæ„Yä{¦Q´3þôÝ÷ewÃ9¯O¸ð¶†Ç÷#Ýü%ôY¼/odYùƒý–&¶çò!SiÝ3Íe–@¥ARª ÁÖtûmBušì F‡Jö#¢Xª€ÖªzÕšœã›Dc¦hO]‡ÊûžC¦iQÙ¤²Aí#—ùk­ðü† 6R‹¹Dy#÷ÿèî´(–Ý㊇P£ŸÒ¹ý9d´[»2ȈY@rOøÒJ⑵§ø’ÅlV)H†HÆFò«pkºlÄâúÙ1ýérëu1EA8Î Í>;ˆö‘%¤Džáqü騂iuüÊ+»g`Rîÿ µË<†ü® ÚɘfÊ2{|ÀŸåL0X²m9Ï Çô¢ÞE]-nz/öu»! 'þ?>EضŽ8µê:~•çË ¶8kÈÕF~IÈÇäjÂÉåbԯч\ÊÇžhäK¿õó;—ôÿÈíO‡¬›ƒoÉç#åHþÓÉâÛ=þRzW$5 B>bÖ®覆þËO\ÕáƲƒ|Ëpqù V*ë¹Õ/†­Ý·ëêäþ¦Ëá¸Øam€ç“Ö¹â½r<Õô·Ç\À3ÿ¡ í|!­ NÕ¢½cº¯Ý‘Oqéôª¶„'®ß‘Šþ€Ë¸Å)€ð« ¤ÛÅm,1Ûª‚ L]TÛ†?L TrYÆã¦=wwý*lUî=ð¤3[^Ý[É—q‚±-Óò­å\J­Ž9ãÖ­dÇm}6¡æ]6m(»³·’m¥#6þfT Ž {Öí³,ˆ®¸ätþ•Ç\|G²»·Ä¶B礙ɆÐj§ü'OF,¬RvcƒIú{ûb§‘ùãØïµ ¢XÀùG'êk€ñ­¥äúܫʭo,ciÉ#ý®ûP åCtÿ"˜€;Ž0rÄW5¨î{Ù0îŸ^MRŠ&òG1âÛ)ßRð²äcå·˜G¨#9ü)7Ç2H*ƒK;X{'ÿ«ó®˜E4—–¡ån+ƒ“Ï¡:UO±O¼ªÊ® 1©ÀÈ/ü©[³$x}ŠœÝü¤´IüëGÄ3à­=Jï} =ãŸé^‚ðDÙÝo Ϭb±¼C¡ÿkEo>J@Å‘QHɤԖè¥%-Œmn°·Ï@çùšé¯²žœ¡ÁØ~nàúÿ:ɳ°k$H7ÈsÈÆsšÙ¹¶’}HbÌdÀ´lâfÖ¥/ƒÿ,r»´²·˜Y‰ÉÎZ¹ßÀx™MÁ¤r6ÿ ì¼?¥Üi¾ŽÖd:oo“œä±ÇëPiv­–dDvbÄ“Ü¸é£ Ôc]¥B€«ÐVdÐ,޵jþá¼Ò©ógÛ¥T3>Y=:Ô½M,sZÔeu_˜¸lþ$ÿJ·¦\Ÿ¶®ü A5zçDÔµMB7¶ÙAäIœ:é|=ðÏÄWS+®—s³ûλGëS͹\®Æ‡À‰§“ź—ÌÅV‘}+ÑäÕ/Äðf5»ãîãñ¨~|7»Ð¥¸»–H¢’XðFâÍü«_SÓÚÒÚFWó™A$ã§ó«ö·3å±GV wáýáN% °Ãtãùׄø¶Þú)$¸-3”ä:צ&µ¨4·÷óAl€¸$)ÎOn+†Õšj¢Îi<ùÛdqËuý­CÕݦ§kæ•Øœ«œw¯DøUàöÕõtšõOØbýã°OËôãš»£ü>}3R´…Ü>@`òƃ$õ8'Ò½]F :ÚW…Q"…ÀÀ­=.K*x·NÒ.%Y峃ˀí€é^+ãT\ëÑZÙF–ðAÈ13ùW]¬øºI¼è‰T|àz\†—§ÿjxºÒ2¹ŠI•eeô'‘Yû;»¢Ô´±Ú|+77óµÕÔ¬ µ9RF9çÿ­Y®â¸’ÜÛ°œ›³œ‘þ5ÒêÖº‰†¥ØÜIkp¹‚ä'æ³™ÿëÔÔQŠeÅJLú6Àý¥G¿B}ª{–ÈÚ€i–¨¶ö1B™ù ùškßZ“æW -lTž-ç bª˜DgåÖ´š<õaôj³Ç'œ»@)žsÔVŒKMŠv·Åx±›vdlå½+¨µù“#î“Y1Æ‚CŸÃŠÒ¶n‡#Ó•”P!p23žsøUÉ8‰{ÛJÊñ+—S‘¢L‘õ¤IÈÆëØô®Øx:ßOµ[UšY‡X•úã5ç>2I¬¼Gesc'“aræ'·'qVÁçž{TFiìR…·6ÌSaHIÿtb›åËœ…oûç5‡ÿ ½Å¿›hÖÉä1PÍŒœqNÿ„æ ‹¿LÇïÛ‘þy¡JBp6O,ÿ.yŒŒþ­€9\ûtÅ'‹µÍ?ÃóØ£ÙË7Ú±†W?.~¦©GâÝ‘ƒZ\¯<±aþ´MØÊ×/™Ø7ã8ßÏåM\p¸n1É­½ì:¶”šÅ£;Â’‚GPH# ®ÔXi~0ð㮟ij·J„G(@¥[Óšin…Fg•ž0VFƒîáGZ½£_ÈŽ#iÚ&ÏÉ&â þ]«Õôÿ‡š,Z$Vúª›‹ã%š6*¾˜æ¼›ÄzU߆¼Cö³æA3æÚp¸ ðŸðª‹SØ$¬upø‹UŽP^óO› .} Æyü*ÐñޱŒ.›×kð®P;`ÿ1U&ñ„{C‹èTf­©èSøÃV Åô€ÉÔâOþµpzÿÅ ̱ÛéÒ‰íufòþ•™;² îl÷Çר[™õ[‚ƒ,ÍÏ¡=J,÷c‹Œ¶:{¿\ø‘~É=ºÃ;ðI#Þ¢Ž!¿‘&ßçšé¬|á$_ø–‰˜²¾¥hIr6üìÛš†MJÔžUǵ/džúÚË¡~Þ×M´P-ìíâØ€þ•)ž1€>ƒÿ­X2ëvk! (aôíQIâvCêjÔ#‘ÍîoÍr6d&F}ë‰×µi 2î¶trÅÜ`a]—¨-ìs:®iœƒõ®WÇßök™YÉÁî?úÔåt®±šþ›5­Èc‘Ú2â>¤ŒzzTß ,-nm¯¼E4*/$™á{D€ÿ3Ö¼vþŠõ¿²§-ù™Éç¯õê?Ï}­yÖrF-äça%v{ç5¡{ðú}Oû^™«H÷j¹Ù³å>áëN¹U¤†àÞÌî!Ô‘À*Fâ2G§Ö¹ï܈SÏY#þ<öæ¹ kÒ5½Ä÷«å_A&ÉãcÜt#ó«:Ƶko3Ì h’Aàõ¢I5x‚ºÜʹñ·Fš ­Ïóš‹ÁzŠÿhOz‘†38‰èFE` °7=»‘êÆ£Ú¦_%ºœ|ºô® ±?áŠu†©uqskìÁr=+[û:ÕÕ`‹åbW?Ò®éöÐ¥Äd"(F p¸èkz~F5Øê጖ƒ£ä届‘ÈC›Å*™~Ò¸_“Ë “랟¥6]äü›Òz½LSÐc0À-ƒœsΣaÈÚW#¸#ùŠyÈøÁÏ^qCHÎ }Ÿ™³±IèG²ÕŽÝÁ ÷ëQù1òM¸ôâ§/V¹ Ö‘ ”¬ÊC#×2Oä*Ôt%É…ô…mŽ3’q€y#üâ¼_â ¾±í ©ïŸò+мU¨ˆlÃÆC÷¸éúþ•ç&º:¼HÉ"`î€ÁéÀÅ*WJ滳žšáds¶$Œq€u? ·Åâ(g‰Xlú g?çÖ³t êZ´â;[røë‘ø×±xKÃ6zi+m–ðŽX}Õ®ZÓ_ :¶¬êFäE ‚q“Š@O^@¦À^Bz*` SN*ÌÍî1AïFsÐdÓ±ƒüèükK†ˆE'ŒqOŽB§æ£•€â«—Ãfžâ6a¸$`ç#Þ¬ÃppHük6מ Ô íÁ WH·${Žäà·8Çòªöà;È s‚´°Í´Œž3š» 3n1©?ÞPØÑÌk¾}AR]:D[°ÆNWãÖ»-'N²Ñ,>Ïo‰Hß·Ö¤·¸¶D£=Ï?áUînL‚Wv-sî&𨣬|êÇå<`ñõçüúW‰|KÓå´½µÖ¥$ÇÐ ¸ãpþF½ºào‰†g­pm+RñφõØÌ¶Ó• 7c w :p?ZÙ;!E;ž=|ÓneŒ!Wrzg<Õhî|¹£ÌJ@ûÄúf½þo†~ŽapÞ¸sö–+ËÓÞ¬Ãð»ÁÐΓ*^3©›ÃèAZçs¾É›¥¼¿3ƾ%^%Äú[ó<¨ÁäÿžõÎ[JÍŸ7û|ON=ëèËï‡~¼ºY¥Žå6…GEQ`”­ðçÂlPýž”ödüBfi$¬¢ÿ¥M}¯Àáþm“ÃVö˜R÷§ ã?ÆÜ}Mz·…t‡°»{ۨ͵ÄD¢$oò:äw?Z­¥øWAÓ‹kyUUƒ/Ì8>½+^{˜íUÝæù3‘œ’?J¤Ü·V2’KfOw+lœç¨¯=øË`×þ[”AçÙ¸š6‘ŠÚ¸ñ^˜nž3³)ä„l/j.o,õkIlá•wÌ… Œä{ŠÚ3Qz™¸vŽ„žáZž }Rö)NÔ½üKˆ£$ã4B÷¹2ÕmÿÖˆ7‘²ª Á'/øGí'™ÌCh?L×ËÚêW¼3¦K;[]ÜÇ3p·¾°Ö„v°¥ª ã×£•ÑŸ+Lã¼i©\éVy‘)ù” 9é\|Þ-¹eC°<‚ /Øx„}§Kº…FçxØ/שó…½Ö [i§s$3:0Sï‘úYéqÉ>‡«M¯Ü¹$‡ ¼äçôªÇU¸o”È«Ç\dטÉy|«”’fÆxÉ5]îõ™AÙæ‚zeA¢MMîÏN“RqÖ÷§Oš¢û}¨’àîy¯3H5éxiTõÍmiÕçýì—€ Ò§šÛAßà9¥¿ðæ£m£¼m{æe|Ìàn gxÞÓPymĶ­4ª“Ì7r+Gà¦ú¦¥uq>æUÀnçÿ®«Xù-ÆÀ¥Ÿ¾?•\õZ Ež ®¾­anÖÂÅ-•Ûs#s7 ïÓ­`¼¯¨ÝZÛÌ/%sždÇlW¯k>—Y˜m“aS•sÎ{×â_ ßhå¦gGM¹fE9ÿ=+>Ws{)loü.–ÿ[ÖäÓ< m-4×€ƒ$üW«*Þ2–ê@À'¿½qáŽÏÀó\ìK«†mÄaŠƒú ë<Õ{v*Cz]R³JÇ>̧rÿ¼Îx÷«<±œƒT䤯GZ· e$ŽG³(/ݼÌžÕAÜÈ5=éÁ©ÍgJüã¾i!–<̺óÔÑtÀÆþFYváÎp¤t5”ß$h ¤õ$ñÞ‹ÓSÊ>"i76ž(KÛ8ÛÉ™OÚ2HóÅsú–¦òC‘ 1DFé]ׯ¨%›Ã>rÜ<- Äq‘þq^F‚W‰%bJ0I}ë;>SfÓW:ÝÄ 2êÀ¨Â€Zëü/}é<–¤1#o¿~Ÿq>Ðíî#7Wé·¦kiln4ø^m(•|*Ù8ÑΖèË–ûø³P{}~ÊâXÚ åç}ÿ*¯x6Ü1^CõÏÒ™,–¡¥Iв²r_¸÷¦ØY´‘¤’–(O9?Zˆ¢g±§¡© ìB€WÓžÿýzÚ°œ2}ë?H‰q&OEþ†¶,´ëˆ [ÇU;ˆÔ¶ycÓ9é¹ع£ éÚ º8‰ˆÏÒ®OmsnÆ)¡hÜAª—(Æ&äuä{V·CHÞçÖê|ç‰? «¶8¯î÷AÁïíúPÑ5öŒÇù ³d J›”ãw§ùí]ž†Svg@БrŽjy@c=ó×ô¨¥G’L&~€SÙûA%Ï>PP¹úsùÖ¦t—.LaŽÞ{ÕJV3K™™÷âÝæŸ¡ÿ -žg –ãÕk–ت³F/´ 9jº¶îª†‚näƒSsáµæ\F¿qAV|=­ÙE¨,W‘Èÿ*·RNF¨† c ·¦þÌøW9ªÇkv²Lé•!•ÂúÿÖ«öŠ;Š0ocRÔ¯¦lLìбÆyÃWC§Aˆ’Ò+§H"‰ƒ3Ž2+¹¸û]¬çFÜ0ëì>•Ð]Ã-Œ.5+p¤d&2GÔãŠå©7-Ú’Ž§¯é¯kk`–öqÆ‘€Bçw¿"©j÷ÑÚFœÿNkðÿŒÖÚÌG;‰1ÂäüûWM¬^/ÒÉK‡·r0YH#ö¬éÅSw’&m·¡Õxvé5 ;í‘”’0zðHü¸«ÍÆ3Ò¡Ó­â²±ŠÎFúÔíŒrrÝ«h»»ô!*ÇZN¨¤Ý·<þ•òªÇ»‘Ö¬¬Û†GÞÇKz™¼¼÷ïëPÍzð!\§ö¬__Ke{g; ‘Ìû\ç€0Lâ–ƒµŽÎ F·5i]]ïÓÊO«Éon>Z£æü¼t÷¬Ýz]DØHºt‰Ê¥× {ñJëv5ôGñkâTZaŸCÓ&¿–2¬‘‚1ó ©ð+ÇV-„uM‘Æ„7(Ø“´ÿJßøoû8jþ)¹¸¾ÖµH­æºi%VÝžxÜιïÿ¼AðÙ´Ë›) Õ­/.< cm¯zœàwÅ,Ó ª{5¿£ÿ#¿ê2P»kÒç²ËQLUá‹Ø˜Á5-³¯i dç˜×ü+šðN­©êž´ºÕcXä)µ]q—Á#$~þ5°Ókµ8½NyÙâ1Œ˜XËå®1ùU/ì½(TÒôý älƒŸÊ›çcݩ㗳‹è5).¥…²Óq¦Ú)´ ÇéO¶‚,í—þÙðªË(ÚìûPÓyãÓ{8®€äßQ×^=ô„úMœ—6ÌL+¹èTãŠf±us.÷Á%ºSD¤cû¾ÝiBê@î8ÈéME-‘=L¸~Ó$¡Y¶©=qIkàÿ Z‰q¥Ãq,îd–Iâ[wúUÂʧ8‚EXy;®¥§R¬aÝx'³6_LO8ŽF_åÅWøonÔŠxÎ0?xóÐ4ÇŒƒÇ¥'ž{µ« ]£“ŸáÞšÁ¼«ÆŽ &yö#­ÏxNÚÊÝ Ýß°`lLÏrsWZq’:Ò=ØHÝrsBŠˆ¯}Í Éôë[Pú3µGYÔ ˜Ä! ƒ€Nx®CÅZ…ÅÃ$p¡hîð8Ï8ü+͵Ïý—]4«é(ä̱’Œ޽©&6} áxã¹›9Tä·j“ÄVÖrÅ'™²œŒz ‹áݼ־–òä2ËvÅÆåÁ ƒúRênŽJ•ë×&ª¤l¬L^§›êZäº\²in|­>5>_–¸äûö«>ñš\ÛÜÞ3G3™#9c“×óŠ¿su¥ØêKä0î—”ó=3þ±õ[ uÛŃE1Á3° @@NäTA¸ô*QOsÐtùá¼ÔÎ1}jI®–^GOµC¢é‰£i†×Ï’âN»äþè=¿Â¨j²Gå·šÀ u>•RòM¸Ô­e£•fõg5Ufrã|$}rqŸÊ²´ _IùU¶,3duÂ}8æ­_ë–† m$Šy;*IŒX¿†5INp5æ°ï –÷_ÞDLq“œ7Ð{V.½«jçPè’[Û0æL–öç5[Äºì¿ØmfRe,„)Û§Sõ5ê>[xëUŠþÍ€ºYiù@ùTc¿½bii—ZÙ¬9lŸ^?AÅsºm¬ÒZ´ŠÃ¼³<“õ®“Áº}Œ—ä<åT…°M8E0wC¼`ɦ´±±€2߇Z§p×6Ë ÅÚ¸N‘”­¯‰ª"„ZDò´x Tn ŸçRø6[ûÁ¬°#C9( ã×Þ”¶­k—4Ý:]AQî^H-Ç©•cøÕ»&Æ â9åÈmÞßZÜ×,Ð_a1ì]ÄlvÅø2Þm[Å­¥Ý=Á¶uܳ)<ÄqŽ Uù¥ÊM¬®ï Ú¤×AZ2‘Æ>¿ã]õõ¥¤g`¤¬KÆ2:zóVlôí7M@¶°† ¥Ù²O¾:VN«¨$M Îæ+œöéEY$¬LaÕŽ¸–-^ÞP$öÇ=ǯóü«[V–61©$gå©úÔÕÖêþêå…o—ŽJc“øs[ž%³Òí-b¼ÜOÁ -Æ{b°kK–‘ÂI£ÝÇ]M# sœ{×3®Þ37·H× `pkzu³`SeÀlõÚ3Xwúlr~ù`O$61õíZOÔŠJÝ\°8'#éV®¯ÚëcH¿8à°î=)š†‘eyö[¨%r¸é]€¼¨ki,дvÊs#²ööÍUhFž¥Âó3|-áíO]¸Xm¢®8¯oð®‰o iIm¸É&>f=¿ÎkSLÓltk´±·TU{¹ý)“KŽâ¹#UÕè‹sIYbd>üt¦Êãž•.«´û%•F{µ牴ȷ)˜ pyë] (™«šåƒ w¬ÝJÒ[ò1ÀþsÏ4Ý/RŽú!"FØndb´‚ãÛK™7dV¨E$9ç&²¼M ¾¡g5› rË·rŒúVÈ× Èôª·ê‘»®ÐN:ÑËa^ûœT´q*<ù1Ëb¶¬5h!½rƒÜúÔ>T’¼O´:€\uàÕt‚ÓíѼj6¯R}pxéYÊ•ÝÍT´;{yÕðèÜ ­½«ŸÓeŽCŽ2;ß…t) ÐïZEi©Œ“èJ0H=iAäg½"ç ó;nÇj‚ö,Dvð{õ§O÷U<šŠ1óŽ™>”û”óm%Lvœc®j‘,¯yosŽd arcªûÕ‹ËUàXÜ ÏoçùU[y¥¸Ñc%ÜT‘Ðà‘š³4¶òÜGͺ ²«´rF}:Ô¸êfV­%ý©W²·ûPSó…8ö÷«3-´q¼ïƒ3„_—øj¸n¬£3Ng€@ƒò©ã¯çHÑC=—˜Ì W„CÄ{ö©ØzµY^ÛM’{e:+~èŽXÀüzW=¥kz½×„ÿ´¤Ó<»¡,бÛæ ì£ó ã]:-š1hÙ|9wäªö$vm&…µåŽhLep¤µLUhÖ„õÜ« Ÿ//•ÿdŽj9J‰žƒÖ¬ÊœÙÀÉþu ‹õ,˜:g ãš°ìUÕ. ½·Ÿj©p6ö| út« –·Y]6¾S® ÷­ &ê-Ê›@qØö¥Ü.ªãØP£<É" y-YPœnÈ9ü)á²…Âeqsо’ bÀ?/8*`$qõ .e ¤Ë|òõïŠO·[íF~p­tÇÙ¢R*䃴óN“kO#² ”à(¿A­ xï –SYz€ ǧj‘ÜÌUI#â´ÔfÒæ9ïþƒçœ2s´Œíúâ—Aó³|NÕ¼šf©lÅþÏrmÞ'ÉWGÈ9ñÁüSñ_Ž5@ïª]›”I ´‹f6n„{ý}+›ø¥¥Íyi¶|¼o¿h=OùÅKðzÊMRÎúúülŽÆm‘ÃŒ0íƒÁÍ,5.~§GÖgÉc³·Ž :ÚÐa|¸•zxëIö»_;ÊG¿n⣭hÝǬžj†]¹#ó¨‘]æ/œåN~+d¤¶9Þ¥q<9xºqR|›w‡‘RGc`6}Á”ˆÁëøóV&Ue*oÖ«^¢3üøÒ¨#œJDš “):zÔÉ4«Y5#¨H[Í4gåÚNzzÔ­chL[TæPÀ÷àQvR·V!x)2¢«wÏÔÊ8à:«yeosÄá‚oÁÁÈÿõÖ‹Ü)ç#Ú™ ”g!@9ÀÍDíʹnƒÖ¡ñÿ‰UÏ>[cŸöMaZ'úfŠýŽzÇøš™Ð)MØß‚zsJU‡<ðzâ¹Ý oÃ噉“Ís“׎ÿY€)¶·˜´“¹Ï<à·N)ú2“}M† ,Ø'¾1U.€0•Û»ÐÔ+º’‘ö‚ þïÞçëWa´ß,kÏÍ& ê1CL. [éú^/n㈼ãpiäzuª­¦h~%Ô~Ç{§G1‹ýÐ¥pxç­f|I´¼¾† [2¥!*Å7m=GÓoáeÁšÓW½”®ègWÝ·8Ïü „“zŽòKC¯¸“ ¦EáG ô¬[ð\·ËøU©/#—˜¤V#<ª¦Q2ÈèÁ¶›ié@–‡|BÓMì8·&O˜7ZÃèìhïd_3ËʱíÏJß¿6˵ÏÊóÈ>3’jõ׆ôk”‹Uy¦{±ËgÛÓð¥ÇT]ï£24¯X]j×Z}ÌË—ÌlÜ\ã­bxÇź<25œWqM+¦UQüë‹ñþŸ…¯UšÚãì$úžÕ•m¤®¡¦Í=ÒDÑå¶ÜƒÀÇ~ù5.i‡+‰§{¬ÝOg”ÛmíÜ…Ú£nüž¾õÔx1ô?ZÍŸ2\>KÉÎ3”gµy¦…sÞ¢ÞÛ¨a PIü?Æ»;»EÔFÛgV l¯EÇAЍ½.êÍ+ëÕ×|IŒÜÌaØZïn$‚̬f®>ï?Zã4²-b}Vð ò¸RëYz¯Œ„‘´¯o#ŠEÆMS´c –¬ÆøÄ픺°ˆù„ìeUä“Üâ¸í ï,îVG¸<ïâ´îueóÛtWîˆ'ùÓdº·™1¹ÏPµe´îi9&¬ÏHð$WMsy¨óÇ–6ŽElôû’XV8¼Æç¾ÕÆØx’;+XÎó¹ûßAX·¾ šIË“('€™æ´›»ÐÎ CÕ·Áq)R SùÕÛ ]bìǪÈÓ· ÉÈþµÃé7š´‘JY<ývþ´ña®o­ü¸Êíëß9ý*£{±;Øé'™mÜ/Ö±5O-„¸`NÒyìÈ©ï5Q7ÎUTü£'Na‹.Ût‰J’Ì1–ü«ž®ºc…øjo#ÔuÔ+ö©~СIúzw®›V¿ʉÂ$#Üîÿ8ª?le²Ôµë‹”geòXŽ˜ŸÖ­Zi,.&KÂÞvæ@9§Z÷RÕÜOÜŧjKzP•ÆF9lõ5»'ˆÞ]@D„|²ÌsÈ›¨]_ÚÃ%½±v`ò0¾ù«Ú…˜žÙ¡ó〷VÆEc*oq©.§ŒÍ¨rËf°\Œ…WÒ´Í_YšH­ôée\ã*§Üšõ¥ÓôKW4k<™9-ŒU{ßÁn  Çè¥BЏ¥» {{ VÚ$µ¶»>’D¬søŠèEX#R5 ª?*ð ëWéz»%8Ü3ØW²èS}ªÉ]X±#¸°’³÷‹I´k;þ"ªÊI#Þ§ëŸÂ¡¹RÈTÈãë]ÎÇžøçLêÜGpèñœ…@èGç\>§ö¨ï–ØC'цüOZõoF{ËYR)šßs#¡ÿ$Õo øjòPê­Ž¿ÄsÏ®*§%ÊT#a|mqYb!@ƒ]tŒzÒ¢‚áQ±> L»`sž sÓ…Êœ®QƒXŒê)lÀÇ#œž¿…k].=Á†:× «j¨·àAšÃ¤«ØgüþUÛØIð*»†,¼:V“n,I6ŽÄsêQjþ]¨Q ‹™\ À‡ñ®RËYÛ}$+9FêN9ö¯hŸG¶ž"‘IYnqȯ+²ø[«ÚxŠY.nú{¶å0¾dï×výkOvKQF÷;χћ¸ êIPp '¯ùÙp0¹s…æ…RÑ(ÇVãÓ½@‘[ȹ(¤²‚£2 ½¿Î*QÈNsÇ_¬4o#ʈ70^jå¶u ‹t{·ŠV°ìd´LsÈ!ºqÒšbLgŒkª·Ñ¢¾kdƒÚžú-¡'åažùÿëSH8å¡íŸO­Zcû€®k¢}ЯÊYHíŸþµP¾Ó$ŠbÀëëIß°4ŽSÄ8:EÈ8 ÄÜwû¦°-ŽÍCLˆçE‘ñès[¾.FMûH |sÇLTVVêÚE¤¦5-öBØù¹#>”â´%˜Z¿ÃQ0=¤’gÓþ»g!òôÐK)Çàÿýj¸¶±E5©H€û=›yxí’8—ëT4ƒ›=#rá¶Hàÿwþ½ FRÕà£^ŠZáØ{à·øWWỸ“Ì?*InÜšÈðÞq~ÖÏb4•šFnƒ–ïëÍvî±ÚÄa€‡¯¹«vèJZ˜ú¦™¦ÝŽXÝ÷ ƒÒ°ü7ᘼ>Úˆ°ºskxw´s‡Æ3ŸËò­û£,Ž@CŽ˜ ÍVk˜íù€ƒÈæ§cCË®±£x‚r’HÖ³ÀŽBœôç¦}kjÚëQ¶„]¶——-’c9'ó®—Mû6©qwˆƒ‹s‚{gÓùTëäàmÞ¼mì(Ûp0´x¥½¾‡R¿·h@;’ÇÔûõ­ÝdyÏ’O#=«ĺݶgö©ˆrBÿ{ŽÕZÔº…¤úTBô]€Ë°ŽÿË×½¢«sÆþ‹Ä–?fžG(„£#žÕçºUŒš6°4íhnß$*àœ*ž¿Ÿµ{•ôd79b㎇Ҹéö÷Òu1Ó¥fãÊÍ#+­NǺG‡íF²½Cx%\œý?å´íBx<¹ž8Ç~}kч€'½•Ú)£Ã(Ÿ—üñL¿øUqýŸ%Äz{´RUyFö<дÔOS 94­fÈŠ4™¶¶GFíþ}ë¡ð½ärÀJ±sž€¥JÍXu.µ:M2ÎÖδ"õáF\úWOáÍ×JÒ£³·ˆ" cÉoƬjÚT7vM‘eXƒœÕÉ5 <ÒâUÔ´•¸yÙc …FèsÏ*)Q§©SŠô[¯ ^ßZ9aû,*0³ÉøsúUÏø'CÑí ÷FþX¶¹Ú™#>¿E:m»±9=Œ½7DÕe"E,2ù+<ŽÄ×Y¢x~=25—UºY%”ÅO¨ki@AD‹òŠæµ/ZÇ:ÛÉx…ß9\œŽõ·:[Ës«Ô5EQå¢8ÀþÁ®cT×RÚ2òÝ$}s¸\Ûø¶Â[—¶šé@ À䓨W q·>+hïg™­eùãó1Ïolþ•›l¨®Œé5ïˆ1Fæ;DyØäoÝ…ÿá5RÔ™ÄÓ°Fþ$ —ÅX­óZXÀ6E÷¦ïoʱPåò$ï£4å±ÕxoNh&_:<†#ãÒ½_ÃoÙ@Œ à ä÷®{OÓ!±Idp²aNƽixCiŽF ‡V öã,gg/xÍö:r@ÜRH9"˜¤ß9§63œãõ­ãª"Äá€<Ôñ?6Þµ ¬’jh 1‚S­0³$ r?*ÅמCo´.P‚=óþq[R)`2+/TÝj—`ÞqÚ©§Ÿê Ê‘n-œ/÷¹­WÅè³ÛDSÌÈò·å\î¸×~!Œ±H9'¦qÅcëKu=ò\Î¥‰!CÃ5•UgïE6´=ÃHÔ’ö!4\®:ç½joãæ5Åø$¬@ Ã?çÞº+ ©ä‘̨<Ž¿çÒ¢Ô&µÐÓŽ5iCõúUÕEl’:uªPÈ@ü*ä9Œ÷ö­ŒîÑcË 2*g“S…GsÓ ÐÛƒŠhw"“?—‚-¼‡– qɦÆAëÅ6á<¶R¿uŽÖ˜‘™ñ BOxFïNÇïB„ã8qÒ—àÚ4¾Fºg’â×÷2îé½p ÷ÍoYƒCÜU½6Ê;yE¢ÖG2:¯rzŸÒ¢k™Xi´ZC뎸¨ Vfëý3S[°`C|ÃÞˆ<¸¤ÙÔŸ›žŸçš¨¤‘7™#šlr•=†9µªñ @À€:ûU íŠa•IÜñVèFîF=@ JÝ9õ9©-í÷JñO{Vo™A#¿4$ • 1lÒ‚çƒô«ñØ1,¨>µb;(C çq–€([#«ƒ×‚kZÜ’eäûsM"ÆØÇ^•µÕôùíš12•fCÓ56‹w‚ÙÇ2F›¯R+°ò'ÏQÏ­4[ÊAËnjlq§\Ç ßª £+õªZ~™q/‰t»O³Èù.dl|«Àצ$Ç.”†"­»ŒABó v+XYÃaj¶vÈ5$ýIêsõ©Í²³oʰVûÝ{R OÒ˜$HqƒµãŽ+”ñ¶„u}&ê [–¶žT!%\œÓ]+>rvª² °*\S)I£Í|?{sàýÓDÔ¼Û›p½º’sÏjçœW/®jg¨[)h$*·}ǽuZ=Ü)l.Ð/÷³ÁÍRŠDݽË6Šñµ¼¶ÎèW“š¯¢Ý}’ËȆ.9ë[QÉЇFÜ„dc¥xïŠ5ÛÝÅ“[ÈGÙ§Rñ¨'$úñíü«)O•–•ÑÐüH ®éÑYîHó.×<ž¢¬[è÷z ¨Z_ÊÊ.Œ ƒô®=vÚöå0/˜`±ã5êÚ|È4ûc‘…ÇÌy#­#+ÄRkc|co21MçATçßšÙðlj ˜ÉÞ"#îäŠåãð¼Þ#Ô|݉!ó ÊÊxR:ƒô⺠_†onáîu¨ÃwH¢-l’)Å=äK·C¤Šþ zH c>Ø«ÖRNÿh(Ä@*¦›¤hz^Ö>ẽ¼ŒÏÐçVîõ°¨c€ŒvAþsS.T5}3¯Îê vêj­Æ©mä‰2zn=«Ö¼G¤[î.QG÷‰ \6¹ñ Ž–Š&oï fæ\`Ùéz¦¸#d°täâ¸{Çv»£IŒÒsò¡¯,ÕüAªjL|û§ÛÐ,d¨ÇçYj²JýÉ©Rl¾FuZѶ&òõÚ~cø×3$óÏ!g–G'’KMJm¤Œ)5aÁ`Fï§­kkº*hÚe¾¡ç‰¼â0›qÁÇ_Î… ï±s óp~÷¥t×Zíá?øH./ È€Œä±žÝkOWŠ;‡–¶È¡%xÃ;NÑßëV´¯Ÿá|6øù•wg9} Wìs–VVÚ§…­®<‘ ¤à¸þ?–kž»… ¼’%=ú×màÔÿ‰Æä™OQÀæ¹ [ ¯])êü«9;48ësÝgdˆ‡]ÄÓ4Ët³g;²I>¹ÿõÕÁÇÊqȨn]BóÔwªaª2kRÒÉži%—bn$ŒäÕ´¨)ÇSŒžgÉ PÓ5¯Â=Pù®bò÷´ q“ÛŠ›Eº)-ϰÿ<ÖF¿d‹g¸±Hã_º¬O¥eü)¹’{‹ðIòD¸ˆß¡þ”åg`Š»;ÆäÔRØN1Ž•+—nzTNFÜ}jbî…cˆñÝœN›ü±¹FIUÎ3ÿë®gIŽ£r&ðOsŒûW¢ëvÑÉjìà1ÛÓzW+¥éfß|­É,J{Sª”£cH;Ž‹i´DUÂô÷­4·UŒ(Ï×5‘¤3Y·ŒÎk^л½—𬨫nL®ËQHõ«Q¶>bHõâ 0£`ç•0Á#&ºˆÔ·“€qM¾Wkrê2G$tãÚ›äŒö«Qa‚2Ò’`dÄAPÇô«q:ÝãR7cå#Ö¢¾,c'$ÄNíÍü>Ʋ´vÏí²[<Ê’)áI°övê†E _ÞÝê“ÃuAå>ЄäŸzî-qµ‡‚Ö{µX¯-þda¶AÆqë[1/N*^¬åL3“’÷=©ña•C„ä|¤÷­)p»\¥dëºíÕºÿf\Æ’+d AÕÅxÏᾕâX^;¦š"ÙÃFqÃ¥CO¡|Ë©ó=Üö‰½ÄeæÁåX€­%½íÄÑÄ«–‰²Ì£®0¥}¦|ðä¿k–êí€ù¾`¹ü…tgÃ?Ø>bÓ„»,Œãñâ­%mDÚè|áee=þ¯î…•X™Ïãþ5íÖך–£¢´ ˜c+ò¾Wà{Î+Ñ4íO²]¶¶6ð¯aJ?•[û2qžÃÒÕ¬‰ò©ü* WØò/ Yëö¶âÚãNš8”|ÅÓæ=úŠÀñ·ÃWÄZÌ…¹ŽÚÞfy^};ó^òÑD:íäUYî,£\RG¥9{ÛŽ:lx·‡~ɯκ#?•z·ƒtëx7m9LgË2HúÖ¥î·q‘sŠæu$jÏ4Ê rrÔ:–V›: iì4‹!a§A¼*½rO¹ëšÅÔõ1wÈqÚ¼ÿÄ?lmˬ,nXö\q\³ã NýßùH{/ZÊSl¨ÀõwÆvEÕîŸá@y?…p ñýíÁhìPFüN2 ã%–Ißs31=ÉÍ k3ò±;/r¥¦ËJîõ «ÇÝs+ÈsÕŽqô¢Þ9¥? &º¯x=œV«c= Ù= 2[xd_žrFhBIéS|¼u>´&+#6}&ЯÊ̘ô5,zM´aXÊÇAWd„:àƒƒC¾=©îZÊÜ&GÜÕií$S€ gÒ¯q¸ʦElîŸJa£3RÙÁÀ#ÐT¾@§áZ!K˜sÞœ 8íEÇÊfy'<Ó–NJ®kImÇB8íJ-F@ÚÒ‚z™é{T‚¼¨8=M^ø(©bˆgž1ëÖ•ŠÐñÚ×…'PY‰Œãñÿ&¹ÏÙ3kó ÈÃnÓØîæ½ãœ3é.®U[ÊfV'8®ö:|_Þnuv@éþÓ|Ãæút¦Þ…icÝš"€Aæ(ã¦?¾|²HÏNô¢4<€¤¶ ¤ö8¦° Ž3“Z"(ÿ»;zRùQÊäŽy§ Òp©¬kË£ÑÉ8§µtÓXÀãÍsØf¸?g Ó¦h5,Q.­f-• œƒÔòjœÊ5 –q .Â8éúš“G7Ë,†íP‡Œe”cœc§áV®ã“È‘c3)Æ3ǯj-pº¹‘¨YÝNÊDÀ0Kæ1öÁÿ>µ§¸w’c©ý2;N†T²‰g@²ªüß6ãù÷«ÀèçMèJsŽH”.wœaÿU9¢]ýx¥Ž_øšÁnyÊ3þª)·ÒNì–ö¡wîVg|í ‘ŸÇÚì(ŒxâƒnÜšçÛ]]KZ“JÓüÓskí1¢ÀÁ^{TÛØv•&psŽØ¤!“ê ˆ§8©³×#Æuä¨Å €ß/hϯziÇ »¾†’@Èü«Q×$! ÇZMŒ×»¾‚!÷¹éɬ›\òñÔšåµMpG¸É*€8çþuÆëþ;Ó­C¬r˜‘ýUVÏD¼ÖX‚D¸8àä×)®ø®ÊÍϹEÇ«Œÿ:ògÇz…ò˜áBÎycø×-usqpåä‘Ý\’jnÍTÔô âÉòXGÛ«cð®'PÖµ ço2yoáÊ«Agq)cbOaÞµ4-íZ¼uÆëyfp¡\`Žiª|Ã牊å?Z¸Ú6¤¶†ïìsp2dØvÇ¥uÿ|+mà»;9lîy¤ M¿ÓŒ×sã‹ðrت„Ű9QŒü£š|©!6xµ­„Ín—[sq»šß²eŽÕÒ´±m§ÿ^´u›xì<j¨£˜P“Üœ ãì.žDÜdr¥ ÝØm+\é<1¨¶…áNÅ̪óJÙpqÿë®ZÅZ?0g%‰foÄŸë]Jl»ÓšÙ”0a•ÛúW!x¯mvðîCŽ{úUKâW%;#nÞ)c¸€DÀ¼Ñ忥Oª#Úé¶Ï2¸“í Nã’FGsO•E•æ‡æ› ù³þéëùT¾4˜K§Bñ1q»#=1ÇJs²Zž¥¯Ï ß…7DsŒÞŸ)ªú$B/j30;ôÀæªÝ x G+Ÿ6nNyÁôý+T‹x<#qKÐ…=ý;þU-r«‚Ô©áéDÞ¹ÚNè¢e#ÔŒóúÔ^ ØÖ“¸a Ãñ§xr)"ðíëtÊØ?˜5€ÚÞú36Ôp8ê0œUØ;$oø)•´öd?u›9þ#»ÿ­\D°3ê×»A!äÈœW§|4Ðo5 *o.Hdy1!_—;zé4/‡º.“q%î«1»™¾êÚ˜ÏqÞªT#Ìœ…ÊÖ±Èxš("¾Fe(Žx#$wëù~µÙx:ÀE`·)fã#°íüÅrÖ÷'Y×Ê! ØeÏ u?çÞ»ÒÑY[ª#PhÙ(„£rã.Øêœ²OåTgÕÕ€(„îÙ¢ŠõP‘žñšåB4Þ!$}:‚9é^5ñÁ:¤z°Ô4ø$»IOΑŒžÿã^ÑŠxÛÖ¨jú½“Î Ž•¥*®/A8ësË®#Õ´ ‰$‡Ê.0©&C wÅs6–¡asöÐàÜ:õ'$Jï>"jV:–’Ö°ÜFó‘€r ⸋ææ+ai:yÇüÀ~Ÿ­KP³oFRnærê÷Rj pí,ÍŒ9ãÚ½«À qság¾»FBÄí 1Çn=Åeèì5Hl漡ŽºA $öUAÔÅ`í7dS|§‘ø–úóXñ%¾‡§`ù͆8ä(ë^³¦ÂöÖq[ÈÊí¸q\ŸÃË æiµ½2K)ÖVEó”+gœíñÎIÚ´œnÒk+Žù¦ÍóFFß®iÑd‘Èæ¦(^6Æ3Ž*Õ‘›g#â@}’e·•TC´gœçù×%áÿjžw—¨K´Žý)ïéXê‘¢ÏhÐ|Kg.¤º|톓„<z×W*ÍŒŽ+ÇôäÓìüL²½ÔL›$-ò«9'·q^¤/ãP¤ˆ*(Ënãó51ž¤Ê)ÑH#­Z•OzÆÓ¯"¹…n-åIb»"0*W£œ£¯Ë¸1 ôÏzÝ275#äqǵN§¡ôªñ·p{v:ò#Hdêyô4îw¦£‹¯'ó©;PM…‚yëOEò¹¦¡ óR/ÐÓê‹´t9áÆ íȦ©§/Þ ã¤pÁô§¡Áà ŒqJSþ£§ÿZšàîê)ÀñÏ_çHHÁéÇ<Ò GûAù‹áÙ%Œ9q éÚ¸ÏØü†Ôî¤'t­h@öùõþ•ÚþÐRJ¾‘ ”ÙUúWûqã SvU´ùŒô>f*ÚÐ}4>”Tãäu§¨+Ðz]¸$ö4Üu©Øp  ;#¿¡ï÷….ìðHúÓÅfÀ9^¢£Ø¬rTf•ÛÆ“w_˜téH]»IÆ8€[ŸÌÔ`åzàSwœŒó@ÉSÀ¤eØ¦Ž¹ð¥cÆ}iˆˆ@¢S.>`1œöàÿ…Iå¡à¥;w9ê==hÝÀz. ౎^HÜüÄM\Ø}iòA¥?4\c@QïøÒ3``b±¦“Á‚Ã]ùÇ^;SK?héÒœ©òñׯֈÂñœóM‘Õ8lñPê7qZÛîwTÜvó\Þµ­$Q–2¯®ê’)&k^j°Å‘Çzçµ=zFÎÖt<õ®Ä~?Ó¬‹«\¤’g•B ¯7×¾ êWA£´"'¯ñb²•^Æ‘¤zÖ½âË;Df¸ºE#‘ÍyÞ¿ñ',ñØÄ_=ð?Ÿ5çW—7.^i^BßÞlÔ;Ž >óܦ’4õmRÔ˜™ç`§øP•›‡•»“[žðÍöµ/—j žç<­_³Ò¿²…?j3Ém"»¸ý†N:Uz'¼ë9E ¹ƒþy®ïám“ø6g»¶†WI~BÀdc ÖN•áèµÿjBkÈíb†A–ÎNç[[UrÜÌñ+ÏÑË䌨'ƒÅMâ$xô+Wtuvù™X`oÊ·PÛÙxãKFTšÞXep0SùÓüæ]jš|ž[H†um¸ÎFxùUhö+ݘZ¬‚‡Œpec§OÒ®Gop¾Ô<àÇÌ|ŒqŽß•wW>¾×ô„‚4†ÉdÁbFÑÓ¯ë·Ñ<9£èºZ[È䊣{HRqÔ ¾X¯ŒÎÿÊygà êúÞ‚è h!”³J„+é^‰á?èÞ²QpEÜÊ»\°ùNzñZwšäqÄ"„ǯʪ0…sz–²iDž`þ"qRêòü"öwÜèµ-n Xż 1¨à"„W)©ké—åCdà“üëšÖüH‚7Úø d±ÀÏ·5æZž³w=É™¥läàŸ•aífŽ¢,¬tÍ>á岆žOõŒ£æ5SWÔ¬áCöƒœŽ yô^,½ó–eÞy/ÈÏëŠÓÖíN£äI6§ Ûc2c¯Ò®ê-s3-Z6ôíCLžcöyC¹àœðs^0Õ¢Òµ%¹Ã08UÛƪ鮣=­©ýØÆ×,2IëÅsz¥…Ö»¨K,X†Ø¥›xÿëŠJÊZ½ ßdu–>6–Hð˜E’\Vgˆ5ÆÔÉÅÔq™fÿëÖ^¹gm¥H#ØBœðNϵsÌæN„­$’wA%ÌhÛÞMçËÙ#)ÀqÓð­{/Ú¤a4‡¢©àó\ÕŒm,N¹è8©¬aÔ$—6Í!N»8üª'y2ãd{¶™âcÐá’ð­¹Ú7Ž™þµ¥¦êÐ]ÿ©}Ã×Û×é^oõýÜF[‡uLa73ïþÖ_Ýêz=¬W–€1UäNxâ¦1qÓ©R]OP¸ºU‘Atæ§yqÐtÍy]®¹«©Ú8šHUe6æá€ç}«¹‡WMCtаÇ„<ã ãZ¹ÛFfâÒº6’åTç8ç ¨µ}fÚÆÅîe~d÷¬V4g+*àvÍs:§Š. ™ÛDÁ³¸¸ÈÀ5WB³eýbM/ÄÂÞY’Kyå%Ü×ÿ¯UôÝ" ¹XjVÆ óâOqŠçnåXŽÚBT[Üoh‡A»‘]g‡5[›íôÙf"Bå#v9xÀý+‹*åmçfò…‘S l ŸÖ½CÀ:U­Æžf/–[ŸPztü«Öånv>€Øxn#†Ùžñ]4/’¬}k.Ê5V8Èp*ôYÇ=«XhC5íœýjÂ8ÏP¥dDØä•lN8Ç•hN¦¤lôëÍL­:JËŽp;çZž;€psLH¾=ièÀwKír3Ÿ¦)EÔx²~t ¿¸{NÜ;þUœn£8Á¦5ð\ñ¸{Ð-YªžN ¾\ðEd.£ ‘íH/²õãŸ.~Á Mq ËÑ‚ôúÖ)½6xMär$Ï–SƒÍ:ÎÆ{©B†F' ßð½{ÿ ãÍ_0ì`oP}j_ ¨²ø5œ ýžù3Éïþ pWµÊ“2õ= ÿF.õc Lp7=;uï^™c¢x~C¨9gº–Íæ6B’ÍüWºk¸VAÃŽ=pEhŨľŠÜM‚!ž£åU)Úè—ÙÜÍø7#¦©|dlˆ–Pd°Çò¨uFó~'iR…Y—\ƒý*/†‘Þ ›…·…¤w HPIå§áQ^Í%·‹-d¼‰¡–)FÐãÇ4vl}ÎÇö‰»-áÄ´ÁÁd<öéYšLá| år~B þ¨þ&Ý.­£¦e99â²t‹ÜèŲ̈p@\ŽÿZ›jÉnÉxNî=*æQælgÜrX dúŸ¨«Kr©¬Ø^• Rê6û2çó¬í2Ò;ÝT«»"í9 ãÓÿ¯Sêð}™ìáNgL~,´-‚×gcñ>þ-_OË!':/šàŸÃ<#¢CîþµaëNÿafcÑã¡äRøáž+Y2HHƒhÏó¢ ßߺ3âÁ#BÚÜr1Ï·ÿª¹K+§Jð´÷®›âëÄŒ–Pú×!µ…–ô%°¯ÿ­J+ßc¿»¡Ýü9F¹;JâS…=‡¹ë9®âñ-ïÙ ’@òáO×Ò»ÿ„úSê:#„ óJwN•蚇tIîííÖ[©þies»tÆGÔã´Ù‹o¡çÚoÃ[UÔmµ™ÖL9|䎼~Ÿá^k¥èzTq„n 6É.©öÏJMKX •ÜpƒãŠæ5]`Â¥÷äã8žõ¯eî«"c-Ù½}­Ÿ›kçrÝ+œ¿ÖR<î=Xu¯<×ülÂVŠÕrðÛ‡Ëüý«¾Öo&¸3=Ã’yëÀü;W2“‘¯*=YñR$í—(ãyᇷ5Æê~+º™$HÛ!ÿˆðGåXîä%˜ú“š·á}5u FWc‰$UÈì ­#IÍØ–ÒØÏšæî|#Jåsœšé´Üë5Ω戠ƒ!˜úŒZø£ Ùøj{(¬—— !cž}«¸ð kÿ ×Qer9õ8µŠŠ‹ò _C›ñ›FZ4òÙy+ÆÓÞ¹“~c†HgÞÇhÂ3}=ýë{ÅWWqŽ»zcÜ ×xì$ï‘Ú²‹¼ ¾¦Ž˜Â^D}²A­}üÃwµ¥Ç÷˜2OÒ¹$c2DXäQÎc;™²:T89tŽ·Æ÷Ð]Û¬€Îz\•©’IJ&æÉè)$rêª{Waàø´ØíL’¬~f zñG7$lÄ¢·9èš[w‘·#‘ší¼'â9t{FŽÞÞ'2rÎGÍô®C_šÝçi-—, g¯ùâ¬ø~íUÄw*^<ô\f¢¤-˦ÓÐÛ¼Ô`{¡-¼~DŒÛ›cðMµi¦½ó!F뜜U]d¹Ž(îIòÎ ;¿­uú ºMžã!‰”÷Ýš[hÊE{hÖÜ.dYD¼•GJôχwZ|ˆö0´6ÌóØâoì£,o€’€c烟JÐðE­å‡‹,äõNJ9„d~ R”n´eÜõ¸r‚0EZOj¯÷e tÎ*tç­i QŒ·%F'Õ&ìqš>˜§ž8­´°b>”ï1¶ãÚ£8<ú÷¦¹ÏN0)BPç8?Zb pj±s€[8 ñȦÞp |ÔÑ1å`3ÅC»<úRç9ǦE+ƒ'Y”ðØ<UDŒTr¸8Å)‘ñ‚yíEì%æZ27Ni¾`ï×ÔÔ>iW?Jc1ô¢àô9¿Šq}£Â×j‡çò‰v⼫öb“gŒbŒ}Å·“»nÒ½oÆó´>¼hÐ3$ä{W•~Îò#xÈÎøóåI: 7 ŒzÕt=ýÛ26:枬p3Ï{UgeóNFjÄ$ÀϪP‹1Ë8=*oAÚ¡\{cŠ™@Æ(ê8c2u桌n8 8=9§q"uÉ<•OLTõÍ8?ë@Û,Ç´à80ªÁÎ1ŒŠ~áŽN29ö >üýi᳎~¹ª»†=?p~ãé@F:ž”å °óíÒ««g¯Ö—vïÇÞhÉL˜ŒŠ«srŠbïO~}8ëX×Ú|³Ý¤ÂæE Ö0xaïKr¬I5È’OÆŸ¿Ê€uÜþ†«—†1†\{PÏpw¯9 qÇj4 ²ïqŽ„Wü};¼-4y ÛzþìÑ’#g `c9ü+Æ>=þœ m<ã¿AÓó¬+lmIjp ¤ßeùL?.? §¢ºˆ7“n+¹‡>Ÿzày<¿-ˆ8Ø§Š‚ÕZßÅ34ÈÈÎrªF ÿõ¿:¨l‡+jZø+I¨©É(?gÄë=¢¡”…UÁàœUŸ0,¨À'9õ¬;[I•Ī穩k-ö;o†º€Òµi@e1Ç¡$…düB¯o…Ë‚xèz(Ñ]BEÜWjôJ5Ð?päfPOâ¿ýzšŠã§¡gw5Äoo+±U›=±YÖRJ÷Jˆ¹ëƒ]Äp¾éR5Y&^8ÈÅahð£Ì»†bSV‘,\\Ïo©@À;VÎ¥+\[éó:Áƒ)õ9åY—¤Gª:¶X`0öã§ëSëræÎÜòP?ËÏò¤ö½‘Ð߆’ÂVPp#=*ÿ‚l"6šv¬®ÂSoµ“±Èü+™Ó®Þ{… ’#ç¿§OÊ·| w–¶ö‰1Þ±ýÏçúÕAjz¾.ý”€úŒ~•É%ÁŽËKuô®§âÓnÓQ3ÈqÜWŒÆP¡7s§¡¬`Ÿ;-µÊ{?Á¿Am¤6•µDç÷žf>•³¬øßOµWßr7¡ÁºÎ¼ŠæÒêÕâ–Mà)òõ¬ÝRÃV†F’ê ƒ7%œc5µ^g¢3‚‹Õ¾±ã‡º %–ÖäÉÓšçõ/ÜÜÆVÞHÉíøW3öyPAù€#é[Vš¨4yu1n>̪y~7`v¬Õ7mKmt1Õnoäi–wnƒ½O¨ÙKg%µ½Ô2A$£*$ÈÅuDšônè®,}à(øã‡ñ–”«Â„àv?®\´Ò·R"ÜÛGUàoÙO¨Mg Üå]À;Gø×œü^•<û½¸ªßíÄúüÙVHKê8çéW| ¢o„âÐó¦†Þ䚘]ó!É«Dòø-5»èd¾H£ÆâyÀN•”m,®6í’o3øˆÁ—Zì"ÔÍž‚ñÜH¢&\ Vü³\¢£n—$ó >§ô©D+j\;i`T-ƒÃÞŸ£ˆí¬dia$ÊçvW’:cŸ¥Er ñùE6£u?Þ¤¼¹H¢VgÀü*]˜Õ˜Éôéep`Žÿº1šs Ý-M¼‘¬lÜá†Iéï]„o¬“Ì–ô`œôW;â«Å¿Ö¾Ó f4]«Ç^”á4ß+BjÚ-åÝ“Ìf4ä9ëEº¤)r®TîAÅEi{Õµám —;5?‰’Ò #F¤…R 厭jô¸1Ú«q{“’²òçëÅzÆiäA` ¯¯Q^Sá¨dÒ¯£¹¾d À³ó/aüëÙ,@x¢rCd¹³’åí¡vÕy€êMXPGÞv桉TŒãÚ§Qó¼WJIÛRTRqÓ´õQÓ½ ç¨Å=F?…²¯RONÔž¸&¤ yþT¾YïÍ…|c¨Á¤<ðG=Fj×’HéɦÉGÖ˜9 sUårWœ~mÔg‘ÍVºù#,€2i¡\=[¤ÎpsžÕV)ÐðH8=EL’¯EÁô©c'\˜Ò;g<úb¢G=úTw7Gþ³ßœb˜\ÉñºðÅæ³ùm·¸â¼‹öx|xÈBØi”HAêÙ¯]×f{Ÿß-«4Fqº¼‡à ¿£¹i%˜3™çüþ5kmG}±2±b9=qS  Œu$集g rE·Þ¡=*ŒŽ3ž§=ªTÒÆƒ$ã#Þ¥ñL5è ·QéO\½Í9TzqI; yrK{ñÚ€h‘q·€4¾ãŒÔvÒ,öÑM;$]Ëš1ÍqØRîéïHG=? LPPnúSƒwÏ^£ö¨qŒþ” «“«Å:6ÃdT”ðzæ—Ìô\aˆ8è}ê)ê;”Âà.GJ0F=é lä~&hþ »Ñd—Ã)úòŠã‡ã§^;S| ¿s¤Ù¶¿fÖwJ?~ b È®·Ï ãŽ=*;‰”/ =óEÒè²+éÊ(¼(þœ×Šüv¶2h+3Ìê¨ÀìSÔñ^£&¨vlÝΧ éõ¯?ø¿SèFà6÷ sõ¬*«£jNÚqàVYnÒ5e_˜ý;ŠÅÔõ nücywæ&Ù÷Gù¯øG¶¿•TáP:ñÁÿ æ/ï×[¾¹ƒžN‡š:$^šš÷·oxª³Âª뎵ÔZMn|=2ùcr9$(¯?²–{”–S¼•ùŽŸ¯J×ѵê!”Èã9­UŒö.iŽßÚ—q†]ÇîçÔÿŸÄSõrDƒ‰×#ÔdgüûÖ>§1ƒV‘÷0ÚÀc¾=?J¿yteÑèŒ.{Ô½PÓÔqpo¥„`§Ïú?SXzj§?ŸÎ´ô9ü餕׿±#׎Ÿ¥Q°hÚí2¹møÏãUÄÝÉuö?Ú Q°@¦; —V t6b 3‚qF¿þÕËýÍ Ÿ^ÕÑÚxuµ¿$ös"I‡†ïN1æLNKCEVþɺ 9(F;šÑøom2j±ù‘0}‡å#œäWMáO M¦þòöH§G*Œ|×geoavD¹QÁÚ+D£I½ô8¯xZ÷^„B®±²¾ãžÝñXð¯oãLWPdr§ükØR%#©£·QËGÒ¥hîê¬q¾O"ÝïØ<È«¹÷³«Ø[=°s 0ÛŒtüëjæÝ#·lç8ÅeêGt€Wåý?¢¤ÛVGx¦ ¾bo8V#‡óü볿PŸT0 ã±Àÿ\—ŽdSso 2 N1Žýwž(Ž(>[\ìCn¤Ÿ\Íb´¤ÍZ¼‘È~Ïñ;kA@ù¼’Gýõ×õ¨þ4Þ<ÓÐŒ±ø­ÙÞ"ueÀ$‹fà{°ÿëT¿4v¾×ÖáP–‰R:ôà{Ö•ã`í)ß…¾_†q“ò†ˆ°ÇlŒ“ùšóßxþ!i î‰F0œ‹×ñ5Ýxråáõ®› )v¶á]qŸ›±´ Åêß_Ÿ6UcUûª?ZÖjõ3OÜhè|I§Ã®k *8–0Ì€~‡½jiÖV–VëP¨TQŽ”Ø¢ª*í` ›,ÜúSÑ7bÒÌù¡ ·N#\¶Ot®ÏÃ~‚4yË0ÈS\îiwi"Ýùx ÈÍuZtÒÊ%½¹“ N?/Ëõ®iÂQô5ºkB§‰¬í µY¡I^ã¿ã\Ì›æb=qùW¢ßhëw§¼±ÌC²îAŒçØÕçw‰åÌÉüJpÃÞ·¥ïGC4ìì_ÓäûHŽÕ,7ŸQ‘Zúׇ౎7IŒ›€$·áÓó®{H™ ¸ªî Éô­ë½^K«y¡ÜÒ¨  ùÖ 5"ÚV1 $¶W!GsW Ö§¶´û`§šÌš Õˆh˜¥S‡7A'æ%ÄÍ)bçsž¦—Ë;2hû%Á Œ•nžø«q Å,dCJQvÑZ;©‘—k²í鎵dKu+ù¡äi{¾î:ª‘6ýõ[y¤ò”)㓎irÙl(]<²LÒM+I&ÜÌXãñ¨rIâ­¥œ’‘Œþ5:iâ7ˆo¥;wÚ=•ÅõÚZÂG˜ý­N9¬%û<¼J£'+ŒÕhšK+ˆîm›cŽ2;UæƒQ×ï…S!wô%f;ètÖáƒGžWe¯=ëOL‡ûfú)¶£Á†GL*çô? jr^‹I¡ÛÌHàc^³áÍ+”"Œžäu£–Îè\Å íPˆNFãó0í]½„-ãŒà„P°¦An‡#¦:UØ£}ÜzU4˜EãxÇ~õ"Çó œ OqÇj™S©ÏÉ®pTSÔ0+øÓÕ0ëV` ÷íM4¢d>•*DŒŽiȸϭJ‹·“ÔS°¬ÕAØ})ÞB ('ëOÚAë׎ԀôäsL[\Z+”`zç¥g]Ú6Ö]¤äc½lûRȨà:S¸ñ.µqáß-µû4V³ó ÎØRßÝÍiËâ8íãß#1‘µ³^‹¬h¿“woñžŠã8®}¼ KyXgî´îWòÎ*Ò¦÷ ¾Ç'oâè®&-—Í‘ÉÚäœ{W—Lñ6³p‡É[+C÷š|†#Ùzþx®ëKÑtÝ:ÜGcaonxã J¾!éÇæiZ+aÝœV¯¥ #Ã7+´Ó¼g,ý:v•åmÚÃâͽ³È$šw•ÊÄxóùWµøþ#ÿíÏÌÊØ8ÅxOìòdo‹©¸³³\KóΟþµÚ #é×÷ît'ŠUg©«3¡É3¸Ð‰wŸåP+‘ªz©ÍJФœ¨Ç¥9W¯§>ôõš†„FFj+…K‚2 š³ÆŠG)à~4ÆRÑmÍ— \*²,A>• ”bµh‹›‹ßÃì=ªKfW“Ídd!p3ŽzÓÔB°àøÒ{ “©ÏlÉjFD žE'©'óô¦ãÖ˜ èy¤-×­ÁÈQQîÀ¤KÐVluüBÎvý)KàH¨†_r(±HlŽFAǶ A$§?:t‡±÷ªó1ÏLÒ•ñf³k¤][´ð¾%;<Î0¹ dþu‰ñiÕ<-ø,¡D˜=q€k«ñ –§dö· c#¯§¸®gâD¿…RÚOÞ¨ˆ(ç“Åc4¬i©ä> o1Ú|œÈ„ãþùÿÖ¹R%åÑSÎóù×Kà¸HkˆŠ„éŸ@iš¢6«<®›•äÁœð¥{&aè&_²]ˆÛÇ€fÃÿ¯ZÚ>ˆšÆ¹vÍsßNOô»]'ÖæÄÖâ5GÈSÐûã¥Z¦­«'šÏCÍ|dòÜOlѰ“cê1г„58%ŽàZ4‘³ó´ò¾õìqiVI(š+h–E gi duÏNÔ'°Ï>ƒÁ1]Mö‹¢ü¨ÛÏùþ•µcáÓ)J¢ÛS€~µÔ­³`œ }jE·R –ŽÝè”›ØJÈË¡vœŽ{T±®9ÅiRTn5²pr§+銂®2.ŽE\^:Ôk ã0EXŽ3€˜-J×£m»|„ÿžµÏêî#´i@$/ ÇNŸ¥t·ÊÉ äð~Sšæµ VÕ‡—´€cŽ+&úÆç“xºH潃å+ mØÇ^+¾ñþ#øCj1öez ¢¸„K‹uUa9ÝŽƒC]¿Å½¶ÿ¬£çÉ@IëÊþ5-/dÆß¾ŒÙÆ!ý¡RM¡bàCóé]v·ÿkI¼/ÊAÁê:b¹ÏÙÊ-—Ò+`7c¨'ÿ¯]^¼?âe!zÀVµ#hD„ß3±N :žEOö”·d,À‡`¼„ñšŽ8™€Ú8®SĶººk×çìŒÀ<íq×ùÔIÙ’z"•iw)cÐU¨×©¼_Öõ‹k¸'g’8­Øõúþb½cÂ×ÇUðå¶¢ê H¸x¥5Ì›"M§©ãÞ.¾ƒjÛDeNHüûÖ Œ³ÜGä" üàw¯Jñá¾ß"±IyÁ‚~•ÎGà]Z0ÑÅ2"ž¹'š·¸èÂ2¶è‹Oñ-”qǧD£l .î§8Çô¨®|;eª\yÈv<ÆMW»ðÛèò#9ÞIÉÁãµhiÑÞFˆ‚; Ý=ë›ÙN›æƒ)òÈu¯‚U1å¨cœŸZÓ‡Á­ò¿ ØŒñþ•ÒøbÖð:¼¨þYëžNxý+§œ¨¡U“z¡rÜàáò€.:íÍLþŒ–Ýäýkº ¿(ü(û:œä+E1ržSsà©^bT”Çe K_ùmûâ퓜°ëú׫e-Òž¶£øT«šègšIà˜$ýJ'xÿ絟ÜÚ#¼ _o sú×¶ý•NHLôIc«.Üî qTªX—Ðù–êeµÆÃk‚8_‚»vÇ…ú×»k~Òµ5Û,ûÉÁükßáµ³‡WÝž0Äœ~une®ÌjRê2Ó´»»éTÙPõȯPðvöòõ\r+ Ò¼5khTRËÆâ?¥o[Z¤x%yŒ W<—B”ŠV¶Hª°ëZQ@71ÅM]N¹©ÑsŽrsÒ†­°n248èN?Z°‰óu¤UÉÅLªzô . ¸â§LAô¦(äp)Xì=¨¸‹!T ãëS ùªÐ–ØÈäqSG×§:ИìM€sÞŽ¢£Ÿ×ŽŸ;ŠÂõç€ð(ÚHÎiUNàw)Ü6Ÿ­*äž)ÁI#ëO ç“Òš “““𬰻¾òÛTqŒu«YP1Iž1ÒUUíŠ^ íŒÐÄLpH8ü(ÉüP¸èDgÝ(M«×׉üuÓþ2ÚKvUåe\q¸?×ù×¾ëv+¨!”…aÃv9®Çá½§Š-õ›{ɘÂÅŠ;g±·_Ò´VkPR±ì“4o3²ò pG¥!UσÜÖtb ·qÈ«FBÏ>õ¬'©ap98ëJ:üª-´dc4þsŠHÝAnp?1Qîõ<ÔlHõÆh:|Iž:àw£~WùU9“tÊûß r1>õ!“,Ku4\ [½(ßÎMVÞÀëJsq@X•°xÏášiaSQ—8Èà~µ1<ŒÑqi÷¨‰=O”²7N•žzöí@„v=FHj ÷àw§äþu{q@Ó¹1#’3U¥b9ÏJ´ë¸gž¾½*)—б•pĹ=G­s—g‡0ÖÇ^˜à…vB¡ À>õÇ|NÔôû ZíY°Bd’p;Öu±pzžOðú%ç Ñ£lsÔV‡‚tén5K¨ÝwF³îÜ=ÕGô­„ZkÿÂIxò/ú3FJñÇ'¡ý*ôË-.Ö̹·¶H‹ÇhÆMi(¤É”Ýô9Itã½WÚ²F†SŽsWmô[hÐ2¨Ã]:À{öö§ˆ0F«r]‰ÔÅÓ4«{7wŠ5F“ýcÖ´Ò ÓŒÕã§µ?a, ©nàG]‡JcãZ’4ãÖ¤UñHdANp;{SÄhì2@⤠=ø¥Ó€‹hhZ|€ç¤F:sÚžãØ@£t§Æ3ÍK³häsÊ™ƒéÅ-E±ORm˜í,¹VtK`Ïò‚p}ë¨Õ@äçŒ{×'®Æ¯dêëzãóýk)«š§¡æ8q<Рw8ÚÄtÈÿëëþ5lmä;Fzû æ>$Ðø"Ê7ÎÒÈAÎÏjvå¤ ûäÿ®WF3´»š9¡"óý+¤–äÝ]3‘œœãçÞ ¿2A ©B(PG^ßÐW ék•þ/Ò·kš)³?´ìL‡¢·=3Ve¶Wˆ,ŠK‘ŽÞõbT¸% ÷«¯nL[” Ý@õö¬ä•…wsÇ|Mgo¬M$êd´óABxã?àzµ Q¦ÅenÄDÐï GÜ'/çY^8ÓfÕ4Ò¶à«XcžkÁ×:&»mìL‹3ù»ç¿þ;üè¡všìµ=XÀ¦šÐm (t5l.CÅ8ªô^Oj…"lsº®ƒ ä!FIôéR麥£¨x“ë[¡O §áO™ì X«>XùW·ñSy`ô©9â—iÇLTŒ„G´ŒŠz *x©vv&£°õ¢ìZ¢Šݧ…ÛÓ¯ó§=9§èAçÚXÐÆJP˜Àæ·¿9ïO^ÜUl"/#ÏÒ—É\аÎqŠpRsž(@@±de»þt¾^aíá3ïOüÝsOÔz‚ñÓŠtQsÔõ©¼¼c§Z!&‹ŠÂÐSÀ;±Å9mÉ✋œqøPÀ :šxôÍ(àR9äqEî*En{SN‚œ*î4‰PóƒÏãNÈ'%†=sUÅÔC£.G¸¦ý¦7æíÈÿirÉ‘úÆž®~•@Ê1Í8IoZ{ Ô¾e*'˜·lUC'>´†FÀè°%9ûÆJÝ€ÅWÝÎ8©ŽI#ó¡0ryàÓÄ€¯"  Aöô¦³1øÐ&Ë;×wnh,¡ºg ªÈã‚ÀãÒ»$ð)‚',O'è*HägëTÉ*Ûx§=88ýiXf€`=µ '9ÕA'qß°4ï0`zš`L\g£20éÒ˜_8ù”ÿJ`ls‘@nÄ`ÓsþÕ ÏáúÓsŽ0*Bh~sß'Þ“p ŒóL94½»S Çnç;†GjBÇÆÈ©Ä‚£4„lb˜A®ií‚2p ^22}(»zý*ãÒ¦až™ÔÑÇZ€ŒŒQ´…ö1L·'@\õã4&Œº'­p¼={«éöÐéã3%ÄrdŽ^–€”¡úô‰x  ÇŽÕˆÓc•Ï>´Õœ“ÁÀ5)‹C¢K•¹Èö©ãpãÎÇ!Wp ëšÒ±›s`ž§¹©nÚŽÆš ñOU8É^(@6ûÓÇšwÜ œP’Aâž3ÔŒQG¡hBqõì ¹ëéKÆE8 £8ÍR`0è@¥ 9À§c4åc#­ƪô§*Òã°Æiû^´î8À šQ€0zÓÀ9ç$Ã@QëÓµ*Œ¶@

        ‚ŸƒœŒ ö§q] ŒŽ<XÅ0M(Åßµ"„ µ÷sÛ4¹Å(|6qQHØáB†Ë.ÄÉÇN3YÓêdnŸNõSÆú=&i´ðáW(ðÿë×”iÞ(º>"ŽûRIí£·Ü­ _¾}zò*¹ek M^×;­{Å6Úf¥o “*Ç,›±<Ž*üš°ÂHˆžõã3¿ÞDÒ¼· ÷Òü=²ÕõB/¶4gw÷<ÔZOR—*Üö I ˆ¯Àð«‰Z»Ó¢ût©sÓ·Ö­ì?$.i dŽi:ŽH¤Ï8çÚ˜åo›’>¹©VLG§5Q˜Žxÿ D”«c×Ö†Æi)ÈÈÏÔS$F:ç¥Co2îÁ ~*Ì…2¬§4&.d@[¤WSÁÀªÅ†O?…"Ì|SeدQÍÆ '°ªÒ?Ëšt,Yy\,‹±¿b4ì稨£#ïüéêx9ëÚl8œ·oñ¤ÜØŒ~´˜87­82í9Áÿd9ÆyÅ óN'Œ f š.VÀ@¤Ç d~4þxâ“Ç\–„0}hÆÀ¥ãÒŒ˜ h=‡^”}±ŽÂžO„• ðhì0r)幩 ô¥UÀ 4’¥%€©îíŠpN8¤nüév ö©R0§ÔúÓö€:sëL=JÅ9ãÖ]¤ Ôì?•D˸Õ»Ð= îpÇÖ«m$ŽÿJ»åç·zAÜJVRšÄH#œS’CW$P}{S¡§qì¥).K€r0h z~T®"䜃ڻŽq‘R“Œb—nùº{QtL úÒ„'…ãšž4éOÊ€T`tüiÜzü§Èè8ïÞš-Éa–ï×*Ò¸ÎÒ@¦³òryÇJ.}Ý’ÍÆc×µ*)lœæ§Aã¹ý).àõØË×´Énïí®-çû7—Ügpô5Å ½û?ÊŒ«zŒõãÒºËÖX¢òçô®7Åö uhn­€ÞŸ0ÁÁ9íY¶ï¡] #)'‘íJ'ùvdcÚ¨4Är3QÞ“ÎyÎ;b²½Éf¤Sà‘Åjéòî8èk–ŠŒ0sÞµ4»è̪K`8Ï&‰]"¢îwPá¢Sí͇šRxÈ=)ã>”›»/ gÞ\y.³ôëéZ/ËW7ã8'k<Õ N¾ÔÓ¸´-®¹·y|Õq TçýzšÛ_ŠæÅ&ŽLo8 ÃOzùîÃZÖµ¨õ Ý ½ÅÅÂFØ8*O—|ûW¢xð^éúF‹¥D¤Êc\uñÕnßDá(½JI4z…½Áš0H!›žEWº¹û>ÝÇ Üþ_MviƒÜëÓwýwL—SÒ䵆CÌÆÉ8öæ”%}«b»Ž]¦2¥X…^G&´Ö6Eù:ŒV_„´ì [Ù¾Ù{ò»’Uö\ò+Uf2¸N5¦ˆ›²h°GLb¤É ÀÇ9Í5¹Ç8¥ÁíÇ­b€ ‚99§„ÏçH‹ÎzŠzŒçgé‚w< qÆõ§c#Ö“nzñë@ UϘϿ¥J«òð ôõ¥T‘Ž;Ð&D('·Nø©B€iÁ29=¨b#ÆqéM#§3þ4áÅ܈&G·ÖŸåà ‘Wiæžq´ã·­Dã4˜QƒšsxœTlq~”‚ËŒæšî¾¢¢rúÔm'{SµÂ㳜ҀÏLÓÕp¾™£…$f•¬ ±1€*7U ‘׸§3Œq¡bHëH˜ÖÎAüø¦n£µHAîsJ¨29§ ?!€§©4›Njm¸ç'éLlŽ{Š.; ÀÛÀɤR6Œ÷¤$žÀ¦;1] ô¢ã$i6¶±¨B{â”#?Jdœ;â‹ 2ý*7—’÷ëHíPI"àã­Kc¥éQ¼£<~5Äc†éU¤ç•4¶˜®s‚=ê¹Ï·Õ¸üª¬²ÝsøÕy%Ëü§ZC²'’äàŒŒUi¦×>µ]å žFj|žëE®Mí±#]Á¨²H È@P[©'Wc$° ‚+:+h®&Þ0ÏÊg±õ­d´rêÛXçעб#n>æX㯭`ê–[‘ŠÆS¨ ù×O${WÜVDš„úK D¦àäaO#½e-eÔãU¤C‘OµJŽÃ†äSWÓÏåÁÿ Å ¸Í…›’^ÓbÛp„g¨ªÛrqØV†‘»íKŒcŠMèRz;(üÃɦ['ŒŒTp#}ž!ÏAü…J±“Ó¥c›w>¸§«|£›ÆGª0ìc¨­Z! Ý×»¦áH('+þµ \ÒŒïb˜ ƒJ c"…aê@àw¥ÎÆ™ÔzpSèhÐqéíBôíH8<Òðx&„Æ… ô¥Š`éÒžG‡õªÐvëKœSÓ¹>ô˜ ÎÞô1ãùR2àP9šA`8Îx c¹£ŸÎ€œ“žJÀFj6ŒN-“ž†Ÿ·äÈ4!X‡™®™e&u|¨šwÐ^¥™Ù~‡Þ±”ÆŠw3†Hã§J¯%öѵYX·æ?Z¿-ºÊ…X=ÅUm&)Knzp?J¥a\’Ût«¹G¾=jÊ!ÇOÒ¥ŽU ¼0*UAŒRm ä )vã‚;Õ¤Œp(òÁíŸj4B‰AÐ QÜäçð«žWži<¡ŽiŒ€/$iJôÍLŒâ•P>\,^¥bn¡u Œg5äÞ1ø{¬^Þ—µPê#/Œ~uíäÎ˜Š¦] €Ãœ{UÂ| qofx®‰ð«Ss%ÚC9û­×ó®ß@øy¤i®'tóç?3‹Ÿ¦k¸ ¾” Çn¢´ußDœÝ‘ÚÄ"D@BŽŒ p¥4¥È"²r¾å¡ùǧJ‰éB䱩@=Ÿ‚1N ÄtíÆipiÝ0ÕŽÏ Ro©çÚ«¸nØëøÑ`i’´À¶÷¨üìÔ{°>´á ž¹¢Â’@Çôy Œu¨7oçR‚1Çÿª”cÓ#ØÓ„ÈÎ}jPF Ï‘Ÿ#·8(¸$ DQŽô›ˆ‘œ{gµDÒç$cÖÇ3wúTeøb›¿>£©¥—=iZÀÅ$}hÜuÂç "›»Œç¥0[£õ r c¥G»=zúÑ»?…!!XŒ|¼Ó6ò48SÒ˜H-œæ‚†±ù£vz{R7ƒšn}ê„8¶p*9øy }@¦î=x÷¤iíÏqíY·vYCÀ>õ´ÄœõéQ:† }{Ñe`¹Ãx…$‚pvÀIœŠá.üT>d¶ˆ±ÝÌ•{%å•Yq׃žõä3ðœúVµöø#y,¥ÿZƒªœT(&õؤô {½Ná–áHB¸;F9à×£éQIk¤ÚÚË&÷Š0¥ýxÃi—6ö¶ãËPª£0àÿvz5Ôwzl2Dᶨ¡àC[7¹bˆJú¶]sïš­;8]ÀqžÕ8p*”ÈÀ¬Çkœ˜Àü(ÝÞš¸#ï rŒ`Ž•Ï°·$ÏËÇ>õwJ|\¦;‡z YKqŸz·¦Iþ”¹|ÃùÒ²h#¹ê'‘°ç gòZŸzäœÖMÉk–àcéNk’{òxÀéSK©RF‰œt½/š;šÊiÉ=G«1 òâµBÔÓƒNßéÒ²~ÐÜdŒ­8\ú?»\ MÊzqZ7T~‡v”N)h´àÉç­8äcŠ‚9Gp©É÷ïB0Éàc¥=Gî;ÓYÇ­JèxlHCé}éU@&•W=ð=iê0¹Æi]X¡Î=:S”nÁéNÚ3Ó­è3M4!0=8§0p1ëCG"‚qùQ£@Çjr.O¹æ˜­Î)À¼ A¨Ï$ r¨`#ÅGæÎìŠw˜Š«ˆ•G8Å(#õ¨KàŒÆ‘e†'½+ÜveŽ1œž(i\ŸÌUF—œŒÿ…A#¹nÿ;\ ßh@öɨÊõäf©s»–â—°;fƒæ^[”àg¹/š¸ÎwgÚ¨ÈÅMØ$qE†YqÈ Ž¼f¢Eln#Šr©+×½ Z’ `~4Ï4è}éNO§zCÆ0:RÐV$ ŸÄP’dõǽ4!n´ªœŠ« x {Ô„c¨×¯*FirzqíG¨‰IÇZMÙúT`œ}ÓøÑƒô  >RBOéK¸•Lþ”àp¼Ï9 c€JRzS cÓ½ Nqų~xS€†Š_Ž J@Ý)DxïžhÚ:qͰÖ'zÒœGâžØRAëHÄØRM!+#$`MÃiÀ5 1> >> endobj 2 0 obj << /Type /Pages /Count 2 /Kids [ 6 0 R 11 0 R ] /MediaBox [ 0 0 612 792 ] /Resources 3 0 R >> endobj 3 0 obj << /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> endobj 4 0 obj << /Producer (PDF::Builder 3.024 [see https://github.com/PhilterPaper/Perl-PDF-Builder/blob/master/INFO/SUPPORT]) >> endobj 5 0 obj << /Type /Font /Subtype /Type1 /BaseFont /Helvetica-Bold /Encoding << /Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences [ 0 /.notdef /acute /caron /circumflex /dieresis /grave /macron /ring /tilde /breve /ogonek /dotaccent /hungarumlaut /cedilla /dblgravecmb /controlSI /controlDLE /controlDC1 /controlDC2 /controlDC3 /controlDC4 /controlNAK /controlSYN /controlETB /controlCAN /controlEM /controlSUB /controlESC /controlFS /controlGS /dotlessi /dotlessj /space /exclam /quotedbl /numbersign /dollar /percent /ampersand /quotesingle /parenleft /parenright /asterisk /plus /comma /hyphen /period /slash /zero /one /two /three /four /five /six /seven /eight /nine /colon /semicolon /less /equal /greater /question /at /A /B /C /D /E /F /G /H /I /J /K /L /M /N /O /P /Q /R /S /T /U /V /W /X /Y /Z /bracketleft /backslash /bracketright /asciicircum /underscore /grave /a /b /c /d /e /f /g /h /i /j /k /l /m /n /o /p /q /r /s /t /u /v /w /x /y /z /braceleft /bar /braceright /asciitilde /controlDEL /Euro /bullet /quotesinglbase /florin /quotedblbase /ellipsis /dagger /daggerdbl /circumflex /perthousand /Scaron /guilsinglleft /OE /bullet /Zcaron /bullet /bullet /quoteleft /quoteright /quotedblleft /quotedblright /bullet /endash /emdash /tilde /trademark /scaron /guilsinglright /oe /bullet /zcaron /Ydieresis /space /exclamdown /cent /sterling /currency /yen /brokenbar /section /dieresis /copyright /ordfeminine /guillemotleft /logicalnot /hyphen /registered /macron /degree /plusminus /twosuperior /threesuperior /acute /mu /paragraph /periodcentered /cedilla /onesuperior /ordmasculine /guillemotright /onequarter /onehalf /threequarters /questiondown /Agrave /Aacute /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla /Egrave /Eacute /Ecircumflex /Edieresis /Igrave /Iacute /Icircumflex /Idieresis /Eth /Ntilde /Ograve /Oacute /Ocircumflex /Otilde /Odieresis /multiply /Oslash /Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn /germandbls /agrave /aacute /acircumflex /atilde /adieresis /aring /ae /ccedilla /egrave /eacute /ecircumflex /edieresis /igrave /iacute /icircumflex /idieresis /eth /ntilde /ograve /oacute /ocircumflex /otilde /odieresis /divide /oslash /ugrave /uacute /ucircumflex /udieresis /yacute /thorn /ydieresis ] >> /FirstChar 32 /LastChar 255 /Name /HeBoCBA /Widths [ 278 333 474 556 556 889 722 238 333 333 389 584 278 333 278 278 556 556 556 556 556 556 556 556 556 556 333 333 584 584 584 611 975 722 722 722 722 667 611 778 722 278 556 722 611 833 722 778 667 778 722 667 611 722 667 944 667 667 611 333 278 333 584 556 333 556 611 556 611 556 333 611 611 278 278 556 278 889 611 611 611 611 389 556 333 611 556 778 556 556 500 389 280 389 584 278 556 350 278 556 500 1000 556 556 333 1000 667 333 1000 350 611 350 350 278 278 500 500 350 556 1000 333 1000 556 333 944 350 500 667 278 333 556 556 556 556 280 556 333 737 370 556 584 333 737 552 400 548 333 333 333 611 556 278 333 333 365 556 834 834 834 611 722 722 722 722 722 722 1000 722 667 667 667 667 278 278 278 278 722 722 778 778 778 778 778 584 778 722 722 722 722 667 667 611 556 556 556 556 556 556 889 556 556 556 556 556 278 278 278 278 611 611 611 611 611 611 611 548 611 611 611 611 611 556 611 556 ] >> endobj 6 0 obj << /Type /Page /Annots [ 9 0 R 10 0 R ] /Contents [ 7 0 R 8 0 R ] /MediaBox [ 0 0 595 842 ] /Parent 2 0 R /Resources << /Font << /HeBoCBA 5 0 R >> /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> >> endobj 7 0 obj << /Length 504 >> stream 0.8 0.8 0.8 RG 10 10 m 510 10 l 10 60 m 510 60 l 10 110 m 510 110 l 10 160 m 510 160 l 10 210 m 510 210 l 10 260 m 510 260 l 10 310 m 510 310 l 10 360 m 510 360 l 10 410 m 510 410 l 10 460 m 510 460 l 10 510 m 510 510 l 10 560 m 510 560 l 10 610 m 510 610 l 10 660 m 510 660 l 10 710 m 510 710 l 10 10 m 10 710 l 60 10 m 60 710 l 110 10 m 110 710 l 160 10 m 160 710 l 210 10 m 210 710 l 260 10 m 260 710 l 310 10 m 310 710 l 360 10 m 360 710 l 410 10 m 410 710 l 460 10 m 460 710 l 510 10 m 510 710 l S endstream endobj 8 0 obj << /Length 2690 >> stream BT ET q BT 1 0 0 1 50 750 Tm 1 0 0 rg /HeBoCBA 20 Tf (Hello World!) Tj ET Q BT 100 Tz 1 0 0 1 0 0 Tm 0 g 0 G ET q BT 1 0 0 1 520 8 Tm /HeBoCBA 10 Tf (0) Tj ET Q BT 100 Tz 1 0 0 1 0 0 Tm 0 g 0 G ET q BT 1 0 0 1 520 58 Tm /HeBoCBA 10 Tf (50) Tj ET Q BT 100 Tz 1 0 0 1 0 0 Tm 0 g 0 G ET q BT 1 0 0 1 520 108 Tm /HeBoCBA 10 Tf (100) Tj ET Q BT 100 Tz 1 0 0 1 0 0 Tm 0 g 0 G ET q BT 1 0 0 1 520 158 Tm /HeBoCBA 10 Tf (150) Tj ET Q BT 100 Tz 1 0 0 1 0 0 Tm 0 g 0 G ET q BT 1 0 0 1 520 208 Tm /HeBoCBA 10 Tf (200) Tj ET Q BT 100 Tz 1 0 0 1 0 0 Tm 0 g 0 G ET q BT 1 0 0 1 520 258 Tm /HeBoCBA 10 Tf (250) Tj ET Q BT 100 Tz 1 0 0 1 0 0 Tm 0 g 0 G ET q BT 1 0 0 1 520 308 Tm /HeBoCBA 10 Tf (300) Tj ET Q BT 100 Tz 1 0 0 1 0 0 Tm 0 g 0 G ET q BT 1 0 0 1 520 358 Tm /HeBoCBA 10 Tf (350) Tj ET Q BT 100 Tz 1 0 0 1 0 0 Tm 0 g 0 G ET q BT 1 0 0 1 520 408 Tm /HeBoCBA 10 Tf (400) Tj ET Q BT 100 Tz 1 0 0 1 0 0 Tm 0 g 0 G ET q BT 1 0 0 1 520 458 Tm /HeBoCBA 10 Tf (450) Tj ET Q BT 100 Tz 1 0 0 1 0 0 Tm 0 g 0 G ET q BT 1 0 0 1 520 508 Tm /HeBoCBA 10 Tf (500) Tj ET Q BT 100 Tz 1 0 0 1 0 0 Tm 0 g 0 G ET q BT 1 0 0 1 520 558 Tm /HeBoCBA 10 Tf (550) Tj ET Q BT 100 Tz 1 0 0 1 0 0 Tm 0 g 0 G ET q BT 1 0 0 1 520 608 Tm /HeBoCBA 10 Tf (600) Tj ET Q BT 100 Tz 1 0 0 1 0 0 Tm 0 g 0 G ET q BT 1 0 0 1 520 658 Tm /HeBoCBA 10 Tf (650) Tj ET Q BT 100 Tz 1 0 0 1 0 0 Tm 0 g 0 G ET q BT 1 0 0 1 520 708 Tm /HeBoCBA 10 Tf (700) Tj ET Q BT 100 Tz 1 0 0 1 0 0 Tm 0 g 0 G ET q BT 1 0 0 1 8 720 Tm /HeBoCBA 10 Tf (0) Tj ET Q BT 100 Tz 1 0 0 1 0 0 Tm 0 g 0 G ET q BT 1 0 0 1 58 720 Tm /HeBoCBA 10 Tf (50) Tj ET Q BT 100 Tz 1 0 0 1 0 0 Tm 0 g 0 G ET q BT 1 0 0 1 108 720 Tm /HeBoCBA 10 Tf (100) Tj ET Q BT 100 Tz 1 0 0 1 0 0 Tm 0 g 0 G ET q BT 1 0 0 1 158 720 Tm /HeBoCBA 10 Tf (150) Tj ET Q BT 100 Tz 1 0 0 1 0 0 Tm 0 g 0 G ET q BT 1 0 0 1 208 720 Tm /HeBoCBA 10 Tf (200) Tj ET Q BT 100 Tz 1 0 0 1 0 0 Tm 0 g 0 G ET q BT 1 0 0 1 258 720 Tm /HeBoCBA 10 Tf (250) Tj ET Q BT 100 Tz 1 0 0 1 0 0 Tm 0 g 0 G ET q BT 1 0 0 1 308 720 Tm /HeBoCBA 10 Tf (300) Tj ET Q BT 100 Tz 1 0 0 1 0 0 Tm 0 g 0 G ET q BT 1 0 0 1 358 720 Tm /HeBoCBA 10 Tf (350) Tj ET Q BT 100 Tz 1 0 0 1 0 0 Tm 0 g 0 G ET q BT 1 0 0 1 408 720 Tm /HeBoCBA 10 Tf (400) Tj ET Q BT 100 Tz 1 0 0 1 0 0 Tm 0 g 0 G ET q BT 1 0 0 1 458 720 Tm /HeBoCBA 10 Tf (450) Tj ET Q BT 100 Tz 1 0 0 1 0 0 Tm 0 g 0 G ET q BT 1 0 0 1 508 720 Tm /HeBoCBA 10 Tf (500) Tj ET Q BT 100 Tz 1 0 0 1 0 0 Tm 0 g 0 G ET endstream endobj 9 0 obj << /Type /Annot /Subtype /Text /Border [ 0 0 0 ] /C [ 0.8 ] /Contents (This is an initially open note.\nnext line) /Name /Key /Open true /Rect [ 60 10 160 110 ] >> endobj 10 0 obj << /Type /Annot /Subtype /Text /Border [ 0 0 0 ] /C [ 0.3 ] /CA 0.75 /Contents (This is an initially closed note) /Rect [ 210 110 310 210 ] /T (Closed for the day!) >> endobj 11 0 obj << /Type /Page /Annots [ 13 0 R 14 0 R 15 0 R 16 0 R ] /Contents [ 12 0 R ] /MediaBox [ 0 0 595 842 ] /Parent 2 0 R /Resources << /Font << /HeBoCBA 5 0 R >> /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> >> endobj 12 0 obj << /Length 952 >> stream BT /HeBoCBA 20 Tf 26 TL 1 0 0 1 75 700 Tm (Sed ut perspiciatis, unde omnis) Tj T* (iste natus error sit voluptatem) Tj T* (accusantium doloremque laudantium,) Tj T* (totam rem aperiam eaque ipsa,) Tj T* (quae ab illo inventore veritatis) Tj T* (et quasi architecto beatae vitae) Tj T* (dicta sunt, explicabo. Nemo) Tj T* (enim ipsam voluptatem, quia) Tj T* (voluptas sit, aspernatur aut) Tj T* (odit aut fugit, sed quia consequuntur) Tj T* (magni dolores eos, qui ratione) Tj T* (dolor sit, voluptatem sequi) Tj T* (nesciunt, neque porro quisquam) Tj T* (est, qui dolorem ipsum, quia) Tj T* (amet, consectetur, adipisci) Tj T* (velit, sed quia non numquam) Tj T* (eius modi tempora incidunt,) Tj T* (ut labore et dolore magnam) Tj T* (aliquam quaerat voluptatem.) Tj T* (Ut enim ad minima veniam,) Tj T* (quis nostrum exercitationem) Tj T* (ullam corporis suscipit laboriosam,) Tj T* (nisi ut aliquid ex ea commodi) Tj T* (consequatur?) Tj T* ET endstream endobj 13 0 obj << /Type /Annot /Subtype /Highlight /C [ 1 0.82 0 ] /Contents (This has a highlighter effect.) /QuadPoints [ 115 693 221 693 115 670 221 670 ] /Rect [ 114.5 669.5 221.5 693.5 ] >> endobj 14 0 obj << /Type /Annot /Subtype /Squiggly /C [ 0 0 1 ] /Contents (This uses a squiggly line.) /QuadPoints [ 75 537 298 537 75 514 298 514 ] /Rect [ 74.5 513.5 298.5 537.5 ] >> endobj 15 0 obj << /Type /Annot /Subtype /Underline /C [ 0 1 0 ] /Contents (This uses an underline spanning two lines.) /QuadPoints [ 277 433 330 433 277 410 330 410 75 407 157 407 75 384 157 384 ] /Rect [ 276.5 409.5 330.5 433.5 ] /T (Some title text) >> endobj 16 0 obj << /Type /Annot /Subtype /StrikeOut /C [ 0.5 ] /CA 0.5 /Contents (This uses a strikeout spanning three lines.) /QuadPoints [ 257 329 350 329 257 306 350 306 75 303 340 303 75 280 340 280 75 277 338 277 75 254 338 254 ] /Rect [ 256.5 305.5 350.5 329.5 ] >> endobj xref 0 17 0000000000 65535 f 0000000015 00000 n 0000000164 00000 n 0000000273 00000 n 0000000342 00000 n 0000000474 00000 n 0000003705 00000 n 0000003921 00000 n 0000004476 00000 n 0000007218 00000 n 0000007397 00000 n 0000007581 00000 n 0000007808 00000 n 0000008812 00000 n 0000009008 00000 n 0000009193 00000 n 0000009449 00000 n trailer << /Info 4 0 R /Root 1 0 R /Size 17 >> startxref 9721 %%EOF PDF-Builder-3.026/examples/resources/pod2htmd.temp0000644000000000000000000000000314534467462020467 0ustar rootroot . PDF-Builder-3.026/examples/055_outlines0000644000000000000000000000145314534467462016235 0ustar rootroot# take a PDF of at least 11 pages, and add outlines (bookmarks) for pages # 1 ("i"), 4 ("1"), and 11 ("7") physical pages. # (after "futuramedium"'s demo and fix for RT 121912 [and RT 41971]) use strict; use warnings; use PDF::Builder; my $infile = 'examples/resources/sample_55.pdf'; my $outfile = 'examples/055_outlines.sample_55.pdf'; my $doc = PDF::Builder-> open($infile); print "Use 'outline' or 'bookmark' feature on your PDF Reader to move around\n"; $doc-> outlines -> outline -> dest( $doc-> openpage( 1 )) -> title( '1st page (i)' ); $doc-> outlines -> outline -> dest( $doc-> openpage( 4 )) -> title( '4th page (1)' ); $doc-> outlines -> outline -> dest( $doc-> openpage( 11 )) -> title( '11th page (7)' ); $doc->saveas($outfile); PDF-Builder-3.026/examples/050_pagelabels0000644000000000000000000001426614534467462016473 0ustar rootroot#!/usr/bin/perl use strict; use warnings; use lib '../lib'; use PDF::Builder; use PDF::Builder::Util; #my $compress = 'none'; # uncompressed streams my $compress = 'flate'; # compressed streams my $section_length = 32; # examples per old and new methods my @labels = ( # new method page_labels() 'upper case Roman numeral I', 'upper case Roman numeral II', 'upper case Roman numeral III', 'upper case Roman numeral IV', 'decimal (Arabic) number 1', 'decimal (Arabic) number 2', 'decimal (Arabic) number 3', 'decimal (Arabic) number 4', 'decimal (Arabic) number 5', 'decimal (Arabic) number 6', 'decimal (Arabic) number 7', 'decimal (Arabic) number 8', 'decimal (Arabic) number 9', 'decimal (Arabic) number 10', 'prefixed A-1', 'prefixed A-2', 'prefixed B-1', 'prefixed B-2', 'prefixed C-1', 'prefixed C-2', 'decimal (Arabic) number 11', 'decimal (Arabic) number 12', 'upper case letter A', 'upper case letter B', 'lower case Roman numeral i', 'lower case Roman numeral ii', 'no counter (blank)', 'no counter (blank)', 'prefix, no counter Z', 'prefix, no counter Z', 'prefix, uc Roman Index I', 'prefix, uc Roman Index II', # old method pageLabel() 'upper case Roman numeral I', 'upper case Roman numeral II', 'upper case Roman numeral III', 'upper case Roman numeral IV', 'decimal (Arabic) number 1', 'decimal (Arabic) number 2', 'decimal (Arabic) number 3', 'decimal (Arabic) number 4', 'decimal (Arabic) number 5', 'decimal (Arabic) number 6', 'decimal (Arabic) number 7', 'decimal (Arabic) number 8', 'decimal (Arabic) number 9', 'decimal (Arabic) number 10', 'prefixed A-1', 'prefixed A-2', 'prefixed B-1', 'prefixed B-2', 'prefixed C-1', 'prefixed C-2', 'decimal (Arabic) number 11', 'decimal (Arabic) number 12', 'upper case letter A', 'upper case letter B', 'lower case Roman numeral i', 'lower case Roman numeral ii', 'no counter (blank)', 'no counter (blank)', 'prefix, no counter Z', 'prefix, no counter Z', 'prefix, uc Roman Index I', 'prefix, uc Roman Index II', # extra: these two styles (4 pages) combined one call, pageLabel only 'lower case letter c', 'lower case letter d', 'lc Roman and prefixed App-iv', 'lc Roman and prefixed App-v', ); my $pdf = PDF::Builder->new(-compress => $compress); my $f1=$pdf->corefont('Helvetica', -encode=>'latin1'); # unused? my $f2=$pdf->corefont('Helvetica-Bold', -encode=>'latin1'); # "Page Index=" text # initial pass, create 2 x $section_length-1 pages labeled # "Page Index=n" for n=0-$section_length # extra pages for pageLabel combined -1 -> +3 foreach my $i (0 .. 2*$section_length+3) { my $page = $pdf->page(); $page->mediabox(595,842); my $text=$page->text(); $text->textlabel(40,700, $f2, 20, 'Page Index='.$i.', Physical Page='.($i+1)); $text->textlabel(40,670, $f2, 20, 'thumbnail label should be '.$labels[$i]); } # modify page numbering /Catalog /PageLabels entries # note that each style change resets page to 1 # this number NOT on printed page... only in reader thumbnail # and possibly the reader's display page # ---------- NEW method using page_labels() # pages 1..4 should be Upper Case Roman (I..IV) $pdf->page_labels(1, -style => 'Roman' ); # << /S /R >> default St 1 # pages 5..14 s/b decimal, restart at 1 (1..10) $pdf->page_labels(5, -start => 1 ); # << /S /D /St 1 >> # pages 15..16 s/b A-decimal, restart at 1 (A-1, A-2) $pdf->page_labels(15, -start => 1, -prefix => 'A-' ); # << /P (A-) /S /D /St 1 >> # pages 17..18 s/b B-1, B-2 $pdf->page_labels(17, -start => 1, -prefix => 'B-' ); # << /P (B-) /S /D /St 1 >> # pages 19..20 s/b C-1, C-2 $pdf->page_labels(19, -start => 1, -prefix => 'C-' ); # << /P (C-) /S /D /St 1 >> # pages 21..22 s/b decimal, restart at 11 (11..12) $pdf->page_labels(21, -start => 11 ); # << /S /D /St 11 >> # pages 23..24 s/b Alpha, auto-restarts at 1 (A, B) $pdf->page_labels(23, -style => 'Alpha' ); # << /S /A >> # pages 25..26 s/b lowercase roman, auto-restarts at 1 (i, ii) $pdf->page_labels(25, -style => 'roman' ); # << /S /r >> # pages 27..28 s/b blank (nocounter) $pdf->page_labels(27, -style => 'nocounter' ); # pages 29..30 s/b blank (nocounter) with Z prefix $pdf->page_labels(29, -style => 'nocounter', -prefix => 'Z' ); # pages 31..32 s/b prefix Index plus UC Roman $pdf->page_labels(31, style => 'Roman', prefix => 'Index ' ); # ---------- OLD method using pageLabel() # pages $section_length+0..3 should be Upper Case Roman (I..IV) $pdf->pageLabel($section_length+0, { -style => 'Roman' }); # << /S /R >> default St 1 # pages $section_length+4..13 s/b decimal, restart at 1 (1..10) $pdf->pageLabel($section_length+4, { -start => 1 }); # << /S /D /St 1 >> # pages $section_length+14..15 s/b A-decimal, restart at 1 (A-1, A-2) $pdf->pageLabel($section_length+14, { -start => 1, -prefix => 'A-' }); # << /P (A-) /S /D /St 1 >> # pages $section_length+16..17 s/b B-1, B-2 $pdf->pageLabel($section_length+16, { -start => 1, -prefix => 'B-' }); # << /P (B-) /S /D /St 1 >> # pages $section_length+18..19 s/b C-1, C-2 $pdf->pageLabel($section_length+18, { -start => 1, -prefix => 'C-' }); # << /P (C-) /S /D /St 1 >> # pages $section_length+20..21 s/b decimal, restart at 11 (10..11) $pdf->pageLabel($section_length+20, { -start => 11 }); # << /S /D /St 11 >> # pages $section_length+22..23 s/b Alpha, auto-restarts at 1 (A, B) $pdf->pageLabel($section_length+22, { -style => 'Alpha' }); # << /S /A >> # pages $section_length+24..25 s/b lowercase roman, auto-restarts at 1 (i, ii) $pdf->pageLabel($section_length+24, { -style => 'roman' }); # << /S /r >> # pages $section_length+26..27 s/b blank (nocounter) $pdf->pageLabel($section_length+26, { -style => 'nocounter' }); # pages $section_length+28..29 s/b blank (nocounter) with Z prefix $pdf->pageLabel($section_length+28, { -style => 'nocounter', -prefix => 'Z' }); # pages $section_length+30..31 s/b prefix Index plus UC Roman $pdf->pageLabel($section_length+30, { 'style' => 'Roman', 'prefix' => 'Index ' }); # ------------- # combine two calls into one for pageLabel only! $pdf->pageLabel($section_length+32, { style => 'alpha', start => 3 }, $section_length+34, { style => 'roman', start => 4, prefix => 'App-' }); # ------------- $pdf->saveas("$0.pdf"); $pdf->end(); exit; __END__ PDF-Builder-3.026/examples/ShowFont.pl0000644000000000000000000002700114534467462016160 0ustar rootroot#!/usr/bin/perl # list a font file's contents # outputs ShowFont...pdf # run without arguments to get help listing # author: Phil M Perry use strict; use warnings; our $VERSION = '3.026'; # VERSION our $LAST_UPDATE = '3.021'; # manually update whenever code is changed use PDF::Builder; use Encode; use utf8; # loaded encodings, and all possible encodings my @list = Encode->encodings(); my @list_all = Encode->encodings(':all'); # default encodings to show if no -e given my @encodings = qw( latin1 latin2 latin3 latin4 latin5 latin6 latin7 latin8 latin9 latin10 utf8 ); # minimum one arg (font name) if ($#ARGV < 0) { usage(); exit(1); } my $type = 'corefont'; # default for -t my $fontfile = ''; # required (last argument) my $fontname = ''; # derived from $fontfile my @encode_list = @encodings; # optional list (-e) my $from = 0; # default start value for UTF-8 (-r) my $to = 0x3FF; # default end value for UTF-8 (-r) my $extra = "ShowFont"; my $T1metrics = ''; # no default my ($f, $i,$j, $page, $text, $grfx); my $pdf = PDF::Builder->new(-compress => 'none'); my $title_font = $pdf->corefont('Helvetica'); my $grid_font = $pdf->corefont('Helvetica-Bold'); #my %infohash = $pdf->info( # 'Creator' => "ShowFont.pl", # 'Producer' => "PDF::Builder is the gr8st"); # go through argument list foreach ($i=0; $icorefont($fontname, -encode => $encode); @planes = ($cur_font, $cur_font->automap()); # 1 or more planes each 256 } elsif ($type eq 'type1') { if ($T1metrics =~ m/\.afm$/i) { $cur_font = $pdf->psfont($fontfile, -encode => $encode, -afmfile => $T1metrics); } else { $cur_font = $pdf->psfont($fontfile, -encode => $encode, -pfmfile => $T1metrics); } @planes = ($cur_font, $cur_font->automap()); # 1 or more planes each 256 } else { # truetype/opentype $cur_font = $pdf->ttfont($fontname, -encode => $encode); @planes = ($cur_font); # automap() not available } for ($plane=0; $plane 0) { my $flag = 0; # no character found yet foreach my $y (0..15) { foreach my $x (0..15) { my $ci = $y*16 + $x; # 0..255 value if ($ci==32 || $ci==33) { next; } # always something there if (defined $planes[$plane]->uniByEnc($ci) && $planes[$plane]->uniByEnc($ci) > 0) { $flag = 1; last; } } if ($flag) { last; } } if (!$flag) { next; } # no characters in this plane } for ($cur_page = 1; $cur_page <= $num_pages; $cur_page++) { my ($row, $col, $c_val, $c); newpage(); # create next page if ($multibyte || $plane == 0) { $page_start += 256; $page_end += 256; } # page and grid headings $text->font($title_font, 25); $text->translate(36,700); $text->text("Font: $fontname ($type)"); $text->font($title_font, 20); $text->translate(36,675); if ($num_pages > 1) { $text->text("Encoding: $encode (page $cur_page of $num_pages)"); } else { $text->text("Encoding: $encode"); } $text->translate(36, 650); $text->text("Plane ".($plane+1)." / ".($#planes+1)); $text->font($grid_font, 20); # label columns for ($i=0; $i<16; $i++) { $text->translate($x_list[$i],$y_list[0]+25); $text->text(sprintf("_%1X", $i)); } # label rows for ($j=0; $j<16; $j++) { $text->translate($x_list[0]-15,$y_list[$j]); $text->text_right(sprintf("%2X_", $page_start/16+$j)); } # the characters themselves, right-justified at x_list + 20 #$text->font($cur_font, 20); $text->font($planes[$plane], 20); for ($row = 0; $row < 16; $row++) { for ($col = 0; $col < 16; $col++) { $c_val = $page_start + (15-$row)*16 + $col; if ($c_val < $from || $c_val > $to) { next; } #if ($c_val < 32) { next; } # control characters if ($type eq 'corefont' && $planes[$plane]->wxMissingByEnc($c_val)) { $grfx->fillcolor(1.0, 0.7, 0.7); # for missing width $grfx->move($x_list[$col]+$x_offset, $y_list[15-$row]-2); $grfx->line($x_list[$col]+$x_offset, $y_list[15-$row]+18); $grfx->line($x_list[$col]+$x_offset+20, $y_list[15-$row]+18); $grfx->line($x_list[$col]+$x_offset+20, $y_list[15-$row]-2); $grfx->close(); $grfx->fill(); $grfx->fillcolor('black'); } # other font types get their widths from their files $text->translate($x_list[$col]+20, $y_list[15-$row]); # $c_val > x7F should be interpreted as either single byte # top half, or UTF-8 Latin-1 area $c = chr($c_val); if ($multibyte && $c_val >= 0x80 && $c_val <= 0xFF) { # for some reason, 80..FF in UTF-8 isn't handled correctly # perldoc.perl.org/functions/chr.html: # Note that characters from 128 to 255 (inclusive) are by # default internally not encoded as UTF-8 for backward # compatibility reasons. $c = Encode::decode('cp-1252', $c); } $text->text_right($c); } } } } } if ($type eq 'corefont') { $type = 'core'; } if ($type eq 'type1') { $type = 'T1'; } if ($type eq 'truetype') { $type = 'TTF'; } # can't use $encode here... no longer set $pdf->saveas("$outpath$extra.$type.$fontname.pdf"); $pdf->end(); sub usage { my $message = <<"EOF"; Usage: ShowFont [options] font-name Options: -t type type = one of corefont (default) truetype type1 (postscript) -e encoding encoding = one or more of latin1 latin2 latin3 latin4 latin5 latin6 latin7 latin8 latin9 latin10 utf8 There are other encodings possible (see listing of Loaded and All encodings) and many aliases and alternate spellings for a given encoding. The list given here is the default if -e is not given. utf8 is ignored for corefont and type1 -r from to This is for UTF-8 only, the start and end Unicode values to be listed, up to 256 per page (pages are xx00 through xxFF). The values may be given in decimal or hex (leading 'x'). The default is 00 through 3FF. Single byte encodings are x00 - xFF even if -r is given. -x extra name info This, if given, replaces "ShowFonts" as the first name field in the file name. It should be characters legal for a file name. -m T1 metrics file name This is required for Type1 files. It must be either an .afm or .pfm file that supplies metrics for the .pfa or .pfb glyph file. EOF print "\nLoaded encodings:\n"; foreach (@list) { print $_." "; } print "\n\nAll encodings:\n"; foreach (@list_all) { print $_." "; } print "\n$message"; return; } sub newpage { $page = $pdf->page(); #print "=== newpage. page=$page\n"; $page->mediabox('universal'); $grfx = $page->gfx(); # define first, so bg fill is under char fg $text = $page->text(); #print "=== newpage. text=$text\n"; return; } PDF-Builder-3.026/examples/020_textrise0000644000000000000000000001602614534467462016234 0ustar rootroot#!/usr/bin/perl use strict; use warnings; use PDF::Builder; use PDF::Builder::Util; #my $compress = 'none'; # no stream compression my $compress = 'flate'; # compressed stream my $pdf = PDF::Builder->new(-compress => $compress); my $f1=$pdf->corefont('Helvetica', -encode=>'latin1'); my $f2=$pdf->corefont('Helvetica-Oblique', -encode=>'latin1'); my $page = $pdf->page(); $page->mediabox(595,842); # A4 paper my $txt = $page->text(); my $grf = $page->gfx(); #$txt->font($f1, 20); my $fsize = 20; # our standard font size for this page my $subsupscl = 0.7; # scale factor for sub and superscripts $grf->strokecolor('green'); # just leave line color as green # rises (up +, down -) are relative to original baseline, not previous text # further note that these are baseline changes, with no guarantee that text # will not ascend above the original baseline (i.e., it is NOT the distance # between the baseline and the TOP of the text!) $grf->poly(50,800, 430,800); $grf->poly(420,805, 430,805, 430,795, 420,795); $grf->stroke(); $txt->translate(435,800); $txt->fillcolor('green'); $txt->font($f1, $fsize*$subsupscl); $txt->text('Baseline'); $txt->fillcolor('black'); $txt->font($f1, $fsize); $txt->translate(50,800); $txt->text('normal text '); $txt->rise(5); $txt->text('rise = 5 units'); $txt->rise(-5); $txt->text('rise = -5 units'); $txt->rise(0); # ---------------------------- $grf->poly(50,600, 430,600); $grf->poly(420,610, 430,610, 430,590, 420,590); $grf->stroke(); $txt->translate(435,600); $txt->fillcolor('green'); $txt->font($f1, $fsize*$subsupscl); $txt->text('Baseline'); $txt->fillcolor('black'); $txt->font($f1, $fsize); $txt->translate(50,600); $txt->text('normal text '); $txt->rise(10); $txt->text('rise = 10 units'); $txt->rise(-10); $txt->text('rise = -10 units'); $txt->rise(0); # ---------------------------- $grf->poly(50,400, 430,400); $grf->poly(420,420, 430,420, 430,380, 420,380); $grf->stroke(); $txt->translate(435,400); $txt->fillcolor('green'); $txt->font($f1, $fsize*$subsupscl); $txt->text('Baseline'); $txt->fillcolor('black'); $txt->font($f1, $fsize); $txt->translate(50,400); $txt->text('normal text '); $txt->rise(20); $txt->text('rise = 20 units'); $txt->rise(-20); $txt->text('rise = -20 units'); $txt->rise(0); # ---------------------------- # now for a line of text # it would be good to consider a convenience function for # subscript($scale,$font,$fontsize,$text) and likewise for superscript() $txt->translate(50, 200); $txt->text('The gases CO'); # $txt->subscript($subsupscl, $f1, $fsize, '2'); $txt->font($f1,$fsize*$subsupscl); $txt->rise(-10*$subsupscl); $txt->text('2'); $txt->rise(0); $txt->font($f1,$fsize); $txt->text(' and CH'); # $txt->subscript($subsupscl, $f1, $fsize, '4'); $txt->font($f1,$fsize*$subsupscl); $txt->rise(-10*$subsupscl); $txt->text('4'); $txt->rise(0); $txt->font($f1,$fsize); $txt->text(' are of concern for climate change.'); # ---------------------------- # and a math equation with sub- and superscripts # italicize all variable name letters not function names $txt->translate(50,100); $txt->font($f2, $fsize); # italic y $txt->text('y'); $txt->font($f1, $fsize); # roman = a $txt->text(' = a'); # $txt->subscript($subsupscl, $f1, $fsize, '2'); $txt->font($f1,$fsize*$subsupscl); # 2 $txt->rise(-10*$subsupscl); $txt->text('2'); $txt->rise(0); $txt->font($f2,$fsize); # italic x $txt->text('x'); # $txt->superscript($subsupscl, $f1, $fsize, '2'); $txt->font($f1,$fsize*$subsupscl); # 2 $txt->rise(10*$subsupscl); $txt->text('2'); $txt->rise(0); $txt->font($f1,$fsize); $txt->text(' + a'); # roman + a # $txt->subscript($subsupscl, $f1, $fsize, '1'); $txt->font($f1,$fsize*$subsupscl); # 1 $txt->rise(-10*$subsupscl); $txt->text('1'); $txt->rise(0); $txt->font($f2,$fsize); # italic x $txt->text('x'); # $txt->superscript($subsupscl, $f1, $fsize, '2'); $txt->font($f1,$fsize*$subsupscl); # 1 $txt->rise(10*$subsupscl); $txt->text('1'); $txt->rise(0); $txt->font($f1,$fsize); $txt->text(' + a'); # roman + a # $txt->subscript($subsupscl, $f1, $fsize, '0'); $txt->font($f1,$fsize*$subsupscl); # 0 $txt->rise(-10*$subsupscl); $txt->text('0'); $txt->rise(0); $txt->font($f1,$fsize); $txt->text(' is an equation.'); # ---------------------------- # ah, just for the halibut, use functions $txt->translate(50,65); $txt->font($f2, $fsize); # italic y $txt->text('y'); $txt->font($f1, $fsize); # roman = a $txt->text(' = a'); subscript($subsupscl, $f1, $fsize, '3'); # 3 $txt->font($f2,$fsize); # italic x $txt->text('x'); superscript($subsupscl, $f1, $fsize, '3'); # 3 $txt->font($f1,$fsize); $txt->text(' + a'); # roman + a subscript($subsupscl, $f1, $fsize, '2'); # 2 $txt->font($f2,$fsize); # italic x $txt->text('x'); superscript($subsupscl, $f1, $fsize, '2'); # 2 $txt->font($f1,$fsize); $txt->text(' + a'); # roman + a subscript($subsupscl, $f1, $fsize, '1'); # 1 $txt->font($f2,$fsize); # italic x $txt->text('x'); superscript($subsupscl, $f1, $fsize, '1'); # 1 $txt->font($f1,$fsize); $txt->text(' + a'); # roman + a subscript($subsupscl, $f1, $fsize, '0'); # 0 $txt->font($f1,$fsize); $txt->text(' is done with functions.'); # ---------------------------- $pdf->saveas("$0.pdf"); $pdf->end(); exit; # TBD These might go into content or content::text. # As a method, $txt might not have to be passed in if can use $self. # It might be a good idea to save and restore the font and size, too # (might need to extend font() method to return the current font and size). # Restores old rise() value, such as for putting superscript on a # subscript, etc., instead of hardcoded 0. Use the current font size # instead of passing it in. Could have optional values to override the # font, size, rise %, etc., by default using the old font. The sub/sup scale # might default, with an override (is it strongly dependent on font?). # Potentially only the $text might be a mandatory parameter, or combine # the functions with a 'sup' or 'sub' parameter, since only one line diff. # TBD Probably doesn't yet handle super on sub and vice-versa, or super on # super, etc. Needs more thought. sub subscript { my ($subsupscl, $font, $fsize, $text) = @_; my $oldRise = $txt->rise(); # save old font here -- need anyway for font() call unless override given $txt->font($font, $fsize*$subsupscl); $txt->rise(-$fsize/2*$subsupscl); $txt->text($text); # restore old font here $txt->rise($oldRise); return; } sub superscript { my ($subsupscl, $font, $fsize, $text) = @_; my $oldRise = $txt->rise(); # save old font here -- need anyway for font() call unless override given $txt->font($font, $fsize*$subsupscl); $txt->rise($fsize/2*$subsupscl); $txt->text($text); # restore old font here $txt->rise($oldRise); return; } __END__ PDF-Builder-3.026/examples/012_pages0000644000000000000000000000174414534467462015466 0ustar rootroot#!/usr/bin/perl use strict; use warnings; use lib '../lib'; use PDF::Builder; #my $compress = 'none'; # uncompressed streams my $compress = 'flate'; # compressed streams my $pdf = PDF::Builder->new(-compress => $compress); my $font = $pdf->corefont('Arial-Bold'); # input: empty page. writes current page number on it (total number of pages) # uses global $pdf to get number of pages sub mark { my ($page, $pageno) = @_; my $t = $page->text(); $t->font($font, 20); $t->translate(20, 700); if (defined $pageno) { $t->text($pageno); # the given page number } else { $t->text($pdf->pages()); # current page number 1, 2, 3,... } return; } # create pages 1 - 8 for (1..8) { mark($pdf->page()); } # create ninth page, inserted before old page 2 mark($pdf->page(2)); # create some Front Matter (TOC, etc.) pages i, ii, iii mark($pdf->page(1), 'i'); mark($pdf->page(2), 'ii'); mark($pdf->page(3), 'iii'); $pdf->saveas("$0.pdf"); __END__ PDF-Builder-3.026/examples/024_bdffonts0000644000000000000000000001744214534467462016201 0ustar rootroot#!/usr/bin/perl # dumps a bitmap distribution format (.bdf) font use strict; use warnings; use PDF::Builder; use PDF::Builder::Util; use File::Basename; use PDF::Builder::Resource::Font::BdFont; use Data::Dumper; my $compress = 'none'; # uncompressed streams #my $compress = 'flate'; # compressed stream my $doDump = 0; # one page per character my $doText = 1; # Lorem Ipsum text my $LoremIpsum=q|Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam eaque ipsa, quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt, explicabo. Nemo enim ipsam voluptatem, quia voluptas sit, aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos, qui ratione voluptatem sequi nesciunt, neque porro quisquam est, qui dolorem ipsum, quia dolor sit, amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt, ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit, qui in ea voluptate velit esse, quam nihil molestiae consequatur, vel illum, qui dolorem eum fugiat, quo voluptas nulla pariatur? At vero eos et accusamus et iusto odio dignissimos ducimus, qui blanditiis praesentium voluptatum deleniti atque corrupti, quos dolores et quas molestias excepturi sint, obcaecati cupiditate non provident, similique sunt in culpa, qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio.|; #Nam libero tempore, cum soluta nobis est eligendi optio, cumque nihil impedit, quo minus id, quod maxime placeat, facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet, ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat.|; ##push @ARGV, "../../old PDF-APIx/work-PDF-Builder/codec/codec.bdf" if !scalar @ARGV; # TEMP die "Require one BDFont file on command line.\n" if !scalar @ARGV; die "Requested BDFont file $ARGV[0] not found.\n" if !-e $ARGV[0]; my $data = PDF::Builder::Resource::Font::BdFont->readBDF($ARGV[0]); #print Dumper($data); my $pdf = PDF::Builder->new(-compress => $compress); if ($doDump) { # loop through characters in font file. ONE PAGE per character!! my $font = $pdf->corefont('Helvetica'); my $fontsize = 10; foreach my $char (@{$data->{'char2'}}) { my $page = $pdf->page(); $page->mediabox('A4'); # 595,842 my $txt = $page->text(); my $gfx = $page->gfx(); # BDF char is presented as an image print "C: $char->{'NAME'} ($char->{'ENCODING'})\n"; my @bbx = @{$char->{'BBX'}}; if (!defined $char->{'hex'}) { # must be a space. give it a hex pattern to avoid error message $char->{'hex'} = '0000'; } my $stream = pack('H*', $char->{'hex'}); my $y = $bbx[1]; # vertical dimension of character (bits) # to be shifted up or down by bbx[3] bits my $xpos = 100; my $ypos = 760; # moved from 50 50 (lower left of page) to 100 760 (upper left) # with CHR(nn) inserted (temporarily) $txt->translate($xpos-80, $ypos); $txt->font($font, $fontsize); $txt->fillcolor('black'); $txt->text("CHR(".$char->{'ENCODING'}.")"); my $cx = $xpos + $bbx[2]; my $cy = $ypos + $bbx[3]; $gfx->strokecolor('red'); # draw character start point and baseline # (10 high x 15 wide box) $gfx->linewidth(1); $gfx->move($xpos-1, $ypos+10-1); $gfx->vline($ypos); $gfx->hline($xpos + 15); $gfx->stroke(); $gfx->strokecolor('black'); next unless $y; # empty char has $y = 0 my $x = 8*length($stream)/$y; my $img = qq|q $x 0 0 $y $cx $cy cm BI /Interpolate false /Decode [1 0] /H $y /W $x /BPC 1 /CS /G ID $stream EI Q|; $gfx->add($img); delete $gfx->{'Filter'}; } # loop through characters in font file that was read in } # do we show one character per page? # show one page of 256 glyphs, in specified coding my $sx = 33; # cell width my $sy = 45; # cell height my $fx = 20; # ascender max my $f1 = $pdf->corefont('Helvetica'); my $f2 = $pdf->corefont('Times-Roman'); #my $font = $pdf->bdfont($ARGV[0]); # default block style #my $font = $pdf->bdfont($ARGV[0], -style=>'block'); # explicit block style my $font = $pdf->bdfont($ARGV[0], -style=>'dot'); my $page = $pdf->page(); $page->mediabox('A4'); # 595x842 my $gfx = $page->gfx(); my $txt = $page->text(); $txt->strokecolor('#000'); # actually, only filling $txt->fillcolor('#000'); $txt->font($font, $fx); my $txt2 = $page->text(); # title of font names $txt2->translate(50,800); $txt2->font($f1, 15); $txt2->text("font='".$font->fontname()." / ".$font->name()."'"); # compact text for 4 lines beneath each cell $txt2->font($f1, 5); $txt2->hscale(80); # underline or cell bottom pts below baseline (<0) to clear descenders my $u = $font->underlineposition()*$fx/1000; # loop character group (row) from low to high foreach my $yp (0..15) { my $y = 15 - $yp; # row position grows high to low (top to bottom) print STDERR "."; # loop column left to right foreach my $x (0..15) { my $ci = $yp*16 + $x; my $c = chr($ci); $txt->translate(50+($sx*$x),50+($sy*$y)); # character position $txt->text($c); # the character itself, in bitmapped font my $wx = $font->width($c)*$fx; # character width in grid units (1000) my $wxs = $wx; # desired on-screen width in pixels # draw lt blue character cell: width of character, full des/asc height $gfx->strokecolor('lightblue'); $gfx->move(50+($sx*$x),50+($sy*$y)+$fx); # UL corner $gfx->line(50+($sx*$x),50+($sy*$y)+$u); # LL corner $gfx->line(50+($sx*$x)+$wxs,50+($sy*$y)+$u); # LR corner $gfx->line(50+($sx*$x)+$wxs,50+($sy*$y)+$fx); # UR corner $gfx->close(); $gfx->stroke(); $gfx->strokecolor('gray'); # baseline $gfx->move(50+($sx*$x),50+($sy*$y)); $gfx->line(50+($sx*$x)+$wxs,50+($sy*$y)); $gfx->stroke(); $txt2->translate(50+($sx*$x)+2,50+($sy*$y)-9); $txt2->text($ci); # decimal character number $txt2->translate(50+($sx*$x)+2,50+($sy*$y)-14); # Unicode number (16 bit) if (defined $font->uniByEnc($ci)) { $txt2->text(sprintf('U+%04X',$font->uniByEnc($ci))); } else { #$txt2->text('U+????'); $txt2->text(sprintf('U+%04X', $ci)); # is Latin-1 } $txt2->translate(50+($sx*$x)+2,50+($sy*$y)-19); $txt2->text($font->glyphByEnc($ci)); # glyph name $txt2->translate(50+($sx*$x)+2,50+($sy*$y)-24); $txt2->text(sprintf('wx=%d',$font->wxByEnc($ci))); # glyph width } # column loop (x) } # row loop (yp/y) if ($doText) { # print out some text in this font on next page my $textL = $LoremIpsum; $page = $pdf->page(); $page->mediabox('A4'); $txt = $page->text(); $txt->fillcolor('black'); $txt->transform(-translate => [50, 800]); $txt->font($f1, 18); $txt->leading(18*1.25); $txt->text("Some 18 point Helvetica text"); $txt->font($f2, 18); $txt->leading(18*1.25); $txt->text(" Some 18 point Times-Roman text"); $txt->transform(-translate => [50, 800-18*1.25]); $txt->font($font, 18); $txt->leading(18*1.25); my $toprint; while ($textL ne '') { ($toprint, $textL) = $txt->_text_fill_line($textL, 500, 0); $txt->text($toprint); $txt->nl(); } } delete $gfx->{'Filter'}; delete $txt->{'Filter'}; delete $txt2->{'Filter'}; my $myName = basename($ARGV[0]); $myName =~ s/\.bdf$//i; # trim off extension $pdf->saveas("$0.$myName.pdf"); $pdf->end(); print STDERR "\n"; __END__ PDF-Builder-3.026/examples/032_separation0000644000000000000000000000474114534467462016536 0ustar rootroot#!/usr/bin/perl # show color separations use strict; use warnings; use PDF::Builder; use PDF::Builder::Util; use POSIX; use Math::Trig; #my $compress = 'none'; # uncompressed streams my $compress = 'flate'; # compressed streams my $cx = 50; my $cy = 50; my $cr = 15; my $cs = 32; my $ang = 30; my $pdf = PDF::Builder->new(-compress => $compress); $pdf->mediabox(595,842); my $fnt = $pdf->corefont('Verdana-Bold'); my $page = $pdf->page(); my $gfx = $page->gfx(); my $text = $page->text(); $text->linewidth(0); $text->render(2); $text->textlabel(300,750, $fnt,20, 'Separation Colorspace(s)', -color=>'#000', -hscale=>125, -center=>1); $text->strokecolor('#000'); # colored section my $y = 0; foreach my $csn (qw( Red %0ff0 Green %f0f0 Blue %ff00 Cyan %f000 Magenta %0f00 Yellow %00f0 )) { my $csp = $pdf->colorspace_separation($csn, $csn); # row labels on left $text->textlabel($cx,$cy+($y*$cs)+14, $fnt,8, $csn, -color=>'#000', -hscale=>85, -right=>1); # 16 circles L to R 0..1 foreach my $x (0 .. 0xf) { $gfx->fillcolor($csp, sprintf('%0.4f',$x/0xf)); $gfx->circle($cx+($x+1)*$cs,$cy+($y+0.5)*$cs, $cr); $gfx->fillstroke(); $text->textlabel($cx+($x+1)*$cs,$cy+($y+0.5)*$cs-2, $fnt,8, sprintf('%0.4f',$x/0xf), -color=>'#000', -hscale=>85, -center=>1); } $y++; } # gray ('All') row my $csp = $pdf->colorspace_separation('All', '#000'); $text->textlabel($cx,$cy+($y*$cs)+14, $fnt,8, 'All', -color=>'#000', -hscale=>85, -right=>1); foreach my $x (0 .. 0xf) { $gfx->fillcolor($csp, sprintf('%0.4f',$x/0xf)); $gfx->circle($cx+($x+1)*$cs,$cy+($y+0.5)*$cs, $cr); $gfx->fillstroke(); $text->textlabel($cx+($x+1)*$cs,$cy+($y+0.5)*$cs-2, $fnt,8, sprintf('%0.4f',$x/0xf), -color=>'#000', -strokecolor=>'#FFF', -hscale=>85, -center=>1); } $y++; # 'None' row $csp = $pdf->colorspace_separation('None', '#000'); $text->textlabel($cx,$cy+($y*$cs)+14, $fnt,8, 'None', -color=>'#000', -hscale=>85, -right=>1); foreach my $x (0 .. 0xf) { $gfx->fillcolor($csp, sprintf('%0.4f',$x/0xf)); $gfx->circle($cx+($x+1)*$cs,$cy+($y+0.5)*$cs, $cr); $gfx->fillstroke(); $text->textlabel($cx+($x+1)*$cs,$cy+($y+0.5)*$cs-2, $fnt,8, sprintf('%0.4f',$x/0xf), -color=>'#000', -hscale=>85, -center=>1); } $y++; delete $gfx->{'Filter'}; $pdf->saveas("$0.pdf"); $pdf->end(); exit; __END__ PDF-Builder-3.026/examples/020_corefonts0000644000000000000000000001740514534467462016371 0ustar rootroot#!/usr/bin/perl # wants one or more font names on the command line. If none given, use full # list of core fonts. If -s given as first arg, use the short list. # CAUTION: the displayed Unicode value (U=xxxx) appears to be correct in most # cases, except that the MS Smart Quotes (32 characters) are given as U=0080 # through U=009F. Those Unicode values are reserved for the C1 Control character # group, not printable glyphs. I don't know if the font files hold incorrect # Unicode values, or this program is in error. See PDF::Builder::Resource:: # Glyphs for u2n and n2u tables -- they may be in error. What the mapping is # from Unicode to the various pages and 00..FF within each page is not clear at # this point, although the "Latinx" encodings seem to be mostly OK. Note that # most fonts spill over onto 1 or more additional pages, which of course is # beyond single byte encoding. use strict; use warnings; use lib '../lib'; use PDF::Builder; use PDF::Builder::Util; #my $compress = 'none'; # uncompressed streams my $compress = 'flate'; # compressed streams my $sx = 33; my $sy = 45; my $fx = 20; my $gLLx = 50; # lower left position of grid my $gLLy = 50; # default list of core fonts if user doesn't provide command line list my @fns=qw{ Helvetica Helvetica-Oblique Helvetica-Bold Helvetica-BoldOblique Courier Courier-Oblique Courier-Bold Courier-BoldOblique Times-Roman Times-Italic Times-Bold Times-BoldItalic Symbol ZapfDingbats georgia georgiaitalic georgiabold georgiabolditalic trebuchet trebuchetbold trebuchetbolditalic trebuchetitalic verdana verdanaitalic verdanabold verdanabolditalic wingdings webdings }; # It's not clear what is being shown for Bank Gothic. # 1. There is only Regular and Italic -- no bold variants # 2. It doesn't look like the Bank Gothic shown on sample font pages -- # perhaps it's some other sans serif font being substituted # bankgothic # bankgothicbold # bankgothicbolditalic # bankgothicitalic my @ARGVcopy = @ARGV; # 'short' (-s flag)? if (@ARGVcopy > 0 && $ARGVcopy[0] eq '-s') { @ARGVcopy = qw{ Courier-Bold Times-Italic Symbol }; } # use only with single byte encodings, as multibyte (including UTF-8) don't # appear to be compatible with these core fonts # there may be a number of aliases available for each encoding. # available encodings (believed to be single byte): # 7bit-jis AdobeStandardEncoding AdobeSymbol AdobeZdingbat ascii # ascii-ctrl cp1006 cp1026 cp1047 cp1250 cp1251 cp1252 cp1253 cp1254 # cp1255 cp1256 cp1257 cp1258 cp37 cp424 cp437 cp500 cp737 cp775 # cp850 cp852 cp855 cp856 cp857 cp858 cp860 cp861 cp862 cp863 cp864 # cp865 cp866 cp869 cp874 cp875 dingbats hp-roman8 iso-8859-1 # iso-8859-2 iso-8859-3 iso-8859-4 iso-8859-5 iso-8859-6 iso-8859-7 # iso-8859-8 iso-8859-9 iso-8859-10 iso-8859-11 iso-8859-13 iso-8859-14 # iso-8859-15 iso-8859-16 iso-ir-165 jis0201-raw koi8-f koi8-r koi8-u # MacArabic MacCentralEurRoman MacCroatian MacCyrillic MacDingbats # MacFarsi MacGreek MacHebrew MacIcelandic MacRoman MacRomanian # MacRumanian MacSami MacSymbol MacThai MacTurkish MacUkrainian nextstep # null posix-bc symbol viscii # multibyte encodings (do not use): # big5-eten big5-hkscs cp932 cp936 cp949 cp950 euc-cn euc-jp euc-kr # gb12345-raw gb2312-raw gsm0338 hz iso-2022-jp iso-2022-jp-1 iso-2022-kr # jis0208-raw jis0212-raw johab ksc5601-raw MacChineseSimp MacChineseTrad # MacJapanese MacKorean MIME-B MIME-Header MIME-Header-ISO_2022_JP MIME-Q # shiftjis UCS-2BE UCS-2LE UTF-16 UTF-16BE UTF-16LE UTF-32 UTF-32BE # UTF-32LE UTF-7 utf-8-strict utf8 and probably others my @ecs = qw{ latin1 latin2 latin3 latin4 latin5 latin6 latin7 latin8 latin9 latin10 }; # just Latin-1 for now... @ecs = qw{ latin1 }; my ($y, $pdf, $f1); # override default list with command line entries if (scalar @ARGVcopy && $ARGVcopy[0] ne '-s') { @fns = @ARGVcopy; } # loop through list of font names foreach my $fn (@fns) { # at least one page for each encoding foreach my $ec (@ecs) { $pdf = PDF::Builder->new(-compress => $compress); $f1 = $pdf->corefont('Helvetica'); # for various labels print STDERR "\n$fn -- $ec\n"; initNameTable(); # set up u2n and n2u hashes my $fnt = $pdf->corefont($fn, -encode => $ec); my @planes = ($fnt, $fnt->automap()); my $flight = -1; foreach my $plane (@planes) { $flight++; # subfonts within overall font (223 characters per plane + space) # they can be treated just like regular fonts my $page = $pdf->page(); $page->mediabox(595,842); my $gfx = $page->gfx(); my $txt = $page->text(); $txt->font($plane,$fx); my $txt2 = $page->text(); $txt2->textlabel($gLLx,800, $f1,20, "font='".$plane->fontname()." / ".$plane->name()."' plane $flight", -hscale=>75); $txt2->textlabel($gLLx,780, $f1,20, "encoding='$ec'"); $txt2->font($f1, 5); $txt2->hscale(80); # distance below baseline (<0) to clear descenders my $u = $plane->underlineposition()*$fx/1000; # draw grid of characters and information # yp character row value (0..F T to B) foreach my $yp (0..15) { $y = 15 - $yp; # y vertical (row) position T to B print STDERR "."; foreach my $x (0..15) { # x horizontal (column) position L to R $txt->translate($gLLx+($sx*$x),$gLLy+($sy*$y)); my $ci = $yp*16 + $x; # 0..255 value my $c = chr($ci); $txt->text($c); my $wx = $plane->width($c)*$fx; # bounding box cell around character $gfx->strokecolor('lightblue'); if ($plane->wxMissingByEnc($ci)) { $gfx->fillcolor(1.0, 0.7, 0.7); } $gfx->move($gLLx+($sx*$x) ,$gLLy+($sy*$y)+$fx); $gfx->line($gLLx+($sx*$x) ,$gLLy+($sy*$y)+$u); $gfx->line($gLLx+($sx*$x)+$wx,$gLLy+($sy*$y)+$u); $gfx->line($gLLx+($sx*$x)+$wx,$gLLy+($sy*$y)+$fx); $gfx->close(); if ($plane->wxMissingByEnc($ci)) { $gfx->fillstroke(); $gfx->fillcolor('black'); } else { $gfx->stroke(); } # baseline $gfx->strokecolor('gray'); $gfx->move($gLLx+($sx*$x) ,$gLLy+($sy*$y)); $gfx->line($gLLx+($sx*$x)+$wx,$gLLy+($sy*$y)); $gfx->stroke(); # character data $txt2->translate($gLLx+($sx*$x)+$wx,$gLLy+($sy*$y)-6); $txt2->text_right($ci); $txt2->translate($gLLx+($sx*$x)+$wx,$gLLy+($sy*$y)-11); if (defined $plane->uniByEnc($ci)) { $txt2->text_right(sprintf('U+%04X',$plane->uniByEnc($ci))); } else { $txt2->text_right('U+????'); } $txt2->translate($gLLx+($sx*$x)+$wx,$gLLy+($sy*$y)-16); $txt2->text_right($plane->glyphByEnc($ci)); $txt2->translate($gLLx+($sx*$x)+$wx,$gLLy+($sy*$y)-21); $txt2->text_right(sprintf('wx=%i',$plane->wxByEnc($ci))); } # loop through columns (x) } # loop through rows (yp/y) print STDERR "\n"; } # loop through "sub" fonts (planes) $pdf->saveas("$0.$fn.$ec.pdf"); $pdf->end(); } # loop through each encoding (ec) } # loop for each font name (fn) exit; __END__ PDF-Builder-3.026/examples/examples.output0000644000000000000000000003066214534467462017163 0ustar rootrootWhat to expect to see while running the examples/ Perl code, and what to expect to see when the resulting PDFs are displayed. 011_open_update 011_open_update.BASE.pdf 1 pg: Hello World! 011_open_update.UPDATED.pdf add pg 2: Hello World! (2) 011_open_update.STRING.pdf add pg 3: Hello World! (3), pg 4: Hello World! (4) 012_pages 012_pages.pdf 8 pages labeled 1 to 8, then page 9 inserted between 1 and 2, 3 pages labeled i to iii, inserted before page 1 giving i ii iii 1 9 2 3 4 5 6 7 8 020_corefonts (020_corefonts.NAME.latin1.pdf) Helvetica -- latin1 020_corefonts.Helvetica.latin1.pdf 2 pages 16x16 char grid Helvetica-Oblique -- latin1 2 pages 16x16 char grid Helvetica-Bold -- latin1 2 pages 16x16 char grid Helvetica-BoldOblique -- latin1 2 pages 16x16 char grid Courier -- latin1 2 pages 16x16 char grid Courier-Oblique -- latin1 2 pages 16x16 char grid Courier-Bold -- latin1 2 pages 16x16 char grid Courier-BoldOblique -- latin1 2 pages 16x16 char grid Times-Roman -- latin1 2 pages 16x16 char grid Times-Italic -- latin1 2 pages 16x16 char grid Times-Bold -- latin1 2 pages 16x16 char grid Times-BoldItalic -- latin1 2 pages 16x16 char grid Symbol -- latin1 1 page 16x16 char grid ZapfDingbats -- latin1 1 page 16x16 char grid bankgothic -- latin1 2 pages 16x16 char grid bankgothicbold -- latin1 2 pages 16x16 char grid bankgothicbolditalic -- latin1 2 pages 16x16 char grid bankgothicitalic -- latin1 2 pages 16x16 char grid georgia -- latin1 3 pages 16x16 char grid georgiaitalic -- latin1 3 pages 16x16 char grid georgiabold -- latin1 3 pages 16x16 char grid georgiabolditalic -- latin1 3 pages 16x16 char grid trebuchet -- latin1 2 pages 16x16 char grid trebuchetbold -- latin1 2 pages 16x16 char grid trebuchetbolditalic -- latin1 2 pages 16x16 char grid trebuchetitalic -- latin1 2 pages 16x16 char grid verdana -- latin1 3 pages 16x16 char grid verdanaitalic -- latin1 3 pages 16x16 char grid verdanabold -- latin1 3 pages 16x16 char grid verdanabolditalic -- latin1 3 pages 16x16 char grid wingdings -- latin1 1 page 16x16 char grid webdings -- latin1 1 page 16x16 char grid 020_textrise 020_textrise.pdf 1 page examples of +/-5, 10, 20 points up and down 020_textunderline 020_textunderline.pdf 1 page showing color, angle, single/multiple underline 021_psfonts glyph_file_name -M "metrics_file_name" 021_psfonts.NAME.latin1.pdf one or more pages of up to 256 characters displayed 021_synfonts 021_synfonts.NAME.pdf "1 font" = one page with 16x16 char grid 4 pages of variants per "font" (slant, oblique, bold, small caps) and a sample page with combined variants. Times-Roman 021_synfonts.Times-Roman.pdf 2 fonts x 4 variants Times-Italic 2x4 Times-Bold 2x4 Times-BoldItalic 2x4 Courier 2x4 Courier-Oblique 2x4 Courier-Bold 2x4 Courier-BoldOblique 2x4 Helvetica 2x4 Helvetica-Oblique 2x4 Helvetica-Bold 2x4 Helvetica-BoldOblique 2x4 Symbol 1x4 ZapfDingbats 1x4 bankgothic 2x4 bankgothicbold 2x4 bankgothicbolditalic 2x4 bankgothicitalic 2x4 georgia 3x4 georgiaitalic 3x4 georgiabold 3x4 georgiabolditalic 3x4 trebuchet 2x4 trebuchetbold 2x4 trebuchetbolditalic 2x4 trebuchetitalic 2x4 verdana 3x4 verdanaitalic 3x4 verdanabold 3x4 verdanabolditalic 3x4 wingdings 1x4 webdings 1x4 022_truefonts times.ttf (sample input) times 022_truefonts.times.pdf 1 page 16x16 grid of selected encoding (SINGLE BYTE, default latin1, omitted if UTF-8 is chosen as the encoding) 23 pages of 15x10 grid of CIDs in order (nothing to do with encoding) 1 page sample text in ASCII 022_truefonts_diacrits_utf8 tahoma.ttf (sample input) tahoma 022_truefonts_diacrits_utf8.tahoma.pdf 1 page 16x16 grid in selected encoding (SINGLE BYTE, default latin1, omitted if UTF-8 is chosen as the encoding) 1 page with sample diacritic spanning 3 letters (UTF-8 input) 023_cjkfonts (requires installation of CJK font package by Adobe Reader) Note that in some cases the Latin text example uses fixed pitch Latin characters, while in others it uses proportional fonts. Ming Ming-Bold Ming-Italic Ming-BoldItalic 023_cjkfonts.Ming*.pdf 127 pages 15x10 char grid + 1 page Latin text Song Song-Bold Song-Italic Song-BoldItalic 023_cjkfonts.Song*.pdf 194 pages 15x10 char grid + 1 page Latin text includes some rotated Latin text MyungJo MyungJo-Bold MyungJo-Italic MyungJo-BoldItalic 023_cjkfonts.MyungJo*.pdf 123 pages 15x10 char grid + 1 page Latin text includes rotated Latin text KozMin KozMin-Bold KozMin-Italic KozMin-BoldItalic 023_cjkfonts.KozMin*.pdf 103 pages 15x10 char grid + 1 page Latin text KozGo KozGo-Bold KozGo-Italic KozGo-BoldItalic 023_cjkfonts.KozGo*.pdf 103 pages 15x10 char grid + 1 page Latin text 024_bdffonts codec.bdf (sample input, not included) 024_pdffonts.codec.pdf optional 190 pages 1 bitmapped char each, 1 page 16x16 char grid and 1 page ipsum lorem Latin text Latin-1 character set, characters 32 (space) through 255 (y-umlaut) 025_unifonts 025_unifonts.pdf 4 pages, each one first 45 lines of embedded PDF-J file, showing one of 4 Western+CJK font combinations. 026_unifont2 026_unifont2.pdf 9 pages of labeled UTF character grids (16x16) 030_colorspecs Note that RGB and L*a*b colors get brighter and brighter as the values increase, while CMYK colors get darker and darker as the values increase. 030_colorspaces.pdf RGB colorspace (16 pages) 16x16 colored dots 0..Fx0..F with x constant per pg RGB colorspace with Gamma 2.2 (16 pages) same layout CMYK colorspace (16 pages) 16x16 colored dots 0..Fx0..F0 with x constant/page L*a*b colorspace (16 pages) 16x16 colored dots x0..F0..F with x constant/page named colors (RGB colorspace) 3 pages 16x16 colored dots, alphabetical order 031_color_hsv 031_color_hsv.pdf 7 pages circular colored dots, subset of total &hhssvv set 032_separation 032_separation.pdf 1 page colored dots 14 models x 16 levels 040_annotation 040_annotation.pdf 1 page two annotations, one initially open, one initially closed you will be prompted by Reader to save changes (if wrote to either) 1 page 4 "markup" annotations in some sample text. 041_annot_fileattach 041_annot_fileattach.pdf 1 page six annotations, two small attached (embedded files) with a variety of icons. if you click on an openable icon, you will be prompted to save your changes when you exit. 042_links 042_links.pdf 1 page with links to browser webpages (with and without target) 1 page with link to previous page (within document) 1 page with link to page 1 of another PDF document 1 page with "launch" (edit a text file), also with fancy border a movie is available if defined 050_pagelabels 050_pagelabels.pdf 26 pages with a variety of thumbnail labels in Reader. your reader should display the indicated page label (on displayed page) on the thumbnail page display on the scrollbar thumb. 055_outlines 055_outlines.sample_55.pdf 12 pages (like 012_pages output) with three bookmarks (outlines) to logical pages 1 ("i"), 4 ("1"), and 11 ("7"). you may need to click on your reader's bookmark icon to display the list of bookmarks available. 060_transparency 060_transparency.pdf 2 pages, each one method of transparency/opacity, with opaque red and 40% transparent black text BarCode.pl BarCode.pdf 1 page x 11 barcodes, NOT VERIFIED AS CORRECT (need scanners!) Boxes.pl Boxes.pdf demonstrate interactions of PDF "boxes" building document Bspline.pl Bspline.pdf 4 pages of showing the use of b-splines Column.pl Column.pdf 12 pages demonstrating column() method with markup Content.pl Content.pdf pg 1: 6 ex. coordinate transforms, 1 line width, 1 line cap, 1 flatness, 3 line joins pg 2: 6 mitered joins effect of miterlimit=4, 1 line dash, 1 hline/vline/line/poly, 1 single and multiple rect(), 1 two examples rectxy(), 1 circle @ 3 radii, 1 ellipse @ 3 sets of radii pg 3: 1 arc @ 3 sets of radii, 1 pie w/ one slice removed, 1 curve, 1 spline, 5 bogen examples, 1 fill with two winding rules, 1 fillstroke with two winding rules pg 4: 3 clip examples, 1 image, 2 formimage with different scaling, 1 charspace examples, 1 wordspace examples, 1 hscale examples, 1 leading examples, 2 render example sets pg 5: 1 rise() examples, 1 cr() examples, 1 nl() examples, 1 textpos() usage, 1 underline and indent examples, 1 advancewidth() example, 1 text() ContentText.pl ContentText.pdf pg 1: text_left (= text), 4 lines separately that overflow text_justified, 4 lines separately, one very squeezed text_fill_left, single string splits to fill, LJ text_fill = text_fill_left text_fill_center, single string split to fill, centered text_fill_right, single string split to fill, RJ text_fill_justified, single string split to fill, each line justified same, but explicitly centered last line same, but explicitly right justified last line paragraph (single string split, default left justify) same, but indent 1.5em (no change to splitting) pg 2: same, but outdent 1.5em (different splitting) paragraph, single string split, justified same, but indent 1.5em (no change to splitting) same, but outdent 1.5em (different splitting) paragraph, single string split, RJ same, plus 2.5em indent (different splitting) same, plus 2em indent (different splitting) paragraph, single string split, centered pg 3: 3 calls to section to fill three columns, paragraphs marked by newline can't see where paragraphs start (except previous line short) pg 4: same, with 10pt interparagraph gap see paragraphs separated by vertical gap pg 5: same, except 2em indent instead of gap see paragraphs start with indent pg 6: same, except 2em outdent instead of gap paragraphs start at left margin. note shorter lines make for more of third column filled pg 7: 3 calls for 3 columns, justified with 2em indent paragraphs marked by first line indentations pg 8: same, add 5pt vertical gap between paragraphs two ways to see separation of paragraphs pg 9: show use of textlabel() options. shows dot for starting x,y point, with default (left), right, centered justification. show text at 45 degree angles, single and triple underline. show auto underline, extra word and character spacing, condensed text (hscale), and render mode 1 (outline/stroke only) pg 10: Latin-1 text, default text fill (left justified), no hyphenation same, but allow hyphenation (soft and hard hyphens, happens to only split at soft) same, but large indent to force different hyphenation points, which are the two hard hyphens and one soft hyphen UTF-8 text (SHYs only difference), no hyphenation same, allow hyphenation, same as Latin-1 same, large indent, same as Latin-1 crazy long URL-style text, default left justify, splits at camelCase, punctuation, letter runs, slashes same, but outdented to force splits at different points FontManager.pl FontManager.pdf One page showing how to easily switch among fonts HarfBuzz.pl HarfBuzz.pdf Page 1: showing various scripts (Latin, Middle Eastern, and South Asian) LTR and RTL, with ligatures and kerning (Latin) in two lines: a raw output of the UTF-8 script using text(), and a line processed through HarfBuzz::Shaper and textHS(). Page 2: showing various alphabets in vertical writing mode. A copy of the output file is provided for your convenience (in case you don't have HarfBuzz::Shaper installed) on the CTS website https://www.catskilltech.com/. RMtutorial.pl RMtutorial.pdf one page Lorem Ipsum, photo, simple graphics as a demo Rotated.pl Rotated.pdf pp 1 and 4 portrait mode Lorem Ipsum text pp 2 and 3 landscape mode two column Lorem Ipsum text ShowFont.pl ShowFont.pdf 15 pages each of Helvetica in 10 different Latin encodings run without command line arguments to get help PDF-Builder-3.026/examples/Boxes.pl0000644000000000000000000006345714534467462015510 0ustar rootroot#!/usr/bin/perl # demonstrate uses of PDF boxes # outputs Boxes.pdf # author: Phil M Perry use strict; use warnings; use PDF::Builder; use constant in => 1 / 72; # e.g., 3.5/in for 3.5 inch dimension use constant cm => 2.54 / 72; use constant mm => 25.4 / 72; use constant pt => 1; my @dual_format = (800, 600); my $live_format = 'letter'; # or A4 my $fontname = 'TimesRoman'; my $trimbox_adj = 1/mm; # in from bleed box my $bleedbox_adj = 36/pt; # in from crop box on top and right for printer inst. my $cropbox_adj = 0.25/in; # in from media edge our $VERSION = '3.026'; # VERSION our $LAST_UPDATE = '3.023'; # manually update whenever code is changed my $PDFname = $0; $PDFname =~ s/\..*$//; # remove extension such as .pl $PDFname .= '.pdf'; # add new extension .pdf my $pdf = PDF::Builder->new(-compress => 'none'); my $font = $pdf->corefont($fontname); my $fontH = $pdf->corefont('Helvetica'); # for headline my ($page, $grfx, $text, $clip); # semi-globals media_page('dual'); page_content('dual'); crop_page('dual'); bleed_page('dual'); printer_page('dual'); trim_page('dual'); art_page('dual'); media_page('live'); page_content('live'); crop_page('live'); bleed_page('live'); printer_page('live'); trim_page('live'); art_page('live'); $pdf->saveas($PDFname); ##################################################### subroutines # --------------- define the media sub media_page { my $mode = shift(); $page = $pdf->page(); $grfx = $page->gfx(); $text = $page->text(); # text always overlays graphics if ($mode eq 'dual') { $page->mediabox(@dual_format); my @size = (0,0, @dual_format); media_layer($mode, $grfx, @size); $text->fillcolor('black'); $text->font($font, 20); $text->translate(400,550); $text->text_center('Set the "paper" (media) size and coordinate system.'); } else { my @size = $page->mediabox($live_format); media_layer($mode, $grfx, @size); $text->font($font, 20); $text->translate($size[2]/2, $size[3]-100); $text->text_center("A page (media) of size '$live_format'"); $text->translate($size[2]/2, $size[3]-130); $text->text_center("Lower left ($size[0],$size[1]) to upper right ($size[2],$size[3])"); } return; } sub media_layer { my ($mode, $grfx, @size) = @_; if ($mode eq 'dual') { # mint background, two generic page outlines $grfx->fillcolor('#E4EFC9'); $grfx->rectxy(@size); $grfx->fill(); $grfx->fillcolor('white'); $grfx->rectxy(50,50, 375,500); $grfx->fill(); $grfx->rectxy(425,50, 750,500); $grfx->fill(); } # nothing for live return; } # --------------- add content to the pages sub page_content { my $mode = shift(); $page = $pdf->page(); $grfx = $page->gfx(); $text = $page->text(); # text always overlays graphics $clip = $page->gfx(); # clip (graphics) overlays text if ($mode eq 'dual') { $page->mediabox(@dual_format); my @size = (0,0, @dual_format); media_layer($mode, $grfx, @size); content_layer($mode, $grfx, $text, @size); $text->fillcolor('black'); $text->font($font, 20); $text->translate(400,550); $text->text_center('Add graphics and text content.'); $text->translate(400,525); $text->text_center('Note that output auto trimmed to media and paper rollers.'); # emulate appropriate clipping (just left and right) $clip->fillcolor('#E4EFC9'); $clip->rectxy(405/pt,40/pt, 425/pt,510/pt); $clip->fill(); $clip->rectxy(750/pt,40/pt, 775/pt,510/pt); $clip->fill(); $clip->fillcolor('gray'); $clip->rectxy(425/pt,50/pt, 428/pt,500/pt); $clip->fill(); $clip->rectxy(747/pt,50/pt, 750/pt,500/pt); $clip->fill(); } else { my @size = $page->mediabox($live_format); media_layer($mode, $grfx, @size); content_layer($mode, $grfx, $text, @size); $clip->fillcolor('gray'); $clip->rectxy(0,0, 3/pt,$size[3]); $clip->fill(); $clip->rectxy($size[2]-3/pt,0, $size[2],$size[3]); $clip->fill(); } return; } sub content_layer { my ($mode, $grfx, $text, @size) = @_; if ($mode eq 'dual') { # left hand page unclipped the_content($mode, $grfx, $text, 50,50, 375,500); # right hand page clipped to media and paper handling # (3 pt on sides here) the_content($mode, $grfx, $text, 425,50, 750,500); } else { # page clipped to media and paper handling # (3 pt on sides here) the_content($mode, $grfx, $text, @size); } return; } sub the_content { my ($mode, $grfx, $text, @size) = @_; my ($width,$height, $x1,$y1, $x2,$y2); my $fontsize = ($mode eq 'dual')? 12: 24; # Lorem Ipsum text, borrowed from examples/ContentText.pl, including newlines # to mark end of paragraphs. my $LoremIpsum = "Sed ut perspiciatis, unde omnis iste natus error sit ". "voluptatem accusantium doloremque laudantium, totam rem aperiam eaque ipsa, ". "quae ab illo inventore veritatis et quasi architecto beatae vitae dicta ". "sunt, explicabo. Nemo enim ipsam voluptatem, quia voluptas sit, aspernatur ". "aut odit aut fugit, sed quia consequuntur magni dolores eos, qui ratione ". "dolor sit, voluptatem sequi nesciunt, neque porro quisquam est, qui dolorem ". "ipsum, quia amet, consectetur, adipisci velit, sed quia non numquam eius ". "modi tempora incidunt, ut labore et dolore magnam aliquam quaerat ". "voluptatem.\nUt enim ad minima veniam, quis nostrum exercitationem ullam ". "corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? ". "Quis autem vel eum iure reprehenderit, qui in ea voluptate velit esse, quam ". "nihil molestiae consequatur, vel illum, qui dolorem eum fugiat, quo voluptas ". "nulla pariatur? At vero eos et accusamus et iusto odio dignissimos ducimus, ". "qui blanditiis praesentium voluptatum deleniti atque corrupti, quos dolores ". "et quas molestias excepturi sint, obcaecati cupiditate non provident, ". "similique sunt in culpa, qui officia deserunt mollitia animi, id est laborum ". "et dolorum fuga.\nEt harum quidem rerum facilis est et expedita distinctio. ". "Nam libero tempore, cum soluta nobis est eligendi optio, cumque nihil ". "impedit, quo minus id, quod maxime placeat, facere possimus, omnis voluptas ". "assumenda est, omnis dolor repellendus.\nTemporibus autem quibusdam et aut ". "officiis debitis aut rerum necessitatibus saepe eveniet, ut et voluptates ". "repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur ". "a sapiente delectus, ut aut reiciendis voluptatibus maiores alias ". "consequatur aut perferendis doloribus asperiores repellat."; # size[0 1]..size[2 3] is media where to draw graphics and text content # left page will go over its boundaries in one case! # the headline box (to bleed box) $grfx->fillcolor('blue'); # top, left, and right to bleedbox $x1 = $size[0] + $cropbox_adj + 0; $x2 = $size[2] - $cropbox_adj - $bleedbox_adj; $height = (($mode eq 'single')?2.5:1)*25/pt; $y2 = $size[3] - $cropbox_adj - $bleedbox_adj; $y1 = $y2 - $height; $grfx->rectxy($x1,$y1, $x2,$y2); $grfx->fill(); $text->font($fontH, 20/pt); $text->fillcolor('white'); $text->translate($x2 - $trimbox_adj - 5/pt, $y1 + 3/pt); $text->text_right("The Headline"); # a well-behaved red separator line to bleed box $grfx->strokecolor('red'); $width = $mode eq 'single'? 3: 1.5; # line width $grfx->linewidth($width); $grfx->poly($x1,$y1-$width/2, $x2,$y1-$width/2); $grfx->stroke(); $y1 -= $width; # the text and background box exceeding media width $grfx->fillcolor('green'); $y1 -= 15/pt; $y2 = $y1 + 10/pt; $grfx->rectxy($size[0]-7/pt,$y1, $size[2]+7/pt,$y2); $grfx->fill(); $text->fillcolor('white'); $text->font($fontH, 8/pt); $text->translate(($size[0]+$size[2])/2, $y1+2/pt); $text->fillcolor('#E4EFC9'); if ($mode eq 'dual') { $text->text_center("This text is so long that it exceeds the media width and will be cropped by media box and printer."); } else { $text->text_center("This text is so long that it exceeds the media width and will be cropped by media box and printer. And here is incredibly even more text to extend the line on a single page format example."); } # the diagonal line exceeding media size $grfx->strokecolor('purple'); $grfx->linewidth(1); $grfx->poly($size[0]-7/pt,$y1, $size[2]+7/pt,$size[1]-4/pt); $grfx->stroke(); # a line to media edge $grfx->strokecolor('yellow'); $width = $mode eq 'single'? 3: 1.5; # line width $grfx->linewidth($width); $y1 -= 5/pt; $y2 = $y1; $grfx->poly($size[0],$y1, $size[2],$y2); $grfx->stroke(); $y1 -= 3*$width; # some Lorem Ipsum text within trim box and a margin $text->fillcolor('black'); $text->font($font, $fontsize); $text->leading($fontsize * 1.25); $x1 += $trimbox_adj + 4/pt; $y1 -= 5/pt + $fontsize/pt; # top baseline less one line $x2 -= $trimbox_adj + 4/pt; $text->translate($x1, $y1); my $cont = 0; my $unused; ($LoremIpsum, $cont, $unused) = $text->section($LoremIpsum, $x2 - $x1, $y1 - $size[1] - 3/pt - $fontsize*1.25, $cont, -spillover => 0, -align => 'justify', -pndnt => 2, -pvgap => 4 ); return; } # --------------- crop the pages to what printer can output # let's say 1/4 inch off each edge (probably too much) sub crop_page { my $mode = shift(); $page = $pdf->page(); $grfx = $page->gfx(); $text = $page->text(); # text always overlays graphics $clip = $page->gfx(); # clip (graphics) overlays text if ($mode eq 'dual') { $page->mediabox(@dual_format); my @size = (0,0, @dual_format); media_layer($mode, $grfx, @size); content_layer($mode, $grfx, $text, @size); $text->fillcolor('black'); $text->font($font, 20); $text->translate(400,550); $text->text_center('Set crop box 1/4 inch all around.'); $text->translate(400,525); $text->text_center('Probably excessive for most printers.'); # draw crop box on left page $grfx->strokecolor('black'); $grfx->linewidth(1); $grfx->linedash(3); $grfx->poly(40/pt,50/pt+$cropbox_adj, 385/pt,50/pt+$cropbox_adj); $grfx->poly(40/pt,500/pt-$cropbox_adj, 385/pt,500/pt-$cropbox_adj); $grfx->poly(50/pt+$cropbox_adj,40/pt, 50/pt+$cropbox_adj,510/pt); $grfx->poly(375/pt-$cropbox_adj,40/pt, 375/pt-$cropbox_adj,510/pt); $grfx->stroke(); $grfx->linedash(); # emulate appropriate clipping $clip->fillcolor('#E4EFC9'); $clip->rectxy(405/pt,40/pt, 425/pt,510/pt); $clip->fill(); $clip->rectxy(750/pt,40/pt, 775/pt,510/pt); $clip->fill(); $clip->fillcolor('gray'); $clip->rectxy(425/pt,50/pt, 425/pt+$cropbox_adj,500/pt); $clip->fill(); $clip->rectxy(750/pt-$cropbox_adj,50/pt, 750/pt,500/pt); $clip->fill(); $clip->rectxy(425/pt,50/pt, 750/pt,50/pt+$cropbox_adj); $clip->fill(); $clip->rectxy(425/pt,500/pt-$cropbox_adj, 750/pt,500/pt); $clip->fill(); } else { my @size = $page->mediabox($live_format); $page->cropbox($size[0]+$cropbox_adj, $size[1]+$cropbox_adj, $size[2]-$cropbox_adj, $size[3]-$cropbox_adj); media_layer($mode, $grfx, @size); content_layer($mode, $grfx, $text, @size); # ->cropbox() should actually trim content } return; } # --------------- set bleed box: no visible effect sub bleed_page { my $mode = shift(); $page = $pdf->page(); $grfx = $page->gfx(); $text = $page->text(); # text always overlays graphics $clip = $page->gfx(); # clip (graphics) overlays text if ($mode eq 'dual') { $page->mediabox(@dual_format); my @size = (0,0, @dual_format); media_layer($mode, $grfx, @size); content_layer($mode, $grfx, $text, @size); $text->fillcolor('black'); $text->font($font, 20); $text->translate(400,550); $text->text_center('Set bleed box bottom and left at crop,'); $text->translate(400,525); $text->text_center('just outside trim box on top and right.'); # draw crop box on left page in gray $grfx->linewidth(1); $grfx->linedash(3); $grfx->strokecolor('black'); # shared with bleed box $grfx->poly(40/pt,50/pt+$cropbox_adj, 385/pt,50/pt+$cropbox_adj); $grfx->stroke(); $grfx->strokecolor('#CCC'); $grfx->poly(50/pt,500/pt-$cropbox_adj, 375/pt,500/pt-$cropbox_adj); $grfx->stroke(); $grfx->strokecolor('black'); # shared with bleed box $grfx->poly(50/pt+$cropbox_adj,40/pt, 50/pt+$cropbox_adj,510/pt); $grfx->stroke(); $grfx->strokecolor('#CCC'); $grfx->poly(375/pt-$cropbox_adj,50/pt, 375/pt-$cropbox_adj,500/pt); $grfx->stroke(); # now bleed box in black on left page (shares left and bottom) $grfx->strokecolor('black'); $grfx->poly(40/pt,500/pt-$cropbox_adj-$bleedbox_adj, 385/pt,500/pt-$cropbox_adj-$bleedbox_adj); $grfx->poly(375/pt-$cropbox_adj-$bleedbox_adj,40/pt, 375/pt-$cropbox_adj-$bleedbox_adj,510/pt); $grfx->stroke(); $grfx->linedash(); # emulate appropriate clipping # no additional content removed by bleed box $clip->fillcolor('#E4EFC9'); $clip->rectxy(405/pt,40/pt, 425/pt,510/pt); $clip->fill(); $clip->rectxy(750/pt,40/pt, 775/pt,510/pt); $clip->fill(); $clip->fillcolor('gray'); $clip->rectxy(425/pt,50/pt, 425/pt+$cropbox_adj,500/pt); $clip->fill(); $clip->rectxy(750/pt-$cropbox_adj,50/pt, 750/pt,500/pt); $clip->fill(); $clip->rectxy(425/pt,50/pt, 750/pt,50/pt+$cropbox_adj); $clip->fill(); $clip->rectxy(425/pt,500/pt-$cropbox_adj, 750/pt,500/pt); $clip->fill(); } else { my @size = $page->mediabox($live_format); $page->cropbox($size[0]+$cropbox_adj, $size[1]+$cropbox_adj, $size[2]-$cropbox_adj, $size[3]-$cropbox_adj); $page->bleedbox($size[0]+$cropbox_adj, $size[1]+$cropbox_adj, $size[2]-$cropbox_adj-$bleedbox_adj, $size[3]-$cropbox_adj-$bleedbox_adj); media_layer($mode, $grfx, @size); content_layer($mode, $grfx, $text, @size); # ->cropbox() should actually trim content } return; } # --------------- add some printer instructions: crop marks, color alignment sub printer_page { my $mode = shift(); $page = $pdf->page(); $grfx = $page->gfx(); $text = $page->text(); # text always overlays graphics $clip = $page->gfx(); # clip (graphics) overlays text if ($mode eq 'dual') { $page->mediabox(@dual_format); my @size = (0,0, @dual_format); media_layer($mode, $grfx, @size); content_layer($mode, $grfx, $text, @size); $text->fillcolor('black'); $text->font($font, 20); $text->translate(400,550); $text->text_center('Add some printer instructions, crop marks,'); $text->translate(400,525); $text->text_center('and color alignment dots.'); # draw crop box on left page in gray $grfx->linewidth(1); $grfx->linedash(3); $grfx->strokecolor('black'); # shared with bleed box $grfx->poly(40/pt,50/pt+$cropbox_adj, 385/pt,50/pt+$cropbox_adj); $grfx->stroke(); $grfx->strokecolor('#CCC'); $grfx->poly(50/pt,500/pt-$cropbox_adj, 375/pt,500/pt-$cropbox_adj); $grfx->stroke(); $grfx->strokecolor('black'); # shared with bleed box $grfx->poly(50/pt+$cropbox_adj,40/pt, 50/pt+$cropbox_adj,510/pt); $grfx->stroke(); $grfx->strokecolor('#CCC'); $grfx->poly(375/pt-$cropbox_adj,50/pt, 375/pt-$cropbox_adj,500/pt); $grfx->stroke(); # now bleed box in black on left page (shares left and bottom) $grfx->strokecolor('black'); $grfx->poly(40/pt,500/pt-$cropbox_adj-$bleedbox_adj, 385/pt,500/pt-$cropbox_adj-$bleedbox_adj); $grfx->poly(375/pt-$cropbox_adj-$bleedbox_adj,40/pt, 375/pt-$cropbox_adj-$bleedbox_adj,510/pt); $grfx->stroke(); $grfx->linedash(); # emulate appropriate clipping # no additional content removed by bleed box $clip->fillcolor('#E4EFC9'); $clip->rectxy(405/pt,40/pt, 425/pt,510/pt); $clip->fill(); $clip->rectxy(750/pt,40/pt, 775/pt,510/pt); $clip->fill(); $clip->fillcolor('gray'); $clip->rectxy(425/pt,50/pt, 425/pt+$cropbox_adj,500/pt); $clip->fill(); $clip->rectxy(750/pt-$cropbox_adj,50/pt, 750/pt,500/pt); $clip->fill(); $clip->rectxy(425/pt,50/pt, 750/pt,50/pt+$cropbox_adj); $clip->fill(); $clip->rectxy(425/pt,500/pt-$cropbox_adj, 750/pt,500/pt); $clip->fill(); printer_marks($mode, $text, $grfx, 50,50, 375,500); printer_marks($mode, $text, $grfx, 425,50, 750,500); } else { my @size = $page->mediabox($live_format); $page->cropbox($size[0]+$cropbox_adj, $size[1]+$cropbox_adj, $size[2]-$cropbox_adj, $size[3]-$cropbox_adj); $page->bleedbox($size[0]+$cropbox_adj, $size[1]+$cropbox_adj, $size[2]-$cropbox_adj-$bleedbox_adj, $size[3]-$cropbox_adj-$bleedbox_adj); media_layer($mode, $grfx, @size); content_layer($mode, $grfx, $text, @size); # ->cropbox() should actually trim content printer_marks($mode, $text, $grfx, @size); } return; } sub printer_marks { my ($mode, $text, $grfx, @size) = @_; my $width = 3/pt; my ($x,$y, $xc,$yc); # add some printing instructions $text->font($fontH, 15); $text->fillcolor('black'); $text->translate(($size[0]+$size[2])/2, $size[3]/pt-40/pt); $text->text_center("Print on 20-24 LB clay-coat"); # and crop marks just outside the trim box $grfx->strokecolor('brown'); $grfx->linewidth($width); $x = $size[0] + $cropbox_adj + $trimbox_adj - $width/2; # lower left $y = $size[1] + $cropbox_adj + $trimbox_adj - $width/2; $grfx->move($x,$y - 5/pt); $grfx->vline($y - 5/pt + 20/pt); $grfx->move($x - 5/pt,$y); $grfx->hline($x - 5/pt + 20/pt); $x = $size[0] + $cropbox_adj + $trimbox_adj - $width/2; # upper left $y = $size[3] - $cropbox_adj - $bleedbox_adj - $trimbox_adj + $width/2; $grfx->move($x,$y + 5/pt); $grfx->vline($y + 5/pt - 20/pt); $grfx->move($x - 5/pt,$y); $grfx->hline($x - 5/pt + 20/pt); $x = $size[2] - $cropbox_adj - $bleedbox_adj - $trimbox_adj + $width/2; # upper right $y = $size[3] - $cropbox_adj - $bleedbox_adj - $trimbox_adj + $width/2; $grfx->move($x,$y + 5/pt); $grfx->vline($y + 5/pt - 20/pt); $grfx->move($x + 5/pt,$y); $grfx->hline($x + 5/pt - 20/pt); $x = $size[2] - $cropbox_adj - $bleedbox_adj - $trimbox_adj + $width/2; # lower right $y = $size[1] + $cropbox_adj + $trimbox_adj - $width/2; $grfx->move($x,$y - 5/pt); $grfx->vline($y - 5/pt + 20/pt); $grfx->move($x + 5/pt,$y); $grfx->hline($x + 5/pt - 20/pt); $grfx->stroke(); # and some color alignment dots $xc = $size[2] - $cropbox_adj - $bleedbox_adj/2; $yc = ($size[1] + $size[3])/2 + 10/pt; $grfx->strokecolor('black'); $grfx->linewidth(1); $grfx->fillcolor('black'); $grfx->circle($xc, $yc, 10/pt); $grfx->fill(); $grfx->poly($xc - 12/pt, $yc, $xc + 12/pt, $yc); $grfx->poly($xc, $yc + 12/pt, $xc, $yc - 12/pt); $grfx->stroke(); $yc -= 35/pt; $grfx->fillcolor('yellow'); $grfx->circle($xc, $yc, 10/pt); $grfx->fill(); $grfx->poly($xc - 12/pt, $yc, $xc + 12/pt, $yc); $grfx->poly($xc, $yc + 12/pt, $xc, $yc - 12/pt); $grfx->stroke(); $yc -= 35/pt; $grfx->fillcolor('magenta'); $grfx->circle($xc, $yc, 10/pt); $grfx->fill(); $grfx->poly($xc - 12/pt, $yc, $xc + 12/pt, $yc); $grfx->poly($xc, $yc + 12/pt, $xc, $yc - 12/pt); $grfx->stroke(); $yc -= 35/pt; $grfx->fillcolor('cyan'); $grfx->circle($xc, $yc, 10/pt); $grfx->fill(); $grfx->poly($xc - 12/pt, $yc, $xc + 12/pt, $yc); $grfx->poly($xc, $yc + 12/pt, $xc, $yc - 12/pt); $grfx->stroke(); return; } # --------------- set trim box: emulate effect of paper being cut sub trim_page { my $mode = shift(); $page = $pdf->page(); $grfx = $page->gfx(); $text = $page->text(); # text always overlays graphics $clip = $page->gfx(); # clip (graphics) overlays text if ($mode eq 'dual') { $page->mediabox(@dual_format); my @size = (0,0, @dual_format); media_layer($mode, $grfx, @size); content_layer($mode, $grfx, $text, @size); $text->fillcolor('black'); $text->font($font, 20); $text->translate(400,550); $text->text_center('Set trim box to final paper size.'); $text->translate(400,525); $text->text_center('Won\'t see anything until paper is actually cut.'); # draw crop box on left page in light gray $grfx->linewidth(1); $grfx->linedash(3); $grfx->strokecolor('#999'); # shared with bleed box $grfx->poly(50/pt,50/pt+$cropbox_adj, 375/pt,50/pt+$cropbox_adj); $grfx->stroke(); $grfx->strokecolor('#CCC'); $grfx->poly(50/pt,500/pt-$cropbox_adj, 375/pt,500/pt-$cropbox_adj); $grfx->stroke(); $grfx->strokecolor('#999'); # shared with bleed box $grfx->poly(50/pt+$cropbox_adj,50/pt, 50/pt+$cropbox_adj,500/pt); $grfx->stroke(); $grfx->strokecolor('#CCC'); $grfx->poly(375/pt-$cropbox_adj,50/pt, 375/pt-$cropbox_adj,500/pt); $grfx->stroke(); # now bleed box in med gray on left page (shares left and bottom) $grfx->strokecolor('#999'); $grfx->poly(50/pt,500/pt-$cropbox_adj-$bleedbox_adj, 375/pt,500/pt-$cropbox_adj-$bleedbox_adj); $grfx->poly(375/pt-$cropbox_adj-$bleedbox_adj,50/pt, 375/pt-$cropbox_adj-$bleedbox_adj,500/pt); $grfx->stroke(); # now trim box in black $grfx->strokecolor('black'); $grfx->poly(40/pt,50/pt+$cropbox_adj+$trimbox_adj, 385/pt,50/pt+$cropbox_adj+$trimbox_adj); $grfx->poly(40/pt,500/pt-$cropbox_adj-$bleedbox_adj-$trimbox_adj, 385/pt,500/pt-$cropbox_adj-$bleedbox_adj-$trimbox_adj); $grfx->poly(50/pt+$cropbox_adj+$trimbox_adj,40/pt, 50/pt+$cropbox_adj+$trimbox_adj,510/pt); $grfx->poly(375/pt-$cropbox_adj-$bleedbox_adj-$trimbox_adj,40/pt, 375/pt-$cropbox_adj-$bleedbox_adj-$trimbox_adj,510/pt); $grfx->stroke(); $grfx->linedash(); # emulate appropriate clipping # no additional content removed by bleed box $clip->fillcolor('#E4EFC9'); $clip->rectxy(405/pt,40/pt, 425/pt,510/pt); $clip->rectxy(750/pt,40/pt, 775/pt,510/pt); $clip->fill(); $clip->fillcolor('gray'); $clip->rectxy(425/pt,50/pt, 425/pt+$cropbox_adj+$trimbox_adj,500/pt); $clip->rectxy(750/pt-$cropbox_adj-$bleedbox_adj-$trimbox_adj,50/pt, 750/pt,500/pt); $clip->rectxy(425/pt,50/pt, 750/pt,50/pt+$cropbox_adj+$trimbox_adj); $clip->rectxy(425/pt,500/pt-$cropbox_adj-$bleedbox_adj-$trimbox_adj, 750/pt,500/pt); $clip->fill(); printer_marks($mode, $text, $grfx, 50,50, 375,500); printer_marks($mode, $text, $grfx, 425,50, 750,500); } else { my @size = $page->mediabox($live_format); #$page->cropbox($size[0]+$cropbox_adj, # $size[1]+$cropbox_adj, # $size[2]-$cropbox_adj, # $size[3]-$cropbox_adj); #$page->bleedbox($size[0]+$cropbox_adj, # $size[1]+$cropbox_adj, # $size[2]-$cropbox_adj-$bleedbox_adj, # $size[3]-$cropbox_adj-$bleedbox_adj); # just emulate trimmed paper with small crop box $page->cropbox($size[0]+$cropbox_adj+$trimbox_adj, $size[1]+$cropbox_adj+$trimbox_adj, $size[2]-$cropbox_adj-$bleedbox_adj-$trimbox_adj, $size[3]-$cropbox_adj-$bleedbox_adj-$trimbox_adj); media_layer($mode, $grfx, @size); content_layer($mode, $grfx, $text, @size); # ->cropbox() should actually trim content printer_marks($mode, $text, $grfx, @size); } return; } # --------------- set art box sub art_page { my $mode = shift(); $page = $pdf->page(); $grfx = $page->gfx(); $text = $page->text(); # text always overlays graphics $clip = $page->gfx(); # clip (graphics) overlays text if ($mode eq 'dual') { $page->mediabox(@dual_format); my @size = (0,0, @dual_format); media_layer($mode, $grfx, @size); content_layer($mode, $grfx, $text, @size); $text->fillcolor('black'); $text->font($font, 20); $text->translate(400,550); $text->text_center('Set art box. No visible effect.'); # draw crop box on left page in light gray $grfx->linewidth(1); $grfx->linedash(3); $grfx->strokecolor('#BBB'); # shared with bleed box $grfx->poly(50/pt,50/pt+$cropbox_adj, 375/pt,50/pt+$cropbox_adj); $grfx->stroke(); $grfx->strokecolor('#EEE'); $grfx->poly(50/pt,500/pt-$cropbox_adj, 375/pt,500/pt-$cropbox_adj); $grfx->stroke(); $grfx->strokecolor('#BBB'); # shared with bleed box $grfx->poly(50/pt+$cropbox_adj,50/pt, 50/pt+$cropbox_adj,500/pt); $grfx->stroke(); $grfx->strokecolor('#EEE'); $grfx->poly(375/pt-$cropbox_adj,50/pt, 375/pt-$cropbox_adj,500/pt); $grfx->stroke(); # now bleed box in med gray on left page (shares left and bottom) $grfx->strokecolor('#BBB'); $grfx->poly(50/pt,500/pt-$cropbox_adj-$bleedbox_adj, 375/pt,500/pt-$cropbox_adj-$bleedbox_adj); $grfx->poly(375/pt-$cropbox_adj-$bleedbox_adj,50/pt, 375/pt-$cropbox_adj-$bleedbox_adj,500/pt); $grfx->stroke(); # now trim box in dark gray for top, black for others # (shared with art box) $grfx->strokecolor('#999'); $grfx->poly(50/pt,500/pt-$cropbox_adj-$bleedbox_adj-$trimbox_adj, 375/pt,500/pt-$cropbox_adj-$bleedbox_adj-$trimbox_adj); $grfx->stroke(); $grfx->strokecolor('black'); $grfx->poly(40/pt,50/pt+$cropbox_adj+$trimbox_adj, 385/pt,50/pt+$cropbox_adj+$trimbox_adj); $grfx->poly(50/pt+$cropbox_adj+$trimbox_adj,40/pt, 50/pt+$cropbox_adj+$trimbox_adj,510/pt); $grfx->poly(375/pt-$cropbox_adj-$bleedbox_adj-$trimbox_adj,40/pt, 375/pt-$cropbox_adj-$bleedbox_adj-$trimbox_adj,510/pt); # art box in black. only top is different from trim box $grfx->poly(40/pt,500/pt-110/pt, 385/pt,500/pt-110/pt); $grfx->stroke(); $grfx->linedash(); # emulate appropriate clipping # no additional content removed by art box $clip->fillcolor('#E4EFC9'); $clip->rectxy(405/pt,40/pt, 425/pt,510/pt); $clip->rectxy(750/pt,40/pt, 775/pt,510/pt); $clip->fill(); $clip->fillcolor('gray'); $clip->rectxy(425/pt,50/pt, 425/pt+$cropbox_adj+$trimbox_adj,500/pt); $clip->rectxy(750/pt-$cropbox_adj-$bleedbox_adj-$trimbox_adj,50/pt, 750/pt,500/pt); $clip->rectxy(425/pt,50/pt, 750/pt,50/pt+$cropbox_adj+$trimbox_adj); $clip->rectxy(425/pt,500/pt-110/pt, 750/pt,500/pt); $clip->fill(); printer_marks($mode, $text, $grfx, 50,50, 375,500); printer_marks($mode, $text, $grfx, 425,50, 750,500); } else { my @size = $page->mediabox($live_format); #$page->cropbox($size[0]+$cropbox_adj, # $size[1]+$cropbox_adj, # $size[2]-$cropbox_adj, # $size[3]-$cropbox_adj); #$page->bleedbox($size[0]+$cropbox_adj, # $size[1]+$cropbox_adj, # $size[2]-$cropbox_adj-$bleedbox_adj, # $size[3]-$cropbox_adj-$bleedbox_adj); # just emulate trimmed paper with small crop box $page->cropbox($size[0]+$cropbox_adj+$trimbox_adj, $size[1]+$cropbox_adj+$trimbox_adj, $size[2]-$cropbox_adj-$bleedbox_adj-$trimbox_adj, $size[3]-110/pt); media_layer($mode, $grfx, @size); content_layer($mode, $grfx, $text, @size); # ->cropbox() should actually trim content printer_marks($mode, $text, $grfx, @size); } return; } PDF-Builder-3.026/examples/026_unifont20000644000000000000000000000552314534467462016137 0ustar rootroot#!/usr/bin/perl # Display a selection of Unicode character pages in various fonts. 9 pages. # Note that this is not strictly Unicode, especially in 00-FF, but closer # to MS CP-1252. use strict; use warnings; use File::Basename; use PDF::Builder; use PDF::Builder::Util; use Unicode::UCD 'charinfo'; use Encode qw[:all]; use Getopt::Long; use utf8; #my $compress = 'none'; # uncompress streams my $compress = 'flate'; # compressed streams my $api = PDF::Builder->new(-compress => $compress); $api->mediabox(595,842); my $helv = $api->corefont('Helvetica-Bold', -encode=>'latin1'); my $ge = $api->corefont('Times-Roman', -encode=>'latin1'); my $g2 = $api->corefont('Times-Roman', -encode=>'uni1'); my $g3 = $api->corefont('Times-Roman', -encode=>'uni2'); my $g4 = $api->corefont('Times-Roman', -encode=>'uni3'); my $g5 = $api->corefont('Times-Roman', -encode=>'uni4'); my $g6 = $api->corefont('Times-Roman', -encode=>'uni5'); my $zf = $api->corefont('zapfdingbats'); my $wd = $api->corefont('wingdings'); my $sx = 33; my $sy = 45; my $fx = 20; my ($uf); my @label = (); $label[ 0] = '0000 - 00FF Basic Latin (ASCII) and Latin-1'; $label[ 1] = '0100 - 01FF Latin Extended-A and part of -B'; $label[ 2] = '0200 - 02FF rem. Latin Ext-B, IPA, Spacing Modifiers'; $label[ 3] = '0300 - 03FF Comb. diacriticals, Greek and Coptic'; $label[ 4] = '0400 - 04FF Cyrillic'; $label[ 5] = '0500 - 05FF Cyrillic supplementary, Armenian, Hebrew'; $label[0x26] = '2600 - 26FF Miscellaneous Symbols'; $label[0x27] = '2700 - 27FF Dingbats'; $label[0xf0] = 'F000 - F0FF (Private Use, shiftJIS encoded)'; $uf = $api->unifont( $ge, [$g2, [1]], [$g3, [2]], [$g4, [3]], [$g5, [4]], [$g6, [5]], [$zf, [0x26,0x27]], [$wd, [0xf0]], -encode=>'shiftjis'); my $toprow = 50 + $sy*15; my $leftcol = 50; # block is starting offset in Unicode (block of 256 characters) foreach my $block (0,1,2,3,4,5,0x26,0x27,0xf0) { print STDERR "."; # one page being output my $page = $api->page(); $page->mediabox(595,842); my $gfx = $page->gfx(); delete $gfx->{'Filter'}; my $text = $page->text(); # label page $text->textlabel($leftcol, 50+$toprow, $helv, 20, $label[$block]); # character is Unicode $block*256 + $y*16 + $x (0..255), arranged in grid # 00 at upper left to FF in lower right foreach my $y (0..15) { # row T to B foreach my $x (0..15) { # column L to R # character (no bounding box) $text->textlabel($leftcol+($sx*$x), $toprow-($sy*$y), $uf, $fx, pack('U',$block*256+$y*16+$x)); # label (Unicode name) below, at a slant to fit horizontally $text->textlabel($leftcol+($sx*$x), $toprow-($sy*$y)-6, $helv, 6, nameByUni($block*256+$y*16+$x), -color=>'#a00000', -hscale=>80, -rotate=>-15); } } } $api->saveas("$0.pdf"); $api->end(); print STDERR "\n"; __END__ PDF-Builder-3.026/examples/Bspline.pl0000644000000000000000000006666614534467462016031 0ustar rootroot#!/usr/bin/perl # exercise Content.pm's bspline call as much as possible # outputs Bspline.pdf # author: Phil M Perry # notes on display: # # -debug settings: 0 = only black line of final Bezier spline (default) # 1 = draw filled green circles of given points (incl move-to) # 2 = draw thick green line of polyline between points # 3 = draw thin blue line of natural tangent at each point # 4 = draw red open circle control points if curve, with # dashed red line connecting to associated point # Note that debug drawings are fixed in Content.pm's bspline() call and # only the black line output is handled here. # # -firstseg controls display and shape of first segment (from current point) # -lastseg controls display and shape of last segment (to final point) # 'curve' = draw Bezier curve (default) # 'line2' = draw straight line between points, forcing new tangents # 'line1' = draw curve, but constrain at "end" point to be on polyline # 'constraint2' = like 'line2', but not drawn # 'constraint1' = like 'line1', but not drawn # # -ratio value > 0 as distance of a curve's control point from its associated # end point, as a fraction of the polyline distance to the next point # # -colinear # 'curve' = attempt to draw Bezier curve from or to a colinear point # 'line' = force a line segment (equals polyline segment) between adjacent # colinear points use warnings; use strict; our $VERSION = '3.026'; # VERSION our $LAST_UPDATE = '3.021'; # manually update whenever code is changed use Math::Trig; use List::Util qw(min max); #use constant in => 1 / 72; #use constant cm => 2.54 / 72; #use constant mm => 25.4 / 72; #use constant pt => 1; use PDF::Builder; my $PDFname = $0; $PDFname =~ s/\..*$//; # remove extension $PDFname .= '.pdf'; # add new extension my $globalX = 0; my $globalY = 0; my $compress = 'none'; #my $compress = 'flate'; my $pdf = PDF::Builder->new(-compress => $compress); my ($page, $grfx, $text); # objects for page, graphics, text my (@points, $i); my ($font); my @axisOffset = (5, 5); # clear the edge of the cell my $db = 4; # debug level my $pageNo = 0; # ================ pg 1 nextPage(); # next (first) page of output, 595pt wide x 792pt high my $fontR = $pdf->corefont('Times-Roman'); my $fontI = $pdf->corefont('Times-Italic'); my $fontC = $pdf->corefont('Courier'); # --------------------------------------- my ($voffset, $hoffset, @pts); $grfx->strokecolor('black'); $grfx->linewidth(1); $grfx->linedash(); # @points includes first (move to) point # ================ pg 1 # duplicate points removal row 1 @points = (10,10, 10,10, 10,10, 10,10); # all same point (no-op) _movedraw(30,700, '1.1', 'show nothing, 1 pt total'); $grfx->bspline(\@pts, -debug=>$db); $grfx->stroke(); @points = (10,10, 10,10, 50,50, 50,50); # line segment _movedraw(100,700, '1.2', '2 pt, single line segment'); $grfx->bspline(\@pts, -debug=>$db); $grfx->stroke(); # degenerate cases row 2,3 @points = (10,10, 50,50); # line segment _movedraw(30,600, '2.1', 'single line segment'); $grfx->bspline(\@pts, -debug=>$db); $grfx->stroke(); @points = (10,10, 50,50, 90,90); # 2 colinear line segments _movedraw(100,600, '2.2', 'straight line of 2 segments'); $grfx->bspline(\@pts, -debug=>$db); $grfx->stroke(); @points = (10,10, 30,50, 90,20); # 3 points non-colinear _movedraw(200,600, '2.3', '2 curves thru 3 pts'); $grfx->bspline(\@pts, -debug=>$db); $grfx->stroke(); # loop-de-loop to a single point, repeating base point @points = (10,10, 40,30, 70,60, 40,30, 60,10); _movedraw(350,600, '2.4', 'tight loop'); $grfx->bspline(\@pts, -debug=>$db); $grfx->stroke(); @points = (10,10, 30,50, 90,20); # 3 points non-colinear _movedraw(200,600, '2.3', '2 curves thru 3 pts'); # line2 forced to line1 since only two segments _movedraw(30,500, '3.1', '2 segments lineX forced to line1 both'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line2', -lastseg=>'line2'); $grfx->stroke(); # same as _movedraw(140,500, '3.2', '2 segments lineX forced to line1 both'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line1', -lastseg=>'line1'); $grfx->stroke(); _movedraw(250,500, '3.3', '2 segments lineX forced to line1 both'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line1', -lastseg=>'line2'); $grfx->stroke(); _movedraw(360,500, '3.4', '2 segments lineX forced to line1 both'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line2', -lastseg=>'line1'); $grfx->stroke(); # 3 colinear points beginning and end row 4 @points = (10,10, 30,30, 50,50, 90,50, 110,30, 130,10); _movedraw(30,400, '4.1', 'ends 2 straight, arc between'); $grfx->bspline(\@pts, -debug=>$db); $grfx->stroke(); @points = (10,10, 30,10, 50,10, 90,50, 110,50, 130,50); _movedraw(180,400, '4.2', 'S-shaped curve, ends 2 straight'); $grfx->bspline(\@pts, -debug=>$db); $grfx->stroke(); @points = (10,10, 30,10, 50,10, 30,50, 50,50, 70,50); _movedraw(350,400, '4.3', 'more extreme S-shaped curve, ends 2 straight'); $grfx->bspline(\@pts, -debug=>$db); $grfx->stroke(); _movedraw(480,400, '4.4', 'like 4.3 but longer control lines'); $grfx->bspline(\@pts, -debug=>$db, -ratio=>0.75); $grfx->stroke(); # one simple curve row 5 @points = (10,10, 30,50, 90,20, 150,40); _movedraw(30,300, '5.1', '3 curved segments'); $grfx->bspline(\@pts, -debug=>$db); $grfx->stroke(); # force first and last to lines _movedraw(230,300, '5.2', 'ends forced straight lines, center S-curve'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line2', -lastseg=>'line2'); $grfx->stroke(); _movedraw(400,280, '5.3', 'like 5.2 but longer control lines'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line2', -lastseg=>'line2', -ratio=>1); $grfx->stroke(); # long end colinears row 6 @points = (10,10, 20,12, 30,14, 40,16, 50,18, 60,20, 70,22, 80,24); _movedraw(30,230, '6.1', '7 straight segments in a row'); $grfx->bspline(\@pts, -debug=>$db); $grfx->stroke(); # short interior colinears row 6 @points = (20,10, 30,30, 50,30, 70,30, 80,10); _movedraw(120,200, '6.2', '4 curved, center 2 nearly flat'); $grfx->bspline(\@pts, -debug=>$db); $grfx->stroke(); @points = (20,10, 30,30, 50,30, 70,30, 80,50); _movedraw(235,200, '6.3', '4 curved, center 2 nearly flat'); $grfx->bspline(\@pts, -debug=>$db); $grfx->stroke(); # longer interior colinears row 6 @points = (20,10, 30,30, 50,30, 70,30, 90,30, 100,10); _movedraw(340,200, '6.4', 'like 6.2 but 3 nearly flat in center'); $grfx->bspline(\@pts, -debug=>$db); $grfx->stroke(); @points = (20,10, 30,30, 50,30, 70,30, 90,30, 100,50); _movedraw(470,200, '6.5', 'like 6.4 but 3 nearly flat in center'); $grfx->bspline(\@pts, -debug=>$db); $grfx->stroke(); # even longer interior colinears row 7 @points = (20,10, 30,30, 50,30, 70,30, 90,30, 110,30, 120,10); _movedraw(30,100, '7.1', 'like 6.4 but 4 nearly flat in center'); $grfx->bspline(\@pts, -debug=>$db); $grfx->stroke(); @points = (20,10, 30,30, 50,30, 70,30, 90,30, 110,30, 120,50); _movedraw(170,100, '7.2', 'like 6.5 but 4 nearly flat in center'); $grfx->bspline(\@pts, -debug=>$db); $grfx->stroke(); # shorter interior colinears with lines row 7 @points = (20,10, 30,30, 50,30, 70,30, 90,30, 100,10); _movedraw(340,100, '7.3', 'like 6.4 but center forced line'); $grfx->bspline(\@pts, -debug=>$db, -colinear=>'line'); $grfx->stroke(); @points = (20,10, 30,30, 50,30, 70,30, 90,30, 100,50); _movedraw(470,100, '7.4', 'like 6.5 but center forced line'); $grfx->bspline(\@pts, -debug=>$db, -colinear=>'line'); $grfx->stroke(); # even longer interior colinears row 8 @points = (20,10, 30,30, 50,30, 70,30, 90,30, 110,30, 120,10); _movedraw(30,10, '8.1', 'like 7.1 but 2 center forced lines'); $grfx->bspline(\@pts, -debug=>$db, -colinear=>'line'); $grfx->stroke(); @points = (20,10, 30,30, 50,30, 70,30, 90,30, 110,30, 120,50); _movedraw(170,10, '8.2', 'like 7.2 but 2 center forced lines'); $grfx->bspline(\@pts, -debug=>$db, -colinear=>'line'); $grfx->stroke(); # ================ pg 2 nextPage(); # try a bunch of constraints $grfx->strokecolor('black'); $grfx->linewidth(1); $grfx->linedash(); # @points includes first (move to) point # duplicate points removal row 1 @points = (10,10, 10,10, 10,10, 10,10); # all same point (no-op) _movedraw(30,700, '1.1', 'like 1-1.1'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'curve', -lastseg=>'curve'); $grfx->stroke(); @points = (10,10, 10,10, 50,50, 50,50); # line segment _movedraw(100,700, '1.2', 'like 1-1.2'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'curve', -lastseg=>'curve'); $grfx->stroke(); # degenerate cases row 2,3 @points = (10,10, 50,50); # line segment _movedraw(30,600, '2.1', 'like 1-2.1'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'constraint2', -lastseg=>'constraint1'); $grfx->stroke(); @points = (10,10, 50,50, 90,90); # 2 colinear line segments _movedraw(100,600, '2.2', 'like 1-2.2'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'constraint2', -lastseg=>'constraint1'); $grfx->stroke(); @points = (10,10, 30,50, 90,20); # 3 points non-colinear _movedraw(200,600, '2.3', '2 curves that blend to straight lines due to override of constraintX by line1'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'constraint2', -lastseg=>'constraint1'); $grfx->stroke(); # line2 forced to line1 since only two segments _movedraw(30,500, '3.1', 'like 2.3 as forced to line1'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line2', -lastseg=>'line2'); $grfx->stroke(); # same as _movedraw(140,500, '3.2', 'like 2.3 as forced to line1'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line1', -lastseg=>'line1'); $grfx->stroke(); _movedraw(250,500, '3.3', 'like 2.3 as forced to line1'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line1', -lastseg=>'line2'); $grfx->stroke(); _movedraw(360,500, '3.4', 'like 2.3 as forced to line1'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line2', -lastseg=>'line1'); $grfx->stroke(); # 3 colinear points beginning and end row 4 @points = (10,10, 30,30, 50,50, 90,50, 110,30, 130,10); _movedraw(30,400, '4.1', 'like 1-4.1 but first and last segments gone and colinearity overrides constraint1 to force constraint2'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'constraint2', -lastseg=>'constraint1'); $grfx->stroke(); @points = (10,10, 30,10, 50,10, 90,50, 110,50, 130,50); _movedraw(180,400, '4.2', 'like 1-4.2 but first and last segments gone and colinearity overrides constraint1 to force constraint2'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'constraint2', -lastseg=>'constraint1'); $grfx->stroke(); @points = (10,10, 30,10, 50,10, 30,50, 50,50, 70,50); _movedraw(350,400, '4.3', 'like 1-4.3 but first and last segments gone'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'constraint2', -lastseg=>'constraint1'); $grfx->stroke(); _movedraw(480,400, '4.4', 'like 1-4.4 but first and last segments gone with longer control points making more extreme S-curve'); $grfx->bspline(\@pts, -debug=>$db, -ratio=>0.75, -firstseg=>'constraint2', -lastseg=>'constraint1'); $grfx->stroke(); # one simple curve row 5 @points = (10,10, 30,50, 90,20, 150,40); _movedraw(30,300, '5.1', 'invisible left end straight line causing curve to match, invisible right end curve matches tangent, end tangent is polyline'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'constraint2', -lastseg=>'constraint1'); $grfx->stroke(); # force first and last to lines _movedraw(230,300, '5.2', 'ends forced to straight lines (line2), center curve matches end lines at their tangents'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line2', -lastseg=>'line2'); $grfx->stroke(); _movedraw(400,280, '5.3', 'like 5.2 but more extreme from longer control lines'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line2', -lastseg=>'line2', -ratio=>1); $grfx->stroke(); # long end colinears row 6 @points = (10,10, 20,12, 30,14, 40,16, 50,18, 60,20, 70,22, 80,24); _movedraw(30,230, '6.1', 'like 1-6.1 with end segments not drawn'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'constraint2', -lastseg=>'constraint1'); $grfx->stroke(); # short interior colinears row 6 @points = (20,10, 30,30, 50,30, 70,30, 80,10); _movedraw(120,200, '6.2', 'ends not drawn, left is line, right is curve, drawn line tangents match'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'constraint2', -lastseg=>'constraint1'); $grfx->stroke(); @points = (20,10, 30,30, 50,30, 70,30, 80,50); _movedraw(235,200, '6.3', 'ends not drawn, left is line, right is curve, drawn line tangents match'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'constraint2', -lastseg=>'constraint1'); $grfx->stroke(); # longer interior colinears row 6 @points = (20,10, 30,30, 50,30, 70,30, 90,30, 100,10); _movedraw(340,200, '6.4', 'like 1-6.4 but end segments not drawn and tangents match'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'constraint2', -lastseg=>'constraint1'); $grfx->stroke(); @points = (20,10, 30,30, 50,30, 70,30, 90,30, 100,50); _movedraw(470,200, '6.5', 'like 1-6.5 but end segments not drawn and tangents match'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'constraint2', -lastseg=>'constraint1'); $grfx->stroke(); # even longer interior colinears row 7 @points = (20,10, 30,30, 50,30, 70,30, 90,30, 110,30, 120,10); _movedraw(30,100, '7.1', 'like 6.4 but new center point is flat'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'constraint2', -lastseg=>'constraint1'); $grfx->stroke(); @points = (20,10, 30,30, 50,30, 70,30, 90,30, 110,30, 120,50); _movedraw(170,100, '7.2', 'like 6.5 but new center point'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'constraint2', -lastseg=>'constraint1'); $grfx->stroke(); # shorter interior colinears with lines row 7 @points = (20,10, 30,30, 50,30, 70,30, 90,30, 100,10); _movedraw(340,100, '7.3', 'like 6.4 but force center line'); $grfx->bspline(\@pts, -debug=>$db, -colinear=>'line', -firstseg=>'constraint2', -lastseg=>'constraint1'); $grfx->stroke(); @points = (20,10, 30,30, 50,30, 70,30, 90,30, 100,50); _movedraw(470,100, '7.4', 'like 6.5 but force center line'); $grfx->bspline(\@pts, -debug=>$db, -colinear=>'line', -firstseg=>'constraint2', -lastseg=>'constraint1'); $grfx->stroke(); # even longer interior colinears row 8 @points = (20,10, 30,30, 50,30, 70,30, 90,30, 110,30, 120,10); _movedraw(30,10, '8.1', 'like 7.1 but force 2 center lines'); $grfx->bspline(\@pts, -debug=>$db, -colinear=>'line', -firstseg=>'constraint2', -lastseg=>'constraint1'); $grfx->stroke(); @points = (20,10, 30,30, 50,30, 70,30, 90,30, 110,30, 120,50); _movedraw(170,10, '8.2', 'like 7.2 but force 2 center lines'); $grfx->bspline(\@pts, -debug=>$db, -colinear=>'line', -firstseg=>'constraint2', -lastseg=>'constraint1'); $grfx->stroke(); # ================ pg 3 nextPage(); # try a bunch of constraints $grfx->strokecolor('black'); $grfx->linewidth(1); $grfx->linedash(); # @points includes first (move to) point # duplicate points removal row 1 @points = (10,10, 10,10, 10,10, 10,10); # all same point (no-op) _movedraw(30,700, '1.1', 'like 2-1.1'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'curve', -lastseg=>'curve'); $grfx->stroke(); @points = (10,10, 10,10, 50,50, 50,50); # line segment _movedraw(100,700, '1.2', 'like 2-1.2'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'curve', -lastseg=>'curve'); $grfx->stroke(); # degenerate cases row 2,3 @points = (10,10, 50,50); # line segment _movedraw(30,600, '2.1', 'like 2-2.1'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'constraint1', -lastseg=>'constraint2'); $grfx->stroke(); @points = (10,10, 50,50, 90,90); # 2 colinear line segments _movedraw(100,600, '2.2', 'like 2-2.2'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'constraint1', -lastseg=>'constraint2'); $grfx->stroke(); @points = (10,10, 30,50, 90,20); # 3 points non-colinear _movedraw(200,600, '2.3', 'like 2-2.3'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'constraint1', -lastseg=>'constraint2'); $grfx->stroke(); # line2 forced to line1 since only two segments _movedraw(30,500, '3.1', 'like 2-3.1'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line2', -lastseg=>'line2'); $grfx->stroke(); # same as _movedraw(140,500, '3.2', 'like 2-3.2'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line1', -lastseg=>'line1'); $grfx->stroke(); _movedraw(250,500, '3.3', 'like 2-3.3'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line1', -lastseg=>'line2'); $grfx->stroke(); _movedraw(360,500, '3.4', 'like 2-3.4'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line2', -lastseg=>'line1'); $grfx->stroke(); # 3 colinear points beginning and end row 4 @points = (10,10, 30,30, 50,50, 90,50, 110,30, 130,10); _movedraw(30,400, '4.1', 'like 2-4.1'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'constraint1', -lastseg=>'constraint2'); $grfx->stroke(); @points = (10,10, 30,10, 50,10, 90,50, 110,50, 130,50); _movedraw(180,400, '4.2', 'like 2-4.2'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'constraint1', -lastseg=>'constraint2'); $grfx->stroke(); @points = (10,10, 30,10, 50,10, 30,50, 50,50, 70,50); _movedraw(350,400, '4.3', 'like 2-4.3'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'constraint1', -lastseg=>'constraint2'); $grfx->stroke(); _movedraw(480,400, '4.4', 'like 2-4.4'); $grfx->bspline(\@pts, -debug=>$db, -ratio=>0.75, -firstseg=>'constraint1', -lastseg=>'constraint2'); $grfx->stroke(); # one simple curve row 5 @points = (10,10, 30,50, 90,20, 150,40); _movedraw(30,300, '5.1', 'end segs invisible, left curve right line, center tangents match'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'constraint1', -lastseg=>'constraint2'); $grfx->stroke(); # force first and last to lines _movedraw(230,300, '5.2', 'like 2-5.2'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line2', -lastseg=>'line2'); $grfx->stroke(); _movedraw(400,280, '5.3', 'like 2-5.3'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line2', -lastseg=>'line2', -ratio=>1); $grfx->stroke(); # long end colinears row 6 @points = (10,10, 20,12, 30,14, 40,16, 50,18, 60,20, 70,22, 80,24); _movedraw(30,230, '6.1', 'like 2-6.1, colinearity overrides constraint1 to constraint2'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'constraint1', -lastseg=>'constraint2'); $grfx->stroke(); # short interior colinears row 6 @points = (20,10, 30,30, 50,30, 70,30, 80,10); _movedraw(120,200, '6.2', 'left invisible curve, right invisible line, curve tangents match'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'constraint1', -lastseg=>'constraint2'); $grfx->stroke(); @points = (20,10, 30,30, 50,30, 70,30, 80,50); _movedraw(235,200, '6.3', 'left invisible curve, right invisible line, curve tangents match'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'constraint1', -lastseg=>'constraint2'); $grfx->stroke(); # longer interior colinears row 6 @points = (20,10, 30,30, 50,30, 70,30, 90,30, 100,10); _movedraw(340,200, '6.4', 'like 6.2 but extra colinear point in middle'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'constraint1', -lastseg=>'constraint2'); $grfx->stroke(); @points = (20,10, 30,30, 50,30, 70,30, 90,30, 100,50); _movedraw(470,200, '6.5', 'like 6.3 but extra colinear point in middle'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'constraint1', -lastseg=>'constraint2'); $grfx->stroke(); # even longer interior colinears row 7 @points = (20,10, 30,30, 50,30, 70,30, 90,30, 110,30, 120,10); _movedraw(30,100, '7.1', 'like 6.4 but new flat center point'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'constraint1', -lastseg=>'constraint2'); $grfx->stroke(); @points = (20,10, 30,30, 50,30, 70,30, 90,30, 110,30, 120,50); _movedraw(170,100, '7.2', 'like 6.5 but new center point'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'constraint1', -lastseg=>'constraint2'); $grfx->stroke(); # shorter interior colinears with lines row 7 @points = (20,10, 30,30, 50,30, 70,30, 90,30, 100,10); _movedraw(340,100, '7.3', 'like 6.4 but force center to line'); $grfx->bspline(\@pts, -debug=>$db, -colinear=>'line', -firstseg=>'constraint1', -lastseg=>'constraint2'); $grfx->stroke(); @points = (20,10, 30,30, 50,30, 70,30, 90,30, 100,50); _movedraw(470,100, '7.4', 'like 6.5 but force center to line'); $grfx->bspline(\@pts, -debug=>$db, -colinear=>'line', -firstseg=>'constraint1', -lastseg=>'constraint2'); $grfx->stroke(); # even longer interior colinears row 8 @points = (20,10, 30,30, 50,30, 70,30, 90,30, 110,30, 120,10); _movedraw(30,10, '8.1', 'like 7.1 but force center 2 segments to lines'); $grfx->bspline(\@pts, -debug=>$db, -colinear=>'line', -firstseg=>'constraint1', -lastseg=>'constraint2'); $grfx->stroke(); @points = (20,10, 30,30, 50,30, 70,30, 90,30, 110,30, 120,50); _movedraw(170,10, '8.2', 'like 7.2 but force center 2 segments to lines'); $grfx->bspline(\@pts, -debug=>$db, -colinear=>'line', -firstseg=>'constraint1', -lastseg=>'constraint2'); $grfx->stroke(); # ================ pg 4 nextPage(); # try a bunch of lines $grfx->strokecolor('black'); $grfx->linewidth(1); $grfx->linedash(); # @points includes first (move to) point # duplicate points removal row 1 @points = (10,10, 10,10, 10,10, 10,10); # all same point (no-op) _movedraw(30,700, '1.1', 'like 3-1.1'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'curve', -lastseg=>'curve'); $grfx->stroke(); @points = (10,10, 10,10, 50,50, 50,50); # line segment _movedraw(100,700, '1.2', 'like 3-1.2'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'curve', -lastseg=>'curve'); $grfx->stroke(); # degenerate cases row 2,3 @points = (10,10, 50,50); # line segment _movedraw(30,600, '2.1', 'like 3-2.1'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line2', -lastseg=>'line1'); $grfx->stroke(); @points = (10,10, 50,50, 90,90); # 2 colinear line segments _movedraw(100,600, '2.2', 'like 3-2.2'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line2', -lastseg=>'line1'); $grfx->stroke(); @points = (10,10, 30,50, 90,20); # 3 points non-colinear _movedraw(200,600, '2.3', 'like 3-2.3'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line2', -lastseg=>'line1'); $grfx->stroke(); # line2 forced to line1 since only two segments _movedraw(30,500, '3.1', 'like 3-3.1'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line2', -lastseg=>'line2'); $grfx->stroke(); # same as _movedraw(140,500, '3.2', 'like 3-3.2'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line1', -lastseg=>'line1'); $grfx->stroke(); _movedraw(250,500, '3.3', 'like 3-3.3'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line1', -lastseg=>'line2'); $grfx->stroke(); _movedraw(360,500, '3.4', 'like 3-3.4'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line2', -lastseg=>'line1'); $grfx->stroke(); # 3 colinear points beginning and end row 4 @points = (10,10, 30,30, 50,50, 90,50, 110,30, 130,10); _movedraw(30,400, '4.1', 'left line1 overridden by colinearity, right line2 line anyway'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line2', -lastseg=>'line1'); $grfx->stroke(); @points = (10,10, 30,10, 50,10, 90,50, 110,50, 130,50); _movedraw(180,400, '4.2', 'right line1 overridden by colinearity, left line2 line anyway'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line2', -lastseg=>'line1'); $grfx->stroke(); @points = (10,10, 30,10, 50,10, 30,50, 50,50, 70,50); _movedraw(350,400, '4.3', 'like 4.2 but more extreme S-curve'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line2', -lastseg=>'line1'); $grfx->stroke(); _movedraw(480,400, '4.4', 'like 4.3 but longer control points'); $grfx->bspline(\@pts, -debug=>$db, -ratio=>0.75, -firstseg=>'line2', -lastseg=>'line1'); $grfx->stroke(); # one simple curve row 5 @points = (10,10, 30,50, 90,20, 150,40); _movedraw(30,300, '5.1', 'force line left end, force constrained curve right end'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line2', -lastseg=>'line1'); $grfx->stroke(); # force first and last to lines _movedraw(230,300, '5.2', 'force lines both ends, curve tangents match'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line2', -lastseg=>'line2'); $grfx->stroke(); _movedraw(400,280, '5.3', 'like 5.2 with longer control points for more extreme S-curve'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line2', -lastseg=>'line2', -ratio=>1); $grfx->stroke(); # long end colinears row 6 @points = (10,10, 20,12, 30,14, 40,16, 50,18, 60,20, 70,22, 80,24); _movedraw(30,230, '6.1', 'right end line1 overridden to line by colinearity'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line2', -lastseg=>'line1'); $grfx->stroke(); # short interior colinears row 6 @points = (20,10, 30,30, 50,30, 70,30, 80,10); _movedraw(120,200, '6.2', 'force left line, right constrained curve, tangents match'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line2', -lastseg=>'line1'); $grfx->stroke(); @points = (20,10, 30,30, 50,30, 70,30, 80,50); _movedraw(235,200, '6.3', 'force left line, right constrained curve, tangents match'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line2', -lastseg=>'line1'); $grfx->stroke(); # longer interior colinears row 6 @points = (20,10, 30,30, 50,30, 70,30, 90,30, 100,10); _movedraw(340,200, '6.4', 'like 6.2 with extra middle point'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line2', -lastseg=>'line1'); $grfx->stroke(); @points = (20,10, 30,30, 50,30, 70,30, 90,30, 100,50); _movedraw(470,200, '6.5', 'like 6.3 with extra middle point'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line2', -lastseg=>'line1'); $grfx->stroke(); # even longer interior colinears row 7 @points = (20,10, 30,30, 50,30, 70,30, 90,30, 110,30, 120,10); _movedraw(30,100, '7.1', 'like 6.4 with new flat center point'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line2', -lastseg=>'line1'); $grfx->stroke(); @points = (20,10, 30,30, 50,30, 70,30, 90,30, 110,30, 120,50); _movedraw(170,100, '7.2', 'like 6.5 with new center point'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line2', -lastseg=>'line1'); $grfx->stroke(); # shorter interior colinears with lines row 7 @points = (20,10, 30,30, 50,30, 70,30, 90,30, 100,10); _movedraw(340,100, '7.3', 'like 6.4 with center segment forced to line'); $grfx->bspline(\@pts, -debug=>$db, -colinear=>'line', -firstseg=>'line2', -lastseg=>'line1'); $grfx->stroke(); @points = (20,10, 30,30, 50,30, 70,30, 90,30, 100,50); _movedraw(470,100, '7.4', 'like 6.5 with center segment forced to line'); $grfx->bspline(\@pts, -debug=>$db, -colinear=>'line', -firstseg=>'line2', -lastseg=>'line1'); $grfx->stroke(); # even longer interior colinears row 8 @points = (20,10, 30,30, 50,30, 70,30, 90,30, 110,30, 120,10); _movedraw(30,10, '8.1', 'like 7.1 but center colinear segments forced to lines'); $grfx->bspline(\@pts, -debug=>$db, -colinear=>'line', -firstseg=>'line2', -lastseg=>'line1'); $grfx->stroke(); @points = (20,10, 30,30, 50,30, 70,30, 90,30, 110,30, 120,50); _movedraw(170,10, '8.2', 'like 7.2 but center colinear segments forced to lines'); $grfx->bspline(\@pts, -debug=>$db, -colinear=>'line', -firstseg=>'line2', -lastseg=>'line1'); $grfx->stroke(); $pdf->saveas($PDFname); # --------------------------------------- # move to first set of points, copy remainder into @pts sub _movedraw { my ($hoffset, $voffset, $label, $explain) = @_; if (!defined $explain) { $explain = ''; } #print "$label\n"; $grfx->move($points[0]+$hoffset, $points[1]+$voffset +2); @pts = (); for ($i=2; $ifont($font, 10); $text->translate($hoffset, $voffset); $text->text($label); # explain fitted in a column $text->font($font, 5); my $line_count = 0; my $w; while ($explain ne '') { $text->translate($hoffset+15, $voffset+3-6*$line_count++); ($w, $explain) = $text->text_fill_left($explain, 15*5); } return; } # --------------------------------------- sub nextPage { $pageNo++; $page = $pdf->page(); $grfx = $page->gfx(); $text = $page->text(); $page->mediabox('Universal'); $font = $pdf->corefont('Times-Roman'); $text->translate(595/2,15); $text->font($font, 10); $text->fillcolor('black'); $text->text_center("-$pageNo-"); # prefill page number before any other content return; } PDF-Builder-3.026/examples/011_open_update0000644000000000000000000000305414534467462016665 0ustar rootroot#!/usr/bin/perl use strict; use warnings; use lib '../lib'; use PDF::Builder; use PDF::Builder::Util; use PDF::Builder::Content; #my $compress = 'none'; # uncompressed streams my $compress = 'flate'; # compressed streams my ($str); # create a "Hello World!" PDF called BASE my $pdf = PDF::Builder->new(-compress => $compress); my $f1 = $pdf->corefont('Verdana'); my $page = $pdf->page(); $page->mediabox(595,842); my $text = $page->text(); $text->textlabel(50,780, $f1, 20, "Hello World!"); $pdf->saveas("$0.BASE.pdf"); $pdf->end(); # open and read BASE, rewrite "Hello World! (2)", save as UPDATED $pdf = PDF::Builder->open("$0.BASE.pdf", -compress => $compress); $f1 = $pdf->corefont('Verdana'); $page = $pdf->page(); $page->mediabox(595,842); $text = $page->text(); $text->textlabel(50,780, $f1, 20, "Hello World! (2)"); $pdf->saveas("$0.UPDATED.pdf"); $pdf->end(); # open and read UPDATED, rewrite "Hello World! (3)", save as string $str $pdf = PDF::Builder->open("$0.UPDATED.pdf", -compress => $compress); $f1 = $pdf->corefont('Verdana'); $page = $pdf->page(); $page->mediabox(595,842); $text = $page->text(); $text->textlabel(50,780, $f1, 20, "Hello World! (3)"); $str = $pdf->to_string(); $pdf->end(); # open and read string $str, rewrite "Hello World! (4)", save as STRING $pdf = PDF::Builder->from_string($str, -compress => $compress); $f1 = $pdf->corefont('Verdana'); $page = $pdf->page(); $page->mediabox(595,842); $text = $page->text(); $text->textlabel(50,780, $f1, 20, "Hello World! (4)"); $pdf->saveas("$0.STRING.pdf"); $pdf->end(); exit; __END__ PDF-Builder-3.026/examples/022_truefonts_diacrits_utf80000644000000000000000000001321214534467462021242 0ustar rootroot#!/usr/bin/perl # given one or more .TTF files on the command line, display their contents: # 256 bytes in one single-byte encoding, plus some sample UTF-8 text. # -e encoding (default is latin1) SINGLE BYTE ONLY! use strict; use warnings; use lib qw{ ../lib }; use File::Basename; use PDF::Builder; use PDF::Builder::Util; use Unicode::UCD 'charinfo'; use Getopt::Long; use utf8; #my $compress = 'none'; # uncompressed streams my $compress = 'flate'; # compressed streams my $sx = 33; my $sy = 45; my $fx = 20; #my $LoremIpsum = qq|Spin\x{0308}al Tap says: Sed ut perspici\x{0361}atis.|; # times.ttf includes my $LoremIpsum = qq|Sed ut perspici\x{0361}atis.|; # times.ttf includes # U+0308 is combining diaeresis (spans n) unfortunately, doesn't quite align # U+0361 is combining double inverted breve (spans i to t) # "use utf8" says to interpret string as UTF-8 my $encoding = 'latin1'; my ($pdf, $f1, $f2, $gfx, $text, $y, $page); GetOptions( "encode|e=s" => \$encoding, ); # loop through command line list of font file names die "Need at least one TTF file name on command line!\n" if !scalar(@ARGV); foreach my $fn (@ARGV) { if (!-r $fn) { print "$fn cannot be read. Skipping...\n\n"; next; } my $myName = basename($fn); $myName =~ s/\.[ot]tf$//i; # remove .ttf/.otf (any case) $pdf = PDF::Builder->new(-compress => $compress, -file => $0.'.'.$myName.".pdf"); $f1 = $pdf->corefont('Helvetica', -encode => 'latin1'); $f2 = $pdf->corefont('Helvetica-Bold', -encode => 'latin1'); print STDERR "\n$myName\n"; my $font=$pdf->ttfont($fn, -encode => $encoding); $font->data->{'nosubset'}=1; # produce a page with dump of font # single byte encoding (16 rows x 16 columns) if ($encoding =~ m/^utf/i || $encoding =~ m/^ucs/i) { print STDERR "can't display page for multibyte encoding.\n"; } else { $page = $pdf->page(); $page->mediabox(595,842); # A4 $gfx = $page->gfx(); my $txt = $page->text(); $txt->font($font, $fx); my $txt2 = $page->text(); #delete $txt->{'Filter'}; #delete $txt2->{'Filter'}; $txt2->textlabel(50,800, $f1,20, "font='".$font->fontname."'"); $txt2->textlabel(50,780, $f1,20, "encoding='$encoding'"); $txt2->font($f1, 5); $txt2->hscale(80); my $u = $font->underlineposition*$fx/1000; # loop through rows (yp growing from bottom) foreach my $yp (0..15) { $y = 15 - $yp; # grow y from top to bottom instead print STDERR "."; # loop through columns left to right foreach my $x (0..15) { $txt->translate(50+($sx*$x),50+($sy*$y)); my $ci = $yp*16 + $x; my $c = chr($ci); #if ($encoding =~ m/^utf/i || $encoding =~ m/^ucs/i) { # # by default, ci=x80 through xFF isn't treated as UTF-8, # # so need to manually encode # if ($ci >= 128 && $ci < 256) { # $c = Encode::decode('cp-1252', $c); # } #} $txt->text($c); my $wx=$font->width($c)*$fx; # draw cell box $gfx->strokecolor('lightblue'); $gfx->move(50+($sx*$x),50+($sy*$y)+$fx); $gfx->line(50+($sx*$x),50+($sy*$y)+$u); $gfx->line(50+($sx*$x)+$wx,50+($sy*$y)+$u); $gfx->line(50+($sx*$x)+$wx,50+($sy*$y)+$fx); $gfx->close(); $gfx->stroke(); $gfx->strokecolor('gray'); $gfx->move(50+($sx*$x),50+($sy*$y)); $gfx->line(50+($sx*$x)+$wx,50+($sy*$y)); $gfx->stroke(); $txt2->translate(50+($sx*$x)+$wx,50+($sy*$y)-6); $txt2->text_right($ci); $txt2->translate(50+($sx*$x)+$wx,50+($sy*$y)-11); if (defined $font->uniByEnc($ci)) { $txt2->text_right(sprintf('U+%04X', $font->uniByEnc($ci))); } else { $txt2->text_right('U+????'); } $txt2->translate(50+($sx*$x)+$wx,50+($sy*$y)-16); $txt2->text_right($font->glyphByEnc($ci)); $txt2->translate(50+($sx*$x)+$wx,50+($sy*$y)-21); $txt2->text_right(sprintf('wx=%i',$font->wxByEnc($ci))); } # loop x L to R along row } # loop yp B to T along column and y T to B } # single byte encoding display chars # unlike 022_truefonts, there is no CId dump # print out some text in this font on next page my $textL = $LoremIpsum; $page = $pdf->page(); $page->mediabox(595,842); # A4 $text = $page->text(); $text->transform(-translate => [50, 800]); $text->fillcolor('black'); $text->font($font, 18); $text->leading(18*1.25); my $toprint; while ($textL ne '') { ($toprint, $textL) = $text->_text_fill_line($textL, 500, 0); $text->text($toprint); $text->nl(); } $pdf->save(); $pdf->end(); } # loop through a font name. go to next command line name. print STDERR "\n"; exit; __END__ =head1 HISTORY $Log$ Revision 1.1 2007/10/23 07:48:08 areibens genesis Revision 2.2 2007/04/07 10:26:23 areibens added lorem ipsum page Revision 2.1 2006/06/19 19:20:13 areibens added details Revision 2.0 2005/11/16 02:16:00 areibens revision workaround for SF cvs import not to screw up CPAN Revision 1.2 2005/11/16 01:27:48 areibens genesis2 Revision 1.1 2005/11/16 01:19:24 areibens genesis Revision 1.3 2005/09/12 16:55:05 fredo various updates Revision 1.2 2004/12/31 02:58:49 fredo no message Revision 1.1 2004/04/06 23:04:06 fredo genesis =cut PDF-Builder-3.026/examples/021_psfonts0000644000000000000000000005677614534467462016102 0ustar rootroot#!/usr/bin/perl # wants one or more font names on the command line. They must have a file # extension of .pfa, .pfb, or .t1 and have an associated metrics file of the # same path and name, except with extension .afm or .pfm respectively. # CAUTION: the displayed Unicode value (U+xxxx) appears to be correct in most # cases, except that the MS Smart Quotes (32 characters) are given as U+0080 # through U+009F. Those Unicode values are reserved for the C1 Control character # group, not printable glyphs. I don't know if the font files hold incorrect # Unicode values, or this program is in error. See PDF::Builder::Resource:: # Glyphs for u2n and n2u tables -- they may be in error. Note that UTF-8 and # other multibyte encodings are not usable with T1 fonts. Note that some fonts # may spill over onto 1 or more additional pages, which of course is beyond # single byte encoding (automap is used here). use strict; use warnings; use lib '../lib'; use PDF::Builder; use PDF::Builder::Util; use File::Basename; my $compress = 'none'; # uncompressed streams #my $compress = 'flate'; # compressed streams my $sx = 33; my $sy = 45; my $fx = 20; # nominal font size in points my $gLLx = 50; # lower left position of grid my $gLLy = 50; my $LoremIpsum=q|Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam eaque ipsa, quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt, explicabo. Nemo enim ipsam voluptatem, quia voluptas sit, aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos, qui ratione voluptatem sequi nesciunt, neque porro quisquam est, qui dolorem ipsum, quia dolor sit, amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt, ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit, qui in ea voluptate velit esse, quam nihil molestiae consequatur, vel illum, qui dolorem eum fugiat, quo voluptas nulla pariatur? At vero eos et accusamus et iusto odio dignissimos ducimus, qui blanditiis praesentium voluptatum deleniti atque corrupti, quos dolores et quas molestias excepturi sint, obcaecati cupiditate non provident, similique sunt in culpa, qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio, cumque nihil impedit, quo minus id, quod maxime placeat, facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet, ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat.|; # build lists of metric paths, glyph files, and metric files my @gns = (); # glyphs: path, name, extension my @mns = (); # metrics: path, name, extension my @ecs = (); # encodings until further notice (one string for each # font, with one or more encodings space-separated) my $mpath = '@./'; # default path list = same dir as glyph file (-m) # must end in / or \ (not added or checked) my $ecflag = 'latin1'; # default encoding to display (-e) # no args, or just -h, -?, or --help if (scalar @ARGV == 0 || (scalar @ARGV == 1 && ($ARGV[0] eq '-h' || $ARGV[0] eq '-?' || $ARGV[0] eq '--help'))) { usage(); exit(1); } # loop through @ARGV, building up @gns (list of glyph file path+names), # @mns (list of metric file path+names), # @ecs (list of encodings for each font file) # check that requested files exist. fatal error if not (show usage). if (processCMD(@ARGV)) { usage(); exit(2); } # use only with single byte encodings, as multibyte (including UTF-8) don't # appear to be compatible with these T1/PS fonts # there may be a number of aliases available for each encoding. # # available encodings (believed to be single byte): # 7bit-jis AdobeStandardEncoding AdobeSymbol AdobeZdingbat ascii # ascii-ctrl cp1006 cp1026 cp1047 cp1250 cp1251 cp1252 cp1253 cp1254 # cp1255 cp1256 cp1257 cp1258 cp37 cp424 cp437 cp500 cp737 cp775 # cp850 cp852 cp855 cp856 cp857 cp858 cp860 cp861 cp862 cp863 cp864 # cp865 cp866 cp869 cp874 cp875 dingbats hp-roman8 iso-8859-1 # iso-8859-2 iso-8859-3 iso-8859-4 iso-8859-5 iso-8859-6 iso-8859-7 # iso-8859-8 iso-8859-9 iso-8859-10 iso-8859-11 iso-8859-13 iso-8859-14 # iso-8859-15 iso-8859-16 iso-ir-165 jis0201-raw koi8-f koi8-r koi8-u # MacArabic MacCentralEurRoman MacCroatian MacCyrillic MacDingbats # MacFarsi MacGreek MacHebrew MacIcelandic MacRoman MacRomanian # MacRumanian MacSami MacSymbol MacThai MacTurkish MacUkrainian nextstep # null posix-bc symbol viscii # # multibyte encodings (do not use): # big5-eten big5-hkscs cp932 cp936 cp949 cp950 euc-cn euc-jp euc-kr # gb12345-raw gb2312-raw gsm0338 hz iso-2022-jp iso-2022-jp-1 iso-2022-kr # jis0208-raw jis0212-raw johab ksc5601-raw MacChineseSimp MacChineseTrad # MacJapanese MacKorean MIME-B MIME-Header MIME-Header-ISO_2022_JP MIME-Q # shiftjis UCS-2BE UCS-2LE UTF-16 UTF-16BE UTF-16LE UTF-32 UTF-32BE # UTF-32LE UTF-7 utf-8-strict utf8 and probably others my ($i, $base, $y, $pdf, $fn, $fnM, $f1); # should have same number of entries each in @gns, @mns, @ecs # loop through list of font names (glyph file names) for ($i=0; $inew(-compress => $compress); $f1 = $pdf->corefont('Helvetica'); # for various labels print STDERR "\n$base -- $ec\n"; initNameTable(); # set up u2n and n2u hashes my $fnt; if ($fnM ne '') { if ($flavor eq 'a') { print "Process glyph file $fn\n with AFM file $fnM,\n $ec encoding\n"; $fnt = $pdf->psfont($fn, -afmfile => $fnM, -encode => $ec); } else { print "Process glyph file $fn\n with PFM file $fnM,\n $ec encoding\n"; $fnt = $pdf->psfont($fn, -pfmfile => $fnM, -encode => $ec); } } else { # no metrics file to be used print "Process glyph file $fn\n with no metrics file, $ec encoding\n"; $fnt = $pdf->psfont($fn, -encode => $ec); } my @planes = ($fnt, $fnt->automap()); my $flight = -1; foreach my $plane (@planes) { $flight++; # for plane 1+ ($flight > 0) check if any characters in it if ($flight > 0) { my $flag = 0; # no character found yet foreach my $yp (0..15) { foreach my $x (0..15) { my $ci = $yp*16 + $x; # 0..255 value # always seems to be something at # ci = 32 (U=0020, space) # ci = 33 (U=E000, .notdef) if ($ci == 32 || $ci == 33) { next; } if (defined $plane->uniByEnc($ci) && $plane->uniByEnc($ci) > 0) { $flag = 1; last; } } if ($flag) { last; } } if (!$flag) { next; } # no characters on this plane } # subfonts within overall font (223 characters per plane + space) # they can be treated just like regular fonts my $page = $pdf->page(); $page->mediabox(595,842); my $gfx = $page->gfx(); my $txt = $page->text(); $txt->font($plane,$fx); my $txt2 = $page->text(); $txt2->textlabel($gLLx,800, $f1,20, "font='".$plane->fontname()." / ".$plane->name()."' plane $flight", -hscale=>75); $txt2->textlabel($gLLx,780, $f1,20, "encoding='$ec'"); $txt2->font($f1, 5); $txt2->hscale(80); # distance below baseline (<0) to clear descenders my $u = $plane->underlineposition()*$fx/1000; # draw grid of characters and information # yp character row value (0..F T to B) foreach my $yp (0..15) { $y = 15 - $yp; # y vertical (row) position T to B print STDERR "."; foreach my $x (0..15) { # x horizontal (column) position L to R $txt->translate($gLLx+($sx*$x),$gLLy+($sy*$y)); my $ci = $yp*16 + $x; # 0..255 value my $c = chr($ci); $txt->text($c); my $wx = $plane->width($c)*$fx; # bounding box cell around character $gfx->strokecolor('lightblue'); $gfx->move($gLLx+($sx*$x) ,$gLLy+($sy*$y)+$fx); $gfx->line($gLLx+($sx*$x) ,$gLLy+($sy*$y)+$u); $gfx->line($gLLx+($sx*$x)+$wx,$gLLy+($sy*$y)+$u); $gfx->line($gLLx+($sx*$x)+$wx,$gLLy+($sy*$y)+$fx); $gfx->close(); $gfx->stroke(); # baseline $gfx->strokecolor('gray'); $gfx->move($gLLx+($sx*$x) ,$gLLy+($sy*$y)); $gfx->line($gLLx+($sx*$x)+$wx,$gLLy+($sy*$y)); $gfx->stroke(); # character data $txt2->translate($gLLx+($sx*$x)+$wx,$gLLy+($sy*$y)-6); $txt2->text_right($ci); $txt2->translate($gLLx+($sx*$x)+$wx,$gLLy+($sy*$y)-11); if (defined $plane->uniByEnc($ci)) { $txt2->text_right(sprintf('U+%04X',$plane->uniByEnc($ci))); } else { $txt2->text_right('U+????'); } $txt2->translate($gLLx+($sx*$x)+$wx,$gLLy+($sy*$y)-16); $txt2->text_right($plane->glyphByEnc($ci)); $txt2->translate($gLLx+($sx*$x)+$wx,$gLLy+($sy*$y)-21); $txt2->text_right(sprintf('wx=%i',$plane->wxByEnc($ci))); } # loop through columns (x) } # loop through rows (yp/y) print STDERR "\n"; } # loop through "sub" fonts (planes) # print out some text in this font on next page my $textL = $LoremIpsum; my $page = $pdf->page(); $page->mediabox(595,842); # A4 my $txt = $page->text(); $txt->transform(-translate => [50, 800]); $txt->fillcolor('black'); $txt->font($fnt, 18); $txt->leading(18*1.25); my $toprint; while ($textL ne '') { ($toprint, $textL) = $txt->_text_fill_line($textL, 500, 0); $txt->text($toprint); $txt->nl(); } $pdf->saveas("$0.$base.$ec.pdf"); $pdf->end(); } # loop through each encoding (ec) } # loop $i for each font name (fn) and metrics file (fnM) exit; # consider a -p flag like -m, but for glyph files # would look for glyph file, push path+token instead of just token sub usage { my $message = <<"END_OF_TEXT"; 021_psfonts [flags_1] glyph_file [flags_2] glyph_file [flags_2]... flags_1 -- -m metrics files paths : or ; separated directories specifying where to look for font metrics files. If relative paths (not starting with /), they are relative to the glyph file being processed if @ prepended, else (no @) relative to the current directory. The default metrics path string is just @./ (glyph file's directory). Entries will apply to following glyph file names until a new -m. The paths are not used if a -M or -N flag is given for a glyph file. -e encodings list latin1 latin2 etc. Default is latin1. Any name with characters other than A-Za-z0-9- is assumed to be a glyph file name or another flag (if starts with -). Entries will apply to the following glyph file names until a new -e. glyph_file -- a .pfa or .pfb or .t1 extension Type 1 (PS) glyph file (with path) flags_2 -- -m metrics files paths as in flags_1, but replaces whatever existed before. Note that the new path list takes effect at the next glyph file, not the previously-given one. -e encodings list as in flags_1, but replaces whatever existed before. Note that the new encoding list takes effect at the next glyph file, not the previously-given one. -M metrics file path and name an absolute (starting with /) or relative (to the glyph file path if starts with @, otherwise relative to the current directory) path and name. This overrides the -m path list for this ONE glyph file. Normally, -M is needed only when the file name differs between the glyph and metrics files, which is unusual, or you don't want to list this path in -m, or perhaps you have only one glyph file to display and want to give the exact metrics file path and name. It must come IMMEDIATELY AFTER the glyph file it pertains to, and applies only to that one glyph file. -N there is no metrics file for the preceeding glyph file. It must come IMMEDIATELY AFTER the glyph file it pertains to, and applies only to that one glyph file. Going through glyph file names, the complete path, name, and extension must be given for each (no wildcards). The base name and extension are case-sensitive. If a -M or -N flag is not given, the program will search for the metrics file (.afm or .pfm) using each metrics file path entry appended to the glyph file path, the base name of the glyph file, and each extension .afm and .pfm are tried (in that order for a .pfa or .t1 glyph file, and in the reverse order for a .pfb glyph file). Matching of extensions is case-insensitive, even on Linux systems (e.g., times-roman.AFM is considered a match for times-roman.pfb). END_OF_TEXT print $message; return; } # fill the glyph, metrics, and encoding arrays from the command line # input: @ARGV command line # output: 0 = OK, 1 = failed sub processCMD { my @args = @_; my ($token, @mpaths, $Mpath, $i, $j, $path, $basename, $extension); my $tokenNumber = 0; # at this point, $mpath is default path list and $ecflag is default encoding @mpaths = split /[:;]+/, $mpath; # each element should end in / or \ $ecflag =~ s/^\s+//; # clean off any leading or trailing whitespace $ecflag =~ s/\s+$//; @ecs = split /\s+/, $ecflag; while (@args) { # -m or -e at any time # -M or -N after a glyph file $token = shift @args; $tokenNumber++; # original token index for messages if (substr($token, 0, 2) eq '-m') { $token = substr($token, 2); # strip off -m if run-together if ($token eq '') { # -m flag was by itself. next token is actual path (must exist) if (!scalar @args) { print "missing metrics path after -m (arg $tokenNumber)\n"; return 1; } $mpath = shift @args; } else { # -m flag and path run together $mpath = stripQuotes($token); } # TBD validate mpath: valid structure, valid dirs # $mpath should not have any leading or trailing whitespace, may # have embedded whitespace (Windows) @mpaths = split /[:;]+/, $mpath; if (!@args) { print "no glyph files after -m path list! (arg $tokenNumber)\n"; return 1; } # each mpaths entry should end in a / for ($i=0; $inew(); my $content; my ($page, $text, $grfx); my $name = $0; $name =~ s/\.pl/.pdf/; # write in examples directory my $magenta = '#ff00ff'; my $fs = 15; my ($rc, $next_y, $unused); print "======================================================= pg 1\n"; $page = $pdf->page(); $text = $page->text(); $grfx = $page->gfx(); print "---- single string entries\n"; $text->column($page, $text, $grfx, 'none', "This is a single string text.\n\nWith two paragraphs.", 'rect'=>[50,750, 500,50], 'outline'=>$magenta); restore_props($text, $grfx); $text->column($page, $text, $grfx, 'md1', "This is a _single string_ **MD** text.\n\nIt should have two paragraphs.", 'rect'=>[50,650, 500,50], 'outline'=>$magenta); restore_props($text, $grfx); $text->column($page, $text, $grfx, 'html', "

        This is a single string HTML text.

        With two paragraphs.

        ", 'rect'=>[50,550, 500,50], 'outline'=>$magenta); print "---- array of string entries\n"; # should be two paragraphs, as a new array element starts a new paragraph restore_props($text, $grfx); $text->column($page, $text, $grfx, 'none', ["This is an array.","Of single string texts. Two paragraphs."], 'rect'=>[50,450, 500,50], 'outline'=>$magenta); restore_props($text, $grfx); $text->column($page, $text, $grfx, 'md1', ["This is an **array**\n \n","Of single _string_ MD texts, two paragraphs."], 'rect'=>[50,350, 500,50], 'outline'=>$magenta); restore_props($text, $grfx); $text->column($page, $text, $grfx, 'html', ['

        This is an array

        ','

        of single string HTML texts. Two paragraphs.

        '], 'rect'=>[50,250, 500,50], 'outline'=>$magenta); restore_props($text, $grfx); print "---- pre array of hashes\n"; $text->column($page, $text, $grfx, 'pre', [ {'text'=>'', 'tag'=>'style' }, # dummy style tag {'text'=>'', 'tag'=>'p'}, {'text'=>'This is an array', 'tag'=>''}, {'text'=>'', 'tag'=>'/p'}, {'text'=>'', 'tag'=>'p'}, {'text'=>'of single string hashes.', 'tag'=>''}, {'text'=>'', 'tag'=>'/p'}, {'text'=>'', 'tag'=>'p'}, {'text'=>'With ', 'tag'=>''}, {'text'=>'', 'tag'=>'b'}, {'text'=>'some ', 'tag'=>''}, {'text'=>'', 'tag'=>'/b'}, {'text'=>'', 'tag'=>'i'}, {'text'=>'markup', 'tag'=>''}, {'text'=>'', 'tag'=>'b'}, {'text'=>'!', 'tag'=>''}, {'text'=>'', 'tag'=>'/b'}, {'text'=>'', 'tag'=>'/i'}, {'text'=>'', 'tag'=>'/p'}, ], 'rect'=>[50,150, 500,50], 'outline'=>$magenta); # larger font size and narrower columns to force line wraps print "======================================================= pg 2\n"; $page = $pdf->page(); $text = $page->text(); $grfx = $page->gfx(); print "---- single string entries\n"; restore_props($text, $grfx); multicol($page, $text, $grfx, 'none', "This is a single string text.\n\nWith two paragraphs.", [50,750, 50,50], $magenta, $fs); restore_props($text, $grfx); multicol($page, $text, $grfx, 'md1', "This is a _single string_ **MD** text.\n\nIt should have two paragraphs.", [50,650, 50,50], $magenta, $fs); restore_props($text, $grfx); multicol($page, $text, $grfx, 'html', "

        This is a single string HTML text.

        Two paragraphs.

        ", [50,550, 50,50], $magenta, $fs); print "---- array of string entries\n"; # should be two paragraphs, as a new array element starts a new paragraph restore_props($text, $grfx); multicol($page, $text, $grfx, 'none', ["This is an array","Of single string texts. Two paragraphs."], [50,450, 50,50], $magenta, $fs); # would be glued together into one line, except there is a blank line in middle restore_props($text, $grfx); multicol($page, $text, $grfx, 'md1', ["This is an **array**\n\n","Of single _string_ MD texts. Two paragraphs.\n"], [50,350, 50,50], $magenta, $fs); # explicitly have two paragraphs restore_props($text, $grfx); multicol($page, $text, $grfx, 'html', ["

        This is an array

        \n","

        Of single string HTML texts. Two paragraphs.

        \n"], [50,250, 50,50], $magenta, $fs); print "---- pre array of hashes\n"; restore_props($text, $grfx); multicol($page, $text, $grfx, 'pre', [ {'text'=>'', 'tag'=>'style' }, # dummy style tag {'text'=>'', 'tag'=>'p'}, {'text'=>'This is an array', 'tag'=>''}, {'text'=>'', 'tag'=>'/p'}, {'text'=>'', 'tag'=>'p'}, {'text'=>'Of single string hashes.', 'tag'=>''}, {'text'=>'', 'tag'=>'/p'}, {'text'=>'', 'tag'=>'p'}, {'text'=>'With ', 'tag'=>''}, {'text'=>'', 'tag'=>'b'}, {'text'=>'some ', 'tag'=>''}, {'text'=>'', 'tag'=>'/b'}, {'text'=>'', 'tag'=>'i'}, {'text'=>'markup', 'tag'=>''}, {'text'=>'', 'tag'=>'b'}, {'text'=>'!', 'tag'=>''}, {'text'=>'', 'tag'=>'/b'}, {'text'=>'', 'tag'=>'/i'}, {'text'=>'', 'tag'=>'/p'}, ], [50,150, 50,50], $magenta, $fs); # let's try some large sample MD and HTML print "======================================================= pg 3\n"; # # Lorem Ipsum text ('none') in mix of single string and array $page = $pdf->page(); $text = $page->text(); $grfx = $page->gfx(); # as an array of strings my @ALoremIpsum = ( "Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam eaque ipsa, quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt, explicabo. Nemo enim ipsam voluptatem, quia voluptas sit, aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos, qui ratione dolor sit, voluptatem sequi nesciunt, neque porro quisquam est, qui dolorem ipsum, quia amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt, ut labore et dolore magnam aliquam quaerat voluptatem. ", "Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit, qui in ea voluptate velit esse, quam nihil molestiae consequatur, vel illum, qui dolorem eum fugiat, quo voluptas nulla pariatur? At vero eos et accusamus et iusto odio dignissimos ducimus, qui blanditiis praesentium voluptatum deleniti atque corrupti, quos dolores et quas molestias excepturi sint, obcaecati cupiditate non provident, similique sunt in culpa, qui officia deserunt mollitia animi, id est laborum et dolorum fuga. ", "Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio, cumque nihil impedit, quo minus id, quod maxime placeat, facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. ", "Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet, ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat. " ); my $SLoremIpsum = join("\n",@ALoremIpsum); print "---- Lorem Ipsum array of string entries, default paragraphs\n"; # default paragraph indent and top margin restore_props($text, $grfx); ($rc, $next_y, $unused) = $text->column($page, $text, $grfx, 'none', \@ALoremIpsum, 'rect'=>[50,750, 500,300], 'outline'=>$magenta ); if ($rc) { print STDERR "Lorem Ipsum array overflowed the column!\n"; } print "---- Lorem Ipsum string entry, block-style paragraphs\n"; # no indent, extra top margin restore_props($text, $grfx); ($rc, $next_y, $unused) = $text->column($page, $text, $grfx, 'none', $SLoremIpsum, 'rect'=>[50,350, 500,300], 'outline'=>$magenta, 'para'=>[ 0, 5 ] ); if ($rc) { print STDERR "Lorem Ipsum string overflowed the column!\n"; } # customer sample Markdown print "======================================================= pg 4\n"; print "---- Customer sample Markdown and Table\n"; $page = $pdf->page(); $text = $page->text(); $grfx = $page->gfx(); $content = <<"END_OF_CONTENT"; Example of Markdown that needs to be supported in document text blocks. There is no need to support this within tables, although it would be a "nice" feature. Firstly just some simple styling: *italics*, **bold** and ***both***. There should also be support for _alternative italics_ Then a bulleted list: * Unordered item * Another unordered item And a numbered list: 1. Item one 2. Item two # We will need a heading ## And a subheading Finally we’ll need some [external links](https://duckduckgo.com). Show that [another link](https://www.catskilltech.com) on the same page works. Show some inserted text and underlined text that display underlines. Show some deleted text, strike-out text, and s'd out text that show line-throughs. More than one at a time are possible via style attribute, also via nested tags. Then we need some styling features in tables as shown in the table below. There is no need to support this in text blocks, although it would be a nice feature (colored text is already available in text blocks using its options). END_OF_CONTENT # TBD in above text, nested tags lost the # space between the words in Treebuilder? needs investigating restore_props($text, $grfx); ($rc, $next_y, $unused) = $text->column($page, $text, $grfx, 'md1', $content, 'rect'=>[50,750, 500,708], 'outline'=>$magenta, 'para'=>[ 0, 5 ] ); if ($rc) { print STDERR "Sample Markdown overflowed the column!\n"; } # customer sample HTML $next_y -= 20; # gap to table if ($use_Table) { # use PDF::Table to draw a table, inheriting font from above # you need to be careful to end a cell with font, etc. restored # this only works if PDF::Table installed! use PDF::Table; my $table = PDF::Table->new(); my $table_data = [ # row 1, solid color lines [ [ 'html', 'This is some red text', { 'font_size' => 12, 'para' => [ 0, 0 ] } ], [ 'html', "This is some green text", { 'font_size' => 12, 'para' => [ 0, 0 ] } ], ], # row 2, special symbols, colored [ [ 'html', 'This is a red cross: 8.', { 'font_size' => 12, 'para' => [ 0, 0 ] } ], [ 'html', "This is a green tick: 4.", { 'font_size' => 12, 'para' => [ 0, 0 ] } ], ], # row 3, like row 2, but using macro substitutions [ [ 'html', "This is a red cross substitute: %cross%.", { 'font_size'=>12, 'para'=>[ 0, 0 ], 'substitute'=>[ ['%cross%','', '8', ''], ['%tick%','', '4', ''] ] } ], [ 'html', "This is a green tick substitute: %tick%.", { 'font_size'=>12, 'para'=>[ 0, 0 ], 'substitute'=>[ ['%cross%','', '8', ''], ['%tick%','', '4', ''] ] } ], ], # row 4, non-markup text [ 'Plain old text', 'More plain text' ], ]; my $size = '* *'; # two equal columns $table->table( $pdf, $page, $table_data, 'x' => 50, 'y' => $next_y, 'w' => 500, 'h' => $next_y-42, 'next_y' => 750, 'next_h' => 708, 'size' => $size, # global markups (can be overridden for row, column, or cell) 'padding' => 4.5, ); } else { # fake a table so that PDF::Table is not required within PDF::Builder # examples! # "table" 2 columns width 500, padding 5, font size 12, draw borders # and rules # we will show a number of different techniques # do 6 cells as 6 small columns in 3x2 grid my $table_rows = 4; my $table_cols = 2; my $cell_height = 20; my $row_num = 0; # # row 1, simple color text restore_props($text, $grfx); $text->column($page, $text, $grfx, 'html', 'This is some red text', 'rect'=>[55,$next_y-(5+$row_num*$cell_height), 240,20], 'font_size'=>12, 'para'=>[ 0, 0 ] ); restore_props($text, $grfx); $text->column($page, $text, $grfx, 'html', 'This is some green text', 'rect'=>[305,$next_y-(5+$row_num*$cell_height), 240,20], 'font_size'=>12, 'para'=>[ 0, 0 ] ); $row_num++; # row 2, show a tick and cross, changed color, font and span tags restore_props($text, $grfx); $text->column($page, $text, $grfx, 'html', 'This is a red cross: 8.', 'rect'=>[55,$next_y-(5+$row_num*$cell_height), 240,20], 'font_size'=>12, 'para'=>[ 0, 0 ] ); restore_props($text, $grfx); $text->column($page, $text, $grfx, 'html', "This is a green tick: 4.", 'rect'=>[305,$next_y-(5+$row_num*$cell_height), 240,20], 'font_size'=>12, 'para'=>[ 0, 0 ] ); $row_num++; # row 3, like 2 but illustrate text/HTML substitution restore_props($text, $grfx); $text->column($page, $text, $grfx, 'md1', "This is a red cross substitute: %cross%.", 'rect'=>[55,$next_y-(5+$row_num*$cell_height), 240,20], 'font_size'=>12, 'para'=>[ 0, 0 ], 'substitute'=>[ ['%cross%','', '8', ''], ['%tick%','', '4', ''] ]); restore_props($text, $grfx); $text->column($page, $text, $grfx, 'html', "This is a green tick substitute: %tick%.", 'rect'=>[305,$next_y-(5+$row_num*$cell_height), 240,20], 'font_size'=>12, 'para'=>[ 0, 0 ], 'substitute'=>[ ['%cross%','', '8', ''], ['%tick%','', '4', ''] ]); $row_num++; # row 4, non-markup text restore_props($text, $grfx); $text->column($page, $text, $grfx, 'none', "Plain old text", 'rect'=>[55,$next_y-(5+$row_num*$cell_height), 240,20], 'font_size'=>12, 'para'=>[ 0, 0 ], ); restore_props($text, $grfx); $text->column($page, $text, $grfx, 'none', "More plain text", 'rect'=>[305,$next_y-(5+$row_num*$cell_height), 240,20], 'font_size'=>12, 'para'=>[ 0, 0 ], ); $row_num++; # draw border and rules $grfx->poly(50,$next_y, 550,$next_y, 550,$next_y-($table_rows*20), 50,$next_y-($table_rows*20), 50,$next_y); # horizontal dividers between rows for (my $r = 1; $r < $table_rows; $r++) { $grfx->move(50,$next_y-($r*20)); $grfx->hline(550); } # vertical divider between columns $grfx->move(300,$next_y); $grfx->vline($next_y-60); # draw it all $grfx->strokecolor('black'); $grfx->stroke(); } # more pages with more extensive MD print "======================================================= pg 5-8\n"; print "---- A README.md file for PDF::Builder\n"; $page = $pdf->page(); $text = $page->text(); $grfx = $page->gfx(); # might need two or even three pages $content = <<"END_OF_CONTENT"; # PDF::Builder A Perl library to facilitate the creation and modification of PDF files ## What is it? PDF::Builder is a **fork** of the popular PDF::API2 Perl library. It provides a library of modules and functions so that a PDF file (document) may be built and maintained from Perl programs. It is not a WYSIWYG editor; nor is it a canned utility or converter. It does _not_ have a GUI -- it is driven by your Perl program. It is a set of **building blocks** with which you can perform a wide variety of operations, ranging from basic operations such as selecting a font face, to defining an entire page at a time in the document, using a large subset of either Markdown or HTML markup languages. You can call it from arbitrary Perl programs, which may even create content on-the-fly (or read it in from other sources). Quite a few code examples are provided, to help you to get started with the process of creating a PDF document. Many enhancements are in the pipeline to make PDF::Builder even more powerful and versatile. [Home Page](https://www.catskilltech.com/FreeSW/product/PDF%2DBuilder/title/PDF%3A%3ABuilder/freeSW_full), including Documentation and Examples. [![Open Issues](https://img.shields.io/github/issues/PhilterPaper/Perl-PDF-Builder)](https://github.com/PhilterPaper/Perl-PDF-Builder/issues) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](https://makeapullrequest.com) [![Maintenance](https://img.shields.io/badge/Maintained%3F-yes-green.svg)](https://GitHub.com/PhilterPaper/Perl-PDF-Builder/graphs/commit-activity) This archive contains the distribution PDF::Builder. See **Changes** file for the version. ## Obtaining the Package The installable Perl package may be obtained from "https://metacpan.org/pod/PDF::Builder", or via a CPAN installer package. If you install this product, only the run-time modules will be installed. Download the full `.tar.gz` file and unpack it (hint: on Windows, **7-Zip File Manager** is an excellent tool) to get utilities, test buckets, example usage, etc. Alternatively, you can obtain the full source files from "https://github.com/PhilterPaper/Perl-PDF-Builder", where the ticket list (bugs, enhancement requests, etc.) is also kept. Unlike the installable CPAN version, this will have to be manually installed (copy files; there are no XS compiles at this time). Note that there are several "optional" libraries (Perl modules) used to extend and improve PDF::Builder. Read about the list of optional libraries in PDF::Builder::Docs, and decide whether or not you want to install any of them. By default, none are installed. ## Requirements ### Perl **Perl 5.26** or higher. It will likely run on somewhat earlier versions, but the CPAN installer may refuse to install it. The reason this version was chosen was so that LTS (Long Term Support) versions of Perl going back about 6 years are officially supported (by PDF::Builder), and older versions are not supported. The intent is to not waste time and effort trying to fix bugs which are an artifact of old Perl releases. #### Older Perls If you MUST install on an older (pre 5.26) Perl, you can try the following for Strawberry Perl (Windows). NO PROMISES! Something similar MAY work for other OS's and Perl installations: 1. Unpack installation file (`.tar.gz`, via a utility such as 7-Zip) into a directory, and cd to that directory 1. Edit META.json and change 5.026000 to 5.016000 or whatever level desired 1. Edit META.yml and change 5.026000 to 5.016000 or whatever level desired 1. Edit Makefile.PL and change `use 5.026000;` to `use 5.016000;`, change `\$PERL_version` from `5.026000` to `5.016000` 1. `cpan .` Note that some Perl installers MAY have a means to override or suppress the Perl version check. That may be easier to use. Or, you may have to repack the edited directory back into a `.tar.gz` installable. YMMV. If all goes well, PDF::Builder will be installed on your system. Whether or not it will RUN is another matter. Please do NOT open a bug report (ticket) unless you're absolutely sure that the problem is not a result of using an old Perl release, e.g., PDF::Builder is using a feature introduced in Perl 5.018 and you're trying to run Perl 5.002! ### Libraries used These libraries are available from CPAN. #### REQUIRED These libraries should be automatically installed... * Compress::Zlib * Font::TTF * Test::Exception (needed only for installation tests) * Test::Memory::Cycle (needed only for installation tests) #### OPTIONAL These libraries are _recommended_ for improved functionality and performance. The default behavior is **not** to attempt to install them during PDF::Builder installation, in order to speed up the testing process and not clutter up matters, especially if an optional package fails to install. You can always manually install them later, if you desire to make use of their added functionality. * Perl::Critic (1.150 or higher, need if running tools/1\_pc.pl) * Graphics::TIFF (19 or higher, recommended if using TIFF image functions) * Image::PNG::Libpng (0.57 or higher, recommended for enhanced PNG image function processing) * HarfBuzz::Shaper (0.024 or higher, needed for Latin script ligatures and kerning, as well as for any complex script such as Arabic, Indic scripts, or Khmer) * Text::Markdown (1.000031 or higher, needed if using 'md1' markup) * HTML::TreeBuilder (5.07 or higher, needed if using 'html' or 'md1' markup) * Pod::Simple::XHTML (3.45 or higher, needed if using buildDoc utility to create HTML documentation) If an optional package is needed, but not installed, sometimes PDF::Builder will be able to fall back to built-in partial functionality (TIFF and PNG images), but other times will fail. After installing the missing package, you may wish to then run the t-test suite for that library to confirm that it is properly running, as well as running the examples. Other than an installer for standard CPAN packages (such as 'cpan' on Strawberry Perl for Windows), no other tools or manually-installed prereqs are needed (worst case, you can unpack the `.tar.gz` file and copy files into place yourself!). Currently there are no compiles and links (Perl extensions) done during the install process, only copying of .pm Perl module files. ## Manually building As is the usual practice with building such a package (from the command line), the steps are: 1. perl Makefile.PL 1. make 1. make test 1. make install If you have your system configured to run Perl for a .pl/.PL file, you may be able to omit "perl" from the first command, which creates a Makefile. "make" is the generic command to run (it feeds on the Makefile), but your system may have it under a different name, such as dmake (Strawberry Perl on Windows), gmake, or nmake. PDF::Builder does not currently compile and link anything, so gcc, g++, etc. will not be used. The build process merely copies .pm files around, and runs the "t" tests to confirm the proper installation. ## Copyright This software is Copyright (c) 2017-2023 by Phil M. Perry. Previous copyrights are held by others (Steve Simms, Alfred Reibenschuh, et al.). See The HISTORY section of the documentation for more information. We would like to acknowledge the efforts and contributions of a number of users of PDF::Builder (and its predecessor, PDF::API2), who have given their time to report issues, ask for new features, and have even contributed code. Generally, you will find their names listed in the Changes and/or issue tickets related to some particular item. ## License This is free software, licensed under: `The GNU Lesser General Public License, Version 2.1, February 1999` EXCEPT for some files which are explicitly under other, compatible, licenses (the Perl License and the MIT License). You are permitted (at your option) to redistribute and/or modify this software (those portions under LGPL) at an LGPL version greater than 2.1. See INFO/LICENSE for more information on the licenses and warranty statement. ### Carrying On... PDF::Builder is Open Source software, built upon the efforts not only of the current maintainer, but also of many people before me. Therefore, it's perfectly fair to make use of the algorithms and even code (within the terms of the LICENSE). That's exactly how the State of the Art progresses! Just please be considerate and acknowledge the work of others that you are building on, as well as pointing back to this package. Drop us a note with news of your project (if based on the code and algorithms in PDF::Builder, or even just heavily inspired by it) and we'll be happy to make a pointer to your work. The more cross-pollination, the better! ## See Also * CONTRIBUTING file for how to contribute to the project * LICENSE file for more on the license term * INFO/RoadMap file for the PDF::Builder road map * INFO/ACKNOWLEDGE.md for "thank yous" to those who contributed to this product * INFO/SUPPORT file for information on reporting bugs, etc. via GitHub Issues * INFO/DEPRECATED file for information on deprecated features * INFO/KNOWN\_INCOMP file for known incompatibilities with PDF::API2 * INFO/CONVERSION file for how to convert from PDF::API2 to PDF::Builder * INFO/Changes\* files for older change logs * INFO/PATENTS file for information on patents `INFO/old/` also has some build and test tool files that are not currently used. ## Documentation To build the full HTML documentation (all the POD), get the full installation and go to the `docs/` directory. Run `buildDoc.pl --all` to generate the full tree of documentation. There's a lot of additional information in the PDF::Builder::Docs module (it's all documentation). You may find it more convenient to point your browser to our [Home Page](https://www.catskilltech.com/FreeSW/product/PDF-Builder/title/PDF%3A%3ABuilder/freeSW_full) to see the full documentation build (as well as most of the example outputs). We admit that the documentation is a bit light on "how to" task orientation. We hope to more fully address this in the future, but for now, get the full installation and look at the `examples/` and `contrib/` directories for sample code that may help you figure out how to do things. The installation tests in the `t/` and `xt/` directories might also be useful to you. END_OF_CONTENT restore_props($text, $grfx); ($rc, $next_y, $unused) = $text->column($page, $text, $grfx, 'md1', $content, 'rect'=>[50,750, 500,700], 'outline'=>$magenta, 'para'=>[ 0, 5 ] ); while ($rc) { # new page $page = $pdf->page(); $text = $page->text(); $grfx = $page->gfx(); ($rc, $next_y, $unused) = $text->column($page, $text, $grfx, 'pre', $unused, 'rect'=>[50,750, 500,700], 'outline'=>$magenta, 'para'=>[ 0, 5 ] ); } # a variety of lists over multiple pages print "======================================================= pg 9\n"; print "---- A variety of lists\n"; $page = $pdf->page(); $text = $page->text(); $grfx = $page->gfx(); $content = <<"END_OF_CONTENT";

        Unordered (bulleted) lists with various markers

        • Unordered 1A, disc and here is a bunch more text to try to cause a spill to a second line. Looks like we need a bit more filler here.
        • Unordered 1B
          • Unordered 2A, circle
          • Unordered 2B and here is a bunch more text to try to cause a spill to a second line. Looks like we need a bit more filler here.
            • Unordered 3A, square
            • Unordered 3B
              • Unordered 4A, box. A “box” marker is non-standard — it is an empty square marker. A bit more filler here. How about a lot more, driving it to three lines in all? Oh yeah, that's the ticket!
              • Unordered 4B
                • Unordered 5A, disc
                • Unordered 5B
                • Unordered 6A, square
                • Unordered 6B

        Ordered (numbered) lists with various markers

        1. Ordered 1A, decimal 1., 2.
        2. Ordered 1B
          1. Ordered 2A, upper-roman I., II.
          2. Ordered 2B
            1. Ordered 3A, upper-alpha A., B.
            2. Ordered 3B
              1. Ordered 4A, lower-roman i., ii.
              2. Ordered 4B
                1. Ordered 5A lower-alpha a., b.
                2. Ordered 5B
                1. Ordered 6A, decimal 1., 2.
                2. Ordered 6B
        END_OF_CONTENT restore_props($text, $grfx); ($rc, $next_y, $unused) = $text->column($page, $text, $grfx, 'html', $content, 'rect'=>[50,750, 500,700], 'outline'=>$magenta, 'para'=>[ 0, 0 ] ); if ($rc) { print STDERR "list example overflowed column!\n"; } print "======================================================= pg 10\n"; print "---- More list examples\n"; $page = $pdf->page(); $text = $page->text(); $grfx = $page->gfx(); $content = <<"END_OF_CONTENT";

        Mixture of ordered and unordered with default markers

        1. Ordered 1A, decimal 1., 2.
        2. Ordered 1B
          • Unordered 2A, circle
          • Unordered 2B
            1. Ordered 3A, decimal 1., 2.
            2. Ordered 3B
              • Unordered 4A, square
              • Unordered 4B
                1. Ordered 5A, decimal 1., 2.
                2. Ordered 5B
                • Unordered 6A, square
                • Unordered 6B
        END_OF_CONTENT restore_props($text, $grfx); ($rc, $next_y, $unused) = $text->column($page, $text, $grfx, 'html', $content, 'rect'=>[50,750, 500,450], 'outline'=>$magenta, 'para'=>[ 0, 0 ] ); if ($rc) { print STDERR "list example overflowed column!\n"; } # try nesting in Markdown $content = <<"END_OF_CONTENT"; ## Try nested Markdown entries (manually indent items) 1. This is a numbered list unnested. 2. This is another item in the numbered list. - This is a first nested level bulleted list. - This is a further nested bulleted list. - And a second item. - Back to first nested level bulleted list 3. One last numbered list item END_OF_CONTENT restore_props($text, $grfx); ($rc, $next_y, $unused) = $text->column($page, $text, $grfx, 'md1', $content, 'rect'=>[50,250, 500,200], 'outline'=>$magenta, 'para'=>[ 0, 0 ] ); if ($rc) { print STDERR "list example overflowed column!\n"; } # Counting down (reversed) ordered lists print "======================================================= pg 11\n"; print "---- Count down list examples\n"; $page = $pdf->page(); $text = $page->text(); $grfx = $page->gfx(); $content = <<"END_OF_CONTENT";

        Test reversed ordered lists

        1. ten
        2. nine
        3. eight
        4. seven
        5. six
        6. five
          1. holding
          2. resume countdown
        7. four
        8. three
        9. two
        10. one

        Reversed ordered list run past 1

        1. three
        2. two
        3. one
        4. zero... blast off!
        5. minus one... the clock is running
        END_OF_CONTENT restore_props($text, $grfx); ($rc, $next_y, $unused) = $text->column($page, $text, $grfx, 'html', $content, 'rect'=>[50,750, 500,450], 'outline'=>$magenta, 'para'=>[ 0, 0 ] ); if ($rc) { print STDERR "list example overflowed column!\n"; } # block quotes and font extent changes print "======================================================= pg 12\n"; print "---- Block quotes\n"; $page = $pdf->page(); $text = $page->text(); $grfx = $page->gfx(); $content = <<"END_OF_CONTENT";

        Block Quote (left and right margins)

        Sed ut perspiciatis, — unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam eaque ipsa, quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt, explicabo. Nemo enim ipsam voluptatem, quia voluptas sit, aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos, qui ratione dolor sit, voluptatem sequi nesciunt, neque porro quisquam est, qui dolorem ipsum, quia amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt, ut labore et dolore magnam aliquam quaerat voluptatem.

        Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit, qui in ea voluptate velit esse, quam nihil molestiae consequatur, vel illum, qui dolorem eum fugiat, quo voluptas nulla pariatur? At vero eos et accusamus et iusto odio dignissimos ducimus, qui blanditiis praesentium voluptatum deleniti atque corrupti, quos dolores et quas molestias excepturi sint, obcaecati cupiditate non provident, similique sunt in culpa, qui officia deserunt mollitia animi, id est laborum et dolorum fuga.

        Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam eaque ipsa, quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt, explicabo. Nemo enim ipsam voluptatem, quia voluptas sit, aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos, qui ratione dolor sit, voluptatem sequi nesciunt, neque porro quisquam est, qui dolorem ipsum, quia amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt, ut labore et dolore magnam aliquam quaerat voluptatem.

        END_OF_CONTENT restore_props($text, $grfx); ($rc, $next_y, $unused) = $text->column($page, $text, $grfx, 'html', $content, 'rect'=>[50,750, 500,300], 'outline'=>$magenta, 'para'=>[ 0, 0 ] ); if ($rc) { print STDERR "Block quotes example overflowed column!\n"; } print "---- Font size changes\n"; $content = <<"END_OF_CONTENT";

        Here is some text at 15 point size. We follow it somewhere down the line with much larger text, and follow it with some ginormous text. That should have moved the entirety of the baseline down by quite a bit, while maintaining an even baseline.

        END_OF_CONTENT restore_props($text, $grfx); ($rc, $next_y, $unused) = $text->column($page, $text, $grfx, 'html', $content, 'rect'=>[50,400, 500,350], 'outline'=>$magenta, 'para'=>[ 0, 0 ] ); if ($rc) { print STDERR "Font size changes example overflowed column!\n"; } # setting your own CSS for Markdown or none print "======================================================= pg 13\n"; $page = $pdf->page(); $text = $page->text(); $grfx = $page->gfx(); print "---- default CSS for Markdown\n"; $content = <<"END_OF_CONTENT"; Ordered list with no margin-top/bottom (extra space between elements) 1. Numbered item 1. 2. Numbered item 2. 3. Numbered item 3. ## And a subheading to make green END_OF_CONTENT restore_props($text, $grfx); ($rc, $next_y, $unused) = $text->column($page, $text, $grfx, 'md1', $content, 'rect'=>[50,750, 500,100], 'outline'=>$magenta, 'para'=>[ 0, 0 ] ); if ($rc) { print STDERR "Markdown CSS example overflowed column!\n"; } print "---- set CSS for Markdown\n"; $content = <<"END_OF_CONTENT"; Ordered list with no margin-top/bottom (no space between elements) and new marker format 1. Numbered item 1. 2. Numbered item 2. 3. Numbered item 3. ## And a subheading to make green END_OF_CONTENT restore_props($text, $grfx); ($rc, $next_y, $unused) = $text->column($page, $text, $grfx, 'md1', $content, 'rect'=>[50,650, 500,100], 'outline'=>$magenta, 'para'=>[ 0, 0 ], 'style'=>" ol { _marker-before: '(' ; _marker-after: ')' ; } li { margin-top: 0; margin-bottom: 0 } h2 { color: green; } ", # marker-before/after could be in ol, too # note that comments not supported in CSS ); if ($rc) { print STDERR "Markdown CSS example overflowed column!\n"; } print "---- horizontal rules Markdown\n"; $content = <<"END_OF_CONTENT"; Markdown horizontal rules: 3 or more ---, ***, or ___. full width ---------- Between two rules **** Between two rules ___ Last commentary END_OF_CONTENT restore_props($text, $grfx); ($rc, $next_y, $unused) = $text->column($page, $text, $grfx, 'md1', $content, 'rect'=>[50,525, 500,125], 'outline'=>$magenta, 'para'=>[ 0, 0 ], ); if ($rc) { print STDERR "Markdown horizontal rule example overflowed column!\n"; } print "---- horizontal rules HTML\n"; $content = <<"END_OF_CONTENT";

        HTML horizontal rules, with CSS


        Between two rules, above is default settings


        Between two rules, above is very thick and blue


        Above rule is only 200pt long


        Above rule is very thick orange and 300pt long

        END_OF_CONTENT restore_props($text, $grfx); ($rc, $next_y, $unused) = $text->column($page, $text, $grfx, 'html', $content, 'rect'=>[50,400, 500,185], 'outline'=>$magenta, 'para'=>[ 0, 0 ], ); if ($rc) { print STDERR "HTML horizontal rule example overflowed column!\n"; } print "---- PDF page link\n"; $content = <<"END_OF_CONTENT"; Let's try linking to [another page](#4) of this document. Also try a link to a [specific place](#4-50-200) unzoomed. While we're here, how about [linking](#4-50-200-1.5) with zoom-in? END_OF_CONTENT restore_props($text, $grfx); ($rc, $next_y, $unused) = $text->column($page, $text, $grfx, 'md1', $content, 'rect'=>[50,200, 500,100], 'outline'=>$magenta, 'para'=>[ 0, 10 ], ); if ($rc) { print STDERR "PDF links example overflowed column!\n"; } # might have to go to a column2.pl! # demonstrate balanced columns two long columns and one short, first pass # fill blindly, overflowing to column 2 then 3, then by trial-and-error # shorten long two columns until short one just fills (show initial and # final runs). graphic X-out block for ad. # headline in English Towne Medium (.otf) "New Yawk Times" ("All the news # that fits, we print!"). Headline under it (across 3 columns): "Congress # Does Something Stoopid". Lorem Ipsum for body text. # continuation to page __ method? text to output for very last line in col. # demonstrate column shapes that split line in two (only first part used) # demonstrate irregularly shaped columns, including a bowtie scaled 3 times # demonstrate two column layout with insets and marginpar (inset routine to # place text w/ hr's, return cutout outline for columns outline creation, # intersect with rectangles for columns) # demonstrate a circular column, etc. # demonstrate a spline column cutout, with image in background with edges # that fade away so text can overlap outer fringes of image # --------------------------------------------------------------------------- # end of program $pdf->saveas($name); # ----------------------- sub multicol { my ($page, $text, $grfx, $markup, $content, $rect, $outline, $fs) = @_; my ($rc, $start_y); ($rc, $start_y, $content) = $text->column($page, $text, $grfx, $markup, $content, 'rect'=>$rect, 'outline'=>$outline, 'font_size'=>$fs); while ($rc == 1) { # ran out of column, do another $rect->[0] += 50+$rect->[2]; ($rc, $start_y, $content) = $text->column($page, $text, $grfx, 'pre', $content, 'rect'=>$rect, 'outline'=>$outline, 'font_size'=>$fs); } return; } # pause during debug sub pause { print STDERR "=====> Press Enter key to continue..."; my $input = <>; return; } # restore font and color in case previous column left it in an odd state. # the default behavior is to use whatever font and color was left from any # previous operation (not necessarily a column() call) unless it was # overridden by various settings. sub restore_props { my ($text, $grfx) = @_; # $text->fillcolor('black'); # $grfx->strokecolor('black'); # italic and bold get reset to 'normal' anyway on column() entry, # but need to fix font face in case it was left something odd # $text->font($pdf->get_font('face'=>'default', 'italic'=>0, 'bold'=>0), 12); return; } PDF-Builder-3.026/examples/Content.pl0000644000000000000000000017661114534467462016037 0ustar rootroot#!/usr/bin/perl # exercise Content.pm as much as possible # outputs Content.pdf # author: Phil M Perry use warnings; use strict; our $VERSION = '3.026'; # VERSION our $LAST_UPDATE = '3.023'; # manually update whenever code is changed use Math::Trig; use List::Util qw(min max); #use constant in => 1 / 72; #use constant cm => 2.54 / 72; #use constant mm => 25.4 / 72; #use constant pt => 1; use PDF::Builder; my $PDFname = $0; $PDFname =~ s/\..*$//; # remove extension $PDFname .= '.pdf'; # add new extension my $globalX = 0; my $globalY = 0; my $compress = 'none'; #my $compress = 'flate'; my $pdf = PDF::Builder->new(-compress => $compress); my ($page, $textUnder, $grfx, $text); # objects for page, graphics, text my (@base, @styles, @points, $i, $lw, $angle, @npts); my (@cellLoc, @cellSize, $font, $width, $d1, $d2, $d3, $d4); my @axisOffset = (5, 5); # clear the edge of the cell my $pageNo = 0; nextPage(); # next (first) page of output, 523pt wide x 720pt high my $fontR = $pdf->corefont('Times-Roman'); my $fontI = $pdf->corefont('Times-Italic'); my $fontC = $pdf->corefont('Courier'); # ============ demonstrate graphics =========================================== # ---------------------------------------------------- # 1. translate 0,0 to 36,36 and draw old and new axes @cellLoc = makeCellLoc(0, 0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; # old axes at "0,0" colors('black'); $grfx->transform(-translate => \@base); $text->transform(-translate => \@base); drawAxes(); drawLabels('oldX', 'oldY'); $grfx->restore(); $grfx->save(); # new axes at "36,36" colors('red'); $base[0] += 36; $base[1] += 36; $grfx->transform(-translate => \@base); $text->transform(-translate => \@base); drawAxes(); drawLabels('newX', 'newY'); # caption drawCaption(['translate(36, 36)'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 2. rotate new axes 30 degrees from old @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; # the translate is just to give clearance for rotated axes $base[0] += 50; $base[1] += 15; # old axes at "0,0" colors('black'); $grfx->transform(-translate => \@base); $text->transform(-translate => \@base); drawAxes(); drawLabels('oldX', 'oldY'); $grfx->restore(); $grfx->save(); # new axes rotated 30 colors('red'); # axes are drawn at @axisOffset, so need to correct for that so origins coincide # alpha must be less than 90 degrees $base[0] += 2.627; # AOy(sin(alpha) + sin(alpha+90) - 1) $base[1] -= 1.740; # AOx(cos(alpha) + cos(alpha+90) - 1) $grfx->transform(-translate => \@base, -rotate => 30); $text->transform(-translate => \@base, -rotate => 30); drawAxes(); drawLabels('newX', 'newY'); # caption drawCaption(['rotate(30)'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 3. scale axes X 1.2x, Y 0.5x @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; # the translate is just to give clearance for scaled axes $base[0] += 5; $base[1] += 15; # old axes at "0,0" colors('black'); $grfx->transform(-translate => \@base); $text->transform(-translate => \@base); drawAxes(); drawLabels('oldX', 'oldY'); $grfx->restore(); $grfx->save(); # new axes scaled 1.2x .5x colors('red'); # axes are drawn at @axisOffset, so need to correct for that so origins coincide # when scaled in both directions $base[0] -= 1.0; $base[1] += 2.5; $grfx->transform(-translate => \@base, -scale => [1.2, 0.5]); $text->transform(-translate => \@base, -scale => [1.2, 0.5]); drawAxes(); drawLabels('newX', 'newY'); # caption drawCaption(['scale(1.2, .5)']); $grfx->restore(); # ---------------------------------------------------- # 4. skew axes X 10 degrees, Y 15 degrees @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; # the translate is just to give clearance for skewed axes $base[0] += 5; $base[1] += 15; # old axes at "0,0" colors('black'); $grfx->transform(-translate => \@base); $text->transform(-translate => \@base); drawAxes(); drawLabels('oldX', 'oldY'); $grfx->restore(); $grfx->save(); # new axes skewed 10 deg (CCW from X), 15 deg (CW from Y) colors('red'); # axes are drawn at @axisOffset, so need to correct for that so origins coincide # when skewed in both directions $base[0] -= 1.0; $base[1] -= 1.0; $grfx->transform(-translate => \@base, -skew => [10, 15]); $text->transform(-translate => \@base, -skew => [10, 15]); drawAxes(); drawLabels('newX', 'newY'); # caption drawCaption(['skew(10, 15)']); $grfx->restore(); # ---------------------------------------------------- # 5. rotate then translate @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; # the translate is just to give clearance for rotated axes $base[0] += 20; $base[1] += 0; # old axes at "0,0" colors('black'); $grfx->transform(-translate => \@base); $text->transform(-translate => \@base); drawAxes(); drawLabels('oldX', 'oldY'); $grfx->restore(); $grfx->save(); # new axes translate(50,15) then rotate(30) colors('red'); $base[0] += 50; $base[1] += 15; $grfx->transform(-translate => \@base, -rotate => 30); $text->transform(-translate => \@base, -rotate => 30); drawAxes(); drawLabels('newX', 'newY'); # caption drawCaption(['translate(50, 15)', 'rotate(30)'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 6. rotate then translate @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; # the translate is just to give clearance for rotated axes $base[0] += 20; $base[1] += 0; # old axes at "0,0" colors('black'); $grfx->transform(-translate => \@base); $text->transform(-translate => \@base); drawAxes(); drawLabels('oldX', 'oldY'); $grfx->restore(); $grfx->save(); # new axes rotate(30) then translate(50,15) # actually, this simulates what would happen if you rotated about the # old origin and then translated, remembering that we start with 0,0 # origin at the lower left corner of the page, rather than the old axes. # we have to use the transform() call, which fixes the order in which # operations are done. # alpha = 30, beta = atan2(15, 50), len = sqrt(15^2 + 50^2) # addl x = len*cos(alpha+beta), addl y = len*sin(alpha+beta) colors('red'); $base[0] += 35.80; $base[1] += 37.99; $grfx->transform(-translate => \@base, -rotate => 30); $text->transform(-translate => \@base, -rotate => 30); drawAxes(); drawLabels('newX', 'newY'); # caption drawCaption(['rotate(30)', 'translate(50, 15)'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 7. various linewidths @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; $base[0] += 10; $base[1] += 10; $grfx->translate(@base); $grfx->strokecolor('black'); foreach my $w (1, 2, 4, 8, 16) { $text->translate($base[0]+$w*8, $base[1]); $text->text_center($w); $grfx->linewidth($w); $grfx->poly($w*8,10, $w*8+10,110); $grfx->stroke(); } # caption drawCaption(['linewidth()'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 8. various linecaps @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; $base[0] += 10; $base[1] += 10; @styles = ('butt', 'round', 'projecting square'); $grfx->translate(@base); $grfx->strokecolor('black'); foreach my $cap (0, 1, 2) { $text->font($fontC, 12); $text->translate($base[0]+8, $base[1]+17+35*$cap); $text->text_center($cap); $text->font($fontI, 8); $text->translate($base[0]+83, $base[1]+17+35*$cap-13); $text->text_center($styles[$cap]); $grfx->linecap($cap); $grfx->strokecolor('red'); $grfx->linewidth(20); $grfx->poly(37,20+35*$cap, 128,20+35*$cap); $grfx->stroke(); $grfx->linecap(0); $grfx->strokecolor('black'); $grfx->poly(37,20+35*$cap, 128,20+35*$cap); $grfx->stroke(); greenLine([37,20+35*$cap, 128,20+35*$cap]); } # caption drawCaption(['linecap()'], 'LC'); $grfx->restore(); if (1 == 1) { # needs more research... shows no visible difference # ---------------------------------------------------- # 9. flatness @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; $base[0] += 10; $base[1] += 10; $grfx->translate(@base); $grfx->strokecolor('black'); $grfx->linewidth(1); $grfx->flatness(1); #$grfx->circle(73,55, 30); @points = (40,75, 100,90, 130,60); # EP1=20,20, CP1, CP2, EP2 $grfx->linedash(); $grfx->move(20, 20); $grfx->curve(@points); $grfx->stroke(); $grfx->flatness(5); #$grfx->circle(73,55, 33); @points = (40,80, 100,95, 130,65); # EP1=20,20, CP1, CP2, EP2 $grfx->linedash(); $grfx->move(20, 25); $grfx->curve(@points); $grfx->stroke(); $text->translate($base[0]+100,$base[1]+60); $text->text_center('1.0'); $text->translate($base[0]+115,$base[1]+85); $text->text_center('5.0'); # caption drawCaption(['flatness()'], 'LC'); $grfx->restore(); } # ---------------------------------------------------- # 10. miter linejoin @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); $lw = 20; makeCell(@cellLoc, @cellSize); @base=@cellLoc; $base[0] += 10; $base[1] += 10; $grfx->translate(@base); @points = (135,25, 35,25, 135,95); $grfx->linecap(0); $grfx->linejoin(0); # draw red, including miter or bevel joint per setting (all that will show) $grfx->strokecolor('red'); $grfx->linewidth($lw); $grfx->poly(@points); $grfx->stroke(); # draw black each of the two thick bars (butt linecap), overlaying most red $grfx->strokecolor('black'); for ($i=0; $ipoly($points[$i],$points[$i+1], $points[$i+2],$points[$i+3]); $grfx->stroke(); } # gray overlap of bars, as custom-written filled shape $grfx->fillcolor('#333333'); $angle = atan2($points[5]-$points[3], $points[4]-$points[2]); @npts = ($points[2], $points[3], $points[2], $points[3]+$lw/2, $points[2]+$lw/2*(1/tan($angle)+1/sin($angle)),$points[3]+$lw/2, $points[2]+$lw/2*sin($angle),$points[3]-$lw/2*cos($angle)); $grfx->poly(@npts); $grfx->close(); $grfx->fill(); # dots and green centerline greenLine(\@points); # caption drawCaption(['linejoin(0) (miter)'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 11. round linejoin @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); $lw = 20; makeCell(@cellLoc, @cellSize); @base=@cellLoc; $base[0] += 10; $base[1] += 10; $grfx->translate(@base); @points = (135,25, 35,25, 135,95); $grfx->linecap(0); $grfx->linejoin(1); # draw red, including miter or bevel joint per setting (all that will show) $grfx->strokecolor('red'); $grfx->linewidth($lw); $grfx->poly(@points); $grfx->stroke(); # draw black each of the two thick bars (butt linecap), overlaying most red $grfx->strokecolor('black'); for ($i=0; $ipoly($points[$i],$points[$i+1], $points[$i+2],$points[$i+3]); $grfx->stroke(); } # gray overlap of bars, as custom-written filled shape $grfx->fillcolor('#333333'); $angle = atan2($points[5]-$points[3], $points[4]-$points[2]); @npts = ($points[2], $points[3], $points[2], $points[3]+$lw/2, $points[2]+$lw/2*(1/tan($angle)+1/sin($angle)),$points[3]+$lw/2, $points[2]+$lw/2*sin($angle),$points[3]-$lw/2*cos($angle)); $grfx->poly(@npts); $grfx->close(); $grfx->fill(); # dots and green centerline greenLine(\@points); # caption drawCaption(['linejoin(1) (round)'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 12. bevel linejoin @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); $lw = 20; makeCell(@cellLoc, @cellSize); @base=@cellLoc; $base[0] += 10; $base[1] += 10; $grfx->translate(@base); @points = (135,25, 35,25, 135,95); $grfx->linecap(0); $grfx->linejoin(2); # draw red, including miter or bevel joint per setting (all that will show) $grfx->strokecolor('red'); $grfx->linewidth($lw); $grfx->poly(@points); $grfx->stroke(); # draw black each of the two thick bars (butt linecap), overlaying most red $grfx->strokecolor('black'); for ($i=0; $ipoly($points[$i],$points[$i+1], $points[$i+2],$points[$i+3]); $grfx->stroke(); } # gray overlap of bars, as custom-written filled shape $grfx->fillcolor('#333333'); $angle = atan2($points[5]-$points[3], $points[4]-$points[2]); @npts = ($points[2], $points[3], $points[2], $points[3]+$lw/2, $points[2]+$lw/2*(1/tan($angle)+1/sin($angle)),$points[3]+$lw/2, $points[2]+$lw/2*sin($angle),$points[3]-$lw/2*cos($angle)); $grfx->poly(@npts); $grfx->close(); $grfx->fill(); # dots and green centerline greenLine(\@points); # caption drawCaption(['linejoin(2) (bevel)'], 'LC'); $grfx->restore(); # new miter limit (4) should be in effect from here on out # HOWEVER, a nextPage() call (within makeCellLoc()) creates a new $grfx, # so it's not carried over to the next cell! repeat at each miter limit # example, after makeCellLoc(), to be sure it's there. #$grfx->miterlimit(4); # default is 10 (11.5 degree miter) # ---------------------------------------------------- # 13. linejoin(0) (miter) at 135 deg at miterlimit 4 @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); $grfx->miterlimit(4); # default is 10 (11.5 degree miter) makeCell(@cellLoc, @cellSize); @base=@cellLoc; $base[0] += 10; $base[1] += 10; $grfx->translate(@base); @points = (135,25, 55,25, 15,95); $grfx->linecap(0); $grfx->linejoin(0); # draw red, including miter or bevel joint per setting (all that will show) $grfx->strokecolor('red'); $grfx->linewidth($lw); $grfx->poly(@points); $grfx->stroke(); # draw black each of the two thick bars (butt linecap), overlaying most red $grfx->strokecolor('black'); for ($i=0; $ipoly($points[$i],$points[$i+1], $points[$i+2],$points[$i+3]); $grfx->stroke(); } # gray overlap of bars, as custom-written filled shape $grfx->fillcolor('#333333'); $angle = atan2($points[5]-$points[3], $points[4]-$points[2]); @npts = ($points[2], $points[3], $points[2], $points[3]+$lw/2, $points[2]+$lw/2*(1/tan($angle)+1/sin($angle)),$points[3]+$lw/2, $points[2]+$lw/2*sin($angle),$points[3]-$lw/2*cos($angle)); $grfx->poly(@npts); $grfx->close(); $grfx->fill(); # dots and green centerline greenLine(\@points); # caption drawCaption(['mitered join 135 deg'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 14. linejoin(0) (miter) at 90 deg at miterlimit 4 @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); $grfx->miterlimit(4); # default is 10 (11.5 degree miter) makeCell(@cellLoc, @cellSize); @base=@cellLoc; $base[0] += 10; $base[1] += 10; $grfx->translate(@base); @points = (135,25, 55,25, 55,95); $grfx->linecap(0); $grfx->linejoin(0); # draw red, including miter or bevel joint per setting (all that will show) $grfx->strokecolor('red'); $grfx->linewidth($lw); $grfx->poly(@points); $grfx->stroke(); # draw black each of the two thick bars (butt linecap), overlaying most red $grfx->strokecolor('black'); for ($i=0; $ipoly($points[$i],$points[$i+1], $points[$i+2],$points[$i+3]); $grfx->stroke(); } # gray overlap of bars, as custom-written filled shape $grfx->fillcolor('#333333'); $angle = atan2($points[5]-$points[3], $points[4]-$points[2]); @npts = ($points[2], $points[3], $points[2], $points[3]+$lw/2, $points[2]+$lw/2*(1/tan($angle)+1/sin($angle)),$points[3]+$lw/2, $points[2]+$lw/2*sin($angle),$points[3]-$lw/2*cos($angle)); $grfx->poly(@npts); $grfx->close(); $grfx->fill(); # dots and green centerline greenLine(\@points); # caption drawCaption(['mitered join 90 deg'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 15. linejoin(0) (miter) at 45 deg at miterlimit 4 @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); $grfx->miterlimit(4); # default is 10 (11.5 degree miter) makeCell(@cellLoc, @cellSize); @base=@cellLoc; $base[0] += 10; $base[1] += 10; $grfx->translate(@base); @points = (135,25, 55,25, 135,105); $grfx->linecap(0); $grfx->linejoin(0); # draw red, including miter or bevel joint per setting (all that will show) $grfx->strokecolor('red'); $grfx->linewidth($lw); $grfx->poly(@points); $grfx->stroke(); # draw black each of the two thick bars (butt linecap), overlaying most red $grfx->strokecolor('black'); for ($i=0; $ipoly($points[$i],$points[$i+1], $points[$i+2],$points[$i+3]); $grfx->stroke(); } # gray overlap of bars, as custom-written filled shape $grfx->fillcolor('#333333'); $angle = atan2($points[5]-$points[3], $points[4]-$points[2]); @npts = ($points[2], $points[3], $points[2], $points[3]+$lw/2, $points[2]+$lw/2*(1/tan($angle)+1/sin($angle)),$points[3]+$lw/2, $points[2]+$lw/2*sin($angle),$points[3]-$lw/2*cos($angle)); $grfx->poly(@npts); $grfx->close(); $grfx->fill(); # dots and green centerline greenLine(\@points); # caption drawCaption(['mitered join 45 deg'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 16. linejoin(0) (miter) at 30 deg at miterlimit 4 @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); $grfx->miterlimit(4); # default is 10 (11.5 degree miter) makeCell(@cellLoc, @cellSize); @base=@cellLoc; $base[0] += 10; $base[1] += 10; $grfx->translate(@base); @points = (135,25, 55,25, 135,71.2); $grfx->linecap(0); $grfx->linejoin(0); # draw red, including miter or bevel joint per setting (all that will show) $grfx->strokecolor('red'); $grfx->linewidth($lw); $grfx->poly(@points); $grfx->stroke(); # draw black each of the two thick bars (butt linecap), overlaying most red $grfx->strokecolor('black'); for ($i=0; $ipoly($points[$i],$points[$i+1], $points[$i+2],$points[$i+3]); $grfx->stroke(); } # gray overlap of bars, as custom-written filled shape $grfx->fillcolor('#333333'); $angle = atan2($points[5]-$points[3], $points[4]-$points[2]); @npts = ($points[2], $points[3], $points[2], $points[3]+$lw/2, $points[2]+$lw/2*(1/tan($angle)+1/sin($angle)),$points[3]+$lw/2, $points[2]+$lw/2*sin($angle),$points[3]-$lw/2*cos($angle)); $grfx->poly(@npts); $grfx->close(); $grfx->fill(); # dots and green centerline greenLine(\@points); # caption drawCaption(['mitered join 30 deg'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 17. linejoin(0) (miter) at 20 deg at miterlimit 4 @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); $grfx->miterlimit(4); # default is 10 (11.5 degree miter) makeCell(@cellLoc, @cellSize); @base=@cellLoc; $base[0] += 10; $base[1] += 10; $grfx->translate(@base); @points = (135,25, 55,25, 135,54.1); $grfx->linecap(0); $grfx->linejoin(0); # draw red, including miter or bevel joint per setting (all that will show) $grfx->strokecolor('red'); $grfx->linewidth($lw); $grfx->poly(@points); $grfx->stroke(); # draw black each of the two thick bars (butt linecap), overlaying most red $grfx->strokecolor('black'); for ($i=0; $ipoly($points[$i],$points[$i+1], $points[$i+2],$points[$i+3]); $grfx->stroke(); } # gray overlap of bars, as custom-written filled shape $grfx->fillcolor('#333333'); $angle = atan2($points[5]-$points[3], $points[4]-$points[2]); @npts = ($points[2], $points[3], $points[2], $points[3]+$lw/2, $points[2]+$lw/2*(1/tan($angle)+1/sin($angle)),$points[3]+$lw/2, $points[2]+$lw/2*sin($angle),$points[3]-$lw/2*cos($angle)); $grfx->poly(@npts); $grfx->close(); $grfx->fill(); # dots and green centerline greenLine(\@points); # caption drawCaption(['mitered join 20 deg'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 18. linejoin(0) (miter) at 15 deg at miterlimit 4 @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); $grfx->miterlimit(4); # default is 10 (11.5 degree miter) makeCell(@cellLoc, @cellSize); @base=@cellLoc; $base[0] += 10; $base[1] += 10; $grfx->translate(@base); @points = (135,25, 55,25, 135,46.4); $grfx->linecap(0); $grfx->linejoin(0); # draw red, including miter or bevel joint per setting (all that will show) $grfx->strokecolor('red'); $grfx->linewidth($lw); $grfx->poly(@points); $grfx->stroke(); # draw black each of the two thick bars (butt linecap), overlaying most red $grfx->strokecolor('black'); for ($i=0; $ipoly($points[$i],$points[$i+1], $points[$i+2],$points[$i+3]); $grfx->stroke(); } # gray overlap of bars, as custom-written filled shape $grfx->fillcolor('#333333'); $angle = atan2($points[5]-$points[3], $points[4]-$points[2]); @npts = ($points[2], $points[3], $points[2], $points[3]+$lw/2, $points[2]+$lw/2*(1/tan($angle)+1/sin($angle)),$points[3]+$lw/2, $points[2]+$lw/2*sin($angle),$points[3]-$lw/2*cos($angle)); $grfx->poly(@npts); $grfx->close(); $grfx->fill(); # dots and green centerline greenLine(\@points); # caption drawCaption(['mitered join 15 deg'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 19. linedash() three examples @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; $base[0] += 10; $base[1] += 10; @styles = ('linedash()', 'linedash(10)', 'linedash(15, 10)', 'linedash(-pattern=>[15,8, 2,5], -shift=>8)'); $grfx->translate(@base); $grfx->strokecolor('black'); $grfx->linewidth(2); foreach my $pat (0, 1, 2, 3) { $text->font($fontI, 8); $text->translate($base[0]+73, $base[1]+17+25*$pat-8); $text->text_center($styles[$pat]); if ($pat == 0) { $grfx->linedash(); } elsif ($pat == 1) { $grfx->linedash(10); } elsif ($pat == 2) { $grfx->linedash(15, 10); } else { $grfx->linedash(-pattern=>[15,8, 2,5], -shift=>8); } $grfx->poly(20,20+25*$pat, 130,20+25*$pat); $grfx->stroke(); } # caption drawCaption(['linedash()'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # egstate(): not shown # ---------------------------------------------------- # move(): shown as part of other examples # ---------------------------------------------------- # close(): shown as part of other examples # ---------------------------------------------------- # endpath(): would be shown as part of other examples # ---------------------------------------------------- # 20. hline(), line(), vline(), poly() @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; $base[0] += 10; $base[1] += 20; $grfx->strokecolor('black'); $grfx->linewidth(2); $text->font($fontC, 8); # move, hline, diagonal line, vline $grfx->save(); $text->translate($base[0]+10, $base[1]+90); $text->text('hline, line, vline'); $grfx->translate(@base); $grfx->move(10, 25); $grfx->hline(30); $grfx->line(60, 60); $grfx->vline(80); $grfx->stroke(); $grfx->restore(); # poly $grfx->save(); $text->translate($base[0]+130, $base[1]+0); $text->text_right('poly'); $grfx->translate($base[0]+70, $base[1]-10); $grfx->poly(10,25, 30,25, 60,60, 60,80); $grfx->stroke(); $grfx->restore(); # caption drawCaption(['hline, line, vline, or poly'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 21. rect() @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; $base[0] += 10; $base[1] += 20; $grfx->strokecolor('black'); $grfx->linewidth(1); $text->font($fontC, 8); # single rectangle (x,y w,h) $grfx->save(); $text->translate($base[0]+30, $base[1]+95); $text->text_center('single rect'); $grfx->translate(@base); $grfx->rect(10,70, 30,15); $grfx->stroke(); greenLine([10,70]); $grfx->restore(); # multiple rectangles (x,y w,h) with common corner $grfx->save(); $text->translate($base[0]+100, $base[1]-5); $text->text_center('multiple rects'); $grfx->translate($base[0]+90,$base[1]-35); # all 10,70 corner. UR + +, LR + -, LL - -, UL - + $grfx->rect(10,70, 30,15, 10,70, 40,-20, 10,70, -35,-25, 10,70, -45,25); $grfx->stroke(); greenLine([10,70]); $grfx->restore(); # caption drawCaption(['rect()'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 22. rectxy() two examples @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; $base[0] += 10; $base[1] += 10; $grfx->strokecolor('black'); $grfx->linewidth(1); $text->font($fontC, 8); # LL - UR corners $grfx->save(); $text->translate($base[0]+10, $base[1]+90); $text->text('LL - UR corners'); $grfx->translate(@base); $grfx->rectxy(10,70, 40,80); $grfx->stroke(); greenLine([10, 70]); $grfx->restore(); # LR - UL corners $grfx->save(); $text->translate($base[0]+130, $base[1]+0); $text->text_right('LR - UL corners'); $grfx->translate($base[0]+70, $base[1]-10); $grfx->rectxy(35,25, 10,50); $grfx->stroke(); greenLine([35,25]); $grfx->restore(); # caption drawCaption(['rectxy()'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 23. circle() @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; $base[0] += 10; $base[1] += 10; $grfx->strokecolor('black'); $grfx->linewidth(2); $text->font($fontC, 8); $grfx->translate(@base); # radius 20, 40, 60 at 75, 55 for (my $r = 20; $r < 80; $r += 20) { $grfx->save(); $grfx->circle(75, 55, $r); $grfx->stroke(); $grfx->restore(); } # caption drawCaption(['circle() 3 radii'], 'LC'); $text->translate($cellLoc[0]+$cellSize[0]/2, $cellLoc[1]-20); $text->font($fontC, 12); $text->fillcolor('black'); $text->text_center('circle() 3 radii'); $grfx->restore(); # ---------------------------------------------------- # 24. ellipse() @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; $base[0] += 10; $base[1] += 10; $grfx->strokecolor('black'); $grfx->linewidth(2); $text->font($fontC, 8); $grfx->translate(@base); # semidiameters 10, 20 at 75, 55 $grfx->save(); $grfx->ellipse(75,55, 10,20); $grfx->stroke(); $grfx->restore(); # semidiameters 40, 30 at 75, 55 $grfx->save(); $grfx->ellipse(75,55, 40,30); $grfx->stroke(); $grfx->restore(); # semidiameters 50, 60 at 75, 55 $grfx->save(); $grfx->ellipse(75,55, 50,60); $grfx->stroke(); $grfx->restore(); # caption drawCaption(['ellipse() 3 radius sets'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 25. arc() @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; $base[0] += 10; $base[1] += 10; $grfx->strokecolor('black'); $grfx->linewidth(2); $text->font($fontC, 8); $grfx->translate(@base); # CCW 90 degrees, semidiameters 10, 20 at 75, 55 $grfx->save(); $grfx->arc(75,55, 10,20, 90,180, 1); $grfx->stroke(); $grfx->restore(); # CCW 180 degrees, semidiameters 40, 30 at 75, 55 $grfx->save(); $grfx->arc(75,55, 40,30, 235,45, 1); $grfx->stroke(); $grfx->restore(); # CW 315 degrees, diameter 60 at 75, 55 $grfx->save(); $grfx->arc(75,55, 60,60, 310,355, 1, 1); $grfx->stroke(); $grfx->restore(); # caption drawCaption(['arc() 3 radius sets'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 26. pie() a.k.a. Pac-man eating a slice of pie @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; $base[0] += 10; $base[1] += 10; $grfx->strokecolor('black'); $grfx->linewidth(2); $text->font($fontC, 8); $grfx->translate(@base); # semidiameters 40,30 50 degree slice missing centered at 0 degrees $grfx->save(); # $grfx->pie(75,55, 40,30, 45,360); $grfx->pie(75,55, 40,30, 25,335); $grfx->stroke(); $grfx->restore(); # removed slice offset to right $grfx->save(); $grfx->pie(95,55, 40,30, 25,335, 1); # draw CW this time $grfx->stroke(); $grfx->restore(); # caption drawCaption(['pie() one slice removed'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 27. curve() (cubic Bezier curve) @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; $base[0] += 10; $base[1] += 10; $grfx->strokecolor('black'); $grfx->linewidth(2); $text->font($fontC, 8); $grfx->translate(@base); @points = (40,75, 100,90, 130,60); # EP1=20,20, CP1, CP2, EP2 $grfx->linedash(); $grfx->move(20, 20); $grfx->curve(@points); $grfx->stroke(); $grfx->linedash(4); greenLine([20, 20, @points]); $grfx->strokecolor('black'); # caption drawCaption(['curve()'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 28. qbspline() (cubic Bezier curve with synthesized control points) @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; $base[0] += 10; $base[1] += 10; $grfx->strokecolor('black'); $grfx->linewidth(2); $text->font($fontC, 8); $grfx->translate(@base); @points = (40,75, 130,60); # EP1=20,20, CP1, EP2 $grfx->linedash(); $grfx->move(20, 20); $grfx->qbspline(@points); $grfx->stroke(); $grfx->linedash(4); greenLine([20, 20, @points]); $grfx->strokecolor('black'); # caption drawCaption(['qbspline()'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 28A. qbspline() (multipiece spline, and with line segment) @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; $base[0] += 10; $base[1] += 10; $grfx->strokecolor('black'); $grfx->linewidth(2); $text->font($fontC, 8); $grfx->translate(@base); @points = (40,95, 50,70, 80,100, 130,70); # EP1=20,50, CP1, P2, CP2, P3 $grfx->linedash(); $grfx->move(20, 50); $grfx->qbspline(@points); $grfx->stroke(); $grfx->linedash(4); greenLine([20, 50, @points]); $grfx->strokecolor('black'); # currently excess point P4 is not drawn (line) as part of the qbspline @points = (40,55, 50,30, 80,60, 130,30, 135,10); # EP1=20,10, CP1, P2, CP2, P3, P4 $grfx->linewidth(2); $grfx->linedash(); $grfx->move(20, 10); $grfx->qbspline(@points); $grfx->stroke(); $grfx->linedash(4); greenLine([20, 10, @points]); $grfx->strokecolor('black'); # caption drawCaption(['multi qbspline()'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 28B. bspline() (multipiece cubic Bezier spline) @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; $base[0] += 10; $base[1] += 10; $grfx->strokecolor('black'); $grfx->linewidth(2); $text->font($fontC, 8); $grfx->translate(@base); @points = (0,0, 20,40, 70,50, 115,40, 145,35, 145,45, 115,40, 70,5); $grfx->linedash(); $grfx->move(0,0); $grfx->bspline(\@points, -debug=>4); $grfx->stroke(); @points = (0,65, 20,105, 70,115, 115,105, 145,100, 145,110, 115,105, 70,70); $grfx->linedash(); $grfx->move(0,65); $grfx->bspline(\@points, -debug=>1); $grfx->stroke(); # caption drawCaption(['bspline() with', 'constructors'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # ---------------------------------------------------- # 29. bogen() (circular arc segment) 1/4 smaller arc, non-flipped @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; $base[0] += 10; $base[1] += 10; $grfx->strokecolor('black'); $grfx->linewidth(2); $text->font($fontC, 8); $grfx->translate(@base); # two intersecting circles in gray $grfx->save(); $grfx->strokecolor('#999999'); $grfx->circle(50,45, 40); $grfx->circle(90,70, 40); $grfx->stroke(); $grfx->restore(); # bogen (arc) smaller arc, clockwise (not flipped) # endpoints are manually calculated $grfx->bogen(53,85, 87,30, 40, 1, 0, 0); #$grfx->hline(160); # show end point of bogen $grfx->stroke(); $text->translate($base[0]+49, $base[1]+90); $text->text_right('P1'); $text->translate($base[0]+92, $base[1]+19); $text->text('P2'); greenLine([53, 85]); greenLine([87, 30]); # caption drawCaption(['bogen() sm arc no-flip'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 29A. bogen() (circular arc segment) 1/4 smaller arc, non-flipped # with start and end connecting lines @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; $base[0] += 10; $base[1] += 10; $grfx->strokecolor('black'); $grfx->linewidth(2); $text->font($fontC, 8); $grfx->translate(@base); # two intersecting circles in gray $grfx->save(); $grfx->strokecolor('#999999'); $grfx->circle(50,45, 40); $grfx->circle(90,70, 40); $grfx->stroke(); $grfx->restore(); # bogen (arc) smaller arc, clockwise (not flipped) # endpoints are manually calculated $grfx->move(0,0); # will connect to existing point $grfx->bogen(53,85, 87,30, 40, 0, 0, 0); $grfx->hline(150); # show end point of bogen $grfx->stroke(); $text->translate($base[0]+49, $base[1]+90); $text->text_right('P1'); $text->translate($base[0]+92, $base[1]+19); $text->text('P2'); greenLine([53, 85]); greenLine([87, 30]); # caption drawCaption(['bogen move=F, end line'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 30. bogen() (circular arc segment) 2/4 larger arc, non-flipped @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; $base[0] += 10; $base[1] += 10; $grfx->strokecolor('black'); $grfx->linewidth(2); $text->font($fontC, 8); $grfx->translate(@base); # two intersecting circles in gray $grfx->save(); $grfx->strokecolor('#999999'); $grfx->circle(50,45, 40); $grfx->circle(90,70, 40); $grfx->stroke(); $grfx->restore(); # bogen (arc) larger arc, clockwise (not flipped) # endpoints are manually calculated $grfx->bogen(53,85, 87,30, 40, 1, 1, 0); #$grfx->hline(160); # show end point of bogen $grfx->stroke(); $text->translate($base[0]+49, $base[1]+90); $text->text_right('P1'); $text->translate($base[0]+92, $base[1]+19); $text->text('P2'); greenLine([53, 85]); greenLine([87, 30]); # caption drawCaption(['bogen() lg arc no-flip'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 31. bogen() (circular arc segment) 3/4 smaller arc, flipped (mirrored) @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; $base[0] += 10; $base[1] += 10; $grfx->strokecolor('black'); $grfx->linewidth(2); $text->font($fontC, 8); $grfx->translate(@base); # two intersecting circles in gray $grfx->save(); $grfx->strokecolor('#999999'); $grfx->circle(50,45, 40); $grfx->circle(90,70, 40); $grfx->stroke(); $grfx->restore(); # bogen (arc) smaller arc, counter-clockwise (flipped) # endpoints are manually calculated $grfx->bogen(53,85, 87,30, 40, 1, 0, 1); #$grfx->hline(160); # show end point of bogen $grfx->stroke(); $text->translate($base[0]+49, $base[1]+90); $text->text_right('P1'); $text->translate($base[0]+92, $base[1]+19); $text->text('P2'); greenLine([53, 85]); greenLine([87, 30]); # caption drawCaption(['bogen() sm arc flip'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 32. bogen() (circular arc segment) 4/4 larger arc, flipped (mirrored) @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; $base[0] += 10; $base[1] += 10; $grfx->strokecolor('black'); $grfx->linewidth(2); $text->font($fontC, 8); $grfx->translate(@base); # two intersecting circles in gray $grfx->save(); $grfx->strokecolor('#999999'); $grfx->circle(50,45, 40); $grfx->circle(90,70, 40); $grfx->stroke(); $grfx->restore(); # bogen (arc) larger arc, counter-clockwise (flipped) # endpoints are manually calculated $grfx->bogen(53,85, 87,30, 40, 1, 1, 1); #$grfx->hline(160); # show end point of bogen $grfx->stroke(); $text->translate($base[0]+49, $base[1]+90); $text->text_right('P1'); $text->translate($base[0]+92, $base[1]+19); $text->text('P2'); greenLine([53, 85]); greenLine([87, 30]); # caption drawCaption(['bogen() lg arc flip'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # stroke(): shown as part of other examples # ---------------------------------------------------- # ---------------------------------------------------- # 33. fill(): 5 pt star with both rules @cellLoc = makeCellLoc(1); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $width=80; $d1= $width*cos(36/180*3.141593); $d2= $width*sin(36/180*3.141593); $d3= $width*cos(18/180*3.141593); $d4= $width*sin(18/180*3.141593); $grfx->strokecolor('black'); $grfx->fillcolor('#999'); $grfx->linewidth(2); $text->font($fontC, 8); $grfx->translate(@base); # fill() (non-zero winding) $grfx->save(); @points = (25,50, $d1,$d2, -$width,0, $d1,-$d2, -$d4,$d3); # convert relative coordinates to absolute for ($i=2; $i<@points; $i+=2) { $points[$i] += $points[$i-2]; $points[$i+1] += $points[$i-1]; } $grfx->poly(@points); $grfx->close(); $grfx->fill(); $grfx->restore(); # fill() (even-odd) $grfx->save(); @points = (95,20, $d1,$d2, -$width,0, $d1,-$d2, -$d4,$d3); # convert relative coordinates to absolute for ($i=2; $i<@points; $i+=2) { $points[$i] += $points[$i-2]; $points[$i+1] += $points[$i-1]; } $grfx->poly(@points); $grfx->close(); $grfx->fill(1); $grfx->restore(); # caption drawCaption(['fill() with non-zero', 'winding and even-odd'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 34. fillstroke(): 5 pt star with both rules @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $width=80; $d1= $width*cos(36/180*3.141593); $d2= $width*sin(36/180*3.141593); $d3= $width*cos(18/180*3.141593); $d4= $width*sin(18/180*3.141593); $grfx->strokecolor('black'); $grfx->fillcolor('#999'); $grfx->linewidth(2); $text->font($fontC, 8); $grfx->translate(@base); # fill() (non-zero winding) $grfx->save(); @points = (25,50, $d1,$d2, -$width,0, $d1,-$d2, -$d4,$d3); # convert relative coordinates to absolute for ($i=2; $i<@points; $i+=2) { $points[$i] += $points[$i-2]; $points[$i+1] += $points[$i-1]; } $grfx->poly(@points); $grfx->close(); $grfx->fillstroke(); $grfx->restore(); # fill() (even-odd) $grfx->save(); @points = (95,20, $d1,$d2, -$width,0, $d1,-$d2, -$d4,$d3); # convert relative coordinates to absolute for ($i=2; $i<@points; $i+=2) { $points[$i] += $points[$i-2]; $points[$i+1] += $points[$i-1]; } $grfx->poly(@points); $grfx->close(); $grfx->fillstroke(1); $grfx->restore(); # caption drawCaption(['fillstroke() w/ non-zero', 'winding and even-odd'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 36A. demonstrate multiple text and graphics layers @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $width=80; $grfx->strokecolor('black'); $grfx->fillcolor('#999'); $grfx->linewidth(1); $text->font($fontC, 16); $grfx->translate(@base); # draw using same text for over and under # since grfx defined before text, both text done after $grfx->save(); $text->translate($base[0]+5,$base[1]+100); $text->font($fontC, 12); $text->fillcolor('black'); $text->text("Text under the graphic"); $grfx->fillcolor('red'); $grfx->strokecolor('green'); $grfx->linewidth(3); $grfx->circle(80,95, 20); $grfx->fillstroke(); $text->translate($base[0]+10,$base[1]+82); $text->font($fontC, 12); $text->fillcolor('black'); $text->text("Text over the graphic"); $grfx->restore(); # draw using a second text object for under # since textUnder defined earlier than grfx, text s/b under $grfx->save(); $textUnder->translate($base[0]+5,$base[1]+40); $textUnder->font($fontC, 12); $textUnder->fillcolor('black'); $textUnder->text("Text under the graphic"); $grfx->fillcolor('red'); $grfx->strokecolor('green'); $grfx->linewidth(3); $grfx->circle(80,35, 20); $grfx->fillstroke(); $text->translate($base[0]+10,$base[1]+22); $text->font($fontC, 12); $text->fillcolor('black'); $text->text("Text over the graphic"); $grfx->restore(); # caption drawCaption(['multiple text and', 'graphic objs'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 37. clip(): single box cut out from filled circle @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $width=80; $grfx->strokecolor('black'); $grfx->fillcolor('#999'); $grfx->linewidth(1); $text->font($fontC, 16); $grfx->translate(@base); # clip port dashed square, solid circle $grfx->save(); $grfx->linedash(3); $grfx->rect(40,55, 40,45); $grfx->stroke(); $grfx->linewidth(2); $grfx->linedash(); $grfx->circle(45,90, 30); $grfx->stroke(); $grfx->restore(); # actual clip port, filled and stroked circle $grfx->save(); $grfx->rect(120,10, 40,45); $grfx->clip(); $grfx->endpath(); # necessary for separating the clip and paint $grfx->circle(125,45, 30); $grfx->fillstroke(); $grfx->restore(); # caption drawCaption(['clip()'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 38. clip(): show that clip-on-clip only reduces clipping area @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $width=80; $grfx->strokecolor('black'); $grfx->fillcolor('#999'); $grfx->linewidth(1); $text->font($fontC, 16); $grfx->translate(@base); # clip port dashed squares, solid circle $grfx->save(); $grfx->linedash(3); $grfx->rect(40,55, 40,45); # two intersecting rectangular clip areas $grfx->rect(60,80, 25,25); $grfx->stroke(); $grfx->linewidth(2); $grfx->linedash(); $grfx->circle(45,90, 30); $grfx->stroke(); $grfx->restore(); # actual clip port, filled and stroked circle $grfx->save(); $grfx->rect(120,10, 40,45); $grfx->clip(); $grfx->endpath(); # necessary for separating the clip and paint $grfx->rect(140,35, 25,25); $grfx->clip(); # remaining clipping area is upper right of first rectangle # (the INTERSECTION of the two rectangles) $grfx->endpath(); # necessary for separating the clip and paint $grfx->circle(125,45, 30); $grfx->fillstroke(); $grfx->restore(); # caption drawCaption(['clip() twice'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 39. clip(): show clip with two clipping areas (union) @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $width=80; $grfx->strokecolor('black'); $grfx->fillcolor('#999'); $grfx->linewidth(1); $text->font($fontC, 16); $grfx->translate(@base); # clip port dashed square, solid circle $grfx->save(); $grfx->linedash(3); $grfx->rect(40,55, 40,45); $grfx->rect(60,80, 25,25); $grfx->stroke(); $grfx->linewidth(2); $grfx->linedash(); $grfx->circle(45,90, 30); $grfx->stroke(); $grfx->restore(); # actual clip port, filled and stroked circle $grfx->save(); $grfx->rect(120,10, 40,45); $grfx->rect(140,35, 25,25); # clipping area is UNION of the two (overlapping) $grfx->clip(); $grfx->endpath(); # necessary for separating the clip and paint $grfx->circle(125,45, 30); $grfx->fillstroke(); $grfx->restore(); # caption drawCaption(['clip() once, two areas'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # fillcolor(): shown as part of other examples # ---------------------------------------------------- # strokecolor(): shown as part of other examples # ---------------------------------------------------- # shade(): omit for now # ---------------------------------------------------- # fillcolor(): shown as part of other examples # ---------------------------------------------------- # strokecolor(): shown as part of other examples # ---------------------------------------------------- # ---------------------------------------------------- # 40. image(): display an image, 640x480 scaled to 160x120 # also rotate and clip, just to show off @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $width=80; $grfx->strokecolor('black'); $grfx->fillcolor('#999'); $grfx->linewidth(2); $text->font($fontC, 16); # define clip port, paint image $grfx->save(); # frame 2pt wide, so size to -1 each side $grfx->rect($base[0]+1,$base[1]+1, 168,129); $grfx->clip(); $grfx->endpath(); # necessary for separating the clip and paint $grfx->translate($base[0]+60,$base[1]-30); $grfx->rotate(35); my $img_obj = $pdf->image_jpeg('examples/resources/aptfrontview.jpg'); $grfx->image($img_obj, 5,5, 160,120); $grfx->restore(); # caption drawCaption(['image() rotate + clip'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 41. formimage(): display an image, 640x480 scaled to 160x120 (25%) @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $width=80; $grfx->strokecolor('black'); $grfx->fillcolor('#999'); $grfx->linewidth(2); $text->font($fontC, 16); $grfx->translate(@base); $img_obj = $pdf->image_jpeg('examples/resources/aptfrontview.jpg'); $grfx->formimage($img_obj, 5,5, 0.25*$img_obj->width(),0.25*$img_obj->height()); # caption drawCaption(['formimage() 25%'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 42. formimage(): display an image, 640x480 scaled to 80x120 (12.5 x 25%) @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $width=80; $grfx->strokecolor('black'); $grfx->fillcolor('#999'); $grfx->linewidth(2); $text->font($fontC, 16); $grfx->translate(@base); $img_obj = $pdf->image_jpeg('examples/resources/aptfrontview.jpg'); $grfx->formimage($img_obj, 45,5, 0.125*$img_obj->width(),0.25*$img_obj->height()); # caption drawCaption(['formimage() 12.5x25%'], 'LC'); $grfx->restore(); # ============ demonstrate text =============================================== # ---------------------------------------------------- # 43. charspace(): show -.9 condensed, 0 normal, +3 expanded @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $text->font($fontR, 20); $text->translate($base[0]+10, $base[1]+100); $text->charspace(-0.9); $text->text('Condensed text'); $text->translate($base[0]+10, $base[1]+60); $text->charspace(0); $text->text('Normal text'); $text->translate($base[0]+10, $base[1]+20); $text->charspace(3); $text->text('Expanded text'); $text->charspace(0); # caption drawCaption(['charspace()'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 44. wordspace(): show -1 condensed, 0 normal, +3 expanded @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $text->font($fontR, 13); $text->translate($base[0]+5, $base[1]+100); $text->wordspace(-1); $text->text('Less space between words'); $text->translate($base[0]+5, $base[1]+60); $text->wordspace(0); $text->text('Normal space between words'); $text->translate($base[0]+5, $base[1]+20); $text->wordspace(3); $text->text('More space between words'); $text->wordspace(0); # caption drawCaption(['wordspace()'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 45. hscale(): show 85 condensed, 100 normal, 125 expanded @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $text->font($fontR, 16); $text->translate($base[0]+15, $base[1]+100); $text->hscale(85); $text->text('85% scaled text'); $text->translate($base[0]+15, $base[1]+60); $text->hscale(100); $text->text('100% scaled text'); $text->translate($base[0]+15, $base[1]+20); $text->hscale(125); $text->text('125% scaled text'); $text->hscale(100); # caption drawCaption(['hscale()'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 46. leading(): show 1.1 tight, 1.4 normal, 2.5 double-space * 10 pt font @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $text->font($fontR, 10); $text->translate($base[0]+15, $base[1]+110); $text->leading(10*1.1); $text->text('tight leading'); $text->cr(); $text->text('at 110% of font size'); $text->translate($base[0]+15, $base[1]+75); $text->leading(10*1.4); $text->text('normal leading'); $text->cr(); $text->text('at 140% of font size'); $text->translate($base[0]+15, $base[1]+40); $text->leading(10*2.5); $text->text('double space leading'); $text->cr(); $text->text('at 250% of font size'); # caption drawCaption(['leading()'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 47. render(): show modes 0 - 3 @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $text->font($fontR, 16); $text->strokecolor('black'); $text->fillcolor('#999'); $text->translate($base[0]+15, $base[1]+110); $text->render(0); $text->text('render 0 fill only'); $text->translate($base[0]+15, $base[1]+80); $text->render(1); $text->text('render 1 stroke only'); $text->translate($base[0]+15, $base[1]+50); $text->render(2); $text->text('render 2 fill + stroke'); $text->translate($base[0]+15, $base[1]+20); $text->render(3); $text->text('render 3 invisible'); $text->render(0); # caption drawCaption(['render()'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 48. render(): show modes 4 - 7 @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $text->font($fontR, 16); $text->strokecolor('black'); $text->fillcolor('#999'); $text->translate($base[0]+15, $base[1]+110); $text->render(4); $text->text('render 4 fill only'); $text->translate($base[0]+15, $base[1]+80); $text->render(5); $text->text('render 5 stroke only'); $text->translate($base[0]+15, $base[1]+50); $text->render(6); $text->text('render 6 fill + stroke'); $text->translate($base[0]+15, $base[1]+20); $text->render(7); $text->text('render 7 invisible'); # clip s/b last line only, so draw filled rectangle over it # expect to see only fill within text (basically, blue-filled text) #$grfx->endpath(); #$grfx->fillcolor('#BBBBFF'); #$grfx->rect($base[0]+10,$base[1]+15, 150,20); #$grfx->fill(); $text->render(0); # caption drawCaption(['render() adds to clip'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 49. rise(): show some sub and super scripts @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $text->font($fontI, 16); $text->strokecolor('black'); $text->fillcolor('black'); $text->translate($base[0]+15, $base[1]+90); $text->text('E = mc'); $text->font($fontI, 10); $text->rise(6); $text->text('2'); $text->font($fontR, 16); $text->rise(0); $text->text(' is famous.'); $text->translate($base[0]+15, $base[1]+50); $text->text('H'); $text->font($fontR, 10); $text->rise(-5); $text->text('2'); $text->font($fontR, 16); $text->rise(0); $text->text('O is plain old water.'); # caption drawCaption(['rise() for sub/super'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # textstate(): omit for now # ---------------------------------------------------- # font(): shown as part of other examples # ---------------------------------------------------- # distance(): shown as part of other examples # ---------------------------------------------------- # ---------------------------------------------------- # 50. cr(): show 3 modes @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $text->font($fontR, 12); $text->strokecolor('black'); $text->fillcolor('black'); $text->leading(15); $text->translate($base[0]+15, $base[1]+105); $text->text('cr()'); $text->cr(); $text->text('goes to the next line'); $text->translate($base[0]+15, $base[1]+70); $text->text('cr(-8) goes DOWN '); $text->cr(-8); $text->text('8pts to start next line'); $text->translate($base[0]+15, $base[1]+40); $text->text('cr(0)'); $text->cr(0); $text->text('will overprint next line'); $text->translate($base[0]+15, $base[1]+10); $text->text('cr(8) goes UP'); $text->cr(8); $text->text('8pts to start next line'); # caption drawCaption(['cr() carriage return'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 51. nl(): show an example @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $text->font($fontR, 12); $text->strokecolor('black'); $text->fillcolor('black'); $text->leading(15); $text->translate($base[0]+25, $base[1]+105); $text->text('Here is some text.'); $text->nl(); $text->text('nl() took us here.'); $text->nl(0); $text->text('nl(0) took us here.'); $text->nl(200); $text->text('nl(200) took us here.'); $text->nl(); $text->text('nl() took us here.'); $text->nl(-75); $text->text('nl(-75) took us here.'); $text->nl(); $text->text('nl() took us here.'); # caption drawCaption(['nl() newline + indent'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 52. textpos(): place some text and return its position @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $text->font($fontR, 12); $text->strokecolor('black'); $text->fillcolor('black'); $text->leading(15); $text->translate($base[0]+15, $base[1]+100); $text->text('Here is some text.'); $text->nl(); my @loc = $text->textpos(); $text->text('* textpos says this line'); $text->nl(); $text->text("starts at @loc."); $text->nl(); $text->text("We requested ".($base[0]+15)." ".($base[1]+100-15)); # caption drawCaption(['textpos()'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 53. text() with 4 underlines, indent @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $text->font($fontR, 12); $text->strokecolor('black'); $text->fillcolor('black'); $text->leading(15); $text->translate($base[0]+15, $base[1]+110); $text->text('Some underlined text.', -underline=>'auto'); $text->translate($base[0]+15, $base[1]+90); $text->text('Loosely underlined text.', -underline=>5); $text->translate($base[0]+15, $base[1]+65); $text->text('Double underlined text.', -underline=>[3, 2, 8, 1]); $text->translate($base[0]+15, $base[1]+35); $text->text('Overlined text.', -underline=>-11); $text->translate($base[0]+15, $base[1]+15); $text->text('Indented 36pt text.', -indent=>36); # caption drawCaption(['text() underline, indent'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 53A. text() with 3 strikethroughs @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $text->font($fontR, 12); $text->strokecolor('black'); $text->fillcolor('black'); $text->leading(15); $text->translate($base[0]+12, $base[1]+85); $text->text('Auto '); $text->text('struck-through', -strikethru=>'auto'); $text->text(' text.'); $text->translate($base[0]+12, $base[1]+65); $text->text('Positioned '); $text->text('struck-through', -strikethru=>4.5); $text->text(' text.'); $text->translate($base[0]+12, $base[1]+45); $text->text('Doubly '); $text->text('struck-through', -strikethru=>[5, 0.7, 2, 0.7]); $text->text(' text.'); $text->translate($base[0]+12, $base[1]+25); $text->text('Color '); $text->text('struck-through', -strikethru=>[5, [0.4, 'green'], 2, [0.6, 'red']]); $text->text(' text.'); # caption drawCaption(['text() strikethru'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 54. advancewidth(): show some text, draw box around based on aw, leading @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $text->font($fontR, 12); $text->strokecolor('black'); $text->fillcolor('black'); $text->leading(15); $grfx->linewidth(1); $grfx->strokecolor('green'); $grfx->translate(@base); $text->translate($base[0]+5, $base[1]+ 95); $i = ' some text to put in a box '; $text->text($i); $lw = $text->advancewidth($i); $grfx->rect(5,95-$text->leading()/4, $lw,$text->leading()); $grfx->stroke(); $text->font($fontR, 36); $text->translate($base[0]+5, $base[1]+ 35); $i = ' more text '; $text->text($i); $lw = $text->advancewidth($i); $grfx->rect(5,35-3*$text->leading()/4, $lw,3*$text->leading()); $grfx->stroke(); # caption drawCaption(['advancewidth()'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 55. text() @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $text->font($fontR, 12); $text->strokecolor('black'); $text->fillcolor('black'); $text->leading(15); $grfx->linewidth(1); $grfx->strokecolor('red'); $grfx->translate(@base); $grfx->poly(15,120, 15,10); $grfx->poly(155,120, 155,10); $grfx->stroke(); $text->translate($base[0]+15, $base[1]+100); $text->text('When in the course'); $text->translate($base[0]+15, $base[1]+ 80); $text->text('of human events, it becomes'); $text->translate($base[0]+15, $base[1]+ 60); $text->text('necessary for one people to dissolve the'); $text->translate($base[0]+15, $base[1]+ 40); $text->text('political bands...'); # caption drawCaption(['text()'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # add(): advanced method to directly add content to PDF stream # ---------------------------------------------------- # compressFlate(): advanced method to turn output compression on # ---------------------------------------------------- # textstart(): advanced method to start a text object # ---------------------------------------------------- # textend(): advanced method to end a text object # ---------------------------------------------------- # ---------------------------------------------------- $pdf->saveas($PDFname); # ===================================================================== sub colors { my $color = shift; $grfx->strokecolor($color); $grfx->fillcolor($color); $text->strokecolor($color); $text->fillcolor($color); return; } # --------------------------------------- # if a single coordinate pair, produces a green dot # if two or more pairs, produces a green dot at each pair, and connects # with a green line sub greenLine { my $pointsRef = shift; my @points = @{ $pointsRef }; my $i; $grfx->linewidth(1); $grfx->strokecolor('green'); $grfx->poly(@points); $grfx->stroke(); # draw green dot at each point $grfx->linewidth(3); $grfx->linecap(1); # round for ($i=0; $i<@points; $i+=2) { $grfx->poly($points[$i],$points[$i+1], $points[$i],$points[$i+1]); } $grfx->stroke(); return; } # --------------------------------------- sub nextPage { $pageNo++; $page = $pdf->page(); $textUnder = $page->text(); # special $grfx = $page->gfx(); $text = $page->text(); $page->mediabox('Universal'); $font = $pdf->corefont('Times-Roman'); $text->translate(595/2,15); $text->font($font, 10); $text->fillcolor('black'); $text->text_center($pageNo); # prefill page number before any other content return; } # --------------------------------------- sub makeCell { my ($cellLocX, $cellLocY, $cellSizeW, $cellSizeH) = @_; # outline and clip of cell $grfx->strokecolor('#CCC'); $grfx->linewidth(2); $grfx->rect($cellLocX,$cellLocY, $cellSizeW,$cellSizeH); $grfx->stroke(); #$grfx->linewidth(1); #$grfx->rect($cellLocX,$cellLocY, $cellSizeW,$cellSizeH); #$grfx->clip(1); #$text->linewidth(1); #$text->rect($cellLocX,$cellLocY, $cellSizeW,$cellSizeH); #$text->clip(1); return; } # --------------------------------------- # draw a set of axes at current origin sub drawAxes { # draw 75-long axes, at offset $grfx->linejoin(0); $grfx->linewidth(1); $grfx->poly($axisOffset[0]+0, $axisOffset[1]+75, $axisOffset[0]+0, $axisOffset[1]+0, $axisOffset[0]+75,$axisOffset[1]+0); $grfx->stroke(); # 36x36 box #$grfx->rect(0,0, 36,36); # draw a square #$grfx->stroke(); # X axis arrowhead draw $grfx->poly($axisOffset[0]+75-2, $axisOffset[1]+0+2, $axisOffset[0]+75+0, $axisOffset[1]+0+0, $axisOffset[0]+75-2, $axisOffset[1]+0-2); $grfx->stroke(); # Y axis arrowhead draw $grfx->poly($axisOffset[0]+0-2, $axisOffset[1]+75-2, $axisOffset[0]+0+0, $axisOffset[1]+75+0, $axisOffset[0]+0+2, $axisOffset[1]+75-2); $grfx->stroke(); return; } # --------------------------------------- # label the X and Y axes, and draw a sample 'n' sub drawLabels { my ($Xlabel, $Ylabel) = @_; my $fontI = $pdf->corefont('Times-Italic'); my $fontR = $pdf->corefont('Times-Roman'); # outline "n" $text->distance($axisOffset[0]+0, $axisOffset[1]+0); $text->font($fontR, 72); $text->render(1); $text->text('n'); $text->render(0); $text->font($fontI, 12); # X axis label $text->distance(75+2, 0-3); $text->text($Xlabel); # Y axis label $text->distance(-75-2+0-4, 0+3+75+2); $text->text($Ylabel); return; } # --------------------------------------- # write out a 1 or more line caption sub drawCaption { my $captionsRef = shift; my @captions = @$captionsRef; my $just = shift; # 'LC' = left justified (centered on longest line) my ($width, $i, $y); $text->font($fontC, 12); $text->fillcolor('black'); # find longest line width $width = 0; foreach (@captions) { $width = max($width, $text->advancewidth($_)); } $y=20; # to shut up perlcritic for ($i=0; $i<@captions; $i++) { # $just = LC $text->translate($cellLoc[0]+$cellSize[0]/2-$width/2, $cellLoc[1]-$y); $text->text($captions[$i]); $y+=13; # to mollify perlcritic } return; } # --------------------------------------- # m, n (both within X and Y index ranges) = set to this position # 0 = next cell (starts new page if necessary) # N = >0 number of cells to skip (starts new page if necessary) sub makeCellLoc { my ($X, $Y) = @_; my @cellX = (36, 212, 388); # horizontal (column positions L to R) my @cellY = (635, 458, 281, 104); # vertical (row positions T to B) my $add; if (defined $Y) { # X and Y given, use if valid indices if ($X < 0 || $X > $#cellX) { die "X = $X is invalid index."; } if ($Y < 0 || $Y > $#cellY) { die "Y = $Y is invalid index."; } $globalX = $X; $globalY = $Y; $add = 0; } elsif ($X == 0) { # requesting next cell $add = 1; } else { # $X is number of cells to skip (1+) $add = $X + 1; } while ($add-- > 0) { if ($globalX == $#cellX) { # already at end of row $globalX = 0; $globalY++; } else { $globalX++; } if ($globalY > $#cellY) { # ran off bottom row, so go to new page $globalX = $globalY = 0; nextPage(); # next page of output, 523pt wide x 720pt high } } return ($cellX[$globalX], $cellY[$globalY]); } PDF-Builder-3.026/examples/025_unifonts0000644000000000000000000015620614534467462016244 0ustar rootroot#!/usr/bin/perl use strict; use warnings; # read in first 45 lines from SJIS-encoded attached PDF-J file, convert to # UTF-8, and output in 4 different CJK+Western font combinations # # NOTE: This code is meant as an example of what could be done. If it was # intended to be a serious utility, we would have to fold long lines that # currently run off the right side of the page, so that content would # not be lost. use File::Basename; use PDF::Builder; use PDF::Builder::Util; use Unicode::UCD 'charinfo'; use Encode qw[:all]; use Getopt::Long; use PDF::Builder::UniWrap; use utf8; #my $compress = 'none'; # uncompressed streams my $compress = 'flate'; # compressed streams #----------------------------------------- ## following char_length is slightly different from one in UniWrap #package PDF::Builder::UniWrap; # #sub char_length { # my $self=shift if ref($_[0]); # my ($c) = @_; # # #if ($c eq 'CM' || $c eq 'ZW') { # # return 0; # #} # if (defined $self && defined $self->{'widthobj'}) { # return $self->{'widthobj'}->width($c); # } # # return 1; #} # #----------------------------------------- package main; my $uw = PDF::Builder::UniWrap->new(line_length=>50, emergency_break=>50); my $api = PDF::Builder->new(-compress => $compress); $api->mediabox(595,842); my $helv = $api->corefont('Helvetica-Bold', -encode=>'latin1'); my $times = $api->corefont('Times-Roman', -encode=>'latin1'); my $time2 = $api->synfont($times, -condense=>1.3); my $treb = $api->corefont('Trebuchet-Italic', -encode=>'latin1'); my $tre2 = $api->synfont($treb, -condense=>1.1, -space=>60); my $georg = $api->corefont('Georgia-Italic', -encode=>'latin1'); my $jfs = $api->cjkfont('KozMin', -encode=>'shiftjis'); my $jf1 = $api->cjkfont('KozMin-Bold', -encode=>'shiftjis'); my $jf2= $api->cjkfont('KozGo-Italic', -encode=>'shiftjis'); my $uf = $api->unifont($jf1, [$time2,[0]], -encode=>'shiftjis'); my $u2 = $api->unifont($jf2, [$tre2,[0]], -encode=>'shiftjis'); my $u3 = $api->unifont($jf2,{'font'=>$georg, 'blocks'=>[0] }, -encode=>'shiftjis'); my $start = tell(DATA); #q| Ming Ming-Bold Ming-Italic Ming-BoldItalic # Song Song-Bold Song-Italic Song-BoldItalic # MyungJo MyungJo-Bold MyungJo-Italic MyungJo-BoldItalic # KozMin KozMin-Bold KozMin-Italic KozMin-BoldItalic # KozGo KozGo-Bold KozGo-Italic KozGo-BoldItalic|; my %fonts = ( 'KozMin' => $jfs, 'KozMin-Bold + Times' => $uf, 'KozGo-Italic + Trebuchet-Italic' => $u2, 'KozGo-Italic + Georgia-Italic' => $u3 ); my ($page, $gfx, $text, $y, $line); foreach my $fontname (keys %fonts) { $y = 800; # title line this page $page = $api->page(); $gfx = $page->gfx(); $text = $page->text(); delete $gfx->{'Filter'}; my $font = $fonts{$fontname}; $uw->{'widthobj'} = $font; seek(DATA, $start, 0); binmode(DATA, ':raw :encoding(shiftjis)'); $text->textlabel(50,$y, $helv,10, $fontname, -color=>'darkred'); # take the first 45 lines of HERE file and output in current font foreach (1..45) { $y -= 15; # output line position $line = ; # get one line of data from HERE file # and converts $line from SJIS to UTF-8 on the fly $line =~ s|[\012\015]+$||go; # remove trailing LFs and CRs $text->textlabel(50,$y, $font,10, $line, -hscale=>80); # note that many lines are long enough to overflow the right margin. # if you wanted to use this for real, you'd probably want to do # something about folding or breaking long lines. } } $api->saveas("$0.pdf"); $api->end; # HERE document (as ) after __END__ marker, is PDF-J document __END__ PDFJ - “ú–{ŒêPDF¶¬ƒ‚ƒWƒ…[ƒ‹ =head1 SYNOPSIS use PDFJ qw(SJIS); $doc = PDFJ::Doc->new($pdfversion, $paperwidth, $paperheight); $font = $doc->new_font('Ryumin-Light', '90ms-RKSJ-H', 'Times-Roman'); $page = $doc->new_page; $text = Text("ƒeƒLƒXƒg", TStyle(font => $font, fontsize => 10)); $paragraph = Paragraph($text, PStyle(size => 100, align => 'w', linefeed => 20)); $image = $doc->new_image($jpgfile, $pixelwidth, $pixelheight, $width, $height); $shape = Shape->ellipse($x, $y, $rx, $ry); $block = Block('V', $paragraph, $image, $shape, BStyle(align => 'c')); $block->show($page, $x, $y); $doc->print('sample.pdf'); =head1 DESCRIPTION =head2 ŠT—v ‚±‚̃‚ƒWƒ…[ƒ‹‚Í“ú–{ŒêPDF‚𶬂·‚éBŽŸ‚̂悤‚È“Á’¥‚ª‚ ‚éB =over 4 =item * JIS X 4051u“ú–{Œê•¶‘‚Ìs‘g”Å•û–@vi1995j‚ɂقڀ‹’‚µ‚½s‘g”Ń‹[ƒ‹‚ð‘g‚Ýž‚ñ‚Å‚ ‚èA‹Ö‘¥‚âs‚Ì‹l‚ßL‚΂µ‚Í‚±‚̃‚ƒWƒ…[ƒ‹‚É”C‚¹‚邱‚Æ‚ª‚Å‚«‚éB =item * ƒ‹ƒrA“Y‚¦ŽšAc‘‚«’†‚̉¢•¶Ac’†‰¡A‰¢•¶‚̃nƒCƒtƒl[ƒVƒ‡ƒ“A‰ºüE–TüAŒ—“_A–ÔŠ|‚¯‚Æ‚¢‚Á‚½‘g”ň—‚à‚±‚̃‚ƒWƒ…[ƒ‹‚É”C‚¹‚邱‚Æ‚ª‚Å‚«‚éB =item * Type1ƒtƒHƒ“ƒg‚Å‚ÍA˜a•¶‚ÉRyumin-Light‚ÆGothicBBB-MediumA‰¢•¶‚ÉTimesAHelveticaACourier‚ÌŠeƒtƒ@ƒ~ƒŠ‚ªŽg‚¦‚éB‚±‚ê‚ç‚̓tƒHƒ“ƒgŽ©‘͖̂„‚ßž‚Ü‚ê‚È‚¢‚Ì‚ÅAƒRƒ“ƒpƒNƒg‚ÈPDF‚ðì‚ê‚éB‚½‚¾‚µ•\ަEˆóüŠÂ‹«‚É‚»‚̃tƒHƒ“ƒg‚ª‚È‚¢‚Æ‘ã‘ÖƒtƒHƒ“ƒg‚ƂȂéB =item * ”CˆÓ‚ÌTrueTypeƒtƒHƒ“ƒg‚ðŽg‚¤‚±‚Æ‚à‚Å‚«‚éBTrueTypeƒtƒHƒ“ƒg‚Í–„‚ßž‚Ü‚ê‚éi˜a•¶‚ɂ‚¢‚Ă̓TƒuƒZƒbƒg‚Åj‚Ì‚ÅAŽáбPDF‚̃TƒCƒY‚ª‘å‚«‚­‚Ȃ邪A‚Ç‚ñ‚Ȋ‹«‚Å‚à“¯‚¶‚悤‚É•\ަEˆóü‚Å‚«‚éB =item * ‰¢•¶‚ÉAŒÅ’èƒsƒbƒ`‚Ì”¼ŠpƒtƒHƒ“ƒg‚ðŽg‚¤‚±‚Æ‚àAƒvƒƒ|[ƒVƒ‡ƒiƒ‹‚ȉ¢•¶ƒtƒHƒ“ƒg‚ðŽg‚¤‚±‚Æ‚à‚Å‚«‚éB =item * “ú–{Œê•¶ŽšƒR[ƒh‚Æ‚µ‚Ä‚ÍAƒVƒtƒgJISA“ú–{ŒêEUCAUTF8AUnicode‚ɑΉž‚µ‚Ä‚¢‚éB =item * JPEG‰æ‘œiƒtƒ@ƒCƒ‹‚¨‚æ‚ÑURLŽw’èj‚Æü‰æ}Œ`‚ªˆµ‚¦‚éB‰æ‘œ‚â}Œ`‚ðƒeƒLƒXƒg‚̈ꕔ‚Æ‚µ‚Äs“à‚É”z’u‚·‚邱‚Æ‚à‰Â”\B‹t‚Éü‰æ}Œ`‚Ì’†‚ɃeƒLƒXƒg‚â‰æ‘œ‚ð”z’u‚·‚邱‚Æ‚à‚Å‚«‚éB =item * ƒeƒLƒXƒg‚ðs’·‚Æs‘—‚è‚ðŽw’肵‚ÄÜ‚è•Ô‚µˆ—‚µA’i—Ž‚ðì‚邱‚Æ‚ª‚Å‚«‚éB’i—Ž‚É‚Í‰Óð‘‚«‚Ì‚½‚߂̃‰ƒxƒ‹‚ð•t‚¯‚邱‚Æ‚ª‚Å‚«‚é =item * ’i—ŽA‰æ‘œA}Œ`‚Ȃǂð•À‚ׂăuƒƒbƒN‚Æ‚¢‚¤‚܂Ƃ܂è‚ðì‚邱‚Æ‚ª‚Å‚«‚éBƒuƒƒbƒN‚É‚ÍA“à—e‚Ì”z’uAŽüˆÍ‚Ì—]”’A˜güA“h‚è‚‚ԂµF‚ȂǂðŽw’è‚Å‚«‚éBƒuƒƒbƒN“à‚Ì•À‚т̕ûŒü‚Æ‚µ‚ÄA㨉ºA¶¨‰EA‰E¨¶‚ª‚ ‚éBƒuƒƒbƒN‚ð“ü‚êŽq‚É‚·‚邱‚Ƃŕ\‚ðì‚邱‚Æ‚ª‚Å‚«‚éB =item * ’i—Ž‚âƒuƒƒbƒN‚ðŽw’è‚̑傫‚³‚ð’´‚¦‚È‚¢‚悤‚É•ªŠ„‚µ‚ÄA•¡”‚̃y[ƒW‚É•ª‚¯‚Ä•\ަ‚·‚邱‚Æ‚ª‚Å‚«‚éB =item * PDF‚Ì•¶‘î•ñAƒAƒEƒgƒ‰ƒCƒ“î•ñAƒnƒCƒp[ƒŠƒ“ƒNi•¶‘“à‚¨‚æ‚ÑURLj‚ð•t‰Á‚Å‚«‚éB =item * ˆÃ†‰»‚ª‚Å‚«‚éB =back =head2 •\ަ‰Â”\‚ȃIƒuƒWƒFƒNƒg PDFJ‚ł͎Ÿ‚Ì•\ަ‰Â”\‚È\¬—v‘f‚ɑΉž‚·‚éƒIƒuƒWƒFƒNƒg‚ð‘g‚݇‚킹‚ÄPDF•¶‘‚ð쬂·‚éB‚±‚ê‚ç‚݂͂ÈAshow‚Æ‚¢‚¤ƒƒ\ƒbƒh‚Ńy[ƒWã‚Ɉʒu‚ðŽw’肵‚Ä•\ަ‚·‚邱‚Æ‚ª‚Å‚«‚éBshowƒƒ\ƒbƒh‚Ì‹ï‘Ì“I‚ÈŽg‚¢•û‚ɂ‚¢‚Ă͌ãq‚·‚éB =over 4 =item ƒeƒLƒXƒgiPDFJ::Textj Žw’è‚Ì•¶Žš—ñ‚ðAŽw’è‚̃tƒHƒ“ƒg‚âƒTƒCƒY‚Ȃǂ̑®«‚É]‚Á‚Ä•\ަ‚·‚é‚à‚ÌBƒtƒHƒ“ƒg‚̃Gƒ“ƒR[ƒfƒBƒ“ƒO‚ªH‚Å‚ ‚ê‚ζ‚©‚ç‰E‚Ö‰¡‘‚«‚ÅAV‚Å‚ ‚ê‚Îã‚©‚牺‚Öc‘‚«‚Å•\ަ‚³‚ê‚éB ƒ‹ƒrA“Y‚¦ŽšAc’†‰¡A‰ºüE–TüAŒ—“_AˆÍ‚݂Ƃ¢‚Á‚½‘®«‚ÌŽw’肪‚Å‚«‚éB ƒeƒLƒXƒgŽ©‘̂ɂÍs’·‚âs‘—‚è‚Æ‚¢‚Á‚½‘®«‚͂Ȃ­AÜ‚è•Ô‚µ‚Ä•\ަ‚³‚ê‚邱‚Ƃ͂Ȃ¢B •¶Žš‚¾‚¯‚łȂ­A•\ަ‰Â”\‚ȃIƒuƒWƒFƒNƒg‚ðŠÜ‚Þ‚±‚Æ‚ª‚Å‚«‚éB =item ’i—ŽiPDFJ::Paragraphj ƒeƒLƒXƒg‚ɑ΂µ‚Äs’·‚Æs‘—‚è‚Æ”z’u‚ðŽw’肵‚Äs‚ÌÜ‚è•Ô‚µ‚ð‚¨‚±‚È‚¢A‚ЂƂ‚̒i—Ž‚Æ‚µ‚Ä•\ަ‚·‚é‚à‚ÌBs‚ÌÜ‚è•Ô‚µ‚É”º‚¤A‹Ö‘¥ˆ—AƒnƒCƒtƒl[ƒVƒ‡ƒ“As‚Ì‹l‚ßL‚΂µ‚ÍŽ©“®“I‚Ɉ—‚³‚ê‚éB ‚Ü‚½ƒeƒLƒXƒg‚É‚ÍA•¶Žš‚¾‚¯‚łȂ­‰æ‘œ‚â}Œ`‚ð‚ЂƂ‚̕¶Žš‚̂悤‚Ɉµ‚Á‚Ċ܂ނ±‚Æ‚à‚Å‚«‚éB s“ªAs––‚̃Cƒ“ƒfƒ“ƒgA擪s‚ɂ‚¯‚郉ƒxƒ‹‚ðŽw’è‚·‚邱‚Æ‚à‚Å‚«‚éB ’i—Ž‚Ì‘OŒã‚ÌŠÔŠu‚ðŽw’è‚·‚邱‚Æ‚ª‚Å‚«‚éB‚±‚ÌŠÔŠu‚Í’i—Ž‚ð•À‚ׂăuƒƒbƒN‚ðì‚éÛ‚É“K—p‚³‚ê‚éB =item ‰æ‘œiPDFJ::Imagej JPEGŒ`Ž®‚ÅAƒtƒ@ƒCƒ‹‚ɕۑ¶‚³‚ê‚Ä‚¢‚é‚à‚Ì‚©AURL‚ÅŽQƂł«‚鉿‘œ‚݂̂ªˆµ‚¦‚éBŒ³‚̃sƒNƒZƒ‹ƒTƒCƒY‚Ƃ͊֌W‚È‚­Žw’è‚̑傫‚³‚Å•\ަ‚Å‚«‚éB ŽüˆÍ‚Ì—]”’‚ðŽw’è‚·‚邱‚Æ‚à‚Å‚«‚éB =item }Œ`iPDFJ::Shapej ’¼üA‹éŒ`A‘½ŠpŒ`A‰~A‘ȉ~AƒxƒWƒG‹Èü‚ð‘g‚݇‚킹‚Ä}Œ`‚ð쬂µA•\ަ‚Å‚«‚éBü‚Ì—L–³A‘¾‚³AFA“_üA“h‚è‚‚Ԃµ‚Ì—L–³AF‚Æ‚¢‚Á‚½‘®«‚ªŽw’è‚Å‚«‚éB }Œ`“à‚ɃeƒLƒXƒg‚ð”z’u‚·‚邱‚Æ‚à‚Å‚«‚éB ŽüˆÍ‚Ì—]”’‚ðŽw’è‚·‚邱‚Æ‚à‚Å‚«‚éB =item ƒuƒƒbƒNiPDFJ::Blockj •\ަ‰Â”\‚ȃIƒuƒWƒFƒNƒg‚ð“Á’è‚Ì•ûŒü‚É•À‚ׂĂЂƂ܂Ƃ߂ɂµ‚½‚à‚ÌB•ûŒü‚Æ‚µ‚Ä‚ÍAHi¶¨‰EjARi‰E¨¶jAVi㨉ºj‚ÌŽOŽí—Þ‚ª‚ ‚éB‘S‘̂̕‚â‚‚³‚ðŽw’肵‚Ä“à—e‚Ì”z’u‚ðŽw’è‚·‚邱‚Æ‚à‚Å‚«‚éB“à—e‚Ì”z’u‚ÍA¶‰E•ûŒü‚ÉAli¶jAci’†‰›jAri‰EjA㉺•ûŒü‚ÉAtiãjAmi’†‰›jAbi‰ºj‚ð‘g‚݇‚킹‚ÄŽw’è‚·‚éB‚½‚¾‚µA‘S‘̂̕‚â‚‚³‚Í“à—e‚É‚æ‚Á‚ÄŒˆ‚܂镂₂³‚æ‚謂³‚­‚͂ł«‚È‚¢B ƒIƒuƒWƒFƒNƒg‚É‘OŒã‚ÌŠÔŠu‚ÌŽw’肪‚ ‚ê‚ÎA‚»‚ê‚É]‚Á‚ÄŠÔŠu‚ª‹ó‚¯‚ç‚ê‚éB‚Ü‚½A’¼Ú”’l‚ÅŠÔŠu‚ðŽw’è‚·‚邱‚Æ‚à‚Å‚«‚éB ƒuƒƒbƒN‚É‚ÍAŽüˆÍ‚Ì—]”’A˜güA“h‚è‚‚ԂµF‚ðŽw’è‚·‚邱‚Æ‚ª‚Å‚«‚éB ƒuƒƒbƒN‚ð“ü‚êŽq‚É‚·‚邱‚Æ‚ÅA•\‚ðì‚邱‚Æ‚ª‚Å‚«‚éB =back =head2 ‚»‚Ì‘¼‚̃IƒuƒWƒFƒNƒg ‚»‚Ì‘¼‚ÉŽŸ‚̂悤‚ȃIƒuƒWƒFƒNƒg‚ªA•\ަ‰Â”\‚ȃIƒuƒWƒFƒNƒg‚ƂƂà‚ÉŽg—p‚³‚ê‚éB =over 4 =item ƒtƒHƒ“ƒgiPDFJ::AFontAPDFJ::CIDFontj ƒtƒHƒ“ƒg‚ÍType1ƒtƒHƒ“ƒg‚Å‚ÍA˜a•¶‚ÉRyumin-Light‚ÆGothicBBB-MediumA‰¢•¶‚ÉTimesAHelveticaACourier‚ÌŠeƒtƒ@ƒ~ƒŠ‚ªŽg‚¦‚éBTrueTypeƒtƒHƒ“ƒg‚Í”CˆÓ‚Ì‚à‚Ì‚ªŽg‚¦‚éB‚½‚¾‚µPDF‚É–„‚ßž‚Ü‚ê‚é‚Ì‚ÅA–„‚ßž‚Ý‚ª‹–‰Â‚³‚ꂽTrueTypeƒtƒHƒ“ƒg‚łȂ¯‚ê‚΂Ȃç‚È‚¢B ˜a•¶ƒtƒHƒ“ƒg‚¾‚¯‚ðŽw’肵‚½ƒeƒLƒXƒg‚ɉ¢•¶‚ªŒ»‚ꂽ‚Æ‚«‚É‚ÍA˜a•¶ƒtƒHƒ“ƒg‚Ì”¼Šp•¶Žši•¶Žš•‚Í”¼ŠpŒÅ’èj‚ªŽg‚í‚ê‚邪A‘g‚݇‚킹‚鉢•¶ƒtƒHƒ“ƒg‚ðŽw’肵‚Ä‚¨‚­‚Æ‚»‚̉¢•¶ƒtƒHƒ“ƒg‚ªŽg‚í‚ê‚éBƒvƒƒ|[ƒVƒ‡ƒiƒ‹‚Șa•¶ƒtƒHƒ“ƒg‚ɂ͑Ήž‚µ‚Ä‚¢‚È‚¢B c‘‚«—pƒGƒ“ƒR[ƒfƒBƒ“ƒOiVj‚ðŽw’肵‚½˜a•¶ƒtƒHƒ“ƒg‚ðŽw’è‚·‚邯A‚»‚̃eƒLƒXƒg‚Íc‘‚«‚ƂȂéB =item ƒeƒLƒXƒgƒXƒ^ƒCƒ‹iPDFJ::TextStylej ƒtƒHƒ“ƒgAƒtƒHƒ“ƒgƒTƒCƒYA•¶Žš•`‰æƒ‚[ƒhAƒx[ƒXƒ‰ƒCƒ“’²®AŽÎ‘ÌA‰ºüic‘‚«‚ł͖TüjAˆÍ‚Ý” AŒ—“_A“Y‚¦ŽšiãE‰ºjAƒ‹ƒrA–T’A}Œ`ƒXƒ^ƒCƒ‹A‚ªŽw’è‚Å‚«‚éB •¶Žš•`‰æƒ‚[ƒh‚ÍA•¶Žš‚̘gü‚Æ“h‚è‚‚Ԃµ‚Ì‘g‚݇‚킹‚ÌŽw’èB}Œ`ƒXƒ^ƒCƒ‹‚ÍA•¶Žš•`‰æA‰ºüE–TüAˆÍ‚Ý” ‚É‚¨‚¯‚é}Œ`ƒXƒ^ƒCƒ‹‚ÌŽw’èB =item ’i—ŽƒXƒ^ƒCƒ‹iPDFJ::ParagraphStylej s’·A‘µ‚¦As‘—‚èAƒ‰ƒxƒ‹Aƒ‰ƒxƒ‹’·As“ªƒCƒ“ƒfƒ“ƒgAs––ƒCƒ“ƒfƒ“ƒgA‘OŠÔŠuAŒãŠÔŠuA‚ªŽw’è‚Å‚«‚éB ‘µ‚¦‚Æ‚µ‚Ä‚ÍAbis“ª‘µ‚¦jAmi’†‰›‘µ‚¦jAeis––‘µ‚¦jAwi—¼’[‘µ‚¦j‚ª‚ ‚éB =item ƒuƒƒbƒNƒXƒ^ƒCƒ‹iPDFJ::BlockStylej •A‚‚³A‘µ‚¦A‘µ‚¦ƒtƒ‰ƒOAŽüˆÍ—]”’A˜güA“h‚è‚‚ԂµFA‘OŠÔŠuAŒãŠÔŠuA‚ªŽw’è‚Å‚«‚éB =item }Œ`ƒXƒ^ƒCƒ‹iPDFJ::ShapeStylej ü•A“_üAüFA“h‚è‚‚ԂµFAŽüˆÍ—]”’A‘OŠÔŠuAŒãŠÔŠuA‚ªŽw’è‚Å‚«‚éB =item FiPDFJ::Colorj ŠDFŽw’è‚ÆA‚q‚f‚aŽw’肪‚Å‚«‚éB}Œ`‘®«‚ÌüF‚Æ“h‚è‚‚ԂµF‚ÌŽw’è‚ÉŽg‚í‚ê‚éB =item ƒy[ƒWiPDFJ::Pagej Šeƒy[ƒW‚Ì“à—e‚ð•ÛŽ‚·‚éBƒeƒLƒXƒg‚â‰æ‘œ‚â}Œ`‚È‚ÇA•\ަ‰Â”\‚ȃIƒuƒWƒFƒNƒg‚̓y[ƒW‚É”z’u‚·‚邱‚ƂŎÀÛ‚É•\ަ‚³‚ê‚éB =item PDF•¶‘iPDFJ::Docj ˆê‚‚ÌPDF•¶‘Bƒy[ƒWŒQ‚âAƒŠƒ\[ƒX‚Æ‚µ‚ẴtƒHƒ“ƒg‚â‰æ‘œ‚ð‚܂ƂßAÅI“I‚Ɉê‚‚ÌPDFƒtƒ@ƒCƒ‹‚Æ‚µ‚Äo—Í‚·‚éB =back =head2 PDFJ‚̃Cƒ“ƒXƒg[ƒ‹ ŠÇ—ŽÒ‚Å‚ ‚ê‚ÎŽŸ‚Ì•W€“I‚Ȏ臂ŃCƒ“ƒXƒg[ƒ‹‚Å‚«‚éB perl Makefile.PL make make install ÅŒã‚Ìmake install‚ÍŠÇ—ŽÒŒ ŒÀ‚ÅŽÀs‚·‚éBWindows‚Å‚Ímake‚łȂ­nmake‚ðŽg—p‚·‚éB ŠÇ—ŽÒ‚łȂ¢ê‡‚Å‚àAPDFJ‚ð\¬‚·‚鎟‚̃‚ƒWƒ…[ƒ‹ƒtƒ@ƒCƒ‹ŒQ‚ðPerl‚©‚ç—˜—p‚Å‚«‚éi‚·‚Ȃ킿@INC‚ɃZƒbƒg‚³‚ꂽjƒfƒBƒŒƒNƒgƒŠ‚É‚¨‚¯‚Η˜—p‚Å‚«‚éB PDFJ.pm PDFJ/Object.pm PDFJ/Unicode.pm PDFJ/E2U.pm PDFJ/S2U.pm PDFJ/U2C.pm PDFJ/TTF.pm PDFJ‚ÍA‰¢•¶‚̃nƒCƒtƒl[ƒVƒ‡ƒ“‚ð‚¨‚±‚È‚¤‚½‚ß‚ÉATeX::Hyphenƒ‚ƒWƒ…[ƒ‹‚ðŽg—p‚µ‚Ä‚¢‚éB‰¢•¶‚ðŠÜ‚ÞƒeƒLƒXƒg‚ðˆµ‚¤ê‡‚Í•K—v‚ƂȂé‚Ì‚ÅACPAN‚©‚çƒ_ƒEƒ“ƒ[ƒh‚µ‚ăCƒ“ƒXƒg[ƒ‹‚µ‚Ä‚¨‚­BŠÇ—ŽÒ‚łȂ¢ê‡‚ÍAŽŸ‚̃‚ƒWƒ…[ƒ‹‚ðPerl‚©‚ç—˜—p‚Å‚«‚éƒfƒBƒŒƒNƒgƒŠ‚É‚¨‚¯‚΂悢B TeX/Hyphen.pm TeX/Hyphen/czech.pm TeX/Hyphen/german.pm PDFJ‚ÍAƒtƒHƒ“ƒg‚â‰æ‘œ‚Ȃǂ̃f[ƒ^‚ð–„‚ßž‚ÞÛ‚ÉAƒfƒtƒHƒ‹ƒg‚Å‚ÍCompress::Zlibƒ‚ƒWƒ…[ƒ‹‚ðŽg—p‚·‚éBCompress::Zlib‚ª‚È‚¢ŠÂ‹«‚âACompress::Zlib‚ðŽg‚¢‚½‚­‚È‚¢ê‡‚Ì‚½‚ß‚ÉACompress::Zlib‚ðŽg‚킸‚Ƀf[ƒ^‚Ì–„‚ßž‚Ý‚ð‚¨‚±‚È‚¤ƒIƒvƒVƒ‡ƒ“‚à—pˆÓ‚³‚ê‚Ä‚¢‚éBiL<"•¶‘ƒIƒuƒWƒFƒNƒg‚Ìì¬">‚ðŽQÆj ˆÃ†‰»‚ð‚¨‚±‚È‚¤Û‚É‚ÍADigest::MD5ƒ‚ƒWƒ…[ƒ‹‚ª•K—v‚Å‚ ‚éB =head2 PDFJ‚ÌŽg—p PDFJ‚ðŽg—p‚·‚é‚É‚ÍA‚‚¬‚̂悤‚É‚µ‚Ä use PDFJ ‚̈ø”‚É“ú–{Œê•¶ŽšƒR[ƒh‚ðŽw’è‚·‚éBÈ—ª‚·‚邯'SJIS'‚Ƃ݂Ȃ³‚ê‚éB # Shift-JIS‚Ìê‡ use PDFJ 'SJIS'; # EUC‚Ìê‡ use PDFJ 'EUC'; # UTF8‚Ìê‡ use PDFJ 'UTF8'; # UNICODEiUCS2j‚Ìê‡ use PDFJ 'UNICODE'; ƒeƒLƒXƒgƒIƒuƒWƒFƒNƒg‚ðì‚鎞‚É—^‚¦‚é•¶Žš—ñ‚âAƒtƒHƒ“ƒg‚̃Gƒ“ƒR[ƒfƒBƒ“ƒO‚ł̓ú–{Œê•¶ŽšƒR[ƒh‚ÍAuse PDFJ ‚ÅŽw’肵‚½‚à‚̂Ƈ’v‚·‚邿‚¤‚É‚µ‚È‚¯‚ê‚΂Ȃç‚È‚¢B ˆÙ‚È‚é•¶ŽšƒR[ƒh‚ð¬Ý‚³‚¹‚½‚èØ‚è‘Ö‚¦‚ÄŽg—p‚·‚邱‚Ƃ͂ł«‚È‚¢B use PDFJ ‚É‚æ‚Á‚ÄŽŸ‚̃Tƒuƒ‹[ƒ`ƒ“‚ªƒGƒNƒXƒ|[ƒg‚³‚ê‚éB Doc Text TStyle NewLine Outline Dest Paragraph PStyle Block BStyle NewBlock BlockSkip Shape SStyle Color =head2 •¶‘ƒIƒuƒWƒFƒNƒg‚Ìì¬ ‚Ü‚¸Å‰‚É•¶‘ƒIƒuƒWƒFƒNƒg‚ð쬂µ‚È‚¯‚ê‚΂Ȃç‚È‚¢B $docobj = PDFJ::Doc->new($version, $width, $height); ‚±‚±‚ÅA$version‚ÍPDF‚̃o[ƒWƒ‡ƒ“i¦‰º‹L‚Ì’‚ðŽQÆjA$width‚̓y[ƒW‚Ì•A$height‚̓y[ƒW‚Ì‚‚³‚ÅA’PˆÊ‚̓|ƒCƒ“ƒgi1/72ƒCƒ“ƒ`j‚Å‚ ‚éBiƒ|ƒCƒ“ƒg‚Ì’è‹`‚Í’è‚Ü‚Á‚½‚à‚Ì‚ª‚È‚¢‚ªAPDF‚Å‚Í1/72ƒCƒ“ƒ`‚Æ‚³‚ê‚Ä‚¢‚éB1ƒCƒ“ƒ`‚Í25.4mmBj ‚È‚¨Aƒy[ƒW‚Ì•‚Æ‚‚³‚ÍAŠeƒy[ƒWƒIƒuƒWƒFƒNƒg‚ð쬂·‚鎞‚Ɍ•ʂɎw’è‚·‚邱‚Æ‚à‚Å‚«‚éB ¦PDF‚̃o[ƒWƒ‡ƒ“ PDF‚̃o[ƒWƒ‡ƒ“‚ÍAŽŸ‚̂悤‚ÉAcrobat‚âAcrobat Reader‚̃o[ƒWƒ‡ƒ“‚ƑΉž‚µ‚Ä‚¢‚éB PDFƒo[ƒWƒ‡ƒ“1.2 c Acrobatƒo[ƒWƒ‡ƒ“3 PDFƒo[ƒWƒ‡ƒ“1.3 c Acrobatƒo[ƒWƒ‡ƒ“4 PDFƒo[ƒWƒ‡ƒ“1.4 c Acrobatƒo[ƒWƒ‡ƒ“5 ‚µ‚½‚ª‚Á‚ÄAcrobat3‚Å‚àŽg‚¦‚邿‚¤‚É‚µ‚½‚¯‚ê‚Î1.2‚É‚µ‚Ä‚¨‚­B‚½‚¾‚µA“ú–{ŒêTrueTypeƒtƒHƒ“ƒg‚ðŽg‚¤‚Æ‚«‚Í1.3ˆÈオ•K—vBAcrobat4ˆÈã‚ÅŽg‚¦‚ê‚΂悢‚Æ‚¢‚¤‚±‚ƂȂçí‚É1.3‚É‚µ‚Ä‚¨‚¯‚΂悢B ¦ƒf[ƒ^–„‚ßž‚Ý•û–@‚ÌŽw’è Compress::Zlib‚ðŽg‚킸‚Ƀf[ƒ^‚Ì–„‚ßž‚Ý‚ð‚¨‚±‚È‚¤ê‡‚ÍA•¶‘ƒIƒuƒWƒFƒNƒg‚Ìfilterƒƒ\ƒbƒh‚ð—p‚¢‚ÄŽŸ‚̂悤‚Ƀf[ƒ^–„‚ßž‚Ý•û–@‚ÌŽw’è‚ð‚¨‚±‚È‚Á‚Ä‚¨‚­B‚±‚ÌŽw’è‚ð‚µ‚È‚¢ê‡‚ÍCompress::Zlib‚ðŽg‚Á‚½–„‚ßž‚Ý‚ª‚¨‚±‚È‚í‚ê‚éB $docobj->filter('a'); =head2 ƒy[ƒWƒIƒuƒWƒFƒNƒg‚Ìì¬ ƒy[ƒW‚Í•¶‘ƒIƒuƒWƒFƒNƒg‚©‚çnew_pageƒƒ\ƒbƒh‚ŒljÁ‚³‚ê‚éB•‚Æ‚‚³‚ðÈ—ª‚·‚邯•¶‘ƒIƒuƒWƒFƒNƒg‚Ì쬂ÌÛ‚ÉŽw’肵‚½‚à‚Ì‚ªŽg‚í‚ê‚éB $pageobj = $docobj->new_page; $pageobj = $docobj->new_page($width, $height); ¡‚̂Ƃ±‚ëAƒy[ƒW‚Í––”ö‚ɒljÁ‚Å‚«‚邾‚¯‚ÅA“r’†‚É‘}“ü‚·‚é•û–@‚Í—pˆÓ‚³‚ê‚Ä‚¢‚È‚¢B ƒy[ƒW”Ô†‚ÍApagenumƒƒ\ƒbƒh‚Å“¾‚ç‚ê‚éB $pagenum = $pageobj->pagenum; =head2 ƒtƒHƒ“ƒgƒIƒuƒWƒFƒNƒg‚Ìì¬ ƒtƒHƒ“ƒgƒIƒuƒWƒFƒNƒg‚ÍA•¶‘ƒIƒuƒWƒFƒNƒg‚©‚çAnew_fontƒƒ\ƒbƒh‚Åì‚ç‚ê‚éB $fontobj = $docobj->new_font($basefont, $encoding); $basefont‚̓x[ƒXƒtƒHƒ“ƒg–¼‚ÅAType1ƒtƒHƒ“ƒg‚ÌꇎŸ‚Ì‚¢‚¸‚ê‚©‚ðŽw’è‚·‚éB ¦‰¢•¶ƒtƒHƒ“ƒg Courier Courier-Bold Courier-BoldOblique Courier-Oblique Helvetica Helvetica-Bold Helvetica-BoldOblique Helvetica-Oblique Times-Bold Times-BoldItalic Times-Italic Times-Roman ¦˜a•¶ƒtƒHƒ“ƒg Ryumin-Light GothicBBB-Medium $basefont‚ÉTrueTypeƒtƒHƒ“ƒg‚̃tƒ@ƒCƒ‹–¼iŠg’£Žq‚ª.ttfj‚ðŽw’è‚·‚邱‚Æ‚ÅATrueTypeƒtƒHƒ“ƒg‚ðŽw’è‚·‚邱‚Æ‚ª‚Å‚«‚éB‚Ü‚½ATrueTypeCollectionƒtƒHƒ“ƒgiŠg’£Žq‚ª.ttcj‚Ìꇂ͂»‚Ì’†‚̉½”Ô–Úi0‚©‚甂¦‚Äj‚̃tƒHƒ“ƒg‚ðŽg‚¤‚©‚ðƒtƒ@ƒCƒ‹–¼‚ÌŒã‚ë‚Éu:”Ô†v‚Æ‚µ‚Ä•t‰Á‚·‚éBi—áFuc:\windows\fonts\msgothic.ttc:0vj =over 4 ¦TrueTypeCollectionƒtƒHƒ“ƒg‚͌Œèƒsƒbƒ`‚̃tƒHƒ“ƒg‚ƃvƒƒ|[ƒVƒ‡ƒiƒ‹‚ȃtƒHƒ“ƒg‚ªƒZƒbƒg‚ɂȂÁ‚Ä‚¢‚邱‚Æ‚ª‘½‚¢‚ªAã‹L‚̂悤‚É‚µ‚ÄŽw’è‚·‚é‚̂͌Œèƒsƒbƒ`‚Ì•û‚łȂ¯‚ê‚΂Ȃç‚È‚¢B•t‘®‚̃XƒNƒŠƒvƒgttcinfo.pl‚ÅTrueTypeCollectionƒtƒHƒ“ƒg‚Ɋ܂܂ê‚éƒtƒHƒ“ƒg–¼‚𒲂ׂ邱‚Æ‚ª‚Å‚«‚éBƒvƒƒ|[ƒVƒ‡ƒiƒ‹‚ȃtƒHƒ“ƒg‚̓tƒHƒ“ƒg–¼‚É P ‚ª•t‰Á‚³‚ê‚Ä‚¢‚邱‚Æ‚ª‘½‚¢B ¦TrueTypeƒtƒHƒ“ƒg‚ÍPDF‚É–„‚ßž‚Ü‚ê‚éi“ú–{ŒêƒtƒHƒ“ƒg‚Ìꇂ̓TƒuƒZƒbƒg‚Åj‚ªA–„‚ßž‚Ý‚ð‹–‰Â‚µ‚È‚¢TrueTypeƒtƒHƒ“ƒg‚à‘¶Ý‚·‚éBPDFJ‚ÍAƒtƒHƒ“ƒgŽ©‘̂̒†‚É‚ ‚é–„‚ßž‚Ý‚ð‹–‰Â‚·‚é‚©‚Ç‚¤‚©‚̃tƒ‰ƒO‚ðŒ©‚ÄAOK‚©‚Ç‚¤‚©‚ð”»’f‚·‚éB‚½‚¾‚µA•ʂ̃‰ƒCƒZƒ“ƒXƒtƒ@ƒCƒ‹‚ȂǂŎg—p‹–‘øðŒ‚ªŽ¦‚³‚ê‚Ä‚¢‚éê‡‚à‚ ‚肤‚é‚Ì‚ÅAƒtƒHƒ“ƒg쬎҂̌ —˜‚ðNŠQ‚µ‚È‚¢‚悤‚É\•ª’ˆÓ‚µ‚Ä‚¢‚½‚¾‚«‚½‚¢B ¦TrueTypeƒtƒHƒ“ƒg‚ð–„‚ßž‚ÞÛ‚É‚ÍAƒtƒHƒ“ƒgƒtƒ@ƒCƒ‹“à‚Ƀ†ƒjƒR[ƒh‚ɑΉž‚µ‚½cmapƒe[ƒuƒ‹iplatformID‚ª3AplatformSpecificID‚ª1Aformat‚ª4‚Ì‚à‚Ìj‚ª•K—v‚Å‚ ‚éBŒÃ‚¢TrueTypeƒtƒHƒ“ƒg‚ł͂±‚Ìcmapƒe[ƒuƒ‹‚ðŽ‚½‚È‚¢‚à‚Ì‚à‘¶Ý‚·‚éBŒ»ó‚ł͂»‚¤‚¢‚¤TrueTypeƒtƒHƒ“ƒg‚Í–„‚ßž‚Þ‚±‚Æ‚ª‚Å‚«‚È‚¢B =back $encoding‚̓Gƒ“ƒR[ƒfƒBƒ“ƒO‚ÅAŽŸ‚Ì‚¢‚¸‚ê‚©‚Ì’è‹`ς݃Gƒ“ƒR[ƒfƒBƒ“ƒO–¼‚ðŽw’è‚·‚éBÈ—ª‚·‚邯A‰¢•¶ƒtƒHƒ“ƒg‚ɑ΂µ‚Ä‚Í'WinAnsiEncoding'A“ú–{ŒêƒtƒHƒ“ƒg‚ɑ΂µ‚Ä‚Í'90ms-RKSJ-H'‚ªŽg‚í‚ê‚éBMacExpertEncoding‚̓GƒLƒXƒp[ƒgƒtƒHƒ“ƒg‚ƌĂ΂ê‚é“ÁŽê‚ȃtƒHƒ“ƒg‚Ì‚½‚߂̃Gƒ“ƒR[ƒfƒBƒ“ƒOB ¦‰¢•¶ƒtƒHƒ“ƒg‚̃Gƒ“ƒR[ƒfƒBƒ“ƒO WinAnsiEncoding MacRomanEncoding MacExpertEncoding ¦“ú–{ŒêƒtƒHƒ“ƒg‚̃Gƒ“ƒR[ƒfƒBƒ“ƒO 83pv-RKSJ-H c Macintosh JIS X 0208 KanjiTalk6Šg’£ 90pv-RKSJ-H c Macintosh JIS X 0208 KanjiTalk7Šg’£ 90ms-RKSJ-H c Microsoft CP932 JIS X 0208 NEC,IBMŠg’£ 90ms-RKSJ-V c Vc‘‚« Add-RKSJ-H c JIS X 0208 •xŽm’ÊFMRŠg’£ Add-RKSJ-V c Vc‘‚« Ext-RKSJ-H c JIS C 6226(JIS78) NECŠg’£ Ext-RKSJ-V c Vc‘‚« EUC-H c JIS X 0208 EUC-V c Vc‘‚« EUC-NEC-H c JIS X 0208 NECŠg’£ EUC-NEC-V c Vc‘‚« UniJIS-UCS2-HW-H c Unicode ‰¡‘‚« UniJIS-UCS2-HW-V c Unicode c‘‚« “ú–{ŒêƒtƒHƒ“ƒg‚̃Gƒ“ƒR[ƒfƒBƒ“ƒO‚Ì––”ö‚Ì'H'‚͉¡‘‚«A'V'‚Íc‘‚«B'RKSJ'‚Ƃ‚­‚à‚Ì‚ÍShift-JIS—pA'EUC'‚Ƃ‚­‚à‚Ì‚ÍEUC—pA'Uni'‚Ƃ‚­‚à‚Ì‚ÍUnicode—pB“ú–{Œêƒvƒƒ|[ƒVƒ‡ƒiƒ‹ƒtƒHƒ“ƒg‚ÍŽg‚¦‚È‚¢‚±‚ƂɒˆÓB‰¢•¶•”•ª‚àŠÜ‚߂Ă·‚ׂĂ̕¶Žš‚ª‘SŠp‚©”¼Šp‚̌Œèƒsƒbƒ`‚ƂȂéB ¦EUC-NEC-H‚ÆEUC-NEC-V‚ÍAEUC-H‚ÆEUC-V‚ðƒx[ƒX‚ÉNECŠg’£•¶Žši‹æ“_‚Å‚Ì13,89-92‹æj‚ð‰Á‚¦‚½‚à‚Ì‚ÅAPDFJ‚œƎ©‚É’è‹`‚µ‚½ƒGƒ“ƒR[ƒfƒBƒ“ƒO‚Å‚ ‚éi‚±‚ê‚ðŽg‚Á‚½PDF‚ðAcrobat‚ȂǂŊJ‚¢‚ătƒHƒ“ƒgî•ñ‚ðŒ©‚é‚ÆƒGƒ“ƒR[ƒfƒBƒ“ƒO‚ÍuƒJƒXƒ^ƒ€v‚Æ•\ަ‚³‚ê‚éjB‚»‚êˆÈŠO‚ÍAdobe‚É‚æ‚Á‚Ä’è‹`ς̃Gƒ“ƒR[ƒfƒBƒ“ƒOB ¦UTF8‚ÌꇂàƒtƒHƒ“ƒgƒGƒ“ƒR[ƒfƒBƒ“ƒO‚É‚Íã‹L‚ÌUnicode—p‚ðŽw’è‚·‚ê‚΂悢B new_fontƒƒ\ƒbƒh‚É‚Í‚à‚¤ˆê‚‚̗p–@‚ª‚ ‚èA‚‚¬‚̂悤‚É‚µ‚Ä“ú–{ŒêƒtƒHƒ“ƒg‚Ɖ¢•¶ƒtƒHƒ“ƒg‚Ì‘g‚ðŽw’è‚·‚éB $fontobj = $docobj->new_font($jbasefont, $jencoding, $abasefont, $aencoding); ‚±‚±‚ÅA$jbasefont‚Í“ú–{Œêƒx[ƒXƒtƒHƒ“ƒg–¼A$jencoding‚Í‚»‚̃Gƒ“ƒR[ƒfƒBƒ“ƒOA$abasefont‚͉¢•¶ƒx[ƒXƒtƒHƒ“ƒg–¼A$aencoding‚Í‚»‚̃Gƒ“ƒR[ƒfƒBƒ“ƒOB$aencoding‚ðÈ—ª‚·‚邯WinAnsiEncodingB ‚±‚̂悤‚É“ú–{ŒêƒtƒHƒ“ƒg‚Ɖ¢•¶ƒtƒHƒ“ƒg‚ð‘g‚݇‚킹‚½ƒtƒHƒ“ƒgƒIƒuƒWƒFƒNƒg‚ðƒeƒLƒXƒg‚ɑ΂µ‚ÄŽw’è‚·‚邯AƒeƒLƒXƒg’†‚Ì“ú–{Œê•”•ª‚Ɖ¢•¶•”•ªi³Šm‚ÉŒ¾‚¤‚Æ0x7f‚܂łÌASCII•¶Žš‚Ì•”•ªj‚ɑ΂µ‚Ä‚»‚ꂼ‚ê‚̃tƒHƒ“ƒg‚ªŽ©“®“I‚ÉØ‚è‘Ö‚¦‚Ä“K—p‚³‚ê‚éB‚±‚ê‚É‚æ‚èA‰¢•¶•”•ª‚ɂ‚¢‚Ă̓vƒƒ|[ƒVƒ‡ƒiƒ‹‚È•\ަ‚ƂȂéB‘gƒtƒHƒ“ƒg‚ł͉¢•¶ƒtƒHƒ“ƒg‚ª“K—p‚³‚ê‚é‚Ì‚ÍASCII•¶Žš‚¾‚¯‚Å‚ ‚èAASCII•¶Žš‚ɂ‚¢‚Ä‚ÍWinAnsiEncoding‚ÆMacRomanEncoding‚ɈႢ‚͂Ȃ¢‚Ì‚ÅA‘g•¶Žš‚̉¢•¶ƒtƒHƒ“ƒg‚̃Gƒ“ƒR[ƒfƒBƒ“ƒO‚͂ǂ¿‚ç‚ðŽw’肵‚Ä‚à“¯‚¶B ’P“Ƃ̉¢•¶ƒtƒHƒ“ƒg‚ð“K—p‚µ‚½•¶Žš—ñ‚ÍAuse PDFJ 'c'‚ÅŽw’肵‚½“ú–{Œê•¶ŽšƒR[ƒh‚É‚æ‚炸A1ƒoƒCƒg1•¶Žš‚Æ‚µ‚ăGƒ“ƒR[ƒfƒBƒ“ƒO‚É]‚Á‚Ä•\ަ‚³‚ê‚éB “ú–{ŒêƒtƒHƒ“ƒg‚Ì•¶ŽšƒZƒbƒg‚ÍAdobe-Japan1-4‚Æ‚µ‚Ĉµ‚í‚ê‚éBAdobe-Japan1-4‚É‚ÍA‘å‚Ü‚©‚ÉŒ¾‚Á‚ÄJIS X 0201‚Æ0208i‘æˆê…€A‘æ“ñ…€jA‚¨‚æ‚ÑŠeƒ[ƒJ[‚ÌŠg’£•¶Žš‚ªŠÜ‚Ü‚ê‚éBÚׂ͎Ÿ‚ðŽQƂ̂±‚ÆB http://partners.adobe.com/asn/developer/pdfs/tn/5078.Adobe-Japan1-6.pdf ÅV‚Ì•¶ŽšƒZƒbƒg‚ÍAdobe-Japan1-6‚Å‚ ‚èA‚±‚ê‚É‚ÍJIS X 0212i•╊¿Žšj‚Æ0213i‘æŽO…€A‘æŽl…€j‚ªŠÜ‚Ü‚ê‚Ä‚¢‚邪A¡‚̂Ƃ±‚ëPDFJ‚Å‚ÍAdobe-Japan1-6‚ł͂Ȃ­Adobe-Japan1-4‚ªŽg‚í‚ê‚éB =head2 ƒeƒLƒXƒgƒIƒuƒWƒFƒNƒg‚Ìì¬ ƒeƒLƒXƒgƒIƒuƒWƒFƒNƒg‚ÍATextƒTƒuƒ‹[ƒ`ƒ“‚Å쬂·‚éB $textobj = Text(@list, $textstyle); ‚±‚±‚ÅA@list‚Í•¶Žš—ñA•\ަ‰Â”\‚ȃIƒuƒWƒFƒNƒgA‰üsƒIƒuƒWƒFƒNƒg‚ÌƒŠƒXƒg‚ÅA@list‚Ì—v‘f‚ª‡‚É•À‚ׂç‚ꂽ“à—e‚̃eƒLƒXƒg‚ªì¬‚³‚ê‚éB$textstyle‚̓eƒLƒXƒgƒXƒ^ƒCƒ‹ƒIƒuƒWƒFƒNƒgB ƒŠƒXƒg‚Í”z—ñŽQƂ̌`‚Å—^‚¦‚邱‚Æ‚à‚Å‚«‚éB $textobj = Text([@list], $textstyle); ‰üsƒIƒuƒWƒFƒNƒg‚ÍNewLineƒTƒuƒ‹[ƒ`ƒ“‚Å쬂·‚éiˆø”–³‚µjB‰üsƒIƒuƒWƒFƒNƒg‚̓eƒLƒXƒgƒIƒuƒWƒFƒNƒg‚ð‚»‚Ì‚Ü‚Ü•\ަ‚·‚éꇂɂ͉½‚ÌŒø‰Ê‚à‚È‚¢‚ªA’i—ŽƒIƒuƒWƒFƒNƒg‚ðì‚éÛ‚É‹­§‰üs‚·‚éŒø‰Ê‚ð‚à‚½‚ç‚·B ƒeƒLƒXƒgƒXƒ^ƒCƒ‹ƒIƒuƒWƒFƒNƒg‚ÍTStyleƒTƒuƒ‹[ƒ`ƒ“‚Å쬂·‚éB $textstyle = TStyle(%args); ˆø”‚ɂ̓nƒbƒVƒ…ƒŠƒXƒg‚ÌŒ`‚ÅŽŸ‚Ì‚à‚Ì‚ð—^‚¦‚éBfont‚Æfontsize‚Í•K{B‚»‚Ì‘¼‚̓IƒvƒVƒ‡ƒ“B font => ƒtƒHƒ“ƒgƒIƒuƒWƒFƒNƒg fontsize => ƒtƒHƒ“ƒgƒTƒCƒYiƒ|ƒCƒ“ƒgj italic => ƒCƒ^ƒŠƒbƒNƒtƒ‰ƒOi^‚ðŽw’è‚·‚邯ƒCƒ^ƒŠƒbƒN‚Éj bold => ƒ{[ƒ‹ƒhƒtƒ‰ƒOi^‚ðŽw’è‚·‚邯ƒ{[ƒ‹ƒh‚Éj slant => ŽÎ‘̃tƒ‰ƒOi^‚ðŽw’è‚·‚邯ŽÎ‘Ì‚Éj render => •¶Žš•`‰æƒ‚[ƒhi0:“h‚è’ׂµA1:˜güA2:“h‚è’ׂµ{˜güj shapestyle => •¶Žš•`‰æ‚Ì}Œ`ƒXƒ^ƒCƒ‹ƒIƒuƒWƒFƒNƒg rise => ƒx[ƒXƒ‰ƒCƒ“‚Ìã’²®’liƒ|ƒCƒ“ƒgj vh => c’†‰¡ƒtƒ‰ƒOi^‚ðŽw’è‚·‚邯c’†‰¡‚Éj withline => ‰ºü‚Ü‚½‚Í–Tüƒtƒ‰ƒOi^‚ðŽw’è‚·‚邯‰ºü‚Ü‚½‚Í–Tü‚ª•t‚­j withlinestyle => ‰ºü‚Ü‚½‚Í–Tü‚Ì}Œ`ƒXƒ^ƒCƒ‹ƒIƒuƒWƒFƒNƒg withbox => ˆÍ‚ݘgŽw’èif:“h‚è’ׂµAs:˜güAsf:“h‚è’ׂµ{˜güj withboxstyle => ˆÍ‚ݘg‚Ì}Œ`ƒXƒ^ƒCƒ‹ƒIƒuƒWƒFƒNƒg withdot => Œ—“_ƒtƒ‰ƒOi^‚ðŽw’è‚·‚邯Œ—“_‚ª•t‚­j withnote => ’ŽßƒeƒLƒXƒgƒIƒuƒWƒFƒNƒg suffix => “Y‚¦ŽšŽw’èi'u'‚ðŽw’è‚·‚邯ã“Y‚¦ŽšA'l'‚ðŽw’è‚·‚邯‰º“Y‚¦Žšj ruby => ƒ‹ƒr•¶Žš—ñ objalign => •\ަ‰Â”\ƒIƒuƒWƒFƒNƒg‚Ì”z’u noglue => •¶ŽšŽí‚É‚æ‚Á‚ÄŽ©“®‘}“ü‚³‚ê‚é’²®—]”’‚ð“ü‚ê‚È‚¢ code => •¶ŽšƒR[ƒhi'SJIS'A'EUC'A'UTF8'A'UNICODE'‚Ì‚¢‚¸‚ê‚©j slant‚É‚æ‚éŽÎ‘͓̂ú–{Œê•¶Žš—ñ‚ɂ̂ݗLŒø‚Å‚ ‚èA‰¢•¶‚ɂ‚¢‚Ä‚ÍItalicŒn‚̃tƒHƒ“ƒg‚ðŽw’è‚·‚邱‚Ƃł¨‚±‚È‚¤‚±‚ÆBitalic‚Æbold‚ɂ‚¢‚Ä‚ÍAL<"ƒCƒ^ƒŠƒbƒN‚ƃ{[ƒ‹ƒh">‚ðŽQÆB render‚âshapestyle‚ÌŽw’è‚ð‚µ‚È‚¢‚ÆA•¶Žš‚Í•‚Ì“h‚è’ׂµ‚Å•`‰æ‚³‚ê‚éB withline‚ðŽw’肵‚Äwithlinestyle‚ðÈ—ª‚·‚邯•‚ÌŽÀü‚ƂȂéBwithbox‚ðŽw’肵‚Äwithboxstyle‚ðÈ—ª‚·‚邯•‚ÌŽÀü‚ƂȂéB withnote‚Í•¶Žš‚Ìã‚â‰E‚ɕʂ̃eƒLƒXƒgi‚»‚̃eƒLƒXƒgƒIƒuƒWƒFƒNƒg‚ðwithnote‚ÅŽw’è‚·‚éj‚ð•\ަ‚·‚é‚à‚̂ł ‚èAsuffix‚ÍŽw’肵‚½•¶Žš‚𬂳‚­‚µ‚Ĉʒu‚ð㉺‚³‚¹‚é–½—߂ł ‚éB ¦withnote‚É•¶Žš—ñ‚ð—^‚¦Awithnotestyle‚ɃeƒLƒXƒgƒXƒ^ƒCƒ‹ƒIƒuƒWƒFƒNƒg‚ð—^‚¦‚邱‚Æ‚à‚Å‚«‚éB objalign‚ÍAText‚ɉ摜‚â}Œ`‚Ȃǂ̕\ަ‰Â”\ƒIƒuƒWƒFƒNƒg‚ª—^‚¦‚ç‚ꂽ‚Æ‚«‚ɂǂ¤”z’u‚·‚é‚©‚ð‚‚¬‚̂悤‚ÉŽw’è‚·‚éBobjalign‚ÌŽw’è‚ðÈ—ª‚·‚邯A‰¡‘‚«‚Å‚Í'b'Ac‘‚«‚Å‚Í'c'‚Ƃ݂Ȃ³‚ê‚éB ¦‰¡‘‚«‚Ìê‡i㉺•ûŒü‚Ì”z’u‚ÌŽw’è‚Æ‚È‚éj t c •¶Žš‚ƃIƒuƒWƒFƒNƒg‚Ìã’[‚ð‚ ‚í‚¹‚é m c •¶Žš‚ƃIƒuƒWƒFƒNƒg‚Ì㉺’†‰›‚ð‚ ‚í‚¹‚é b c •¶Žš‚ƃIƒuƒWƒFƒNƒg‚̉º’[‚ð‚ ‚í‚¹‚é ¦c‘‚«‚Ìê‡i¶‰E•ûŒü‚Ì”z’u‚ÌŽw’è‚Æ‚È‚éj l c •¶Žš‚ƃIƒuƒWƒFƒNƒg‚̶’[‚ð‚ ‚í‚¹‚é c c •¶Žš‚ƃIƒuƒWƒFƒNƒg‚̶‰E’†‰›‚ð‚ ‚í‚¹‚é r c •¶Žš‚ƃIƒuƒWƒFƒNƒg‚̉E’[‚ð‚ ‚í‚¹‚é code‚ÍAuse PDFJ‚ÅŽw’肵‚½•¶ŽšƒR[ƒh‚Ƃ͈Ⴄ•¶ŽšƒR[ƒh‚É‚æ‚éƒeƒLƒXƒg‚ð—^‚¦‚½‚¢‚Æ‚«‚ÉŽw’è‚·‚éB =head2 ƒeƒLƒXƒgƒIƒuƒWƒFƒNƒg‚Ì“ü‚êŽq‚É‚æ‚é•”•ªƒXƒ^ƒCƒ‹Žw’è ƒeƒLƒXƒg‚̈ꕔ•ª‚¾‚¯‚É“Á’è‚̃Xƒ^ƒCƒ‹‚ð“K—p‚µ‚½‚¢ê‡AƒeƒLƒXƒgƒIƒuƒWƒFƒNƒg‚ð“ü‚êŽq‚É‚µ‚Ä•”•ªƒXƒ^ƒCƒ‹‚ðŽw’è‚·‚邱‚Ƃł¨‚±‚È‚¤B“ü‚êŽq‚ɂȂÁ‚½ƒeƒLƒXƒgƒIƒuƒWƒFƒNƒg‚ł͎q‚̃Xƒ^ƒCƒ‹‚ÅŽw’肳‚ê‚Ä‚¢‚È‚¢ƒXƒ^ƒCƒ‹‚Íe‚Ì‚à‚Ì‚ªˆø‚«Œp‚ª‚ê‚éB —Ⴆ‚ÎA–¾’©‚̃eƒLƒXƒg‚̈ꕔ‚ðƒSƒVƒbƒN‚É‚µ‚½‚¢ê‡A‚‚¬‚̂悤‚É‚·‚éB $mincho = $docobj->new_font('Ryumin-Light', '90ms-RKSJ-H'); $gothic = $docobj->new_font('GothicBBB-Medium', '90ms-RKSJ-H'); $textobj = Text([ "–¾’©", Text("ƒSƒVƒbƒN", TStyle(font => $gothic)), "‚±‚±‚à–¾’©" ], TStyle(font => $mincho, fontsize => 10)); ‚±‚Ìê‡A"ƒSƒVƒbƒN"‚ɑ΂·‚éƒXƒ^ƒCƒ‹‚Å‚Ífontsize‚ªŽw’肳‚ê‚Ä‚¢‚È‚¢‚Ì‚ÅAeƒXƒ^ƒCƒ‹‚Ìfontsize‚Ì10‚ªˆø‚«Œp‚ª‚ê‚éB ƒeƒLƒXƒg‚̈ꕔ‚ɉºü‚ðˆø‚­ê‡‚ÍA—Ⴆ‚΂‚¬‚̂悤‚É‚·‚éB $mincho = $docobj->new_font('Ryumin-Light', '90ms-RKSJ-H'); $normal_style = TStyle(font => $mincho, fontsize => 10); $uline_style = TStyle(withline => 1); $textobj = Text([ "ƒeƒLƒXƒg", Text("‰ºü•t‚«", $uline_style), ], $normal_style); ƒeƒLƒXƒgƒXƒ^ƒCƒ‹‚Í‚±‚̂悤‚ɕϔ‚ɃZƒbƒg‚µ‚Ä‚¨‚¢‚ÄŽg‚¤‚±‚Æ‚à‚Å‚«‚邵Aæ‚Ì—á‚̂悤‚É’¼ÚTStyleƒTƒuƒ‹[ƒ`ƒ“‚ðŽg‚Á‚Ä‚à‚æ‚¢B =head2 ƒCƒ^ƒŠƒbƒN‚ƃ{[ƒ‹ƒh ƒeƒLƒXƒgƒXƒ^ƒCƒ‹‚Ìitalic‚Æbold‚ðŽg‚¤‚½‚߂ɂÍA‚ǂ̃tƒHƒ“ƒg‚ª‚ǂ̃tƒHƒ“ƒg‚̃Cƒ^ƒŠƒbƒNŒ`‚âƒ{[ƒ‹ƒhŒ`‚Å‚ ‚éA‚Æ‚¢‚¤‚±‚Æ‚ðƒhƒLƒ…ƒƒ“ƒgƒIƒuƒWƒFƒNƒg‚É‹³‚¦‚Ä‚¨‚¢‚Ä‚â‚é•K—v‚ª‚ ‚éB‚»‚Ì‚½‚ß‚ÉAitalic()‚Æbold()ƒƒ\ƒbƒh‚ðŽg‚¤B—Ⴆ‚ÎŽŸ‚̂悤‚É‚·‚éB $ft = $docobj->new_font('Times-Roman'); $fti = $docobj->new_font('Times-Italic'); $ftb = $docobj->new_font('Times-Bold'); $ftbi = $docobj->new_font('Times-BoldItalic'); $docobj->italic($ft, $fti, $ftb, $ftbi); $docobj->bold($ft, $ftb, $fti, $ftbi); ‚±‚̂悤‚ÉAŒ³ƒtƒHƒ“ƒgA‚»‚ÌCüƒtƒHƒ“ƒgA‚̇‚ÅA“ñ‘gˆÈã‚ð‚܂Ƃ߂Ĉø”‚É—^‚¦‚邱‚Æ‚ª‚Å‚«‚éB‘g‚ƂȂéƒtƒHƒ“ƒg‚ÍA‰¢•¶ƒtƒHƒ“ƒg“¯ŽmA“ú–{ŒêƒtƒHƒ“ƒg“¯ŽmA‰¢•¶ƒtƒHƒ“ƒg‚Æ‘g‚ɂȂÁ‚½“ú–{ŒêƒtƒHƒ“ƒg“¯ŽmA‚łȂ¯‚ê‚΂Ȃç‚È‚¢B Text('normal', Text('italic', TStyle(italic => 1)), TStyle(font => $ft)) ‚±‚̂悤‚ȃeƒLƒXƒgƒIƒuƒWƒFƒNƒg‚ðì‚邯A'normal'‚É‚Í$ft‚ªA'italic'‚É‚Í$fti‚ªŽg‚í‚ê‚邱‚ƂɂȂéB italic()‚âbold()‚ł̓o˜^‚ª‚³‚ê‚Ä‚¢‚È‚¢ƒtƒHƒ“ƒg‚ɑ΂µ‚Äitalic‚âbold‚̃Xƒ^ƒCƒ‹‚ð—^‚¦‚½ê‡‚ÍA‰½‚ÌŒø‰Ê‚à‚à‚½‚炳‚È‚¢B ‚È‚¨Aˆê”ʂɓú–{ŒêƒtƒHƒ“ƒg‚ɂ̓Cƒ^ƒŠƒbƒNŒ`‚Í‘¶Ý‚µ‚È‚¢‚Ì‚ÅA“ú–{Œê•¶Žš—ñ‚ɑ΂µ‚ăeƒLƒXƒgƒXƒ^ƒCƒ‹‚Åitalic‚ªŽw’肳‚ꂽꇂÍAslant‚É’u‚«Š·‚¦‚ÄŒX‚¯‚Ä•\ަ‚·‚éB =head2 ’i—ŽƒIƒuƒWƒFƒNƒg‚Ìì¬ ’i—ŽƒIƒuƒWƒFƒNƒg‚ÍParagraphƒTƒuƒ‹[ƒ`ƒ“‚Å쬂·‚éB $paragraphobj = Paragraph($textobj, $parastyle); ‚±‚±‚ÅA$textobj‚̓eƒLƒXƒgƒIƒuƒWƒFƒNƒgA$parastyle‚Í’i—ŽƒXƒ^ƒCƒ‹ƒIƒuƒWƒFƒNƒgB•¡”‚̃eƒLƒXƒg‚ð—^‚¦‚½‚¢‚Æ‚«‚Í‚»‚ê‚ðˆê‚‚̃eƒLƒXƒgƒIƒuƒWƒFƒNƒg‚ɂ܂Ƃ߂½ã‚Å—^‚¦‚éB ’i—ŽƒXƒ^ƒCƒ‹ƒIƒuƒWƒFƒNƒg‚ÍPStyleƒTƒuƒ‹[ƒ`ƒ“‚Å쬂·‚éB $parastyle = PStyle(%args); ˆø”‚ɂ̓nƒbƒVƒ…ƒŠƒXƒg‚ÌŒ`‚ÅŽŸ‚Ì‚à‚Ì‚ð—^‚¦‚éBsize‚Ælinefeed‚Æalign‚Í•K{B‘¼‚̓IƒvƒVƒ‡ƒ“B size => ’i—Ž‚Ìs•ûŒü‚̃TƒCƒYiƒ|ƒCƒ“ƒgj align => ‘µ‚¦ib:s“ª‘µ‚¦ m:’†‰›‘µ‚¦ e:s––‘µ‚¦ w:—¼’[‘µ‚¦ W:‹­§—¼’[‘µ‚¦j linefeed => s‘—‚èiƒ|ƒCƒ“ƒgj preskip => ’i—Ž‘O‚ÌŠÔŠuiƒ|ƒCƒ“ƒgj postskip => ’i—ŽŒã‚ÌŠÔŠuiƒ|ƒCƒ“ƒgj beginindent => s“ªƒCƒ“ƒfƒ“ƒg endindent => s––ƒCƒ“ƒfƒ“ƒg beginpadding => s“ª‘¤‚Ì—]”’iƒ|ƒCƒ“ƒgj labeltext => ƒ‰ƒxƒ‹‚̃eƒLƒXƒgƒIƒuƒWƒFƒNƒg labelsize => ƒ‰ƒxƒ‹‚Ìs•ûŒü‚̃TƒCƒYiƒ|ƒCƒ“ƒgj labelskip => ƒ‰ƒxƒ‹‚Æ–{•¶‚ÌŠÔŠuiƒ|ƒCƒ“ƒgj nobreak => ^‚¾‚Æbreakƒƒ\ƒbƒh‚Å•ªŠ„‚³‚ê‚È‚¢ postnobreak => ^‚¾‚ƃuƒƒbƒN‚Ìbreak‚Å‚»‚ÌŒã‚ë‚Å•ªŠ„‚³‚ê‚È‚¢ float => ƒuƒƒbƒN‚Ìbreak‚ňʒu‚ðŽ©“®ˆÚ“®iuƒuƒƒbƒNƒIƒuƒWƒFƒNƒg‚Ì•ªŠ„vŽQÆj linefeed‚ÅŽw’è‚·‚é‚Ì‚Ís‘—‚è‚Å‚ ‚Á‚ÄsŠÔ‚ł͂Ȃ¢‚±‚ƂɒˆÓBlinefeed => '150%' ‚̂悤‚É ”’l% ‚ÆŽw’è‚·‚邯AƒeƒLƒXƒgƒIƒuƒWƒFƒNƒg‚̃tƒHƒ“ƒgƒTƒCƒY‚ɑ΂·‚銄‡‚Ƃ݂Ȃ³‚ê‚éB preskip‚Æpostskip‚ÍAƒuƒƒbƒN“à‚É’i—Ž‚ð•À‚ׂ鎞‚ÌŠÔŠu‚Æ‚µ‚ÄŽg‚í‚ê‚éBÈ—ª‚·‚邯A‚»‚ꂼ‚êsŠÔis‘—‚è‚©‚çƒtƒHƒ“ƒgƒTƒCƒY‚ð·‚µˆø‚¢‚½’·‚³j‚Ì”¼•ª‚ɃZƒbƒg‚³‚ê‚éB ƒeƒLƒXƒg‚ÍA(size - beginpadding - beginindent - endindent - labelsize)‚Æ‚¢‚¤s’·‚ð’´‚¦‚È‚¢‚悤‚ÉÜ‚è•Ô‚µˆ—‚³‚êAalign‚É‚µ‚½‚ª‚Á‚Ä‘µ‚¦‚ç‚ê‚éBw‚É‚æ‚é—¼’[‘µ‚¦‚ÌŽžA––”ös‚¾‚¯‚Ís“ª‘µ‚¦‚ƂȂéBW‚É‚æ‚é‹­§—¼’[‘µ‚¦‚Å‚ÍA––”ös‚àŠÜ‚߂ė¼’[‘µ‚¦‚ƂȂéBs‚ÌÜ‚è•Ô‚µ‚Ìۂ֑̋¥‚ƃnƒCƒtƒl[ƒVƒ‡ƒ“A—¼’[‘µ‚¦‚ÌÛ‚Ì‹l‚ßL‚΂µ‚ÍAJIS X 4051‚ɂقڑ¥‚Á‚Ä‚¨‚±‚È‚í‚ê‚éB beginindent‚Æendindent‚ð”z—ñŽQƂ̌`‚Å—^‚¦‚邯A擪s‚©‚燂Ɏg‚í‚ê‚éBs”‚ª—v‘f”‚æ‚è‘å‚«‚¢‚Æ‚«‚ÍÅŒã‚Ì—v‘f‚ªŒJ‚è•Ô‚µŽg‚í‚ê‚éB beginpadding‚ÍAƒ‰ƒxƒ‹‚àŠÜ‚ß‚½’i—Ž‘S‘Ì‚ÌAs“ª‘¤‚ÉŽæ‚é—]”’‚ðŽw’è‚·‚éBi‚±‚Ì—]”’‚Ísize‚Ì’†‚Ɋ܂܂ê‚éBj‚µ‚½‚ª‚Á‚ÄAƒ‰ƒxƒ‹‚ª‚È‚¢‚Æ‚«‚ÍAbeginpadding‚ÌŽw’è‚Æ’P“Æ—v‘f‚Ìbeginindent‚ÌŽw’è‚Í“¯‚¶Œø‰Ê‚ðŽ‚ÂB labeltext‚ŃeƒLƒXƒgƒIƒuƒWƒFƒNƒg‚ªŽw’肳‚ê‚邯Aƒ‰ƒxƒ‹‚Æ‚µ‚Äæ“ªs‚Ì‘O‚É•\ަ‚³‚ê‚éBƒ‰ƒxƒ‹‚Æ–{•¶‚ÌŠÔ‚É‚Ílabelskip‚¾‚¯‚ÌŠÔŠu‚ªŽæ‚ç‚ê‚éBlabeltext‚É•¶Žš—ñ‚ð—^‚¦‚邯–{‘̂̃eƒLƒXƒgƒIƒuƒWƒFƒNƒg‚Æ“¯‚¶ƒeƒLƒXƒgƒXƒ^ƒCƒ‹‚ŃeƒLƒXƒgƒIƒuƒWƒFƒNƒg‰»‚³‚ê‚éB labeltext‚É‚ÍAƒeƒLƒXƒgƒIƒuƒWƒFƒNƒg‚ð•Ô‚·ƒTƒuƒ‹[ƒ`ƒ“ŽQÆ‚ÆA‚»‚̃Tƒuƒ‹[ƒ`ƒ“‚É—^‚¦‚éˆø”‚ÌƒŠƒXƒg‚ðA”z—ñŽQƂ̌`‚Å—^‚¦‚邱‚Æ‚à‚Å‚«‚éB‚±‚ê‚É‚æ‚Á‚ĔԆ•t‚«‰Óð‘‚«‚ªŽÀŒ»‚Å‚«‚éB—Ⴆ‚΂‚¬‚̂悤‚ɂȂéB $LabelNum = 1; sub numlabel { my($fmt, $style) = @_; Text(sprintf($fmt, $LabelNum++), $style); } $ol_style = PStyle(size => 500, align => 'w', labelsize => 30, labeltext => [\&numlabel, "%d.", $normal_style]); $para1 = Paragaph($text1, $ol_style); $para2 = Paragaph($text2, $ol_style); postnobreak‚Æfloat‚ÍA‚±‚Ì’i—Ž‚ðŠÜ‚ÞƒuƒƒbƒN‚ªbreak‚³‚ê‚邯‚«‚ɈӖ¡‚ðŽ‚ÂB =head2 ’i—ŽƒIƒuƒWƒFƒNƒg‚Ì•ªŠ„ ’i—Ž‚Ìs•ûŒü‚̑傫‚³‚Í’i—ŽƒXƒ^ƒCƒ‹‚Ìsize‚ÅŽw’肵‚½‚à‚̂ɂȂ邪A‚»‚ê‚Æ‚’¼‚È•ûŒü‚̑傫‚³‚Ís”i‚Æs‘—‚è‚ÆƒtƒHƒ“ƒgƒTƒCƒYj‚ÅŒˆ‚Ü‚éB‚±‚ꂪˆê’è‚̑傫‚³‚É‚È‚é‚æ‚¤‚É’i—Ž‚ð•ªŠ„‚·‚邽‚ß‚ÉAbreakƒƒ\ƒbƒh‚ª—pˆÓ‚³‚ê‚Ä‚¢‚éB—Ⴆ‚Ή¡‘‚«‚Ì’i—ŽƒIƒuƒWƒFƒNƒg$para‚ɑ΂µ‚ÄA @paras = $para->break(200); ‚Æ‚·‚邯A‚‚³‚ª200ƒ|ƒCƒ“ƒgˆÈ‰º‚É‚È‚é‚æ‚¤‚É•ªŠ„‚µ‚½’i—Ž‚ÌƒŠƒXƒg‚ª“¾‚ç‚ê‚éB‚à‚µAʼn‚Ì’i—Ž‚¾‚¯‚Í‚‚³‚ð100ˆÈ‰º‚É‚µ‚½‚¯‚ê‚ÎA‚‚¬‚̂悤‚É‚·‚ê‚΂悢B @paras = $para->break(100, 200); break‚̈ø”‚ÉŽw’肵‚½ƒTƒCƒY‚ÌƒŠƒXƒg‚͇‚É•ªŠ„‚·‚é’i—Ž‚ÌƒTƒCƒY‚Æ‚µ‚ÄŽg‚í‚êA‚È‚­‚È‚é‚ÆÅŒã‚̃TƒCƒY‚ªŒJ‚è•Ô‚µŽg‚í‚ê‚éB break‚̈ø”‚ÉŽw’肵‚½ƒTƒCƒY‚ª¬‚³‚·‚¬‚ÄAÅŒã‚̃TƒCƒY‚Å‚à•ªŠ„‚Å‚«‚È‚¢•”•ª‚ªŽc‚Á‚½‚Æ‚«‚ÍA•ªŠ„‚ÉŽ¸”s‚µ‚½‚à‚̂Ƃµ‚Ä–¢’è‹`’l‚ª•Ô‚³‚ê‚éB ‚à‚µA$para->break(5, 200) ‚̂悤‚Éʼn‚â“r’†‚ɃtƒHƒ“ƒgƒTƒCƒY‚æ‚謂³‚ȃTƒCƒY‚ðŽw’è‚·‚邯A‚»‚ê‚ɑΉž‚µ‚Ä‹ó‚Ì’i—ŽƒIƒuƒWƒFƒNƒg‚ª“¾‚ç‚ê‚éB‚±‚Ì—á‚Å‚ÍAʼn‚É‹ó‚Ì’i—ŽƒIƒuƒWƒFƒNƒgA‘±‚¢‚Ä200‚¸‚‚ɕªŠ„‚³‚ꂽ’i—ŽƒIƒuƒWƒFƒNƒg‚ª•Ô‚³‚ê‚邱‚ƂɂȂéB ’i—ŽƒXƒ^ƒCƒ‹‚Ìnobreak‚ª^‚Éݒ肳‚ê‚Ä‚¢‚邯A•ªŠ„‚³‚ê‚È‚¢B—Ⴆ‚Înobreak‚ȉ¡‘‚«’i—ŽƒIƒuƒWƒFƒNƒg$upara‚ª‚ ‚èA‚»‚Ì‚‚³‚ª150‚Å‚ ‚邯‚«‚ÉA$upara->break(100, 200) ‚Í (‹ó’i—ŽƒIƒuƒWƒFƒNƒg, $upara‚Æ“¯‚¶ƒIƒuƒWƒFƒNƒg) ‚ð•Ô‚·B$upara->break(100) ‚ł͕ªŠ„‚ÉŽ¸”s‚µ‚Ä–¢’è‹`’l‚ð•Ô‚·B =head2 ƒuƒƒbƒNƒIƒuƒWƒFƒNƒg‚Ìì¬ ƒuƒƒbƒNƒIƒuƒWƒFƒNƒg‚ÍBlockƒTƒuƒ‹[ƒ`ƒ“‚Å쬂·‚éB $blockobj = Block($direction, @objlit, $blockstyle); ‚±‚±‚ÅA$direction‚̓uƒƒbƒN‚Ì“à—e‚ð•À‚ׂé•ûŒüA@objlit‚Í•\ަ‰Â”\‚ȃIƒuƒWƒFƒNƒg‚ÌƒŠƒXƒgA$blockstyle‚̓uƒƒbƒNƒXƒ^ƒCƒ‹ƒIƒuƒWƒFƒNƒgB ƒIƒuƒWƒFƒNƒg‚ÌƒŠƒXƒg‚͂‚¬‚̂悤‚É”z—ñŽQƂ̌`‚Å—^‚¦‚邱‚Æ‚à‚Å‚«‚éB $blockobj = Block($direction, [@objlit], $blockstyle); ƒuƒƒbƒN‚Ì“à—e‚ð•À‚ׂé•ûŒü‚ÍAŽŸ‚Ì‚¢‚¸‚ê‚©‚ðŽw’è‚·‚éB H c ¶‚©‚ç‰E R c ‰E‚©‚ç¶ V c ã‚©‚牺 $direction‚ÅŽw’肵‚½•ûŒü‚ÉA@objlit‚Ì—v‘f‚ð‡‚É•À‚ׂ½‚à‚Ì‚ªƒuƒƒbƒN‚Ì“à—e‚ƂȂéB‚»‚ÌÛAŠe—v‘f‚Ì•\ަ‰Â”\‚ȃIƒuƒWƒFƒNƒg‚ÉApreskip‚âpostskip‚̃Xƒ^ƒCƒ‹‚ªŽw’肳‚ê‚Ä‚¢‚ê‚ÎA‚»‚ê‚É‚µ‚½‚ª‚Á‚ÄŠÔŠu‚ªŽæ‚ç‚ê‚éB‚Ü‚½“ÁŽê‚ÈŽw’è‚Æ‚µ‚ÄA@objlist‚Ì’†‚ɃIƒuƒWƒFƒNƒg‚łȂ­¶‚Ì”’l‚ð“ü‚ê‚邯‚»‚ÌŠÔŠu‚ªŽæ‚ç‚ê‚éB ƒuƒƒbƒNƒXƒ^ƒCƒ‹ƒIƒuƒWƒFƒNƒg‚ÍBStyleƒTƒuƒ‹[ƒ`ƒ“‚Å쬂·‚éB $blockstyle = BStyle(%args); ˆø”‚ɂ̓nƒbƒVƒ…ƒŠƒXƒg‚ÌŒ`‚ÅŽŸ‚Ì‚à‚Ì‚ð—^‚¦‚éB width => •iƒ|ƒCƒ“ƒgj height => ‚‚³iƒ|ƒCƒ“ƒgj align => ‘µ‚¦ adjust => ‘µ‚¦ƒtƒ‰ƒOi^‚ðŽw’è‚·‚邯—v‘f‚̃uƒƒbƒN‚̃TƒCƒY‚𑵂¦‚éj padding => ŽüˆÍ—]”’iƒ|ƒCƒ“ƒgj beginpadding => s“ª‘¤‚Ì—]”’iƒ|ƒCƒ“ƒgj withbox => ˆÍ‚ݘgŽw’èif:“h‚è’ׂµAs:˜güAsf:“h‚è’ׂµ{˜güj withboxstyle => ˆÍ‚ݘg‚Ì}Œ`ƒXƒ^ƒCƒ‹ƒIƒuƒWƒFƒNƒg preskip => ‘O‚ÌŠÔŠuiƒ|ƒCƒ“ƒgj postskip => Œã‚ÌŠÔŠuiƒ|ƒCƒ“ƒgj nobreak => ^‚¾‚Æbreak‚Å•ªŠ„‚³‚ê‚È‚¢ postnobreak => ^‚¾‚ƃuƒƒbƒN‚Ìbreak‚Å‚»‚ÌŒã‚ë‚Å•ªŠ„‚³‚ê‚È‚¢ repeatheader => break‚Å•ªŠ„‚·‚邯‚«æ“ª‚ÅŒJ‚è•Ô‚·—v‘f” float => ƒuƒƒbƒN‚Ìbreak‚ňʒu‚ðŽ©“®ˆÚ“®iuƒuƒƒbƒNƒIƒuƒWƒFƒNƒg‚Ì•ªŠ„vŽQÆj nofirstfloat => ^‚¾‚Æbreak‚Åæ“ª‚É‚Ífloat—v‘f‚ð’u‚©‚È‚¢ bfloatsep => float‚ªb‚Ì—v‘f‚Æ‚»‚êˆÈŠO‚Ì—v‘f‚ÌŠÔ‚É‘}“ü‚³‚ê‚é•\ަ‰Â”\ƒIƒuƒWƒFƒNƒg efloatsep => float‚ªe‚Ì—v‘f‚Æ‚»‚êˆÈŠO‚Ì—v‘f‚ÌŠÔ‚É‘}“ü‚³‚ê‚é•\ަ‰Â”\ƒIƒuƒWƒFƒNƒg widthAheight‚Å•‚â‚‚³‚ðŽw’肵‚½ê‡A“à—e‚Ì•‚â‚‚³‚ª‚»‚ê‚æ‚è‘å‚«‚¢ê‡‚Í“à—e‚ɇ‚킹‚ç‚ê‚éB“à—e‚æ‚è‚àŽw’肵‚½•‚â‚‚³‚ª‘å‚«‚¢ê‡‚ÍAalign‚É‚µ‚½‚ª‚Á‚Ĉʒu‚ª‘µ‚¦‚ç‚ê‚éB align‚É‚æ‚鑵‚¦‚ÍŽŸ‚Ì‚¢‚¸‚ê‚©‚ð‘g‚݇‚킹‚ÄŽw’èBÈ—ª‚·‚邯'tl'‚Ƃ݂Ȃ³‚ê‚éB ¦¶‰E•ûŒü l c ¶Šñ‚¹ c c ’†‰›Šñ‚¹ r c ‰EŠñ‚¹ ¦ã‰º•ûŒü t c ãŠñ‚¹ m c ’†‰›Šñ‚¹ b c ‰ºŠñ‚¹ adjust‚ð^‚ÉŽw’è‚·‚邯A•ûŒü‚ªH‚âR‚Ìꇂ͗v‘fƒuƒƒbƒN‚Ì‚‚³AV‚Ìꇂ͗v‘fƒuƒƒbƒN‚Ì•‚ðA‚à‚Á‚Æ‚à‘å‚«‚¢‚à‚̂ɑµ‚¦‚éBƒuƒƒbƒN‚ð•À‚ׂĕ\‚ð쬂·‚邯‚«‚ÉŽg—p‚·‚éB padding‚Í“à—e‚ÌŽü‚è‚ÉŽæ‚ç‚ê‚é—]”’‚Ì•‚Å‚ ‚èAwithbox‚ň͂ݘg‚ðŽw’肵‚½ê‡‚Í‚»‚Ì—]”’‚ÌŠO‘¤‚É•`‰æ‚³‚ê‚éB beginpadding‚͈͂ݘg‚ÌŠO‚Ìs“ª‘¤‚ÉŽæ‚ç‚ê‚é—]”’‚ÌŽw’è‚Å‚ ‚éB withbox‚Å‚ÍA's','f','sf'‚Ì‘¼‚ÉA'rX'iX‚Í”’lj‚ð•t‰Á‚·‚邯Šp‚ª”¼ŒaX‚ÅŠÛ‚­‚È‚éB =head2 ƒuƒƒbƒNƒIƒuƒWƒFƒNƒg‚Ì•ªŠ„ ’i—ŽƒIƒuƒWƒFƒNƒg‚Æ“¯—l‚ÉAƒuƒƒbƒNƒIƒuƒWƒFƒNƒg‚àbreakƒƒ\ƒbƒh‚É‚æ‚Á‚Ä•ªŠ„‚ª‚Å‚«‚éB—Ⴆ‚ΕûŒü‚ª'V'‚̃uƒƒbƒNƒIƒuƒWƒFƒNƒg$block‚ð‚‚³‚ª200ƒ|ƒCƒ“ƒgˆÈ‰º‚É‚È‚é‚æ‚¤‚É•ªŠ„‚µ‚½‚¯‚ê‚ÎA @blocks = $block->break(200); ‚Æ‚·‚ê‚΂悢Bʼn‚̃uƒƒbƒN‚¾‚¯‚‚³‚ð100ˆÈ‰º‚É‚µ‚½‚¯‚ê‚ÎA‚‚¬‚̂悤‚É‚·‚éB @blocks = $block->break(100, 200); break‚̈ø”‚ÉŽw’肵‚½ƒTƒCƒY‚ÌƒŠƒXƒg‚͇‚É•ªŠ„‚µ‚½’i—Ž‚ÌƒTƒCƒY‚Æ‚µ‚ÄŽg‚í‚êA‚È‚­‚È‚é‚ÆÅŒã‚̃TƒCƒY‚ªŒJ‚è•Ô‚µŽg‚í‚ê‚éB ƒuƒƒbƒN‚Ì•ªŠ„‚ÌÛAƒuƒƒbƒN“à‚̃IƒuƒWƒFƒNƒg‚Æ‚µ‚ÄA•ûŒü‚Ì“¯‚¶ƒuƒƒbƒN‚âAs•ûŒü‚̈قȂé’i—Ži'V'‚È‚ç'H'A'H'‚â'R'‚È‚ç'V'j‚ª‚ ‚邯A‚»‚̃IƒuƒWƒFƒNƒg‚à•ªŠ„‚·‚邱‚Ƃłł«‚邾‚¯Žw’è‚̃TƒCƒY‚ɇ‚¤‚悤‚É•ªŠ„‚³‚ê‚éB Žw’肵‚½ƒTƒCƒY‚Å•ªŠ„‚ª‚Å‚«‚È‚©‚Á‚½ê‡Abreakƒƒ\ƒbƒh‚Í–¢’è‹`’l‚ð•Ô‚·B•¡”‚̃TƒCƒY‚ðŽw’肵‚½ê‡‚ÉAÅŒãˆÈŠO‚̃TƒCƒY‚ª¬‚³‚·‚¬‚½ê‡‚ÍA‚»‚ê‚ɑΉž‚·‚é‚à‚̂Ƃµ‚Ä‹ó‚̃uƒƒbƒN‚ª•Ô‚³‚ê‚éB ƒuƒƒbƒNƒXƒ^ƒCƒ‹‚Å nobreak ‚ª^‚ɂȂÁ‚Ä‚¢‚邯A‚»‚̃uƒƒbƒN‚Í•ªŠ„‚³‚ê‚È‚¢B ƒuƒƒbƒN‚Ì’†‚ÉNewBlockƒTƒuƒ‹[ƒ`ƒ“‚Å쬂³‚ê‚é‰üƒuƒƒbƒNƒIƒuƒWƒFƒNƒg‚ª‚ ‚邯AƒuƒƒbƒN‚Ì•ªŠ„‚ÌÛ‚É‚»‚±‚Å‹­§“I‚É•ªŠ„‚³‚ê‚éB ƒuƒƒbƒN‚Ì•ªŠ„‚ÌÛA‚»‚Ì—v‘f‚ƂȂéƒuƒƒbƒN‚â’i—Ž‚â}Œ`‚̃Xƒ^ƒCƒ‹‚Å postnobreak ‚ª^‚Éݒ肳‚ê‚Ä‚¢‚邯A‚»‚ÌŒã‚ë‚Å•ªŠ„‚³‚ê‚邱‚Ƃ͂Ȃ¢B‚±‚ê‚É‚æ‚Á‚ÄAŒ©o‚µ’i—Ž‚Æ–{•¶’i—Ž‚ª•ʃy[ƒW‚É•ª‚©‚ê‚邱‚Æ‚ð–h‚®‚±‚Æ‚ª‚Å‚«‚éB ƒuƒƒbƒN‚Ì•ªŠ„‚ÌÛA‚»‚Ì—v‘f‚ƂȂéƒuƒƒbƒN‚â’i—Ž‚â}Œ`‚̃Xƒ^ƒCƒ‹‚Å float ‚ªÝ’肳‚ê‚Ä‚¢‚邯A‚»‚Ì—v‘f‚Í•ªŠ„‚³‚ꂽƒuƒƒbƒN“à‚ÅŽw’è‚̈ʒu‚Ɉړ®‚³‚ê‚éBfloatŽw’è‚̈Ӗ¡‚ÍŽŸ‚̂Ƃ¨‚èB bN:•ªŠ„‚³‚ꂽƒuƒƒbƒN‚Ìæ“ªiN‚Í1`9‚Ü‚½‚ÍÈ—ªj eN:•ªŠ„‚³‚ꂽƒuƒƒbƒN‚Ì––”öiN‚Í1`9‚Ü‚½‚ÍÈ—ªj h:•ªŠ„‚¹‚¸‚ɉ”\‚Ȃ炻‚̈ʒu‚ÉA–³—‚Ȃ玟‚̃uƒƒbƒN‚Ìæ“ª‚É b‚Æe‚ÌŒã‚ë‚É1`9‚̔Ԇ‚ð•t‚¯‚Ä”Žš•ʂɃOƒ‹[ƒv‰»‚Å‚«‚éB”Žš‚̑傫‚È‚à‚Ì‚Ù‚Çæ“ª‚Ü‚½‚Í––”öŠñ‚è‚É”z’u‚³‚ê‚éBb0‚âe0‚Ƃ͂¹‚¸‚Éb‚âe‚Æ‚·‚邱‚ƂɒˆÓB ƒuƒƒbƒNƒXƒ^ƒCƒ‹‚Ånofirstfloat‚ð^‚ÉŽw’è‚·‚邯Abreak‚ÌÛ‚É‘S‘Ì‚Ìæ“ª‚É‚Ífloat—v‘f‚ð’u‚©‚È‚¢B ƒuƒƒbƒNƒXƒ^ƒCƒ‹‚Ìbfloatsep‚Å•\ަ‰Â”\ƒIƒuƒWƒFƒNƒg‚ðŽw’è‚·‚邯Afloat‚ªb‚Åæ“ª‚Ɉړ®‚µ‚½—v‘fŒQ‚ÌŒã‚É‘}“ü‚³‚ê‚éBefloatsep‚ÅŽw’肵‚½ƒIƒuƒWƒFƒNƒg‚Ífloat‚ªe‚Å––”ö‚Ɉړ®‚µ‚½—v‘fŒQ‚Ì‘O‚É‘}“ü‚³‚ê‚éB‚±‚ê‚É‚æ‚èAfloat‚ðe‚Æ‚µ‚ăy[ƒW––”ö‚Ɉړ®‚µ‚½‹r’’i—Ž‚Æ–{•¶’i—Ž‚ÌŠÔ‚É‹æØ‚èü‚ð“ü‚ê‚邿‚¤‚È‚±‚Æ‚ª‚Å‚«‚éBfloat‚ÉbN‚âeNiN‚Í1`9j‚ðŽg‚¤ê‡‚ÍAbfloatsep‚âefloatsep‚É”z—ñŽQƂ̌`‚ŃIƒuƒWƒFƒNƒg‚ÌƒŠƒXƒg‚ð—^‚¦‚邯A‚»‚ÌN”Ô–Ú‚Ì‚à‚Ì‚ªŽg‚í‚ê‚éib‚âe‚É‚Í0”Ô–Ú‚Ì‚à‚Ì‚ªŽg‚í‚ê‚éjB‚È‚¨Abfloatsep‚âefloatsep‚ÉŽg‚¤ƒIƒuƒWƒFƒNƒg‚Í‚»‚êê—p‚ÉŽg—p‚µA•ªŠ„‚³‚ê‚éƒuƒƒbƒN‚Ì“à—e‚Æ‚µ‚ÄŽg‚Á‚Ă͂Ȃç‚È‚¢B‚Ü‚½Abfloatsep‚ÉŽg‚¤ƒIƒuƒWƒFƒNƒg‚Æefloatsep‚ÉŽg‚¤ƒIƒuƒWƒFƒNƒg‚àˆÙ‚È‚éƒIƒuƒWƒFƒNƒg‚łȂ¯‚ê‚΂Ȃç‚È‚¢B ƒuƒƒbƒNƒXƒ^ƒCƒ‹‚Å repeatheader ‚ªŽw’肳‚ê‚Ä‚¢‚邯A‚»‚Ì’l‚Ì”‚¾‚¯‚Ìæ“ª—v‘f‚ªA•ªŠ„‚³‚ꂽŠeƒuƒƒbƒN‚Ìæ“ª‚ÅŒJ‚è•Ô‚³‚ê‚éBi‚½‚¾‚µæ“ª—v‘f‚Ì“r’†‚âŒã‚ë‚Å•ªŠ„‚³‚ꂽꇂ͜‚­Bj‚±‚ê‚É‚æ‚Á‚Ä•\‚Ìæ“ª‚Ì€–Ú–¼‚Ìs‚ðŒJ‚è•Ô‚·‚±‚Æ‚ª‚Å‚«‚éB擪—v‘fŽ©‘Ì‚ª•ªŠ„‚³‚ê‚邯‚¨‚©‚µ‚ÈŒ‹‰Ê‚ª“¾‚ç‚ê‚é‚Ì‚ÅA擪—v‘f‚ª•ªŠ„‰Â”\‚È’i—Ž‚âƒuƒƒbƒN‚Ìê‡‚Í nobreak ‚ðŽw’肵‚Ä‚¨‚­‚±‚Æi•ûŒü‚̈ႤƒuƒƒbƒN‚Ìꇂ͕s—vjB‚Ü‚½æ“ª—v‘f‚ÆŽŸ‚Ì—v‘f‚ª•ªŠ„‚³‚ꂽꇂà•s“K؂Ȍ‹‰Ê‚ƂȂé‚Ì‚ÅA擪—v‘f‚É‚Í postnobreak ‚ÌŽw’è‚ð‚µ‚Ä‚¨‚­‚±‚ÆB =head2 ‰æ‘œƒIƒuƒWƒFƒNƒg‚Ìì¬ ‰æ‘œƒIƒuƒWƒFƒNƒg‚ÍJPEG‰æ‘œ‚ɂ‚¢‚Ă̂Ý쬂ł«A•¶‘ƒIƒuƒWƒFƒNƒg‚©‚çnew_imageƒƒ\ƒbƒh‚Å쬂·‚éB $imgobj = $docobj->new_image($src, $pxwidth, $pxheight, $width, $height, $padding, $colorspace); ‚±‚±‚ÅA$src‚ÍURL‚Ü‚½‚̓tƒ@ƒCƒ‹–¼iŠg’£Žq‚Í.jpg‚Ü‚½‚Í.jpeg‚Å‚ ‚邱‚ÆjA$pxwidth‚Æ$pxheight‚͉摜‚̃sƒNƒZƒ‹ƒTƒCƒYA$width‚Æ$height‚Í•\ަƒTƒCƒYiƒ|ƒCƒ“ƒgjA$padding‚ÍŽüˆÍ‚Ì—]”’iƒ|ƒCƒ“ƒgjA$colorspace‚̓Jƒ‰[ƒXƒy[ƒXirgb,gray,cmyk‚Ì‚¢‚¸‚ê‚©‚ÅÈ—ª‚·‚邯rgbjB$padding‚Æ$colorspace‚ÍÈ—ª‚Å‚«‚éB Œ»Ý‚ÌŽd—l‚Å‚ÍAURLŽw’肵‚½ê‡‚Ͷ¬‚³‚ê‚éPDF‚É‚ÍURLî•ñ‚¾‚¯‚ª–„‚ßž‚Ü‚êA•\ަ‚·‚éÛ‚ÉAcrobatReader‚ª‚»‚ÌURL‚ɃAƒNƒZƒX‚µ‚ĉ摜“à—e‚ð“ǂ݂ƂéB‚µ‚½‚ª‚Á‚Ä•\ަ‚ÉŽžŠÔ‚ª‚©‚©‚Á‚½‚èAƒAƒNƒZƒX‚Å‚«‚È‚¢‚Ɖ摜‚ª•\ަ‚Å‚«‚È‚¢‚Æ‚¢‚Á‚½‚±‚Æ‚ª‹N‚±‚肤‚éB ƒtƒ@ƒCƒ‹–¼Žw’肵‚½‰æ‘œ‚ÌꇂÍA¶¬‚³‚ꂽPDF‚ɉ摜“à—e‚»‚Ì‚à‚Ì‚ªƒf[ƒ^‚Æ‚µ‚Ä–„‚ßž‚Ü‚ê‚é‚Ì‚ÅAŒ³‚̉摜ƒtƒ@ƒCƒ‹‚ðPDFƒtƒ@ƒCƒ‹‚ƈê‚É”z•z‚µ‚½‚è‚·‚é•K—v‚͂Ȃ¢B ‰æ‘œƒIƒuƒWƒFƒNƒg‚ɂ͑¼‚Ì•\ަ‰Â”\‚ȃIƒuƒWƒFƒNƒg‚ƈá‚Á‚ăXƒ^ƒCƒ‹‚ÌŽw’è‚͂Ȃ¢BƒuƒƒbƒN‚Ɋ܂߂éÛ‚Épostnobreak‚ðŽw’肵‚½‚¢‚Æ‚¢‚¤‚悤‚ȂƂ«‚ÍA}Œ`ƒIƒuƒWƒFƒNƒg‚Ì’†‚ɉ摜ƒIƒuƒWƒFƒNƒg‚ðŠÜ‚ß‚ÄA‚»‚Ì}Œ`ƒIƒuƒWƒFƒNƒg‚ɃXƒ^ƒCƒ‹‚ðŽw’è‚·‚éB =head2 }Œ`ƒIƒuƒWƒFƒNƒg‚Ìì¬ }Œ`ƒIƒuƒWƒFƒNƒg‚ÍShapeƒTƒuƒ‹[ƒ`ƒ“‚Å쬂·‚éB $shapeobj = Shape($shapestyle); ‚±‚±‚Å$shapestyle‚Í}Œ`ƒXƒ^ƒCƒ‹ƒIƒuƒWƒFƒNƒgB$shapestyle‚ÍÈ—ª‚Å‚«‚éB‚±‚ꂾ‚¯‚ł͉½‚à’†–¡‚̂Ȃ¢}Œ`ƒIƒuƒWƒFƒNƒg‚ªì‚ç‚ê‚邾‚¯‚Å‚ ‚éB‚»‚ÌŒãAŽŸ‚̃ƒ\ƒbƒh‚ðŽg‚Á‚Ä}Œ`‚ð‰Á‚¦‚Ä‚¢‚­B =over 4 =item ’¼üilineƒƒ\ƒbƒhj $shapeobj->line($x, $y, $w, $h, $style); ($x,$y)‚©‚ç($x+$w,$y+$h)‚Ö’¼ü‚ªˆø‚©‚ê‚éB$style‚Í}Œ`ƒXƒ^ƒCƒ‹ƒIƒuƒWƒFƒNƒg‚ÅAÈ—ª‰Â”\B =item ‹éŒ`iboxƒƒ\ƒbƒhj $shapeobj->box($x, $y, $w, $h, $spec, $style); ($x,$y)‚Æ($x+$w,$y+$h)‚ð‘Ίp‚Æ‚·‚é‹éŒ`‚ª•`‚©‚ê‚éB$style‚Í}Œ`ƒXƒ^ƒCƒ‹ƒIƒuƒWƒFƒNƒg‚ÅAÈ—ª‰Â”\B$spec‚ÍŽŸ‚Ì•`‰æŽw’èB f c “h‚è’ׂµ‚Ì‚Ý s c ˜gü‚Ì‚Ý sf c “h‚è’ׂµ{˜gü n c •`‰æ‚µ‚È‚¢ ¦ã‹L‚Ìs‚Ì‘ã‚í‚è‚ÉAli¶•ÓjAri‰E•ÓjAtiã•ÓjAbi‰º•ÓjA‚Ì‘g‚݇‚킹‚à‰Â ¦ŽŸ‚̓IƒvƒVƒ‡ƒ“ rX c iX‚Í”’ljŠp‚𔼌aX‚ÅŠÛ‚­‚·‚é box()‚ɑ΂·‚é$style‚Å‚ÍA’Êí‚Ì}Œ`ƒXƒ^ƒCƒ‹‚ɉÁ‚¦‚ÄŽŸ‚̃Xƒ^ƒCƒ‹‚ªŽg‚¦‚éBiL<"ƒnƒCƒp[ƒŠƒ“ƒN">‚ðŽQÆj link => ƒŠƒ“ƒNæi•¶‘“à‚ÌƒŠƒ“ƒNæ–¼‚Ü‚½‚ÍAURI:‚ð•t‚¯‚½URI–¼j =item ‰~icircleƒƒ\ƒbƒhj $shapeobj->circle($x, $y, $r, $spec, $arcarea, $style); ($x,$y)‚ª’†SA$r‚ª”¼Œa‚̉~‚ª•`‚©‚ê‚éB$arcarea‚ÍŽl”¼‰~Žw’èi1:‰EãA2:¶ãA3:¶‰ºA4:‰E‰ºj‚ÅÈ—ª‚·‚ê‚ΑS‰~B$style‚Í}Œ`ƒXƒ^ƒCƒ‹ƒIƒuƒWƒFƒNƒg‚ÅAÈ—ª‰Â”\B$spec‚ÍŽŸ‚Ì•`‰æŽw’èB f c “h‚è’ׂµ‚Ì‚Ý s c ˜gü‚Ì‚Ý sf c “h‚è’ׂµ{˜gü =item ‘ȉ~iellipseƒƒ\ƒbƒhj $shapeobj->ellipse($x, $y, $xr, $yr, $spec, $arcarea, $style); $xr‚ª‰¡”¼ŒaA$yr‚ªc”¼Œa‚Å‚ ‚邱‚Ƃ𜂯‚Ή~‚Æ“¯‚¶B =item ‘½ŠpŒ`ipolygonƒƒ\ƒbƒhj $shapeobj->polygon([@coords], $spec, $style); @coords‚Í’¸“_‚ÌÀ•W‚ÌX‚ÆY‚Ì‘g‚ð‡‚É•À‚ׂ½ƒŠƒXƒgB$style‚Í}Œ`ƒXƒ^ƒCƒ‹ƒIƒuƒWƒFƒNƒg‚ÅAÈ—ª‰Â”\B$spec‚ÍŽŸ‚Ì•`‰æŽw’èB f c “h‚è’ׂµ‚Ì‚Ý s c ˜gü‚Ì‚Ý sf c “h‚è’ׂµ{˜gü =item ‰~ŒÊiarcƒƒ\ƒbƒhj $shapeobj->arc($x, $y, $r, $start, $end, $spec, $style); ($x,$y)‚ª’†SA$r‚ª”¼ŒaAŠJŽnŠp$startAI—¹Šp$end‚̉~ŒÊ‚Ü‚½‚͉~ŒÊ‚Æ”¼Œa‚ň͂܂ꂽ—̈悪•`‚©‚ê‚éBŠJŽnŠpAI—¹Šp‚̓‰ƒWƒAƒ“B$style‚Í}Œ`ƒXƒ^ƒCƒ‹ƒIƒuƒWƒFƒNƒg‚ÅAÈ—ª‰Â”\B$spec‚ÍŽŸ‚Ì•`‰æŽw’èB$spec‚ªa‚ÌŽž‚͉~ŒÊ‚Ì‚ÝA‚»‚Ì‘¼‚Ìꇂ͉~ŒÊ‚Æ”¼Œa‚ň͂܂ꂽ—̈悪•`‰æ‚³‚ê‚éB a c ‰~ŒÊ‚Ì‚Ý f c “h‚è’ׂµ‚Ì‚Ý s c ˜gü‚Ì‚Ý sf c “h‚è’ׂµ{˜gü =item ƒIƒuƒWƒFƒNƒgiobjƒƒ\ƒbƒhj $shapeobj->obj($obj, @showargs); }Œ`’†‚É•\ަ‰Â”\‚ȃIƒuƒWƒFƒNƒg$obj‚ðA$obj->show($page, @showargs)‚É‚æ‚Á‚Ä”z’u‚·‚éB =back ˆÈã‚̃ƒ\ƒbƒh‚݂͂ȃIƒuƒWƒFƒNƒgŽ©g‚ð•Ô‚·‚Ì‚ÅA $shapeobj = Shape->line(c)->box(c)->obj(c); ‚̂悤‚É‹Lq‚·‚邱‚Æ‚à‰Â”\B ˆÈã‚̃ƒ\ƒbƒh‚Å•`‰æ‚·‚éꇂÍAŒ‹‰Ê‚Æ‚µ‚Ä‚»‚Ì}Œ`ƒIƒuƒWƒFƒNƒg‚ªã‰º¶‰E‚ɂǂꂾ‚¯‚͈̔͂ðè‚߂邩‚Æ‚¢‚¤‘S‘̂Ƃµ‚Ä‚Ì}Œ`‚̑傫‚³‚ª“à•”“I‚ÉŠÇ—‚³‚êA•‚Æ‚‚³‚ðŽ‚Á‚½•\ަ‰Â”\ƒIƒuƒWƒFƒNƒg‚Æ‚µ‚Ĉµ‚¤‚±‚Æ‚ª‚Å‚«‚éB ‚±‚ê‚çˆÈŠO‚̃vƒŠƒ~ƒeƒBƒu‚È•`‰æƒƒ\ƒbƒh‚à‚ ‚éiPDFJ::Shape‚̃ƒ\ƒbƒhˆê——‚ðŽQÆj‚ªA‚»‚ê‚ç‚̃ƒ\ƒbƒh‚ðŽg‚Á‚½ê‡‚Í}Œ`ƒIƒuƒWƒFƒNƒg‚̑傫‚³‚ÌŠÇ—‚Í‚¨‚±‚È‚í‚ê‚È‚¢‚±‚ƂɒˆÓ‚ª•K—vB }Œ`ƒXƒ^ƒCƒ‹ƒIƒuƒWƒFƒNƒg‚ÍASStyleƒTƒuƒ‹[ƒ`ƒ“‚Å쬂·‚éB $shapestyle = SStyle(%args); ˆø”‚ɂ̓nƒbƒVƒ…ƒŠƒXƒg‚ÌŒ`‚ÅŽŸ‚Ì‚à‚Ì‚ð—^‚¦‚éB fillcolor => “h‚è’ׂµFiFƒIƒuƒWƒFƒNƒgj strokecolor => üFiFƒIƒuƒWƒFƒNƒgj linewidth => ü•iƒ|ƒCƒ“ƒgj linedash => [$dash, $gap, $phase] ‚Ü‚½‚Í "$dash, $gap, $phase" preskip => ‘O‚ÌŠÔŠuiƒ|ƒCƒ“ƒgj postskip => Œã‚ÌŠÔŠuiƒ|ƒCƒ“ƒgj postnobreak => ^‚¾‚ƃuƒƒbƒN‚Ìbreak‚Å‚»‚ÌŒã‚ë‚Å•ªŠ„‚³‚ê‚È‚¢ float => ƒuƒƒbƒN‚Ìbreak‚ňʒu‚ðŽ©“®ˆÚ“®iuƒuƒƒbƒNƒIƒuƒWƒFƒNƒg‚Ì•ªŠ„vŽQÆj linedash‚ÌŽw’è‚ÅA$dash‚Í”jü’·A$gap‚ÍŒ„ŠÔ’·A$phase‚ÍŠJŽnˆÊ’uB$phase‚ÍÈ—ª‰Â”\B preskipApostskipApostnobreakAfloat‚ÍAƒuƒƒbƒN‚Ì’†‚É}Œ`ƒIƒuƒWƒFƒNƒg‚ð’u‚­‚Æ‚«‚ɈӖ¡‚ðŽ‚ÂB box()‚ɑ΂·‚é$style‚Å‚ÍAã‹L‚Ì}Œ`ƒXƒ^ƒCƒ‹‚ɉÁ‚¦‚ÄŽŸ‚̃Xƒ^ƒCƒ‹‚ªŽg‚¦‚éB link => ƒŠƒ“ƒNæi•¶‘“à‚ÌƒŠƒ“ƒNæ–¼‚Ü‚½‚ÍAURI:‚ð•t‚¯‚½URI–¼j =head2 ’ljÁ‚Ì}Œ`ƒIƒuƒWƒFƒNƒgƒƒ\ƒbƒh use PDFJ::Shape; ‚·‚邯AŽŸ‚̒ljÁ‚Ì}Œ`•`‰æƒƒ\ƒbƒh‚ªPDFJ::Shape‚ɒljÁ‚³‚ê‚éB‚±‚ê‚ç‚̃ƒ\ƒbƒh‚Í‚¢‚¸‚ê‚àƒIƒuƒWƒFƒNƒgŽ©g‚ð•Ô‚·B‚Ü‚½A•`‰æ”͈͂̊Ǘ‚ª‚¨‚±‚È‚í‚ê‚éB =over 4 =item –îˆóiarrowƒƒ\ƒbƒhj $shapeobj->arrow($x, $y, $w, $h, $headsize, $headangle, $style); $headsize‚Æ$headangleˆÈŠO‚̈ø”‚Íline‚Æ“¯‚¶B’¼ü‚ÌI’[‚ÉA’·‚³‚ª$headsizeAæ’[Šp“x‚Ì”¼•ª‚ª$headangleiƒ‰ƒWƒAƒ“j‚ÌŽOŠpŒ`‚ÌèV‚ª•t‚¯‚ç‚ê‚éB =item ”gЇŒÊibraceƒƒ\ƒbƒhj $shapeobj->brace($x, $y, $w, $h, $style); ˆø”‚̈Ӗ¡‚Í‹éŒ`‚Æ“¯‚¶B‚»‚Ì‹éŒ`‚Ì’†‚É”[‚Ü‚é”gЇŒÊ‚ð•`‰æ‚·‚éB$w‚ª³‚È‚çŠJ‚«Š‡ŒÊA•‰‚Ȃ畂¶Š‡ŒÊB•¶Žš‚Ì{}‚ł͊Ԃɇ‚í‚È‚¢‘å‚«‚È”gЇŒÊ‚ª•K—v‚ÈꇂɎg—p‚·‚éB =item ŠpЇŒÊibracketƒƒ\ƒbƒhj $shapeobj->bracket($x, $y, $w, $h, $style); ˆø”‚̈Ӗ¡‚Í‹éŒ`‚Æ“¯‚¶B‚»‚Ì‹éŒ`‚Ì’†‚É”[‚Ü‚éŠpЇŒÊ‚ð•`‰æ‚·‚éB$w‚ª³‚È‚çŠJ‚«Š‡ŒÊA•‰‚Ȃ畂¶Š‡ŒÊB•¶Žš‚Ì[]‚ł͊Ԃɇ‚í‚È‚¢‘å‚«‚ÈŠpЇŒÊ‚ª•K—v‚ÈꇂɎg—p‚·‚éB =item ŠÛЇŒÊiparenƒƒ\ƒbƒhj $shapeobj->paren($x, $y, $w, $h, $style); ˆø”‚̈Ӗ¡‚Í‹éŒ`‚Æ“¯‚¶B‚»‚Ì‹éŒ`‚Ì’†‚É”[‚Ü‚éŠÛЇŒÊ‚ð•`‰æ‚·‚éB$w‚ª³‚È‚çŠJ‚«Š‡ŒÊA•‰‚Ȃ畂¶Š‡ŒÊB•¶Žš‚Ì()‚ł͊Ԃɇ‚í‚È‚¢‘å‚«‚ÈŠpЇŒÊ‚ª•K—v‚ÈꇂɎg—p‚·‚éB =back =head2 FƒIƒuƒWƒFƒNƒg‚Ìì¬ FƒIƒuƒWƒFƒNƒg‚ÍAColorƒTƒuƒ‹[ƒ`ƒ“‚Å쬂·‚éB $colorobj = Color($r, $g, $b); $colorobj = Color('#RRGGBB'); $colorobj = Color($g); ŽOˆø”‚Ìê‡A$r‚ÍÔA$g‚Í—ÎA$b‚Í‚̂»‚ꂼ‚ê‚ÌŠ„‡i0‚©‚ç1‚܂ł͈̔͂̔’ljB ˆêˆø”‚ÅA#‚ÅŽn‚Ü‚é16i6Œ…‚Ì•¶Žš—ñ‚Ìê‡A“ñŒ…‚¸‚ÂÔA—ÎA‚̊„‡i00‚©‚çff‚Ü‚Åj‚Ƃ݂Ȃ³‚ê‚éB ˆêˆø”‚ÅA”’l‚ÌꇂÍAƒOƒŒ[‚ÌŠ„‡i0‚©‚ç1‚܂ł͈̔͂̔’ljB0‚ª•A1‚ª”’B =head2 •\ަ‰Â”\ƒIƒuƒWƒFƒNƒg‚̃y[ƒW‚Ö‚Ì”z’u •\ަ‰Â”\‚ȃIƒuƒWƒFƒNƒg‚ðƒy[ƒWã‚É”z’u‚·‚é‚É‚ÍAshowƒƒ\ƒbƒh‚ð—p‚¢‚éB $obj->show($page, $x, $y, $align, $transtype, @transargs); ‚±‚±‚ÅA$page‚̓y[ƒWƒIƒuƒWƒFƒNƒgA$xA$y‚Í•\ަˆÊ’uA$align‚Í”z’uA$transtype‚͕ό`‚ÌŽí—ÞA@transargs‚͕ό`‚̃pƒ‰ƒ[ƒ^‚Å‚ ‚éB$alignˆÈ~‚̈ø”‚ÍÈ—ª‚Å‚«‚éB •\ަˆÊ’u‚ÌÀ•W‚ÍAƒy[ƒW‚̶‰º‹÷‚ªŒ´“_(0,0)‚ƂȂèAXÀ•W‚͉E‚ÖAYÀ•W‚Íã‚ÖŒü‚©‚Á‚Ä‘‰Á‚·‚éB’PˆÊ‚̓|ƒCƒ“ƒg‚Å‚ ‚éB ”z’u$align‚ÍA($x,$y)‚ÅŽw’肵‚½•\ަˆÊ’u‚ɑ΂µ‚ÄAƒIƒuƒWƒFƒNƒg‚ð‚ǂ̂悤‚É”z’u‚·‚é‚©‚ðŽw’è‚·‚é‚à‚Ì‚ÅAŽŸ‚̉¡ˆÊ’u‚ÆcˆÊ’u‚ð‘g‚݇‚킹‚ÄŽw’è‚·‚éB ‰¡ˆÊ’u l c ƒIƒuƒWƒFƒNƒg‚̶’[‚ð$x‚É‚ ‚킹‚é c c ƒIƒuƒWƒFƒNƒg‚Ì’†‰›‚ð$x‚É‚ ‚킹‚é r c ƒIƒuƒWƒFƒNƒg‚̉E’[‚ð$x‚É‚ ‚킹‚é cˆÊ’u t c ƒIƒuƒWƒFƒNƒg‚Ìã’[‚ð$y‚É‚ ‚킹‚é m c ƒIƒuƒWƒFƒNƒg‚Ì’†‰›‚ð$y‚É‚ ‚킹‚é b c ƒIƒuƒWƒFƒNƒg‚̉º’[‚ð$y‚É‚ ‚킹‚é ”z’u$align‚ÌŽw’è‚ðÈ—ª‚·‚邯A‚»‚̃IƒuƒWƒFƒNƒgŒÅ—L‚ÌŒ´“_‚ð($x,$y)‚É‚ ‚킹‚éBŠeƒIƒuƒWƒFƒNƒg‚̌ŗL‚ÌŒ´“_‚ÍŽŸ‚̂Ƃ¨‚èB ‰¡‘‚«ƒeƒLƒXƒg c 擪•¶Žš‚̶’[‚ÌA‰º’[‚©‚ç‚‚³‚Ì0.125”{‚¾‚¯ã‚̈ʒu c‘‚«ƒeƒLƒXƒg c 擪•¶Žš‚Ìã’[‚ÌA¶‰E’†‰›‚̈ʒu ’i—Ž c 擪sƒeƒLƒXƒg‚̌ŗL‚ÌŒ´“_ ƒuƒƒbƒN c ¶ã‹÷ ‰æ‘œ c ¶‰º‹÷ }Œ` c •`‰æ–½—߂̌´“_‚ª‚»‚̂܂܌´“_‚ƂȂé showƒƒ\ƒbƒh‚ÉA$transtypeˆÈ~‚̈ø”‚ð—^‚¦‚邯A•\ަ‚Ìۂɕό`‚·‚邱‚Æ‚ª‚Å‚«‚éB•ÏŒ`‚ÌŽí—Þ$transtype‚Æ‚»‚̃pƒ‰ƒ[ƒ^@transargs‚ɂ͎Ÿ‚Ì‚¢‚¸‚ê‚©‚ðŽw’è‚·‚éB 'magnify', $mx, $my c ‰¡•ûŒü‚É$mx”{Ac•ûŒü‚É$my”{AŠg‘åEk¬‚·‚é 'rotate', $rad c ”½ŽžŒv‰ñ‚è‚É$radƒ‰ƒWƒAƒ“‚¾‚¯‰ñ“]‚·‚é 'distort', $xtan, $ytan c (1,0)‚ð(1,$xtan)‚ÖA(0,1)‚ð($ytan,1)‚ÖˆÚ‚·‚悤‚ÉA‰¡Ž²Ac޲‚ð‚»‚ê‚¼‚êŒX‚¯‚é Še•ÏŒ`‚ÍAshowƒƒ\ƒbƒh‚Ì$x‚Æ$y‚̈ø”‚ÅŒˆ‚Ü‚éˆÊ’u‚ðŒ´“_‚Æ‚µ‚Ä‚¨‚±‚È‚í‚ê‚éB =head2 ƒy[ƒW‚̃ŒƒCƒ„ showƒƒ\ƒbƒh‚Å•\ަ‰Â”\ƒIƒuƒWƒFƒNƒg‚ðƒy[ƒW‚É”z’u‚µ‚Ä‚¢‚­‚ÆAŒã‚©‚ç”z’u‚µ‚½‚à‚Ì‚ªŽè‘O‚É”z’u‚³‚ê‚ÄA‘O‚É”z’u‚³‚ꂽ‚à‚Ì‚Éd‚È‚Á‚Ä‚¢‚­B ‚±‚Ìd‚È‚è‚̇˜‚ð§Œä‚µ‚½‚¢ê‡‚Ì‚½‚ß‚ÉAƒy[ƒWƒIƒuƒWƒFƒNƒg‚Élayerƒƒ\ƒbƒh‚ª—pˆÓ‚³‚ê‚Ä‚¢‚éB $pageobj->layer($layernum); $layernum‚̓ŒƒCƒ„”Ô†‚ÅA0ˆÈã‚Ì®”’lBlayerƒƒ\ƒbƒh‚ðŽÀs‚·‚邯A‚»‚êˆÈ~‚Ì•`‰æ‚ÍŽw’肵‚½ƒŒƒCƒ„”Ô†‚̃ŒƒCƒ„‚ɑ΂µ‚Ä‚¨‚±‚È‚í‚ê‚éB ƒy[ƒW‚Ì“à—e‚ª•\ަ‚³‚ê‚邯‚«‚É‚ÍAƒŒƒCƒ„”Ô†‚̇”Ô‚É”z’u‚³‚ê‚éB =head2 ƒXƒ^ƒCƒ‹‚̃Rƒs[ ’¼Ú“ü‚êŽq‚ɂȂÁ‚½ƒeƒLƒXƒgƒIƒuƒWƒFƒNƒg‚̃eƒLƒXƒgƒXƒ^ƒCƒ‹‚ÉŠÖ‚µ‚Ä‚ÍAeŽqŠÖŒW‚É‚æ‚é“à—e‚ÌŒp³‚ª‚¨‚±‚È‚í‚ê‚é‚Ì‚ÅA•”•ªƒXƒ^ƒCƒ‹‚ÌŽw’肪‚Å‚«‚éB‚»‚êˆÈŠO‚ÌꇂɃXƒ^ƒCƒ‹‚ÌŽ©“®“I‚ÈŒp³‚ª‚¨‚±‚È‚í‚ê‚邱‚Ƃ͂Ȃ¢B Šù‘¶‚̃Xƒ^ƒCƒ‹‚ðŒ³‚É‚µ‚Ä‘®«‚ð•ÏX‚µ‚½‚è’ljÁ‚µ‚½‚肵‚½ƒXƒ^ƒCƒ‹‚ð쬂µ‚½‚¢ê‡Acloneƒƒ\ƒbƒh‚ð—p‚¢‚éB‚±‚̃ƒ\ƒbƒh‚̓eƒLƒXƒgƒXƒ^ƒCƒ‹A’i—ŽƒXƒ^ƒCƒ‹AƒuƒƒbƒNƒXƒ^ƒCƒ‹A}Œ`ƒXƒ^ƒCƒ‹‚Ì‚·‚ׂĂɂ‚¢‚ÄŽg‚¦‚éB $newstyle = $originalstyle->clone(%newargs); %newargs‚ðŽw’肵‚È‚¯‚ê‚Î’P‚ɃRƒs[‚ªì‚ç‚ê‚éB%newargs‚ÅŽw’肵‚½‘®«‚ÍŒ³‚Ì‘®«‚ðã‘‚«‚·‚éiŒ³‚Ì‘®«‚ª‚È‚¯‚ê‚ΒljÁ‚³‚ê‚éjB =head2 ƒXƒ^ƒCƒ‹Žw’è‚Ì‚³‚Ü‚´‚܂ȕû–@ ŠeŽí‚̃Xƒ^ƒCƒ‹ƒIƒuƒWƒFƒNƒg‚ð쬂µ‚½‚èAclone()‚ŃRƒs[‚µ‚½‚è‚·‚邯‚«‚ÉA‚»‚̈ø”‚̓nƒbƒVƒ…ƒŠƒXƒg‚Å—^‚¦‚邪AƒnƒbƒVƒ…ŽQÆ‚âcssƒ‰ƒCƒN‚È•¶Žš—ñ‚Å—^‚¦‚邱‚Æ‚à‚Å‚«‚éBŽŸ‚Í“¯“™‚Å‚ ‚éB PStyle(size => 200, align => 'w', linefeed => '150%') PStyle({size => 200, align => 'w', linefeed => '150%'}) PStyle('size:200; align:w; linefeed:150%') •¶Žš—ñ‚Å—^‚¦‚邯‚«‚ÍAu‘®«–¼:‘®«’lv‚ðu;v‚Å‹æØ‚Á‚Ä•À‚ׂĎw’è‚·‚éB‚½‚¾‚µAƒnƒbƒVƒ…ŽQÆ‚â•¶Žš—ñ‚ÅŽw’è‚·‚邯‚«‚͈ø”‚Í‚»‚̈ê‚‚¾‚¯‚łȂ¯‚ê‚΂Ȃç‚È‚¢B ‘®«’l‚Æ‚µ‚ăIƒuƒWƒFƒNƒg‚ð—^‚¦‚邯‚«‚Í•¶Žš—ñ‚É‚æ‚é•û–@‚ÍŽæ‚ê‚È‚¢‚ªA‘®«’l‚àƒXƒ^ƒCƒ‹ƒIƒuƒWƒFƒNƒg‚Å‚ ‚鎞‚É‚ÍAŽŸ‚̂悤‚É {} ‚ÅŽw’肪‰Â”\‚Å‚ ‚éB TStyle('withline:1; withlinestyle:{linewidth:0.5; linedash:2,2; strokecolor:#ff0000}') ˆø”‚ɃnƒbƒVƒ…ƒŠƒXƒg‚ð—^‚¦‚邯‚«‚É‚àA‘®«’l‚Æ‚µ‚ăXƒ^ƒCƒ‹ƒIƒuƒWƒFƒNƒg‚ðŽæ‚é‘®«i‘®«–¼‚ªstyle‚ÅI‚í‚éj‚âAColorƒIƒuƒWƒFƒNƒg‚ðŽæ‚é‘®«i‘®«–¼‚ªcolor‚ÅI‚í‚éj‚ɂ‚¢‚Ä‚ÍA‘®«’l‚ðƒIƒuƒWƒFƒNƒg‚łȂ­ƒnƒbƒVƒ…ŽQÆ‚â•¶Žš—ñ‚Å—^‚¦‚邱‚Æ‚ª‚Å‚«‚éB TStyle(withline => 1, withlinestyle => {linewidth => 0.5, linedash => '2,2', strokecolor => '#ff0000'}) =head2 PDF•¶‘‚Ìo—Í ì¬‚µ‚½PDF•¶‘‚ðƒtƒ@ƒCƒ‹‚Éo—Í‚·‚é‚É‚ÍA•¶‘ƒIƒuƒWƒFƒNƒg‚Ìprintƒƒ\ƒbƒh‚ð—p‚¢‚éB $docobj->print($filename); ƒtƒ@ƒCƒ‹–¼$filename‚ÌŠg’£Žq‚ÍA’Êí‚Í.pdf‚Æ‚·‚éB ƒtƒ@ƒCƒ‹–¼‚Æ‚µ‚Ä '-' ‚ðŽw’è‚·‚邯•W€o—Í‚Éo—Í‚³‚ê‚éB =head2 •¶‘î•ñ‚̒ljÁ PDF‚ɂ͕¶‘‚̃^ƒCƒgƒ‹A쬎ÒAƒL[ƒ[ƒh‚Ȃǂ̕¶‘î•ñ‚ð“ü‚ê‚邱‚Æ‚ª‚Å‚«‚éB‚±‚ê‚ð‚¨‚±‚È‚¤‚É‚ÍAŽŸ‚̂悤‚Éadd_info()ƒƒ\ƒbƒh‚ð—p‚¢‚éB $docobj->add_info(Title => 'ƒ^ƒCƒgƒ‹', Author => '쬎Ò'); Žw’è‚Å‚«‚éƒL[‚ÍŽŸ‚Ì‚à‚Ì‚ª‚ ‚éB Title => •¶‘‚̃^ƒCƒgƒ‹ Author => •¶‘‚Ì쬎Җ¼ Subject => •¶‘‚ÌŽå‘è Keywords => •¶‘‚ÉŠÖ˜A‚·‚éƒL[ƒ[ƒh Creator => •¶‘‚ð쬂µ‚½ƒAƒvƒŠƒP[ƒVƒ‡ƒ“–¼ ‚È‚¨AProducerƒL[‚É‚ÍuPDFJ ƒo[ƒWƒ‡ƒ“v‚ªACreationDateƒL[‚É‚Í쬓úŽži•W€Žžj‚ªŽ©“®“I‚ɃZƒbƒg‚³‚ê‚éB =head2 ƒAƒEƒgƒ‰ƒCƒ“ PDF‚ɂ̓AƒEƒgƒ‰ƒCƒ“‚Æ‚¢‚¤–ÚŽŸ‹@”\‚ª‚ ‚éi‚µ‚¨‚è‚Æ‚àŒ¾‚¤jBƒAƒEƒgƒ‰ƒCƒ“‚Ì€–Ú‚ðƒ}ƒEƒX‚ŃNƒŠƒbƒN‚·‚邯‚»‚Ì€–Ú‚ÅŽw’肳‚ꂽˆÊ’u‚ª•\ަ‚³‚ê‚éBƒAƒEƒgƒ‰ƒCƒ“‚ÍŠK‘w“I‚É\¬‚³‚êAÍ‚â߂Ȃǂ̌©o‚µ‚ðƒAƒEƒgƒ‰ƒCƒ“‚ɑΉž‚³‚¹‚邱‚Æ‚ª‘½‚¢B PDFJ‚Å•¶‘‚ɃAƒEƒgƒ‰ƒCƒ“‚ð•t‰Á‚·‚é‚É‚ÍAƒeƒLƒXƒgƒIƒuƒWƒFƒNƒg‚ð쬂·‚éÛ‚ÉA‘ÎÛ‚Ì•¶Žš—ñ‚âƒIƒuƒWƒFƒNƒg‚Ì‘O‚ɃAƒEƒgƒ‰ƒCƒ“ŽwަƒIƒuƒWƒFƒNƒg‚ð’u‚­BƒAƒEƒgƒ‰ƒCƒ“ŽwަƒIƒuƒWƒFƒNƒg‚Í Outline() ƒTƒuƒ‹[ƒ`ƒ“‚Å쬂·‚éB—Ⴆ‚ÎAu‚Í‚¶‚ß‚Év‚Æ‚¢‚¤Œ©o‚µ‚ðƒAƒEƒgƒ‰ƒCƒ“‚̃gƒbƒvƒŒƒxƒ‹‚ɉÁ‚¦‚½‚¢ê‡A‚‚¬‚̂悤‚É‚·‚éB Text(Outline('‚Í‚¶‚ß‚É'), '‚Í‚¶‚ß‚É', $midasi_style) ‚±‚̃eƒLƒXƒgƒIƒuƒWƒFƒNƒg‚ªƒy[ƒW‚É”z’u‚³‚ê‚邯A•¶‘‚̃AƒEƒgƒ‰ƒCƒ“‚Éu‚Í‚¶‚ß‚Év‚Æ‚¢‚¤€–Ú‚ªì‚ç‚ê‚Ä‚±‚Ìu‚Í‚¶‚ß‚Év‚Æ‚¢‚¤ƒeƒLƒXƒg‚̶ã‚̈ʒu‚ªŽw’肳‚ê‚éB‚±‚Ì—á‚ł̓AƒEƒgƒ‰ƒCƒ“€–ڂƃeƒLƒXƒg‚Ì•¶Žš—ñ‚𓯂¶‚É‚µ‚Ä‚¢‚邪AˆÙ‚È‚é•¶Žš—ñ‚ðŽw’肵‚Ä‚à‚æ‚¢B ‚PƒŒƒxƒ‹‰º‚Ìu–{‘‚Ì“à—ev‚Æ‚¢‚¤Œ©o‚µ‚ðƒAƒEƒgƒ‰ƒCƒ“‚ɉÁ‚¦‚½‚¢ê‡A‚‚¬‚̂悤‚É‚·‚éB Text(Outline('–{‘‚Ì“à—e', 1), '–{‘‚Ì“à—e', $midasi_style) Outline() ‚Ì‚Q”Ԗڂ̈ø”‚É‚ÍAƒAƒEƒgƒ‰ƒCƒ“‚ÌŠK‘wƒŒƒxƒ‹‚ðŽw’è‚·‚éBƒŒƒxƒ‹ 0 ‚Íã‹L‚Ìu‚Í‚¶‚ß‚Év‚Ì—á‚̂悤‚ÉÈ—ª‚Å‚«‚éB ƒAƒEƒgƒ‰ƒCƒ“‚ÍAOutline()‚ðŠÜ‚ñ‚¾ƒeƒLƒXƒgƒIƒuƒWƒFƒNƒg‚ªƒy[ƒW‚É”z’u‚³‚ê‚邯‚«‚ɇ‚ɒljÁ‚³‚ê‚Äì‚ç‚ê‚Ä‚¢‚­B‚¢‚܂̂Ƃ±‚ëAŠù‘¶‚̃AƒEƒgƒ‰ƒCƒ“‚Ì“r’†‚É‘}“ü‚·‚éŽè’i‚Í—pˆÓ‚³‚ê‚Ä‚¢‚È‚¢BƒŒƒxƒ‹0‚Ì€–Ú‚ÌŽŸ‚ɃŒƒxƒ‹2‚Ì€–Ú‚ðì‚é‚È‚ÇAŠK‘w‚̃Mƒƒƒbƒv‚ª¶‚¶‚邯AƒMƒƒƒbƒv‚𖄂߂邽‚߂̋󕶎š—ñ‚É‚æ‚éƒAƒEƒgƒ‰ƒCƒ“€–Ú‚ªì‚ç‚ê‚éB =head2 ƒnƒCƒp[ƒŠƒ“ƒN PDF‚ɂ̓nƒCƒp[ƒŠƒ“ƒN‹@”\‚ª‚ ‚èAƒy[ƒWã‚ÌƒŠƒ“ƒNŒ³‚ÉŽw’肳‚ꂽ—̈æ‚ðƒNƒŠƒbƒN‚·‚邯A‚»‚ÌƒŠƒ“ƒN悪•\ަ‚³‚ê‚éBƒŠƒ“ƒNæ‚Æ‚µ‚Ä‚ÍA“¯‚¶•¶‘“à‚ÌêŠA•ʂ̕¶‘‚ÌêŠAURIihttp:‚ȂǂŎn‚Ü‚éƒCƒ“ƒ^[ƒlƒbƒgã‚ÌꊂÆl‚¦‚ê‚΂悢j‚ª‚ ‚邪A¡‚̂Ƃ±‚ëPDFJ‚ł͓¯‚¶•¶‘“à‚ÌꊂÆURI‚ɑΉž‚µ‚Ä‚¢‚éB “¯‚¶•¶‘“à‚Å‚ÌƒŠƒ“ƒN‚ðì‚é‚É‚ÍAƒŠƒ“ƒNæ‚̃eƒLƒXƒg‚ÉDest()ƒTƒuƒ‹[ƒ`ƒ“‚Å–¼‘O‚ðŽw’肵‚Ä쬂µ‚½PDFJ::DestƒIƒuƒWƒFƒNƒg‚ð”z’u‚·‚éB—Ⴆ‚Î Text(Dest('dest'),'ƒŠƒ“ƒNæ',TStyle(c)) ‚Æ‚·‚邯A'ƒŠƒ“ƒNæ'‚Æ‚¢‚¤ƒeƒLƒXƒg‚Ì‘O‚É'dest'‚Æ‚¢‚¤–¼‘O‚ÌƒŠƒ“ƒN悪ì‚ç‚ê‚éBDest()‚Åì‚ç‚ê‚éPDFJ::DestƒIƒuƒWƒFƒNƒgŽ©‘Ì‚ÍA•\ަ‚ɂ͌»‚ê‚È‚¢BƒŠƒ“ƒNæ‚Ì–¼‘O‚Í”CˆÓ‚Ì•¶Žš—ñ‚ªŽg‚¦‚邪AuURI:v‚ÅŽn‚Ü‚é‚à‚Ì‚ÍURI‚Ö‚ÌƒŠƒ“ƒN‚Ì‚½‚߂Ɏg‚í‚ê‚éB ƒŠƒ“ƒNŒ³‚ł͋éŒ`‚Ì}Œ`ƒIƒuƒWƒFƒNƒg‚Ì}Œ`ƒXƒ^ƒCƒ‹‚Ìlink‚ÅƒŠƒ“ƒNæ–¼‚ðŽw’è‚·‚é‚©AƒeƒLƒXƒgƒXƒ^ƒCƒ‹‚Ìwithboxstyle‚Å“¯—l‚ÉlinkŽw’è‚ð‚·‚éB—Ⴆ‚Î Shape->box(0,0,100,50,'s',SStyle(link => 'dest')) ‚Æ‚·‚邯A‰¡100ƒ|ƒCƒ“ƒgAc50ƒ|ƒCƒ“ƒg‚Ì‹éŒ`‚ªì‚ç‚ê‚ÄA‚»‚Ì“à•”‚ðƒNƒŠƒbƒN‚·‚邯–¼‘O‚ª'dest'‚ÌƒŠƒ“ƒNæ‚É”ò‚ÔBƒeƒLƒXƒg‚ÌꇂÍA Text('‚±‚±‚ðƒNƒŠƒbƒN', TStyle(withbox => 'n', withboxstyle => SStyle(link => 'dest'))) ‚̂悤‚É‚·‚ê‚΂悢B‚±‚̂悤‚Éwithbox => 'n' ‚Æ‚·‚邯‹éŒ`‚Í•`‰æ‚³‚ê‚È‚¢BƒŠƒ“ƒN‚Å‚ ‚邱‚Æ‚ðŽ¦‚·‚½‚ß‚ÉF‚ð•Ï‚¦‚邯‚©‰ºü‚ð•t‚¯‚邯‚©‚¢‚Á‚½H•v‚̓†[ƒU[‚É”C‚³‚ê‚Ä‚¢‚éBiwithbox => 'b' ‚ʼnºü‚ð•t‚¯‚邱‚Æ‚ª‚Å‚«‚éBj URIƒŠƒ“ƒN‚ÌꇂÍADest()‚É‚æ‚郊ƒ“ƒNæ‚ÌÝ’è‚Í•K—v‚È‚­AƒŠƒ“ƒNæ‚Ì–¼‘O‚Æ‚µ‚ÄAuURI:v‚É‘±‚¯‚ÄURI‚𑂯‚΂悢B—Ⴆ‚Î Text('•ăAƒhƒr', TStyle(withbox => 'n', withboxstyle => SStyle(link => 'URI:http://www.adobe.com/'))) ‚̂悤‚É‚·‚éB URI‚Í‚·‚Å‚ÉURIƒGƒ“ƒR[ƒh‚³‚ê‚Ä‚¢‚È‚¢ŒÀ‚èURIƒGƒ“ƒR[ƒh‚³‚ê‚éB =head2 ˆÃ†‰» PDF‚͈Ɖ»‚Å‚«‚éBPDF‚̃o[ƒWƒ‡ƒ“‚É‚æ‚Á‚ÄŽg—p‚Å‚«‚éˆÃ†‰»•ûŽ®‚͈̔͂ªˆá‚¤‚ªA¡‚̂Ƃ±‚ëPDFJ‚ł͂à‚Á‚Æ‚àŠî–{“I‚È40ƒrƒbƒgRC4ˆÃ†‰»‚ðƒTƒ|[ƒg‚µ‚Ä‚¢‚éB ˆÃ†‰»‚·‚é‚É‚ÍAencrypt()ƒƒ\ƒbƒh‚ð—p‚¢‚ÄAƒI[ƒi[ƒpƒXƒ[ƒhAƒ†[ƒU[ƒpƒXƒ[ƒhAƒ†[ƒU[‚Ö‚ÌŽg—p‹–‰Âƒtƒ‰ƒOA‚ðŽw’è‚·‚éB $docobj->encrypt($ownerpass, $userpass, $allow); ƒI[ƒi[ƒpƒXƒ[ƒh‚ƃ†[ƒU[ƒpƒXƒ[ƒh‚É“¯‚¶‚à‚Ì‚ðŽw’è‚·‚邯AƒI[ƒi[Œ ŒÀ‚ÅŠJ‚­‚±‚Ƃ͂ł«‚È‚­‚È‚éB ƒ†[ƒU[‚Ö‚ÌŽg—p‹–‰Âƒtƒ‰ƒO‚ÍAŽŸ‚Ì‹L†‚ð•À‚ׂ½•¶Žš—ñ‚Æ‚µ‚ÄŽw’è‚·‚éB P c •¶‘‚̈óü M c •¶‘“à—e‚Ì•ÏX C c •¶‘‚©‚ç‚̃eƒLƒXƒg‚Ɖ摜‚̃Rƒs[ N c ƒeƒLƒXƒg’Žß‚¨‚æ‚ёΘbƒtƒH[ƒ€ƒtƒB[ƒ‹ƒh‚̒ljÁA•ÏX ¦ƒeƒLƒXƒg’Žß‚¨‚æ‚ёΘbƒtƒH[ƒ€‹@”\‚Í¡‚̂Ƃ±‚ëPDFJ‚ł͖¢ƒTƒ|[ƒg =head2 PDFJ::DocƒNƒ‰ƒX‚̃ƒ\ƒbƒh PDFJ::Doc->new($version, $pagewidth, $pageheight) PDFJ::Doc->new({version => $version, pagewidth => $pagewidth, pageheight => $pageheight}) add_info($key => $value, ...) add_info({$key => $value, ...}) encrypt($ownerpass, $userpass, $allow) encrypt({ownerpass => $ownerpass, userpass => $userpass, allow => $allow}) filter($filter) filter({filter => $filter}) print($file) print({file => $file}) new_page($pagewidth, $pageheight) new_page({pagewidth => $pagewidth, pageheight => $pageheight}) get_page($pagenum) get_page({number => $pagenum}) get_lastpagenum new_font($basefont, $encoding, $abasefont, $aencoding) new_font({basefont => $basefont, encoding => $encoding, abasefont => $abasefont, aencoding => $aencoding}) italic($font1, $font2, ...) italic({base => $font1, decorated => $font2}) bold($font1, $font2, ...) bold({base => $font1, decorated => $font2}) new_image($src, $pxwidth, $pxheight, $width, $height, $padding, $colorspace) new_image({src => $src, pxwidth => $pxwidth, pxheight => $pxheight, width => $width, height => $height, padding => $padding, colorspace => $colorspace}) =head2 PDFJ::PageƒNƒ‰ƒX‚̃ƒ\ƒbƒh PDFJ::Page->new($docobj, $pagewidth, $pageheight) pagenum layer($layernum) layer({layer => $layernum}) =head2 PDFJ::AFontƒNƒ‰ƒX‚̃ƒ\ƒbƒh PDFJ::AFont->new_std($docobj, $basefont, $encoding) PDFJ::AFont->new_ttf($docobj, $ttffile, $encoding) =head2 PDFJ::CIDFontƒNƒ‰ƒX‚̃ƒ\ƒbƒh PDFJ::CIDFont->new_std($docobj, $basefont, $encoding, $afontobj) PDFJ::CIDFont->new_ttf($docobj, $ttffile, $encoding, $afontobj) =head2 PDFJ::ShowableƒNƒ‰ƒX‚̃ƒ\ƒbƒh ŽŸ‚̃ƒ\ƒbƒh‚ÍAPDFJ::TextAPDFJ::ParagraphAPDFJ::BlockAPDFJ::ImageAPDFJ::Shape‚ÌŠeƒNƒ‰ƒX‚Å‹¤’Ê‚µ‚ÄŽg‚¦‚éB show($page, $x, $y, $align, $transtype, @transargs) show({page => $page, x => $x, y => $y, align => $align, transtype => $transtype, transargs => [@transargs]}) width height =head2 PDFJ::TextƒNƒ‰ƒX‚̃ƒ\ƒbƒh PDFJ::Text->new($text, $style) PDFJ::Text->new(@texts, $style) PDFJ::Text->new([@texts], $style) PDFJ::Text->new({texts => $text, style => $style}) PDFJ::Text->new({texts => [@text], style => $style}) =head2 PDFJ::ParagraphƒNƒ‰ƒX‚̃ƒ\ƒbƒh PDFJ::Paragraph->new($text, $style) PDFJ::Paragraph->new({text => $text, style => $style}) linesnum break($size) break(@sizes) break({sizes => $size}) break({sizes => [@sizes]}) =head2 PDFJ::BlockƒNƒ‰ƒX‚̃ƒ\ƒbƒh PDFJ::Block->new($direction, $object, $style) PDFJ::Block->new($direction, @objects, $style) PDFJ::Block->new($direction, [@objects], $style) PDFJ::Block->new({direction => $direction, objects => $object, style => $style}) PDFJ::Block->new({direction => $direction, objects => [@objects], style => $style}) adjustwidth($size) adjustwidth({size => $size}) adjustheight($size) adjustheight({size => $size}) break($size) break(@sizes) break({sizes => $size}) break({sizes => [@sizes]}) =head2 PDFJ::BlockSkipƒNƒ‰ƒX‚̃ƒ\ƒbƒh PDFJ::BlockSkip->new($skip) PDFJ::BlockSkip->new({skip => $skip}) =head2 PDFJ::ImageƒNƒ‰ƒX‚̃ƒ\ƒbƒh PDFJ::Image->new($docobj, $src, $pxwidth, $pxheight, $width, $height, $padding) setsize($width, $height) setpadding($padding) =head2 PDFJ::ShapeƒNƒ‰ƒX‚̃ƒ\ƒbƒh PDFJ::Shape->new($style) PDFJ::Shape->new({style => $style}) ƒ}ƒNƒ–½—ßi•`‰æ”͈͂̊Ǘ‚ª‚¨‚±‚È‚í‚ê‚éj line($x, $y, $w, $h, $style) line({x => $x, y => $y, w => $w, h => $h, style => $style}) box($x, $y, $w, $h, $spec, $style) box({x => $x, y => $y, w => $w, h => $h, spec => $spec, style => $style}) circle($x, $y, $r, $spec, $arcarea, $style) circle({x => $x, y => $y, r => $r, spec => $spec, arcarea => $arcarea, style => $style}) ellipse($x, $y, $xr, $yr, $spec, $arcarea, $style) ellipse({x => $x, y => $y, xr => $xr, yr => $yr, spec => $spec, arcarea => $arcarea, style => $style}) polygon([@coords], $spec, $style) polygon({coords => [@coords], spec => $spec, style => $style}) arc($x, $y, $r, $start, $end, $spec, $style) arc({x => $x, y => $y, r => $r, start => $start, end => $end, spec => $spec, style => $style}) ƒIƒuƒWƒFƒNƒg”z’u–½—ßi•`‰æ”͈͂̊Ǘ‚ª‚¨‚±‚È‚í‚ê‚éj obj($obj, @showargs) obj({obj => $obj, showargs => [@showargs]}) ƒvƒŠƒ~ƒeƒBƒu–½—ß setboundary($x, $y) gstatepush gstatepop linewidth($w) linedash($dash, $gap, $phase) ctm(@array) fillcolor($color) strokecolor($color) fillgray($g) strokegray($g) fillrgb($r, $g, $b) strokergb($r, $g, $b) moveto($x, $y) lineto($x, $y) curveto($x1, $y1, $x2, $y2, $x3, $y3) rectangle($x, $y, $w, $h) closepath newpath stroke closestroke fill fill2 fillstroke =head2 PDFJ::StyleƒNƒ‰ƒX‚̃ƒ\ƒbƒh ŽŸ‚̃ƒ\ƒbƒh‚ÍPDFJ::TextStyleAPDFJ::ParagraphStyleAPDFJ::BlockStyleAPDFJ::ShapeStyle‚Ì‚·‚ׂĂŎg‚¦‚éB clone(%args) clone({%args}) clone($argstr) =head2 PDFJ::TextStyleƒNƒ‰ƒX‚̃ƒ\ƒbƒh PDFJ::TextStyle->new(%args) PDFJ::TextStyle->new({%args}) PDFJ::TextStyle->new($argstr) =head2 PDFJ::ParagraphStyleƒNƒ‰ƒX‚̃ƒ\ƒbƒh PDFJ::ParagraphStyle->new(%args) PDFJ::ParagraphStyle->new({%args}) PDFJ::ParagraphStyle->new($argstr) =head2 PDFJ::BlockStyleƒNƒ‰ƒX‚̃ƒ\ƒbƒh PDFJ::BlockStyle->new(%args) PDFJ::BlockStyle->new({%args}) PDFJ::BlockStyle->new($argstr) =head2 PDFJ::ShapeStyleƒNƒ‰ƒX‚̃ƒ\ƒbƒh PDFJ::ShapeStyle->new(%args) PDFJ::ShapeStyle->new({%args}) PDFJ::ShapeStyle->new($argstr) =head2 PDFJ::ColorƒNƒ‰ƒX‚̃ƒ\ƒbƒh PDFJ::Color->new($r, $g, $b) PDFJ::Color->new($rgb) PDFJ::Color->new($g) PDFJ::Color->new({value => $rgb}) PDFJ::Color->new({value => $g}) =head2 PDFJ::OutlineƒNƒ‰ƒX‚̃ƒ\ƒbƒh PDFJ::Outline->new($title, $level) PDFJ::Outline->new({title => $title, level => $level}) =head2 PDFJ::DestƒNƒ‰ƒX‚̃ƒ\ƒbƒh PDFJ::Dest->new($name) PDFJ::Dest->new({name => $name}) =head2 “à•”ƒNƒ‰ƒX ˆÈ‰º‚ÍA’Êí‚̓†[ƒU[‚ª’¼Úˆµ‚¤•K—v‚̂Ȃ¢APDFJ“à•”‚ÅŽg‚í‚ê‚éƒNƒ‰ƒXB =over 4 =item PDFJ::FileƒNƒ‰ƒX PDFJ::Doc‚̉º¿‚¯BPDF•¶‘PDFJ::DocƒIƒuƒWƒFƒNƒg‚ðPDFƒtƒ@ƒCƒ‹‚É‘‚«o‚·Û‚ÉAPDFƒIƒuƒWƒFƒNƒg‚Ìõˆøî•ñ‚Ȃǂ̃ƒ^ƒf[ƒ^‚ð•t‰Á‚µ‚ÄA‹K’è‚É]‚Á‚½ƒtƒ@ƒCƒ‹\‘¢‚ðì‚é–ðŠ„‚ð‚·‚éB =item PDFJ::ObjTableƒNƒ‰ƒX PDFJ::Doc‚̉º¿‚¯BPDFJ::DocƒIƒuƒWƒFƒNƒg‚Ɋ܂܂ê‚éPDFƒIƒuƒWƒFƒNƒg‚ðŠÇ—‚·‚éB =item PDFJ::TextSpecƒNƒ‰ƒX PDFJ::Text‚̉º¿‚¯‚Æ‚µ‚ÄAƒeƒLƒXƒg‘®«‚ð•ÛŽ‚·‚éB =item PDFJ::Object::* ƒNƒ‰ƒXŒQ PDF•¶‘‚ÍAdobeŽÐ‚ª‹K’肵‚½PDF‚Ì•¶–@‚ɉˆ‚Á‚Ä\¬‚³‚ê‚Ä‚¨‚èA‚»‚Ì\¬’PˆÊ‚à‚Ü‚½uƒIƒuƒWƒFƒNƒgv‚ƌĂ΂ê‚éB‚±‚ÌPDFƒŒƒxƒ‹‚̃IƒuƒWƒFƒNƒg‚ðAã‹L‚Åà–¾‚µ‚½‚悤‚ÈPDFJ‚É‚¨‚¯‚éPerlƒIƒuƒWƒFƒNƒg‚Æ‹æ•Ê‚·‚邽‚ß‚ÉAuPDFƒIƒuƒWƒFƒNƒgv‚ƌĂԂ±‚Ƃɂ·‚éBPDFJ‚ÍA’჌ƒxƒ‹‚ŃvƒŠƒ~ƒeƒBƒu‚ÈPDFƒIƒuƒWƒFƒNƒg‚ð‰B•Á‚µAƒ†[ƒU[‚ª’¼Úˆµ‚í‚È‚­‚Ă悢‚悤‚É‚µ‚Ä‚¢‚éB‚à‚µŽ©•ª‚ÅPDFƒIƒuƒWƒFƒNƒg‚ð‘€ì‚µ‚½‚¢‚Æ‚«‚ÍAPDFJ::Object::* ƒNƒ‰ƒXŒQ‚ðŽg‚¦‚΂悢B =item PDFJ::TTFƒNƒ‰ƒX TrueTypeƒtƒHƒ“ƒgƒtƒ@ƒCƒ‹(.ttf)‚Ì“à—e‚ð“ǂ݂ƂÁ‚½‚èAƒTƒuƒZƒbƒg‚ð쬂µ‚½‚è‚·‚éB =item PDFJ::TTCƒNƒ‰ƒX TrueTypeCollectionƒtƒHƒ“ƒgƒtƒ@ƒCƒ‹(.ttc)‚ð“ǂ݂ƂÁ‚ÄAŽw’肵‚½”Ô†‚̃tƒHƒ“ƒg‚ɂ‚¢‚Ä‚ÌPDFJ::TTFƒIƒuƒWƒFƒNƒg‚𓾂éB =back =head1 AUTHOR ’†“‡ –õ L L =head1 SEE ALSO uJIS X 4051i“ú–{Œê•¶‘‚Ìs‘g”Å•û–@jv(JISA1995) uPDFƒŠƒtƒ@ƒŒƒ“ƒX ‘æ‚Q”Åv(ƒAƒhƒrƒVƒXƒeƒ€ƒYA2001) PDF-Builder-3.026/examples/030_colorspecs0000644000000000000000000001425314534467462016542 0ustar rootroot#!/usr/bin/perl # display RGB colorspace 16 pages (green 0 to F) of 256 colors R x B # with red increasing to right and blue increasing to top # same, for Gamma 2.2 # display CMYK colorspace 16 pages (magenta 0 to F) of 256 colors C x Y # with cyan increasing to right and yellow increasing to top. Black = 0 in all # display Lab colorspace 16 pages (L 0 to F) of 256 colors a x b # with a increasing to right and b increasing to top # display named colors 2.5 pages, alphabetical order L to R, B to T # TBD: consider reordering to put min in upper left, max in lower right # (are there any conventions for this?). currently is LL/UR. use strict; use warnings; use PDF::Builder; use PDF::Builder::Util; use POSIX; use Math::Trig; #my $compress = 'none'; # uncompressed streams my $compress = 'flate'; # compressed streams my $cx = 315; my $cy = 400; my $cr = 15; my $cs = 32; my $ang = 30; my $pdf = PDF::Builder->new(-compress => $compress); my @doSect = (1, 1, 1, 1, 1); # which section(s) to display $pdf->mediabox(595,842); my $fnt = $pdf->corefont('Verdana-Bold'); my ($page, $gfx, $text); if ($doSect[0]) { # RGB colorspace print STDERR "RGB colorspace (16 pages) "; foreach my $z (0 .. 0xf) { # one green value per page print STDERR "."; $page = $pdf->page(); $gfx = $page->gfx(); $text = $page->text(); $text->linewidth(0); $text->render(2); $text->textlabel(300,750, $fnt, 20, 'RGB Colorspace', -color=>'#000', -hscale=>125, -center=>1); $text->strokecolor('#000'); foreach my $x (0 .. 0xf) { foreach my $y (0 .. 0xf) { my $t = sprintf('#%01X%01X%01X', $x,$z,$y); $gfx->fillcolor($t); $gfx->circle($cx+($x-8)*$cs,$cy+($y-8)*$cs, $cr); $gfx->fillstroke(); $text->textlabel($cx+($x-8)*$cs+2,$cy+($y-8)*$cs-2, $fnt,8, $t, -color=>'#000', -strokecolor=>'#FFF', -rotate=>$ang, -hscale=>85, -center=>1); } } } print STDERR "\n"; } if ($doSect[1]) { # RGB colorspace with Gamma = 2.2 print STDERR "RGB colorspace with Gamma 2.2 (16 pages) "; foreach my $z (0 .. 0xf) { # one green value per page print STDERR "."; $page = $pdf->page(); $gfx = $page->gfx(); $text = $page->text(); $text->linewidth(0); $text->render(2); $text->textlabel(300,750, $fnt, 20, 'RGB Colorspace (Gamma=2.2)', -color=>'#000', -hscale=>125, -center=>1); $text->strokecolor('#000'); foreach my $x (0 .. 0xf) { foreach my $y (0 .. 0xf) { my $t = sprintf('#%01X%01X%01X', $x,$z,$y); $gfx->fillcolor($x/0xf,$z/0xf,$y/0xf); $gfx->circle($cx+($x-8)*$cs,$cy+($y-8)*$cs, $cr); $gfx->fillstroke(); $text->textlabel($cx+($x-8)*$cs+2,$cy+($y-8)*$cs-2, $fnt,8, $t, -color=>'#000', -strokecolor=>'#FFF', -rotate=>$ang, -hscale=>85, -center=>1); } } } print STDERR "\n"; } if ($doSect[2]) { # CMYK colorspace print STDERR "CMYK colorspace (16 pages) "; foreach my $z (0 .. 0xf) { # one magenta value per page print STDERR "."; $page = $pdf->page(); $gfx = $page->gfx(); $text = $page->text(); $text->linewidth(0); $text->render(2); $text->textlabel(300,750, $fnt,20, 'CMYK Colorspace', -color=>'#000', -hscale=>125, -center=>1); $text->strokecolor('#000'); foreach my $x (0 .. 0xf) { foreach my $y (0 .. 0xf) { my $t = sprintf('%%%01X%01X%01X0', $x,$z,$y); $gfx->fillcolor($t); $gfx->circle($cx+($x-8)*$cs,$cy+($y-8)*$cs, $cr); $gfx->fillstroke(); $text->textlabel($cx+($x-8)*$cs+2,$cy+($y-8)*$cs-2, $fnt,8, $t, -color=>'#000', -strokecolor=>'#FFF', -rotate=>$ang, -hscale=>85, -center=>1); } } } print STDERR "\n"; } if ($doSect[3]) { # Lab colorspace print STDERR "L*a*b colorspace (16 pages) "; foreach my $z (0 .. 0xf) { # one L value per page print STDERR "."; $page = $pdf->page(); $gfx = $page->gfx(); $text = $page->text(); $text->linewidth(0); $text->render(2); $text->textlabel(300,750, $fnt,20, 'Lab Colorspace', -color=>'#000', -hscale=>125, -center=>1); $text->strokecolor('#000'); foreach my $x (0 .. 0xf) { foreach my $y (0 .. 0xf) { my $t=sprintf('$%01X%01X%01X',$z,$x,$y); $gfx->fillcolor($t); $gfx->circle($cx+($x-8)*$cs,$cy+($y-8)*$cs, $cr); $gfx->fillstroke(); $text->textlabel($cx+($x-8)*$cs+2,$cy+($y-8)*$cs-2, $fnt,8, $t, -color=>'#000', -strokecolor=>'#FFF', -rotate=>$ang, -hscale=>85, -center=>1); } } } print STDERR "\n"; } if ($doSect[4]) { # named colors print STDERR "named colors (RGB colorspace) "; my @cols=sort keys %PDF::Builder::Util::colors; # quick'n'dirty numeric sort of two 0..100 sections of list # after sorting, they should be contiguous stretches. will need to revisit # this code if no longer 0..max sequence foreach my $base ('gray', 'grey') { my $start = 0; my $end = -1; my ($i, $j); for ($i=0; $i 0) { # next (up to) 256 names print STDERR "."; $page = $pdf->page(); $gfx = $page->gfx(); $text = $page->text(); $text->linewidth(0); $text->render(2); $text->textlabel(300,750, $fnt,20, 'Named Colors (RGB)', -color=>'#000', -hscale=>125, -center=>1); $text->strokecolor('#000'); foreach my $x (0 .. 0xf) { last if scalar @cols == 0; foreach my $y (0 .. 0xf) { last if scalar @cols == 0; my $t = shift @cols; $gfx->fillcolor($t); $gfx->circle($cx+($x-8)*$cs,$cy+($y-8)*$cs, $cr); $gfx->fillstroke(); $text->textlabel($cx+($x-8)*$cs+2,$cy+($y-8)*$cs-2, $fnt,7, $t, -color=>'#000', -strokecolor=>'#FFF', -rotate=>$ang, -hscale=>85, -center=>1); } } } print STDERR "\n"; } $pdf->saveas("$0.pdf"); $pdf->end(); exit; __END__ PDF-Builder-3.026/examples/021_synfonts0000644000000000000000000002411014534467462016242 0ustar rootroot#!/usr/bin/perl # command line defaults to 0 (full list of core fonts). 1 or -s is for a # short list, 2 is a single TTF, and 3 is a single Type 1 use strict; use warnings; use lib '../lib'; use PDF::Builder; use PDF::Builder::Util; my $type = 0; # 0 = full list of core fonts # 1 or -s = single core font (for testing) # 2 = TTF font(s) # 3 = Type1 (PS) font(s) my $encoding = 'latin1'; # normally latin1 # TBD future: -t type -e encoding and possibly font name(s) and which variant(s) # for testing, command line number is type if (scalar @ARGV > 0) { if ($ARGV[0] eq '-s') { $type = 1; # -s is alias for 1 } elsif ($ARGV[0] > -1 && $ARGV[0] < 4) { # command line type 0 1 2 or 3 $type = $ARGV[0]; } } my @variants = (); my @varLabels = (); # show condense example push @variants, {-condense=>0.750}; push @varLabels, 'condense 0.750'; # show oblique example push @variants, {-oblique=>12}; push @varLabels, 'oblique 12'; # show bold example push @variants, {-bold=>4}; push @varLabels, 'bold 4'; # show small caps example push @variants, {-caps=>1}; push @varLabels, 'caps 1'; #my $compress = 'none'; # no stream compression my $compress = 'flate'; # compress streams my $sx = 33; my $sy = 45; my $fx = 20; my ($ci, $y, $k); my (@font_list, @short_name, @T1_metrics); # core if ($type == 0) { @font_list = qw( Times-Roman Times-Italic Times-Bold Times-BoldItalic Courier Courier-Oblique Courier-Bold Courier-BoldOblique Helvetica Helvetica-Oblique Helvetica-Bold Helvetica-BoldOblique Symbol ZapfDingbats bankgothic georgia georgiaitalic georgiabold georgiabolditalic trebuchet trebuchetitalic trebuchetbold trebuchetbolditalic verdana verdanaitalic verdanabold verdanabolditalic wingdings webdings ); } if ($type == 1) { @font_list = qw( Courier-Oblique ); } # note that for TTF and Type1, spaces in names (Windows) replaced by ~ # TTF if ($type == 2) { @font_list = qw( C:\\Windows\\Fonts\\calibri.ttf ); @short_name = qw( Calibri ); } # Type1 if ($type == 3) { # note that URWPalladioL appears to have some internal problems, resulting # in some characters appearing in the wrong slot. other fonts are OK, and there # is no obvious pattern, so for now it can't be fixed. suspect a bad font # "encoding map" resulting is mismapping by BaseFont::strByUtf to wrong # character in BaseFont::textByStr returned to BaseFont::text #C:\\Users\\Phil\\fonts\\T1fonts\\URWPalladioL-Roma.pfb @font_list = qw( C:\\Users\\Phil\\fonts\\T1fonts\\gfsneohellenic\\type1\\GFSNeohellenic-Regular.pfb C:\\Users\\Phil\\fonts\\T1fonts\\URWPalladioL-Roma.pfb ); #C:\\Program~Files~(x86)\\MiKTeX~2.9\\fonts\\type1\\urw\\avantgar\\uagd8a.pfb @T1_metrics = qw( C:\\Users\\Phil\\fonts\\T1fonts\\gfsneohellenic\\afm\\GFSNeohellenic-Regular.afm C:\\Users\\Phil\\fonts\\T1fonts\\URWPalladioL-Roma.afm ); #C:\\Program~Files~(x86)\\MiKTeX~2.9\\fonts\\type1\\urw\\avantgar\\uagd8a.pfm @short_name = qw( Neohellenic Palladio ); #Avant~Garde } my ($metrics, $sname); # outer loop, one file each for Times-Roman, Times-Italic, etc. foreach my $fn (@font_list) { $fn =~ s/~/ /g; # restore name if ($type == 3) { # Type1 also has metrics file $metrics = shift @T1_metrics; $metrics =~ s/~/ /g; # restore name } if ($type < 2) { # core fn and sname are the same $sname = $fn; } else { # TTF and Type1 have font short name $sname = shift @short_name; $sname =~ s/~/ /g; # restore name } my $pdf = PDF::Builder->new(-compress => $compress); initNameTable(); my $f1 = $pdf->corefont('Helvetica'); # for various labels print STDERR "\n$fn\n"; my $fn1; if ($type == 0 || $type == 1) { $fn1 = $pdf->corefont($fn, -encode => $encoding); } elsif ($type == 2) { $fn1 = $pdf->ttfont($fn, -encode => $encoding); } else { # type == 3 if ($metrics =~ m/\.afm/i) { $fn1 = $pdf->psfont($fn, -afmfile => $metrics, -encode => $encoding); } else { $fn1 = $pdf->psfont($fn, -pfmfile => $metrics, -encode => $encoding); } } my @planes; if ($type != 2) { @planes = ($fn1, $fn1->automap()); } else { # TrueType can't use automap. Need to get to glyphs beyond basic encoding @planes = ($fn1); } print STDERR " ".(scalar @variants)." variants of font, each up to ". (scalar @planes)." page(s)\n"; # Note that synfont() itself only returns a "standard" 255 character font. # For characters beyond that (Unicode), you need to get plane 1, 2, etc. # and run synfont() against that "font". 'fi' and 'fl' ligatures are # found on plane 1 or 2 (not plane 0 basic). It does not appear possible # to replace a ligature on plane 1+ with plane 0 ASCII letters. foreach my $varNum ( 0 .. $#variants ) { # 4 or so variants requested per font $k = $variants[$varNum]; foreach my $fnt (@planes) { # individual planes of each font, character list varies by font my $font = $pdf->synfont($fnt, %{$k}); # check if there is anything to be shown in this plane ($fnt) my $flag = 0; # no character found yet foreach my $yp (0..15) { foreach my $x (0..15) { $ci = $yp*16 + $x; # 0..255 value # always seems to be something at # ci = 32 (U+0020, space) # ci = 33 (U+E000, .notdef) if ($ci == 32 || $ci == 33) { next; } if (defined $fnt->uniByEnc($ci) && $fnt->uniByEnc($ci) > 0) { $flag = 1; # found at least one character (glyph) last; } } if ($flag) { last; } } if (!$flag) { next; } # no glyphs to show on this plane my $page = $pdf->page(); $page->mediabox(595,842); my $gfx = $page->gfx(); my $txt = $page->text(); $txt->font($font, $fx); my $txt2 = $page->text(); my $xname; $txt2->translate(50,800); $txt2->font($f1, 20); if (defined $font->fontname()) { $xname = $font->fontname(); } else { $xname = $sname; } if (defined $font->name()) { $y = $font->name(); } else { $y = '??????'; } $txt2->text("font='$xname / $y'"); $txt2->translate(50,780); $txt2->font($f1, 15); $txt2->text("variant = $varLabels[$varNum]"); $txt2->translate(300,780); $txt2->text("encoding = $encoding"); $txt2->font($f1, 5); $txt2->hscale(80); # distance below baseline (<0) to clear descenders my $u=$font->underlineposition * $fx/1000; print STDERR "."; # one . per page # draw grid of characters and information # yp character row value (increasing) foreach my $yp (0 .. 15) { $y = 15 - $yp; # y vertical (row) position T to B foreach my $x (0 .. 15) { $txt->translate(50+($sx*$x), 50+($sy*$y)); $ci = $yp*16 + $x; my $c = chr($ci); $txt->text($c); my $wx = $font->width($c) * $fx; # bound box cell around character $gfx->strokecolor('lightblue'); $gfx->move(50+($sx*$x), 50+($sy*$y)+$fx); $gfx->line(50+($sx*$x), 50+($sy*$y)+$u); $gfx->line(50+($sx*$x)+$wx, 50+($sy*$y)+$u); $gfx->line(50+($sx*$x)+$wx, 50+($sy*$y)+$fx); $gfx->close(); $gfx->stroke(); # baseline $gfx->strokecolor('gray'); $gfx->move(50+($sx*$x), 50+($sy*$y)); $gfx->line(50+($sx*$x)+$wx, 50+($sy*$y)); $gfx->stroke(); # character data $txt2->translate(50+($sx*$x)+$wx, 50+($sy*$y)-6); $txt2->text_right($ci); $txt2->translate(50+($sx*$x)+$wx, 50+($sy*$y)-11); if (defined $font->uniByEnc($ci)) { $txt2->text_right(sprintf('U+%04X',$font->uniByEnc($ci))); } else { $txt2->text_right('U+????'); } $txt2->translate(50+($sx*$x)+$wx, 50+($sy*$y)-16); $txt2->text_right($font->glyphByEnc($ci)); $txt2->translate(50+($sx*$x)+$wx, 50+($sy*$y)-21); $txt2->text_right(sprintf('wx=%i', $font->wxByEnc($ci))); } } } # end inner loop of 1 or more font pages } # end middle loop of @variants list # print some text with a weird combination of options. # only basic plane (0) $fn1 to be used. my $font = $pdf->synfont($fn1, -caps=>1, -bold=>8, -oblique=>-15, -condense=>3.5, -space=>300); my $page = $pdf->page(); $page->mediabox(595,842); my $txt = $page->text(); $txt->font($font, $fx); my $LoremIpsum=q|Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam eaque ipsa, quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt, explicabo. Nemo enim ipsam voluptatem, quia voluptas sit, aspernatur aut odit aut fugit.|; # 150% width + 300 milliems, so not much to fill up a page! $txt->transform(-translate => [50, 800]); $txt->fillcolor('black'); $txt->font($f1, 18); # Hevetica labels $txt->leading(18*1.25); my $title = "caps 1, bold 8, oblique -15, condense 1.5, space 300."; my $toprint; print STDERR "."; while ($title ne '') { ($toprint, $title) = $txt->_text_fill_line($title, 500, 0); $txt->text($toprint); $txt->nl(); } $txt->nl(); $txt->font($font, 18); while ($LoremIpsum ne '') { ($toprint, $LoremIpsum) = $txt->_text_fill_line($LoremIpsum, 500, 0); $txt->text($toprint); $txt->nl(); } $pdf->saveas("$0.$sname.pdf"); $pdf->end(); print STDERR "\n"; } # loop of typefaces Times-Roman, Times-Italic, etc. separate files exit; __END__ PDF-Builder-3.026/examples/042_links0000644000000000000000000002165214534467462015512 0ustar rootroot# Note: this is not an exhaustive list, just something to orient you. use strict; use warnings; use PDF::Builder; # program settings my $border = 1; # line width of click rectangle, 0 for none my $b_red = 0; # click rectangle border color (here medium green) my $b_green = 0.5; my $b_blue = 0; my $normal_text_color = 'black'; my $link_text_color = 'blue'; my $font_size = 20; # 20pt text my $local_movie = ""; # a local movie file such as .avi # =========================================== my $PDFname = $0; $PDFname =~ s/\..*$//; # remove any existing extension $PDFname .= '.pdf'; # add new extension my $pdf = PDF::Builder->new(-compress => 'none'); my $page = $pdf->page(); my $text = $page->text(); my $font = $pdf->corefont('Times-Roman'); $text->font($font, $font_size); $text->fillcolor($normal_text_color); my $x = 100; my $y = 700; $text->translate($x, $y); $text->text("Page 1. Go to a web page in a browser."); # ---------- go to a URL in a browser $x = 100; $y = 600; $text->translate($x, $y); $text->text("Click "); $x += $text->advancewidth("Click "); # x,y should be at LL corner of "here" (on baseline) $text->fillcolor($link_text_color); $text->text("here"); my $target_width = $text->advancewidth("here"); my $annotation = $page->annotation(); # method 'url' is still usable $annotation->uri("https://www.google.com", -rect => [$x-1, $y-5, $x+1+$target_width, $y-5+1+$font_size], # clickable area -border => [0, 0, $border], # show border -color => [$b_red, $b_green, $b_blue], # border color ); # restore color and do rest of line $text->fillcolor($normal_text_color); $text->text(" to go to Google."); # ---------- go to a specific location in a browser $x = 100; $y = 500; $text->translate($x, $y); $text->text("Go to "); $x += $text->advancewidth("Go to "); # x,y should be at LL corner of "here" (on baseline) $text->fillcolor($link_text_color); $text->text("a specific point"); $target_width = $text->advancewidth("a specific point"); $annotation = $page->annotation(); # method 'url' is still usable $annotation->uri("https://www.catskilltech.com/#Catskills", -rect => [$x-1, $y-5, $x+1+$target_width, $y-5+1+$font_size], # clickable area -border => [0, 0, $border], # show border -color => [$b_red, $b_green, $b_blue], # border color ); # restore color and do rest of line $text->fillcolor($normal_text_color); $text->text(" on a website."); # ---------- reminder to user $x = 50; $y = 300; $text->translate($x, $y); $text->text("In these examples the link text is explicitly colored blue and the"); $text->translate($x, $y-25); $text->text("link box is outlined in green. These may be changed in the code."); # ---------- go to a page within THIS document $page = $pdf->page(); # page 2 $text = $page->text(); $text->font($font, $font_size); $x = 100; $y = 700; $text->translate($x, $y); $text->text("Page 2. Go to a point in this document (on Page 1)."); $x = 100; $y = 600; $text->translate($x, $y); $text->text("Click "); $x += $text->advancewidth("Click "); # x,y should be at LL corner of "here" (on baseline) $text->fillcolor($link_text_color); $text->text("here"); $target_width = $text->advancewidth("here"); $annotation = $page->annotation(); my $tgt_page = $pdf->openpage(1); # target page 1 # method 'link' is still usable $annotation->link($tgt_page, -rect => [$x-1, $y-5, $x+1+$target_width, $y-5+1+$font_size], # clickable area -border => [0, 0, $border], # show border -color => [$b_red, $b_green, $b_blue], # border color ); # restore color and do rest of line $text->fillcolor($normal_text_color); $text->text(" to go to Page 1."); # same, except position and zoom $x = 100; $y = 400; $text->translate($x, $y); $text->text("Click "); $x += $text->advancewidth("Click "); # x,y should be at LL corner of "here" (on baseline) $text->fillcolor($link_text_color); $text->text("here"); $target_width = $text->advancewidth("here"); $annotation = $page->annotation(); $tgt_page = $pdf->openpage(1); # target page 1 # method 'link' is still usable $annotation->link($tgt_page, -rect => [$x-1, $y-5, $x+1+$target_width, $y-5+1+$font_size], # clickable area -border => [0, 0, $border], # show border -color => [$b_red, $b_green, $b_blue], # border color -xyz => [ 200,550, 1.5 ], # new position, zoom factor 150% ); # restore color and do rest of line $text->fillcolor($normal_text_color); $text->text(" to go to Page 1 positioned/zoomed."); # ---------- go to a page in ANOTHER document $page = $pdf->page(); # page 3 $text = $page->text(); $text->font($font, $font_size); $x = 100; $y = 700; $text->translate($x, $y); $text->text("Page 3. Go to a point in another PDF document (on Page 1)."); $x = 100; $y = 600; $text->translate($x, $y); $text->text("Click "); $x += $text->advancewidth("Click "); # x,y should be at LL corner of "here" (on baseline) $text->fillcolor($link_text_color); $text->text("here"); $target_width = $text->advancewidth("here"); $annotation = $page->annotation(); # methods 'pdfile' and 'pdf_file' are still usable $annotation->pdf("resources/040_annotation.pdf", 1, # page number -rect => [$x-1, $y-5, $x+1+$target_width, $y-5+1+$font_size], # clickable area -border => [0, 0, $border], # show border -color => [$b_red, $b_green, $b_blue], # border color ); # restore color and do rest of line $text->fillcolor($normal_text_color); $text->text(" to go to Page 1 of another PDF document."); # same, except position and zoom $x = 100; $y = 400; $text->translate($x, $y); $text->text("Click "); $x += $text->advancewidth("Click "); # x,y should be at LL corner of "here" (on baseline) $text->fillcolor($link_text_color); $text->text("here"); $target_width = $text->advancewidth("here"); $annotation = $page->annotation(); # methods 'pdfile' and 'pdf_file' are still usable $annotation->pdf("resources/040_annotation.pdf", 1, # page number -rect => [$x-1, $y-5, $x+1+$target_width, $y-5+1+$font_size], # clickable area -border => [0, 0, $border], # show border -color => [$b_red, $b_green, $b_blue], # border color -fitr => [0,0, 100,250], # new viewport ); # restore color and do rest of line $text->fillcolor($normal_text_color); $text->text(" to go to Page 1 of another PDF document, windowed."); # ---------- launch (default OS action) another file $page = $pdf->page(); # page 4 $text = $page->text(); $text->font($font, $font_size); $x = 100; $y = 700; $text->translate($x, $y); $text->text("Page 4. Launch (usually a \"default\" action) a file."); # on Windows, default for .txt is usually to open it in Notepad, # default for .html is usually to open it in a browser $x = 100; $y = 600; $text->translate($x, $y); $text->text("Click "); $x += $text->advancewidth("Click "); # x,y should be at LL corner of "here" (on baseline) $text->fillcolor($link_text_color); $text->text("here"); $target_width = $text->advancewidth("here"); $annotation = $page->annotation(); # method 'file' is still usable $annotation->launch("resources/sample.txt", -rect => [$x-1, $y-5, $x+1+$target_width, $y-5+1+$font_size], # clickable area -border => [0, 0, $border], # show border -color => [$b_red, $b_green, $b_blue], # border color ); # restore color and do rest of line $text->fillcolor($normal_text_color); $text->text(" to \"launch\" a .txt file."); # ---------------------- $x = 100; $y = 500; $text->translate($x, $y); # x,y should be at LL corner of full text (on baseline) $text->fillcolor('purple'); my $line_of_text = "Whole line is link with fancy border"; $text->text($line_of_text); $target_width = $text->advancewidth($line_of_text); $annotation = $page->annotation(); # method 'file' is still usable $annotation->launch("resources/sample.txt", -rect => [$x-4, $y-7, $x+5+$target_width, $y-7+6+$font_size], # clickable area -border => [0, 0, 3, [5,5]], # show border (thick, dashed) -color => [1, 1, 0], # yellow border color ); # restore color $text->fillcolor($normal_text_color); # ---------------------- if ($local_movie ne '' && -r $local_movie) { $x = 100; $y = 400; $text->translate($x, $y); $text->text("Double-click in box to play your movie..."); my $movie_title = $local_movie; $movie_title =~ s#^.*/##; $movie_title =~ s#\.[^.]+$##; $annotation->movie($local_movie, 'Movie', -rect => [100,150, 400,300], # both click rectangle AND display area -text => $movie_title, # not sure where this is supposed to go! -border => [0, 0, 2, [1,1]], -color => [0, 1, 0] # dashed bright green border ); } # ---------------------- # ->text: done in 040_annotation # ->file_attachment: done in 041_annot_fileattach # ---------------------- $pdf->saveas($PDFname); PDF-Builder-3.026/examples/041_annot_fileattach0000644000000000000000000000772414534467462017700 0ustar rootroot#!/usr/bin/perl # demonstrate file attachment annotations. # # Note that some PDF/A-oriented PDF validation tools (such as PDF Tools Online) # object to embedded (attached) files in Archival PDFs, as the fear is that # this can lead to external file dependencies. It also objects to something # about a missing Subtype in samples 5 and 6, which may or may not be PDF/A- # related, but I haven't yet been able to find anything that appears to be # missing a Subtype entry. use strict; use warnings; use lib '../lib'; use PDF::Builder; use PDF::Builder::Util; my $compress = 'none'; # uncompressed streams #my $compress = 'flate'; # compressed streams my $pdf = PDF::Builder->new(-compress => $compress); #my $f1 = $pdf->corefont('Helvetica', -encode=>'latin1'); # unused my $f2 = $pdf->corefont('Helvetica-Bold', -encode=>'latin1'); # page heading my $page = $pdf->page(); $page->mediabox(595,842); # just some random text near the top of the page my $gfx = $page->gfx(); my $text = $page->text(); $text->textlabel(50,750, $f2,20, 'Hello World!', -color=>'red'); # draw a grid with 50pt blocks to see where rectangles are $gfx->strokecolor("#CCC"); my $gridH = 700; my $gridW = 500; # horizontal grid lines and labels for (my $i=0; $i<=$gridH; $i+=50) { # i is Y coordinate (bottom is 0) $gfx->poly(10,$i+10, $gridW+10,$i+10); $text->textlabel($gridW+15,$i+7, $f2,10, $i); } # vertical grid lines and labels for (my $i=0; $i<=$gridW; $i+=50) { # i is X coordinate (left is 0) $gfx->poly($i+10,10, $i+10,$gridH+10); $text->textlabel($i+8,$gridH+20, $f2,10, $i); } $gfx->stroke(); # location of file relative to where you run the example from my $base = "examples/resources/"; # offset everything by 10,10 so grid has a little space around it # in each call, file name and click area -rect are required # single click enables drag and drop of icon, double click to run # default pushpin, 50x100 size at LL=50,50, default border # active area is supposed to be 50x50, but it seems to be little # larger than the visible icon! BTW, the icon can be dragged and dropped (will # ask for confirmation to save PDF). my $ant1 = $page->annotation(); $ant1->file_attachment($base."sample.txt", -rect=>[60,60, 110,160] # usual default icon is PushPin # icon color default to black ); # paperclip icon, 100x150 size at LL= 50,200, default border my $ant2 = $page->annotation(); $ant2->file_attachment($base."pod2htmd.temp", -rect=>[60,210, 160,360], -icon=>'Paperclip', -color=>[0.8] # very light gray icon (grayscale) ); # tag icon, 150x100 size at LL= 250,200, border 10pt thick my $ant3 = $page->annotation(); $ant3->file_attachment($base."pod2htmd.temp", -rect=>[260,210, 410,310], -icon=>'Tag', -color=>[1, 0.4, 0.1], # orange icon (RGB) -border=>[0,0, 10] ); # graph icon, 100x100 size at LL= 250,50, border 10pt thick my $ant4 = $page->annotation(); $ant4->file_attachment($base."pod2htmd.temp", -rect=>[260,60, 360,160], -icon=>'Graph', -color=>[1, 1, 0, .5], # dark blue icon (CMYK) -opacity=>0.35, # mostly translucent -border=>[10,10, 10] ); # None icon, 100x100 size at LL= 50,400, border 10pt thick # Notice that although the icon is "None", since an icon is "used", the # border is suppressed my $ant5 = $page->annotation(); $ant5->file_attachment($base."sample.txt", -rect=>[60,410, 160,510], -icon=>'None', -border=>[10,10, 10] ); # None icon, 100x100 size at LL= 250,400, border 10pt thick, comment my $ant6 = $page->annotation(); $ant6->file_attachment($base."sample.txt", -rect=>[260,410, 360,510], -icon=>'None', -text=>'I am here', -border=>[10,10, 10] ); $pdf->saveas("$0.pdf"); $pdf->end(); exit; __END__ PDF-Builder-3.026/examples/031_color_hsv0000644000000000000000000000272114534467462016362 0ustar rootroot#!/usr/bin/perl # display a subset of possible HSV colors. # TBD: consider at least more Values pages (currently 8 and 10-15). use strict; use warnings; use PDF::Builder; use PDF::Builder::Util; use POSIX; use Math::Trig; #my $compress = 'none'; # uncompressed streams my $compress = 'flate'; # compressed streams my $cx = 300; my $cy = 400; my $cr = 15; my $cs = 32; my $ang = 30; my $pdf = PDF::Builder->new(-compress => $compress); $pdf->mediabox(595,842); my $fnt = $pdf->corefont('Verdana-Bold'); # the 7 pages output are 7 levels of Value (why not anything less than 8?) foreach my $v (0xf, 0xE, 0xd, 0xC, 0xb, 0xA, 0x8) { my $page = $pdf->page(); my $gfx = $page->gfx(); my $text = $page->text(); $text->textlabel(300,750, $fnt,20, 'HSV Colorspace', -color=>'#000', -hscale=>125, -center=>1); $text->strokecolor('#000'); foreach my $s (0 .. 0x7) { my $ha = $s/2; foreach my $h (0 .. (12*$ha)-1) { my $t = sprintf('&%02X%02X%02X', floor(256*$h/(12*$ha)), (($s*2)<<4|($s*2)), ($v<<4|$v)); $gfx->fillcolor($t); $gfx->circle($cx+cos(deg2rad(360*$h/(12*$ha)))*$cs*$s,$cy+sin(deg2rad(360*$h/(12*$ha)))*$cs*$s, $cr); $gfx->fillstroke(); $text->textlabel($cx+cos(deg2rad(360*$h/(12*$ha)))*$cs*$s,$cy-2+sin(deg2rad(360*$h/(12*$ha)))*$cs*$s, $fnt,6, $t, -color=>'#000', -hscale=>80, -center=>1); } } } $pdf->saveas("$0.pdf"); $pdf->end(); exit; __END__ PDF-Builder-3.026/examples/020_textunderline0000644000000000000000000000206014534467462017250 0ustar rootroot#!/usr/bin/perl use strict; use warnings; use lib '../lib'; use PDF::Builder; use PDF::Builder::Util; #my $compress = 'none'; # no stream compression my $compress = 'flate'; # compressed streams my $pdf = PDF::Builder->new(-compress => $compress); my $f1 = $pdf->corefont('Helvetica', -encode=>'latin1'); my $f2 = $pdf->corefont('Helvetica-Bold', -encode=>'latin1'); my $page = $pdf->page(); $page->mediabox(595,842); my $text = $page->text(); $text->textlabel(50,700, $f2, 20, 'Normal Text in Red (no underline)', -color=>'red'); $text->textlabel(50,600, $f2, 20, 'Normal Text in Blue Underline in Red+Yellow', -color=>'#0000CC', -rotate=>-45, -hscale=>65, -underline=>[4,[1,'red'],7,[1.5,'yellow'],11,2], ); $text->textlabel(300,600, $f2, 20, 'Text Centered', -color=>'#0000CC', -rotate=>45, -center=>1, -underline=>[4,[2,'red']], ); $text->textlabel(550,600, $f2, 20, 'Text Right', -color=>'#0000CC', -rotate=>-45, -right=>1, -underline=>[4,[2,'red']], ); $pdf->saveas("$0.pdf"); $pdf->end(); exit; __END__ PDF-Builder-3.026/examples/040_annotation0000644000000000000000000001363414534467462016543 0ustar rootroot#!/usr/bin/perl # demonstrate (initially) open and closed annotations. the icons can be dragged # elsewhere, and one annotation is initally open for update. if you make any # posts (replies), you will be prompted to save the document before leaving. use strict; use warnings; use lib '../lib'; use PDF::Builder; use PDF::Builder::Util; my $compress = 'none'; # uncompressed streams #my $compress = 'flate'; # compressed streams my ($ant, $ant2, $ant3, $ant4, $ant5, $ant6); my $pdf = PDF::Builder->new(-compress => $compress); #my $f1 = $pdf->corefont('Helvetica', -encode=>'latin1'); # unused my $f2 = $pdf->corefont('Helvetica-Bold', -encode=>'latin1'); # page heading my $page = $pdf->page(); $page->mediabox(595,842); # A4 paper # just some random text near the top of the page my $gfx = $page->gfx(); my $text = $page->text(); $text->textlabel(50,750, $f2,20, 'Hello World!', -color=>'red'); # draw a grid with 50pt blocks to see where rectangles are $gfx->strokecolor("#CCC"); my $gridW = 500; my $gridH = 700; # offset everything by 10,10 to clear edges # horizontal lines and labels, i is Y (0 at bottom) for (my $i=0; $i<=$gridH; $i+=50) { $gfx->poly(10,$i+10, $gridW+10,$i+10); $text->textlabel($gridW+20,$i+8, $f2,10, $i); } # vertical lines and labels, i is X (0 at left) for (my $i=0; $i<=$gridW; $i+=50) { $gfx->poly($i+10,10, $i+10,$gridH+10); $text->textlabel($i+8,$gridH+20, $f2,10, $i); } $gfx->stroke(); # initially open note (annotation), can be replied to multiple times by users. # active area is supposed to be 100x100 at 50,150 (LL), but it seems to be a # little larger than the visible icon! BTW, the icon can be dragged and dropped. $ant = $page->annotation(); $ant->text("This is an initially open note.\nnext line", -color=>[ 0.8 ], # light gray icon fill -icon=>'Key', -rect=>[60,10, 160,110], -open=>1); # initially closed note (annotation), can be replied to multiple times by users. # active area is supposed to be 100x100 at 200,300 (LL), but it seems to be # little larger than the visible icon! BTW, the icon can be dragged and dropped. # note that a new annotation object must be created. $ant2 = $page->annotation(); $ant2->text('This is an initially closed note', -color=>[ 0.3 ], # dark gray icon fill -text=>'Closed for the day!', # extra note on rollover -opacity=> 0.75, # a little translucency # -border=>[10,10, 10], # prominent border N/A # -icon use default (Note) -rect=>[210,110, 310,210]); # ------------------ # some text on a new page to illustrate some more annotations $page = $pdf->page(); $page->mediabox(595,842); # A4 paper # just some random text near the top of the page my $LoremIpsum = "Sed ut perspiciatis, unde omnis iste natus error sit ". "voluptatem accusantium doloremque laudantium, totam rem aperiam eaque ipsa, ". "quae ab illo inventore veritatis et quasi architecto beatae vitae dicta ". "sunt, explicabo. Nemo enim ipsam voluptatem, quia voluptas sit, aspernatur ". "aut odit aut fugit, sed quia consequuntur magni dolores eos, qui ratione ". "dolor sit, voluptatem sequi nesciunt, neque porro quisquam est, qui dolorem ". "ipsum, quia amet, consectetur, adipisci velit, sed quia non numquam eius ". "modi tempora incidunt, ut labore et dolore magnam aliquam quaerat ". "voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam ". "corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur?"; #$gfx = $page->gfx(); my $fontsize = 20; my $descender = 3; # eyeball estimate my $leading = $fontsize * 1.30; $text = $page->text(); $text->font($f2, $fontsize); $text->leading($leading); $text->translate(75, 700); # upper left baseline of 250-wide paragraph my ($spill, $unused) = $text->paragraph($LoremIpsum, 250,640, 0, -spillover=>1); # Now to do some annotations $ant3 = $page->annotation(); # 1 line down from upper line my $note = "This has a highlighter effect."; my @topbot = y_topbot(700, 1, $leading, $fontsize, $descender); my $corners = [115,$topbot[0], 221,$topbot[0], 115,$topbot[1], 221,$topbot[1]]; $ant3->markup($note, $corners, "Highlight", -color=>[1, .82, 0]); $ant4 = $page->annotation(); # 7 lines down from upper line $note = "This uses a squiggly line."; @topbot = y_topbot(700, 7, $leading, $fontsize, $descender); $corners = [75,$topbot[0], 298,$topbot[0], 75,$topbot[1], 298,$topbot[1]]; $ant4->markup($note, $corners, "Squiggly", -color=>[0, 0, 1]); $ant5 = $page->annotation(); # 11 lines down from upper line $note = "This uses an underline spanning two lines."; @topbot = y_topbot(700, 11, $leading, $fontsize, $descender); $corners = [277,$topbot[0], 330,$topbot[0], 277,$topbot[1], 330,$topbot[1], 75,$topbot[0]-$leading, 157,$topbot[0]-$leading, 75,$topbot[1]-$leading, 157,$topbot[1]-$leading]; $ant5->markup($note, $corners, "Underline", -color=>[0, 1, 0], -text=>"Some title text"); $ant6 = $page->annotation(); # 15 lines down from upper line $note = "This uses a strikeout spanning three lines."; @topbot = y_topbot(700, 15, $leading, $fontsize, $descender); $corners = [257,$topbot[0], 350,$topbot[0], 257,$topbot[1], 350,$topbot[1], 75,$topbot[0]-$leading, 340,$topbot[0]-$leading, 75,$topbot[1]-$leading, 340,$topbot[1]-$leading, 75,$topbot[0]-2*$leading, 338,$topbot[0]-2*$leading, 75,$topbot[1]-2*$leading, 338,$topbot[1]-2*$leading]; $ant6->markup($note, $corners, "StrikeOut", -opacity=>0.5); # ------------------ $pdf->saveas("$0.pdf"); $pdf->end(); exit; sub y_topbot { my ($topbase, $line, $leading, $fontsize, $descender) = @_; # topbase = y of top line's baseline # line = line number (top line is 0, below it is 1, etc.) # leading = baseline-to-baseline distance # fontsize = font size (baseline to top of ascenders) # descender = descender size my $base = $topbase - $line * $leading; my $delta = $fontsize/20; return ($base+$fontsize-$delta, $base-$descender-$delta); } __END__ PDF-Builder-3.026/examples/README0000644000000000000000000002241214534467462014735 0ustar rootrootThese "examples" were only used for testing by a former maintainer, and thus were removed from the official distribution (2.026). However, I feel that they can provide some interesting examples of code, and thus should continue to be provided. SOME OF THESE EXAMPLES MAY NOT WORK (SEE NOTES). USE AT YOUR OWN RISK. THEY ARE NOT INTENDED TO BE OFFICIAL TEST CASES, NOR ARE THEY WELL DOCUMENTED OR NECESSARILY EVEN WELL WRITTEN. They are provided as examples of code, and some (e.g., listing of fonts) may even be useful to you. Run from parent of examples directory, e.g., perl examples/011_open_update. Creates output PDF files in examples directory (with exceptions as noted). Fixing these examples is a low priority task, but I will try to get to it over time. Meanwhile, fixes, suggestions, and even new (working!) examples from the community are welcome. As of 2.025 (last version tested against)... (see bug 108987) tested against 3.003 April 2017 tested against 3.004 July 2017 tested with each release thereafter =========== broken: =========== possibly OK: BarCode.pl Demonstrate the bar code library, 1 page (11 one-dimensional barcodes). It appears to mostly be there, but some heavy bars seem to be merging into their neighbors, AT LEAST ON LOW-TO- MEDIUM RESOLUTION screens, and there may be other problems. On a laser printer the merged or "blotted" lines appear to separate into discrete lines, but MAY still be too close for accurate scanning! My advice is to use the barcode functions in production code ONLY WITH EXTREME CAUTION AND TESTING FOR SUITABILITY. Be sure to scan a number of sample bar codes with production scanner equipment, before deciding that they're suitable for real use. =========== successful (produced reasonable looking PDF, and no messages): 011_open_update BASE is one page Hello World!. UPDATED is two page, second page is new Hello World! (2). Internal string adds third page Hello World! (3). STRING PDF adds fourth page Hello World! (4). 012_pages output pages numbered i - iii, 1, 9, 2 - 8 (generate pages 1 - 8, insert page 9 before 2, insert Front Matter i-iii) 020_corefonts latin1 encoding only (actually looks more like Windows-1252). 4 variants most faces one page per font plane (256 characters each), as most fonts have more than 256 glyphs from a variety of encodings (uses automap). command line list of core fonts to display, or entire list by default note that "utf8" (and any other multibyte characters) does not appear to work with core fonts! 020_textrise show a line of text with rise of +5 (superscript) and -5 (subscript). Also +/- 10 and 20 units. 020_textunderline show off textlabel() call with angles, colors, and a variety of underlining. 021_psfonts Given one or more Type1 (PS) fonts and their metrics files on the command line, a PDF showing the characters and CID details is produced for each font file. 021_synfonts .75 slant, 12 oblique, 4 bold, and small caps variants (where available) of the given core fonts, as available, for 32 core fonts. Also, a sample page with combined variants. 022_truefonts Given one or more TrueType (.ttf) font FILES on the command line, a PDF showing the characters (256 per indicated SINGLE BYTE encoding, default is 'latin1'), the CID details for all the characters in the font, and some ASCII sample text is produced for each file. Note that unlike most of the other example programs, the resulting PDF(s) are in the directory you run the program from, not the examples/ directory where 022_truefonts lives! OpenType (.otf) fonts also appear to work well here. The first (encoding) page works only with single byte encodings (not UTF-8). The CID list is independent of the encoding, and the sample text is ASCII. 022_truefonts_diacrits_utf8 similar to 022_truefonts in its inputs and outputs (no CId character dump). times.ttf and tahoma.ttf (and presumably others) contain the U+0361 combining diacritic used on the second page. 'utf8' encoding doesn't work for the first page (dump of 256 characters in given encoding), only single byte encodings. UTF-8 input is used for the second page string, and the encoding is ignored. 023_cjkfonts (MyungJo fonts only) the last several hundred characters (2 pages, rotated ASCII) get an undefined value returned by $font->uniByCId($xo), and so end up being formatted U+???? to avoid a fatal error. Presumably, rotated text should not have a Unicode number. The Lorem Ipsum text on the last page of some fonts (KozGo, KozMin, MyungJo) appears to be using the fixed pitch variants of Latin alphabet, rather than proportional. 024_bdffonts produces a grid and sample text for a customer-supplied BDF (bitmapped) font. 025_unifonts produces a PDF with a segment of an attached PDF-J file (SJIS encoding) rendered in four different Western+CJK font combinations. 026_unifont2 a selection of Unicode alphabets and symbols, in several font faces (Helvetica Bold, Times Roman, symbols). Note that the glyph name is printed at an angle, due to its length. 030_colorspecs displays 16 pages each of RGB, RGB Gamma 2.2, CMYK, and L*a*b colorspaces, and almost 3 pages of named colors. 16 pages of 256 colors each, except named colors. All are sorted from lower left to upper right (opposite of font pages). Black (K) = 0 for all CMYK entries, else it would have 256 pages. 031_color_hsv displays 7 page subset of HSV colorspace as color wheels. 032_separation show color separation (CMYK) grid. 040_annotation demonstrate open and closed "text" annotations on a page. Both permit editing of the text, with the "open" annotation coming up already opened for editing, and the "closed" annotation needing to be clicked on to allow editing. If you make a change to the open annotation, when you exit you will be prompted to save the changes (you don't have to, unless you want to open the PDF again and see your entry still there). Also show some "markup" annotations on the second page. 041_annot_fileattach demonstrate file attachment annotations on a page. Two small files are attached in six different ways (mostly a variety of icons and their coloring). 042_links demonstrate some links from PDF text to other places in a document, to other PDFs, and to HTML files in browsers. 050_pagelabels all 26 pages show "Page Index=n" (0..25). The reader's thumbnail display is labeled with the appropriate Roman Numerals, etc., and is NOT on the page itself. Note that each time the display format is changed, the page number resets to 1 (I, i, A, a). 055_outlines take PDF like 012_page's, and add three outlines (bookmarks) to physical pages 1, 4, and 11 (labeled i, 1, 7). 060_transparency show writing opaque and translucent text by two methods. =========== other example material: Bspline.pl show off splines which connect all given points. Content.pl demonstrate Content.pm graphics and text calls, 5 pages. ContentText.pl demonstrate Content-related text call, 10 pages. RMtutorial.pl Rich Measham's basic tutorial on using PDF::API2, updated for PDF::Builder. HarfBuzz.pl show use with HarfBuzz::Shaper to shape complex scripts as well as ligatures and kerning in Latin fonts. Rotated.pl demonstrates how to rotate selected pages Boxes.pl demonstrates PDF "boxes". ShowFont.pl list glyphs in a font. output varies by font, encoding(s), and font type. FontManager.pl show the usage of the Font Manager, with some sample PDF output. Windows/ 027_winfont demo Windows registry access Win32.pm glue routine (lib/PDF/Builder/Win32.pm) only used in 027_winfont. The Windows routines have been broken at least since Windows 7, and the demo wasn't terribly useful, anyway, so it has been removed. Notes: * Makefile.PL commented out Win32::TieRegistry prereq * examples.bat has been updated to remove Windows test (027_winfont) * t/00-all-usable.t has not been changed, as Win32.pm should not be encountered during testing PDF-Builder-3.026/examples/FontManager.pl0000644000000000000000000003474414534467462016626 0ustar rootroot#!/usr/bin/perl # list a font file's contents # outputs ShowFont...pdf # run without arguments to get help listing # author: Phil M Perry use strict; use warnings; our $VERSION = '3.026'; # VERSION our $LAST_UPDATE = '3.024_002'; # manually update whenever code is changed use PDF::Builder; use utf8; use Carp; my $do_noncore = 1; # TTF, etc., will require manual update before running! my $dump = 1; # debug dump of font data my $name = $0; $name =~ s/\.pl$/.pdf/; # write into examples directory my ($page, $text, $grfx); my $pdf = PDF::Builder->new('compress' => 'none'); # a font to use that doesn't hit anything in FontManager #my $exmpl_font = $pdf->corefont('Helvetica'); # page 1 $page = $pdf->page(); $text = $page->text(); #$grfx = $page->gfx(); if ($dump) { print "=================================================================\n"; print "=== dump initial state of FontManager before doing anything else.\n"; # note that this prints to STDOUT, not to the PDF $pdf->dump_font_tables(); } # we have the default core fonts loaded. put out a little text my ($x,$y, $xcur, $word, $width, @textwords); $x = 50; $y = 700; my $colwidth = 400; my $font_size = 20; my $leading = 1.1 * $font_size; $xcur = $x; # x,y is start of current line, xcur,y is where we are in line if ($dump) { print "**** Times Roman\n"; } # should be current font (core, Times Roman) $text->font($pdf->get_font('italic'=>0), $font_size); my $space_w = $text->advancewidth(' '); @textwords = split / /, "Start out in normal text. Now switch"; while (@textwords) { ($xcur,$y, @textwords) = output($text, $xcur,$y, $x,$x+$colwidth, $space_w, $leading, @textwords); } if ($dump) { print "**** Times Italic\n"; } $text->font($pdf->get_font('italic'=>1), $font_size); $space_w = $text->advancewidth(' '); @textwords = split / /, "from normal to italic text."; while (@textwords) { ($xcur,$y, @textwords) = output($text, $xcur,$y, $x,$x+$colwidth, $space_w, $leading, @textwords); } if ($dump) { print "**** Times Roman\n"; } # back to Roman. could add 'bold'=>0 to be certain $text->font($pdf->get_font('italic'=>0), $font_size); $space_w = $text->advancewidth(' '); @textwords = split / /, "And back to Roman (normal)."; while (@textwords) { ($xcur,$y, @textwords) = output($text, $xcur,$y, $x,$x+$colwidth, $space_w, $leading, @textwords); } if ($dump) { print "**** Times Bold\n"; } $text->font($pdf->get_font('bold'=>1), $font_size); $space_w = $text->advancewidth(' '); @textwords = split / /, "Does BOLD get your attention?"; while (@textwords) { ($xcur,$y, @textwords) = output($text, $xcur,$y, $x,$x+$colwidth, $space_w, $leading, @textwords); } if ($dump) { print "**** Times BoldItalic\n"; } $text->font($pdf->get_font('italic'=>1), $font_size); $space_w = $text->advancewidth(' '); @textwords = split / /, "Then how about bold AND italic?"; while (@textwords) { ($xcur,$y, @textwords) = output($text, $xcur,$y, $x,$x+$colwidth, $space_w, $leading, @textwords); } if ($dump) { print "**** Times Roman\n"; } $text->font($pdf->get_font('italic'=>0, 'bold'=>0), $font_size); $space_w = $text->advancewidth(' '); @textwords = split ' ', "OK, too much excitement. Back to plain old Roman."; while (@textwords) { ($xcur,$y, @textwords) = output($text, $xcur,$y, $x,$x+$colwidth, $space_w, $leading, @textwords); } # start next paragraph $y -= 3*$leading; $xcur = $x; if ($dump) { print "=================================================================\n"; print "=== dump state of FontManager after playing with Times face.\n"; # note that this prints to STDOUT, not to the PDF $pdf->dump_font_tables(); } if ($dump) { print "**** Helvetica (sans serif)\n"; } $text->font($pdf->get_font('face'=>'sans-serif', 'italic'=>0, 'bold'=>0), $font_size); $space_w = $text->advancewidth(' '); @textwords = split / /, "Take the default sans serif face, which is Helvetica."; while (@textwords) { ($xcur,$y, @textwords) = output($text, $xcur,$y, $x,$x+$colwidth, $space_w, $leading, @textwords); } if ($dump) { print "**** Courier\n"; } $text->font($pdf->get_font('face'=>'Courier'), $font_size); $space_w = $text->advancewidth(' '); @textwords = split / /, "No? Then how about typewriter output (Courier)?"; while (@textwords) { ($xcur,$y, @textwords) = output($text, $xcur,$y, $x,$x+$colwidth, $space_w, $leading, @textwords); } if ($dump) { print "**** Symbol\n"; } $text->font($pdf->get_font('face'=>'Symbol'), $font_size); $space_w = $text->advancewidth(' '); @textwords = split / /, "Any idea what this says, like whazzup, dude?"; while (@textwords) { ($xcur,$y, @textwords) = output($text, $xcur,$y, $x,$x+$colwidth, $space_w, $leading, @textwords); } if ($dump) { print "**** Helvetica\n"; } $text->font($pdf->get_font('face'=>'Helvetica'), $font_size); $space_w = $text->advancewidth(' '); @textwords = split / /, "And this looks like the signs in the NYC subway."; while (@textwords) { ($xcur,$y, @textwords) = output($text, $xcur,$y, $x,$x+$colwidth, $space_w, $leading, @textwords); } if ($dump) { print "**** default font\n"; } $text->font($pdf->get_font('face'=>'default'), $font_size); $space_w = $text->advancewidth(' '); @textwords = split / /, "Back to the default face (Times)."; while (@textwords) { ($xcur,$y, @textwords) = output($text, $xcur,$y, $x,$x+$colwidth, $space_w, $leading, @textwords); } if ($do_noncore) { if ($dump) { print "**** Georgia\n"; } # CAUTION: face may need to be changed on non-Windows systems $text->font($pdf->get_font('face'=>'Georgia'), $font_size); $space_w = $text->advancewidth(' '); @textwords = split / /, "And finally, I've got Georgia on my mind..."; while (@textwords) { ($xcur,$y, @textwords) = output($text, $xcur,$y, $x,$x+$colwidth, $space_w, $leading, @textwords); } } if ($dump) { print "=================================================================\n"; print "=== dump state of FontManager after face switching.\n"; # note that this prints to STDOUT, not to the PDF $pdf->dump_font_tables(); } # now to load in some non-core fonts. you will need to update these! if ($do_noncore) { # codec BDF if ($pdf->add_font('face' => 'Codec', 'type' => 'bdf', 'style' => 'sans-serif', 'width' => 'constant', 'settings' => { 'encode' => 'iso-8859-1' }, 'file' => { 'roman' => 'codec/codec.bdf' } )) { carp "Something went sideways trying to add BDF font to list."; } # URW PalladioL-Roma T1 if ($pdf->add_font('face' => 'Palladio', 'type' => 'type1', 'style' => 'serif', 'width' => 'proportional', 'settings' => { 'encode' => 'iso-8859-1', 'afmfile' => 'URWPalladioL-Roma.afm' }, 'file' => { 'roman' => 'URWPalladioL-Roma.pfb' } )) { carp "Something went sideways trying to add T1 font to list."; } # DejaVu Sans TTF if ($pdf->add_font('face' => 'DejaVuSans', 'type' => 'ttf', 'style' => 'sans-serif', 'width' => 'proportional', 'settings' => { 'encode' => 'utf8' }, 'file' => { 'roman' => 'DejaVuSans.ttf', 'italic' => 'DejaVuSans-Oblique.ttf', 'bold' => 'DejaVuSans-Bold.ttf', 'bold-italic' => 'DejaVuSans-BoldOblique.ttf' } )) { carp "Something went sideways trying to add TTF font to list."; } # Adobe Gothic Standard (Chinese) CJK if ($pdf->add_font('face' => 'Chinese', 'type' => 'ttf', 'style' => 'serif', 'width' => 'proportional', 'settings' => { 'encode' => 'utf8' }, 'file' => { 'roman' => '/Program Files/Adobe/Acrobat DC/Resource/CIDFont/AdobeGothicStd-Light.otf' } )) { carp "Something went sideways trying to add CJK font to list."; } # FR SCRIPT script font if ($pdf->add_font('face' => 'FRscript', 'type' => 'ttf', 'style' => 'sans-serif', 'width' => 'proportional', 'settings' => { 'encode' => 'utf8' }, 'file' => { 'roman' => 'FRSCRIPT.TTF' } )) { carp "Something went sideways trying to add script font to list."; } # and load some local font search paths. you will need to update these! # currently, these paths are NOT checked/validated upon entry! # Windows predefined /WINDOWS/Fonts for TTF my @fontpaths; # ==== type1 (PS) push @fontpaths, "C:/Users/Phil/fonts/T1fonts"; # Windows absolute path with drive letter # URW Bookman for MikTex (Windows) push @fontpaths, "/Program Files/MikTex 2.9/fonts/type1/urw/bookman"; # URW Bookman for older versions of MikTex (Windows) push @fontpaths, "/Program Files (x86)/MikTex 2.9/fonts/type1/urw/bookman"; # ==== BDF (bitmapped) push @fontpaths, "/Users/Phil/fonts/BDFfonts"; # ==== CJK (Chinese) push @fontpaths, "/Program Files/Adobe/Acrobat DC/Resource/CIDFont"; while (@fontpaths) { my $path = shift @fontpaths; if ($pdf->add_font_path($path)) { print "Something went wrong with adding path '$path'\n"; } } if ($dump) { print "=================================================================\n"; print "=== dump state of FontManager after adding more fonts.\n"; # note that this prints to STDOUT, not to the PDF $pdf->dump_font_tables(); } # start next paragraph $y -= 3*$leading; $xcur = $x; if ($dump) { print "**** default font\n"; } $text->font($pdf->get_font('face'=>'default'), $font_size); $space_w = $text->advancewidth(' '); @textwords = split / /, "Start with the default face (core Times)."; while (@textwords) { ($xcur,$y, @textwords) = output($text, $xcur,$y, $x,$x+$colwidth, $space_w, $leading, @textwords); } if ($dump) { print "**** DejaVu Sans TTF font\n"; } $text->font($pdf->get_font('face'=>'DejaVuSans'), $font_size); $space_w = $text->advancewidth(' '); @textwords = split / /, "Switch to DejaVu Sans, also in"; while (@textwords) { ($xcur,$y, @textwords) = output($text, $xcur,$y, $x,$x+$colwidth, $space_w, $leading, @textwords); } $text->font($pdf->get_font('face'=>'DejaVuSans', 'italic'=>1), $font_size); $space_w = $text->advancewidth(' '); @textwords = split / /, "italic,"; while (@textwords) { ($xcur,$y, @textwords) = output($text, $xcur,$y, $x,$x+$colwidth, $space_w, $leading, @textwords); } $text->font($pdf->get_font('face'=>'DejaVuSans', 'italic'=>0, 'bold'=>1), $font_size); $space_w = $text->advancewidth(' '); @textwords = split / /, "bold,"; while (@textwords) { ($xcur,$y, @textwords) = output($text, $xcur,$y, $x,$x+$colwidth, $space_w, $leading, @textwords); } $text->font($pdf->get_font('face'=>'DejaVuSans', 'italic'=>1), $font_size); $space_w = $text->advancewidth(' '); @textwords = split / /, "and both."; while (@textwords) { ($xcur,$y, @textwords) = output($text, $xcur,$y, $x,$x+$colwidth, $space_w, $leading, @textwords); } # remember that both italic and bold flags are set if ($dump) { print "**** Palladio Type1 font\n"; } $text->font($pdf->get_font('face'=>'Palladio', 'italic'=>0, 'bold'=>0), $font_size); $space_w = $text->advancewidth(' '); @textwords = split / /, "Now try out a Type 1 (PostScript) font named PalladioL, from URW."; while (@textwords) { ($xcur,$y, @textwords) = output($text, $xcur,$y, $x,$x+$colwidth, $space_w, $leading, @textwords); } if ($dump) { print "**** Codec BDF (bitmapped) font\n"; } $text->font($pdf->get_font('face'=>'Codec'), $font_size); $space_w = $text->advancewidth(' '); @textwords = split / /, "This should be ugly: X11 bitmapped Codec font."; while (@textwords) { ($xcur,$y, @textwords) = output($text, $xcur,$y, $x,$x+$colwidth, $space_w, $leading, @textwords); } if ($dump) { print "**** Adobe Gothic CJK (Chinese) font\n"; } $text->font($pdf->get_font('face'=>'Chinese'), $font_size); $space_w = $text->advancewidth(' '); @textwords = split / /, "And finally, a sample of CJK (e.g., Chinese) text output: \x{4F7F}\x{7528}\x{9019}\x{500B}\x{FF08}\x{66F4}\x{767D}\x{7684}\x{7259}\x{9F52}\x{FF09}\x{3002}"; while (@textwords) { ($xcur,$y, @textwords) = output($text, $xcur,$y, $x,$x+$colwidth, $space_w, $leading, @textwords); } if ($dump) { print "**** FRSCRIPT script font\n"; } $text->font($pdf->get_font('face'=>'FRscript'), $font_size); $space_w = $text->advancewidth(' '); @textwords = split / /, "Let's try a possible script font."; while (@textwords) { ($xcur,$y, @textwords) = output($text, $xcur,$y, $x,$x+$colwidth, $space_w, $leading, @textwords); } $pdf->font_settings('script' => 'FRscript'); # make it the new default script $text->font($pdf->get_font('face'=>'default'), $font_size); $space_w = $text->advancewidth(' '); @textwords = split / /, "Indeed, it was script."; while (@textwords) { ($xcur,$y, @textwords) = output($text, $xcur,$y, $x,$x+$colwidth, $space_w, $leading, @textwords); } $text->font($pdf->get_font('face'=>'script'), $font_size); $space_w = $text->advancewidth(' '); @textwords = split / /, "Have some more!"; while (@textwords) { ($xcur,$y, @textwords) = output($text, $xcur,$y, $x,$x+$colwidth, $space_w, $leading, @textwords); } if ($dump) { print "=================================================================\n"; print "=== dump state of FontManager after non-core fonts used.\n"; # note that this prints to STDOUT, not to the PDF $pdf->dump_font_tables(); } } # non-core samples, likely requiring manual updates $pdf->saveas($name); # output a stream of words on THIS line, returning unused portion. # for now, not worrying about running off bottom of page! sub output { my ($text, $xcur, $y, $x, $max_x, $space, $leading, @words) = @_; $text->translate($xcur,$y); # only need to do at start of string while (@words) { $word = shift @words; $width = $text->advancewidth($word); if ($xcur+$width > $max_x) { # need to split text. for now, just fit whole words unshift @words, $word; $y -= $leading; # for now, not checking if go off bottom! $xcur = $x; # start of new line return ($xcur,$y, @words); } # there is room for at least one more word on this line # we will put down TRAILING space after a word. let's not worry # for now whether this space actually exceeds right margin, as # it's invisible anyway. $text->text($word.' '); $xcur += $width+$space; } # we used up all the words without filling the line? return return ($xcur,$y, @words); } PDF-Builder-3.026/examples/060_transparency0000644000000000000000000000272014534467462017076 0ustar rootroot#!/usr/bin/perl # show writing opaque and translucent text by two methods use strict; use warnings; use lib '../lib/'; use PDF::Builder; use PDF::Builder::Util; use POSIX; my $compress = 'none'; # uncompressed streams #my $compress = 'flate'; # compressed streams my $pdf = PDF::Builder->new(-compress => $compress); $pdf->mediabox(595,842); my $TRANSPARENT = $pdf->egstate(); # Called just once $TRANSPARENT->transparency(0.4); # only 60% opaqueness my $fnt = $pdf->corefont('Verdana-Bold'); my $page = $pdf->page(); my $text = $page->text(); # page 1: opaque red text put down, then almost transparent black partly over. # both texts bleed off right side of page $text->textlabel(30,750, $fnt,100, '100% Opaque', -color=>'#F00'); $text->egstate($TRANSPARENT); $text->textlabel(30,720, $fnt,100, '40% Transparent', -color=>'#000'); # page 2: similar to page 1, but using different methods. bleed off left side. $page = $pdf->page(); $text = $page->text(); $text->font($fnt, 100); $text->fillcolor('red'); $text->translate(570,750); $text->text_right('Opaque 100%'); $text->textend(); # back into graphics state so can do transparency #$text->save(); # unnecessary, as this is the last segment $text->egstate($TRANSPARENT); $text->textstart(); # back into text mode $text->font($fnt, 100); $text->fillcolor('black'); $text->translate(570,720); $text->text_right('Transparent 40%'); $text->textend(); #$text->restore(); $pdf->saveas("$0.pdf"); $pdf->end(); exit; __END__ PDF-Builder-3.026/examples/HarfBuzz.pl0000644000000000000000000010611214534467462016145 0ustar rootroot#!/usr/bin/perl # demonstrate some usage of HarfBuzz::Shaper and related text calls # outputs HarfBuzz.pdf # author: Phil M Perry use strict; use warnings; our $VERSION = '3.026'; # VERSION our $LAST_UPDATE = '3.021'; # manually update whenever code is changed my $PDFname = $0; $PDFname =~ s/\..*$//; # remove extension such as .pl $PDFname .= '.pdf'; # add new extension pdf use PDF::Builder; # do NOT attempt to run unless HarfBuzz::Shaper is installed # (should fail gracefully with message) my $rc; $rc = eval { require HarfBuzz::Shaper; 1; }; if (!defined $rc) { $rc = 0; } # else is 1 if ($rc == 0) { print STDERR "HarfBuzz::Shaper does not appear to be installed. Not running HarfBuzz.pl\n"; exit; } my $dokern = 1; # ttfont defaults -dokern to 0, Shaper to 1 my $doliga = 1; # built-in ligatures my $fontsize = 20; my $dump = 0; # 1 to dump Shaper data, 0 no my $showNextWrite = 1; # 1 to write | after text (at next position) my $strike = 'none'; # or 'auto' strikethrough my $under = 'none'; # or 'auto' underlining (only for alignment examples) my $leading = 1.6; # baseline-to-baseline * font size my $latinFont = # for kerning, ligature demos # '/WINDOWS/Fonts/times.ttf'; # '/WINDOWS/Fonts/arial.ttf'; '/Users/Phil/AppData/Local/Microsoft/Windows/Fonts/NimbusRoman-Regular.otf'; my $ligFont = # for full ligature list, Shaper ignores # $latinFont; # '/Users/Phil/AppData/Local/Microsoft/Windows/Fonts/NimbusRoman-Regular.otf'; # '/WINDOWS/Fonts/verdana.ttf'; # '/WINDOWS/Fonts/arial.ttf'; '/WINDOWS/Fonts/times.ttf'; # missing fj, ij, and et my $arabicFont = '/Program Files/Adobe/Acrobat DC/Resource/Font/AdobeArabic-Regular.otf'; # You will certainly have to modify the font file locations and names # per your local installation and operating system, here and below in %samples. # Some .ttf fonts may be usable by HarfBuzz for shaping, but others don't seem # to be. my $pdf = PDF::Builder->new(-compress => 'none'); #my $pdf = PDF::Builder->new(); $pdf->mediabox('universal'); # narrower and shorter of US letter and A4, so # it should be printable on either paper my $labelFont = $pdf->corefont('Helvetica'); my ($font); # A collection of text in various scripts. Non-Latin (English) lines include # "PDF::Builder" chunks in the middle, to demonstrate switching back and forth # of scripts, and that LTR text like that stays in that direction even when the # rest of the line is RTL (Arabic, Hebrew). # # The top line of each pair outputs the raw text (Unicode points) WITHOUT # HarfBuzz::Shaper modifying it, using the normal text() method. There is no # shaping. The bottom line uses HarfBuzz::Shaper to rearrange and substitute # characters (details below). Some of the glyphs may not have Unicode points. my %samples = ( # Demonstrate ligatures in a Latin script, assuming you haven't disabled # ligatures with $doliga = 0. 'ft', 'ffl', and 'fi' may have ligatures # available in the font, although 'fi' is the only common one. 'ff' is # another commonly available ligature, but here it is disabled with a ZWNJ # (Zero Width Non Joiner U+200C) between the f's. Some fonts may respond # instead to a ZWJ (Zero Width Joiner U+200D), so you might need to change # the text if you change fonts. The ZWNJ is removed if ligatures are # disabled, otherwise a space is left between the f's! 'LatinL' => { 'title' => "LatinL", # are ligatures done? 'fontFile' => $latinFont, 'dir' => 'L', 'script' => 'Latn', # ft, ffl, fi ligatures desired, if available; ff no ligature! # might have to insert ZWNJ (U+200C) between f-f # ZWNJ (U+200c) text() renders as full space, Shaper renders # as full space but advance = 0 # ZWJ (U+200d) text() renders as full space, Shaper renders # as ff legature PLUS full space, advance = 0 'text' => ["Eat soft waffles in a field, read a shelf\x{200c}ful of books"] }, # Demonstrate all Unicode ligatures in a Latin script. Not all will be # available in a given font. note that Shaper is not used for ligatures! # It also seems to ignore most or all ligatures in .ttf fonts. 'LatinL2' => { 'title' => "LatinL2", 'fontFile' => $ligFont, 'dir' => 'L', 'script' => 'Latn', 'specials' => 1, # -liga plus call Builder filter # ss/eszett sz/eszett 'n/'n, ff fi fl fj oo 'text' => ["strasse strasze R 'n R staff fish flow fjord good"] }, 'LatinL3' => { 'title' => "LatinL3", 'fontFile' => $ligFont, 'dir' => 'L', 'script' => 'Latn', 'specials' => 1, # -liga plus call Builder filter # long-st st aa ao au av ay et 'text' => ["mo\x{017f}t fast aardvark Mao Maui have aye et"] }, 'LatinL4' => { 'title' => "LatinL4", 'fontFile' => $ligFont, 'dir' => 'L', 'script' => 'Latn', 'specials' => 1, # -liga plus call Builder filter # tz TZ ue vy ffi ffl ij # TBD see if setting language to German will do ss, tz, TZ 'text' => ["Tirpitz TIRPITZ blue heavy suffice waffle pij"] }, # Demonstrate kerning (closing up overlapping characters) in a Latin script. # You should see AVA and AWAY are closed up, due to letter shapes. This can # be disabled with $dokern = 0. Note that some minor kerning may be done # between other letter pairs, such as 'ke'. 'LatinK' => { 'title' => "LatinK", # is kerning done? YES! 'fontFile' => $latinFont, 'dir' => 'L', 'script' => 'Latn', 'text' => ["AVA, do AWAY with kerning!"] }, # Demonstrate synthesis of new accented letters and logos by manipulating a # HarfBuzz array directly. Creates an n-umlaut (not a standard character) # and rescales and moves letters (think of the "LA" combination as a new # ligature). Note that three letters are Greek, which if it ever causes a # problem, would need to be split into separate Shaper chunks. 'LatinS' => { 'title' => "LatinS", 'fontFile' => '/Windows/Fonts/times.ttf', 'dir' => 'L', 'script' => 'Latn', 'specials' => 2, # note use of NONcombining diaeresis, Tau-Epsilon-Chi # this will be cut into 3 pieces, because A is smaller 'text' => ["This is Spi\x{A8}nal Tap! LA\x{03a4}\x{0395}\x{03a7} Rulz?"] }, # Some Devanagari text (an Indian script). I have no idea if the words here # mean anything... I just copied them from an article on typesetting. You # can see that there is some rearrangement of characters and some combining # and removal, all taken care of by HarfBuzz. 'Devan' => { 'title' => "Devanagari", # see PP_Advanced pg 26 & 27 # and PP_Avanced_typography_in_PDF.pdf 'fontFile' => '/Program Files/Adobe/Acrobat DC/Resource/Font/AdobeDevanagari-Regular.otf', 'dir' => 'L', 'script' => 'Deva', 'text' => ["\x{091A}\x{093F}\x{0928}\x{094D}\x{0939}\x{0947}", " PDF::Builder ", "\x{0905}\x{0932}\x{093f}\x{091c}\x{093f}\x{0939}\x{094d}\x{0935}\x{0940}\x{092f}"] }, # Some Khmer text (a Cambodian script). I don't think the first "word" means # anything, but the second may be something like "a dog". 'Khmer' => { 'title' => "Khmer", 'fontFile' => '/Users/Phil/Desktop/closed tickets/D.O.N.E/khmer/KhmerOS_.ttf', 'dir' => 'L', 'script' => 'Khmr', # KA COENG KA and "dog" CHA COENG KA AE 'text' => ["\x{1780}\x{17D2}\x{1780}", " PDF::Builder ", "\x{1786}\x{17D2}\x{1780}\x{17C2}"] }, # Some Arabic text. I understand that the first "word" translates to "the # Arabic language". I just removed a couple letters to make the second # "word", which probably is meaningless now (just to show the RTL order they # were rendered in). Note that the "left" margin is over on the right side of # the page. 'Arabic' => { 'title' => "Arabic", # see Wikipedia/Complex_text_layout 'fontFile' => $arabicFont, 'dir' => 'R', 'script' => 'Arab', 'text' => ["\x{0627}\x{0644}\x{0639}\x{0631}\x{0628}\x{064a}\x{0629}", " PDF::Builder ", "\x{0627}\x{0644}\x{0628}\x{064a}\x{0629}"] }, # Some Hebrew text. I used Google Translate on a couple phrases like "Hello, # my name is" and "Happy to meet you", and transliterated them into Unicode # points. The typefaces were not identical (between GT and my Unicode # reference book), so I may have made some mistakes, and I removed a word or # two to shorten the line and emphasize that it is written RTL, so now it # probably doesn't make any sense! 'Hebrew' => { 'title' => "Hebrew", 'fontFile' => '/WINDOWS/Fonts/times.ttf', # has Hebrew too 'dir' => 'R', 'script' => 'Hebr', 'text' => ["\x{05e9}\x{05dc}\x{05d5}\x{05dd} \x{05e9}\x{05de}\x{05d9}", " PDF::Builder ", "\x{05d5}\x{05d0}\x{05e0}\x{05d9} \x{05e9}\x{05de}\x{05d7}\x{05d4} \x{05dc}\x{05e4}\x{05d2}\x{05d5}\x{05e9} \x{05d0}\x{05d5}\x{05ea}."] }, ); # many examples (incl Arabic) in # https://en.wikipedia.org/wiki/Zero-width_non-joiner (need fonts to try out) # also GitHub tangrams/harfBuzz-example/ # also see https://english.stackexchange.com/questions/50660/when-should-i-not- # use-a-ligature-in-english-typesetting#answer-50957 for many places NOT to # use a ligature (according to the "don't ligature across a morpheme # boundary camp"). my $page = $pdf->page(); my $text = $page->text(); my $grfx = $page->gfx(); my $y = 750; my $hb = HarfBuzz::Shaper->new(); my ($fontfile, $info, $startx, $starty); my %settings; foreach my $samp (sort keys %samples) { $settings{'dump'} = $dump; ### diagnostic dump to STDOUT my $title = $samples{$samp}->{'title'}; $settings{'script'} = $samples{$samp}->{'script'}; ### Latn, Hebr, etc. $settings{'features'} = (); ### required entry $fontfile = $samples{$samp}->{'fontFile'}; $text->font($labelFont, $fontsize); my $dir = $samples{$samp}->{'dir'}; # L(TR), R(TL), future T(TB), B(TT) $text->translate(25, $y); $text->text($title); # same line, at x=150 write raw characters print "###### start of $samp output\n"; my $specials = $samples{$samp}->{'specials'} || 0; # default 0 # $hb->set_language( 'en_US' ); # unnecessary? # $settings{'language'} = 'en'; ### # TBD try language = de (German) and see if tz, etc. automatically done if ($samples{$samp}->{'script'} eq 'Latn') { if (!$doliga || $specials==1) { ### not needed in textHS $hb->add_features( '-liga' ); # +liga is default, -liga works push @{ $settings{'features'} }, '-liga'; } if (!$dokern || $specials==1) { ### needed in textHS # for forceLigs, turn off kerning to keep clean $hb->add_features( '-kern' ); # shut off kerning, +kern default push @{ $settings{'features'} }, '-kern'; } } $font = $pdf->ttfont($fontfile); $text->font($font, $fontsize); $text->translate(150, $y); my $textstr = join('', @{ $samples{$samp}->{'text'} }); $textstr =~ s/[\x{200c}\x{200d}]//g; # remove ZWNJ, ZWJ for text() output $text->text($textstr, -strikethru=>$strike, -underline=>$under); $y -= $leading*$fontsize; # write Shaped chars at x=150 (LTR) or 550 (RTL) # Shaper output is LTR even if chunk is RTL # we will let 'align' value default (Left aligned for LTR) if ($dir eq 'L') { $startx = 150; # $settings{'align'} = 'B'; ### beginning of line (LTR at L) } else { $startx = 550; # $settings{'align'} = 'B'; ### beginning of line (RTL at R) } $starty = $y; $settings{'dir'} = $dir; ### L(TR), R(TL) $hb->set_font($fontfile); $hb->set_size($fontsize); # start at left or right end of line (beginning) $text->translate($startx, $starty); foreach (@{ $samples{$samp}->{'text'} }) { # a "chunk" of text # if no ligatures, remove ZWNJ and ZWJ (ligature suppression) # otherwise may get odd extra space in middle of word if (!$doliga) { $_ =~ s/[\x{200c}\x{200d}]//g; } # TBD here could split up a long string for paragraph/page shaping, # or wait until Shaper gives final sizes. # TBD here could do line full justification (modify ax per charspace # and wordspace settings). for connected/cursive scripts, don't # change interletter spacing, just interword. Probably want to # wait for Shaper to give final sizes. $hb->set_text($_); $info = $hb->shaper(); # output is built LTR in all cases if ($specials == 1) { # here modify $info array to use additional ligatures if # Shaper doesn't pick them up (e.g., many .ttf fonts) $info = uniLigatures($info); } if ($specials == 2) { # special treatment for one line, and only tail end is output here $info = buildChars($info, $strike, %settings); } # output to the PDF file $text->textHS($info, \%settings, -strikethru=>$strike, -underline=>$under); } # end of array of chunks for one sample # show where next write would go nextWrite($dir); $y -= $leading*$fontsize; } # end loop through samples # demonstrate alignment print "###### start of alignment output\n"; my @xpos = (85, 210, 335, 460); my @align = ('', 'B', 'C', 'E'); $text->font($labelFont, $fontsize); $text->translate($xpos[0], 100); $text->text_center('Default'); $text->translate($xpos[1], 100); $text->text_center('B (begin)'); $text->translate($xpos[2], 100); $text->text_center('C (centered)'); $text->translate($xpos[3], 100); $text->text_center('E (end)'); foreach my $x (@xpos) { $grfx->poly($x,70, $x,90); $grfx->stroke(); $grfx->poly($x,40, $x,60); $grfx->stroke(); $grfx->circle($x,75, 2); $grfx->fill(); $grfx->circle($x,45, 2); $grfx->fill(); } # first line is Latin text $hb->set_font($latinFont); $hb->set_size($fontsize); $hb->set_text('aligned'); $info = $hb->shaper(); $settings{'dir'} = 'L'; $font = $pdf->ttfont($latinFont); $text->font($font, $fontsize); for my $i (0 .. 3) { $text->translate($xpos[$i],75); # output to the PDF file $settings{'align'} = $align[$i]; if ($settings{'align'} eq '') { delete $settings{'align'}; } $text->textHS($info, \%settings, -strikethru=>$strike, -underline=>$under); # show where next write would go nextWrite('L'); } # second line is Arabic text $hb->set_font($arabicFont); $hb->set_size($fontsize); $hb->set_text("\x{0627}\x{0644}\x{0639}\x{0631}\x{0628}\x{064a}\x{0629}"); $info = $hb->shaper(); $settings{'dir'} = 'R'; $font = $pdf->ttfont($arabicFont); $text->font($font, $fontsize); for my $i (0 .. 3) { $text->translate($xpos[$i],45); # output to the PDF file $settings{'align'} = $align[$i]; if ($settings{'align'} eq '') { undef $settings{'align'}; } $text->textHS($info, \%settings, -strikethru=>$strike, -underline=>$under); # show where next write would go nextWrite('R'); } ###### second page with vertical orientation text $page = $pdf->page(); $text = $page->text(); $grfx = $page->gfx(); $y = 750; #$doliga = 0; # suppress ligatures NOT necessary? #$dokern = 0; # suppress kerning NOT necessary? %samples = ( # Latin (English) text top to bottom 'TTBLatin' => { 'title' => 'TTBLatin', 'fontFile' => $latinFont, 'dir' => 'T', 'script' => 'Latn', 'text' => ["Hi There!"] }, # Latin (English) text bottom to top # note that Shaper returns reversed text to be rendered TTB 'BTTLatin' => { 'title' => 'BTTLatin', 'fontFile' => $latinFont, 'dir' => 'B', 'script' => 'Latn', 'text' => ["Hi There!"] }, # some random Chinese characters. most interested in what direction is # the default, and what is settable 'TTBChinese' => { 'title' => 'TTBChinese', # 'fontFile' => '/Program Files/Adobe/Acrobat DC/Resource/CIDFont/AdobeMingStd-Light.otf', 'fontFile' => '/Program Files/Adobe/Acrobat DC/Resource/CIDFont/AdobeGothicStd-Light.otf', 'dir' => 'T', 'script' => 'Chin', # 'text' => ["\x{5A40}\x{5A41}\x{5A42}\x{5A43}", " PDF::Builder ", "\x{5A44}\x{5A45}"] }, # 'text' => ["\x{58D8}\x{5A41}\x{5C62}\x{6A13}", " PDF::Builder ", "\x{6DDA}\x{6F0F}"] }, # want to show some punctuation that gets rotated around in TTB mode. text is Google Translate-produced "use this (whiter teeth)" ## 'text' => ["使用這個(更白的牙齒)。"] }, 'text' => ["\x{4F7F}\x{7528}\x{9019}\x{500B}\x{FF08}\x{66F4}\x{767D}\x{7684}\x{7259}\x{9F52}\x{FF09}\x{3002}"] }, # Languages which are normally RTL don't seem to behave with TTB. # I would expect them to be reversed, but they aren't. Maybe the direction # override is scrambling HarfBuzz? # # Hebrew (normally RTL) and Latin (LTR) TTB direction 'TTBHebrew' => { 'title' => "TTBHebrew", 'fontFile' => '/WINDOWS/Fonts/times.ttf', # has Hebrew too 'dir' => 'T', 'script' => 'Hebr', 'text' => ["\x{05e9}\x{05dc}\x{05d5}\x{05dd} \x{05e9}\x{05de}\x{05d9}", " PDF ", "\x{05d5}\x{05d0}\x{05e0}\x{05d9}"] }, # A cursive script such as Arabic needs to be drawn as unconnected individual # (standalone) glyphs, but still, I would expect the order to be reversed. # Arabic (normally RTL) and Latin (LTR) TTB direction 'TTBArabic' => { 'title' => "TTBArabic", 'fontFile' => $arabicFont, 'dir' => 'T', 'script' => 'Arab', 'text' => ["\x{0627}\x{0644}\x{0639}\x{0631}\x{0628}\x{064a}\x{0629}", " PDF ", "\x{0627}\x{0644}\x{0639}"] }, # Hebrew (normally RTL) and Latin (normally LTR) BTT direction 'BTTHebrew' => { 'title' => "BTTHebrew", 'fontFile' => '/WINDOWS/Fonts/times.ttf', # has Hebrew too 'dir' => 'B', 'script' => 'Hebr', 'text' => ["\x{05e9}\x{05dc}\x{05d5}\x{05dd} \x{05e9}\x{05de}\x{05d9}", " NOT rec. ", "\x{05d5}\x{05d0}\x{05e0}\x{05d9}"] }, # Arabic (normally RTL) and Latin (normally LTR) BTT direction 'BTTArabic' => { 'title' => "BTTArabic", 'fontFile' => $arabicFont, 'dir' => 'B', 'script' => 'Arab', 'text' => ["\x{0627}\x{0644}\x{0639}\x{0631}\x{0628}\x{064a}\x{0629}", " NOT rec. ", "\x{0627}\x{0644}\x{0639}"] }, ); my $depth = 1; # indentation foreach my $samp ('TTBLatin', 'BTTLatin', 'TTBChinese', 'BTTHebrew', 'BTTArabic', 'TTBHebrew', 'TTBArabic') { # in order given $settings{'dump'} = $dump; ### diagnostic dump to STDOUT my $title = $samples{$samp}->{'title'}; $settings{'script'} = $samples{$samp}->{'script'}; ### Latn, Hebr, etc. $settings{'features'} = (); ### required entry $fontfile = $samples{$samp}->{'fontFile'}; $text->font($labelFont, $fontsize); my $dir = $samples{$samp}->{'dir'}; # L(TR), R(TL), T(TB), B(TT) # no underline or strikethru for now TTB, BTT if ($dir eq 'T' || $dir eq 'B') { #$strike = 'none'; $under = 'none'; } $text->translate(50*$depth, $y); $text->text($title); # same line, at x+150 write raw characters print "###### start of $samp output\n"; my $specials = $samples{$samp}->{'specials'} || 0; # default 0 # $hb->set_language( 'en_US' ); # unnecessary? # $settings{'language'} = 'en'; ### # language de-DE does NOT auto-ligature ss and tz # if ($samples{$samp}->{'script'} eq 'Latn') { # if (!$doliga || $specials==1) { ### not needed in textHS # $hb->add_features( '-liga' ); # +liga is default, -liga works # push @{ $settings{'features'} }, '-liga'; # } # if (!$dokern || $specials==1) { ### needed in textHS # # for forceLigs, turn off kerning to keep clean # $hb->add_features( '-kern' ); # shut off kerning, +kern default # push @{ $settings{'features'} }, '-kern'; # } # } $hb->reset(); # clear out previous chunk's explicit settings if ($samples{$samp}->{'dir'} eq 'T') { $hb->set_direction('TTB'); } elsif ($samples{$samp}->{'dir'} eq 'B') { $hb->set_direction('BTT'); } elsif ($samples{$samp}->{'dir'} eq 'L') { $hb->set_direction('LTR'); } else { # R $hb->set_direction('RTL'); } # horizontal non-Shaper output $font = $pdf->ttfont($fontfile); $text->font($font, $fontsize); $text->translate(120+50*$depth, $y); my $textstr = join('', @{ $samples{$samp}->{'text'} }); $textstr =~ s/[\x{200c}\x{200d}]//g; # remove ZWNJ, ZWJ for text() output $text->text($textstr, -strikethru=>$strike, -underline=>$under); $y -= $leading*$fontsize; # write Shaped chars at x=50*$depth # Shaper output is TTB even if chunk is BTT # we will let 'align' value default (Left aligned for LTR) $startx = 50*$depth; $starty = $y; if ($samp eq 'BTTHebrew') { $starty -= 440; } if ($samp eq 'BTTArabic') { $starty -= 400; } $settings{'dir'} = $dir; ### L(TR), R(TL), T(TB), B(TT) my %opts; # my $minKern = 1; $hb->set_font($fontfile); $hb->set_size($fontsize); my $first_chunk = 1; foreach (@{ $samples{$samp}->{'text'} }) { # a "chunk" of text # if no ligatures, remove ZWNJ and ZWJ (ligature suppression) # otherwise may get odd extra space in middle of word #if (!$doliga) { # $_ =~ s/[\x{200c}\x{200d}]//g; #} # TBD here could split up a long string for paragraph/page shaping, # or wait until Shaper gives final sizes. # TBD here could do line full justification (modify ax per charspace # and wordspace settings). for connected/cursive scripts, don't # change interletter spacing, just interword. Probably want to # wait for Shaper to give final sizes. $hb->set_text($_); # $info = $hb->shaper(); # output is built LTR or TTB in all cases # what was used? #print "language found by Shaper (or set): ".($hb->get_language())."\n"; #print "direction found by Shaper (or set): ".($hb->get_direction())."\n"; #print "script found by Shaper (or set): ".($hb->get_script())."\n"; # #if ($samples{$samp}->{'dir'} eq 'T' || $samples{$samp}->{'dir'} eq 'B') { # foreach (@{$info}) { # if (defined $_->{'g'}) { print "g $_->{'g'} "; } # print "ax $_->{'ax'}, ay $_->{'ay'} dx $_->{'dx'} dy $_->{'dy'}\n"; # } #} if ($samp eq 'TTBLatin') { # for single Latin text, show alignments, output text, next write # my $chunkLength = $text->advancewidthHS($info, \%settings, # %opts, -doKern=>$dokern, -minKern=>$minKern); my $chunkLength = $text->advancewidthHS($info, \%settings, %opts); # B position at top (startx, starty) $text->translate($startx-15, $starty-5); $text->text_right('B'); $text->translate($startx, $starty); $grfx->poly($startx-10,$starty, $startx+10,$starty); $grfx->stroke(); $grfx->circle($startx,$starty, 2); $grfx->fill(); # output text $settings{'align'} = 'B'; $text->textHS($info, \%settings, -strikethru=>$strike, -underline=>$under); # show next write nextWrite($dir); # C position lower $starty -= 1.5*$chunkLength + 50; $text->translate($startx-15, $starty-5); $text->text_right('C'); $text->translate($startx, $starty); $grfx->poly($startx-10,$starty, $startx+10,$starty); $grfx->stroke(); $grfx->circle($startx,$starty, 2); $grfx->fill(); # output text $settings{'align'} = 'C'; $text->textHS($info, \%settings, -strikethru=>$strike, -underline=>$under); # show next write nextWrite($dir); # E position at bottom $starty -= 1.5*$chunkLength + 50; $text->translate($startx-15, $starty-5); $text->text_right('E'); $text->translate($startx, $starty); $grfx->poly($startx-10,$starty, $startx+10,$starty); $grfx->stroke(); $grfx->circle($startx,$starty, 2); $grfx->fill(); # output text $settings{'align'} = 'E'; $text->textHS($info, \%settings, -strikethru=>$strike, -underline=>$under); } elsif ($samp eq 'BTTLatin') { # for single Latin text, show alignments, output text, next write # my $chunkLength = $text->advancewidthHS($info, \%settings, # %opts, -doKern=>$dokern, -minKern=>$minKern); my $chunkLength = $text->advancewidthHS($info, \%settings, %opts); # B position at top (startx, starty-chunkLength) $starty -= $chunkLength; $text->translate($startx-15, $starty-5); $text->text_right('B'); $text->translate($startx, $starty); $grfx->poly($startx-10,$starty, $startx+10,$starty); $grfx->stroke(); $grfx->circle($startx,$starty, 2); $grfx->fill(); # output text $settings{'align'} = 'B'; $text->textHS($info, \%settings, -strikethru=>$strike, -underline=>$under); # show next write nextWrite($dir); # C position lower $starty -= 0.5*$chunkLength + 50; $text->translate($startx-15, $starty-5); $text->text_right('C'); $text->translate($startx, $starty); $grfx->poly($startx-10,$starty, $startx+10,$starty); $grfx->stroke(); $grfx->circle($startx,$starty, 2); $grfx->fill(); # output text $settings{'align'} = 'C'; $text->textHS($info, \%settings, -strikethru=>$strike, -underline=>$under); # show next write nextWrite($dir); # E position at bottom $starty -= 0.5*$chunkLength + 50; $text->translate($startx-15, $starty-5); $text->text_right('E'); $text->translate($startx, $starty); $grfx->poly($startx-10,$starty, $startx+10,$starty); $grfx->stroke(); $grfx->circle($startx,$starty, 2); $grfx->fill(); # output text $settings{'align'} = 'E'; $text->textHS($info, \%settings, -strikethru=>$strike, -underline=>$under); } else { if ($first_chunk) { # only do first time # mark starting position (dir TTB, align B) $grfx->poly($startx-10,$starty, $startx+10,$starty); $grfx->stroke(); $grfx->circle($startx,$starty, 2); $grfx->fill(); # output text $text->translate($startx, $starty); $settings{'align'} = 'B'; $first_chunk = 0; } $text->textHS($info, \%settings, -strikethru=>$strike, -underline=>$under); } } # end of array of chunks for one sample # show next write nextWrite($dir); if ($dir eq 'L' || $dir eq 'R') { $y -= $leading*$fontsize; } $depth++; } ###### $pdf->saveas($PDFname); ################################################################### sub nextWrite { my $dir = shift; my @pos = $text->textpos(); if ($showNextWrite) { if ($dir eq 'L') { $grfx->poly($pos[0],$pos[1], $pos[0],$pos[1]+10, $pos[0]+5,$pos[1]+5); } elsif ($dir eq 'R') { $grfx->poly($pos[0],$pos[1], $pos[0],$pos[1]+10, $pos[0]-5,$pos[1]+5); } elsif ($dir eq 'T') { $grfx->poly($pos[0]-5,$pos[1], $pos[0]+5,$pos[1], $pos[0],$pos[1]-5); } else { # B $grfx->poly($pos[0]-5,$pos[1], $pos[0]+5,$pos[1], $pos[0],$pos[1]+5); } } $grfx->close(); $grfx->fill(); return; } ################################################################### # A crude filter to look at all Unicode ligatures in a chunk and return # a modified chunk with ligatures replacing letter combinations it can # find a glyph for. Note that this may violate a number of languages' # orthography rules, so use only as a starting point for your own version! # If you use ZWJ or ZWNJ between letters, it will skip that ligature, but # then you may have to remove the resulting space between letters. # # Some fonts have many, many more ligatures (without Unicode points). Perhaps # looking at the font CMap could tell what's available (for automated), or # just look at 022_truefonts output to manually build another list with # similar code. sub uniLigatures { my ($info) = @_; # array of hashes my @array = @{ $info }; # inherited from caller: $font, $fontsize # a table of all known Unicode Latin script ligatures. longest ones first! # N=in NimbusRoman-Regular, V=Verdana, A=Arial, T=Times my @list = ( ['ffi', 0xFB03], # NV T ['ffl', 0xFB04], # NV T ["\x{017f}t", 0xFB05], # long s followed by t AT ['et', 0x1F670], # cannot have a letter preceding or following # et also 1F671, 1F673, 1F674 (bold); 1F672, 1F675 (light) ["\x{02BC}n", 0x149], # close single quote followed by n. cf 'n AT ['ss', 0xDF ], # NVAT ['sz', 0xDF ], # NVAT ["'n", 0x149 ], # ' may be U+02BC # NVAT ['ff', 0xFB00], # NVAT ['fi', 0xFB01], # NV T ['fl', 0xFB02], # NV T ['st', 0xFB06], # AT ['aa', 0xA733], # AT ['ao', 0xA735], # AT ['au', 0xA737], # AT ['av', 0xA739], # AT ['ay', 0xA73D], # AT ['oo', 0xA74F], # AT ['tz', 0xA729], # AT ['TZ', 0xA728], # AT ['Tz', 0xA728], # unclear whether you'll ever see this AT ['ue', 0x1D6B], # AT ['vy', 0xA761], # AT ); # The input @array contains glyph IDs, but not Unicode points. # For each entry in the substitution @list, build a list of glyphs. # Also check that the replacement glyph exists in this font! # Compare to @array and if you have 2 or 3 glyph matches, replace # the 2 or 3 @array elements by one new element with the replacement # glyph and its ax (from character width). ay, dx, dy are 0. my $arrayLen = scalar @array; foreach my $item (@list) { # longest to shortest. does replacement glyph (ligature) even exist? if (!defined $font->cidByUni($item->[1])) { next; } my @letters = split //, $item->[0]; # 'f', 'f', 'i' etc. my @glyphs; # empty list of CIDs for (my $i=0; $icidByUni(ord($letters[$i])) || 0; } my $glyphsLen = scalar @glyphs; for (my $letterS=0; $letterS<=$arrayLen-$glyphsLen; $letterS++) { # start char number in array (element number) for (my $i=0; $i<$glyphsLen; $i++) { if ($array[$letterS+$i]->{'g'} != $glyphs[$i]) { last; } # so far, so good. are we on the last glyph? while ($i == $glyphsLen-1) { # special cases? # et must have a space on both sides, or be at end # if necessary, could check against letters and punctuation if ($item->[0] eq 'et') { my $space = $font->cidByUni(0x20) || 0; if ($letterS > 0 && $array[$letterS-1]->{'g'} != $space) { last; } if ($letterS < $arrayLen-$glyphsLen && $array[$letterS+$glyphsLen]->{'g'} != $space) { last; } } # Ladies and Gentlemen, we have a match! # rewrite array[letterS] with ligature $array[$letterS]->{'g'} = $font->cidByUni($item->[1]) || 0; $array[$letterS]->{'ax'} = $font->wxByUni($item->[1])/1000*$fontsize || 0; $array[$letterS]->{'ay'} = 0; $array[$letterS]->{'dx'} = 0; $array[$letterS]->{'dy'} = 0; $array[$letterS]->{'name'} = $item->[0]; # discard rest of matched elements splice(@array, $letterS+1, $glyphsLen-1); $arrayLen -= $glyphsLen-1; # search will resume at $letterS+1, as array shortened last; } # all matched, may or may not have substituted } # loop through all glyphs in ligature } # go through letters (glyphs) in chunk } # go through each ligature to be considered return \@array; } ################################################################### # An example of creating a non-standard accented letter (n-umlaut, in this # case), and replacing and moving characters. In the latter case, since # one letter is rescaled, the array has to be broken up into five arrays # and the first four are output here, with the fifth returned for standard # processing. sub buildChars { my ($info, $strike, %settings) = @_; # array of hashes my @array = @{ $info }; # inherited from caller: $text, $font, $fontsize my $arrayLen = scalar @array; if ($arrayLen != 33) { print STDERR "Something went sideways with LatinS, array not expected length\n of 33, but is $arrayLen."; return \@array; } # Assume no ligatures or other funny stuff, so glyphs in the same postion # as the Unicode points in the original string. # # First, we need to split the array into three pieces: up to the 'A' in # LATeX, the 'A' itself (as the font size is 60%), and the TeX Greek text. # The first two will be fed to textHS() here, and the third part returned # for normal output. my (@subArray1, @subArray2); @subArray1 = @subArray2 = @array; splice(@subArray1, 23); # This is Spinal Tap! L # note that this includes an umlaut for the n, auto. taken care of splice(@subArray2, 24); # A to be reduced and moved northwest splice(@subArray2, 0, 23); splice(@array, 0, 24); # Tau-Epsilon (drop)-Chi Rulz? # there's a lot of trial-and-error positioning and sizing glyphs. you # will have to start all over if you change the font or font size. # first, adjust the diaeresis (umlaut) position [11] up and right. # n-umlaut is not a standard Unicode character! $subArray1[11]->{'dx'} = 1.6; $subArray1[11]->{'dy'} = 1.4; $subArray1[11]->{'axs'} = 0; # SET width ("n" starts right after "i") $text->textHS(\@subArray1, \%settings, -strikethru=>$strike, -underline=>$under); # second, scale down 'A' and move and write. we have to do this letter # all by itself b/c the scale has changed. let 'L' take care of underline # or strikethru, as 'A' baseline is different. If 'A' extended past 'L', # there might be a problem with baseline alignments. $text->font($font, 0.6*$fontsize); $subArray2[0]->{'axs'} = 0; # will be almost entirely "within" L $subArray2[0]->{'dx'} = -7; $subArray2[0]->{'dy'} = 3.9; $text->textHS(\@subArray2, \%settings, -strikethru=>$strike, -underline=>$under); # TBD consider second write with offset to make a little heavier. this # would be repeating the element, with a slightly different dx and dy # (say, about 0.5 points each) $text->font($font, $fontsize); # restore font # third, move Tau left close to LA $array[0]->{'dx'} = -2; # close up to previous glyph $array[0]->{'axr'} = 2; # preserve overall chunk length # fourth, move Epsilon down and left. It may already have some kerning # built-in from Tau before it $array[1]->{'dx'} = -2; $array[1]->{'dy'} = -4; $array[1]->{'axr'} = 5; # close up next glyph # Chi and rest of text start at normal place. close up space a bit $array[3]->{'axr'} = 2; # return Tau Epsilon Chi Rulz? for normal output return \@array; } PDF-Builder-3.026/examples/ContentText.pl0000644000000000000000000011750514534467462016701 0ustar rootroot#!/usr/bin/perl # exercise Content/Text.pm as much as possible # outputs ContentText.pdf # author: Phil M Perry use warnings; use strict; our $VERSION = '3.026'; # VERSION our $LAST_UPDATE = '3.023'; # manually update whenever code is changed use Math::Trig; use List::Util qw(min max); #use constant in => 1 / 72; #use constant cm => 2.54 / 72; #use constant mm => 25.4 / 72; #use constant pt => 1; use PDF::Builder; my $PDFname = $0; $PDFname =~ s/\..*$//; # remove extension $PDFname .= '.pdf'; # add new extension my $globalX = 0; my $globalY = 0; my $DofI = 'When in the course of human events, it becomes necessary for ' . 'one people to dissolve the political bands which have heretofore ' . 'connected them with another...'; # Lorem Ipsum text, borrowed from examples/022_truefonts and newlines inserted. # To use without newlines, $LoremIpsum =~ s/\n/ /g; my $LoremIpsum = "Sed ut perspiciatis, unde omnis iste natus error sit ". "voluptatem accusantium doloremque laudantium, totam rem aperiam eaque ipsa, ". "quae ab illo inventore veritatis et quasi architecto beatae vitae dicta ". "sunt, explicabo. Nemo enim ipsam voluptatem, quia voluptas sit, aspernatur ". "aut odit aut fugit, sed quia consequuntur magni dolores eos, qui ratione ". "dolor sit, voluptatem sequi nesciunt, neque porro quisquam est, qui dolorem ". "ipsum, quia amet, consectetur, adipisci velit, sed quia non numquam eius ". "modi tempora incidunt, ut labore et dolore magnam aliquam quaerat ". "voluptatem.\nUt enim ad minima veniam, quis nostrum exercitationem ullam ". "corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? ". "Quis autem vel eum iure reprehenderit, qui in ea voluptate velit esse, quam ". "nihil molestiae consequatur, vel illum, qui dolorem eum fugiat, quo voluptas ". "nulla pariatur? At vero eos et accusamus et iusto odio dignissimos ducimus, ". "qui blanditiis praesentium voluptatum deleniti atque corrupti, quos dolores ". "et quas molestias excepturi sint, obcaecati cupiditate non provident, ". "similique sunt in culpa, qui officia deserunt mollitia animi, id est laborum ". "et dolorum fuga.\nEt harum quidem rerum facilis est et expedita distinctio. ". "Nam libero tempore, cum soluta nobis est eligendi optio, cumque nihil ". "impedit, quo minus id, quod maxime placeat, facere possimus, omnis voluptas ". "assumenda est, omnis dolor repellendus.\nTemporibus autem quibusdam et aut ". "officiis debitis aut rerum necessitatibus saepe eveniet, ut et voluptates ". "repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur ". "a sapiente delectus, ut aut reiciendis voluptatibus maiores alias ". "consequatur aut perferendis doloribus asperiores repellat."; # A short LI paragraph my $LoremIpsumPara = "Sed ut perspiciatis, unde omnis iste natus error sit ". "voluptatem accusantium doloremque laudantium, totam rem aperiam eaque ipsa, ". "quae ab illo inventore veritatis."; my ($unused, $cell_height, $j, $cont); my $pdf = PDF::Builder->new(); my ($page, $grfx, $text); # objects for page, graphics, text my (@base, @points, $i, $lw); #$pdf->{'forcecompress'} = 0; # don't compress, so we can see what's happening my (@cellLoc, @cellSize, $font, $width); my @axisOffset = (5, 5); # clear the edge of the cell my $pageNo = 0; nextPage(); # next (first) page of output, 523pt wide x 720pt high my $fontR = $pdf->corefont('Times-Roman'); my $fontI = $pdf->corefont('Times-Italic'); my $fontC = $pdf->corefont('Courier'); # ---------------------------------------------------- # 1. text_left() alias for text @cellLoc = makeCellLoc(0, 0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $text->font($fontR, 12); $text->strokecolor('black'); $text->fillcolor('black'); $text->leading(15); $grfx->linewidth(1); $grfx->strokecolor('red'); $grfx->translate(@base); $grfx->poly(15,120, 15,10); $grfx->poly(155,120, 155,10); $grfx->stroke(); $text->translate($base[0]+15, $base[1]+100); $text->text_left('When in the course'); $text->translate($base[0]+15, $base[1]+ 80); $text->text_left('of human events, it becomes'); $text->translate($base[0]+15, $base[1]+ 60); $text->text_left('necessary for one people to dissolve the'); $text->translate($base[0]+15, $base[1]+ 40); $text->text_left('political bands...'); # caption drawCaption(['text_left()'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 2. text_justified() @cellLoc = makeCellLoc(1); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $text->font($fontR, 12); $text->strokecolor('black'); $text->fillcolor('black'); $text->leading(15); $grfx->linewidth(1); $grfx->strokecolor('red'); $grfx->translate(@base); $grfx->poly(15,120, 15,10); $grfx->poly(155,120, 155,10); $grfx->stroke(); $text->translate($base[0]+15, $base[1]+100); $text->text_justified('When in the course', 140); $text->translate($base[0]+15, $base[1]+ 80); $text->text_justified('of human events, it becomes', 140); $text->translate($base[0]+15, $base[1]+ 60); $text->text_justified('necessary for one people to dissolve the', 140); $text->translate($base[0]+15, $base[1]+ 40); $text->text_justified('political bands...', 140); # caption drawCaption(['text_justified()'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 3. text_fill_left(): show one long original line chopped into short lines @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $text->font($fontR, 12); $text->strokecolor('black'); $text->fillcolor('black'); $text->leading(15); $grfx->linewidth(1); $grfx->strokecolor('red'); $grfx->translate(@base); $grfx->poly(15,120, 15,10); $grfx->poly(155,120, 155,10); $grfx->stroke(); $i = $DofI; $text->translate($base[0]+15, $base[1]+105); while ($i ne '') { ($lw, $i) = $text->text_fill_left($i, 140, -spillover=>0); $text->cr(); } # caption drawCaption(['text_fill_left()'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 4. text_fill(): alias for text_fill_left() @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $text->font($fontR, 12); $text->strokecolor('black'); $text->fillcolor('black'); $text->leading(15); $grfx->linewidth(1); $grfx->strokecolor('red'); $grfx->translate(@base); $grfx->poly(15,120, 15,10); $grfx->poly(155,120, 155,10); $grfx->stroke(); $i = $DofI; $text->translate($base[0]+15, $base[1]+105); while ($i ne '') { ($lw, $i) = $text->text_fill($i, 140, -spillover=>0); $text->cr(); } # caption drawCaption(['text_fill()'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 5. text_fill_center(): show one long original line chopped into short lines @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $text->font($fontR, 12); $text->strokecolor('black'); $text->fillcolor('black'); $text->leading(15); $grfx->linewidth(1); $grfx->strokecolor('red'); $grfx->translate(@base); $grfx->poly(15,120, 15,10); $grfx->poly(155,120, 155,10); $grfx->stroke(); $i = $DofI; $text->translate($base[0]+15+140/2, $base[1]+105); while ($i ne '') { ($lw, $i) = $text->text_fill_center($i, 140, -spillover=>0); $text->cr(); } # caption drawCaption(['text_fill_center()'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 6. text_fill_right(): show one long original line chopped into short lines @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $text->font($fontR, 12); $text->strokecolor('black'); $text->fillcolor('black'); $text->leading(15); $grfx->linewidth(1); $grfx->strokecolor('red'); $grfx->translate(@base); $grfx->poly(15,120, 15,10); $grfx->poly(155,120, 155,10); $grfx->stroke(); $i = $DofI; $text->translate($base[0]+15+140, $base[1]+105); while ($i ne '') { ($lw, $i) = $text->text_fill_right($i, 140, -spillover=>0); $text->cr(); } # caption drawCaption(['text_fill_right()'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 7. text_fill_justified(): show one long original line chopped into short lines @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $text->font($fontR, 12); $text->strokecolor('black'); $text->fillcolor('black'); $text->leading(15); $grfx->linewidth(1); $grfx->strokecolor('red'); $grfx->translate(@base); $grfx->poly(15,120, 15,10); $grfx->poly(155,120, 155,10); $grfx->stroke(); $i = $DofI; $text->translate($base[0]+15, $base[1]+105); while ($i ne '') { ($lw, $i) = $text->text_fill_justified($i, 140, -spillover=>0); $text->cr(); } # caption drawCaption(['text_fill_justified()'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 8. text_fill_justified() with centered final line @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $text->font($fontR, 12); $text->strokecolor('black'); $text->fillcolor('black'); $text->leading(15); $grfx->linewidth(1); $grfx->strokecolor('red'); $grfx->translate(@base); $grfx->poly(15,120, 15,10); $grfx->poly(155,120, 155,10); $grfx->stroke(); $i = $DofI; $text->translate($base[0]+15, $base[1]+105); while ($i ne '') { ($lw, $i) = $text->text_fill_justified($i, 140, -spillover=>0, -last_align => 'c'); $text->cr(); } # caption drawCaption(['... last line centered'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 9. text_fill_justified() with right-aligned final line @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $text->font($fontR, 12); $text->strokecolor('black'); $text->fillcolor('black'); $text->leading(15); $grfx->linewidth(1); $grfx->strokecolor('red'); $grfx->translate(@base); $grfx->poly(15,120, 15,10); $grfx->poly(155,120, 155,10); $grfx->stroke(); $i = $DofI; $text->translate($base[0]+15, $base[1]+105); while ($i ne '') { ($lw, $i) = $text->text_fill_justified($i, 140, -spillover=>0, -last_align => 'r'); $text->cr(); } # caption drawCaption(['... last line right'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 10. paragraph(): fits a paragraph of text to a given width @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $text->font($fontR, 12); $text->strokecolor('black'); $text->fillcolor('black'); $text->leading(15); $grfx->linewidth(1); $grfx->strokecolor('red'); $grfx->translate(@base); $grfx->poly(15,120, 15,10); $grfx->poly(155,120, 155,10); $grfx->stroke(); $i = $LoremIpsumPara; $text->translate($base[0]+15, $base[1]+105); ($i, $unused) = $text->paragraph($i, 140,110, 0, -spillover=>0); if ($i ne '') { print "paragraph() had leftover text!\n"; } # caption drawCaption(['paragraph()'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 11. paragraph() left aligned, indent 1.5em @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $text->font($fontR, 12); $text->strokecolor('black'); $text->fillcolor('black'); $text->leading(15); $grfx->linewidth(1); $grfx->strokecolor('red'); $grfx->translate(@base); $grfx->poly(15,120, 15,10); $grfx->poly(155,120, 155,10); $grfx->stroke(); $i = $LoremIpsumPara; $text->translate($base[0]+15, $base[1]+105); ($i, $unused) = $text->paragraph($i, 140,110, 0, -spillover=>0, -align => 'left', -pndnt => 1.5 ); if ($i ne '') { print "paragraph() had leftover text!\n"; } # caption drawCaption(['paragraph() ind 1.5em'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 12. paragraph() left aligned, outdent 1.5em @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $text->font($fontR, 12); $text->strokecolor('black'); $text->fillcolor('black'); $text->leading(15); $grfx->linewidth(1); $grfx->strokecolor('red'); $grfx->translate(@base); $grfx->poly(15,120, 15,10); $grfx->poly(155,120, 155,10); $grfx->stroke(); $i = $LoremIpsumPara; $text->translate($base[0]+15, $base[1]+105); ($i, $unused) = $text->paragraph($i, 140,110, 0, -spillover=>0, -align => 'left', -pndnt => -1.5 ); if ($i ne '') { print "paragraph() had leftover text!\n"; } # caption drawCaption(['paragraph() ind -1.5em'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 13. paragraph() justified @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $text->font($fontR, 12); $text->strokecolor('black'); $text->fillcolor('black'); $text->leading(15); $grfx->linewidth(1); $grfx->strokecolor('red'); $grfx->translate(@base); $grfx->poly(15,120, 15,10); $grfx->poly(155,120, 155,10); $grfx->stroke(); $i = $LoremIpsumPara; $text->translate($base[0]+15, $base[1]+105); ($i, $unused) = $text->paragraph($i, 140,110, 0, -spillover=>0, -align => 'justified' ); if ($i ne '') { print "paragraph() had leftover text!\n"; } # caption drawCaption(['paragraph() justified'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 14. paragraph() justified indent 1.5em @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $text->font($fontR, 12); $text->strokecolor('black'); $text->fillcolor('black'); $text->leading(15); $grfx->linewidth(1); $grfx->strokecolor('red'); $grfx->translate(@base); $grfx->poly(15,120, 15,10); $grfx->poly(155,120, 155,10); $grfx->stroke(); $i = $LoremIpsumPara; $text->translate($base[0]+15, $base[1]+105); ($i, $unused) = $text->paragraph($i, 140,110, 0, -spillover=>0, -align => 'justified', -pndnt => 1.5 ); if ($i ne '') { print "paragraph() had leftover text!\n"; } # caption drawCaption(['paragraph() j ind 1.5'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 15. paragraph() justified, outdent 1.5em @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $text->font($fontR, 12); $text->strokecolor('black'); $text->fillcolor('black'); $text->leading(15); $grfx->linewidth(1); $grfx->strokecolor('red'); $grfx->translate(@base); $grfx->poly(15,120, 15,10); $grfx->poly(155,120, 155,10); $grfx->stroke(); $i = $LoremIpsumPara; $text->translate($base[0]+15, $base[1]+105); ($i, $unused) = $text->paragraph($i, 140,110, 0, -spillover=>0, -align => 'justified', -pndnt => -1.5 ); if ($i ne '') { print "paragraph() had leftover text!\n"; } # caption drawCaption(['paragraph() j ind -1.5'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 16. paragraph() right aligned @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $text->font($fontR, 12); $text->strokecolor('black'); $text->fillcolor('black'); $text->leading(15); $grfx->linewidth(1); $grfx->strokecolor('red'); $grfx->translate(@base); $grfx->poly(15,120, 15,10); $grfx->poly(155,120, 155,10); $grfx->stroke(); $i = $LoremIpsumPara; $text->translate($base[0]+15+140, $base[1]+105); ($i, $unused) = $text->paragraph($i, 140,110, 0, -spillover=>0, -align => 'right' ); if ($i ne '') { print "paragraph() had leftover text!\n"; } # caption drawCaption(['paragraph() right algn'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 17. paragraph() right aligned indent 2.5em @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $text->font($fontR, 12); $text->strokecolor('black'); $text->fillcolor('black'); $text->leading(15); $grfx->linewidth(1); $grfx->strokecolor('red'); $grfx->translate(@base); $grfx->poly(15,120, 15,10); $grfx->poly(155,120, 155,10); $grfx->stroke(); $i = $LoremIpsumPara; $text->translate($base[0]+15+140, $base[1]+105); ($i, $unused) = $text->paragraph($i, 140,110, 0, -spillover=>0, -align => 'right', -pndnt => 2.5 ); if ($i ne '') { print "paragraph() had leftover text!\n"; } # caption drawCaption(['paragraph() r ind 2.5'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 18. paragraph() right aligned, outdent 2.0em @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $text->font($fontR, 12); $text->strokecolor('black'); $text->fillcolor('black'); $text->leading(15); $grfx->linewidth(1); $grfx->strokecolor('red'); $grfx->translate(@base); $grfx->poly(15,120, 15,10); $grfx->poly(155,120, 155,10); $grfx->stroke(); $i = $LoremIpsumPara; $text->translate($base[0]+15+140, $base[1]+105); ($i, $unused) = $text->paragraph($i, 140,110, 0, -spillover=>0, -align => 'right', -pndnt => -2.0 ); if ($i ne '') { print "paragraph() had leftover text!\n"; } # caption drawCaption(['paragraph() r ind -2.0'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 19. paragraph() centered @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $text->font($fontR, 12); $text->strokecolor('black'); $text->fillcolor('black'); $text->leading(15); $grfx->linewidth(1); $grfx->strokecolor('red'); $grfx->translate(@base); $grfx->poly(15,120, 15,10); $grfx->poly(155,120, 155,10); $grfx->stroke(); $i = $LoremIpsumPara; $text->translate($base[0]+15+140/2, $base[1]+105); ($i, $unused) = $text->paragraph($i, 140,110, 0, -spillover=>0, -align => 'center' ); if ($i ne '') { print "paragraph() had leftover text!\n"; } # caption drawCaption(['paragraph() centered'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 20. section() @cellLoc = makeCellLoc(4); # new page @cellLoc = makeCellLoc(0, 2); # full page, start at second row up $cell_height = 440; @cellSize = (520, $cell_height); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $text->font($fontR, 12); $text->strokecolor('black'); $text->fillcolor('black'); $text->leading(15); $grfx->linewidth(1); $grfx->strokecolor('red'); $grfx->translate(@base); # column limits $grfx->poly(15,$cell_height-11, 15,10); $grfx->poly(155,$cell_height-11, 155,10); $grfx->poly(190,$cell_height-11, 190,10); $grfx->poly(330,$cell_height-11, 330,10); $grfx->poly(365,$cell_height-11, 365,10); $grfx->poly(505,$cell_height-11, 505,10); $grfx->stroke(); $i = $LoremIpsum; $cont = 0; for ($j=0; $j<3; $j++) { $text->translate($base[0]+15+175*$j, $base[1]+$cell_height-23); ($i, $cont, $unused) = $text->section($i, 140,$cell_height-42, $cont, -spillover=>0, -align => 'left' ); } if ($i ne '') { print "section() had leftover text!\n"; } # caption drawCaption(['section() left aligned (3 calls)'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 21. section() with 10pt paragraph spacing @cellLoc = makeCellLoc(5); # new page @cellLoc = makeCellLoc(0, 2); # full page, start at second row up $cell_height = 440; @cellSize = (520, $cell_height); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $text->font($fontR, 12); $text->strokecolor('black'); $text->fillcolor('black'); $text->leading(15); $grfx->linewidth(1); $grfx->strokecolor('red'); $grfx->translate(@base); # column limits $grfx->poly(15,$cell_height-11, 15,10); $grfx->poly(155,$cell_height-11, 155,10); $grfx->poly(190,$cell_height-11, 190,10); $grfx->poly(330,$cell_height-11, 330,10); $grfx->poly(365,$cell_height-11, 365,10); $grfx->poly(505,$cell_height-11, 505,10); $grfx->stroke(); $i = $LoremIpsum; $cont = 0; for ($j=0; $j<3; $j++) { $text->translate($base[0]+15+175*$j, $base[1]+$cell_height-23); ($i, $cont, $unused) = $text->section($i, 140,$cell_height-42, $cont, -spillover=>0, -align => 'left', -pvgap => 10 ); } if ($i ne '') { print "section() had leftover text!\n"; } # caption drawCaption(['section() left align 10pt para gap (3 calls)'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 22. section() with 2em paragraph indent @cellLoc = makeCellLoc(5); # new page @cellLoc = makeCellLoc(0, 2); # full page, start at second row up $cell_height = 440; @cellSize = (520, $cell_height); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $text->font($fontR, 12); $text->strokecolor('black'); $text->fillcolor('black'); $text->leading(15); $grfx->linewidth(1); $grfx->strokecolor('red'); $grfx->translate(@base); # column limits $grfx->poly(15,$cell_height-11, 15,10); $grfx->poly(155,$cell_height-11, 155,10); $grfx->poly(190,$cell_height-11, 190,10); $grfx->poly(330,$cell_height-11, 330,10); $grfx->poly(365,$cell_height-11, 365,10); $grfx->poly(505,$cell_height-11, 505,10); $grfx->stroke(); $i = $LoremIpsum; $cont = 0; for ($j=0; $j<3; $j++) { $text->translate($base[0]+15+175*$j, $base[1]+$cell_height-23); ($i, $cont, $unused) = $text->section($i, 140,$cell_height-42, $cont, -spillover=>0, -align => 'left', -pndnt => 2 ); } if ($i ne '') { print "section() had leftover text!\n"; } # caption drawCaption(['section() left align 2em para indent (3 calls)'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 23. section() with 2em paragraph outdent @cellLoc = makeCellLoc(5); # new page @cellLoc = makeCellLoc(0, 2); # full page, start at second row up $cell_height = 440; @cellSize = (520, $cell_height); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $text->font($fontR, 12); $text->strokecolor('black'); $text->fillcolor('black'); $text->leading(15); $grfx->linewidth(1); $grfx->strokecolor('red'); $grfx->translate(@base); # column limits $grfx->poly(15,$cell_height-11, 15,10); $grfx->poly(155,$cell_height-11, 155,10); $grfx->poly(190,$cell_height-11, 190,10); $grfx->poly(330,$cell_height-11, 330,10); $grfx->poly(365,$cell_height-11, 365,10); $grfx->poly(505,$cell_height-11, 505,10); $grfx->stroke(); $i = $LoremIpsum; $cont = 0; for ($j=0; $j<3; $j++) { $text->translate($base[0]+15+175*$j, $base[1]+$cell_height-23); ($i, $cont, $unused) = $text->section($i, 140,$cell_height-42, $cont, -spillover=>0, -align => 'left', -pndnt => -2 ); } if ($i ne '') { print "section() had leftover text!\n"; } # caption drawCaption(['section() left align 2em para outdent (3 calls)'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 24. section() justified with 2em paragraph indent @cellLoc = makeCellLoc(5); # new page @cellLoc = makeCellLoc(0, 2); # full page, start at second row up $cell_height = 440; @cellSize = (520, $cell_height); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $text->font($fontR, 12); $text->strokecolor('black'); $text->fillcolor('black'); $text->leading(15); $grfx->linewidth(1); $grfx->strokecolor('red'); $grfx->translate(@base); # column limits $grfx->poly(15,$cell_height-11, 15,10); $grfx->poly(155,$cell_height-11, 155,10); $grfx->poly(190,$cell_height-11, 190,10); $grfx->poly(330,$cell_height-11, 330,10); $grfx->poly(365,$cell_height-11, 365,10); $grfx->poly(505,$cell_height-11, 505,10); $grfx->stroke(); $i = $LoremIpsum; $cont = 0; for ($j=0; $j<3; $j++) { $text->translate($base[0]+15+175*$j, $base[1]+$cell_height-23); ($i, $cont, $unused) = $text->section($i, 140,$cell_height-42, $cont, -spillover=>0, -align => 'justified', -pndnt => 2 ); } if ($i ne '') { print "section() had leftover text!\n"; } # caption drawCaption(['section() justified 2em para indent (3 calls)'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 25. section() justified with 2em paragraph indent and 5pt gap @cellLoc = makeCellLoc(5); # new page @cellLoc = makeCellLoc(0, 2); # full page, start at second row up $cell_height = 440; @cellSize = (520, $cell_height); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $text->font($fontR, 12); $text->strokecolor('black'); $text->fillcolor('black'); $text->leading(15); $grfx->linewidth(1); $grfx->strokecolor('red'); $grfx->translate(@base); # column limits $grfx->poly(15,$cell_height-11, 15,10); $grfx->poly(155,$cell_height-11, 155,10); $grfx->poly(190,$cell_height-11, 190,10); $grfx->poly(330,$cell_height-11, 330,10); $grfx->poly(365,$cell_height-11, 365,10); $grfx->poly(505,$cell_height-11, 505,10); $grfx->stroke(); $i = $LoremIpsum; $cont = 0; for ($j=0; $j<3; $j++) { $text->translate($base[0]+15+175*$j, $base[1]+$cell_height-23); ($i, $cont, $unused) = $text->section($i, 140,$cell_height-42, $cont, -spillover=>0, -align => 'justify', -pndnt => 2, -pvgap => 5 ); } if ($i ne '') { print "section() had leftover text!\n"; } # caption drawCaption(['section() justified 2em para indent 5pt gap (3 calls)'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 26. textlabel() examples # code borrowed from examples/020_textunderline and modified @cellLoc = makeCellLoc(5); # new page @cellLoc = makeCellLoc(0, 3); # full page, start at bottom row $cell_height = 500; @cellSize = (520, $cell_height); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $text->font($fontR, 12); $text->strokecolor('black'); $text->fillcolor('black'); $text->leading(15); #my $f1 = $pdf->corefont('Helvetica', -encode=>'latin1'); my $f2 = $pdf->corefont('Helvetica-Bold', -encode=>'latin1'); # place black dot at text origin coordinates $grfx->linewidth(2); $grfx->strokecolor('black'); $grfx->circle(50,530, 0.5); $grfx->stroke(); $text->textlabel(50,530, $f2, 20, 'Normal Helvetica Bold Text in Red', -color=>'red'); $grfx->circle(50,430, 0.5); $grfx->stroke(); $text->textlabel(50,430, $f2, 20, 'Normal Text in Blue Triple Underline in Red+Yellow+Black -45d', -color=>'#0000CC', -rotate=>-45, -hscale=>65, # 3 underlines: # distance 4, thickness 1, color red # distance 7, thickness 1.5, color yellow # distance 11, thickness 2, color (strokecolor default) black -underline=>[4,[1,'red'],7,[1.5,'yellow'],11,2], ); $grfx->circle(300,430, 0.5); $grfx->stroke(); $text->textlabel(300,430, $f2, 20, 'Text Centered +45d', -color=>'#0000CC', -rotate=>45, -center=>1, -underline=>[4,[2,'red']], ); $grfx->circle(520,430, 0.5); $grfx->stroke(); $text->textlabel(520,430, $f2, 20, 'Text Right -45d', -color=>'#0000CC', -rotate=>-45, -right=>1, -underline=>[4,[2,'red']], ); $grfx->circle(300,360, 0.5); $grfx->stroke(); $text->textlabel(300,360, $f2, 20, '"auto" underline', -color=>'#0000CC', -underline=>'auto', ); $grfx->circle(300,330, 0.5); $grfx->stroke(); $text->textlabel(300,330, $f2, 20, 'Extra word spacing', -color=>'#0000CC', -wordspace=>10, ); $grfx->circle(300,300, 0.5); $grfx->stroke(); $text->textlabel(300,300, $f2, 20, 'Extra char spacing', -color=>'#0000CC', -charspace=>2, ); $grfx->circle(300,270, 0.5); $grfx->stroke(); $text->textlabel(300,270, $f2, 20, 'Condensed text', -color=>'#0000CC', -charspace=>-2, ); $grfx->circle(300,240, 0.5); $grfx->stroke(); $text->textlabel(300,240, $f2, 20, 'Render mode 1', # note that color is fill color, which is not used (only stroke color) -color=>'#0000CC', -render=>1, ); # caption drawCaption(['textlabel() samples'], 'LC'); $grfx->restore(); # soft hyphens (Latin-1) and a couple of hard hyphens in DofI my $DofIh = "When in the course of hu\xADman events, it be-comes " . "ne\xADces\xADsa\xADry for one peo\xADple to dis\xADsolve the " . "po\xADlit\xADi-cal bands which have here\xADto\xADfore " . "con\xADnect\xADed them with ano\xADther..."; @cellLoc = makeCellLoc(1); # skip to new page # ---------------------------------------------------- # 27. text_fill() with soft hyphens and a couple of hard hyphens, no hyphenate # no splitting of words @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $text->font($fontR, 12); $text->strokecolor('black'); $text->fillcolor('black'); $text->leading(15); $grfx->linewidth(1); $grfx->strokecolor('red'); $grfx->translate(@base); $grfx->poly(15,120, 15,10); $grfx->poly(155,120, 155,10); $grfx->stroke(); $i = $DofIh; $text->translate($base[0]+15, $base[1]+105); while ($i ne '') { ($lw, $i) = $text->text_fill($i, 140, -spillover=>0); $text->cr(); } # caption drawCaption(['Latin-1, hyph. off'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 28. text_fill() with soft hyphens and a couple of hard hyphens, do hyphenate # splits at 3 soft hyphens @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $text->font($fontR, 12); $text->strokecolor('black'); $text->fillcolor('black'); $text->leading(15); $grfx->linewidth(1); $grfx->strokecolor('red'); $grfx->translate(@base); $grfx->poly(15,120, 15,10); $grfx->poly(155,120, 155,10); $grfx->stroke(); $i = $DofIh; $text->translate($base[0]+15, $base[1]+105); while ($i ne '') { ($lw, $i) = $text->text_fill($i, 140, -spillover=>0, -hyphenate=>1); $text->cr(); } # caption drawCaption(['Latin-1, SHY+hard'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 29. paragraph() with soft hyphens and a couple of hard hyphens, do hyphenate # and indent to force split at hard hyphen (also 1 soft hyphen) @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $text->font($fontR, 12); $text->strokecolor('black'); $text->fillcolor('black'); $text->leading(15); $grfx->linewidth(1); $grfx->strokecolor('red'); $grfx->translate(@base); $grfx->poly(15,120, 15,10); $grfx->poly(155,120, 155,10); $grfx->stroke(); $i = $DofIh; $text->translate($base[0]+15, $base[1]+105); ($lw, $i) = $text->paragraph($i, 140,110, 0, -spillover=>0, -pndnt=>3.5, -hyphenate=>1 ); # caption drawCaption(['Latin-1, ind frc new'], 'LC'); $grfx->restore(); # change $DofIh to UTF-8 SHYs should expand to C2AD internally, no visible chg. $DofIh = Encode::decode('latin1', $DofIh); # ---------------------------------------------------- # 30. text_fill() with soft hyphens and a couple of hard hyphens, no hyphenate # no splitting of words @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $text->font($fontR, 12); $text->strokecolor('black'); $text->fillcolor('black'); $text->leading(15); $grfx->linewidth(1); $grfx->strokecolor('red'); $grfx->translate(@base); $grfx->poly(15,120, 15,10); $grfx->poly(155,120, 155,10); $grfx->stroke(); $i = $DofIh; $text->translate($base[0]+15, $base[1]+105); while ($i ne '') { ($lw, $i) = $text->text_fill($i, 140, -spillover=>0); $text->cr(); } # caption drawCaption(['UTF-8, hyph. off'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 31. text_fill() with soft hyphens and a couple of hard hyphens, do hyphenate # splits at 3 soft hyphens @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $text->font($fontR, 12); $text->strokecolor('black'); $text->fillcolor('black'); $text->leading(15); $grfx->linewidth(1); $grfx->strokecolor('red'); $grfx->translate(@base); $grfx->poly(15,120, 15,10); $grfx->poly(155,120, 155,10); $grfx->stroke(); $i = $DofIh; $text->translate($base[0]+15, $base[1]+105); while ($i ne '') { ($lw, $i) = $text->text_fill($i, 140, -spillover=>0, -hyphenate=>1); $text->cr(); } # caption drawCaption(['UTF-8, SHY+hard'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 32. paragraph() with soft hyphens and a couple of hard hyphens, do hyphenate # and indent to force split at hard hyphen (also 1 soft hyphen) @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $text->font($fontR, 12); $text->strokecolor('black'); $text->fillcolor('black'); $text->leading(15); $grfx->linewidth(1); $grfx->strokecolor('red'); $grfx->translate(@base); $grfx->poly(15,120, 15,10); $grfx->poly(155,120, 155,10); $grfx->stroke(); $i = $DofIh; $text->translate($base[0]+15, $base[1]+105); ($lw, $i) = $text->paragraph($i, 140,110, 0, -spillover=>0, -pndnt=>3.5, -hyphenate=>1 ); # caption drawCaption(['UTF-8, ind frc new'], 'LC'); $grfx->restore(); my $nonsense = "HereAreLongCamelCaseWordsThatNeedToBeSplitUp." . "fdsfsdflf;dp-dflkjfad.df;ljgsdfdfl:dfd-0igabc1123456defgh!" . "blahBlah/necch/necch/necch."; # ---------------------------------------------------- # 33. paragraph() with punctuation, digit runs, and camelCase, do hyphenate @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $text->font($fontR, 12); $text->strokecolor('black'); $text->fillcolor('black'); $text->leading(15); $grfx->linewidth(1); $grfx->strokecolor('red'); $grfx->translate(@base); $grfx->poly(15,120, 15,10); $grfx->poly(155,120, 155,10); $grfx->stroke(); $i = $nonsense; $text->translate($base[0]+15, $base[1]+105); ($lw, $i) = $text->paragraph($i, 140,110, 0, -spillover=>0, -pndnt=>0, -hyphenate=>1 ); # caption drawCaption(['Latin-1 non-hyphen'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 34. paragraph() with punctuation, digit runs, and camelCase, do hyphenate @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $text->font($fontR, 12); $text->strokecolor('black'); $text->fillcolor('black'); $text->leading(15); $grfx->linewidth(1); $grfx->strokecolor('red'); $grfx->translate(@base); $grfx->poly(15,120, 15,10); $grfx->poly(155,120, 155,10); $grfx->stroke(); $i = $nonsense; $text->translate($base[0]+15, $base[1]+105); ($lw, $i) = $text->paragraph($i, 140,110, 0, -spillover=>0, -pndnt=>-1.0, -hyphenate=>1 ); # caption drawCaption(['Latin-1 non-hyphen, outd'], 'LC'); $grfx->restore(); # ---------------------------------------------------- $pdf->saveas($PDFname); # ===================================================================== sub colors { my $color = shift; $grfx->strokecolor($color); $grfx->fillcolor($color); $text->strokecolor($color); $text->fillcolor($color); return; } # --------------------------------------- # if a single coordinate pair, produces a green dot # if two or more pairs, produces a green dot at each pair, and connects # with a green line sub greenLine { my $pointsRef = shift; my @points = @{ $pointsRef }; my $i; $grfx->linewidth(1); $grfx->strokecolor('green'); $grfx->poly(@points); $grfx->stroke(); # draw green dot at each point $grfx->linewidth(3); $grfx->linecap(1); # round for ($i=0; $i<@points; $i+=2) { $grfx->poly($points[$i],$points[$i+1], $points[$i],$points[$i+1]); } $grfx->stroke(); return; } # --------------------------------------- sub nextPage { $pageNo++; $page = $pdf->page(); $grfx = $page->gfx(); $text = $page->text(); $page->mediabox('Universal'); $font = $pdf->corefont('Times-Roman'); $text->translate(595/2,15); $text->font($font, 10); $text->fillcolor('black'); $text->text_center($pageNo); # prefill page number before any other content return; } # --------------------------------------- sub makeCell { my ($cellLocX, $cellLocY, $cellSizeW, $cellSizeH) = @_; # outline and clip of cell $grfx->strokecolor('#CCC'); $grfx->linewidth(2); $grfx->rect($cellLocX,$cellLocY, $cellSizeW,$cellSizeH); $grfx->stroke(); #$grfx->linewidth(1); #$grfx->rect($cellLocX,$cellLocY, $cellSizeW,$cellSizeH); #$grfx->clip(1); #$text->linewidth(1); #$text->rect($cellLocX,$cellLocY, $cellSizeW,$cellSizeH); #$text->clip(1); return; } # --------------------------------------- # draw a set of axes at current origin sub drawAxes { # draw 75-long axes, at offset $grfx->linejoin(0); $grfx->linewidth(1); $grfx->poly($axisOffset[0]+0, $axisOffset[1]+75, $axisOffset[0]+0, $axisOffset[1]+0, $axisOffset[0]+75,$axisOffset[1]+0); $grfx->stroke(); # 36x36 box #$grfx->rect(0,0, 36,36); # draw a square #$grfx->stroke(); # X axis arrowhead draw $grfx->poly($axisOffset[0]+75-2, $axisOffset[1]+0+2, $axisOffset[0]+75+0, $axisOffset[1]+0+0, $axisOffset[0]+75-2, $axisOffset[1]+0-2); $grfx->stroke(); # Y axis arrowhead draw $grfx->poly($axisOffset[0]+0-2, $axisOffset[1]+75-2, $axisOffset[0]+0+0, $axisOffset[1]+75+0, $axisOffset[0]+0+2, $axisOffset[1]+75-2); $grfx->stroke(); return; } # --------------------------------------- # label the X and Y axes, and draw a sample 'n' sub drawLabels { my ($Xlabel, $Ylabel) = @_; my $fontI = $pdf->corefont('Times-Italic'); my $fontR = $pdf->corefont('Times-Roman'); # outline "n" $text->distance($axisOffset[0]+0, $axisOffset[1]+0); $text->font($fontR, 72); $text->render(1); $text->text('n'); $text->render(0); $text->font($fontI, 12); # X axis label $text->distance(75+2, 0-3); $text->text($Xlabel); # Y axis label $text->distance(-75-2+0-4, 0+3+75+2); $text->text($Ylabel); return; } # --------------------------------------- # write out a 1 or more line caption sub drawCaption { my $captionsRef = shift; my @captions = @$captionsRef; my $just = shift; # 'LC' = left justified (centered on longest line) my ($width, $i, $y); $text->font($fontC, 12); $text->fillcolor('black'); # find longest line width $width = 0; foreach (@captions) { $width = max($width, $text->advancewidth($_)); } $y=20; # shut up perlcritic for ($i=0; $i<@captions; $i++) { # $just = LC $text->translate($cellLoc[0]+$cellSize[0]/2-$width/2, $cellLoc[1]-$y); $text->text($captions[$i]); $y+=13; # shut up perlcritic } return; } # --------------------------------------- # m, n (both within X and Y index ranges) = set to this position # 0 = next cell (starts new page if necessary) # N = >0 number of cells to skip (starts new page if necessary) sub makeCellLoc { my ($X, $Y) = @_; # lower left corner of cell my @cellX = (36, 212, 388); # horizontal (column positions L to R) my @cellY = (625, 458, 281, 104); # vertical (row positions T to B) my $add; if (defined $Y) { # X and Y given, use if valid indices if ($X < 0 || $X > $#cellX) { die "X = $X is invalid index."; } if ($Y < 0 || $Y > $#cellY) { die "Y = $Y is invalid index."; } $globalX = $X; $globalY = $Y; $add = 0; } elsif ($X == 0) { # requesting next cell $add = 1; } else { # $X is number of cells to skip (1+) $add = $X + 1; } while ($add-- > 0) { if ($globalX == $#cellX) { # already at end of row $globalX = 0; $globalY++; } else { $globalX++; } if ($globalY > $#cellY) { # ran off bottom row, so go to new page $globalX = $globalY = 0; nextPage(); # next page of output, 523pt wide x 720pt high } } return ($cellX[$globalX], $cellY[$globalY]); } PDF-Builder-3.026/examples/023_cjkfonts0000644000000000000000000001643614534467462016216 0ustar rootroot#!/usr/bin/perl -w # wants one or more font names on the command line. If none given, use full # list of CJK fonts. If -s given as first arg, use the short list. use strict; use warnings; use lib qw{ ../lib }; use PDF::Builder; use PDF::Builder::Util; use Unicode::UCD 'charinfo'; #my $compress = 'none'; # uncompressed streams my $compress = 'flate'; # compressed streams # Note that to display the resulting PDF, many users will have to install # "East Asian" font package(s) for their browser. This is normally an easy # "one-button" process. my $LoremIpsum=q|Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam eaque ipsa, quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt, explicabo. Nemo enim ipsam voluptatem, quia voluptas sit, aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos, qui ratione voluptatem sequi nesciunt, neque porro quisquam est, qui dolorem ipsum, quia dolor sit, amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt, ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit, qui in ea voluptate velit esse, quam nihil molestiae consequatur, vel illum, qui dolorem eum fugiat, quo voluptas nulla pariatur? At vero eos et accusamus et iusto odio dignissimos ducimus, qui blanditiis praesentium voluptatum deleniti atque corrupti, quos dolores et quas molestias excepturi sint, obcaecati cupiditate non provident, similique sunt in culpa, qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio, cumque nihil impedit, quo minus id, quod maxime placeat, facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet, ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat.|; my $sx = 33; my $sy = 45; my $fx = 20; my ($pdf, $f1, $gfx, $text, $page); # font name list my @fontnames = qw[ Ming Ming-Bold Ming-Italic Ming-BoldItalic Song Song-Bold Song-Italic Song-BoldItalic MyungJo MyungJo-Bold MyungJo-Italic MyungJo-BoldItalic KozMin KozMin-Bold KozMin-Italic KozMin-BoldItalic KozGo KozGo-Bold KozGo-Italic KozGo-BoldItalic ]; # 'short' (-s flag)? if (@ARGV > 0 && $ARGV[0] eq '-s') { @fontnames = qw[ KozGo Ming-Bold ]; } # override default list with command line entries if (scalar @ARGV && $ARGV[0] ne '-s') { @fontnames = @ARGV; } foreach my $fn (@fontnames) { #if ($fn eq 'Ming-Bold') { last; } # for testing $pdf = PDF::Builder->new(-compress => $compress, -file => "$0.$fn.pdf"); $f1 = $pdf->corefont('Helvetica'); print STDERR "\n$fn\n"; my $font = $pdf->cjkfont($fn); $font->tounicodemap(); my @cids = (0 .. $font->glyphNum()-1); # WARNING: apparently not all fonts include a fontbbox entry my @fbbx = $font->fontbbox(); my $xw = int(($fbbx[2] - $fbbx[0])/20)*20; my $yw = int(($fbbx[3] - $fbbx[1])/20)*20; my $fw = $xw>$yw? $yw: $xw; my $mw = 800/$fw; my $y0 = int((20 - $fbbx[1])/20)*20*$mw; my $scale = 0.045; while (scalar @cids>0) { $page = $pdf->page(); $page->mediabox(595,842); $gfx = $page->gfx(); $text = $page->text(); # loop through rows (y) top to bottom foreach my $y (750,700,650,600,550,500,450,400,350,300,250,200,150,100,50) { # loop through columns (x) left to right foreach my $x (50,100,150,200,250,300,350,400,450,500) { my $xo = shift(@cids); $gfx->save(); $gfx->transform(-translate => [$x, $y], -scale => [0.045, 0.045]); # draw cell box 1000x1000 user units $gfx->linewidth(10); $gfx->rect(0,0, 1000,1000); $gfx->stroke(); my $wx = $font->wxByCId($xo)*$mw; my $x0 = (1000 - $wx)/2; # dashed lines for baseline, left and right limits $gfx->linedash(10,20); $gfx->linewidth(0.5); $gfx->move($x0,0); $gfx->line($x0,1000); # left limit $gfx->move($x0+$wx,1000); $gfx->line($x0+$wx,0); # right limit $gfx->move(0,$y0); $gfx->line(1000,$y0); # baseline $gfx->stroke(); $text->font($font, 1000*$mw*$scale); $text->translate($x+$x0*$scale,$y+$y0*$scale); $text->add($font->text_cid(pack('n',$xo)),'Tj'); $text->font($f1, 80*$scale); $text->hscale(80); $text->translate($x+25*$scale,$y+810*$scale); $text->text("G+$xo"); $text->translate($x+25*$scale,$y+10*$scale); my $fontValue = $font->uniByCId($xo); if (defined $fontValue) { $text->text(sprintf('U+%04X',$fontValue)); } else { $text->text('U+????'); } $text->translate($x+975*$scale,$y+10*$scale); $text->text_right('wx='.$font->wxByCId($xo)); my $ci = charinfo($font->uniByCId($xo) || 0); my $name = $font->glyphByCId($xo); if ($name =~ m|^uni[0-9a-f]{4}$|io) { $text->fillcolor('red'); $name = $ci->{'name'} || "NONE"; } else { $text->fillcolor('blue'); } $text->translate($x+975*$scale,$y+910*$scale); $text->hscale(70); $text->text_right($name); # restore $text->hscale(100); $text->fillcolor('black'); $gfx->restore(); last unless scalar @cids>0; } # column loop x coordinates last unless scalar @cids>0; } # row loop y coordinates print STDERR "."; $pdf->finishobjects($page,$gfx); } # while loop until run out of cids my $textL = $LoremIpsum; $page = $pdf->page(); $page->mediabox(595,842); $text = $page->text(); $text->transform(-translate => [50, 800]); $text->fillcolor('black'); $text->font($font, 18); $text->leading(18*1.25); my $toprint; while($textL ne '') { ($toprint, $textL) = $text->_text_fill_line($textL, 500, 0); $text->text($toprint); $text->nl(); } $pdf->save(); $pdf->end(); } # while loop, done with this font. repeat with next print STDERR "\n"; exit; __END__ =head1 HISTORY $Log$ Revision 2.1 2007/04/07 10:28:35 areibens added lorem ipsum page Revision 2.0 2005/11/16 02:16:00 areibens revision workaround for SF cvs import not to screw up CPAN Revision 1.2 2005/11/16 01:27:48 areibens genesis2 Revision 1.1 2005/11/16 01:19:24 areibens genesis Revision 1.3 2005/09/12 16:55:05 fredo various updates Revision 1.2 2004/12/31 02:59:35 fredo no message Revision 1.1 2004/04/06 23:08:57 fredo genesis =cut PDF-Builder-3.026/examples/BarCode.pl0000644000000000000000000005273714534467462015726 0ustar rootroot#!/usr/bin/perl # exercise BarCode.pm as much as possible # outputs BarCode.pdf # author: Phil M Perry # information from http://www.keyence.com/ss/products/auto_id/barcode_lecture/ # https://www.scandit.com/types-barcodes-choosing-right-barcode/ # contains examples to check against use warnings; use strict; our $VERSION = '3.026'; # VERSION our $LAST_UPDATE = '3.023'; # manually update whenever code is changed use Math::Trig; use List::Util qw(min max); #use constant in => 1 / 72; #use constant cm => 2.54 / 72; #use constant mm => 25.4 / 72; #use constant pt => 1; use PDF::Builder; #my $compress = 'flate'; # compressed streams my $compress = 'none'; # no stream compression, for debugging my $PDFname = $0; $PDFname =~ s/\..*$//; # remove extension $PDFname .= '.pdf'; # add new extension my $globalX = 0; my $globalY = 0; my $pdf = PDF::Builder->new(-compress => $compress); my ($page, $grfx, $text); # objects for page, graphics, text my (@base, @points, $i); my (@cellLoc, @cellSize, $font, $width); my @axisOffset = (5, 5); # clear the edge of the cell my ($barcode, $type, $content, $bar_height, $mils, $scale); my $pageNo = 0; nextPage(); # next (first) page of output, 523pt wide x 720pt high my $fontR = $pdf->corefont('Times-Roman'); my $fontI = $pdf->corefont('Times-Italic'); my $fontC = $pdf->corefont('Courier'); my $fontH = $pdf->corefont('Helvetica'); # page title $text->textlabel(40,765, $fontR,20, "1D Barcodes"); $bar_height = 80; $mils = 8; # bar width unit (minimum bar/gap size, in .001"). default 1 pt $scale = 1; # formimage scaling factor # ---------------------------------------------------- # UPC not supported # alphabet: 0..9 # length: 12 digits UPC-A (1+5+5+1) or 8 digits UPC-E (1+6+1) # scandit says -E is 6 digits... need to check # should have longer left guard, center (UPC-A), and right guard bars # $content = '234567899992'; # ---------------------------------------------------- # 1. Codabar # alphabet: 0..9 - $ / . + (codabar.pm also allows : ) # length: unlimited, manually add start and stop characters # scandit says max 16 plus 4 start/stop characters # 4 bars + 3 gaps per character + 1 narrow, 2 widths narrow and wide (2x) # start and stop characters any one or two of A B C D a b c d # note that codabar.pm uppercases start and stop characters, may be error! # variants: Codeabar, Ames Code, NW-7, Monarch, Code 2 of 7, # Rationalized Codabar, ANSI/AIM BC3-1995, USD-4 @cellLoc = makeCellLoc(0, 0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $text->font($fontR, 20); $text->strokecolor('black'); $text->fillcolor('black'); $text->leading(15); $type = 'Codabar'; ##$content = 'A32134567890123B'; # len 16 includes start/stop chars, encode=16 $content = 'A23342453D'; # not like scandit example, and start/stop chars gone $barcode = $pdf->xo_codabar( -code => $content, -zone => $bar_height, -umzn => 0, -lmzn => 10, -font => $fontH, -fnsz => 10, -mils => $mils, ); $barcode->{'-docompress'} = 0; delete $barcode->{'Filter'}; $grfx->formimage($barcode, centerbc($barcode, @cellSize, @base), $scale); # caption drawCaption([$type], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 2. Code 128A # alphabet: 128 ASCII characters 0x00..0x7F or 99 digit pairs # CODE A: ASCII sp.._ (x20..x5F) NUL..US (x00..x1F) UPPER CASE only # CODE B: ASCII sp..DEL (x20..x7F) with | (x7C) replaced by a hook symbol # CODE C: numeric decimal 00..99 (2n digits only) # all alphabets have additional EAN-128-specific controls in alphabet # START CODE A, may change to CODE x midstream # length: unlimited # 4 distinct bar and gap widths @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $text->font($fontR, 20); $text->strokecolor('black'); $text->fillcolor('black'); $text->leading(15); $type = 'Code 128 A'; $content = 'TEST of '.$type; $barcode = $pdf->xo_code128( -code => $content, -zone => $bar_height, -umzn => 0, -lmzn => 10, -font => $fontH, -fnsz => 10, -mils => $mils, ); $barcode->{'-docompress'} = 0; delete $barcode->{'Filter'}; $grfx->formimage($barcode, centerbc($barcode, @cellSize, @base), $scale); # caption drawCaption([$type], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 3. Code 128B # alphabet: 128 ASCII characters 0x00..0x7F or 99 digit pairs # CODE A: ASCII sp.._ (x20..x5F) NUL..US (x00..x1F) UPPER CASE only # CODE B: ASCII sp..DEL (x20..x7F) with | (x7C) replaced by a hook symbol # CODE C: numeric decimal 00..99 (2n digits only) # all alphabets have additional EAN-128-specific controls in alphabet # START CODE B, may change to CODE x midstream # length: unlimited # 4 distinct bar and gap widths @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $text->font($fontR, 20); $text->strokecolor('black'); $text->fillcolor('black'); $text->leading(15); $type = 'Code 128 B'; ##$content = 'Test Of '.$type; $content = 'Count01234567 :'; # does NOT match scandit example! $barcode = $pdf->xo_code128( -code => $content, -zone => $bar_height, -umzn => 0, -lmzn => 10, -font => $fontH, -fnsz => 10, -mils => $mils, ); $barcode->{'-docompress'} = 0; delete $barcode->{'Filter'}; $grfx->formimage($barcode, centerbc($barcode, @cellSize, @base), $scale); # caption drawCaption([$type], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 4. Code 128C # alphabet: 0..9 # length: max 10?, 2n values in this mode # START CODE C, may change to CODE x midstream # 4 distinct bar and gap widths @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $text->font($fontR, 20); $text->strokecolor('black'); $text->fillcolor('black'); $text->leading(15); $type = 'Code 128 C'; #$content = '0123456789'; # doesn't work! $content = 'Test Of '.$type; $barcode = $pdf->xo_code128( -code => $content, -zone => $bar_height, -umzn => 0, -lmzn => 10, -font => $fontH, -fnsz => 10, -mils => $mils, ); $barcode->{'-docompress'} = 0; delete $barcode->{'Filter'}; $grfx->formimage($barcode, centerbc($barcode, @cellSize, @base), $scale); # caption drawCaption([$type], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 5. Code EAN-128 # note that EAN-128 is part of Code 128 # alphabet: 128 ASCII characters 0x00..0x7F or 99 digit pairs # CODE A: ASCII sp.._ (x20..x5F) NUL..US (x00..x1F) # CODE B: ASCII sp..DEL (x20..x7F) with | (x7C) replaced by a hook symbol # CODE C: numeric decimal 00..99 # all alphabets have additional EAN-128-specific controls in alphabet # superset of CODE 128, with FNC1 required after START CODE x # length: there appears to be a lengh limit of around 8 digits per (group), and # codes will overlay each other if too long. if groups short enough, # length is unlimited @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $text->font($fontR, 20); $text->strokecolor('black'); $text->fillcolor('black'); $text->leading(15); $type = 'Code EAN-128'; #$content = '00123456780000000001'; # seems to be too long $content = '(00)12345(11)0001'; $barcode = $pdf->xo_code128( -code => $content, -zone => $bar_height, -umzn => 0, -lmzn => 10, -font => $fontH, -fnsz => 10, -mils => $mils, ); $barcode->{'-docompress'} = 0; delete $barcode->{'Filter'}; $grfx->formimage($barcode, centerbc($barcode, @cellSize, @base), $scale); # caption drawCaption([$type], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 6. Code 3 of 9 (aka Code39) # alphabet: 0..9 A..Z _ sp - $ / . + % # length: up to 43 # narrow bar/gap and wide bar/gap (3 to 5.3 times wider) 1 character is 9 bars # and spaces, with 3 wide and 6 narrow # * used for start and stop characters @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $text->font($fontR, 20); $text->strokecolor('black'); $text->fillcolor('black'); $text->leading(15); $type = 'Code 3 of 9'; ##$content = 'Test '.$type; # 3 of 9 will uppercase this $content = 'ABC 123'; # does NOT match scandit example! $barcode = $pdf->xo_3of9( -code => $content, -zone => $bar_height, -umzn => 0, -lmzn => 10, -font => $fontH, -fnsz => 10, -mils => $mils, ); $barcode->{'-docompress'} = 0; delete $barcode->{'Filter'}; $grfx->formimage($barcode, centerbc($barcode, @cellSize, @base), $scale); # caption drawCaption([$type], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 7. Code 3 of 9 with check digit (aka Code39) # alphabet: 0..9 A..Z _ sp - $ / . + % # length: up to 43 # narrow bar/gap and wide bar/gap (3 to 5.3 times wider) 1 character is 9 bars # and spaces, with 3 wide and 6 narrow # * used for start and stop characters @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $text->font($fontR, 20); $text->strokecolor('black'); $text->fillcolor('black'); $text->leading(15); $type = 'Code 3 of 9'; $content = 'Test '.$type; # 3 of 9 will uppercase this $barcode = $pdf->xo_3of9( -code => $content, -zone => $bar_height, -umzn => 0, -lmzn => 10, -font => $fontH, -fnsz => 10, -mils => $mils, ); $barcode->{'-docompress'} = 0; delete $barcode->{'Filter'}; $grfx->formimage($barcode, centerbc($barcode, @cellSize, @base), $scale); # caption drawCaption([$type.' check digit'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 8. Code 3 of 9 with check digit (aka Code39) # alphabet: 0..9 A..Z _ sp - $ / . + % # length: up to 43 # narrow bar/gap and wide bar/gap (3 to 5.3 times wider) 1 character is 9 bars # and spaces, with 3 wide and 6 narrow # * used for start and stop characters @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $text->font($fontR, 20); $text->strokecolor('black'); $text->fillcolor('black'); $text->leading(15); $type = 'Code 3 of 9'; $content = 'Test '.$type; # 3 of 9 will uppercase this $barcode = $pdf->xo_3of9( -code => $content, -zone => $bar_height, -umzn => 0, -lmzn => 10, -font => $fontH, -fnsz => 10, -mils => $mils, ); $barcode->{'-docompress'} = 0; delete $barcode->{'Filter'}; $grfx->formimage($barcode, centerbc($barcode, @cellSize, @base), $scale); # caption drawCaption([$type.' full ASCII'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 9. Code 3 of 9 full ASCII with check digit (aka Code39) # alphabet: full ASCII x00..x7F # length: up to 43 # narrow bar/gap and wide bar/gap (3 to 5.3 times wider) 1 character is 9 bars # and spaces, with 3 wide and 6 narrow # * used for start and stop characters @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $text->font($fontR, 20); $text->strokecolor('black'); $text->fillcolor('black'); $text->leading(15); $type = 'Code 3 of 9'; $content = 'Test '.$type; # 3 of 9 will uppercase this $barcode = $pdf->xo_3of9( -code => $content, -zone => $bar_height, -umzn => 0, -lmzn => 10, -font => $fontH, -fnsz => 10, -mils => $mils, ); $barcode->{'-docompress'} = 0; delete $barcode->{'Filter'}; $grfx->formimage($barcode, centerbc($barcode, @cellSize, @base), $scale); # caption drawCaption([$type.' fASC chkd'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # Code 93 (not supported) # alphabet: full ASCII x00..x7F # $content = 'CODE93'; # ---------------------------------------------------- # ---------------------------------------------------- # Code EAN (EAN-8) not supported # variants: EAN-8, EAN-13, JAN-13, ISBN, ISSN # alphabet: 0..9 # length: 13 chkdig + 6 + 6 # 8 4+4 (4+3 & chkdig) # should have longer left guard, center, and right guard bars # narrow bar width .26 to .66mm (.33mm preferred) # bar height (guard bars/text) 18.29 to 45.72mm (22.86mm preferred) # total length excluding left/right margins 29.83 to 74.58mm (37.29mm preferred) # ---------------------------------------------------- # 10. Code EAN-13 # alphabet: 0..9 # length: 13 (for books: 978 + 10-digit ISBN) 1+6+6 (1+6+5 & chkdig) # should have longer left guard, center, and right guard bars # narrow bar width .26 to .66mm (.33mm preferred) # bar height (guard bars/text) 18.29 to 45.72mm (22.86mm preferred) # total length excluding left/right margins 29.83 to 74.58mm (37.29mm preferred) @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $text->font($fontR, 20); $text->strokecolor('black'); $text->fillcolor('black'); $text->leading(15); $type = 'Code EAN-13'; ##$content = '9123456789013'; $content = '1325764098273'; # does NOT match scandit example! $barcode = $pdf->xo_ean13( -code => $content, -zone => $bar_height, -umzn => 0, -lmzn => 10, -font => $fontH, -fnsz => 10, -mils => $mils*2, ); $barcode->{'-docompress'} = 0; delete $barcode->{'Filter'}; $grfx->formimage($barcode, centerbc($barcode, @cellSize, @base), $scale); # caption drawCaption([$type.' w/ prefix'], 'LC'); $grfx->restore(); # ---------------------------------------------------- # 11. Code Interleaved 2 of 5 (aka ITF) # alphabet: 0..9 (scandit says "full ASCII set") # length: even (2n) number of digits # NOTE: Industrial 2 of 5, Matrix 2 of 5, COOP 2 of 5, and IATA barcodes # are variations on this barcode, but not equal to it! # 5 bars first digit interleaved with 5 spaces of second digit, etc. @cellLoc = makeCellLoc(0); @cellSize = (170, 131); $grfx->save(); makeCell(@cellLoc, @cellSize); @base=@cellLoc; #$base[0] += 10; #$base[1] += 10; $text->font($fontR, 20); $text->strokecolor('black'); $text->fillcolor('black'); $text->leading(15); $type = 'Code Int 2 of 5'; ##$content = '0123456789'; $content = '01234565'; # looks pretty close to scandit example $barcode = $pdf->xo_2of5int( -code => $content, -zone => $bar_height, -umzn => 0, -lmzn => 10, -font => $fontH, -fnsz => 10, -mils => $mils*2, ); $barcode->{'-docompress'} = 0; delete $barcode->{'Filter'}; $grfx->formimage($barcode, centerbc($barcode, @cellSize, @base), $scale); # caption drawCaption([$type], 'LC'); $grfx->restore(); # ---------------------------------------------------- # GS1 DATABAR (not supported) # alphabet: ? # variants = GS1 DataBar Omnidirectional, Truncated, Stacked, # Stacked Omnidirectional, Expanded, Expanded Stacked # $content = ? # ---------------------------------------------------- # ---------------------------------------------------- # MS1 PLESSEY (not supported) aka Modified Plessey # alphabet: ? # $content = '01234567897'; # ---------------------------------------------------- # ---- 2D bar codes ---------------------------------- # QR CODE (not supported) # alphabet: ? # variants: numeric, alphanumeric, byte/binary, Kanji # $content = ? # ---------------------------------------------------- # ---------------------------------------------------- # DATAMATRIX CODE (not supported) # alphabet: ? # variants: Micro-Datamatrix # $content = ? # ---------------------------------------------------- # ---------------------------------------------------- # PDF417 (not supported) # alphabet: ? # variants: Truncated PDF417 # $content = ? # ---------------------------------------------------- # ---------------------------------------------------- # AZTEC (not supported) # alphabet: ? # variants: Truncated PDF417 # $content = ? # ---------------------------------------------------- # ---------------------------------------------------- $pdf->saveas($PDFname); # ===================================================================== # note that formimage() will output to absolute position on page, and # not relative to the graphics current position! sub centerbc { my ($img, $wcapacity,$hcapacity, @base) = @_; my $w = ($wcapacity - $img->width())/2 + $base[0]; my $h = ($hcapacity - $img->height())/2 + $base[1]; return ($w, $h); } # --------------------------------------- sub colors { my $color = shift; $grfx->strokecolor($color); $grfx->fillcolor($color); $text->strokecolor($color); $text->fillcolor($color); return; } # --------------------------------------- # if a single coordinate pair, produces a green dot # if two or more pairs, produces a green dot at each pair, and connects # with a green line sub greenLine { my $pointsRef = shift; my @points = @{ $pointsRef }; my $i; $grfx->linewidth(1); $grfx->strokecolor('green'); $grfx->poly(@points); $grfx->stroke(); # draw green dot at each point $grfx->linewidth(3); $grfx->linecap(1); # round for ($i=0; $i<@points; $i+=2) { $grfx->poly($points[$i],$points[$i+1], $points[$i],$points[$i+1]); } $grfx->stroke(); return; } # --------------------------------------- sub nextPage { $pageNo++; $page = $pdf->page(); $grfx = $page->gfx(); $text = $page->text(); $page->mediabox('Universal'); $font = $pdf->corefont('Times-Roman'); $text->translate(595/2,15); $text->font($font, 10); $text->fillcolor('black'); $text->text_center($pageNo); # prefill page number before any other content return; } # --------------------------------------- sub makeCell { my ($cellLocX, $cellLocY, $cellSizeW, $cellSizeH) = @_; # outline and clip of cell $grfx->strokecolor('#CCC'); $grfx->linewidth(2); $grfx->rect($cellLocX,$cellLocY, $cellSizeW,$cellSizeH); $grfx->stroke(); #$grfx->linewidth(1); #$grfx->rect($cellLocX,$cellLocY, $cellSizeW,$cellSizeH); #$grfx->clip(1); #$text->linewidth(1); #$text->rect($cellLocX,$cellLocY, $cellSizeW,$cellSizeH); #$text->clip(1); return; } # --------------------------------------- # draw a set of axes at current origin sub drawAxes { # draw 75-long axes, at offset $grfx->linejoin(0); $grfx->linewidth(1); $grfx->poly($axisOffset[0]+0, $axisOffset[1]+75, $axisOffset[0]+0, $axisOffset[1]+0, $axisOffset[0]+75,$axisOffset[1]+0); $grfx->stroke(); # 36x36 box #$grfx->rect(0,0, 36,36); # draw a square #$grfx->stroke(); # X axis arrowhead draw $grfx->poly($axisOffset[0]+75-2, $axisOffset[1]+0+2, $axisOffset[0]+75+0, $axisOffset[1]+0+0, $axisOffset[0]+75-2, $axisOffset[1]+0-2); $grfx->stroke(); # Y axis arrowhead draw $grfx->poly($axisOffset[0]+0-2, $axisOffset[1]+75-2, $axisOffset[0]+0+0, $axisOffset[1]+75+0, $axisOffset[0]+0+2, $axisOffset[1]+75-2); $grfx->stroke(); return; } # --------------------------------------- # label the X and Y axes, and draw a sample 'n' sub drawLabels { my ($Xlabel, $Ylabel) = @_; my $fontI = $pdf->corefont('Times-Italic'); my $fontR = $pdf->corefont('Times-Roman'); # outline "n" $text->distance($axisOffset[0]+0, $axisOffset[1]+0); $text->font($fontR, 72); $text->render(1); $text->text('n'); $text->render(0); $text->font($fontI, 12); # X axis label $text->distance(75+2, 0-3); $text->text($Xlabel); # Y axis label $text->distance(-75-2+0-4, 0+3+75+2); $text->text($Ylabel); return; } # --------------------------------------- # write out a 1 or more line caption sub drawCaption { my $captionsRef = shift; my @captions = @$captionsRef; my $just = shift; # 'LC' = left justified (centered on longest line) my ($width, $i, $y); $text->font($fontC, 12); $text->fillcolor('black'); # find longest line width $width = 0; foreach (@captions) { $width = max($width, $text->advancewidth($_)); } $y=20; # to mollify perlcritic for ($i=0; $i<@captions; $i++) { # $just = LC $text->translate($cellLoc[0]+$cellSize[0]/2-$width/2, $cellLoc[1]-$y); $text->text($captions[$i]); $y+=13; # to shut up perlcritic } return; } # --------------------------------------- # m, n (both within X and Y index ranges) = set to this position # 0 = next cell (starts new page if necessary) # N = >0 number of cells to skip (starts new page if necessary) sub makeCellLoc { my ($X, $Y) = @_; # lower left corner of cell my @cellX = (36, 212, 388); # horizontal (column positions L to R) my @cellY = (625, 458, 281, 104); # vertical (row positions T to B) my $add; if (defined $Y) { # X and Y given, use if valid indices if ($X < 0 || $X > $#cellX) { die "X = $X is invalid index."; } if ($Y < 0 || $Y > $#cellY) { die "Y = $Y is invalid index."; } $globalX = $X; $globalY = $Y; $add = 0; } elsif ($X == 0) { # requesting next cell $add = 1; } else { # $X is number of cells to skip (1+) $add = $X + 1; } while ($add-- > 0) { if ($globalX == $#cellX) { # already at end of row $globalX = 0; $globalY++; } else { $globalX++; } if ($globalY > $#cellY) { # ran off bottom row, so go to new page $globalX = $globalY = 0; nextPage(); # next page of output, 523pt wide x 720pt high } } return ($cellX[$globalX], $cellY[$globalY]); } PDF-Builder-3.026/t/0000755000000000000000000000000014534671355012477 5ustar rootrootPDF-Builder-3.026/t/annotate.t0000644000000000000000000000505614534467462014505 0ustar rootroot#!/usr/bin/perl use strict; use warnings; use Test::More tests => 6; use PDF::Builder; use PDF::Builder::Basic::PDF::Array; my $pdf = PDF::Builder->new('compress' => 'none'); my $page = $pdf->page(); # (1) Text annotation my $annotation = $page->annotation(); $annotation->text('This is an annotation', 'rect' => [ 72, 144, 172, 244 ]); my $string = $pdf->to_string(); like($string, qr{/Annot /Subtype /Text /Border \[ 0 0 0 \] /Contents \(This is an annotation\) /Rect \[ 72 144 172 244 \]}, q{Text Annotation in a rectangle}); # (2) Link annotation $pdf = PDF::Builder->new(); $page = $pdf->page(); $annotation = $page->annotation(); my $page2 = $pdf->page(); $annotation->link($page2); $string = $pdf->to_string(); like($string, qr{/Annot /Subtype /Link /A << /D \[ \d+ 0 R /XYZ null null null \] /S /GoTo >>}, q{Link Annotation}); # (3) URL annotation $pdf = PDF::Builder->new(); $page = $pdf->page(); $annotation = $page->annotation(); $annotation->uri('http://perl.org'); $string = $pdf->to_string(); like($string, qr{/Annot /Subtype /Link /A << /S /URI /URI \(http://perl.org\) >>}, q{URL Annotation}); # (4) File annotation $pdf = PDF::Builder->new(); $page = $pdf->page(); $annotation = $page->annotation(); $annotation->launch('test.pdf'); $string = $pdf->to_string(); like($string, qr{/Annot /Subtype /Link /A << /F \(test.pdf\) /S /Launch >>}, q{File Annotation}); # (5) PDF File annotation $pdf = PDF::Builder->new(); $page = $pdf->page(); $annotation = $page->annotation(); $annotation->pdf('test.pdf', 2); $string = $pdf->to_string(); like($string, qr{/Annot /Subtype /Link /A << /D \[ 1 /XYZ null null null \] /F \(test.pdf\) /S /GoToR >>}, q{PDF File Annotation}); # [RT #118352] Crash if $page->annotation is called on a page with an # existing Annots array stored in an indirect object # (6) add to existing annotation $pdf = PDF::Builder->new(); $page = $pdf->page(); my $array = PDF::Builder::Basic::PDF::Array->new(); $pdf->{'pdf'}->new_obj($array); $page->{'Annots'} = $array; $page->update(); $string = $pdf->to_string(); $pdf = PDF::Builder->from_string($string); $page = $pdf->open_page(1); $annotation = $page->annotation(); $annotation->text('This is an annotation', 'rect' => [ 72, 144, 172, 244 ]); $string = $pdf->to_string(); like($string, qr{/Annot /Subtype /Text /Border \[ 0 0 0 \] /Contents \(This is an annotation\) /Rect \[ 72 144 172 244 \]}, q{Add an annotation to an existing annotations array stored in an indirect object}); 1; PDF-Builder-3.026/t/extgstate.t0000644000000000000000000000101214534467462014670 0ustar rootroot#!/usr/bin/perl use strict; use warnings; use Test::More tests => 2; use PDF::Builder; # Dash my $pdf = PDF::Builder->new('-compress' => 'none'); my $egs = $pdf->egstate(); $egs->dash(2, 1); like($pdf->to_string, qr{<< /Type /ExtGState /D \[ \[ 2 1 \] 0 \] /Name /[\w]+ >>}, 'dash'); # Rendering Intent $pdf = PDF::Builder->new('-compress' => 'none'); $egs = $pdf->egstate(); $egs->renderingintent('Perceptual'); like($pdf->to_string, qr{<< /Type /ExtGState /Name /[\w]+ /RI /Perceptual >>}, 'renderingintent'); 1; PDF-Builder-3.026/t/rt120397.t0000644000000000000000000000637514534467462014014 0ustar rootroot#!/usr/bin/perl use warnings; use strict; use Test::More; use PDF::Builder::Basic::PDF::File; my ($result, $remainder); sub readval { my ($read, $unread, %options) = @_; open my $fh, '<', \$unread or die "Can't open 'unread' for input"; my $parser = { ' INFILE' => $fh }; bless $parser, 'PDF::Builder::Basic::PDF::File'; my ($result, $remainder) = $parser->readval($read, %options); close $fh; return ($result, $remainder); } ($result, $remainder) = readval('1 0 R', ''); is(ref($result), 'PDF::Builder::Basic::PDF::Objind', q{Basic indirect reference}); ($result, $remainder) = readval('1 0 obj << >> endobj', ''); is(ref($result), 'PDF::Builder::Basic::PDF::Dict', q{Basic indirect object}); ($result, $remainder) = readval('1', ''); is(ref($result), 'PDF::Builder::Basic::PDF::Number', q{Basic number}); ($result, $remainder) = readval("1\n0 R", ''); is(ref($result), 'PDF::Builder::Basic::PDF::Objind', q{Indirect reference on multiple already-read lines}); ($result, $remainder) = readval("1\n0 obj << >> endobj", ''); is(ref($result), 'PDF::Builder::Basic::PDF::Dict', q{Indirect object on multiple already-read lines}); ($result, $remainder) = readval("1 %comment\n0 R", ''); is(ref($result), 'PDF::Builder::Basic::PDF::Objind', q{Indirect reference with embedded comment 1/2}); ($result, $remainder) = readval("1 0 %comment\nR", ''); is(ref($result), 'PDF::Builder::Basic::PDF::Objind', q{Indirect reference with embedded comment 2/2}); ($result, $remainder) = readval("1 %comment\n0 obj << >> endobj", ''); is(ref($result), 'PDF::Builder::Basic::PDF::Dict', q{Indirect object with embedded comment 1/3}); ($result, $remainder) = readval("1 0 %comment\nobj << >> endobj", ''); is(ref($result), 'PDF::Builder::Basic::PDF::Dict', q{Indirect object with embedded comment 2/3}); ($result, $remainder) = readval("1 0 obj %comment\n<< >> endobj", ''); is(ref($result), 'PDF::Builder::Basic::PDF::Dict', q{Indirect object with embedded comment 3/3}); ($result, $remainder) = readval('1', ' 0 R'); is(ref($result), 'PDF::Builder::Basic::PDF::Objind', q{Indirect reference on partially-read line}); ($result, $remainder) = readval('1', ' 0 obj << >> endobj'); is(ref($result), 'PDF::Builder::Basic::PDF::Dict', q{Indirect object on partially-read line}); ($result, $remainder) = readval("1\n", '0 R'); is(ref($result), 'PDF::Builder::Basic::PDF::Objind', q{Indirect reference on multiple lines with only the first line read 1/3}); ($result, $remainder) = readval("1 0\n", 'R'); is(ref($result), 'PDF::Builder::Basic::PDF::Objind', q{Indirect reference on multiple lines with only the first line read 2/3}); ($result, $remainder) = readval("1 0%comment\n", 'R'); is(ref($result), 'PDF::Builder::Basic::PDF::Objind', q{Indirect reference on multiple lines with only the first line read 3/3}); ($result, $remainder) = readval("1\n", '0 obj << >> endobj'); is(ref($result), 'PDF::Builder::Basic::PDF::Dict', q{Indirect object on multiple lines with only the first line read}); ($result, $remainder) = readval("1\n", '(string)'); is(ref($result), 'PDF::Builder::Basic::PDF::Number', q{Number on a line by itself followed by a non-number}); is($remainder, '(string)', q{Remainder doesn't get lost}); done_testing(); 1; PDF-Builder-3.026/t/text.t0000644000000000000000000001664314534467462013664 0ustar rootroot#!/usr/bin/perl use warnings; use strict; use Test::More tests => 27; use PDF::Builder; my $pdf = PDF::Builder->new(); my $page = $pdf->page(); my $text = $page->text(); my $font = $pdf->corefont('Helvetica'); # advancewidth $text->font($font, 12); $text->text('Test Text'); my $width = $text->advancewidth('Test Text'); is($width, '50.016', 'Advance Width Check'); $text->charspace(2); is($text->charspace(), 2, 'Charspace is set'); $width = $text->advancewidth('Test Text'); is($width, '66.016', 'Advance width check with charspace added'); $width = $text->advancewidth('Test Text', charspace => 0); is($width, '50.016', 'Advance width check with charspace 2 overridden to 0'); $text->wordspace(4); is($text->wordspace(), 4, 'Wordspace is set'); $width = $text->advancewidth('Test Text'); is($width, '70.016', 'Advance width check with wordspace added'); $width = $text->advancewidth('Test Text', wordspace => 0); is($width, '66.016', 'Advance width check with wordspace 4 overridden to 0'); # Check for death if text() is called without font() $text = $page->text(); { local $@; eval { $text->text('This should die because no font has been set') }; like($@, qr{Can't add text without first setting a font and font size}, q{Call to text without a set font returns an informative error}); # Call font(), but without setting a font size eval { $text->font($font); }; like($@, qr{A font size is required}, q{Call to text without a set font size returns an informative error}); } # text $pdf = PDF::Builder->new(-compress => 'none'); $text = $pdf->page()->text(); $font = $pdf->corefont('Helvetica'); $text->font($font, 12); $width = $text->text('Test Text'); like($pdf->to_string(), qr/\(Test Text\) Tj/, q{Basic text call}); is($width, '50.016', q{Basic text call has expected width}); # text with indent $pdf = PDF::Builder->new(-compress => 'none'); $text = $pdf->page()->text(); $font = $pdf->corefont('Helvetica'); $text->font($font, 12); $width = $text->text('Test Text', -indent => 72); like($pdf->to_string(), qr/\[ -6000 \(Test Text\) \] TJ/, q{text with indent}); is($width, '50.016', q{text with indent has expected width}); # text_right $pdf = PDF::Builder->new(-compress => 'none'); $text = $pdf->page()->text(); $font = $pdf->corefont('Helvetica'); $text->font($font, 12); $width = $text->text_right('Test Text'); like($pdf->to_string(), qr/\[ 4168 \(Test Text\) \] TJ/, q{text_right}); # text_center $pdf = PDF::Builder->new(-compress => 'none'); $text = $pdf->page()->text(); $font = $pdf->corefont('Helvetica'); $text->font($font, 12); $width = $text->text_center('Test Text'); like($pdf->to_string(), qr/\[ 2084 \(Test Text\) \] TJ/, q{text_center}); # text_justified $pdf = PDF::Builder->new(-compress => 'none'); $text = $pdf->page()->text(); $font = $pdf->corefont('Helvetica'); $text->font($font, 12); $width = $text->text_justified('Test Text', 72); like($pdf->to_string(), qr/3.336 Tw 2.331 Tc \(Test Text\) Tj 100 Tz 0 Tw/, q{text_justified}); # paragraph # note that it spills over past the right margin without the -spillover flag # note that this is by default, left-justified (ragged right) # paragraph originally 72 high, but this allows full fit with no leftover $pdf = PDF::Builder->new(-compress => 'none'); $text = $pdf->page()->text(); $font = $pdf->corefont('Helvetica'); $text->font($font, 12); $text->leading(15); my $leftover = $text->paragraph(('aaa ' x 30), 144, 57, 1,-spillover=>0); like($pdf->to_string(), qr/15 TL (\((aaa ){5}aaa\) Tj T\* ){4}\s*ET/, q{paragraph}); is($leftover, 'aaa aaa aaa aaa aaa aaa', q{paragraph has expected leftover}); # paragraph, align right $pdf = PDF::Builder->new(-compress => 'none'); $text = $pdf->page()->text(); $font = $pdf->corefont('Helvetica'); $text->font($font, 12); $text->leading(15); $text->paragraph(('aaa ' x 10), 144, 72, 1,-align => 'right', -spillover=>0); like($pdf->to_string(), qr/\[ 11398 \((aaa ){5}aaa\) \] TJ T\* \[ 7506 \(aaa aaa aaa aaa\) \] TJ T\*/, q{paragraph, align right}); # paragraph, align center $pdf = PDF::Builder->new(-compress => 'none'); $text = $pdf->page()->text(); $font = $pdf->corefont('Helvetica'); $text->font($font, 12); $text->leading(15); $text->paragraph(('aaa ' x 10), 144, 72, 1,-align => 'center', -spillover=>0); like($pdf->to_string(), qr/\[ 5699 \((aaa ){5}aaa\) \] TJ T\* \[ 3753 \(aaa aaa aaa aaa\) \] TJ T\*/, q{paragraph, align center}); # paragraph, justified left $pdf = PDF::Builder->new(-compress => 'none'); $text = $pdf->page()->text(); $font = $pdf->corefont('Helvetica'); $text->font($font, 12); $text->leading(15); $text->paragraph(('aaa ' x 10), 144, 72, 1,-align => 'justified', -spillover=>0); like($pdf->to_string(), qr/1.4448 Tw \((aaa ){5}aaa\) Tj 100 Tz 0 Tw 0 Tc T\* \(aaa aaa aaa aaa\) Tj T\*/, q{paragraph, justified, last line left}); # paragraph, justified right $pdf = PDF::Builder->new(-compress => 'none'); $text = $pdf->page()->text(); $font = $pdf->corefont('Helvetica'); $text->font($font, 12); $text->leading(15); $text->paragraph(('aaa ' x 10), 144, 72, 1,-align => 'j', -spillover=>0, '-last_align' => 'r'); like($pdf->to_string(), qr/1.4448 Tw \((aaa ){5}aaa\) Tj 100 Tz 0 Tw 0 Tc T\* \[ -4494 \((aaa ){3}aaa\) \] TJ T\*/, q{paragraph, justified, last line right}); # paragraph, justified center $pdf = PDF::Builder->new(-compress => 'none'); $text = $pdf->page()->text(); $font = $pdf->corefont('Helvetica'); $text->font($font, 12); $text->leading(15); $text->paragraph(('aaa ' x 10), 144, 72, 1,-align => 'justified', -spillover=>0, '-last_align' => 'center'); like($pdf->to_string(), qr/1.4448 Tw \((aaa ){5}aaa\) Tj 100 Tz 0 Tw 0 Tc T\* \[ -2247 \((aaa ){3}aaa\) \] TJ T\*/, q{paragraph, justified, last line center}); # paragraph, justified, last line justified # PDF::Builder does not support justification for short last lines #$pdf = PDF::Builder->new(-compress => 'none'); #$text = $pdf->page()->text(); #$font = $pdf->corefont('Helvetica'); #$text->font($font, 12); #$text->leading(15); #$text->paragraph(('aaa ' x 10), 144, 72, 1,-align => 'justified', #-spillover=>0, '-align-last' => 'justified'); #like($pdf->to_string(), #qr/1.204 Tw \((aaa ){5}aaa\) Tj 0 Tw T\* 13.482 Tw \((aaa ){3}aaa\) Tj 0 Tw/, #q{paragraph, justified, last line justified}); # paragraphs (formerly "section") $pdf = PDF::Builder->new(-compress => 'none'); $text = $pdf->page()->text(); $font = $pdf->corefont('Helvetica'); $text->font($font, 12); $text->leading(15); my $input = 'aaa ' x 10 . "\n\n" . 'bbb ' x 10; $leftover = $text->paragraphs($input, 144, 40, 1,-spillover=>0); like($pdf->to_string(), qr/15 TL \((aaa ){5}aaa\) Tj T\* \((aaa ){3}aaa\) Tj T\* \((bbb ){5}bbb\) Tj T\*\s+ET/, q{paragraphs}); is($leftover, 'bbb bbb bbb bbb', q{paragraphs has expected leftover}); # section (same as "paragraphs") $pdf = PDF::Builder->new(-compress => 'none'); $text = $pdf->page()->text(); $font = $pdf->corefont('Helvetica'); $text->font($font, 12); $text->leading(15); $input = 'aaa ' x 10 . "\n\n" . 'bbb ' x 10; $leftover = $text->section($input, 144, 40, 1,-spillover=>0); like($pdf->to_string(), qr/15 TL \((aaa ){5}aaa\) Tj T\* \((aaa ){3}aaa\) Tj T\* \((bbb ){5}bbb\) Tj T\*\s+ET/, q{section}); is($leftover, 'bbb bbb bbb bbb', q{section has expected leftover}); 1; PDF-Builder-3.026/t/filter-lzwdecode.t0000644000000000000000000000551714534467462016141 0ustar rootroot#!/usr/bin/perl use warnings; use strict; use PDF::Builder::Basic::PDF::Utils; use PDF::Builder::Basic::PDF::Filter::LZWDecode; use Test::More tests => 9; #-# 4 note() debugs presently commented out my $filter = PDF::Builder::Basic::PDF::Filter::LZWDecode->new(); my $in = 'BT /F1 24 Tf 100 700 Td (Hello World)Tj ET'; my $out = $filter->outfilt($in); is $filter->infilt($out), $in, 'LZWDecode test string round-tripped correctly'; ### my $repeat = 22; #-#note( 'Test data size: ' . length($in)*$repeat ); $filter = PDF::Builder::Basic::PDF::Filter::LZWDecode->new(); $out = $filter->outfilt($in x $repeat); #-#note( 'Final bits: '.$filter->{code_length} ); cmp_ok length($out), '<', length($in)*$repeat, "Data compresses smaller"; $filter = PDF::Builder::Basic::PDF::Filter::LZWDecode->new(); is $filter->infilt($out), $in x $repeat, 'Data decompresses unchanged at 10bit boundary'; ### $in = pack "H*", '8000000014040807050001e100f840fd00e0003fd00ff8a44e2b01'; my $expected = pack "H*", '00000180000003800000078000000f8000003f80e000ff80ffffff80ffffff80'; $filter = PDF::Builder::Basic::PDF::Filter::LZWDecode->new(); $out = $filter->infilt($in); is $out, $expected, 'decompress binary data'; ($in, $expected) = ($expected, $in); $filter = PDF::Builder::Basic::PDF::Filter::LZWDecode->new(); $out = $filter->outfilt($in); is $out, $expected, 'compress binary data'; ### $repeat = 30000; $in = ''; for (0..$repeat) {$in .= chr(int(rand(256)))} #-#note( 'Test data size: ' . length($in) ); $filter = PDF::Builder::Basic::PDF::Filter::LZWDecode->new(); $out = $filter->outfilt($in); #-#note( 'Final bits: '.$filter->{'code_length'} ); $filter = PDF::Builder::Basic::PDF::Filter::LZWDecode->new(); is $filter->infilt($out), $in, 'Data decompresses unchanged after reaching max code length'; ### $in = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; my $height = 2; $filter = PDF::Builder::Basic::PDF::Filter::LZWDecode->new({Predictor => PDFNum(2), Rows=>PDFNum($height), Columns=>PDFNum(length($in)/$height)}); $out = $filter->outfilt($in); is $filter->infilt($out), $in, 'LZWDecode test string round-tripped correctly with horizontal predictor'; ### $in = '000FFF000000FFF000'; $height = 2; my $colors = 3; $filter = PDF::Builder::Basic::PDF::Filter::LZWDecode->new({Predictor => PDFNum(2), Rows=>PDFNum($height), Columns=>PDFNum(length($in)/$height/$colors), Colors=>PDFNum($colors)}); $out = $filter->outfilt($in); is $filter->infilt($out), $in, 'LZWDecode test string round-tripped correctly with horizontal predictor + 3 color channels'; ### $in = pack "H*", '0000FFFFFFFF0000'; $expected = pack "H*", '0000FF00FF000100'; $filter = PDF::Builder::Basic::PDF::Filter::LZWDecode->new({Predictor => PDFNum(2), Rows=>PDFNum($height), Columns=>PDFNum(length($in)/$height)}); $out = $filter->_predict($in); is $out, $expected, 'predict binary data with overflow'; PDF-Builder-3.026/t/resources/0000755000000000000000000000000014534671355014511 5ustar rootrootPDF-Builder-3.026/t/resources/sample-xrefstm-index.pdf0000644000000000000000000001046513756522545021267 0ustar rootroot%PDF-1.5 %Çìó¢ 1 0 obj << /Type /Catalog /ViewerPreferences << /NonFullScreenPageMode /UseNone >> /PageLayout /SinglePage /Pages 2 0 R /PageMode /UseNone >> endobj 2 0 obj << /Type /Pages /Kids [ 6 0 R ] /Resources 3 0 R /Count 1 >> endobj 3 0 obj << /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> endobj 4 0 obj << /Producer (Edited by hand on Linux) >> endobj 5 0 obj << /Type /Font /Subtype /Type1 /FirstChar 32 /Encoding << /Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences [ 0 /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /space /exclam /quotedbl /numbersign /dollar /percent /ampersand /quotesingle /parenleft /parenright /asterisk /plus /comma /hyphen /period /slash /zero /one /two /three /four /five /six /seven /eight /nine /colon /semicolon /less /equal /greater /question /at /A /B /C /D /E /F /G /H /I /J /K /L /M /N /O /P /Q /R /S /T /U /V /W /X /Y /Z /bracketleft /backslash /bracketright /asciicircum /underscore /grave /a /b /c /d /e /f /g /h /i /j /k /l /m /n /o /p /q /r /s /t /u /v /w /x /y /z /braceleft /bar /braceright /asciitilde /bullet /Euro /bullet /quotesinglbase /florin /quotedblbase /ellipsis /dagger /daggerdbl /circumflex /perthousand /Scaron /guilsinglleft /OE /bullet /Zcaron /bullet /bullet /quoteleft /quoteright /quotedblleft /quotedblright /bullet /endash /emdash /tilde /trademark /scaron /guilsinglright /oe /bullet /zcaron /Ydieresis /space /exclamdown /cent /sterling /currency /yen /brokenbar /section /dieresis /copyright /ordfeminine /guillemotleft /logicalnot /hyphen /registered /macron /degree /plusminus /twosuperior /threesuperior /acute /mu /paragraph /periodcentered /cedilla /onesuperior /ordmasculine /guillemotright /onequarter /onehalf /threequarters /questiondown /Agrave /Aacute /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla /Egrave /Eacute /Ecircumflex /Edieresis /Igrave /Iacute /Icircumflex /Idieresis /Eth /Ntilde /Ograve /Oacute /Ocircumflex /Otilde /Odieresis /multiply /Oslash /Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn /germandbls /agrave /aacute /acircumflex /atilde /adieresis /aring /ae /ccedilla /egrave /eacute /ecircumflex /edieresis /igrave /iacute /icircumflex /idieresis /eth /ntilde /ograve /oacute /ocircumflex /otilde /odieresis /divide /oslash /ugrave /uacute /ucircumflex /udieresis /yacute /thorn /ydieresis ] >> /BaseFont /Helvetica /LastChar 255 /Widths [ 278 278 355 556 556 889 667 191 333 333 389 584 278 333 278 278 556 556 556 556 556 556 556 556 556 556 278 278 584 584 584 556 1015 667 667 722 722 667 611 778 722 278 500 667 556 833 722 778 667 778 722 667 611 722 667 944 667 667 611 278 278 278 469 556 333 556 556 500 556 556 278 556 556 222 222 500 222 833 556 556 556 556 333 500 278 556 500 722 500 500 500 334 260 334 584 350 556 350 222 556 333 1000 556 556 333 1000 667 333 1000 350 611 350 350 222 222 333 333 350 556 1000 333 1000 500 333 944 350 500 667 278 333 556 556 556 556 260 556 333 737 370 556 584 333 737 333 400 584 333 333 333 556 537 278 333 333 365 556 834 834 834 611 667 667 667 667 667 667 1000 722 667 667 667 667 278 278 278 278 722 722 778 778 778 778 778 584 778 722 722 722 722 667 667 611 556 556 556 556 556 556 889 500 556 556 556 556 278 278 278 278 556 556 556 556 556 556 556 584 611 556 556 556 556 500 556 500 ] /Name /HelvCBB~1299252700 >> endobj 6 0 obj << /Type /Page /Contents [ 7 0 R ] /Parent 2 0 R /Resources << /Font 9 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> >> endobj 7 0 obj << /Length 60 >> stream BT /HelvCBB~1299252700 12 Tf [ (Hello World!) ] TJ ET endstream endobj 8 0 obj << /Type /ObjStm /N 1 /First 9 /Length 43 >> stream 12 0 9 3 123<< /HelvCBB~1299252700 5 0 R >> endstream endobj 10 0 obj << /Type /XRef /Root 1 0 R /Info 4 0 R /Size 7 /W [1 2 2] /Filter /ASCIIHexDecode /Length 90 >> stream 00 0000 ffff 01 000f 0000 01 00a4 0000 01 00f0 0000 01 0135 0000 01 016e 0000 01 0de5 0000 endstream endobj 11 0 obj << /Type /XRef /Root 1 0 R /Info 4 0 R /Size 13 /W [1 2 2] /Filter /ASCIIHexDecode /Length 78 /Index [7 7] /Prev 3932 >> stream 01 0e75 0000 01 0ee3 0000 02 0008 0001 01 0f5c 0000 01 1038 0000 02 0008 0000 endstream endobj startxref 4152 %%EOF PDF-Builder-3.026/t/resources/1x1-lzw.tif0000644000000000000000000004432012667371630016441 0ustar rootrootII*þžHòú(12¼M=2I† €>i‡¤H€ü '€ü 'Adobe Photoshop CS4 Windows2011:03:04 11:16:43 Adobe Photoshop CS4 Windows 2011-03-04T11:16:43-05:00 2011-03-04T11:16:43-05:00 2011-03-04T11:16:43-05:00 image/tiff xmp.iid:57B895CB7A46E011A46AFE1DB39C4641 xmp.did:57B895CB7A46E011A46AFE1DB39C4641 xmp.did:57B895CB7A46E011A46AFE1DB39C4641 created xmp.iid:57B895CB7A46E011A46AFE1DB39C4641 2011-03-04T11:16:43-05:00 Adobe Photoshop CS4 Windows 1 720000/10000 720000/10000 2 256,257,258,259,262,274,277,284,530,531,282,283,296,301,318,319,529,532,306,270,271,272,305,315,33432;CF5B90DC7ECAC651CE28BAEADB408F02 1 1 1 5 0 1 1 1 65535 36864,40960,40961,37121,37122,40962,40963,37510,40964,36867,36868,33434,33437,34850,34852,34855,34856,37377,37378,37379,37380,37381,37382,37383,37384,37385,37386,37396,41483,41484,41486,41487,41488,41492,41493,41495,41728,41729,41730,41985,41986,41987,41988,41989,41990,41991,41992,41993,41994,41995,41996,42016,0,2,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,20,22,23,24,25,26,27,28,30;2B394B6A01F58AFEE00C10B419784CBE 0 8BIM%8BIMíHH8BIM&?€8BIM x8BIM8BIMó 8BIM' 8BIM@@8BIM6¨nullVrsnlongenabbool numBeforelongnumAfterlongSpcnlong minOpacitylong maxOpacitylong2BlnMlong8BIM3null Vrsnlong frameStepObjcnull numeratorlong denominatorlongX frameRatedoub@>timeObjcnull numeratorlong denominatorlongXdurationObjcnull numeratorlongp denominatorlongX workInTimeObjcnull numeratorlong denominatorlongX workOutTimeObjcnull numeratorlongp denominatorlongXLCntlongglobalTrackListVlLs hasMotionbool8BIM4FnullVrsnlongsheetTimelineOptionsVlLs8BIM8BIMI Untitled-1nullboundsObjcRct1Top longLeftlongBtomlongRghtlongslicesVlLsObjcslicesliceIDlonggroupIDlongoriginenum ESliceOrigin autoGeneratedTypeenum ESliceTypeImg boundsObjcRct1Top longLeftlongBtomlongRghtlongurlTEXTnullTEXTMsgeTEXTaltTagTEXTcellTextIsHTMLboolcellTextTEXT horzAlignenumESliceHorzAligndefault vertAlignenumESliceVertAligndefault bgColorTypeenumESliceBGColorTypeNone topOutsetlong leftOutsetlong bottomOutsetlong rightOutsetlong8BIM( ?ð8BIM8BIM8BIM D(ÿØÿàJFIFHHÿí Adobe_CMÿîAdobed€ÿÛ„            ÿÀ"ÿÝÿÄ?   3!1AQa"q2‘¡±B#$RÁb34r‚ÑC%’Sðáñcs5¢²ƒ&D“TdE£t6ÒUâeò³„ÃÓuãóF'”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷5!1AQaq"2‘¡±B#ÁRÑð3$bár‚’CScs4ñ%¢²ƒ&5ÂÒD“T£dEU6teâò³„ÃÓuãóF”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö'7GWgw‡—§·ÇÿÚ ?ò¤’I%?ÿÙ8BIM!UAdobe PhotoshopAdobe Photoshop CS4€  ÿÿ  PDF-Builder-3.026/t/resources/1x1.pbm0000644000000000000000000000001612776602200015604 0ustar rootrootP6 1 1 255 PDF-Builder-3.026/t/resources/1x1.png0000644000000000000000000000012212667371632015623 0ustar rootroot‰PNG  IHDR%ÛVÊPLTE§z=Ú IDAT™c`ôqd¦IEND®B`‚PDF-Builder-3.026/t/resources/sample-xrefstm.pdf0000644000000000000000000001022013756522472020146 0ustar rootroot%PDF-1.5 %Çìó¢ 1 0 obj << /Type /Catalog /ViewerPreferences << /NonFullScreenPageMode /UseNone >> /PageLayout /SinglePage /Pages 2 0 R /PageMode /UseNone >> endobj 2 0 obj << /Type /Pages /Kids [ 6 0 R ] /Resources 3 0 R /Count 1 >> endobj 3 0 obj << /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> endobj 4 0 obj << /Producer (Edited by hand on Linux) >> endobj 5 0 obj << /Type /Font /Subtype /Type1 /FirstChar 32 /Encoding << /Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences [ 0 /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /space /exclam /quotedbl /numbersign /dollar /percent /ampersand /quotesingle /parenleft /parenright /asterisk /plus /comma /hyphen /period /slash /zero /one /two /three /four /five /six /seven /eight /nine /colon /semicolon /less /equal /greater /question /at /A /B /C /D /E /F /G /H /I /J /K /L /M /N /O /P /Q /R /S /T /U /V /W /X /Y /Z /bracketleft /backslash /bracketright /asciicircum /underscore /grave /a /b /c /d /e /f /g /h /i /j /k /l /m /n /o /p /q /r /s /t /u /v /w /x /y /z /braceleft /bar /braceright /asciitilde /bullet /Euro /bullet /quotesinglbase /florin /quotedblbase /ellipsis /dagger /daggerdbl /circumflex /perthousand /Scaron /guilsinglleft /OE /bullet /Zcaron /bullet /bullet /quoteleft /quoteright /quotedblleft /quotedblright /bullet /endash /emdash /tilde /trademark /scaron /guilsinglright /oe /bullet /zcaron /Ydieresis /space /exclamdown /cent /sterling /currency /yen /brokenbar /section /dieresis /copyright /ordfeminine /guillemotleft /logicalnot /hyphen /registered /macron /degree /plusminus /twosuperior /threesuperior /acute /mu /paragraph /periodcentered /cedilla /onesuperior /ordmasculine /guillemotright /onequarter /onehalf /threequarters /questiondown /Agrave /Aacute /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla /Egrave /Eacute /Ecircumflex /Edieresis /Igrave /Iacute /Icircumflex /Idieresis /Eth /Ntilde /Ograve /Oacute /Ocircumflex /Otilde /Odieresis /multiply /Oslash /Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn /germandbls /agrave /aacute /acircumflex /atilde /adieresis /aring /ae /ccedilla /egrave /eacute /ecircumflex /edieresis /igrave /iacute /icircumflex /idieresis /eth /ntilde /ograve /oacute /ocircumflex /otilde /odieresis /divide /oslash /ugrave /uacute /ucircumflex /udieresis /yacute /thorn /ydieresis ] >> /BaseFont /Helvetica /LastChar 255 /Widths [ 278 278 355 556 556 889 667 191 333 333 389 584 278 333 278 278 556 556 556 556 556 556 556 556 556 556 278 278 584 584 584 556 1015 667 667 722 722 667 611 778 722 278 500 667 556 833 722 778 667 778 722 667 611 722 667 944 667 667 611 278 278 278 469 556 333 556 556 500 556 556 278 556 556 222 222 500 222 833 556 556 556 556 333 500 278 556 500 722 500 500 500 334 260 334 584 350 556 350 222 556 333 1000 556 556 333 1000 667 333 1000 350 611 350 350 222 222 333 333 350 556 1000 333 1000 500 333 944 350 500 667 278 333 556 556 556 556 260 556 333 737 370 556 584 333 737 333 400 584 333 333 333 556 537 278 333 333 365 556 834 834 834 611 667 667 667 667 667 667 1000 722 667 667 667 667 278 278 278 278 722 722 778 778 778 778 778 584 778 722 722 722 722 667 667 611 556 556 556 556 556 556 889 500 556 556 556 556 278 278 278 278 556 556 556 556 556 556 556 584 611 556 556 556 556 500 556 500 ] /Name /HelvCBB~1299252700 >> endobj 6 0 obj << /Type /Page /Contents [ 7 0 R ] /Parent 2 0 R /Resources << /Font 9 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> >> endobj 7 0 obj << /Length 60 >> stream BT /HelvCBB~1299252700 12 Tf [ (Hello World!) ] TJ ET endstream endobj 8 0 obj << /Type /ObjStm /N 2 /First 9 /Length 43 >> stream 11 0 9 3 123<< /HelvCBB~1299252700 5 0 R >> endstream endobj 10 0 obj << /Type /XRef /Root 1 0 R /Info 4 0 R /Size 12 /W [1 2 2] /Filter /ASCIIHexDecode /Length 155 >> stream 00 0000 ffff 01 000f 0000 01 00a4 0000 01 00f0 0000 01 0135 0000 01 016e 0000 01 0de5 0000 01 0e75 0000 01 0ee3 0000 02 0008 0001 01 0f5c 0000 02 0008 0000 endstream endobj startxref 3932 %%EOF PDF-Builder-3.026/t/resources/1x1.tif0000644000000000000000000005175012667371632015636 0ustar rootrootII*þ ¶S(1 2<¼>PI†f?i‡¼Ss‡H nG€ü '€ü 'Adobe Photoshop CS4 Windows2011:03:04 10:14:02 Adobe Photoshop CS4 Windows 2011-03-04T10:14:02-05:00 2011-03-04T10:14:02-05:00 2011-03-04T10:14:02-05:00 image/tiff xmp.iid:C236C4097246E011ADE4D8D6BB511D5D xmp.did:C236C4097246E011ADE4D8D6BB511D5D xmp.did:C236C4097246E011ADE4D8D6BB511D5D created xmp.iid:C236C4097246E011ADE4D8D6BB511D5D 2011-03-04T10:14:02-05:00 Adobe Photoshop CS4 Windows 1 720000/10000 720000/10000 2 256,257,258,259,262,274,277,284,530,531,282,283,296,301,318,319,529,532,306,270,271,272,305,315,33432;00AC7A9F766C16C4AF92865A8001BC55 1 1 8 8 8 1 2 3 1 1 1 1 36864,40960,40961,37121,37122,40962,40963,37510,40964,36867,36868,33434,33437,34850,34852,34855,34856,37377,37378,37379,37380,37381,37382,37383,37384,37385,37386,37396,41483,41484,41486,41487,41488,41492,41493,41495,41728,41729,41730,41985,41986,41987,41988,41989,41990,41991,41992,41993,41994,41995,41996,42016,0,2,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,20,22,23,24,25,26,27,28,30;88353302ACFF76240E76AAF38CF46E36 3 sRGB IEC61966-2.1 8BIM%8BIMíHH8BIM&?€8BIM x8BIM8BIMó 8BIM' 8BIMõH/fflff/ff¡™š2Z5-8BIMøpÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿèÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿèÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿèÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿè8BIM8BIM8BIM08BIM-8BIM@@8BIM8BIMI Untitled-1nullboundsObjcRct1Top longLeftlongBtomlongRghtlongslicesVlLsObjcslicesliceIDlonggroupIDlongoriginenum ESliceOrigin autoGeneratedTypeenum ESliceTypeImg boundsObjcRct1Top longLeftlongBtomlongRghtlongurlTEXTnullTEXTMsgeTEXTaltTagTEXTcellTextIsHTMLboolcellTextTEXT horzAlignenumESliceHorzAligndefault vertAlignenumESliceVertAligndefault bgColorTypeenumESliceBGColorTypeNone topOutsetlong leftOutsetlong bottomOutsetlong rightOutsetlong8BIM( ?ð8BIM8BIM E)ÿØÿàJFIFHHÿí Adobe_CMÿîAdobed€ÿÛ„            ÿÀ"ÿÝÿÄ?   3!1AQa"q2‘¡±B#$RÁb34r‚ÑC%’Sðáñcs5¢²ƒ&D“TdE£t6ÒUâeò³„ÃÓuãóF'”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷5!1AQaq"2‘¡±B#ÁRÑð3$bár‚’CScs4ñ%¢²ƒ&5ÂÒD“T£dEU6teâò³„ÃÓuãóF”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö'7GWgw‡—§·ÇÿÚ ?õT—Ê©$§ÿÙ8BIM!UAdobe PhotoshopAdobe Photoshop CS4 HLinomntrRGB XYZ Î 1acspMSFTIEC sRGBöÖÓ-HP cprtP3desc„lwtptðbkptrXYZgXYZ,bXYZ@dmndTpdmddĈvuedL†viewÔ$lumiømeas $tech0 rTRC< gTRC< bTRC< textCopyright (c) 1998 Hewlett-Packard CompanydescsRGB IEC61966-2.1sRGB IEC61966-2.1XYZ óQÌXYZ XYZ o¢8õXYZ b™·…ÚXYZ $ „¶ÏdescIEC http://www.iec.chIEC http://www.iec.chdesc.IEC 61966-2.1 Default RGB colour space - sRGB.IEC 61966-2.1 Default RGB colour space - sRGBdesc,Reference Viewing Condition in IEC61966-2.1,Reference Viewing Condition in IEC61966-2.1view¤þ_.ÏíÌ \žXYZ L VPWçmeassig CRT curv #(-27;@EJOTY^chmrw|†‹•šŸ¤©®²·¼ÁÆËÐÕÛàåëðöû %+28>ELRY`gnu|ƒ‹’š¡©±¹ÁÉÑÙáéòú &/8AKT]gqz„Ž˜¢¬¶ÁËÕàëõ !-8COZfr~Š–¢®ºÇÓàìù -;HUcq~Œš¨¶ÄÓáðþ +:IXgw†–¦µÅÕåö'7HYj{Œ¯ÀÑãõ+=Oat†™¬¿Òåø 2FZn‚–ª¾Òçû  % : O d y ¤ º Ï å û  ' = T j ˜ ® Å Ü ó " 9 Q i € ˜ ° È á ù  * C \ u Ž § À Ù ó & @ Z t Ž © Ã Þ ø.Id›¶Òî %A^z–³Ïì &Ca~›¹×õ1OmŒªÉè&Ed„£Ãã#Ccƒ¤Åå'Ij‹­Îð4Vx›½à&Il²ÖúAe‰®Ò÷@eНÕú Ek‘·Ý*QwžÅì;cвÚ*R{£ÌõGp™Ãì@j”¾é>i”¿ê  A l ˜ Ä ð!!H!u!¡!Î!û"'"U"‚"¯"Ý# #8#f#”#Â#ð$$M$|$«$Ú% %8%h%—%Ç%÷&'&W&‡&·&è''I'z'«'Ü( (?(q(¢(Ô))8)k))Ð**5*h*›*Ï++6+i++Ñ,,9,n,¢,×- -A-v-«-á..L.‚.·.î/$/Z/‘/Ç/þ050l0¤0Û11J1‚1º1ò2*2c2›2Ô3 3F33¸3ñ4+4e4ž4Ø55M5‡5Â5ý676r6®6é7$7`7œ7×88P8Œ8È99B99¼9ù:6:t:²:ï;-;k;ª;è<' >`> >à?!?a?¢?â@#@d@¦@çA)AjA¬AîB0BrBµB÷C:C}CÀDDGDŠDÎEEUEšEÞF"FgF«FðG5G{GÀHHKH‘H×IIcI©IðJ7J}JÄK KSKšKâL*LrLºMMJM“MÜN%NnN·OOIO“OÝP'PqP»QQPQ›QæR1R|RÇSS_SªSöTBTTÛU(UuUÂVV\V©V÷WDW’WàX/X}XËYYiY¸ZZVZ¦Zõ[E[•[å\5\†\Ö]']x]É^^l^½__a_³``W`ª`üaOa¢aõbIbœbðcCc—cëd@d”dée=e’eçf=f’fèg=g“géh?h–hìiCišiñjHjŸj÷kOk§kÿlWl¯mm`m¹nnknÄooxoÑp+p†pàq:q•qðrKr¦ss]s¸ttptÌu(u…uáv>v›vøwVw³xxnxÌy*y‰yçzFz¥{{c{Â|!||á}A}¡~~b~Â#„å€G€¨ kÍ‚0‚’‚ôƒWƒº„„€„ã…G…«††r†×‡;‡ŸˆˆiˆÎ‰3‰™‰þŠdŠÊ‹0‹–‹üŒcŒÊ1˜ÿŽfŽÎ6žnÖ‘?‘¨’’z’ã“M“¶” ”Š”ô•_•É–4–Ÿ— —u—à˜L˜¸™$™™üšhšÕ›B›¯œœ‰œ÷dÒž@ž®ŸŸ‹Ÿú i Ø¡G¡¶¢&¢–££v£æ¤V¤Ç¥8¥©¦¦‹¦ý§n§à¨R¨Ä©7©©ªª««u«é¬\¬Ð­D­¸®-®¡¯¯‹°°u°ê±`±Ö²K²Â³8³®´%´œµµŠ¶¶y¶ð·h·à¸Y¸Ñ¹J¹Âº;ºµ».»§¼!¼›½½¾ ¾„¾ÿ¿z¿õÀpÀìÁgÁãÂ_ÂÛÃXÃÔÄQÄÎÅKÅÈÆFÆÃÇAÇ¿È=ȼÉ:ɹÊ8Ê·Ë6˶Ì5̵Í5͵Î6ζÏ7ϸÐ9кÑ<ѾÒ?ÒÁÓDÓÆÔIÔËÕNÕÑÖUÖØ×\×àØdØèÙlÙñÚvÚûÛ€ÜÜŠÝÝ–ÞÞ¢ß)߯à6à½áDáÌâSâÛãcãëäsäü儿 æ–çç©è2è¼éFéÐê[êåëpëûì†ííœî(î´ï@ïÌðXðåñrñÿòŒóó§ô4ôÂõPõÞömöû÷Šøø¨ù8ùÇúWúçûwüü˜ý)ýºþKþÜÿmÿÿÿÿÿ   PDF-Builder-3.026/t/resources/1x1.gif0000644000000000000000000000004312667371630015604 0ustar rootrootGIF87a€,D;PDF-Builder-3.026/t/resources/test-rgba.png0000644000000000000000000006364114154035131017101 0ustar rootroot‰PNG  IHDR|B‡}>gAMA±Ž|ûQ“ cHRMo?r‡ô$„Ïm_èj<‹W§–mªg,IDATxœbüÿÿ?Ã(£`Œ‚áˆi 0 FÁ(£€> €F üQ0 FÁ(! €F üQ0 FÁ(! €F üQ0 FÁ(! €F üQ0 FÁ(! €F üQ0 FÁ(! €F üQ0 9]:= ¨h´À£`ƒÿþ3Œ–÷£€Z €G[£`Œ‚Q02@¶ðGÁ(£`„€-ðGÁ(£`„€-ðGÁ(£`„€-ðGÁ(£`„€-ðGÁ(£`„€-ðGÁ(£`„€-ðGÁ(£`„€-ðGÁ(£`„€-ðGÁ(£`„€-ðGÁ(£`„€-ðGÁ(£`„€-ðGÁ(£`„€-ðGÁ(£`„€-ðGÁ(£`„€-ðGÁ(£`„€-ðGÁ(£`„€-ðGÁ(£`„€-ðGÁ(£`„€-ðGÁ(£`„€-ðGÁ(£`„€-ðGÁ(äàÿ£€R@,í€Q0 F~ÀÈ8Ð.ÃÐh Œ‚Q0 F ÑŒ‚Q0 F ÑŒ‚Q0 F ÑŒ‚Q0 F ÑŒ‚Q0 F ÑŒ‚Q0 F ÑŒ‚Q0 F ÑŒ‚Q0 F ÑŒ‚Q0 F ÑŒ‚Q0 F ÑŒ‚Q0 F ÑŒ‚Q0 F ÑŒ‚Q0 F ÑŒ‚Q0 F ÑŒ‚Q0 F ÑŒ‚Q0 F ÑŒ‚Q0 F ÑŒ‚Q0 F ÑŒ‚Q0 F ÑŒ‚Q0 F ÑŒ‚Q0 F ÑŒ‚Q0 F ÑŒ‚Q0 F ÑŒ‚Q0 F ÑŒ‚Q0 F ÑŒ‚Q0 F ÑŒ‚Q0 F ÑŒ‚Q0 F –vÀ(C D–,óRî ŒŒÚ@Z›È``dø"€èµŠñÿö¥áŸÚ­£` €büÿÿ?Ý,SLWRÜdhæ$†—7×Ï|4C—Hõÿ¡4Àì UÁˆPvÈãfdd”€Ã3 Ìgm0ø$‡ÄúriUÿR=7 †ˆ(YªŒä^`ÜëÓ8õ ¥FXrøÏð¨¦pIgØñtò(( €èÝÂObm(›Fèò5@ü ˆ›qèE7B+:`ÆeD(·ÒÊ œNˆÂÿ°< $ÿƒuþG©"þ³=X!ÔÜ‹@\ŒÃ?£`àÂ|kûˆn û Õ©èÿÿc€$Fpúÿšª@Í'FF¦ÿ ”Á \S¾ºxIgè*ZùcŒR@Ñ{ ÿƒ È¿Hührÿ‘Ø ú°ujÆ45ÿ°°ÿca£©cüÇ¢ÿ1#ÿ¹‡áúÚi—€UÁQ4}E;D-”T2¨¬ï?È,H΃Îç–Í‹‰U^²$˜&ºþÃÓ,#,Îÿƒ ÿÿÐt¢a|Hÿ”þwÇT¬¶¤™gFÁ( ½ |X!ú—³0F.ÑÅW"™­’øË€¨@þ¢‰c˜)œ‘äÿƒ!L¨±6 ˜aAîFF¨JË™{ÁýIÝe`ëþ*’¸zØÌý .œ½opÆfØÿˆŒ ×ÖN{ äìe\ˆÜ0þVy02BZxŒˆÞh ƒ ‚y¼ÿÿ/Æš:$-À8ÎÆ*¤‚÷òþ‚ óÿÐtñÿ?¬¢‡÷ S<aâÀô![±&„†^£€(@9¤ƒk(½u¿‡¸0º9è½ °¨u)¨ÿ#*F”{h¸†nhR9@+Ѐí_¤–Ü?D•1 ,˜§ŒË5ŒÿÕái…0øÏNà!#\´âø?:¤3APþ\u`¡<A’ÿ¡®ÿ!…5^V²D¨ˆi¸¬&jã024ë‰M ˆþÈj-ðуà]ÛÈö'ˆ`³€½U`a¿”&ž£€D@]à£Ý¶î“`¶ñzlC<ÈG9@ÖIÿG¬¡ÿè’ã,ò¯®™ü˜Ñýg@ÚxkEÂímáðÏ¥¤ú¥9'$W`‡VþÃçZ Ã9¤l’[ÙóˆA‡öõñ§ÿð4ňÎúŒˆ¹H¥3sIghõ}< Fy €rH Ê,[I0¹ Ç×êÇŠaÝpX‹÷X·‡|¦Î?Fä%x£ëðéürgºã­ð\³¾ÁKeaC-ÿa󌈉Wp¯ŒˆI[t°¢'z%P_ Ù4í&Ê!|Hïš dø-í ›E]ߎ‚Q@ Üx…¾Qê$°uÿ–H3`z`‹ßð-Ë„±ajÿ1ÀöÝ@EÀ‹+1ÍÀW€­|мu@ft=>ÔÈ’m"Övê`aï ÷è[”tõzÞ5#R,CS‚ϸdüÏ@z+º£¿0@óèYºÂÉÞ[K»Â¿Pâ§Q0 h h ×á#ï¬ÝN¤È•˜¶XvÛB®}vÿ¾íòQK³A‡ª10ºi.ÈJè=G-–£-|:ßÜnÀh+aüÏôé $p¼CwÃ"n¸ÊýGì‹Å¶—,°¼;âÖùØŠ Øú{ø>ãºWVOþ¤v3ÀV|ÀVû€ON´¥ðË™á ,³‹ áý>.[=Æ6Ì™¬…·#–7 FÁ4PC:È-{ØI‚°3t`×p¶Ö?Rw|”ÎâZõ¨¨ctC[’›±H˜4Ž,ÇnÔ'Ô,ÇZ7ÎÈxýÌÒŽNdufÑ•@ñJh?âMƒèë'7¿!Ùñ$ÇäQ ]ÚÀ°RÒ¢@·,Ø7»ìµsj7踂l Ÿ±ÿ˜Ñ¥·¯!ÃíL1Àä`ƒ+`ÅL Þ¾mÓr‰Ú˜ä—3Ýhn!dîbÚØá5Ðq›ÿÿNŸiOð!¾Âù=§Á¯,ƒ9õîªÞ8ÐÆ-Ðå'@¸ÿ‡;æˆ>Ⱦ]ÁÈÀ¹‹ÙŸŒ°ÅóÅ¡X{±ñ•ëò€f©¡t<À &¤]¼hA9Ͷ]âÆ­³š<· ›^¿Ã(éÃøîèŒpßÞê½ 93µÎù1q@MPÚy ˜ù€NÑrynX÷¹«Ì¤ Y]eÏy üÿjDÈ"4ªá#v8ò4²`sK‘.ú¡Œ#Ð@ éÀ |X|†„Ö=º0€­gÀ"×Òð€ù‰Ø«.¯žôM74T@ùÀLjÿÃÅ Œ"K€£ PµÐnX9 ™Wd„´LÑ#t Š<&¡$Ôy×d¡ElíY v_ÔŒíÌ!Š€Cr;èþVO ­¦pW02,ö ù½³K¿ ýU@75Å‘ï)f‚¬A‡•ê°«$¡ÁÄ[eOð)ÓŒ—‰q“oÎtg ž|FÈYóHe#Rf‡l¸øÿQügD¤ˆ3tUB!R<â@ÁX¸]ÐÝ0w .Äd€Z+ü¡i tý%®aKÐ*#}H‹Q®ƒúLÐzUŽî?HÉsöYL£%Ž5Bò##ríL– ›!@Fd7í» T±XðoÆáNª€’Ž xt2]A X”0Âv ]м ´ˆrꂃ³ØK|ä2‚J^r €z v“hlý4¾–<2@WÎ댈$= Ö$0þªæÔ‰Ô.Ã9L`Yâ ´Â ˜¤¹¡Nø‡p”…µ‡®þ1@/Jeüu,¤ÝldYÆÕ*\v|QÓ7â=€ {Pç ½¿z0ÃþÙ(«¨€…þ—Ôž ³Žtù;lòô?tfÑþEtªÀœÿïÂd+Z`aT›‡4ÿ‚<@ÿ:mÎs2Ø*Dó! Hص 7@F8ÿ#ÍAlù+µ!U2ãx óÙ!ÿU ¬Ô†ž¬óÿ±< ÿÐÂRŽCV¡TbP ð^ ¬ÀþÏ€-ýþ‡êSoB€3tñ¼ÂP²ë€*P¤qJ­– „вÃ6`è퟼Æç…RBFB6Ÿ½Vy;lÊ?¡ ~CªµÎ4Yõ9v² ˆ*J1Q.QðŽ!Âçɦ˜;v2XXðŽàŸ²AÑ¥gNô+Y” éº:”©,Cü [JÔ[ýu/ôÿã~~q÷ß! –¡QRP2áI§˜jƒvo·MgÒD9 N'•yg¯dˆI0-z7ù’lBò,˜z|!}i¦˜8i©¹|¿Ò ['D!s§öfÿ}n{ÐúS´A×ÀÜ7­¯q0‘R-æl ‚Þi°ý!=Ç™¦z"uŠb‰ e52,FËséE݃ŸÉêÚp?;÷­bv+”ˆ ‡úÇ$|oÿç'6é<ȳšñׄÿ€¼+Öi †¡và/˜ØYA0ÁwTêÐ ‰ é$`de@]øª*Hü ;+ƉßKr¢J DjÓëÇιî³ïî/ªtXe³þ¶«³î{öÖŸ¡X;(;èo»æ>ñÙéN4Uì4²ùмpÎ;‰Z©‰(Í€m[#Ò†3–/m’”bç¤ÈwSD|<n^Ÿ†­0ýÓÙí¡³8B•-E¶µÁãÓDìÜþÞjqµèù,/_Îæ÷ió‚ [ÜXkBŽ\‰K\!;nîìSDøæ.a€z¨¿}ï¦Â«&qG\ެÂö&ô•¼@£×"p³uœõ{•D…ÿ&Æb„þs‘F­êšð¹XfËd?8%ÁùĪ|/¥‰Ö.Ë€Öá…gßFÆù¢"nÿãÿS Ô¤í`ëþ™fÀ2,c êÈ?’Šü.øz°$'„K«'~× +¶nÜa‰J?¼(HI2€/º†ÙËI¬ð‹W`Ù© „tÕ±¹üür FD9«$ ³‡ˆ5i@QPWýxìà?c8dÈà?R ^fˆâˆé`VΩ]ÿ÷Î.›‹n°Ð?ìš:r†!l êü8´û÷Ù¸'PÀÖ©Ù BcéœoÎôÿÿ!—’À¦4aSxÐÉ\ئgFjdf6‘ ZÓŸp…`Ø@ ‘¿HóÏŒ°yZ&Øô0¢ü„ÿ¶Tk ŒøŽÎfÏ»þƒE-ÌœÿðZ“á|Á't‰"õÃÖ-eÂRPÂ4QM;p{aY"‚ÔÓñ` ²Àöª@ÍSÀG‰ÃRP«ÿCBÚ)ÿᣨЋi`é Ã-/ 3™“äðÅYÿáXÉ÷>*Iz‹n˜€ä=Â0 …#p$F3,Hœ‰V&ÄÈ à(,&ÄX=Ò$Ïq˯`` [DÚÚ yŸ‹ý †_.äó—sXI[O±lûdžâó±?½›]Ê“e{4oú~_[G܈ •¤.¡§ðÝ”©)Ûæ“.%°Ë%‰hCålD=áþÓ‚ôƫ֫ ÷§ûŽ_m ©òÏ(³uä ¡Âdd~ÓN7“{sî·‹“¿Q…3¨->sÚ ám¥7S³  XVñQ‰+ÂÆ`²˜‚XÊŽ}SÚóWD´èI!±P"1I®` ãhîžlžÝ#¬]éÙOùì„F¶…A…ÂXÂÍåà,ǘL\Šœ Û@‘0UèÏÖ‡n}îm‰ðŸ’4Ÿ#ò²±‰ßÁÄ´„~BVmIdô³~Ô.6`n?ƒdûýþe» @Þµã ÃÐø,ììÌlÜ$vĘXX¹G`D¹ ,åÑøƒRQÁÀ@†ªªÒ4uêgËÏÃ?wÞýíË1¢‚ÅÅ­Åñï=פ-!*ÕGírØ]»ÛO̽QÊÛ.XN}ˆ1*éç D¾›=¿ ´L„dïjÀP²+ÚÏÉcÍHs¬Cç•ðø°¹ ¢´H“ér;¯ {ܯ› úéUñr5(Vtv$[ÄÁÂ&‹ý;ÉäŸË<¥2•Æ%„÷ðøu¬M;¤YÅ*1|ɲ|Ð ž]"I³žÉSžø„¾f}Ú´Ð5Pp–²¯‹’µ0þ§nTdNåÛóõPAþ:w‡®G"3ÞIjµiÜ¿K*»ÉNx°ËÛH o"—¡ê=à£TXŸgHÑö:| ö¹= ïÚq†ah½3p`ggç\€…ÛpŽǪ&yþ´i+$$†ªjIâ†Ç³ýjÿðßIÎo{{6l}t4¥Óçþ•1ÛI»/æõÐàZÏ[/Û)-,±ÊF}~mÒ5êä K)8Á“ 1«9P@{eù›ÅYKw¨$I0…«E @"+T¸]‹÷q<]o—©¯VÐê=÷dzeÝìCL¾p67ÝúTã™IJÊŽŸ2ðôxgbÓŸŒÇ Gß…ŒÓâí}ì!3…É5£t‡Ëg—ÆónköÇo¶òÄ0¢ÆõLÅ}oRÄ™1,qŒšµJë'Ùá^¥mh')!¦ $"»%;)دôš³íû¢,sé$™9(N€•5¡üÔ¤ÑÃ.bC uYýemª×bë‘ìµ´`oxð× ÿ%ygo„0 Ca«#° 4lÀ =;P2 ‹0+q+zO „ðwGƒ«¾sâXÒ'ùÅùµÃ?}I÷µ EîüR‡#½âÈÜŽ!Ü*åK^|A¡žUÃðY6ñ°$êêÕ£[ñÙœI¡B‡úi¦¸ö ñ/Õ$ÃÓÙ£{ž®¶Íµ÷(½Ñ¥B¦h*&á¹ïi·Ó´NæëݲoŒã~SþáÆ˜©Ò7 _Q&` ýv.o•à]ª…S}‘ðÚkfãåHSùC-@º£÷ï;J*W0 ŒCÅ6p%A2¥—ö„–ðp¥-öï@Cú…:J­Õ +yÞøž|³Ú®ÇO&jqíÚ@•’^ѼV|Mž;}/J•ÕÝs`2JêlO‹Ð¦Aý´ƒà2ðým»@ÞÛ ÄÀ÷tôÔHÔ,À”´´0=s°ƒ°9üg;É' „hˆ„D}'¾;_,ýO¿ûÛ–)xü_ÿ„J­)`Émÿç¿ØìgõZ“¸QöS}ÀÒ=IŒSèí;xæðõ‹*!1½k@'-žüIŒ`õ|(æú¤Fýç´hÄíŠ2N,®& ¸3X-W»ã¶tËép­;'}ððe ÀǘÅ'Ð<–)•[T´Ó¨–ƒöæž¶9°À»Ð]€ã¬jûaöÉÐU EÇ2ÌĬ4hWÓU²Bí-.$sϬŸ3„9!±Ù}å±Óéx¢°'—vžÔâ¡@¹;iƒãÄìÈ´£(O4Ñ ãJ$Zðþ{{eK+G­ÿy< ïìq†a(loˆ‰ƒ +ç`cæ œ ‰[!Sšçç±Ð©?Rš¤ýúÅN­ð¿±Ý{ìÞqvê?”r Ø߃¥€Ý‚_ÐQ Z»¢ã¨ÜBÕ™f«m"¸œu6±x-°™{¾Éz{˜gÊÁJ’FUéL<~qŠ"dáþ%…û)öm±ÙåFPúg¹-:§dÄ>°ßfø2F´¸¡oy¹'T;U°osEn@_/|e?ش٠m<>2¸Ëù1V$Pܳû)T°iÝ¥]…vÓ± Ëc»›¬Û¤ôâ ÛqŽFw êÎ2Ëæ$ø¬Wýýñ´Êšh9¿{4$Î)þ:¦pøVµYÓ|„ØÄ3õ1ëý¢u—þ—þßnWÈ»–#bª±Ç«kñj%žíÁ lÀ®wù<Ø,fFoŽ÷ Ùax< üªÁ¯}Fû½7_­ï¦^Èïþ„î熧 'Ú‚04›<„Öä†_Ò?û®’Ã*‰ÈpC8,èZ«´K‘МÈ-ùW«)|F½ÈeB%wf EV³•„m!AØÕ¹3Q¦í4zhKþÛþv<àæÚ†ah4+0ð @ËT4,A†i¨©Œ°#½çÏù’K i’Üq‰PdéYzÒ/:ürõœ|X¸&Rz¡3^É/DÚ‰µäƒ‡íò™A*ézÒ X¬Z¤hºÆh(N”Ꜻp¾9ªÁ'™6=©ÇÛùñRèÆXaÀ& dær“õ‘Ñ£*—¥ûCtúûÞ{×Ó=žž¾}2ëÃ;„„ {Bì¡`2ùèŒâúUäÄWR I{m)€¦ëlG¹¨®K¨R‰¬ù\Á¨EÀ7luî†lw­Â̱*ä Ð@ÚÎûQ&ý”éBÒ‰uÔ•ÿxS1wëÀæC[2î=kTêºáÿDTSapÆZi>Á”þÉY¤dÅÒ§Ø]{#oõ]šû™ÀõÿÇWòÎåa¢Þ&.F”CtD=Ž[ZI&8a¸1á”É!1!Ò>},þÑáïQüž ÄKà½ðN?. §u{iDF›+A’ö;=¯’lË£{Á4þ­«_Còœš^ P1Sƒkdxž/½<Ã9†÷¡³LÏ.ºIª0=eyyŒ«Ÿ»Nþýö¢¤¿¹)éý£[3« ÔÉÀk ¶¡'½PÌY„óâ_¾‚eˆm#|P\‹ Ò¢£~ÞÓÂôÆVDáƒð‡™¢P0ÏÎáiIð½pýñ+:£Cþž,äZ{/4T£sæ1áavýÅ)fó” PÑIï@ªap#¢Ù–R0ÇN>Œä*E1‰Ó]#Üe :<å¿ ç n†a`úbÄL€XŒÂ“ ˜ø0Jîì‹ä´ðDäW©u¢&9Ÿ/v~ð?‘sæÒ2ï*‰H}¯á¯6‡‘=/ ˜%íɦ"ÛÃ3ÓÔ¨ÛGêf BuD¼ÙóÍLk;. s‡ãŒÔ|'ج ·ÈÃ×È0ÀÎÃpóB"l`èÇZ+)xe»ÞÓ¢Ëi~}ví±ÇÞˆÁz)Ù@2«,Ø”œ02qÇ;0kg¾;ƒ—Z ¯õfÞG3'SQŒ¹ìTLþ{e®&vIøþвõLäEcˆr8^”›a?²GÏ6zX„‹T¾&ÎBI¯SÌg=›’Ë“‰0Ø B‡¹0%&­L›É9 öc{ @Þ!AÒ„ ²Ÿö`–`þ­Ã¿U@ÄÜîÞ†¯#3¼“;2,›»½ã¿fî½N òëÓ‹W:úvsâËR·Hbldi‹H¤ÞáVµÑ4ê{(Ž •@Xa¢\ùjÅYd}jGÛ<ž÷ë{ü ’¼%=> eMògë•“Åþ ©«m×]E29Ÿ.·ckþGýaׯìaX±NfÅ©Ûf)9àríS]ß1Ÿ+ZA¤©ÁØ,tôÎí ÈGˆ&# k‰ÿ(ÅL f©v˜l…ß+Ÿ²ûLÛ)·Ä\ÓPG‚Ûùa 6ç=Q•Tð‰ådᎋÅp‹õ $¬·6LŒòÛvy¨WP>¨~ïë¹ÿô?w7Ã0ÐoÆaø° /FéF¬À™VöÙ—6*UˆN’È2û¡@gá*NNLw¹ _蔇í•Áå¢ÂH½9TAëÿKeŸxa4%ša}÷ߘrH™)”$ID"àØ½ŒŸZD_Î×û¡7ýð¸=7¯·u²ÐcвIü>T¢ÄE"Å÷á+G’,õ²˜7ºI³GÌ+{à÷$¼o"Á×;åÁýûÚ?ŒÓ›Ã"1‚ÿÏ §\1¿ž^)S›ô$Ã>N•Ô´ÀG^b—¨© F+ÖÕ7¦]!kÎ6(Y2.1¹¹>ÿoÇGr®ea†5$øH>áÃRÛé*í†Øi¦e[b×vµáûð;znW4®CN´@JyêE¨oô¥»Ä+ Ÿ-2&Mi™lÙÇ£ MOW§:}[¢Ó{ âóQQþÑô±OLÀ0N ”ÚDXB %h<š¾™žK4áúz¯Mÿz¦Î,Fˆ¶ÙVë.‹"—!Lƒ A¢Õ>+ûë…JüÊîª@ÊY—é–&8tynoùå@ $l >‰½Á«îb5d8´>®þÚ}ÔŠà‘'2N@ÂuO²Íÿ’#¸q‰Ë9بù˜jõ’µUÃS6ÐS)ÅñÝ:ÂOíF§@Ú¼âÖ y¼ ï r†aXóÄ ù&_àE#LIì¸LÀ ÑË4­šÖ¬MœÌî~Õá#²käÞû¦Ïî܉< úb"ø Ï,¤ÚH™‰Ò õ˜)Êž„OS«Mc´eaYCéŠDktL‡muú·õp »à[D—):‡*7¯'ûƒB'ª%ióBEõ<¯íò¹Åƒµ^Eƒ%€ g)ïØ„jJ;€9òֻ¢Fd; EƒhŸ}’4zTÒÉù%1+f ÕCÊESwîG„o,»;gFL=/é’±Õ<ñW/ìÕc]&Þۧ|j¢Zµ­´^Eé( ΢¶Ùm^àëÅ[¯`Sê€3­ûÈ„þ¶= a •hÙ‚(銊è驨žމXÁéÿm‘ Gƒ‹pbÉÒËgËFúu<üoAzsÞëÓRý-Õ•ô;<šøÃŠZy¿ê~QÒ‰€ˆÈÆ™&\-m´qIÜ‘R Õxm¾×AÁýúhèÒúe­‡µ÷Æ 8rN›ò¶œ÷ëÓt±=žŸ…w]-}—œ» ¼&ê€|½“ œ§¨}<[nçÇÝêðW½Ñä¨7 fu×WÃRWØÛÅ– ®Ô.[}(R³iS|šê´ðÄ<µD]È=óІ\}àØ©B.U®ˆø ªGšpRùÐPÛ$åqøHãHÞ`íÉè¢\„¸áÁ:‹4T7¥°G©Ú` Î_ڷפ‰4)‹øù±:i„Ù")ñŽ"Jíþí ÿ.yW„0 ¡¯ð¾Ò—ø/Þ¼øÇˆµ, trÐzrì¥3M É0Ý_üÑG[C  ÚtÕN¨‚û|Q‡;ŒX´`8ÁJ„/"û4Å™¯¸ËÂI3(´ëz<ÜçÛe£^[&rÒ×STvz g#̱ÑŒ½Ì"ºÀ¬ÄÛ¥'Æðø¶ŸAÿ6ƒþùsýxÌ$ÐÆwé¤ý Ê.!Xœ¦ÐÉ’Ýé yÊ2F ÏTW §h E}¸"VI=ª?ª@wŸh„×Ô3Ù½hâìÛ­›Ì³gE©§?3 ÞÆ÷q¬²à¤¼±½–>Ê*®z(±¶®£ò6¥FÁ¥4â•.*+«& !ŠÁÎÿ"Ñ£áª1þ9à @ÞÜ ±d3ž¬Â ŒÁŸ“°âgªÔ¾øªDÀ ¡FªTõÑ&×´ÊÙ>ç_!”®Ž¤à©Qq¨±ôÕþ °{ËF,¹`‹_ ‹Oö¹L©¿ð¸_ÏÏ¥·¥_”n;tfU™Õ  Æ!ô¸KFJ¹Ž§Ë§›jl›”Cî¸H·2íw&¢¦~yÛøJŸ!ø.‡W¯îÌJ—F¤¶JØ9éYLùcs¤WôrfjÓ—6gÐÇ ¬ºöL¥X´â4͹Z´)äcœ”‡¤«Ä»Cn9ê¼`”Ä@ÜEòxbÝDxÑs át Ûht†š¾gZZFÄ蟀õ™Ó8í¢½àîJŽ„a Ô]RJÚI )„.ÒI&PI»"#fÂ#üa†>°W°ÚµÏø\lû²Ìf æ‹ÁyÒÃežÔï|>øòºQUYd"UÃ]8|ØÄ¡—a}ÑÇ</ªÉ©·f«Šˆp?*ûÍþ'¯º‚Üåz»ï›Âú²áÔÃxÅà£È)ï¥7Àü¶Ž>k+ç²y‚V(àýrrªKû¹z¦ßÉ’=2ǃ1Ÿ“u½jññ Tn›:Šá¬´såÏó€R'€p*—Tê/KæYT´×ÿÂŒíg½BÎß”Û"xÿ Mn—*ÞÝ$ÕT‚O°Ûø p=”»9kù@ÞÜ Ã@ûÇl,ÀlÀ¼ƒ?ë ±J ñ/QKûÑG[©UmµîÙNìË/þ\5ÎXvUä|¼—Àƒ†àüƒ+[±‡>r\@Ý] $úR¦Å/ñc»]N÷×áj ÐQÚEºp`¼fYAú'˜üèj…Óa<ï6+ÖÆ®»oë©c±±Æ­âÙÔ U½çæ¿î„, K( &h•:#ÀÈ(wU–%"â>³*ÆrÛKÚy˜†è°lIõ!«µ÷–Åi·ÈØ–’ŽÉ¸ßò\ô‡Ýó_s4£…LNåx‘ìÉÀάÎh[&¨3þû:üIò®ía* °0›ðÁü³[ðϬÀ ­ µï|•Ò¨ýABDÊO+õ‘ºgŸ{vð;Qûâl9 ‹Ä²ƒSã͆`ŸŸàÒuhJÂ’Õ†ªbøê8ž¯û:­}ÛåYW倞do†ulá—Ard¤Wb³5îwW·žV_pVW XdÒ‘R?úLm€)Ÿ§CZìÄ—âÄyg$ºtux½ÊÞ)OAçåšr:‘dV^Èá g(ÐóXRÒ°-R'T4‰„цì\iÚÇŸïX§xï%6µ“±Æÿ‚y!ê·di´Ÿ¢Ï°1Í8G›±çøsV3ºŸ³Ô?oÈ»‚„a(/Á:¼@b žìÁŒÅ—1`…š´¾³(•¢}äÕÖ²’sbû®¿ø=0o§ZE{Û|VÍy0…3çX9‘Õj_)s’y~Évi’Bøöe¶ï·Çs÷G)ôoe¸ «=¢s¡s±¢ÒA#TI !sÀ¶Õ2n§Ën…Ñ9¨±IyÓ^]Zd•À=]ï¬z$ÈŠ}3¤+2ŸÛˆ]"­¿Æ“+¤²… k@žÎ ¢Â`*Î:%£[{ÅNËýÃ#¬{8á)„ÆÈ[€rç„Ò³³®Gþ*Ïß™vø‚°E¦54—*=¦Ì†•ð[´[N* ¡ûö¦W?k¡4o0¦™SVÕÈ -¹¥12JE#jèù ¯µ£‹ÁXg,Tû€ÂºŒ<3GH‘ÓÖ.Œ3WTš´î¸½©ÿ‰zatM.[Źï0ÙlYK0xžö$¬ ;]ÃâH.@ýk´Ì‡Ô]Û Â0 t`>‘‚˜„­˜‡$†@Gkû÷‘¨?è/¨ÄIkÎgûü µg‡žÌ>ˈ~ÞåÚë]Ep„oˆñðƒƒ›‹WìbpÄdÓA‡óu×ÿ†®i,Ñ=/M§lzJ¥S ‘t‹©EAßd="ã"2 å19Ëakö› *!û`Dí:lf,>TÑ1§G‚F‚„c±¶6¨Ò :— 7ñ0ÑéöÔÆ#+ZD8Íû‹Ôd-èhMO?xñ¨ö2çšï!¬þŒfãYè ëê{BÖÕ¿µ°ÑLgÔZþÝP|áz |UÁuî#ÑÍD¿Ù£”RýÒ*õm”W'¾»Jr™Ø\’ð–ü<Ù7®·ä]±Â0 ´ ŽQ( 蘀ž)‚-˜ˆ2%Cä„cé%ë…»t.’ÆDZ-)/éõ‹ÉA;³6Ël¡³žr¿±Ñ€g¯5Á'™'Æ]^ÜQ$³D ¬gcnj§ë}*oxH;ˆÅ«<,¼«×K&ôk‡g}ÿ·Â7cóçdÍ1{ß~,Á–Æ_‚eO(îÎÇãùöدNÈØ;-’E¹Z$c”ÝYÅžaÚGË|ÁÔÀm IÅ&dJƒ…Ô1dRÁjó!¨.øÒr‡&î‘$±|/s§|sz†R.ÀîØ„C=ž¶ˆ–µ0Ke6ƒ™âPhÆ ¼®”'‡ý!wÔ_ð5Ê8о›øS$':ËE1s¥³tæ¡þ²}àa ÜÀÔ B•;† ¥c V`†h)býKq’Ë]:p‘"qìÈŽßÒ[–ðãÏYvj©ÝYfþ´Ì³$=…¾áü¾k…„X)ÐMÞ¬šHû,¬4íçu[~%srñЈ®þU{ÝWÇ˦Ìö¸žÞíºµ¥½0Iš+$,º+züyí{#%w¯{|ë÷í¬`¾[3ÆiÔâÚ%À+òínx"2é i:hÕMÞ ‡@éVJž¸uÁ÷ÃGÁX`%iŠ“/„ú3÷H‰4ÙP…ò!üÿ’a¦º ¼>5á–ZòûSÜårñš”…èÈ{4´tÅA1¬}5I·i,_K’"–’µ;O•ÉìA4ÿŸ>PwÅ8Ã0Ð L¼ˆ…G±ð‰>€03ó&žÀÂÆ2&¶ÏNQ êDBU!MªâÚÎårùG‡ßrö}ÇÞÂõÝ1eYaýŒ\‚wØvq§d°6Ìž¸‘9ä›OäàãYØW{D‘¾æÒê¬5Ö×J/ºq©åf¦òÝRœþK¶½ß¬nRo'W])8ð*œ‚YŒš*Ñ8Nª†.(—q9on–]ʳ6 kW¡dÔ¥PÙ5U˜<£õQƧO1ÃnX*Q 3éÙ82|<›7pðó€€8ìˆÊ\‡«T5m¡_! 4š¦*@(A!±©\G‡ d¦Á˜#1²¡n½8Ëá¨%&©óæ0¦»„ߺ71Çc;¨aaVÿ ®5¢«%{€ý¡Ÿì0 þrÄ”‡Ê>òŒ>¶]Mê  »zÀ$tï?R&…obDO|Œ(™’yÿ#vêR XÇ׃–Zª@&åø 6‰èZƒ°0°pösHîÀ,ôg—¿fÎu@¿|g@«/郚…TèC†þ#Z˜¨“™(•/80z®ýï†Nâ!ÙÛœƒ4© ­LaöÂâèW Êé.Ä$?ôZIøÒOè\Èág°uåЂO@w¶þ‡M¤Â[ì° åð1¤ÞÄÿ`»q sâèn(<¼‚˜[V*ÿ¡sŒ°a)áõ;T?ÂLئFDƒs/#Ü-ȇõaÚ…˜†ÇùȆ5èÊè²O´Epÿ#³ÉØQ?\@ò®Ýa†Êô Á t À TÌ@KËìAÇÔܱ=ÂŽ¬÷D.Îq ‡›¤‰?±-?}žüË¿5©c¨Ÿï4+ÐiûAÉ(ÿ–…Í]°i@ÀaÛH?lvÍŠ®4¤tý òXnöó¼C†Ö;$×,Êp@þ7KŸUlá³ÜÇõj{˜ö¿;w…pv¢4iR¿h;•ŽqË ´/Õœ·I'£ƒ3âÕkÝŒô¡zß -Dƒ@ó@&Ê·æ»ÊÐG5(Bjyh©›•ÁΜÆNÊ¢öÒœaÝ@½îtr~° Y­h§EŽJn6 ¤$#EU­Jî™?8JÞæHÉ(ÿš^¿ˆ}Ö?5k– +8¢‡u•Я²Î’k%ýùƒ ZÙß"ü§ä]ÁÂ0 sF`–àØ…-x³ c°óp&¹X²Ò#m'øÑG>I›DqËþÀÇDnq÷‹ö ¥33å¿¶º+Ÿ9ŽÂéXtAÐÓé’ÿ¥ f-to¯.·cíó ºª¤w=7rð4-j‚›Õõ9ýk‹NzÀ+ôæH‡ÔÉG÷ùC´I÷˜ÒxŽž$=Hrë•qEõ¥­oÂîxI=üEŒÔŠKZ‚Âu Ji…F(…ªÔ~þ§Hið‚ˆ(j_âr:´Sá•EZñ°© ‚óVáƱðÂw|¬»µB:z·@€·‡:ŽJ[G*ÒI^Cÿ>!‚{õ.©Š«{Ó’¶OrÔÚFª‚ÓÎr³›§®‚njºóÜ1‹p‚P³ãsÞœ³ô\´¾OBÿ‰Ðè‚wõqSÔK^ÀQ°œBøóœÅ >ðs½,L½¹÷8ëhŒFf+ Tgòw':‚™/÷r‚a³úÁ»¨×©ß{ÜM¡òÄ$‡ ª ,í`àêUIø ï°öœ¶Ö5!P.æ)¹ë©Z§ˆµèºüÀ*Þo×·ôÞ1ÈËÂ'ï5Q€ìˆ`ÊÝ”4>V\?Å­6o mnA2k·ÎŸ–‡ä]1Â0 4 /aeGB0ð6žÀ„ÄÎÆÎ x;?`gbd¦&Â>û@-T0!*U’(Nj_ì³ó« ŸðKGéM„×ÒÚÿRáúsÀää$M~sÒ2äëâCô1˜.»EÙ˘}(øM=^šÚzucªÑ¶K vGÉÚ›ÌV£º>v›ù±|öáÊ 9M¦.OÆ øxç׳íÀ_míÌ7Ÿ§*Ë‚ªHö÷:-,dŸvkíôpBò—Q>Y&â7´M§–ˆ34"Ìî²54.¿Jú§Á0K×—O¨,©\¨•jæØ1ˆ u¸Z j§¾¼Ö‹á©4Ûzÿ<Ÿ«³PUõ1Öbüï>‰{ÊeJ{5–›Ï A-8¬þWÝ‹Ü ïÚmb¨o:X‚"53P1¢§É ”°% ˆIs‰ý|9¢ Ñ ¨ ‚(ÎÏ~Ï~ùŀ߽y$ÄíLæ²ej/û-ç|(ÿú‹?&vY%¸gpµÈô >þ+NëqÜ÷<¾¹ãª¾w›û»ß$d‚2e}r&³å¶Èí§ úñûWYŒTaAT;x®¯d–z-ü6ÂGÿ³FaT1„~l±v¼3ihaSŸÉçeP¾X͇$¦±¯ä€ÐŠ«’-˜Ö¨ CŸHÌžæR‘TzeAÿ9@ïG 4PfÛ³´‘eìä:¼ö"`bÀ^CH:Œ÷ W¹*NñBï™ì9Éjûàl¥dàcâz\š“HšIEð™«dwî€=Ÿþ5‡ÿ@C±ÀǿܒpE€PElU§Îr-`¡˜¨ž“%ãÿÿH­>ØnÂÐeŒ‘ŒÂ>v‰˜ÇÖ([öî@]& e”ÿë”á-ö;G4ÇkÐð$è_èzkèšmHë :, +ør=%`¡oͨݳJí¿‰âOèò;˜» ã¸ÐzæûØ>†OÛ¦å¾!àuþÂç`”02Àþ‚‡/¤wÛ ]eƒ:D0—ZþGI;ÐÖø´‚å/¢`…o*ƒ 7à‰[èxùXEi”À—b2 sèä+t²¾Ê >y‹Õä9è’L´óäÿÃZ@TÈ›ºð ³àý•Ög€vÍ2Ÿ0ÀZøùѳýÛ«€Ø¿€ @þvv|XˆÕä5ù£cø@@C±ÀG/ıµèÑ+\•´… ß!K5L¶çæÂÆóa¥Õ Ëè°3ÈŽÅ$ºç:tó˜jQóØj}‹ØO 9 cø~€·– …ÓÿãG6œ$èPðâçÿðSa¬‹ü¶"„~ï(¨SrNíÒÄfÜî™ÅG€Ô-Ä89ìhÄP¬ÕË€Ôõ†vÑv/˜@Ĭ¥ [Ø\òø3ìþSø†&HK’¨Ø†*Bž—@:Ú—Q0þ‡¥EØå"ˆ^¢‡ƒÓSÐÊqÞ të¼ðEZñòÒ€ô”¡n@ZŠáè+DˆzA|h„‘çŽ ôUY=ë«´š4oÐÄï`À†ßàË,‘—G3üEº Óˆ‰éˆÍ[ð zhú…¯½GêEY®9b[ø4T¯8„öðÀ‘ÇÈ€˜m…E$#j¤2¢‰C¯Œ0>#Ô@ª%`+ÿ·AxÑ1 ‰ú@k$`%ÌåðÑ#äË8ÿói+ÓèJ{¾]÷r…¨Ï½ü v¤G»<æ‡ÿ_^;stQ#±p€-Ñ;Œ0w1 …9ý?ÒvÆÀBÿ×ÞÙeÃE»gqMëcj—ƒºð»F‘ÂÁ†t-mŸžó°s!…5Ä-`Ç1BîVd„vV@A„ÿ{$ÁFXã9ðøÐ ü*@P‘»‡8Œ 0yèÄ…e°Ëñµð C9ÿ!÷½Â® þ6ÈùL°ä¿ñ:ò=ã{ú…ކ’Ô!Ã\`ÇCæÌa×þg„Ì“@̇,2€'²@o¥åÞâŽãGf€V…a¦Ãâq;2,£ˆ*X:…Ä5ø¢øµ¢pÏ"¹Ýጠ”xd€Š>¬öG.ä°G.’Š8t ,ãÿGÕBpaeßo uÆ0¼Xh´ èÂH1*Ça™º~Ù6ô¼/F ›ÉQpC®ÇeBì †ÝIÍÀpH]?¶¨ñ7ÑŽ„T};Ia×´B,…Þz-ía¢ˆ¢¤ÄÜ%µûÿžÙ¥÷Ðj~ûŸIV3A+®ÿÐâj"ìNÖÿï€üÃć,¸e ±2$Ä)j™ ÆÁ [x™º†ú€'²j‡µð™ Ë« E;ŠnÈUªr˜Z%£7&ðoªƒ Çü‡"ÁªZXÁc3@ëúÿ0—ÀëRFœ ÈJ"D¥ -]`u4,@¶2AMb€ÕiÈÕ4E™£·Â´új/—tœ­4˜/þs Vb„œËrˇÿ áP _0À–ØBÝ‹fXámÃÁ†ælÀÛ ¡\àƒ#ýM4y#_,ý’ÁhtÞù•½÷ #J^™ aqD+f'Ä-Ð w4¢˜…¥s¨û¡ û?¼1Úùz娢¦¤º Ú®ú÷Ñ "ãC‹·°›¸`¥>ü®m3—Ô†=³KP }HA>` Úƒ´ÆaZÿÃ9 ùŽKÛ§åý"ÎÅŒ°1{xÝÇ€ì.hÈý‡99£3B­%¾jg„Í‹ÀúH^€+:…a,´n€vA`aˆ@†q ‘­Ä&3À’ØDh¯ÌfD\ 1kÏ®„VŠŒpwAkD‡‘ÀpOþÇYPz*,ž)&<„‡ì‘ÿð9%DhCãZöÿCÔ{ðü#ºe4\ |\lä–?ZKÞèd€gN¢Û}¤ƒó+z¾©s†¥B@k¥€–É0Âg°r º}ÚÆBjT!õbPF…É{Ç5}"×]¼Z¯ü‡Yü‡7O!N€6ø`-Kˆ”iê’Öý~ϬÒ÷HFËÿ‡Œ£ÃŠ'$§3¼g=ÄÀpsûô¼¯¤¹ø?lh ÞO€¶ç‘‹~”b)ë3B—ª’Ñÿ!³ï°ž¤èa‚µøá/¬)ö*¡-Q¼cà°¹(Ö¤†µÈ!þf„ú°ž!ÐHσ Vb/ð!×2B»8¯l‚˜k,cô þab BK¨¸ý¸Ðp  %ðáM Å?€ÎºßSnö‚#þC÷ @Ý 59ôa‰¥qÄ€=b@ Åÿ1_â’ƒ´à #x³šà¦JÁùÝï€Ô;£ÈÒ@ëAG S¯8¼Ö¶‡¡_Ü.5~ÞYï€øåÉÅÍÄÝàÿÿš{!€lPZÖ¾ªý½cFÁ+ŠÜËÈðhèy¤ÁXïˆ>ubdÞ‘c€÷d°¯YÇ †ÿŸ6œF*a7ÐÆ´¤‡¼ð11XƒÔ x*eÆk@eOàÝ>x'áJø;¼²g@ ºÀš¹LO°þÜ”a„7‡¡E<,œ`Îe„WÇPÅt$¡°ÂŠÚɵÚ5+ ͺ@[9 §´óÔ ü®r³ ¸Ìø’!³oÿáE=@‡ëàþ{¤âšÏFì@‘uo÷( >0‰*ç&FÐx&ïX®—%Œ Ý‹ÀÞãçSKZ)/àGÁ( (j;æL»æÈ£”dès!ͺËM7b3«¢ûœPm"r÷Ÿ Þ/e€MÐ@¬Aïí#·è9-EºóN#ÐPláKpfY'h7,SÖ£``aï ,Zõ KNá]h?Z@C‡¾á]5ݲ®3ÿºÊL6c3º! 1ˆ^ïÀ™‚LùB»2Ƚc4,:r[ø4×á‚Q0 1(l;j ,‰AÇsC×ïÿ‡ì{øÝäÝˆÈøq¨d]=HZ¯¼ëŒc!“Ï H{B GS£ì­a„Q¤ºöþ? î†+ ÑŒ‚Q@5,ìùe«%#|3b“täŒ)І5ÆÿH;pQŽFÀ<¾ÒN‡o¢D*¼á;#|ƒÆ™ø¨›¡sM#Ðh? FÁ( &0O‹CŽo€]tÈdVðBïGÀ(œY­|]SáG)#ìß# ï9À|ûßýŒÚÚo)Òý@Ÿ | €F üQ0 FÕ°ŒUb@:Š‚éˆ Äý°–?âP;ø×ð#$d1 GŒ¹"vm(d¸ù2t˜™XŽRa¸O‡`´ €F'mGÁ(T­GØy gÝ@7ÃWùB7s£l/„¯@ý¶…̪‚{èW]þ‡ ÝuÀÝl…¼Šô?|÷æ2Rÿõ}>t@ø£`ŒêFØf»ÿˆÕîðeñŒÈœÿð…óð£p ÇA‹lŒ܇ï&`€E“CT#(kí‘¶Û@À%jzy¨€-ðGÁ(TÐ3yþÁO8‚´é¡Å9ü ¤P Ðcø™à»äà§&`Ü4b€ï:†«àv"¯ÃGY“ÿ¸¥H—äãG† ÑŒ‚Q@ð1n™žù?´iÜ*;=±{<ÆyÜb•B)üàR´ƒ°ƒ»ŽÐÀÛC Ðh? FÁ( x½ qôØ%øÉŒÈ[ba­xÐÚè¸ûØñv ¨á z Ð?`ÚÁ@EnÌcÙiûÿZK‘ú±,#Ðè*Q0 FUÀ„j›_À‚tføHøMaŒÐûœáà0@oì_὎Οފ>ôÂÆ€|CÖØæ*ˆ™ÿ‘×ÞÃWúÀð Ø~:Å 4Zà‚Q0 ¨þ3>e@¹) roñøê È÷Ï¢^. AªÑ—OJB–b2@6o1¢ßó ½Qí?|Í=ìÞjÐ)µ›[ŠtÒ// ÑŒ‚Q@5l™ßþ¿r|#ìÚDøšyX ÒZ‡ÜÕËÞy‹8‘‘ýp3uÄ1Òðݶÿ¡w3Âv×2"] ,ìrk€…=‘·¿ @£þ(£€j`B•õs`áûºØùð&,Fø l·,ürqpkrçí¥ÎRcø…8ÝçÔ€úX w/@6UÁÔÃ7WÁ þÿHÃ8 ë…ý†Q4Zà‚Q0 ¨  Þïÿ‘‡\ ýø!f»”açÛü‡ ó€†òAsga•weªµ@ž éü‡ ýg„W*ТTi€ÎÕ_5ZØc€=Œ‚Q@uPØvLX˜Û q^øŽ(ÈŽ,Äñøhgã©÷@Æá®rÓw0s*ºÎÕ 1Àç l¯Ÿ†¸+†ñÿ¦«­Eº˜wâŽ0 ÑŒ‚Q@PÔ~ Ø:gÐÆêÀB™VVƒRÂï5—Þ_€r÷ºËMá7^•uŸeʘ1þgP/ñD\ªÌ)îÁoø6ñ°µXÿ ]=8@ø£`Œš‚¢öãlÀ¢YÈ–öÜЋt |ÐÕ†/»+Ì_¢ë)ë:Ã,Ïy`Ë둚õ¿ÚK ß¡«Ä€-ðGÁ(£`„€´£`Œ‚h´À£`Œ‚h´À£`Œ‚h´À£`Œ‚h´À£`Œ‚h´À£`Œ‚h´À£`Œ‚h´À£`Œ‚pwm·Ä Øë&u¤‡H©ñºbÖ10 ‘"å7'ù¼Àðð~ígþ¬xõù|9»uÐå~Ç>}¾ßÝ~$ùéRØÛ¥Â±Å]Ê'åc<…ëÝNÊ7ÛOœÓ0ÝTÑù 5MÖÎ߱qÜk´¸$ŸëÈ¢mË ¹òš=o;m ›=3OdÎ!§ú ú,È5cN\œã,ǹP·ãÐc.çÂ,ë.ÏϽvÎì•ñ. ÇófŒô*Àƒ RÉQã9ß ˆS„ÂIuê(p!¢J¶¡öRÆ«Ÿô~¿ÕG9`làxÛ_²öùˆjg¡üÓ™Ñm~li‘Êôów>k¬¸xª£‡–øy–YkÌÇZ½z®6€2ï– 6 CÍüYåÚ±öß#öd?ðà^fLŸe®œ8\®ÄFÞ`Ẇ³Ä[öÕØÝyê_‰díåA ÿ…}Ûì÷7ùo¿/Ø»‚€A¦ÿ´Ûa…%©xÙe‚Èl›¶i…ô‹?üçɱ#;\y4¸»> ¯®Ye™Â©ÜPo’lÁ·òÇy%(c»E3É—Î'ã!îçäâO£ãp‘n—Ç6*VWKÔSÜr\¨ëêŸú¾ãùô¬8¼d§buÜ«¨=¬¿êß9Þ=‚~'ÿ•÷¸ · v€`ÿÿÓN’¥ißHÄ…‹Ó*Ê+çï‡6Æmv¨±îr^25øÄ±38Âvu墜Næ×94–Æ;,§¯jå4"¼d0éÁ½¡ižÖ­ù´®“Þá·Š»C'})FýÄQ?CjÊ[ãºGε铖r¿,SòË €„ÿÿµWBÚ¡rðâ› U4e|øi íÔœFÓ}s¹n‡7ÕMH_éª&…‹ë¯#²é#Us}VõÍ+Ьú´_´äW÷Ñuç5ÿ ݼÔÔú’¡Øý¶0Ö½Óþ}üGnÌÿÿµkCਓ‰]µŠ©öUKgFku¸ynŒÚ$ôåOÎÕá¥\%#u¾DŠî\í±'œIë%ÂJ‚pëX'†³w9Ž´7õu÷oswk¤¨xÝš‰Œ[½è÷Õê¥û%| {GÖ‰DUƒjuk8¾#9V‚úÿ«;µ9†@uèG3Ór ½úÒY:Õ1û”П[s ÉâPdœÍD ÓÝNK(ÎÚ¡NR÷Ö©0‚Ã&óEÒU“CÛ)‰U¿]]±’úݦ5Žnm žOZ»¨WÓZº·Þ©›h¾þ)€bHY [«åJL¡L(Ñ[ñàêv£«!”q™‹«õ‡«åƒÞ3@6‹P!F¨òDWOí./¡4±W8!ÛM_<áK;Ĥ\[!ãã‹/|-yrÜ€-ì±¥%R¾Ê››ð¹ŸpžÀ¥™F¯Øq¹‹Úi{È€ÜšÛ Cÿÿ¯{•áæ¡‚ ^¢©Û¢Wÿð«ÃQæ—‚(90q$'£m“ÔOû¹dE’‘Ø»…Ĥ:{ðÕºÓ½:¦NXawªbšãI‚ÜoZ›?!ÙâX¶®ˆM"¤í€ÞõŸÝe À}¹£Â0Tïi'¡”$MtÄ¿‰y/ Ÿ]n…`ޱ"››žTÝÁõݦDtŠîÝì¤'çãB}˜p• •¡#óÌÔÃÖè€H“·Á#©ÂBî_oµ6eì¨T4Ç>@¥E´Ÿ9ð\q‡”:„ÆÉÑÙ÷e @Žä‚ õÿOwjc;tÉSkÖJÁ—=|&¿˜Õ‡€ŒÚÉa…ÆØÅT±\Ë$ÁÁDyÃ<_¥ˆÜžÝÇ&2\ÞcRØ[O>x’Ô«oZ ]rÇu윮óq¦ â±qªÖ0ÆIYb¾bªyEJœúüšáoÈ1ƒ †þÿ_»JÓ·u¸$fÖvóê¿ö$3I²Ïì)a©}“Ò7µEç» u ®**s"ÊD>7@Ú„ÔùGíÕ;hOâì|G™â$ŽÈ÷®:qkG´ÖïöÓ½*¨HßµŠŒO‰Ø½³úQ÷êø»¶`ÇÊqA˜þÿÓN&¤iK™\dóBD)ÅWø €¹Ç3aHn¿IɘŒc%·²! "ÇÆŸ)= Í \]à+€îª36u×¶bÖ.ALî‘% ¦C+ñ}Êvß‹ûØjb‹K$ ¨§ºpÍä¾XŒÕ±ÛÿY=È€œ3ÖB¨ÿÿÕ®†ðàÚÅAÆ+¹+Â-½ùó´–t§®kª ˜œ?ñ8÷Ó¹N)Å+'=?í$(ªa3?J¶nÏZ^Hºž’¨ãئˆ”$µöSc!¸KhrQRÿ\_'“Ü_|áÓŒ•Þ×ôª¥Ï­#-][r­` ýÿ_?:<™ÎíÒ¡ÝŠ’ 37ºõß¾ „„ˆ‰ÂÏëPshu޶º0ŽÜV}(~ Ó¹uW2`œ¿=q‹j¯›Œmâ4Ýø ±6%÷ø¤Èî­: 1É{ÒƒïÇ@=†Ø01-4bZØ2/)ÝWr3 L/:ŸPKT@Nw™Ð©ŸŸB…)µÂ&†¯Uˆ^yâj\`s¾Š WEGŠß LR[ìøäµæñ\~ÇØMèzÐÜP^*60"[÷ €ûrIèýO]ÛA}F4«Ð"ó“΋Ÿ$™KÝ7)$ÊtÂÉîÊÐ5(2Õ;õM¤Á¹b;AU씲Çó]C&÷«>ÆpyÇÈÔ·“¼uˆqËôÔq]1¼îSu6vë˜Ne¯ÊN†µïÖ`õ ¶äœ1 ÿÿk'AÂ%Á.: ÚVl‰ƒ/ËL2ðfŽ6 •”·Iw êæjümÓäobH tÚó†Ú¸´=QLc/]d •Ñ6ðU)ùKj“€ãÌ£[íUª¡VÓ‰l¸u4»ïêgªÚÔ_«:_“‹lB¾jKrÌ€ùÿ«ÓZ# l·RRû ‡Áξt©±‹R]my±›Ê×*»ˆsrñL?E"÷?}ÒèKlôs´‘E*&uqC“ËÙ4bÞLi CCÜNÜ“ºw°åo…{ÆSd«r_ŸöiŠøúöœH¤õ,é_¸9ƒ€a¶ÿÿtO°8³-=ê-Âj0A'—|ñ—ÎnÙ´–o­Ÿ’Q=+SoeþÜó†Jñiÿ¤±g¤g„Ùè´ æ–{ŠkMŒêx^×=‡ã‡¨Ú^ 4ÈSoµ¡œt6¹nù3.ÑÔ¨óޤ.ý ¤™â™5X| ¿µKòË`„ÿÿu×7C—2F‘@Á1Ç—†Ÿ $} cK#o褙ö›€LÈóžQŸQa;ðÈ’A܈¿í mÖ'ª1QÜ4h2sªÅò§þ$ð œôþ3ÎÚ[À8ßc†Œõ—†àfÊvfšMÃóÖ|[Ü6¥ßÅ#9掃ÐûßÚµix€“ƒlm´?Á×_:TL­¼S Õ2Êd¿Á.\*b‰sœX¾ƒRt·~ïi5/Õ<É-ÓMjÍå ©°iß5‡ô8»$ÅÕæÑ¶¥|îÛØš G¡QjŽò')!£Â÷Žb¡“=èdÏ(£`Œ €²…? FÁ(£€Ž €F üQ0 FÁ(! €F üQ0 FÁ(! €F üQ0 FÁ(! €F üQ0 FÁ(! €F üQ0 FÁ(! €F üQ0 FÁ(! €F üQ0 FÁ(! ùV0ÂØÿìÁ,Ë$i’âa—íâ¬X ê±_¯†½.·¹æ™Ã.bˆã>ŒÍði»k1ËËrâú³ïNE«Âo¶ç©´F'o·—˜ÃGµ~ƒVgÔÂâOx”^W÷åôŒªduuu2]>†±>«˜ÏÙÙª3-Óy›Œ›ib<¾6ìgß-wgŒ@Aÿÿj¹BËÎ&6°0ÆMP´s|ùÅá×”RÇWðß>ý'ê;S@”«Aû„‡ |ZSzÒNœš)Ž@u•ECuÖi é .ñWÍŽ ã.TÒtþ).#íQÇÌQ[›°‘(.á*j ±‚μ„¾ µ¤³ê8B‰‰¤wB‡ápÖŸýb&~i[òÎ €„¡÷¿µ-“IÂs‹mLå þù‰y ¬¬ê}±EÐ’e#@7wº[S«ôx¶¢˜|r¤}Û¿§õŽ™ûí,-*C;ÙÑsh|hÁnkM–õŒÍ—Vȧ•i9¤ºdúÛ|™ ÷Q>qãgqàæŒq Azÿ[ÿÕ4¥¯ãð ¡eá5Ã'Fn,F¢äÓâ,òÙDÃjØ€‡»¯BS #¦3õ­¶ ôS3N ¡S[bðÉ·#,NwŠC}®y¤ÆGSÝÔÜô?8‘nbþ;’Þqš¬ Ų'qþF>È9c€b†ÞÿÖ•g‚K‡ïV•Z“¸ôÅø›ªKM¦†ÎAt1`´wÖTSkÔ.Gz T{£*/$|QI­ÿFäi;Q_×W€f»twv“ìüunbé»ù"bÛ„B³ͼÃÕž„^KJø¿´Or­e„Õÿÿt§@Öt³K‡¼b5Êע׿tÞ;tœ]> \E»;A¥p1<ÝávsœÉqdÁä$µ8Gu—ÑV·Ò³D­ºçŽtŠUÕ *_`kÝ<%T :Ú¸Ì Y +.Œ ~åÛÛõnÑ@Ìq¬öͰ3|ßÊ€»+FAÿÿu«Ç ‚Ý5äœ0ضôú”d`µq†âf¸·"žˆB’.”x£QN‰H±$Tù’$çžc[˜ÂM×·”¡2®éÕ>çé¡ÃpKη›ë&3ƒ@^äRwÕ™½2·n“Ûðu ïÜqAzÿ[»â{E™ Aù´|õ‰yšÊö¦ìà¦A)Ið)—$O L†÷{ØÀ–±ðSàëqÉOàeïIÊðv!§ó¤vÕgÊÓêD9t£…¹«¡I­ëN [Š91"4©Ç¦³hdò;[[.)€ ½ÿ­[C̯‚6¹ *Tßøøj@]“™<Ùš ÏmZx6[ȩᦙÀœ °ŒÍâ5ì@¡UÎñ¶Æ 0­p(ß\ 8]ÿÛ»Õçü§Ä’å,‰r“k³µ·±wkó… È/ƒa†ýÿ×\«ÊaH\ÈmЉie^ò5ðí€ÒsƒŠ¹DAƒœ4­Ç\ÏœKñ´4½# MS»KTOÉôÝÙKi={ïÚÄbµ©¯)¡4›ýsÙìÿ˜Æ-”mv}rÖ6Þ¦âÔ˜<íÓ/t @~¤Â ÿÿº«ˆ:A‡vªÜ(}áðo`lcuÂHDl’Š’~š›BÍPwç”Ýžxnœ sÛÓ;'‘c<ÆPâÜš…ÛŠ“*'˜)¹¨Ýgú£ö“رp&.óÜÄcçØ1¥aÏU2nÿ{›ù_Ô€{+H„Aÿÿu§`ˆ:½tÈKV´¶å‚^~¼š-" ~Ç¿ýè8î¡Q¸ Ji·É„¤Û§ v6n^HJ#—õß¹›½)…˜Ø+¹p6ŠvM*†is'¶êÆÙ¯MPîÑG’jIE¾SÏiì¨uYâŸ|çӗ8oî8à ½ÿ©Û©Re=°d‰—Hù¢±ròãÕ×R¹–ó, -»d¤5´Göu¶y*Rª°U#SELgw$Sу1EÞ³U.ÿš {s#“ºÝøÕîjR¤}t¾åÜSÌß"!d¿‘ ü]ùÊâ(×]…WîÍ †¡÷¿µ“ Á×$ù`Áj#hÓtðWNíyRdm›éph­Ž”À“™ºâ6‰MÖ"M×ö»Byž%UòÓYbŸ”ZÔ¶ÏÝ)Ýë-Ž#sŤ¸)!ëžÔˆP]ñÕšÎJqO µ^S`ž´%€jãz†"&S R¡î).µØZkø* tsI-¼‰ú@£$ÃÁÌBojÅ“Rx’ÒÛÂð…1²Ð+\qF(Ýáj(à’#§!¦"D–ÃUáJ7¤Æ©€˜|I(âJØÌ!µÇ¬ŸF zo¼B¦alB5=¾V5.>63ˆmáÒœèÐ |]ktw[°j½ÁôRƒl.uÈþ!'ƒàËŒØh\ò0@¨‰.¯EGL/ gx›81ñˆl>® …X?cãS!QC ±½CREATOR: gd-jpeg v1.0 (using IJG JPEG v62), default quality ÿÛC    $.' ",#(7),01444'9=82<.342ÿÛC  2!!22222222222222222222222222222222222222222222222222ÿÀ"ÿÄ ÿĵ}!1AQa"q2‘¡#B±ÁRÑð$3br‚ %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚáâãäåæçèéêñòóôõö÷øùúÿÄ ÿĵw!1AQaq"2B‘¡±Á #3RðbrÑ $4á%ñ&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz‚ƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚâãäåæçèéêòóôõö÷øùúÿÚ ?ùþŠ( ÿÙPDF-Builder-3.026/t/resources/sample.pdf0000644000000000000000000000775113034236700016460 0ustar rootroot%PDF-1.4 %Çìó¢ 1 0 obj << /Type /Catalog /ViewerPreferences << /NonFullScreenPageMode /UseNone >> /PageLayout /SinglePage /Pages 2 0 R /PageMode /UseNone >> endobj 2 0 obj << /Type /Pages /Kids [ 6 0 R ] /Resources 3 0 R /Count 1 >> endobj 3 0 obj << /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> endobj 4 0 obj << /Producer (PDF::API2 2.016 [linux]) >> endobj 5 0 obj << /Type /Font /Subtype /Type1 /FirstChar 32 /Encoding << /Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences [ 0 /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /space /exclam /quotedbl /numbersign /dollar /percent /ampersand /quotesingle /parenleft /parenright /asterisk /plus /comma /hyphen /period /slash /zero /one /two /three /four /five /six /seven /eight /nine /colon /semicolon /less /equal /greater /question /at /A /B /C /D /E /F /G /H /I /J /K /L /M /N /O /P /Q /R /S /T /U /V /W /X /Y /Z /bracketleft /backslash /bracketright /asciicircum /underscore /grave /a /b /c /d /e /f /g /h /i /j /k /l /m /n /o /p /q /r /s /t /u /v /w /x /y /z /braceleft /bar /braceright /asciitilde /bullet /Euro /bullet /quotesinglbase /florin /quotedblbase /ellipsis /dagger /daggerdbl /circumflex /perthousand /Scaron /guilsinglleft /OE /bullet /Zcaron /bullet /bullet /quoteleft /quoteright /quotedblleft /quotedblright /bullet /endash /emdash /tilde /trademark /scaron /guilsinglright /oe /bullet /zcaron /Ydieresis /space /exclamdown /cent /sterling /currency /yen /brokenbar /section /dieresis /copyright /ordfeminine /guillemotleft /logicalnot /hyphen /registered /macron /degree /plusminus /twosuperior /threesuperior /acute /mu /paragraph /periodcentered /cedilla /onesuperior /ordmasculine /guillemotright /onequarter /onehalf /threequarters /questiondown /Agrave /Aacute /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla /Egrave /Eacute /Ecircumflex /Edieresis /Igrave /Iacute /Icircumflex /Idieresis /Eth /Ntilde /Ograve /Oacute /Ocircumflex /Otilde /Odieresis /multiply /Oslash /Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn /germandbls /agrave /aacute /acircumflex /atilde /adieresis /aring /ae /ccedilla /egrave /eacute /ecircumflex /edieresis /igrave /iacute /icircumflex /idieresis /eth /ntilde /ograve /oacute /ocircumflex /otilde /odieresis /divide /oslash /ugrave /uacute /ucircumflex /udieresis /yacute /thorn /ydieresis ] >> /BaseFont /Helvetica /LastChar 255 /Widths [ 278 278 355 556 556 889 667 191 333 333 389 584 278 333 278 278 556 556 556 556 556 556 556 556 556 556 278 278 584 584 584 556 1015 667 667 722 722 667 611 778 722 278 500 667 556 833 722 778 667 778 722 667 611 722 667 944 667 667 611 278 278 278 469 556 333 556 556 500 556 556 278 556 556 222 222 500 222 833 556 556 556 556 333 500 278 556 500 722 500 500 500 334 260 334 584 350 556 350 222 556 333 1000 556 556 333 1000 667 333 1000 350 611 350 350 222 222 333 333 350 556 1000 333 1000 500 333 944 350 500 667 278 333 556 556 556 556 260 556 333 737 370 556 584 333 737 333 400 584 333 333 333 556 537 278 333 333 365 556 834 834 834 611 667 667 667 667 667 667 1000 722 667 667 667 667 278 278 278 278 722 722 778 778 778 778 778 584 778 722 722 722 722 667 667 611 556 556 556 556 556 556 889 500 556 556 556 556 278 278 278 278 556 556 556 556 556 556 556 584 611 556 556 556 556 500 556 500 ] /Name /HelvCBB~1299252700 >> endobj 6 0 obj << /Type /Page /Contents [ 7 0 R ] /Parent 2 0 R /Resources << /Font << /HelvCBB~1299252700 5 0 R >> /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> >> endobj 7 0 obj << /Length 60 >> stream BT /HelvCBB~1299252700 12 Tf [ (Hello World!) ] TJ ET endstream endobj xref 0 8 0000000000 65535 f 0000000015 00000 n 0000000164 00000 n 0000000240 00000 n 0000000309 00000 n 0000000366 00000 n 0000003557 00000 n 0000003727 00000 n trailer << /Root 1 0 R /Size 8 /Info 4 0 R >> startxref 3837 %%EOF PDF-Builder-3.026/t/bbox.t0000644000000000000000000000104414534467462013617 0ustar rootroot#!/usr/bin/perl use strict; use warnings; use Test::More; use PDF::Builder; my $pdf = PDF::Builder->new(); # this first test is the opposite of PDF::API2's, where there is # no default Media Box ok($pdf->mediabox(), q{Global media box exists on a new PDF}); $pdf->mediabox('letter'); is(join(',', $pdf->mediabox()), '0,0,612,792', q{Global media box can be read after being set}); my $string = $pdf->to_string(); like($string, qr{/MediaBox \[ 0 0 612 792 \]}, q{Global media box is recorded in the PDF}); done_testing(); 1; PDF-Builder-3.026/t/rt69503.t0000644000000000000000000000130114534467462013715 0ustar rootroot#!/usr/bin/perl use strict; use warnings; use Test::More tests => 2; use PDF::Builder; # -firstpage as page number (original bug report) my $pdf = PDF::Builder->new(); my $page1 = $pdf->page(); my $page2 = $pdf->page(); $pdf->preferences(-firstpage => [2, -fit => 1]); my $output = $pdf->to_string(); like($output, qr/OpenAction \[ 2 \/Fit \]/, q{-firstpage accepts a page number}); # -firstpage as page object (regression) $pdf = PDF::Builder->new(); $page1 = $pdf->page(); $page2 = $pdf->page(); $pdf->preferences(-firstpage => [$page2, -fit => 1]); $output = $pdf->to_string(); like($output, qr/OpenAction \[ \d+ 0 R \/Fit \]/, q{-firstpage accepts a page object}); 1; PDF-Builder-3.026/t/gd.t0000644000000000000000000000120114534467462013252 0ustar rootroot#!/usr/bin/perl use warnings; use strict; use Test::More tests => 2; use PDF::Builder; SKIP: { eval { require GD }; if ($@) { skip q{GD not installed; skipping image_gd tests}, 2; } my $gd = GD::Image->new(1, 1); $gd->colorAllocate(0, 0, 0); my $pdf = PDF::Builder->new('-compress' => 'none'); my $img = $pdf->image_gd($gd); isa_ok($img, 'PDF::Builder::Resource::XObject::Image::GD', q{$pdf->image_gd()}); my $gfx = $pdf->page()->gfx(); $gfx->image($img, 72, 144, 216, 288); like($pdf->to_string(), qr/q 216 0 0 288 72 144 cm \S+ Do Q/, q{Add GD to PDF}); } 1; PDF-Builder-3.026/t/filter-runlengthdecode.t0000644000000000000000000000140314534467462017321 0ustar rootroot#!/usr/bin/perl use warnings; use strict; use Test::More tests => 4; use PDF::Builder::Basic::PDF::Filter::RunLengthDecode; my $in = '--- Look at this test string. ---'; my $out = "\xfe-\x01 L\xffo\x16k at this test string. \xfe-"; my $filter = bless {}, 'PDF::Builder::Basic::PDF::Filter::RunLengthDecode'; is($filter->outfilt($in), $out, q{RunLengthDecode test string is encoded correctly}); is($filter->infilt($out), $in, q{RunLengthDecode test string is decoded correctly}); # Add the end-of-document marker $out .= "\x80"; is($filter->outfilt($in, 1), $out, q{RunLengthDecode test string with EOD marker is encoded correctly}); is($filter->infilt($out), $in, q{RunLengthDecode test string with EOD marker is decoded correctly}); 1; PDF-Builder-3.026/t/pnm.t0000644000000000000000000000201014534467462013451 0ustar rootroot#!/usr/bin/perl use warnings; use strict; use Test::More tests => 6; use PDF::Builder; # Filename my $pdf = PDF::Builder->new('-compress' => 'none'); my $pnm = $pdf->image_pnm('t/resources/1x1.pbm'); isa_ok($pnm, 'PDF::Builder::Resource::XObject::Image::PNM', q{$pdf->image_pnm(filename)}); is($pnm->width(), 1, q{Image from filename has a width}); my $gfx = $pdf->page->gfx(); $gfx->image($pnm, 72, 144, 216, 288); like($pdf->to_string(), qr/q 216 0 0 288 72 144 cm \S+ Do Q/, q{Add PNM to PDF}); # Filehandle $pdf = PDF::Builder->new(); open my $fh, '<', 't/resources/1x1.pbm' or die "Can't open file t/resources/1x1.pbm"; $pnm = $pdf->image_pnm($fh); isa_ok($pnm, 'PDF::Builder::Resource::XObject::Image::PNM', q{$pdf->image_pnm(filehandle)}); is($pnm->width(), 1, q{Image from filehandle has a width}); close $fh; # Missing file $pdf = PDF::Builder->new(); eval { $pdf->image_pnm('t/resources/this.file.does.not.exist') }; ok($@, q{Fail fast if the requested file doesn't exist}); 1; PDF-Builder-3.026/t/00-all-usable.t0000644000000000000000000000574514534467462015137 0ustar rootroot#!/usr/bin/perl use warnings; use strict; use Test::More; use File::Find; # minimum versions, **if used** my $GrTFversion = 19; # minimum version of Graphics::TIFF my $HBShaperVer = 0.024; # minimum version of HarfBuzz::Shaper my $LpngVersion = 0.57; # minimum version of Image::PNG::Libpng my $TextMarkdown = 1.000031; # minimum version of Text::Markdown my $HTMLTreeBldr = 5.07; # minimum version of HTML::TreeBuilder my $PodSimpleXHTML = 3.45; # minimum version of Pod::Simple::XHTML # Test all of the modules to make sure that a simple "use Module" # won't result in a crash. # first, build files list of all .pm under lib/ my @files; find(\&add_to_files, 'lib'); sub add_to_files { return unless -f $_; return unless $_ =~ /\.pm$/; ### 3 currently disabled return if ($_ =~ m/CCITTFaxDecode\.pm$/); return if ($_ =~ m/Reader\.pm$/); return if ($_ =~ m/Writer\.pm$/); ### push @files, $File::Find::name; return; } plan tests => scalar @files; # test each one, skipping over certain name patterns my @opt_modules; foreach my $file (@files) { ($file) = $file =~ m|^lib/(.*)\.pm$|; $file =~ s|/|::|g; if ($file =~ /Win32/) { # require Windows system to run # not currently under lib/ anyway # "SKIP Windows module(s) not currently used" # next; } if ($file =~ /_GT$/) { # require Graphics::TIFF be installed # but rarely is on test platforms # check for Graphics::TIFF installed, and if so, run use test my $rc = eval { require Graphics::TIFF; 1; }; if (!defined $rc) { $rc = 0; } # else is 1 if ($rc) { if ($Graphics::TIFF::VERSION < $GrTFversion) { # installed, but back-level... skip push @opt_modules, $file; next; } # fall through to use test } else { push @opt_modules, $file; next; } } if ($file =~ /_IPL$/) { # require Image::PNG::Libpng be installed # but rarely is on test platforms # check for Image::PNG::Libpng installed, and if so, run use test my $rc = eval { require Image::PNG::Libpng; 1; }; if (!defined $rc) { $rc = 0; } # else is 1 if ($rc) { if ($Image::PNG::Libpng::VERSION < $LpngVersion) { # installed, but back-level... skip push @opt_modules, $file; next; } # fall through to use test } else { push @opt_modules, $file; next; } } # HarfBuzz::Shaper is built into Content.pm, doesn't have its own module # Text::Markdown is built into Content/Text.pm, doesn't have its own module # HTML::TreeBuilder is built into Content/Text.pm, doesn't have its own module # Pod::Simple::XHTML is built into buildDoc.pl, doesn't have its own module use_ok($file); } # special message and automatic pass for skipped-over modules TODO: { local $TODO = q{skipped due to optional library not installed}; foreach my $file (@opt_modules) { ok(1, $file); } } 1; PDF-Builder-3.026/t/rt120450.t0000644000000000000000000000034114534467462013765 0ustar rootroot#!/usr/bin/perl use warnings; use strict; use Test::More (tests => 1); use PDF::Builder; my $pdf = PDF::Builder->open('t/resources/sample.pdf'); ok($pdf->to_string(), q{open() followed by saveas() doesn't crash}); 1; PDF-Builder-3.026/t/deprecations.t0000644000000000000000000003712514534467462015356 0ustar rootroot#!/usr/bin/perl use strict; use warnings; use Test::More tests => 49; use PDF::Builder; my ($pdf, $page, $pdf2, $pdf_string, $media, $sizes_PDF, $sizes_page, @box); #### TBD when a deprecated interface is removed, keep the test for the new #### replacement here, while commenting out the old interface ## new_api -- removed from PDF::Builder, deprecated in PDF::API2 #use PDF::Builder::Resource::XObject::Image::JPEG; #$pdf = PDF::Builder->new(); #my $image = PDF::Builder::Resource::XObject::Image::JPEG->new_api($pdf, 't/resources/1x1.jpg'); #ok($image, q{new_api still works}); # TBD need test for replacement call # create a dummy PDF (as string) for further tests $pdf = PDF::Builder->new(); $pdf->page()->gfx()->fillcolor('blue'); $pdf_string = $pdf->to_string(); ## openScalar() -> open_scalar() -> from_string() $pdf = PDF::Builder->openScalar($pdf_string); is(ref($pdf), 'PDF::Builder', q{openScalar still works}); $pdf = PDF::Builder->open_scalar($pdf_string); is(ref($pdf), 'PDF::Builder', q{open_scalar replacement for openScalar IS available}); $pdf = PDF::Builder->from_string($pdf_string); is(ref($pdf), 'PDF::Builder', q{from_string replacement for openScalar and open_scalar IS available}); ## importpage() -> import_page() # removed from PDF::Builder, deprecated in PDF::API2 $pdf2 = PDF::Builder->new(); #$page = $pdf2->importpage($pdf, 1); #is(ref($page), 'PDF::Builder::Page', # q{importpage still works}); $page = $pdf2->import_page($pdf, 1); is(ref($page), 'PDF::Builder::Page', q{import_page replacement for importpage IS available}); ## openpage() -> open_page() # replaced by open_page in API2 $pdf2 = PDF::Builder->from_string($pdf_string); $page = $pdf2->openpage(1); is(ref($page), 'PDF::Builder::Page', q{openpage still works}); $page = $pdf2->open_page(1); is(ref($page), 'PDF::Builder::Page', q{open_page replacement for openpage IS available}); # PDF::Builder-specific cases to ADD tests for (deprecated but NOT yet removed): # ## elementsof() -> elements() $pdf2 = PDF::Builder->new(); $page = $pdf2->page(); # should be US letter [ 0 0 612 792 ] for default media #$media = $page->find_prop('MediaBox'); #$media = [ map { $_->val() } $media->elementsof() ]; #ok($media->[0]==0 && $media->[1]==0 && $media->[2]==612 && $media->[3]==792, #q{elementsof still works}); $media = $page->find_prop('MediaBox'); $media = [ map { $_->val() } $media->elements() ]; ok($media->[0]==0 && $media->[1]==0 && $media->[2]==612 && $media->[3]==792, q{elements replacement for elementsof IS available}); # removeobj() -> (gone) # get_mediabox() -> mediabox() # default mediabox size, inherited by page # should be US letter [ 0 0 612 792 ] for default media $sizes_PDF = [0, 0, 612, 792]; $sizes_page = [0, 0, 612, 792]; $pdf2 = PDF::Builder->new(); $page = $pdf2->page(); #@box = $page->get_mediabox(); #ok(array_comp($sizes_page, @box), # q{get_mediabox still works for default page media size}); @box = $pdf2->mediabox(); ok(array_comp($sizes_PDF, @box), q{mediabox IS available for default PDF media size}); @box = $page->mediabox(); ok(array_comp($sizes_page, @box), q{mediabox replacement for get_mediabox IS available for default page media size}); # set mediabox at PDF, page should inherit $sizes_PDF = [ 0, 0, 100, 150 ]; $sizes_page = [ 0, 0, 100, 150 ]; $pdf2 = PDF::Builder->new(); $pdf2->mediabox(0, 0, 100, 150); $page = $pdf2->page(); #@box = $page->get_mediabox(); #ok(array_comp($sizes_page, @box), # q{get_mediabox still works for PDF-set page media size}); @box = $pdf2->mediabox(); ok(array_comp($sizes_PDF, @box), q{mediabox IS available for PDF-set PDF media size}); @box = $page->mediabox(); ok(array_comp($sizes_page, @box), q{mediabox replacement for get_mediabox IS available for PDF-set page media size}); # set mediabox at page, PDF is default $sizes_PDF = [ 0, 0, 612, 792 ]; $sizes_page = [ 0, 0, 100, 150 ]; $pdf2 = PDF::Builder->new(); $page = $pdf2->page(); $page->mediabox(0, 0, 100, 150); #@box = $page->get_mediabox(); #ok(array_comp($sizes_page, @box), # q{get_mediabox still works for page-set page media size}); @box = $pdf2->mediabox(); ok(array_comp($sizes_PDF, @box), q{mediabox IS available for default PDF media size}); @box = $page->mediabox(); ok(array_comp($sizes_page, @box), q{mediabox replacement for get_mediabox IS available for page-set page media size}); # set mediabox at PDF and page $sizes_PDF = [ 0, 0, 200, 300 ]; $sizes_page = [ 0, 0, 100, 150 ]; $pdf2 = PDF::Builder->new(); $pdf2->mediabox(0, 0, 200, 300); $page = $pdf2->page(); $page->mediabox(0, 0, 100, 150); #@box = $page->get_mediabox(); #ok(array_comp($sizes_page, @box), # q{get_mediabox still works for page-set page media size}); @box = $pdf2->mediabox(); ok(array_comp($sizes_PDF, @box), q{mediabox IS available for PDF-set PDF media size}); @box = $page->mediabox(); ok(array_comp($sizes_page, @box), q{mediabox replacement for get_mediabox IS available for page-set page media size}); # get_cropbox() -> cropbox() # default cropbox size, inherited by page # should be US letter [ 0 0 612 792 ] for default media $sizes_PDF = [0, 0, 612, 792]; $sizes_page = [0, 0, 612, 792]; $pdf2 = PDF::Builder->new(); $page = $pdf2->page(); #@box = $page->get_cropbox(); #ok(array_comp($sizes_page, @box), # q{get_cropbox still works for default page cropbox size}); @box = $pdf2->cropbox(); ok(array_comp($sizes_PDF, @box), q{cropbox IS available for default PDF cropbox size}); @box = $page->cropbox(); ok(array_comp($sizes_page, @box), q{cropbox replacement for get_cropbox IS available for default page cropbox size}); # set cropbox at PDF, page should inherit $sizes_PDF = [ 0, 0, 100, 150 ]; $sizes_page = [ 0, 0, 100, 150 ]; $pdf2 = PDF::Builder->new(); $pdf2->cropbox(0, 0, 100, 150); $page = $pdf2->page(); #@box = $page->get_cropbox(); #ok(array_comp($sizes_page, @box), # q{get_cropbox still works for PDF-set page cropbox size}); @box = $pdf2->cropbox(); ok(array_comp($sizes_PDF, @box), q{cropbox IS available for PDF-set PDF cropbox size}); @box = $page->cropbox(); ok(array_comp($sizes_page, @box), q{cropbox replacement for get_cropbox IS available for PDF-set page cropbox size}); # set cropbox at page, PDF is default $sizes_PDF = [ 0, 0, 612, 792 ]; $sizes_page = [ 0, 0, 100, 150 ]; $pdf2 = PDF::Builder->new(); $page = $pdf2->page(); $page->cropbox(0, 0, 100, 150); #@box = $page->get_cropbox(); #ok(array_comp($sizes_page, @box), # q{get_cropbox still works for page-set page cropbox size}); @box = $pdf2->cropbox(); ok(array_comp($sizes_PDF, @box), q{cropbox IS available for default PDF cropbox size}); @box = $page->cropbox(); ok(array_comp($sizes_page, @box), q{cropbox replacement for get_cropbox IS available for page-set page cropbox size}); # set cropbox at PDF and page $sizes_PDF = [ 0, 0, 200, 300 ]; $sizes_page = [ 0, 0, 100, 150 ]; $pdf2 = PDF::Builder->new(); $pdf2->cropbox(0, 0, 200, 300); $page = $pdf2->page(); $page->cropbox(0, 0, 100, 150); #@box = $page->get_cropbox(); #ok(array_comp($sizes_page, @box), # q{get_cropbox still works for page-set page cropbox size}); @box = $pdf2->cropbox(); ok(array_comp($sizes_PDF, @box), q{cropbox IS available for PDF-set PDF cropbox size}); @box = $page->cropbox(); ok(array_comp($sizes_page, @box), q{cropbox replacement for get_cropbox IS available for page-set page cropbox size}); # get_bleedbox() -> bleedbox() # default bleedbox size, inherited by page # should be US letter [ 0 0 612 792 ] for default media $sizes_PDF = [0, 0, 612, 792]; $sizes_page = [0, 0, 612, 792]; $pdf2 = PDF::Builder->new(); $page = $pdf2->page(); #@box = $page->get_bleedbox(); #ok(array_comp($sizes_page, @box), # q{get_bleedbox still works for default page bleedbox size}); @box = $pdf2->bleedbox(); ok(array_comp($sizes_PDF, @box), q{bleedbox IS available for default PDF bleedbox size}); @box = $page->bleedbox(); ok(array_comp($sizes_page, @box), q{bleedbox replacement for get_bleedbox IS available for default page bleedbox size}); # set bleedbox at PDF, page should inherit $sizes_PDF = [ 0, 0, 100, 150 ]; $sizes_page = [ 0, 0, 100, 150 ]; $pdf2 = PDF::Builder->new(); $pdf2->bleedbox(0, 0, 100, 150); $page = $pdf2->page(); #@box = $page->get_bleedbox(); #ok(array_comp($sizes_page, @box), # q{get_bleedbox still works for PDF-set page bleedbox size}); @box = $pdf2->bleedbox(); ok(array_comp($sizes_PDF, @box), q{bleedbox IS available for PDF-set PDF bleedbox size}); @box = $page->bleedbox(); ok(array_comp($sizes_page, @box), q{bleedbox replacement for get_bleedbox IS available for PDF-set page bleedbox size}); # set bleedbox at page, PDF is default $sizes_PDF = [ 0, 0, 612, 792 ]; $sizes_page = [ 0, 0, 100, 150 ]; $pdf2 = PDF::Builder->new(); $page = $pdf2->page(); $page->bleedbox(0, 0, 100, 150); #@box = $page->get_bleedbox(); #ok(array_comp($sizes_page, @box), # q{get_bleedbox still works for page-set page bleedbox size}); @box = $pdf2->bleedbox(); ok(array_comp($sizes_PDF, @box), q{bleedbox IS available for default PDF bleedbox size}); @box = $page->bleedbox(); ok(array_comp($sizes_page, @box), q{bleedbox replacement for get_bleedbox IS available for page-set page bleedbox size}); # set bleedbox at PDF and page $sizes_PDF = [ 0, 0, 200, 300 ]; $sizes_page = [ 0, 0, 100, 150 ]; $pdf2 = PDF::Builder->new(); $pdf2->bleedbox(0, 0, 200, 300); $page = $pdf2->page(); $page->bleedbox(0, 0, 100, 150); #@box = $page->get_bleedbox(); #ok(array_comp($sizes_page, @box), # q{get_bleedbox still works for page-set page bleedbox size}); @box = $pdf2->bleedbox(); ok(array_comp($sizes_PDF, @box), q{bleedbox IS available for PDF-set PDF bleedbox size}); @box = $page->bleedbox(); ok(array_comp($sizes_page, @box), q{bleedbox replacement for get_bleedbox IS available for page-set page bleedbox size}); # get_trimbox() -> trimbox() # default trimbox size, inherited by page # should be US letter [ 0 0 612 792 ] for default media $sizes_PDF = [0, 0, 612, 792]; $sizes_page = [0, 0, 612, 792]; $pdf2 = PDF::Builder->new(); $page = $pdf2->page(); #@box = $page->get_trimbox(); #ok(array_comp($sizes_page, @box), # q{get_trimbox still works for default page trimbox size}); @box = $pdf2->trimbox(); ok(array_comp($sizes_PDF, @box), q{trimbox IS available for default PDF trimbox size}); @box = $page->trimbox(); ok(array_comp($sizes_page, @box), q{trimbox replacement for get_trimbox IS available for default page trimbox size}); # set trimbox at PDF, page should inherit $sizes_PDF = [ 0, 0, 100, 150 ]; $sizes_page = [ 0, 0, 100, 150 ]; $pdf2 = PDF::Builder->new(); $pdf2->trimbox(0, 0, 100, 150); $page = $pdf2->page(); #@box = $page->get_trimbox(); #ok(array_comp($sizes_page, @box), # q{get_trimbox still works for PDF-set page trimbox size}); @box = $pdf2->trimbox(); ok(array_comp($sizes_PDF, @box), q{trimbox IS available for PDF-set PDF trimbox size}); @box = $page->trimbox(); ok(array_comp($sizes_page, @box), q{trimbox replacement for get_trimbox IS available for PDF-set page trimbox size}); # set trimbox at page, PDF is default $sizes_PDF = [ 0, 0, 612, 792 ]; $sizes_page = [ 0, 0, 100, 150 ]; $pdf2 = PDF::Builder->new(); $page = $pdf2->page(); $page->trimbox(0, 0, 100, 150); #@box = $page->get_trimbox(); #ok(array_comp($sizes_page, @box), # q{get_trimbox still works for page-set page trimbox size}); @box = $pdf2->trimbox(); ok(array_comp($sizes_PDF, @box), q{trimbox IS available for default PDF trimbox size}); @box = $page->trimbox(); ok(array_comp($sizes_page, @box), q{trimbox replacement for get_trimbox IS available for page-set page trimbox size}); # set trimbox at PDF and page $sizes_PDF = [ 0, 0, 200, 300 ]; $sizes_page = [ 0, 0, 100, 150 ]; $pdf2 = PDF::Builder->new(); $pdf2->trimbox(0, 0, 200, 300); $page = $pdf2->page(); $page->trimbox(0, 0, 100, 150); #@box = $page->get_trimbox(); #ok(array_comp($sizes_page, @box), # q{get_trimbox still works for page-set page trimbox size}); @box = $pdf2->trimbox(); ok(array_comp($sizes_PDF, @box), q{trimbox IS available for PDF-set PDF trimbox size}); @box = $page->trimbox(); ok(array_comp($sizes_page, @box), q{trimbox replacement for get_trimbox IS available for page-set page trimbox size}); # get_artbox() -> artbox() # default artbox size, inherited by page # should be US letter [ 0 0 612 792 ] for default media $sizes_PDF = [0, 0, 612, 792]; $sizes_page = [0, 0, 612, 792]; $pdf2 = PDF::Builder->new(); $page = $pdf2->page(); #@box = $page->get_artbox(); #ok(array_comp($sizes_page, @box), # q{get_artbox still works for default page artbox size}); @box = $pdf2->artbox(); ok(array_comp($sizes_PDF, @box), q{artbox IS available for default PDF artbox size}); @box = $page->artbox(); ok(array_comp($sizes_page, @box), q{artbox replacement for get_artbox IS available for default page artbox size}); # set artbox at PDF, page should inherit $sizes_PDF = [ 0, 0, 100, 150 ]; $sizes_page = [ 0, 0, 100, 150 ]; $pdf2 = PDF::Builder->new(); $pdf2->artbox(0, 0, 100, 150); $page = $pdf2->page(); #@box = $page->get_artbox(); #ok(array_comp($sizes_page, @box), # q{get_artbox still works for PDF-set page artbox size}); @box = $pdf2->artbox(); ok(array_comp($sizes_PDF, @box), q{artbox IS available for PDF-set PDF artbox size}); @box = $page->artbox(); ok(array_comp($sizes_page, @box), q{artbox replacement for get_artbox IS available for PDF-set page artbox size}); # set artbox at page, PDF is default $sizes_PDF = [ 0, 0, 612, 792 ]; $sizes_page = [ 0, 0, 100, 150 ]; $pdf2 = PDF::Builder->new(); $page = $pdf2->page(); $page->artbox(0, 0, 100, 150); #@box = $page->get_artbox(); #ok(array_comp($sizes_page, @box), # q{get_artbox still works for page-set page artbox size}); @box = $pdf2->artbox(); ok(array_comp($sizes_PDF, @box), q{artbox IS available for default PDF artbox size}); @box = $page->artbox(); ok(array_comp($sizes_page, @box), q{artbox replacement for get_artbox IS available for page-set page artbox size}); # set artbox at PDF and page $sizes_PDF = [ 0, 0, 200, 300 ]; $sizes_page = [ 0, 0, 100, 150 ]; $pdf2 = PDF::Builder->new(); $pdf2->artbox(0, 0, 200, 300); $page = $pdf2->page(); $page->artbox(0, 0, 100, 150); #@box = $page->get_artbox(); #ok(array_comp($sizes_page, @box), # q{get_artbox still works for page-set page artbox size}); @box = $pdf2->artbox(); ok(array_comp($sizes_PDF, @box), q{artbox IS available for PDF-set PDF artbox size}); @box = $page->artbox(); ok(array_comp($sizes_page, @box), q{artbox replacement for get_artbox IS available for page-set page artbox size}); # Invalid input to pageLabel { # for local declaration $pdf = PDF::Builder->new(); local $SIG{__WARN__} = sub {}; $pdf->pageLabel(0, { 'style' => 'arabic' }); like($pdf->to_string(), qr{/PageLabels << /Nums \[ 0 << /S /D >> \] >>}, q{pageLabel defaults to decimal if given invalid input}); } ## ## ===== scheduled to be REMOVED 3/2023 ## lead() -> leading() #$pdf2 = PDF::Builder->new('compress' => 'none'); #my $text = $pdf2->page()->text(); #$text->lead(15); #like($pdf2->to_string(), qr/15 TL/, q{lead still works }); $pdf2 = PDF::Builder->new('compress' => 'none'); my $text = $pdf2->page()->text(); $text->leading(15); like($pdf2->to_string(), qr/15 TL/, q{leading replacement for lead IS available}); ## ## textlead() -> textleading() Lite.pm only, no t test # if nothing left to check... #is(ref($pdf), 'PDF::Builder', # q{No deprecated tests to run at this time}); sub array_comp { my ($expected_size_ref, @got_size) = @_; my $len_e = scalar(@{$expected_size_ref}); my $len_g = scalar(@got_size); if ($len_e != $len_g) { return 0; } for (my $e = 0; $e < $len_e; $e++) { if ($expected_size_ref->[$e] != $got_size[$e]) { return 0; } } return 1; } 1; PDF-Builder-3.026/t/viewer-preferences.t0000644000000000000000000000120514534467462016464 0ustar rootroot#!/usr/bin/perl use strict; use warnings; use Test::More tests => 3; use PDF::Builder; my $pdf = PDF::Builder->new(); $pdf->preferences(-simplex => 1); like($pdf->to_string(), qr{/ViewerPreferences << [^>]*?/Duplex /Simplex}, q{Duplex => Simplex}); $pdf = PDF::Builder->new(); $pdf->preferences(-duplexfliplongedge => 1); like($pdf->to_string(), qr{/ViewerPreferences << [^>]*?/Duplex /DuplexFlipLongEdge}, q{Duplex => DuplexFlipLongEdge}); $pdf = PDF::Builder->new(); $pdf->preferences(-duplexflipshortedge => 1); like($pdf->to_string(), qr{/ViewerPreferences << [^>]*?/Duplex /DuplexFlipShortEdge}, q{Duplex => DuplexFlipShortEdge}); 1; PDF-Builder-3.026/t/03-xrefstm-index.t0000644000000000000000000000107214534467462015703 0ustar rootroot#!/usr/bin/perl use warnings; use strict; use Test::More tests => 3; use PDF::Builder; my $pdf = PDF::Builder->open('t/resources/sample-xrefstm-index.pdf', 'outver'=>1.5); isa_ok($pdf, 'PDF::Builder', q{PDF::Builder->open() on a PDF with a cross-reference stream using an Index returns a PDF::Builder object}); my $object = $pdf->{'pdf'}->read_objnum(9, 0); ok($object, q{Read the high object from an indexed object stream}); $object = $pdf->{'pdf'}->read_objnum(12, 0); ok($object, q{Read the low object from an indexed object stream}); 1; PDF-Builder-3.026/t/circular-references.t0000644000000000000000000000227214534467462016614 0ustar rootroot#!/usr/bin/perl use strict; use warnings; use Test::More; use Test::Exception; use PDF::Builder; use Scalar::Util qw(isweak); use Test::Memory::Cycle; # RT #56681: Devel::Cycle throws spurious warnings since 5.12 local $SIG{'__WARN__'} = sub { warn $_[0] unless $_[0] =~ /Unhandled type: GLOB/ }; # (1) Read a simple PDF my $pdf = PDF::Builder->open('t/resources/sample.pdf'); memory_cycle_ok($pdf, q{Open sample.pdf}); # TODO: Create a sample PDF that uses as much PDF::Builder functionality as # possible (outlines and annotations in particular) to build confidence that all # circular references have been removed. # Check pagestack weakened status my $page = $pdf->page(); ok(isweak($pdf->{'pagestack'}->[-1]), q{An appended page is marked as weakened in the page stack}); $page = $pdf->page(1); ok(isweak($pdf->{'pagestack'}->[0]), q{A prepended page is marked as weakened in the page stack}); $page = $pdf->page(1); ok(isweak($pdf->{'pagestack'}->[1]), q{A spliced page is marked as weakened in the page stack}); # Font out of scope { $pdf->corefont('Helvetica'); } lives_ok(sub { $pdf->to_string() }, 'Font added inside a block is still present on save'); done_testing(); 1; PDF-Builder-3.026/t/lite.t0000644000000000000000000000252614534467462013630 0ustar rootroot#!/usr/bin/perl use warnings; use strict; use Test::More tests => 10; use PDF::Builder::Lite; my $pdf = PDF::Builder::Lite->new(); isa_ok($pdf,'PDF::Builder::Lite'); # check return values for methods without arguments isa_ok($pdf->page,'PDF::Builder::Lite'); # check return value for method requireing aruments isa_ok($pdf->mediabox(100,100),'PDF::Builder::Lite'); # testing serializing (stringify) # this destroys something so further tests needs a refresh # this method also contains some code which is never executed? my $str = $pdf->saveas('-'); my @lines = split/\x0a/ , $str; is($lines[0],"%PDF-1.4","PDF default version is 1.4 for PDF::Builder::Lite"); is($lines[-1],"%%EOF","correct ending eof sequence"); $pdf = PDF::Builder::Lite->new(); my $font; $font = $pdf->corefont('Times-Roman'); isa_ok($font,'PDF::Builder::Resource::Font::CoreFont'); $font = $pdf->corefont('Times-Bold'); isa_ok($font,'PDF::Builder::Resource::Font::CoreFont'); $font = $pdf->corefont('Helvetica'); isa_ok($font,'PDF::Builder::Resource::Font::CoreFont'); $font = $pdf->corefont('ZapfDingbats'); isa_ok($font,'PDF::Builder::Resource::Font::CoreFont'); $pdf = PDF::Builder::Lite->new(); # RT #58386 my $egstate = $pdf->create_egs(); is(ref($egstate), 'PDF::Builder::Resource::ExtGState', q{create_egs returns an extended graphics state object instead of dying}); 1; PDF-Builder-3.026/t/content-deprecated.t0000644000000000000000000002061614534467462016443 0ustar rootroot#!/usr/bin/perl use warnings; use strict; use Test::More; use PDF::Builder; # for Builder, many of these method names are actually still the primary # names; those added for PDF::API2 are the alternates (though not deprecated) ### testing for PDF::Builder::Content and Content::Text # Transform my $pdf = PDF::Builder->new('compress' => 0); my $gfx = $pdf->page->gfx(); $gfx->transform(-translate => [20, 50], -rotate => 10, -scale => [1.5, 3], -skew => [10, -20]); $gfx->transform(-translate => [20, 50], -rotate => 10, -scale => [1.5, 3], -skew => [10, -20]); like($pdf->to_string, qr/1.3854 0.78142 -1.0586 2.8596 20 50 cm 1.3854 0.78142 -1.0586 2.8596 20 50 cm/, q{transform + transform}); # Relative Transform $pdf = PDF::Builder->new('compress' => 0); $gfx = $pdf->page->gfx(); $gfx->transform(-translate => [20, 50], -rotate => 10, -scale => [1.5, 3], -skew => [10, -20]); $gfx->transform_rel(-translate => [10, 10], -rotate => 10, -scale => [2, 4], -skew => [5, -10]); like($pdf->to_string, qr/1.3854 0.78142 -1.0586 2.8596 20 50 cm 1.7193 4.0475 -5.7318 10.684 30 60 cm/, q{transform + transform_rel}); # Fill Color $pdf = PDF::Builder->new('compress' => 0); $gfx = $pdf->page->gfx(); $gfx->fillcolor('blue'); like($pdf->to_string(), qr/0 0 1 rg/, q{fillcolor('blue')}); # Stroke Color $pdf = PDF::Builder->new('compress' => 0); $gfx = $pdf->page->gfx(); $gfx->strokecolor('blue'); like($pdf->to_string(), qr/0 0 1 RG/, q{strokecolor('blue')}); # Line Width $pdf = PDF::Builder->new('compress' => 0); $gfx = $pdf->page->gfx(); $gfx->linewidth(8.125); like($pdf->to_string, qr/8.125 w/, q{linewidth(8.125)}); # Line Cap Style $pdf = PDF::Builder->new('compress' => 0); $gfx = $pdf->page->gfx(); $gfx->linecap(1); like($pdf->to_string, qr/1 J/, q{linecap(1)}); # Line Join Style $pdf = PDF::Builder->new('compress' => 0); $gfx = $pdf->page->gfx(); $gfx->linejoin(1); like($pdf->to_string, qr/1 j/, q{linejoin(1)}); # Miter Limit $pdf = PDF::Builder->new('compress' => 0); $gfx = $pdf->page->gfx(); $gfx->miterlimit(3); like($pdf->to_string, qr/3 M/, q{miterlimit(3)}); # Miter Limit (deprecated typo) # #$pdf = PDF::Builder->new('compress' => 0); #$gfx = $pdf->page->gfx(); # #$gfx->meterlimit(3); #like($pdf->to_string, qr/3 M/, q{meterlimit(3)}); # Line Dash $pdf = PDF::Builder->new('compress' => 0); $gfx = $pdf->page->gfx(); $gfx->linedash(3); like($pdf->to_string, qr/\[ 3 \] 0 d/, q{linedash(3)}); # Flatness Tolerance $pdf = PDF::Builder->new('compress' => 0); $gfx = $pdf->page->gfx(); $gfx->flatness(5); like($pdf->to_string, qr/5 i/, q{flatness(5)}); ## ## PATH CONSTRUCTION ## # Poly-Line (4 args, 1 line segment) $pdf = PDF::Builder->new('compress' => 0); $gfx = $pdf->page->gfx(); $gfx->poly(72, 144, 216, 288); $gfx->stroke(); like($pdf->to_string, qr/72 144 m 216 288 l S/, q{poly, four arguments}); # Poly-Line (6 args, 2 line segments) $pdf = PDF::Builder->new('compress' => 0); $gfx = $pdf->page->gfx(); $gfx->poly(72, 144, 216, 288, 100, 200); $gfx->stroke(); like($pdf->to_string, qr/72 144 m 216 288 l 100 200 l S/, q{poly, six arguments}); # Rectangle $pdf = PDF::Builder->new('compress' => 0); $gfx = $pdf->page->gfx(); $gfx->rect(100, 200, 25, 50); $gfx->stroke(); $gfx->rect(100, 200, 25, -50); $gfx->stroke(); $gfx->rect(200, 300, 50, 75, 400, 800, 10, 15); $gfx->stroke(); like($pdf->to_string, qr/100 200 25 50 re S 100 200 25 -50 re S 200 300 50 75 re 400 800 10 15 re S/, q{rect}); # XY Rectangle $pdf = PDF::Builder->new('compress' => 0); $gfx = $pdf->page->gfx(); $gfx->rectxy(100, 200, 125, 250); $gfx->stroke(); $gfx->rectxy(100, 200, 125, 150); $gfx->stroke(); like($pdf->to_string, qr/100 200 25 50 re S 100 200 25 -50 re S/, q{rectxy}); # Bogen (with move) $pdf = PDF::Builder->new('compress' => 0); $gfx = $pdf->page->gfx(); $gfx->bogen(72, 72, 216, 72, 72, 1); $gfx->stroke(); like($pdf->to_string, qr/72 72 m 72 81.455 73.862 90.818 77.481 99.553 c 81.099 108.29 86.402 116.23 93.088 122.91 c 99.774 129.6 107.71 134.9 116.45 138.52 c 125.18 142.14 134.54 144 144 144 c 153.46 144 162.82 142.14 171.55 138.52 c 180.29 134.9 188.23 129.6 194.91 122.91 c 201.6 116.23 206.9 108.29 210.52 99.553 c 214.14 90.818 216 81.455 216 72 c S/, q{bogen, with move}); # Bogen (without move) $pdf = PDF::Builder->new('compress' => 0); $gfx = $pdf->page->gfx(); $gfx->move(72, 72); $gfx->bogen(72, 72, 216, 72, 72, 0); $gfx->stroke(); like($pdf->to_string, qr/72 72 m 72 81.455 73.862 90.818 77.481 99.553 c 81.099 108.29 86.402 116.23 93.088 122.91 c 99.774 129.6 107.71 134.9 116.45 138.52 c 125.18 142.14 134.54 144 144 144 c 153.46 144 162.82 142.14 171.55 138.52 c 180.29 134.9 188.23 129.6 194.91 122.91 c 201.6 116.23 206.9 108.29 210.52 99.553 c 214.14 90.818 216 81.455 216 72 c S/, q{bogen, without move}); # Bogen (with move, outer) $pdf = PDF::Builder->new('compress' => 0); $gfx = $pdf->page->gfx(); $gfx->move(72, 72); $gfx->bogen(72, 72, 144, 144, 72, 0, 1); $gfx->stroke(); like($pdf->to_string, qr/72 72 m 64.919 72 57.876 73.045 51.1 75.1 c 44.323 77.156 37.887 80.2 31.999 84.134 c 26.111 88.068 20.836 92.85 16.343 98.324 c 11.851 103.8 8.1906 109.9 5.4807 116.45 c 2.7707 122.99 1.0408 129.9 0.3467 136.94 c -0.3474 143.99 0.00195 151.1 1.3835 158.05 c 2.765 164.99 5.1635 171.7 8.5017 177.94 c 11.84 184.19 16.081 189.9 21.088 194.91 c 26.096 199.92 31.814 204.16 38.059 207.5 c 44.305 210.84 51.008 213.24 57.953 214.62 c 64.899 216 72.01 216.35 79.057 215.65 c 86.105 214.96 93.011 213.23 99.553 210.52 c 106.1 207.81 112.2 204.15 117.68 199.66 c 123.15 195.16 127.93 189.89 131.87 184 c 135.8 178.11 138.84 171.68 140.9 164.9 c 142.96 158.12 144 151.08 144 144 c S/, q{bogen, without move, with outer}); # Bogen (without move, inner, reverse) $pdf = PDF::Builder->new('compress' => 0); $gfx = $pdf->page->gfx(); $gfx->move(72, 72); $gfx->bogen(72, 72, 144, 144, 72, 0, 0, 1); $gfx->stroke(); like($pdf->to_string, qr/72 72 m 81.455 72 90.818 73.862 99.553 77.481 c 108.29 81.099 116.23 86.402 122.91 93.088 c 129.6 99.774 134.9 107.71 138.52 116.45 c 142.14 125.18 144 134.54 144 144 c S/, q{bogen, without move, without outer, with reverse}); # End Path $pdf = PDF::Builder->new('compress' => 0); $gfx = $pdf->page->gfx(); $gfx->move(72, 144); $gfx->line(216, 288); $gfx->endpath(); like($pdf->to_string, qr/72 144 m 216 288 l n/, q{endpath}); # Horizontal Scale (deprecated) # #$pdf = PDF::Builder->new('compress' => 0); #$gfx = $pdf->page->gfx(); # #$gfx->hspace(105); #like($pdf->to_string, qr/105 Tz/, q{hspace(105)}); # Fill Path (even-odd rule) $pdf = PDF::Builder->new('compress' => 0); $gfx = $pdf->page->gfx(); $gfx->fill(1); $gfx->close(); $gfx->stroke(); like($pdf->to_string, qr/f\* h S/, q{fill(1)}); # Fill and Stroke $pdf = PDF::Builder->new('compress' => 0); $gfx = $pdf->page->gfx(); $gfx->fillstroke(); $gfx->close(); $gfx->stroke(); like($pdf->to_string, qr/B h S/, q{fillstroke()}); # Fill and Stroke (even-odd rule) $pdf = PDF::Builder->new('compress' => 0); $gfx = $pdf->page->gfx(); $gfx->fillstroke(1); $gfx->close(); $gfx->stroke(); like($pdf->to_string, qr/B\* h S/, q{fillstroke(1)}); # Clipping Path (even-odd rule) $pdf = PDF::Builder->new('compress' => 0); $gfx = $pdf->page->gfx(); $gfx->clip(1); $gfx->close(); $gfx->stroke(); like($pdf->to_string, qr/W\* h S/, q{clip(1)}); # Character Spacing $pdf = PDF::Builder->new('compress' => 0); $gfx = $pdf->page->gfx(); $gfx->charspace(2); like($pdf->to_string, qr/2 Tc/, q{charspace(2)}); # Word Spacing $pdf = PDF::Builder->new('compress' => 0); $gfx = $pdf->page->gfx(); $gfx->wordspace(2); like($pdf->to_string, qr/2 Tw/, q{wordspace(2)}); ## Text Leading # #$pdf = PDF::Builder->new('compress' => 0); #$gfx = $pdf->page->gfx(); # #$gfx->lead(14); #like($pdf->to_string, qr/14 TL/, q{lead(14) (deprecated)}); # distance $pdf = PDF::Builder->new('compress' => 0); $gfx = $pdf->page->gfx(); $gfx->distance(3, 4); like($pdf->to_string, qr/3 4 Td/, q{distance(3, 4)}); # cr $pdf = PDF::Builder->new('compress' => 0); $gfx = $pdf->page->gfx(); $gfx->cr(); $gfx->cr(12.5); $gfx->cr(0); like($pdf->to_string, qr/T\* 0 12.5 Td 0 0 Td/, q{cr}); # nl $pdf = PDF::Builder->new('compress' => 0); $gfx = $pdf->page->gfx(); $gfx->nl(); like($pdf->to_string, qr/T\*/, q{nl}); done_testing(); 1; PDF-Builder-3.026/t/page.t0000644000000000000000000001312014534467462013577 0ustar rootroot#!/usr/bin/perl use warnings; use strict; use Test::More tests => 84; use PDF::Builder; my $pdf = PDF::Builder->new(); my $page = $pdf->page(); # notice that page->*box is used to GET the values just SET $pdf->mediabox(100, 200); my @mediabox = $page->mediabox(); is($mediabox[0], 0, 'Global Mediabox LLX'); is($mediabox[1], 0, 'Global Mediabox LLY'); is($mediabox[2], 100, 'Global Mediabox URX'); is($mediabox[3], 200, 'Global Mediabox URY'); $pdf->cropbox(200, 300); my @cropbox = $page->cropbox(); is($cropbox[0], 0, 'Global Cropbox LLX'); is($cropbox[1], 0, 'Global Cropbox LLY'); is($cropbox[2], 200, 'Global Cropbox URX'); is($cropbox[3], 300, 'Global Cropbox URY'); $pdf->bleedbox(200, 300); my @bleedbox = $page->bleedbox(); is($bleedbox[0], 0, 'Global Bleedbox LLX'); is($bleedbox[1], 0, 'Global Bleedbox LLY'); is($bleedbox[2], 200, 'Global Bleedbox URX'); is($bleedbox[3], 300, 'Global Bleedbox URY'); $pdf->trimbox(200, 300); my @trimbox = $page->trimbox(); is($trimbox[0], 0, 'Global Trimbox LLX'); is($trimbox[1], 0, 'Global Trimbox LLY'); is($trimbox[2], 200, 'Global Trimbox URX'); is($trimbox[3], 300, 'Global Trimbox URY'); $pdf->artbox(200, 300); my @artbox = $page->artbox(); is($artbox[0], 0, 'Global Artbox LLX'); is($artbox[1], 0, 'Global Artbox LLY'); is($artbox[2], 200, 'Global Artbox URX'); is($artbox[3], 300, 'Global Artbox URY'); # Page Size $page->size('letter'); my @box = $page->_bounding_box('MediaBox'); is($box[0], 0, q{$page->size('letter') X1}); is($box[1], 0, q{$page->size('letter') Y1}); is($box[2], 612, q{$page->size('letter') X2}); is($box[3], 792, q{$page->size('letter') Y2}); # Page Boundaries $page->boundaries('media' => 'letter'); @box = $page->_bounding_box('MediaBox'); is($box[0], 0, q{$page->boundaries(media => 'letter') X1}); is($box[1], 0, q{$page->boundaries(media => 'letter') Y1}); is($box[2], 612, q{$page->boundaries(media => 'letter') X2}); is($box[3], 792, q{$page->boundaries(media => 'letter') Y2}); $page->boundaries('media' => '12x18', 'trim' => 0.5 * 72); @box = $page->_bounding_box('MediaBox'); is($box[0], 0, q{$page->boundaries('media' => '12x18') X1}); is($box[1], 0, q{$page->boundaries('media' => '12x18') Y1}); is($box[2], 12 * 72, q{$page->boundaries('media' => '12x18') X2}); is($box[3], 18 * 72, q{$page->boundaries('media' => '12x18') Y2}); @box = $page->_bounding_box('TrimBox'); is($box[0], 36, q{Single-argument trim X1}); is($box[1], 36, q{Single-argument trim Y1}); is($box[2], 828, q{Single-argument trim X2}); is($box[3], 1260, q{Single-argument trim Y2}); # Default Page Size $pdf->default_page_size('letter'); @box = $pdf->_bounding_box('MediaBox'); is($box[0], 0, q{$pdf->default_page_size('letter') X1}); is($box[1], 0, q{$pdf->default_page_size('letter') Y1}); is($box[2], 612, q{$pdf->default_page_size('letter') X2}); is($box[3], 792, q{$pdf->default_page_size('letter') Y2}); # Default Page Boundaries $pdf->default_page_boundaries('media' => 'letter'); @box = $pdf->_bounding_box('MediaBox'); is($box[0], 0, q{$page->boundaries('media' => 'letter') X1}); is($box[1], 0, q{$page->boundaries('media' => 'letter') Y1}); is($box[2], 612, q{$page->boundaries('media' => 'letter') X2}); is($box[3], 792, q{$page->boundaries('media' => 'letter') Y2}); $pdf->default_page_boundaries(media => '12x18', trim => 0.5 * 72); @box = $pdf->_bounding_box('MediaBox'); is($box[0], 0, q{$page->boundaries('media' => '12x18') X1}); is($box[1], 0, q{$page->boundaries('media' => '12x18') Y1}); is($box[2], 12 * 72, q{$page->boundaries('media' => '12x18') X2}); is($box[3], 18 * 72, q{$page->boundaries('media' => '12x18') Y2}); @box = $pdf->_bounding_box('TrimBox'); is($box[0], 36, q{Single-argument trim X1}); is($box[1], 36, q{Single-argument trim Y1}); is($box[2], 828, q{Single-argument trim X2}); is($box[3], 1260, q{Single-argument trim Y2}); $page->mediabox(720, 1440); @mediabox = $page->mediabox(); is($mediabox[0], 0, 'Mediabox LLX'); is($mediabox[1], 0, 'Mediabox LLY'); is($mediabox[2], 720, 'Mediabox URX'); is($mediabox[3], 1440, 'Mediabox URY'); $page->mediabox('LEDGER'); @mediabox = $page->mediabox(); is($mediabox[0], 0, 'Mediabox LLX (ledger)'); is($mediabox[1], 0, 'Mediabox LLY (ledger)'); is($mediabox[2], 1224, 'Mediabox URX (ledger)'); is($mediabox[3], 792, 'Mediabox URY (ledger)'); $page->mediabox('non-existent'); @mediabox = $page->mediabox(); is($mediabox[0], 0, 'Mediabox LLX (unknown named type)'); is($mediabox[1], 0, 'Mediabox LLY (unknown named type)'); is($mediabox[2], 612, 'Mediabox URX (unknown named type)'); is($mediabox[3], 792, 'Mediabox URY (unknown named type)'); $page->mediabox(1, 2, 3, 4); @mediabox = $page->mediabox(); is($mediabox[0], 1, 'Mediabox LLX (offset)'); is($mediabox[1], 2, 'Mediabox LLY (offset)'); is($mediabox[2], 3, 'Mediabox URX (offset)'); is($mediabox[3], 4, 'Mediabox URY (offset)'); $page->cropbox(10, 20); @cropbox = $page->cropbox(); is($cropbox[0], 0, 'Cropbox LLX'); is($cropbox[1], 0, 'Cropbox LLY'); is($cropbox[2], 10, 'Cropbox URX'); is($cropbox[3], 20, 'Cropbox URY'); $page->bleedbox(30, 40); @bleedbox = $page->bleedbox(); is($bleedbox[0], 0, 'Bleedbox LLX'); is($bleedbox[1], 0, 'Bleedbox LLY'); is($bleedbox[2], 30, 'Bleedbox URX'); is($bleedbox[3], 40, 'Bleedbox URY'); $page->trimbox(50, 60); @trimbox = $page->trimbox(); is($trimbox[0], 0, 'Trimbox LLX'); is($trimbox[1], 0, 'Trimbox LLY'); is($trimbox[2], 50, 'Trimbox URX'); is($trimbox[3], 60, 'Trimbox URY'); $page->artbox(70, 80); @artbox = $page->artbox(); is($artbox[0], 0, 'Artbox LLX'); is($artbox[1], 0, 'Artbox LLY'); is($artbox[2], 70, 'Artbox URX'); is($artbox[3], 80, 'Artbox URY'); done_testing(); 1; PDF-Builder-3.026/t/version.t0000644000000000000000000000454714534467462014365 0ustar rootroot#!/usr/bin/perl use strict; use warnings; use Test::More; use PDF::Builder; # PDF::API2 changed header to 1.3, but PDF::Builder doesn't permit # PDF::Builder will warn if PDF version is decreased my $pdf = PDF::Builder->new('compress' => 0); # default header 1.4, no trailer $pdf->{'pdf'}->header_version('1.5'); # header says 1.5 $pdf->{'pdf'}->trailer_version('1.6'); # trailer says 1.6 is($pdf->version(), '1.6', # trailer overrides header 1.6 vs 1.5 q{version() returns whichever version is largest (1/2)}); $pdf->{'pdf'}->header_version('1.7'); is($pdf->version(), '1.7', # header overrides trailer 1.7 vs 1.6 q{version() returns whichever version is largest (2/2)}); $pdf->version('1.8'); # sets both header and trailer versions to 1.8 is($pdf->version(), '1.8', # larger of H/T. then check individually q{version() is settable}); is($pdf->{'pdf'}->header_version(), '1.8', # expect 1.8, set by version q{version() set header version}); is($pdf->{'pdf'}->trailer_version(), '1.8', # expect 1.8, set by version q{version() set trailer version}); my $string = $pdf->to_string(); like($string, qr/%PDF-1.8/, q{Expected header version is present}); like($string, qr{/Version /1.8}, q{Expected trailer version is present}); $pdf = PDF::Builder->new('compress' => 0); $pdf->{'pdf'}->header_version('2.3'); $pdf->{'pdf'}->trailer_version('2.4'); # header 2.3, trailer 2.4, need 2.3 or higher so no change my $version = $pdf->{'pdf'}->require_version('2.3'); is($version, '2.4', q{require_version returns current version}); $pdf->{'pdf'}->require_version('2.4'); is($pdf->{'pdf'}->header_version(), '2.3', q{require_version doesn't increase header version if trailer is sufficient}); # header 2.3, trailer 2.4, need 2.5 or higher so change both to 2.5 $version = $pdf->{'pdf'}->require_version('2.5'); is($pdf->version(), '2.5', q{require_version increases version when needed}); is($version, '2.4', q{require_version returns the previous version number}); #$pdf = PDF::Builder->new('compress' => 'none'); # version (header only) 1.4 #$pdf->version(1.3); # need to capture STDERR warning that version illegal #is($pdf->version(), '1.4'); # should still be 1.4 # #$pdf->version(1.6); #$pdf->version(1.5); # need to capture STDERR warning that version drops #is($pdf->version(), '1.5'); # should have dropped to 1.5 done_testing(); 1; PDF-Builder-3.026/t/font-type1.t0000644000000000000000000000534514534467462014703 0ustar rootroot#!/usr/bin/perl use warnings; use strict; use Test::More tests => 2; my $test_count = 2; use PDF::Builder; my (@pfb_list, @pfm_list); my ($pfb_file, $pfm_file); my $OSname = $^O; # expecting a matching pfb and pfm set. if you have .pfa and/or .afm|.xfm, # something will have to be done about that if ($OSname eq 'MSWin32') { # Windows systems (MikTex installation assumed, as Windows doesn't come # with any Type1 fonts preinstalled). new and older MiKTeX paths. push @pfb_list, 'C:/Program Files/MikTex 2.9/fonts/type1/urw/bookman/ubkd8a.pfb'; push @pfm_list, 'C:/Program Files/MikTex 2.9/fonts/type1/urw/bookman/ubkd8a.pfm'; push @pfb_list, 'C:/Program Files (x86)/MikTex 2.9/fonts/type1/urw/bookman/ubkd8a.pfb'; push @pfm_list, 'C:/Program Files (x86)/MikTex 2.9/fonts/type1/urw/bookman/ubkd8a.pfm'; push @pfb_list, 'C:/Users/Phil/fonts/T1fonts/URWGothic-Book.t1'; push @pfm_list, 'C:/Users/Phil/fonts/T1fonts/URWGothic-Book.afm'; } else { # Unix/Linux systems assumed. is this a standard location everyone has? push @pfb_list, '/usr/share/fonts/type1/gsfonts/a010013l.pfb'; push @pfm_list, '/usr/share/fonts/type1/gsfonts/a010013l.pfm'; push @pfb_list, '/usr/share/X11/fonts/urw-fonts/a010013l.pfb'; push @pfm_list, '/usr/share/X11/fonts/urw-fonts/a010013l.pfm'; push @pfb_list, '/usr/share/fonts/urw-base35/URWGothic-Book.t1'; push @pfm_list, '/usr/share/fonts/urw-base35/URWGothic-Book.afm'; } # This may or may not work on Macs ("darwin" string) and other platforms # ("os2", "dos", "cygwin"). Might need some updates once the appropriate # file paths are known. Suggestions are welcome for Windows and non-Windows # font paths that could be tried. # find a working file set (hopefully matched set of font and metrics!) foreach (@pfb_list) { if (-f $_ && -r $_) { $pfb_file = $_; last; } } foreach (@pfm_list) { if (-f $_ && -r $_) { $pfm_file = $_; last; } } SKIP: { skip "Skipping Type1 tests... URW Gothic L Book font not found", $test_count unless (defined $pfb_file and defined $pfm_file); my $pdf = PDF::Builder->new(); my $font; # handle both afm and pfm metric files if ($pfm_file =~ m/\.pfm$/i) { # $font = $pdf->font($pfb_file, 'pfmfile' => $pfm_file); $font = $pdf->psfont($pfb_file, 'pfmfile' => $pfm_file); } else { # $font = $pdf->font($pfb_file, 'afmfile' => $pfm_file); $font = $pdf->psfont($pfb_file, 'afmfile' => $pfm_file); } # Do something with the font to see if it appears to have opened # properly. ok($font->glyphNum() > 0, q{Able to read a count of glyphs (>0) from a Type1 font}); like($font->{'Name'}->val(), qr/^Ur/, q{Font has the expected name}); } 1; PDF-Builder-3.026/t/cs-webcolor.t0000644000000000000000000000077514534467462015116 0ustar rootroot#!/usr/bin/perl use warnings; use strict; use Test::More tests => 2; use PDF::Builder; my $pdf = PDF::Builder->new('-compress' => 'none'); my $cs = $pdf->colorspace_web(); my $gfx = $pdf->page->gfx(); $gfx->strokecolor($cs, 3); $gfx->move(72, 144); $gfx->hline(288); $gfx->stroke(); my $string = $pdf->to_string(); like($string, qr{obj \[ /Indexed /DeviceRGB 255}, q{ColorSpace is present}); like($string, qr{CS 3 SC 72 144 m 288 144 l S}, q{Indexed color is used for horizontal line}); 1; PDF-Builder-3.026/t/02-xrefstm.t0000644000000000000000000000122614534467462014576 0ustar rootroot#!/usr/bin/perl use warnings; use strict; use Test::More tests => 4; use PDF::Builder; my $pdf = PDF::Builder->new('msgver' => 0); $pdf = PDF::Builder->open('t/resources/sample-xrefstm.pdf'); isa_ok($pdf, 'PDF::Builder', q{PDF::Builder->open() on a PDF with a cross-reference stream returns a PDF::Builder object}); my $object = $pdf->{'pdf'}->read_objnum(9, 0); ok($object, q{Read an object from an object stream}); my ($key) = grep { $_ =~ /^Helv/ } keys %$object; ok($key, q{The compressed object contains an expected key}); $object = $pdf->{'pdf'}->read_objnum(11, 0); ok($object, q{Read a number from an object stream}); 1; PDF-Builder-3.026/t/01-basic.t0000644000000000000000000000176714534467462014200 0ustar rootroot#!/usr/bin/perl use warnings; use strict; use Test::More tests => 7; use PDF::Builder; my $pdf = PDF::Builder->new(); isa_ok($pdf, 'PDF::Builder', q{PDF::Builder->new() returns a PDF::Builder object}); my $page = $pdf->page(); isa_ok($page, 'PDF::Builder::Page', q{$pdf->page() returns a PDF::Builder::Page object}); my $gfx = $page->gfx(); isa_ok($gfx, 'PDF::Builder::Content', q{$pdf->gfx() returns a PDF::Builder::Content object}); my $text = $page->text(); isa_ok($text, 'PDF::Builder::Content::Text', q{$pdf->text() returns a PDF::Builder::Content::Text object}); is($pdf->pages(), 1, q{$pdf->pages() returns 1 on a one-page PDF}); # Insert a second page $page = $pdf->page(); is($pdf->pages(), 2, q{$pdf->pages() returns 2 after a second page is added}); # Open a PDF $pdf = PDF::Builder->open('t/resources/sample.pdf'); isa_ok($pdf, 'PDF::Builder', q{PDF::Builder->open() returns a PDF::Builder object}); 1; PDF-Builder-3.026/t/barcode.t0000644000000000000000000001305414534467462014270 0ustar rootroot#!/usr/bin/perl use warnings; use strict; use Test::More tests => 28; use PDF::Builder; my $pdf = PDF::Builder->new('-compress' => 'none'); # Check to ensure all barcode types can be loaded my $xo_codabar = $pdf->xo_codabar(-code => 0); isa_ok($xo_codabar, q{PDF::Builder::Resource::XObject::Form::BarCode::codabar}, q{xo_codabar loads}); my $xo_code128 = $pdf->xo_code128(-code => 0); isa_ok($xo_code128, q{PDF::Builder::Resource::XObject::Form::BarCode::code128}, q{xo_code128 loads}); my $xo_2of5int = $pdf->xo_2of5int(-code => 0); isa_ok($xo_2of5int, q{PDF::Builder::Resource::XObject::Form::BarCode::int2of5}, q{xo_2of5int loads}); my $xo_3of9 = $pdf->xo_3of9(-code => 0); isa_ok($xo_3of9, q{PDF::Builder::Resource::XObject::Form::BarCode::code3of9}, q{xo_3of9 loads}); my $xo_ean13 = $pdf->xo_ean13(-code => '0123456789012'); isa_ok($xo_ean13, q{PDF::Builder::Resource::XObject::Form::BarCode::ean13}, q{xo_ean13 loads}); # Translate my $page = $pdf->page(); my $barcode = $pdf->xo_3of9( -code => '1', -zone => 10, -umzn => 0, -lmzn => 10, -font => $pdf->corefont('Helvetica'), -fnsz => 10, ); $barcode->{'-docompress'} = 0; delete $barcode->{'Filter'}; my $gfx = $page->gfx(); $gfx->formimage($barcode, 100, 100, 1); my $string = $pdf->to_string(); like($string, qr{/BBox \[ 0 0 39 20 \]}, q{Barcode is the expected size}); like($string, qr{0 0 0 rg}, q{Barcode is black}); like($string, qr{q 1 0 0 1 100 100 cm}, q{Barcode is in the expected location}); # Encoding require PDF::Builder::Resource::XObject::Form::BarCode::codabar; is(join('', map { ref($_) ? $_->[0] : $_ } PDF::Builder::Resource::XObject::Form::BarCode::codabar->encode('A31234567890123B')), 'aabbabaa2211111111112211111211212211111111211211211112111211112112112111122111112112111111111221111122111112112122111111ababaaba', q{Correctly encoded Codabar barcode}); require PDF::Builder::Resource::XObject::Form::BarCode::code128; is(join('', map { ref($_) ? $_->[0] : $_ } PDF::Builder::Resource::XObject::Form::BarCode::code128->encode_128('a', 'TEST')), 'b1a4a2213311132113213113213311241211b3c1a1b', q{Correctly encoded Code 128A barcode}); is(join('', map { ref($_) ? $_->[0] : $_ } PDF::Builder::Resource::XObject::Form::BarCode::code128->encode_128('b', 'Test')), 'b1a2a4213311112214114212124112311321b3c1a1b', q{Correctly encoded Code 128B barcode}); is(join('', map { ref($_) ? $_->[0] : $_ } PDF::Builder::Resource::XObject::Form::BarCode::code128->encode_128('c', '01234567890')), 'b1a2c2222122312131113123141122212141114131123122111422b3c1a1b', q{Correctly encoded Code 128C barcode}); is(join('', map { ref($_) ? $_->[0] : $_ } PDF::Builder::Resource::XObject::Form::BarCode::code128->encode_ean128('00123456780000000001')), 'b1a2c2411131212222112232131123331121241112212222212222212222212222222122131222b3c1a1b', q{Correctly encoded EAN-128 barcode}); require PDF::Builder::Resource::XObject::Form::BarCode::code3of9; is(join('', map { ref($_) ? $_->[0] : $_ } PDF::Builder::Resource::XObject::Form::BarCode::code3of9::encode_3of9('TEST')), 'abaababaa11111212211211122111111211122111111212211abaababaa1', q{Correctly encoded Code 39 barcode}); is(join('', map { ref($_) ? $_->[0] : $_ } PDF::Builder::Resource::XObject::Form::BarCode::code3of9::encode_3of9('TEST', 1, 0)), 'abaababaa111112122112111221111112111221111112122112111221111abaababaa1', q{Correctly encoded Code 39 barcode (with check digit)}); is(join('', map { ref($_) ? $_->[0] : $_ } PDF::Builder::Resource::XObject::Form::BarCode::code3of9::encode_3of9('Test', 0, 1)), 'abaababaa11111212211121112121121112211111211121211112111221112111212111111212211abaababaa1', q{Correctly encoded Code 39 barcode (full ASCII)}); is(join('', map { ref($_) ? $_->[0] : $_ } PDF::Builder::Resource::XObject::Form::BarCode::code3of9::encode_3of9('Test', 1, 1)), 'abaababaa111112122111211121211211122111112111212111121112211121112121111112122112112112111abaababaa1', q{Correctly encoded Code 39 barcode (full ASCII and check digit)}); require PDF::Builder::Resource::XObject::Form::BarCode::ean13; my $ean13_codes = { '0123456789012' => '07a1a2221212214111132123111141a1a1131212133112321122212122a1a', '1123456789011' => '07a1a2221212211411132132141111a1a1131212133112321122212221a1a', '2123456789010' => '07a1a2221212211412311123141111a1a1131212133112321122213211a1a', '3123456789019' => '07a1a2221212211412311132111141a1a1131212133112321122213112a1a', '4123456789018' => '07a1a2221221214111132132141111a1a1131212133112321122211213a1a', '5123456789017' => '07a1a2221221211411132123141111a1a1131212133112321122211312a1a', '6123456789016' => '07a1a2221221211412311123111141a1a1131212133112321122211114a1a', '7123456789015' => '07a1a2221221214112311123141111a1a1131212133112321122211231a1a', '8123456789014' => '07a1a2221221214112311132111141a1a1131212133112321122211132a1a', '9123456789013' => '07a1a2221221211411132132111141a1a1131212133112321122211411a1a', }; foreach my $code (sort keys %$ean13_codes) { is(join('', map { ref($_) ? $_->[0] : $_ } PDF::Builder::Resource::XObject::Form::BarCode::ean13->encode($code)), $ean13_codes->{$code}, q{Correctly encoded EAN 13 barcode with prefix } . substr($code, 0, 1)); } require PDF::Builder::Resource::XObject::Form::BarCode::int2of5; is(join('', map { ref($_) ? $_->[0] : $_ } PDF::Builder::Resource::XObject::Form::BarCode::int2of5->encode('0123456789')), 'aaaa12112121121222111121121122112111212112122112112211baaa', q{Correctly encoded Interleaved 2 of 5 barcode}); 1; PDF-Builder-3.026/t/gif.t0000644000000000000000000000203414534467462013432 0ustar rootroot#!/usr/bin/perl use warnings; use strict; use Test::More tests => 6; use PDF::Builder; # Filename my $pdf = PDF::Builder->new('compress' => 'none'); my $gif = $pdf->image_gif('t/resources/1x1.gif'); isa_ok($gif, 'PDF::Builder::Resource::XObject::Image::GIF', q{$pdf->image_gif(filename)}); is($gif->width(), 1, q{Image from filename has a width}); my $gfx = $pdf->page()->gfx(); $gfx->image($gif, 72, 144, 216, 288); like($pdf->to_string(), qr/q 216 0 0 288 72 144 cm \S+ Do Q/, q{Add GIF to PDF}); # Filehandle $pdf = PDF::Builder->new(); open my $fh, '<', 't/resources/1x1.gif' or die "Can't open file t/resources/1x1.gif"; $gif = $pdf->image($fh); # use convenience function isa_ok($gif, 'PDF::Builder::Resource::XObject::Image::GIF', q{$pdf->image(filehandle)}); is($gif->width(), 1, q{Image from filehandle has a width}); close $fh; # Missing file $pdf = PDF::Builder->new(); eval { $pdf->image_gif('t/resources/this.file.does.not.exist') }; ok($@, q{Fail fast if the requested file doesn't exist}); 1; PDF-Builder-3.026/t/filter-ascii85decode.t0000644000000000000000000000162714534467462016570 0ustar rootroot#!/usr/bin/perl use warnings; use strict; use Test::More tests => 4; use PDF::Builder::Basic::PDF::Filter::ASCII85Decode; my $filter = PDF::Builder::Basic::PDF::Filter::ASCII85Decode->new(); my $in = 'BT /F1 24 Tf 100 700 Td (Hello World)Tj ET'; my $out = q{6<#'\7PQ#@1a#b0+>GQ(+?(u.+B2ko-qIocCi:FtDfTZ).9(%)78s~>}; is($filter->outfilt($in, 1), $out, q{ASCII85Decode test string is encoded correctly}); is($filter->infilt($out, 1), $in, q{ASCII85Decode test string is decoded correctly}); $in = 'BT /F1 24 Tf 100 700 Td (Hello Worlds!)Tj ET'; $out = q{6<#'\7PQ#@1a#b0+>GQ(+?(u.+B2ko-qIocCi:FtDfTZ)F!2u3C*5rE~>}; is($in, $filter->infilt($filter->outfilt($in, 1), 1), q{ASCII85Decode test string encodes and decodes without changing the string (multiple of four bytes)}); is($filter->outfilt($in, 1), $out, q{ASCII85Decode test string is encoded correctly (multiple of four bytes)}); 1; PDF-Builder-3.026/t/font-ttf.t0000644000000000000000000000165014534467462014431 0ustar rootroot#!/usr/bin/perl use warnings; use strict; use Test::More tests => 2; my $test_count = 2; use PDF::Builder; my @possible_locations = ( '/usr/share/fonts/dejavu-sans-fonts/DejaVuSans.ttf', '/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf', '/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf', '/var/lib/defoma/gs.d/dirs/fonts/DejaVuSans.ttf', 'C:/Windows/fonts/DejaVuSans.ttf', ); my ($font_file) = grep { -f && -r } @possible_locations; SKIP: { skip "Skipping TTF tests... DejaVu Sans font not found", $test_count unless $font_file; my $pdf = PDF::Builder->new(); my $font = $pdf->font($font_file); # originally ttfont() # Do something with the font to see if it appears to have opened # properly. ok($font->glyphNum() > 0, q{Able to read a count of glyphs (>0) from a TrueType font}); like($font->{'Name'}->val(), qr/^De/, q{Font has the expected name}); } 1; PDF-Builder-3.026/t/pdf.t0000644000000000000000000001026014534467462013436 0ustar rootroot#!/usr/bin/perl use warnings; use strict; use Test::More tests => 16; use File::Temp qw(tempfile); use PDF::Builder; my $pdf = PDF::Builder->new(); $pdf->info(Producer => 'PDF::Builder Test Suite'); my %info = $pdf->info(); is($info{'Producer'}, 'PDF::Builder Test Suite', 'Check info string'); my $gfx = $pdf->page()->gfx(); $gfx->fillcolor('blue'); my $new = PDF::Builder->from_string($pdf->to_string()); %info = $new->info(); is($info{'Producer'}, 'PDF::Builder Test Suite', 'Check info string after save and reload'); ## ## import_page ## $pdf = $new; $new = PDF::Builder->new(); my $form = $new->importPageIntoForm($pdf, 1); #$form->{'-docompress'} = 0; # not in API2 tests delete $form->{'Filter'}; my $string = $new->to_string(); like($string, qr/0 0 1 rg/, q{Page imported by import_page contains content from original}); # Add a second page with a different page size $new = PDF::Builder->from_string($string, 'compress' => 'none'); my $page = $pdf->page(); my $font = $pdf->corefont('Helvetica'); $page->mediabox(0, 0, 72, 144); my $text = $page->text(); $text->font($font, 12); $text->text('This is a test'); $pdf = PDF::Builder->from_string($pdf->to_string()); $form = $new->importPageIntoForm($pdf, 2); #$form->{'-docompress'} = 0; # not in API2 tests delete $form->{'Filter'}; is(($form->bbox())[2], 72, q{Form bounding box is set from imported page}); $string = $new->to_string(); like($string, qr/\(This is a test\)/, q{Second imported page contains text}); # Page Numbering $pdf = PDF::Builder->new('compress' => 'none'); $pdf->pageLabel(0, { 'style' => 'Roman' }); like($pdf->to_string(), qr{/PageLabels << /Nums \[ 0 << /S /R >> \] >>}, q{Page Numbering: Upper-case Roman Numerals}); $pdf = PDF::Builder->new('compress' => 'none'); $pdf->pageLabel(0, { 'style' => 'roman' }); like($pdf->to_string(), qr{/PageLabels << /Nums \[ 0 << /S /r >> \] >>}, q{Page Numbering: Upper-case Roman Numerals}); $pdf = PDF::Builder->new('compress' => 'none'); $pdf->pageLabel(0, { 'style' => 'Alpha' }); like($pdf->to_string(), qr{/PageLabels << /Nums \[ 0 << /S /A >> \] >>}, q{Page Numbering: Upper-case Alphabet Characters}); $pdf = PDF::Builder->new('compress' => 'none'); $pdf->pageLabel(0, { 'style' => 'alpha' }); like($pdf->to_string(), qr{/PageLabels << /Nums \[ 0 << /S /a >> \] >>}, q{Page Numbering: Lower-case Alphabet Characters}); $pdf = PDF::Builder->new('compress' => 'none'); $pdf->pageLabel(0, { 'style' => 'decimal' }); like($pdf->to_string(), qr{/PageLabels << /Nums \[ 0 << /S /D >> \] >>}, q{Page Numbering: Decimal Characters}); $pdf = PDF::Builder->new('compress' => 'none'); $pdf->pageLabel(0, { 'start' => 11 }); like($pdf->to_string(), qr{/PageLabels << /Nums \[ 0 << /S /D /St 11 >> \] >>}, q{Page Numbering: Decimal Characters (implicit), starting at 11}); $pdf = PDF::Builder->new('compress' => 'none'); $pdf->pageLabel(0, { 'prefix' => 'Test' }); like($pdf->to_string(), qr{/PageLabels << /Nums \[ 0 << /P \(Test\) /S /D >> \] >>}, q{Page Numbering: Decimal Characters (implicit), with prefix}); ## ## to_string ## $pdf = PDF::Builder->new('compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->fillcolor('blue'); $string = $pdf->to_string(); like($string, qr/0 0 1 rg/, q{Stringify of newly-created PDF contains expected content}); my ($fh, $filename) = tempfile(); print $fh $string; close $fh; $pdf = PDF::Builder->open($filename); $string = $pdf->to_string(); like($string, qr/0 0 1 rg/, q{Stringify of newly-opened PDF contains expected content}); ## ## saveas with same filename ## (in response to bug 134993, introduced by 113516, not yet in PDF::Builder) ## $pdf = PDF::Builder->new('compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->fillcolor('blue'); ($fh, $filename) = tempfile(); print $fh $pdf->to_string(); close $fh; $pdf = PDF::Builder->open($filename, 'compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->fillcolor('red'); $pdf->saveas($filename); $pdf = PDF::Builder->open($filename, 'compress' => 'none'); $string = $pdf->to_string(); like($string, qr/0 0 1 rg/, q{saveas($opened_filename) contains original content}); like($string, qr/1 0 0 rg/, q{saveas($opened_filename) contains new content}); 1; PDF-Builder-3.026/t/cmap.t0000644000000000000000000000041714534467462013610 0ustar rootroot#!/usr/bin/perl use warnings; use strict; use Test::More tests => 1; use PDF::Builder; my $pdf = PDF::Builder->new(); my $font = $pdf->cjkfont('simplified'); is(ref($font), 'PDF::Builder::Resource::CIDFont::CJKFont', q{Check that .cmap files are being used}); 1; PDF-Builder-3.026/t/content.t0000644000000000000000000005163114534467462014346 0ustar rootroot#!/usr/bin/perl use warnings; use strict; use Test::More tests => 83; use PDF::Builder; # Translate my $pdf = PDF::Builder->new('compress' => 'none'); my $gfx = $pdf->page()->gfx(); $gfx->translate(72, 144); like($pdf->to_string(), qr/1 0 0 1 72 144 cm/, q{translate(72, 144)}); # Rotate $pdf = PDF::Builder->new('-compress' => 0); $gfx = $pdf->page()->gfx(); $gfx->rotate(65); like($pdf->to_string, qr/0.42262 0.90631 -0.90631 0.42262 0 0 cm/, q{rotate(65)}); # Scale $pdf = PDF::Builder->new('compress' => 0); $gfx = $pdf->page()->gfx(); $gfx->scale(1.1, 2.5); like($pdf->to_string, qr/1.1 0 0 2.5 0 0 cm/, q{scale(1.1, 2.5)}); # Skew $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->graphics(); $gfx->skew(15, 25); like($pdf->to_string, qr/1 0.26795 0.46631 1 0 0 cm/, q{skew(15, 25)}); # Transform $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->transform(-translate => [20, 50], -rotate => 10, -scale => [1.5, 3], -skew => [10, -20]); $gfx->transform(-translate => [20, 50], -rotate => 10, -scale => [1.5, 3], -skew => [10, -20]); like($pdf->to_string, qr/1.3854 0.78142 -1.0586 2.8596 20 50 cm 1.3854 0.78142 -1.0586 2.8596 20 50 cm/, q{transform + transform}); # Relative Transform $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->transform(-translate => [20, 50], -rotate => 10, -scale => [1.5, 3], -skew => [10, -20]); $gfx->transform(-translate => [10, 10], -rotate => 10, -scale => [2, 4], -skew => [5, -10], 'repeat' => 1); like($pdf->to_string, qr/1.3854 0.78142 -1.0586 2.8596 20 50 cm 1.7193 4.0475 -5.7318 10.684 30 60 cm/, q{transform + transform_repeat}); # Matrix $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->matrix(1.3854, 0.78142, -1.0586, 2.8596, 20, 50); like($pdf->to_string, qr/1.3854 0.78142 -1.0586 2.8596 20 50 cm/, q{matrix}); # Save $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->save(); like($pdf->to_string, qr/q/, q{save}); # Restore $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->restore(); like($pdf->to_string, qr/Q/, q{restore}); # Named Fill Color $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->fill_color('blue'); like($pdf->to_string(), qr/0 0 1 rg/, q{fill_color('blue')}); # RGB Fill Color $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->fillcolor('#ff0000'); # red like($pdf->to_string(), qr/1 0 0 rg/, q{fillcolor('#ff0000')}); # CMYK Fill Color $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->fillcolor('%ff000000'); # cyan like($pdf->to_string, qr/1 0 0 0 k/, q{fillcolor('%ff000000')}); # Named Stroke Color $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->stroke_color('blue'); like($pdf->to_string(), qr/0 0 1 RG/, q{stroke_color('blue')}); # RGB Stroke Color $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->strokecolor('#ff0000'); # red like($pdf->to_string(), qr/1 0 0 RG/, q{strokecolor('#ff0000')}); # CMYK Stroke Color $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->strokecolor('%ff000000'); # cyan like($pdf->to_string, qr/1 0 0 0 K/, q{strokecolor('%ff000000')}); # HSV Fill Color $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->fillcolor('!ffffcccc3333'); # dark red color like($pdf->to_string, qr/0.2 0.04 0.0426667 rg/, q{fillcolor('!ffffcccc3333')}); # L*a*b Fill Color $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->fillcolor('&abc'); # ? color like($pdf->to_string, qr|/LabS cs 94.6667 -51.8545 -51.8545 sc|, q{fillcolor('&abc')}); # Grayscale Fill Color $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->fillcolor(0.5); # medium gray like($pdf->to_string, qr/0.5 g/, q{fillcolor(0.5)}); # pattern or shading space Fill Color TBD # Legacy format RGB Fill Color $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->fillcolor(0, 0.5, 0.5); # medium cyan like($pdf->to_string, qr/0 0.5 0.5 rg/, q{fillcolor(0, 0.5, 0.5)}); # Legacy format CMYK Fill Color $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->fillcolor(0.5, 0.5, 0, 0); # medium blue like($pdf->to_string, qr/0.5 0.5 0 0 k/, q{fillcolor(0.5, 0.5, 0, 0)}); # indexed colorspace plus color-index Fill Color TBD # custom colorspace plus parameter Fill Color TBD # HSV Stroke Color (note: 11 digits; 9 will be used) $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->strokecolor('!ffffcccc333'); # dark red color like($pdf->to_string, qr/0.0124971 0.00249943 0.00266606 RG/, q{strokecolor('!ffffcccc333')}); # L*a*b Stroke Color $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->strokecolor('&778899'); # ? color like($pdf->to_string, qr|/LabS CS 81.3333 -52.0374 11.6854 SC|, q{strokecolor('&778899')}); # Grayscale Stroke Color $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->strokecolor(1.7); # white, after being clamped to 1.0 max like($pdf->to_string, qr/1 G/, q{strokecolor(1.7)}); # pattern or shading space Stroke Color TBD # Legacy format RGB Stroke Color $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->strokecolor(1, 5, 0); # yellow after Green clamped to max 1.0 like($pdf->to_string, qr/1 1 0 RG/, q{strokecolor(1, 5, 0)}); # Legacy format CMYK Stroke Color $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->strokecolor(0.5, 0.5, -1, 0); # medium blue after Yellow clamped to 0 like($pdf->to_string, qr/0.5 0.5 0 0 K/, q{strokecolor(0.5, 0.5, -1, 0)}); # indexed colorspace plus color-index Stroke Color TBD # custom colorspace plus parameter Stroke Color TBD # Line Width $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->linewidth(8.125); like($pdf->to_string, qr/8.125 w/, q{linewidth(8.125)}); $pdf = PDF::Builder->new('compress' => 'none'); $gfx = $pdf->page()->graphics(); $gfx->line_width(9.125); like($pdf->to_string, qr/9.125 w/, q{line_width(9.125)}); # Line Cap Style $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->linecap(1); like($pdf->to_string, qr/1 J/, q{linecap(1)}); $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->line_cap(2); like($pdf->to_string, qr/2 J/, q{line_cap(2)}); # Line Join Style $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->linejoin(1); like($pdf->to_string, qr/1 j/, q{linejoin(1)}); $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->line_join(2); like($pdf->to_string, qr/2 j/, q{line_join(2)}); # Miter Limit $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->miterlimit(3); like($pdf->to_string, qr/3 M/, q{miterlimit(3)}); $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->miter_limit(3.5); like($pdf->to_string, qr/3.5 M/, q{miter_limit(3.5)}); # Line Dash (no args) $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->linedash(); like($pdf->to_string, qr/\[ \] 0 d/, q{linedash()}); # Line Dash (1 arg) $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->linedash(3); like($pdf->to_string, qr/\[ 3 \] 0 d/, q{linedash(3)}); # Line Dash (2 args) $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->line_dash_pattern(2, 1); like($pdf->to_string, qr/\[ 2 1 \] 0 d/, q{line_dash_pattern(2, 1)}); # Line Dash (hash) $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->linedash(-pattern => [15, 5, 3, 2], -shift => 8); like($pdf->to_string, qr/\[ 15 5 3 2 \] 8 d/, q{linedash(-pattern => [15, 5, 3, 2], -shift => 8)}); # Flatness Tolerance $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->flatness(5); like($pdf->to_string, qr/5 i/, q{flatness(5)}); $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->flatness_tolerance(7); like($pdf->to_string, qr/7 i/, q{flatness_tolerance(7)}); ## ## PATH CONSTRUCTION ## # Horizontal Line $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->move(72, 144); $gfx->hline(288); $gfx->stroke(); like($pdf->to_string, qr/72 144 m 288 144 l S/, q{hline}); # Vertical Line $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->move(72, 144); $gfx->vline(288); $gfx->stroke(); like($pdf->to_string, qr/72 144 m 72 288 l S/, q{vline}); # Poly-Line (4 args, 1 line segment) $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->poly(72, 144, 216, 288); $gfx->stroke(); like($pdf->to_string, qr/72 144 m 216 288 l S/, q{poly, four arguments}); $pdf = PDF::Builder->new('compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->move(72, 144); $gfx->polyline(216, 288); $gfx->stroke(); like($pdf->to_string, qr/72 144 m 216 288 l S/, q{polyline, two arguments}); # Poly-Line (6 args, 2 line segments) $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->poly(72, 144, 216, 288, 100, 200); $gfx->stroke(); like($pdf->to_string, qr/72 144 m 216 288 l 100 200 l S/, q{poly, six arguments}); $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->move(0, 0); $gfx->polyline(72, 144, 216, 288, 100, 200); $gfx->stroke(); like($pdf->to_string, qr/0 0 m 72 144 l 216 288 l 100 200 l S/, q{polyline, six arguments}); # Rectangle $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->rect(100, 200, 25, 50); $gfx->stroke(); $gfx->rect(100, 200, 25, -50); $gfx->stroke(); $gfx->rect(200, 300, 50, 75, 400, 800, 10, 15); $gfx->stroke(); like($pdf->to_string, qr/100 200 25 50 re S 100 200 25 -50 re S 200 300 50 75 re 400 800 10 15 re S/, q{rect}); $pdf = PDF::Builder->new('compress' => 0); $gfx = $pdf->page()->graphics(); $gfx->rectangle(100, 200, 125, 250); $gfx->stroke(); $gfx->rectangle(125, 200, 100, 250); $gfx->stroke(); like($pdf->to_string, qr/100 200 25 50 re S 100 200 25 50 re S/, q{rectangle}); # XY Rectangle $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->rectxy(100, 200, 125, 250); $gfx->stroke(); $gfx->rectxy(100, 200, 125, 150); $gfx->stroke(); like($pdf->to_string, qr/100 200 25 50 re S 100 200 25 -50 re S/, q{rectxy}); # Curve $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->move(72, 144); $gfx->curve(100, 200, 125, 250, 144, 288); $gfx->stroke(); like($pdf->to_string, qr/72 144 m 100 200 125 250 144 288 c S/, q{curve}); # qbSpline $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->move(30, 60); $gfx->qbspline(90, 120, 150, 180); $gfx->stroke(); like($pdf->to_string, qr/30 60 m 70 100 110 140 150 180 c S/, q{qbspline}); # bSpline $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); my @points = (20,40, 70,50, 115,40, 145,35, 145,45, 115,40, 70,5); $gfx->move(30, 60); $gfx->bspline(\@points); $gfx->stroke(); like($pdf->to_string, qr/30 60 m 30 60 m 22.547 60.065 15.476 45.923 20 40 c 30.316 26.494 53.006 50.181 70 50 c 85.364 49.837 99.918 42.93 115 40 c 124.95 38.067 137.27 28.448 145 35 c 147.54 37.154 147.54 42.846 145 45 c 137.27 51.552 124.28 44.069 115 40 c 97.597 32.372 81.677 19.99 70 5 c S/, q{bspline}); # Arc (with move) $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->move(72, 144); $gfx->arc(216, 288, 144, 72, 90, 180, 1); $gfx->stroke(); like($pdf->to_string, qr/72 144 m 216 360 m 197.09 360 178.36 358.14 160.89 354.52 c 143.42 350.9 127.55 345.6 114.18 338.91 c 100.8 332.23 90.198 324.29 82.961 315.55 c 75.725 306.82 72 297.46 72 288 c S/, q{arc, with move}); # Arc (without move) $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->move(72, 144); $gfx->arc(216, 288, 144, 72, 90, 180, 0); $gfx->stroke(); like($pdf->to_string, qr/72 144 m 197.09 360 178.36 358.14 160.89 354.52 c 143.42 350.9 127.55 345.6 114.18 338.91 c 100.8 332.23 90.198 324.29 82.961 315.55 c 75.725 306.82 72 297.46 72 288 c S/, q{arc, without move}); # Pie $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->pie(216, 288, 100, 80, 30, 100); $gfx->stroke(); like($pdf->to_string, qr/216 288 m 302.6 328 l 297.5 335.07 291.08 341.47 283.56 346.98 c 276.04 352.5 267.51 357.06 258.26 360.5 c 249.02 363.95 239.17 366.25 229.05 367.32 c 218.94 368.38 208.68 368.2 198.64 366.78 c h S/, q{pie(216,288, 100,80, 30,100)}); # Bogen (with move) $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->bogen(72, 72, 216, 72, 72, 1); $gfx->stroke(); like($pdf->to_string, qr/72 72 m 72 81.455 73.862 90.818 77.481 99.553 c 81.099 108.29 86.402 116.23 93.088 122.91 c 99.774 129.6 107.71 134.9 116.45 138.52 c 125.18 142.14 134.54 144 144 144 c 153.46 144 162.82 142.14 171.55 138.52 c 180.29 134.9 188.23 129.6 194.91 122.91 c 201.6 116.23 206.9 108.29 210.52 99.553 c 214.14 90.818 216 81.455 216 72 c S/, q{bogen, with move}); # Bogen (without move) $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->move(72, 72); $gfx->bogen(72, 72, 216, 72, 72, 0); $gfx->stroke(); like($pdf->to_string, qr/72 72 m 72 81.455 73.862 90.818 77.481 99.553 c 81.099 108.29 86.402 116.23 93.088 122.91 c 99.774 129.6 107.71 134.9 116.45 138.52 c 125.18 142.14 134.54 144 144 144 c 153.46 144 162.82 142.14 171.55 138.52 c 180.29 134.9 188.23 129.6 194.91 122.91 c 201.6 116.23 206.9 108.29 210.52 99.553 c 214.14 90.818 216 81.455 216 72 c S/, q{bogen, without move}); # Bogen (without move, outer) $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->move(72, 72); $gfx->bogen(72, 72, 144, 144, 72, 0, 1); $gfx->stroke(); like($pdf->to_string, qr/72 72 m 64.919 72 57.876 73.045 51.1 75.1 c 44.323 77.156 37.887 80.2 31.999 84.134 c 26.111 88.068 20.836 92.85 16.343 98.324 c 11.851 103.8 8.1906 109.9 5.4807 116.45 c 2.7707 122.99 1.0408 129.9 0.3467 136.94 c -0.3474 143.99 0.00195 151.1 1.3835 158.05 c 2.765 164.99 5.1635 171.7 8.5017 177.94 c 11.84 184.19 16.081 189.9 21.088 194.91 c 26.096 199.92 31.814 204.16 38.059 207.5 c 44.305 210.84 51.008 213.24 57.953 214.62 c 64.899 216 72.01 216.35 79.057 215.65 c 86.105 214.96 93.011 213.23 99.553 210.52 c 106.1 207.81 112.2 204.15 117.68 199.66 c 123.15 195.16 127.93 189.89 131.87 184 c 135.8 178.11 138.84 171.68 140.9 164.9 c 142.96 158.12 144 151.08 144 144 c S/, q{bogen, without move, with outer}); # Bogen (without move, inner, reverse) $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->move(72, 72); $gfx->bogen(72, 72, 144, 144, 72, 0, 0, 1); $gfx->stroke(); like($pdf->to_string, qr/72 72 m 81.455 72 90.818 73.862 99.553 77.481 c 108.29 81.099 116.23 86.402 122.91 93.088 c 129.6 99.774 134.9 107.71 138.52 116.45 c 142.14 125.18 144 134.54 144 144 c S/, q{bogen, without move, without outer, with reverse}); # Close Path $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->move(72, 144); $gfx->line(216, 288); $gfx->line(360, 432); $gfx->close(); $gfx->stroke(); like($pdf->to_string, qr/72 144 m 216 288 l 360 432 l h S/, q{close}); # End Path $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->move(72, 144); $gfx->line(216, 288); $gfx->endpath(); like($pdf->to_string, qr/72 144 m 216 288 l n/, q{endpath}); # Ellipse $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->ellipse(144, 216, 108, 36); $gfx->stroke(); like($pdf->to_string, qr/252 216 m 252 220.73 249.21 225.41 243.78 229.78 c 238.35 234.14 230.4 238.11 220.37 241.46 c 210.34 244.8 198.43 247.45 185.33 249.26 c 172.23 251.07 158.18 252 144 252 c 129.82 252 115.77 251.07 102.67 249.26 c 89.567 247.45 77.661 244.8 67.632 241.46 c 57.604 238.11 49.649 234.14 44.221 229.78 c 38.794 225.41 36 220.73 36 216 c 36 211.27 38.794 206.59 44.221 202.22 c 49.649 197.86 57.604 193.89 67.632 190.54 c 77.661 187.2 89.567 184.55 102.67 182.74 c 115.77 180.93 129.82 180 144 180 c 158.18 180 172.23 180.93 185.33 182.74 c 198.43 184.55 210.34 187.2 220.37 190.54 c 230.4 193.89 238.35 197.86 243.78 202.22 c 249.21 206.59 252 211.27 252 216 c h S/, q{ellipse}); # Circle $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->circle(144, 216, 72); $gfx->stroke(); like($pdf->to_string, qr/216 216 m 216 225.46 214.14 234.82 210.52 243.55 c 206.9 252.29 201.6 260.23 194.91 266.91 c 188.23 273.6 180.29 278.9 171.55 282.52 c 162.82 286.14 153.46 288 144 288 c 134.54 288 125.18 286.14 116.45 282.52 c 107.71 278.9 99.774 273.6 93.088 266.91 c 86.402 260.23 81.099 252.29 77.481 243.55 c 73.862 234.82 72 225.46 72 216 c 72 206.54 73.862 197.18 77.481 188.45 c 81.099 179.71 86.402 171.77 93.088 165.09 c 99.774 158.4 107.71 153.1 116.45 149.48 c 125.18 145.86 134.54 144 144 144 c 153.46 144 162.82 145.86 171.55 149.48 c 180.29 153.1 188.23 158.4 194.91 165.09 c 201.6 171.77 206.9 179.71 210.52 188.45 c 214.14 197.18 216 206.54 216 216 c h S/, q{circle}); # Horizontal Scale $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->hscale(105); like($pdf->to_string, qr/105 Tz/, q{hscale(105)}); # Fill Path $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->fill(); $gfx->close(); $gfx->stroke(); like($pdf->to_string, qr/f h S/, q{fill()}); # Fill Path (even-odd rule) $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->fill(1); $gfx->close(); $gfx->stroke(); like($pdf->to_string, qr/f\* h S/, q{fill(1)}); # Fill and Stroke $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->fillstroke(); $gfx->close(); $gfx->stroke(); like($pdf->to_string, qr/B h S/, q{fillstroke()}); # Fill and Stroke (even-odd rule) $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->fillstroke(1); $gfx->close(); $gfx->stroke(); like($pdf->to_string, qr/B\* h S/, q{fillstroke(1)}); # Clipping Path $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->clip(); $gfx->close(); $gfx->stroke(); like($pdf->to_string, qr/W h S/, q{clip()}); # Clipping Path (even-odd rule) $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->clip(1); $gfx->close(); $gfx->stroke(); like($pdf->to_string, qr/W\* h S/, q{clip(1)}); # Character Spacing $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->charspace(2); like($pdf->to_string, qr/2 Tc/, q{charspace(2)}); $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->char_space(3); like($pdf->to_string, qr/3 Tc/, q{char_space(3)}); $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->character_spacing(4); like($pdf->to_string, qr/4 Tc/, q{character_spacing(4)}); # Word Spacing $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->wordspace(2); like($pdf->to_string, qr/2 Tw/, q{wordspace(2)}); $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->word_space(3); like($pdf->to_string, qr/3 Tw/, q{word_space(3)}); $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->word_spacing(4); like($pdf->to_string, qr/4 Tw/, q{word_spacing(4)}); # Text Leading $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->leading(14); like($pdf->to_string, qr/14 TL/, q{leading(14)}); # Text Rendering Mode $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->render(4); like($pdf->to_string, qr/4 Tr/, q{render(4)}); # Text Rise $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->rise(4); like($pdf->to_string, qr/4 Ts/, q{rise(4)}); # Distance $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->distance(3, 4); like($pdf->to_string, qr/3 4 Td/, q{distance(3, 4)}); # cr $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->cr(); $gfx->cr(12.5); $gfx->cr(0); $gfx->cr(-9); like($pdf->to_string, qr/T\* 0 12.5 Td 0 0 Td 0 -9 Td/, q{cr() cr(12.5) cr(0) cr(-9)}); # nl $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->nl(); like($pdf->to_string, qr/T\*/, q{nl}); # nl(0) $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->nl(0); like($pdf->to_string, qr/T\*/, q{nl(0)}); # nl(width) $pdf = PDF::Builder->new('-compress' => 'none'); $gfx = $pdf->page()->gfx(); $gfx->nl(300); like($pdf->to_string, qr/T\* \[-3000\] TJ/, q{nl(300)}); 1; PDF-Builder-3.026/t/rt67767.t0000644000000000000000000000107614534467462013740 0ustar rootroot#!/usr/bin/perl use strict; use warnings; use Test::More tests => 1; use PDF::Builder; # Create a PDF with an empty page my $empty_page_pdf = PDF::Builder->new(); my $page = $empty_page_pdf->page(); $page->mediabox('Letter'); # Save and reopen the PDF $empty_page_pdf = PDF::Builder->from_string($empty_page_pdf->to_string()); my $container_pdf = PDF::Builder->new(); # This dies through API2 version 2.025. eval { $container_pdf->importPageIntoForm($empty_page_pdf, 1); }; ok(!$@, q{Calling importPageIntoForm using an empty page doesn't result in a crash}); 1; PDF-Builder-3.026/t/font-corefont.t0000644000000000000000000000140214534467462015446 0ustar rootroot#!/usr/bin/perl use strict; use warnings; use Test::More; use Test::Exception; use PDF::Builder; my $pdf = PDF::Builder->new(); foreach my $font (qw(bankgothic courier courierbold courierboldoblique courieroblique georgia georgiabold georgiabolditalic georgiaitalic helvetica helveticabold helveticaboldoblique helveticaoblique symbol timesbold timesbolditalic timesitalic timesroman trebuchet trebuchetbold trebuchetbolditalic trebuchetitalic verdana verdanabold verdanabolditalic verdanaitalic webdings wingdings zapfdingbats)) { lives_ok(sub { $pdf->corefont($font) }, "Load font $font"); } done_testing(); 1; PDF-Builder-3.026/t/font-synfont.t0000644000000000000000000000171414534467462015335 0ustar rootroot#!/usr/bin/perl use warnings; use strict; use Test::More tests => 2; my $test_count = 2; use PDF::Builder; my @possible_locations = ( '/usr/share/fonts/dejavu-sans-fonts/DejaVuSans.ttf', '/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf', '/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf', '/var/lib/defoma/gs.d/dirs/fonts/DejaVuSans.ttf', 'C:/Windows/fonts/DejaVuSans.ttf', ); my ($font_file) = grep { -f && -r } @possible_locations; SKIP: { skip "Skipping synthetic font tests... DejaVu Sans font not found", $test_count unless $font_file; my $pdf = PDF::Builder->new(); my $ttf = $pdf->ttfont($font_file); my $font = $pdf->synfont($ttf); # Do something with the font to see if it appears to have opened # properly. ok($font->glyphNum() > 0, q{Able to read a count of glyphs (>0) from a TrueType font}); like($font->{'Name'}->val(), qr/^SynDe/, q{Font has the expected name}); } 1; PDF-Builder-3.026/t/filter-asciihexdecode.t0000644000000000000000000000330114534467462017107 0ustar rootroot#!/usr/bin/perl use warnings; use strict; use Test::More tests => 7; use PDF::Builder::Basic::PDF::Filter::ASCIIHexDecode; my $in = 'This is a test string.'; my $out = '546869732069732061207465737420737472696e672e'; is(PDF::Builder::Basic::PDF::Filter::ASCIIHexDecode->outfilt($in), $out, q{ASCIIHexDecode test string is encoded correctly}); is(PDF::Builder::Basic::PDF::Filter::ASCIIHexDecode->infilt($out), $in, q{ASCIIHexDecode test string is decoded correctly}); # Add the end-of-document marker $out .= '>'; is(PDF::Builder::Basic::PDF::Filter::ASCIIHexDecode->outfilt($in, 1), $out, q{ASCIIHexDecode test string with EOD marker is encoded correctly}); is(PDF::Builder::Basic::PDF::Filter::ASCIIHexDecode->infilt($out), $in, q{ASCIIHexDecode test string with EOD marker is decoded correctly}); # Ensure the filter is case-insensitive $out = uc($out); is(PDF::Builder::Basic::PDF::Filter::ASCIIHexDecode->infilt($out), $in, q{ASCIIHexDecode is case-insensitive}); # Check for death if invalid characters are included { local $@; eval { PDF::Builder::Basic::PDF::Filter::ASCIIHexDecode->infilt('This is not valid input') }; ok($@, q{ASCIIHexDecode dies if invalid characters are passed to infilt}); } # PDF 1.7, section 7.4.2: # "If the filter encounters the EOD marker after reading an odd number # of hexadecimal digits, it shall behave as if a 0 (zero) followed the # last digit" my $odd_out = 'FF00F>'; my $expected_bytes = '255 0 240'; my $actual_bytes = join(' ', map { ord } split //, PDF::Builder::Basic::PDF::Filter::ASCIIHexDecode->infilt($odd_out)); is($actual_bytes, $expected_bytes, q{ASCIIHexDecode handles odd numbers of characters correctly}); 1; PDF-Builder-3.026/t/outline.t0000644000000000000000000000774214534467462014357 0ustar rootroot#!/usr/bin/perl use warnings; use strict; use Test::More tests => 34; use PDF::Builder; my $pdf = PDF::Builder->new('-compress' => 'none'); my $page1 = $pdf->page(); my $page2 = $pdf->page(); my $outlines = $pdf->outlines(); my $outline = $outlines->outline(); $outline->title('Test Outline'); $outline->dest($page2); like($pdf->to_string, qr{/Dest \[ 6 0 R /XYZ null null null \] /Parent 7 0 R /Title \(Test Outline\)}, q{Basic outline test}); $pdf = PDF::Builder->new(compress => 0); $page1 = $pdf->page(); $page2 = $pdf->page(); $outlines = $pdf->outlines(); $outline = $outlines->outline(); $outline->title('Test Outline'); $outline->dest($page2); is($outlines->count(), 1, q{Outline tree has one entry}); $outline->delete(); is($outlines->count(), 0, q{Outline tree has no entries after sole entry is deleted}); ok(!$outlines->has_children(), q{has_children returns false when the sole item is deleted}); my $aa = $outlines->outline(); my $bb = $outlines->outline(); my $cc = $outlines->outline(); $aa->title('Test Outline'); is($outlines->count(), 3, q{Outline tree has three entries}); is($outlines->first(), $aa, q{$outlines->first() returns the first item}); is($outlines->first->next(), $bb, q{$outlines->first->next() returns the second item}); is($outlines->last(), $cc, q{$outlines->last() returns the final item}); is($outlines->last->prev(), $bb, q{$outlines->last->prev() returns the second item}); my $dd = $aa->outline(); is($outlines->count(), 4, q{Outline count includes grandchild}); my $ee = $dd->outline(); is($outlines->count(), 5, q{Outline count includes great-grandchild}); $dd->is_open(0); is($outlines->count(), 4, q{Outline count doesn't include children of closed children}); is($dd->count(), 1, q{$outline->count() is still positive when closed}); $dd->count(); is($dd->{'Count'}->val(), -1, q{... but the Count key is negative when closed}); $pdf = PDF::Builder->from_string($pdf->to_string()); $outlines = $pdf->outlines(); is($outlines->count(), 4, q{Opened PDF returns expected item count}); ok($outlines->first->is_open(), q{Opened PDF returns expected is_open result for open item}); ok(!$outlines->first->first->is_open(), q{Opened PDF returns expected is_open result for closed item}); is($outlines->first->title(), 'Test Outline', q{$outline->title() returns expected value from opened PDF}); $pdf = PDF::Builder->new(compress => 0); $page1 = $pdf->page(); $page2 = $pdf->page(); $outlines = $pdf->outlines(); $aa = $outlines->outline(); $bb = $outlines->outline(); $cc = $outlines->outline(); $dd = $aa->insert_after(); is($outlines->count(), 4, q{3x insert + insert_after = 4 items}); $ee = $cc->insert_before(); is($outlines->count(), 5, q{3x insert + insert_after + insert_before = 5 items}); is($aa->next(), $dd, q{$insert->insert_after() sets $insert->next()}); is($dd->prev(), $aa, q{$insert->insert_after() sets $sibling->prev()}); is($bb->prev(), $dd, q{$insert->insert_after() sets $insert->next->prev()}); is($dd->next(), $bb, q{$insert->insert_after() sets $sibling->next()}); is($cc->prev(), $ee, q{$insert->insert_before() sets $insert->prev()}); is($ee->next(), $cc, q{$insert->insert_before() sets $sibling->next()}); is($bb->next(), $ee, q{$insert->insert_before() sets $insert->prev->next()}); is($ee->prev(), $bb, q{$insert->insert_before() sets $sibling->prev()}); my $ff = $aa->insert_before(); is($aa->prev(), $ff, q{$item->insert_before() on first item sets $item->prev()}); is($ff->next(), $aa, q{$item->insert_before() on first item sets $sibling->next()}); ok(!$ff->prev(), q{$item->insert_before() on first item doesn't set $sibling->prev()}); my $gg = $cc->insert_after(); is($cc->next(), $gg, q{$item->insert_after() on last item sets $item->next()}); is($gg->prev(), $cc, q{$item->insert_after() on last item sets $sibling->prev()}); ok(!$gg->next(), q{$item->insert_after() on last item doesn't set $sibling->next()}); done_testing(); 1; PDF-Builder-3.026/t/jpg.t0000644000000000000000000000163614534467462013454 0ustar rootroot#!/usr/bin/perl use warnings; use strict; use Test::More tests => 5; use PDF::Builder; my $pdf = PDF::Builder->new('compress' => 'none'); my $jpg = $pdf->image_jpeg('t/resources/1x1.jpg'); isa_ok($jpg, 'PDF::Builder::Resource::XObject::Image::JPEG', q{$pdf->image_jpeg()}); my $gfx = $pdf->page()->gfx(); $gfx->image($jpg, 72, 144, 216, 288); like($pdf->to_string(), qr/q 216 0 0 288 72 144 cm \S+ Do Q/, q{Add JPG to PDF}); # Filehandle $pdf = PDF::Builder->new(); open my $fh, '<', 't/resources/1x1.jpg'; $jpg = $pdf->image($fh); # use convenience function isa_ok($jpg, 'PDF::Builder::Resource::XObject::Image::JPEG', q{$pdf->image(filehandle)}); is($jpg->width(), 1, q{Image from filehandle has a width}); close $fh; # Missing file $pdf = PDF::Builder->new(); eval { $pdf->image_jpeg('t/resources/this.file.does.not.exist') }; ok($@, q{Fail fast if the requested file doesn't exist}); 1; PDF-Builder-3.026/t/png.t0000644000000000000000000000520714534467462013456 0ustar rootroot#!/usr/bin/perl use warnings; use strict; use Test::More tests => 9; use PDF::Builder; # tests 1 and 7 will mention PNG_IPL if Image::PNG::Libpng is installed # and usable, otherwise they will display just PNG. you can use this # information if you are not sure about the status of Image::PNG::Libpng. # (1,2,3) Filename my $pdf = PDF::Builder->new('compress' => 'none'); # silent shuts off one-time warning for rest of run my $png = $pdf->image_png('t/resources/1x1.png', 'silent' => 1); if ($png->usesLib() == 1) { isa_ok($png, 'PDF::Builder::Resource::XObject::Image::PNG_IPL', q{$pdf->image_png(filename)}); } else { isa_ok($png, 'PDF::Builder::Resource::XObject::Image::PNG', q{$pdf->image_png(filename)}); } is($png->width(), 1, q{Image from filename has a width}); my $gfx = $pdf->page()->gfx(); $gfx->image($png, 72, 144, 216, 288); like($pdf->to_string(), qr/q 216 0 0 288 72 144 cm \S+ Do Q/, q{Add PNG to PDF}); # (4) RGBA PNG file $pdf = PDF::Builder->new(); $png = $pdf->image_png('t/resources/test-rgba.png'); if ($png->usesLib() == 1) { isa_ok($png, 'PDF::Builder::Resource::XObject::Image::PNG_IPL', q{$pdf->image_png(filename)}); } else { isa_ok($png, 'PDF::Builder::Resource::XObject::Image::PNG', q{$pdf->image_png(filename)}); } my $page = $pdf->page(); $page->mediabox(840,600); $gfx=$page->gfx(); $gfx->image($png,134,106,510,281); my $rgba1_pdf_string = $pdf->to_string(); # (5,6) RGBA PNG file Pure Perl $pdf = PDF::Builder->new(); my $png2 = $pdf->image_png('t/resources/test-rgba.png', 'nouseIPL'=>1); isa_ok($png2, 'PDF::Builder::Resource::XObject::Image::PNG', q{$pdf->image_png(filename), pure Perl}); my $page2 = $pdf->page(); $page2->mediabox(840,600); my $gfx2 = $page2->gfx(); $gfx2->image($png2,134,106,510,281); my $rgba2_pdf_string = $pdf->to_string(); is(substr($rgba1_pdf_string, 0, 512), substr($rgba2_pdf_string, 0, 512), q{XS and pure perl PDFs are the same}); # (7,8) Filehandle $pdf = PDF::Builder->new(); open my $fh, '<', 't/resources/1x1.png' or die "Can't open file t/resources/1x1.png"; $png = $pdf->image($fh); # use convenience function on this one if ($png->usesLib() == 1) { isa_ok($png, 'PDF::Builder::Resource::XObject::Image::PNG_IPL', q{$pdf->image(filehandle)}); } else { isa_ok($png, 'PDF::Builder::Resource::XObject::Image::PNG', q{$pdf->image(filehandle)}); } is($png->width(), 1, q{Image from filehandle has a width}); close $fh; # (9) Missing file $pdf = PDF::Builder->new(); eval { $pdf->image_png('t/resources/this.file.does.not.exist') }; ok($@, q{Fail fast if the requested file doesn't exist}); 1; PDF-Builder-3.026/t/info.t0000644000000000000000000000151614534467462013624 0ustar rootroot#!/usr/bin/perl use strict; use warnings; use Test::More; use PDF::Builder; my $pdf = PDF::Builder->new(); # 1 like($pdf->producer(), qr/PDF::Builder/, q{Producer is set on PDF creation}); $pdf->producer('Test'); # 2 is($pdf->producer(), 'Test', q{Producer can be changed}); # 3 $pdf->producer(undef); ok(!$pdf->producer(), q{Producer can be cleared}); # 4 $pdf->created('D:20000101000000Z'); like($pdf->to_string(), qr{/CreationDate \(D:20000101000000Z\)}, q{CreationDate is correctly encoded}); # 5 $pdf = PDF::Builder->new(); # not sure why have to get a fresh PDF object... # did some test upstream corrupt it? $pdf->modified("D:20230402144932-04'00"); like($pdf->to_string(), qr{/ModDate \(D:20230402144932-04'00\)}, q{ModDate is correctly encoded}); done_testing(); PDF-Builder-3.026/t/string.t0000644000000000000000000001372514534467462014204 0ustar rootroot#!/usr/bin/perl use strict; use warnings; use utf8; use Test::More tests => 42; use PDF::Builder::Basic::PDF::String; my $string; $string = PDF::Builder::Basic::PDF::String->from_pdf('(Test)'); is($string->val(), 'Test', q{Basic literal string test}); is($string->as_pdf(), '(Test)', q{Basic literal string output}); $string = PDF::Builder::Basic::PDF::String->from_pdf('<54657374>'); is(length($string->val()), 4, q{Basic hexadecimal string length test}); is($string->val(), 'Test', q{Basic hexadecimal string test}); is($string->as_pdf(), '<54657374>', q{Basic hexadecimal string output}); # PDF Spec 1.7 Section 7.3.4.2 Examples $string = PDF::Builder::Basic::PDF::String->from_pdf("(Strings may contain newlines\nand such)"); is($string->val(), "Strings may contain newlines\nand such", q{PDF 1.7 section 7.3.4.2 Example 1 (1/3)}); my $input = q|Strings may contain balanced parentheses ( ) and special characters (*!&}^% and so on).|; $string = PDF::Builder::Basic::PDF::String->from_pdf('(' . $input . ')'); is($string->val(), $input, q{PDF 1.7 section 7.3.4.2 Example 1 (2/3)}); $string = PDF::Builder::Basic::PDF::String->from_pdf('()'); is($string->val(), '', q{PDF 1.7 section 7.3.4.2 Example 1 (3/3)}); $input = q|These \ two strings \ are the same.|; $string = PDF::Builder::Basic::PDF::String->from_pdf($input); is($string->val(), 'These two strings are the same.', q{PDF 1.7 section 7.3.4.2 Example 2 (end-of-line backslash)}); $string = PDF::Builder::Basic::PDF::String->from_pdf("(Test line\015)"); is($string->val(), "Test line\012", q{PDF 1.7 section 7.3.4.2 Example 3 (end-of-line character conversion) 1/3}); $string = PDF::Builder::Basic::PDF::String->from_pdf("(Test line\015\012)"); is($string->val(), "Test line\012", q{PDF 1.7 section 7.3.4.2 Example 3 (end-of-line character conversion) 2/3}); $string = PDF::Builder::Basic::PDF::String->from_pdf("(Test line\012)"); is($string->val(), "Test line\012", q{PDF 1.7 section 7.3.4.2 Example 3 (end-of-line character conversion) 3/3}); # PDF Spec 1.7 Section 7.3.4.3 Hexadecimal Strings $string = PDF::Builder::Basic::PDF::String->from_pdf('<5 550>'); is($string->val(), 'UP', q{PDF 1.7 section 7.3.4.3 Example 1 (whitespace is ignored)}); $string = PDF::Builder::Basic::PDF::String->from_pdf('<555>'); is($string->val(), 'UP', q{PDF 1.7 section 7.3.4.3 Example 2 (odd number of hex digits)}); # Escape Characters $string = PDF::Builder::Basic::PDF::String->from_pdf('(\n)'); is($string->val(), "\x0A", q{Escape Character: \n}); is($string->as_pdf(), '(\n)', q{Escape Character: \n (output)}); $string = PDF::Builder::Basic::PDF::String->from_pdf('(\r)'); is($string->val(), "\x0D", q{Escape Character: \r}); is($string->as_pdf(), '(\r)', q{Escape Character: \r (output)}); $string = PDF::Builder::Basic::PDF::String->from_pdf('(\t)'); is($string->val(), "\x09", q{Escape Character: \t}); is($string->as_pdf(), '(\t)', q{Escape Character: \t (output)}); $string = PDF::Builder::Basic::PDF::String->from_pdf('(\b)'); is($string->val(), "\x08", q{Escape Character: \b}); is($string->as_pdf(), '(\b)', q{Escape Character: \b (output)}); $string = PDF::Builder::Basic::PDF::String->from_pdf('(\f)'); is($string->val(), "\x0C", q{Escape Character: \f}); is($string->as_pdf(), '(\f)', q{Escape Character: \f (output)}); $string = PDF::Builder::Basic::PDF::String->from_pdf('(\()'); is($string->val(), '(', q{Escape Character: \(}); is($string->as_pdf(), '(\()', q{Escape Character: \( (output)}); $string = PDF::Builder::Basic::PDF::String->from_pdf('(\))'); is($string->val(), ')', q{Escape Character: \)}); is($string->as_pdf(), '(\))', q{Escape Character: \) (output)}); $string = PDF::Builder::Basic::PDF::String->from_pdf('(\\)'); is($string->val(), "\\", q{Escape Character: \\}); is($string->as_pdf(), "(\\\\)", q{Escape Character: \\ (output)}); $string = PDF::Builder::Basic::PDF::String->from_pdf("(a\\\x0Ab)"); is($string->val(), 'ab', q{Backslash followed by an EOL marker (LF) is ignored}); $string = PDF::Builder::Basic::PDF::String->from_pdf("(a\\\x0Db)"); is($string->val(), 'ab', q{Backslash followed by an EOL marker (CR) is ignored}); $string = PDF::Builder::Basic::PDF::String->from_pdf("(a\\\x0D\x0Ab)"); is($string->val(), 'ab', q{Backslash followed by an EOL marker (CRLF) is ignored}); $string = PDF::Builder::Basic::PDF::String->from_pdf("(\\0053)"); is($string->val(), "\x05" . '3', q{Escape Character: 3-digit octal followed by a digit is interpreted as two characters}); $string = PDF::Builder::Basic::PDF::String->from_pdf("(\\053)"); is($string->val(), '+', q{Escape Character: 3-digit octal}); $string = PDF::Builder::Basic::PDF::String->from_pdf("(\\53)"); is($string->val(), '+', q{Escape Character: 2-digit octal}); $string = PDF::Builder::Basic::PDF::String->from_pdf("(\\5)"); is($string->val(), "\x05", q{Escape Character: 1-digit octal}); use PDF::Builder::Basic::PDF::Utils; # PDF::API2 enters string as 'PiDeltaPhi', not escapes $string = PDFStr("\x{03A0}\x{0394}\x{03A6}"); is($string->as_pdf(), '', q{A string with the utf8 flag set is automatically encoded as UCS-16BE}); # RT 63918 $string = PDF::Builder::Basic::PDF::String->from_pdf('(3\000f' . "\x5c\x5c" . '3\000f)'); is($string->val(), "3\x00f\\3\x00f", q{[RT #63918] Incorrect handling of literal backslashes 1/2 (input)}); is($string->as_pdf(), '<3300665C330066>', q{[RT #63918] Incorrect handling of literal backslashes 1/2 (output)}); $string = PDF::Builder::Basic::PDF::String->from_pdf('(\000\000\000' . "\x5c\x5c" . '\000\000\000\000)'); is($string->as_pdf(), '<0000005C00000000>', q{[RT #63918] Incorrect handling of literal backslashes 2/2}); # RT 134957 $string = PDFStr("\x00\n\x00"); is($string->as_pdf(), '<000A00>', q{\n in a string containing non-printable characters is hex-encoded}); done_testing(); 1; PDF-Builder-3.026/t/papersizes.t0000644000000000000000000001440114534467462015053 0ustar rootroot#!/usr/bin/perl use warnings; use strict; use Test::More tests => 100; use PDF::Builder; my $pdf = PDF::Builder->new(); my $page = $pdf->page(); my @mediabox; # test named page sizes in Resource/PaperSizes.pm # add additional tests if more sizes uncommented or added in that file $page->mediabox('4a0'); @mediabox = $page->mediabox(); is($mediabox[0], 0, 'PaperSizes LLX (4a0)'); is($mediabox[1], 0, 'PaperSizes LLY (4a0)'); is($mediabox[2], 4760, 'PaperSizes URX (4a0)'); is($mediabox[3], 6716, 'PaperSizes URY (4a0)'); $page->mediabox('2a0'); @mediabox = $page->mediabox(); is($mediabox[0], 0, 'PaperSizes LLX (2a0)'); is($mediabox[1], 0, 'PaperSizes LLY (2a0)'); is($mediabox[2], 3368, 'PaperSizes URX (2a0)'); is($mediabox[3], 4760, 'PaperSizes URY (2a0)'); $page->mediabox('a0'); @mediabox = $page->mediabox(); is($mediabox[0], 0, 'PaperSizes LLX (a0)'); is($mediabox[1], 0, 'PaperSizes LLY (a0)'); is($mediabox[2], 2380, 'PaperSizes URX (a0)'); is($mediabox[3], 3368, 'PaperSizes URY (a0)'); $page->mediabox('a1'); @mediabox = $page->mediabox(); is($mediabox[0], 0, 'PaperSizes LLX (a1)'); is($mediabox[1], 0, 'PaperSizes LLY (a1)'); is($mediabox[2], 1684, 'PaperSizes URX (a1)'); is($mediabox[3], 2380, 'PaperSizes URY (a1)'); $page->mediabox('a2'); @mediabox = $page->mediabox(); is($mediabox[0], 0, 'PaperSizes LLX (a2)'); is($mediabox[1], 0, 'PaperSizes LLY (a2)'); is($mediabox[2], 1190, 'PaperSizes URX (a2)'); is($mediabox[3], 1684, 'PaperSizes URY (a2)'); $page->mediabox('a3'); @mediabox = $page->mediabox(); is($mediabox[0], 0, 'PaperSizes LLX (a3)'); is($mediabox[1], 0, 'PaperSizes LLY (a3)'); is($mediabox[2], 842, 'PaperSizes URX (a3)'); is($mediabox[3], 1190, 'PaperSizes URY (a3)'); $page->mediabox('a4'); @mediabox = $page->mediabox(); is($mediabox[0], 0, 'PaperSizes LLX (a4)'); is($mediabox[1], 0, 'PaperSizes LLY (a4)'); is($mediabox[2], 595, 'PaperSizes URX (a4)'); is($mediabox[3], 842, 'PaperSizes URY (a4)'); $page->mediabox('a5'); @mediabox = $page->mediabox(); is($mediabox[0], 0, 'PaperSizes LLX (a5)'); is($mediabox[1], 0, 'PaperSizes LLY (a5)'); is($mediabox[2], 421, 'PaperSizes URX (a5)'); is($mediabox[3], 595, 'PaperSizes URY (a5)'); $page->mediabox('a6'); @mediabox = $page->mediabox(); is($mediabox[0], 0, 'PaperSizes LLX (a6)'); is($mediabox[1], 0, 'PaperSizes LLY (a6)'); is($mediabox[2], 297, 'PaperSizes URX (a6)'); is($mediabox[3], 421, 'PaperSizes URY (a6)'); $page->mediabox('4b0'); @mediabox = $page->mediabox(); is($mediabox[0], 0, 'PaperSizes LLX (4b0)'); is($mediabox[1], 0, 'PaperSizes LLY (4b0)'); is($mediabox[2], 5656, 'PaperSizes URX (4b0)'); is($mediabox[3], 8000, 'PaperSizes URY (4b0)'); $page->mediabox('2b0'); @mediabox = $page->mediabox(); is($mediabox[0], 0, 'PaperSizes LLX (2b0)'); is($mediabox[1], 0, 'PaperSizes LLY (2b0)'); is($mediabox[2], 4000, 'PaperSizes URX (2b0)'); is($mediabox[3], 5656, 'PaperSizes URY (2b0)'); $page->mediabox('b0'); @mediabox = $page->mediabox(); is($mediabox[0], 0, 'PaperSizes LLX (b0)'); is($mediabox[1], 0, 'PaperSizes LLY (b0)'); is($mediabox[2], 2828, 'PaperSizes URX (b0)'); is($mediabox[3], 4000, 'PaperSizes URY (b0)'); $page->mediabox('b1'); @mediabox = $page->mediabox(); is($mediabox[0], 0, 'PaperSizes LLX (b1)'); is($mediabox[1], 0, 'PaperSizes LLY (b1)'); is($mediabox[2], 2000, 'PaperSizes URX (b1)'); is($mediabox[3], 2828, 'PaperSizes URY (b1)'); $page->mediabox('b2'); @mediabox = $page->mediabox(); is($mediabox[0], 0, 'PaperSizes LLX (b2)'); is($mediabox[1], 0, 'PaperSizes LLY (b2)'); is($mediabox[2], 1414, 'PaperSizes URX (b2)'); is($mediabox[3], 2000, 'PaperSizes URY (b2)'); $page->mediabox('b3'); @mediabox = $page->mediabox(); is($mediabox[0], 0, 'PaperSizes LLX (b3)'); is($mediabox[1], 0, 'PaperSizes LLY (b3)'); is($mediabox[2], 1000, 'PaperSizes URX (b3)'); is($mediabox[3], 1414, 'PaperSizes URY (b3)'); $page->mediabox('b4'); @mediabox = $page->mediabox(); is($mediabox[0], 0, 'PaperSizes LLX (b4)'); is($mediabox[1], 0, 'PaperSizes LLY (b4)'); is($mediabox[2], 707, 'PaperSizes URX (b4)'); is($mediabox[3], 1000, 'PaperSizes URY (b4)'); $page->mediabox('b5'); @mediabox = $page->mediabox(); is($mediabox[0], 0, 'PaperSizes LLX (b5)'); is($mediabox[1], 0, 'PaperSizes LLY (b5)'); is($mediabox[2], 500, 'PaperSizes URX (b5)'); is($mediabox[3], 707, 'PaperSizes URY (b5)'); $page->mediabox('b6'); @mediabox = $page->mediabox(); is($mediabox[0], 0, 'PaperSizes LLX (b6)'); is($mediabox[1], 0, 'PaperSizes LLY (b6)'); is($mediabox[2], 353, 'PaperSizes URX (b6)'); is($mediabox[3], 500, 'PaperSizes URY (b6)'); $page->mediabox('letter'); @mediabox = $page->mediabox(); is($mediabox[0], 0, 'PaperSizes LLX (letter)'); is($mediabox[1], 0, 'PaperSizes LLY (letter)'); is($mediabox[2], 612, 'PaperSizes URX (letter)'); is($mediabox[3], 792, 'PaperSizes URY (letter)'); $page->mediabox('broadsheet'); @mediabox = $page->mediabox(); is($mediabox[0], 0, 'PaperSizes LLX (broadsheet)'); is($mediabox[1], 0, 'PaperSizes LLY (broadsheet)'); is($mediabox[2], 1296, 'PaperSizes URX (broadsheet)'); is($mediabox[3], 1584, 'PaperSizes URY (broadsheet)'); $page->mediabox('ledger'); @mediabox = $page->mediabox(); is($mediabox[0], 0, 'PaperSizes LLX (ledger)'); is($mediabox[1], 0, 'PaperSizes LLY (ledger)'); is($mediabox[2], 1224, 'PaperSizes URX (ledger)'); is($mediabox[3], 792, 'PaperSizes URY (ledger)'); $page->mediabox('tabloid'); @mediabox = $page->mediabox(); is($mediabox[0], 0, 'PaperSizes LLX (tabloid)'); is($mediabox[1], 0, 'PaperSizes LLY (tabloid)'); is($mediabox[2], 792, 'PaperSizes URX (tabloid)'); is($mediabox[3], 1224, 'PaperSizes URY (tabloid)'); $page->mediabox('legal'); @mediabox = $page->mediabox(); is($mediabox[0], 0, 'PaperSizes LLX (legal)'); is($mediabox[1], 0, 'PaperSizes LLY (legal)'); is($mediabox[2], 612, 'PaperSizes URX (legal)'); is($mediabox[3], 1008, 'PaperSizes URY (legal)'); $page->mediabox('executive'); @mediabox = $page->mediabox(); is($mediabox[0], 0, 'PaperSizes LLX (executive)'); is($mediabox[1], 0, 'PaperSizes LLY (executive)'); is($mediabox[2], 522, 'PaperSizes URX (executive)'); is($mediabox[3], 756, 'PaperSizes URY (executive)'); $page->mediabox('36x36'); @mediabox = $page->mediabox(); is($mediabox[0], 0, 'PaperSizes LLX (36x36)'); is($mediabox[1], 0, 'PaperSizes LLY (36x36)'); is($mediabox[2], 2592, 'PaperSizes URX (36x36)'); is($mediabox[3], 2592, 'PaperSizes URY (36x36)'); done_testing(); 1; PDF-Builder-3.026/t/rt126274.t0000644000000000000000000000205114534467462013777 0ustar rootroot#!/usr/bin/perl use warnings; use strict; use Test::More; use PDF::Builder; my $pdf = PDF::Builder->new(); # was 'latin1' encoding, but some Solaris test systems fail on that my $corefont = $pdf->corefont('Helvetica', 'encode' => 'iso-8859-1')->tounicodemap(); my $block1 = $pdf->corefont('Helvetica', 'encode' => 'uni1'); my $unifont = $pdf->unifont($corefont, [$block1, [1]], 'encode' => 'utf-8'); my $page = $pdf->page(); $page->mediabox('letter'); my $text = $page->text(); $text->font($unifont, 12); my $reset = $text->{' stream'}; $text->transform('translate' => [100, 100]); $text->text_center("test"); my $value = $text->{' stream'}; like($value, qr/\[ \d+ \(test\) \] TJ/, q{Centered text is offset when it doesn't contain any special characters}); $text->{' stream'} = $reset; $text->transform('translate' => [100, 100]); $text->text_center("test\x{151}"); $value = $text->{' stream'}; like($value, qr/\[ \d+ \(test\) \] TJ \/\S+ \d+ Tf \(Q\) Tj/, q{Centered text is offset when it contains special characters}); done_testing(); 1; PDF-Builder-3.026/t/named-destinations.t0000644000000000000000000000061514534467462016456 0ustar rootroot#!/usr/bin/perl use strict; use warnings; use Test::More; use PDF::Builder; use PDF::Builder::NamedDestination; my $pdf = PDF::Builder->new(); my $page1 = $pdf->page(); my $dest = PDF::Builder::NamedDestination->new($pdf, $page1, 'fit'=>1); my $string = $pdf->to_string(); like($string, qr{/D \[ \d+ 0 R /Fit \]}, q{Basic named destination is recorded in the PDF}); done_testing(); 1; PDF-Builder-3.026/t/tiff.t0000644000000000000000000005557414534467462013636 0ustar rootroot#!/usr/bin/perl use warnings; use strict; use English qw( -no_match_vars ); use IPC::Cmd qw(can_run run); use File::Spec; use File::Temp; use version; use Test::More tests => 19; #use Test::More tests => 25; when TIFF changes in use PDF::Builder; # 0: allow use of Graphics::TIFF, 1: force non-GT usage my $noGT = 0; my $diag = ''; my $failed; # Filename 3 tests ------------------ # tests 1 and 3 will mention TIFF_GT if Graphics::TIFF is installed and # usable, otherwise they will display just TIFF. you can use this information # if you are not sure about the status of Graphics::TIFF. my $pdf = PDF::Builder->new('-compress' => 'none'); # common $pdf all tests my $has_GT = 0; # global flag for all tests that need to know if Graphics::TIFF my ($page, $img, $example, $expected); # -silent shuts off one-time warning for rest of run my $tiff = $pdf->image_tiff('t/resources/1x1.tif', -silent => 1, -nouseGT => $noGT); # 1 if ($tiff->usesLib() == 1) { $has_GT = 1; isa_ok($tiff, 'PDF::Builder::Resource::XObject::Image::TIFF_GT', q{$pdf->image_tiff(filename)}); } else { isa_ok($tiff, 'PDF::Builder::Resource::XObject::Image::TIFF', q{$pdf->image_tiff(filename)}); } # 2 is($tiff->width(), 1, q{Image from filename has a width}); # 3 my $gfx = $pdf->page()->gfx(); $gfx->image($tiff, 72, 144, 216, 288); like($pdf->to_string(), qr/q 216 0 0 288 72 144 cm \S+ Do Q/, q{Add TIFF to PDF}); # Filehandle (old library only) 2 tests ------------------ # 4 $pdf = PDF::Builder->new(); open my $fh, '<', 't/resources/1x1.tif' or die "Couldn't open file t/resources/1x1.tif"; $tiff = $pdf->image_tiff($fh, -nouseGT => 1); isa_ok($tiff, 'PDF::Builder::Resource::XObject::Image::TIFF', q{$pdf->image_tiff(filehandle)}); # 5 is($tiff->width(), 1, q{Image from filehandle has a width}); close $fh; # LZW Compression 2 tests ------------------ $pdf = PDF::Builder->new('-compress' => 'none'); # 6 my $lzw_tiff = $pdf->image_tiff('t/resources/1x1-lzw.tif', -nouseGT => $noGT); if ($lzw_tiff->usesLib() == 1) { isa_ok($lzw_tiff, 'PDF::Builder::Resource::XObject::Image::TIFF_GT', q{$pdf->image_tiff(), LZW compression}); } else { isa_ok($lzw_tiff, 'PDF::Builder::Resource::XObject::Image::TIFF', q{$pdf->image_tiff(), LZW compression}); } $gfx = $pdf->page()->gfx(); $gfx->image($lzw_tiff, 72, 360, 216, 432); # 7 like($pdf->to_string(), qr/q 216 0 0 432 72 360 cm \S+ Do Q/, q{Add TIFF to PDF}); # Missing file 1 test ------------------ # 8 $pdf = PDF::Builder->new(); eval { $pdf->image_tiff('t/resources/this.file.does.not.exist', -nouseGT => $noGT) }; ok($@, q{Fail fast if the requested file doesn't exist}); ############################################################## # common data for remaining tests my $width = 1000; my $height = 100; my $directory = File::Temp->newdir(); my $tiff_f = File::Spec->catfile($directory, 'test.tif'); my $pdfout = File::Spec->catfile($directory, 'test.pdf'); my $pngout = File::Spec->catfile($directory, 'out.png'); # NOTE: following 4 tests use 'convert' tool from ImageMagick. # They may require software installation on your system, and # will be skipped if the necessary software is not found. # # Some of the following tests will need ghostScript on Windows platforms. # Note that GS installation MAY not permanently add GS to %Path% -- you # may have to do this manually my ($convert, $gs, $convertX, $gsX); # ImageMagick pre-v7 has a "convert" utility. # On v7, this is called via "magick convert" # On Windows, be careful NOT to run "convert", as this is a HDD reformatter! if (can_run("magick")) { $convert = "magick convert"; } elsif ($OSNAME ne 'MSWin32' and can_run("convert")) { $convert = "convert"; } # check if reasonably recent version $convert = check_version($convert, '-version', 'ImageMagick ([0-9.]+)', '6.9.7'); # use $convertX instead of $convert in selected tests if IM excluded version # (error) found #$convertX = exclude_version($convert, '-v', 'ImageMagick ([0-9.]+)', # ['8.0.4','100.0', ]); #$convertX = $convert; # if want to keep tests changed, but not exclude # $convert undef if not installed, can't parse format, version too low # will skip "No ImageMagick" # on Windows, ImageMagick can be 64-bit or 32-bit version, so try both. it's # needed for some magick convert operations, and also standalone, and # usually must be installed. # on Linux-like systems, it's usually just 'gs' and comes with the platform. if (can_run("gswin64c")) { $gs = "gswin64c"; } elsif (can_run("gswin32c")) { $gs = "gswin32c"; } elsif (can_run("gs")) { $gs = "gs"; } # check if reasonably recent version $gs = check_version($gs, '-v', 'Ghostscript ([0-9.]+)', '9.25.0'); # use $gsX instead of $gs in selected tests if GS excluded version (error) found $gsX = exclude_version($gs, '-v', 'Ghostscript ([0-9.]+)', ['9.56.0','9.56.1', ]); #$gsX = $gs; # if want to keep tests changed, but not exclude # $convert undef if not installed, can't parse format, version too low # will skip "No Ghostscript" # alpha layer handling ------------------ # convert and Graphics::TIFF needed # 9 SKIP: { skip "Either ImageMagick, Ghostscript or Graphics::TIFF not available.", 1 unless defined $convert and defined $gs and $has_GT; system("$convert -depth 1 -gravity center -pointsize 78 -size ${width}x${height} caption:\"A caption for the image\" $tiff_f"); # ---------- $pdf = PDF::Builder->new(-file => $pdfout); $page = $pdf->page(); $page->mediabox($width, $height); $gfx = $page->gfx(); $img = $pdf->image_tiff($tiff_f, -nouseGT => $noGT); $gfx->image($img, 0, 0, $width, $height); $pdf->save(); $pdf->end(); # ---------- system("$gs -q -dNOPAUSE -dBATCH -sDEVICE=pngalpha -g${width}x${height} -dPDFFitPage -dUseCropBox -sOutputFile=$pngout $pdfout"); my $example = `$convert $pngout -colorspace gray -depth 1 txt:-`; my $expected = `$convert $tiff_f -depth 1 txt:-`; # ---------- is($example, $expected, 'alpha + flate') or show_diag(); } # G4 (NOT converted to Flate) ------------------ # convert and Graphics::TIFF are needed # 10 SKIP: { skip "Either ImageMagick, Ghostscript or Graphics::TIFF not available.", 1 unless defined $convert and defined $gs and $has_GT; system("$convert -depth 1 -gravity center -pointsize 78 -size ${width}x${height} caption:\"A caption for the image\" -background white -alpha off -compress Group4 $tiff_f"); # ---------- $pdf = PDF::Builder->new(-file => $pdfout); $page = $pdf->page(); $page->mediabox($width, $height); $gfx = $page->gfx(); $img = $pdf->image_tiff($tiff_f, -nouseGT => $noGT); $gfx->image($img, 0, 0, $width, $height); $pdf->save(); $pdf->end(); # ---------- system("$gs -q -dNOPAUSE -dBATCH -sDEVICE=pnggray -g${width}x${height} -dPDFFitPage -dUseCropBox -sOutputFile=$pngout $pdfout"); $example = `$convert $pngout -depth 1 txt:-`; $expected = `$convert $tiff_f -depth 1 txt:-`; # ---------- is($example, $expected, 'G4 (not converted to flate)') or show_diag(); } # LZW (NOT converted to Flate) ------------------ # convert and Graphics::TIFF needed for these two tests # 11 SKIP: { skip "Either ImageMagick, Ghostscript or Graphics::TIFF not available.", 1 unless defined $convert and defined $gs and $has_GT; system("$convert -depth 1 -gravity center -pointsize 78 -size ${width}x${height} caption:\"A caption for the image\" -background white -alpha off -compress lzw $tiff_f"); # ---------- $pdf = PDF::Builder->new(-file => $pdfout); $page = $pdf->page(); $page->mediabox( $width, $height ); $gfx = $page->gfx(); $img = $pdf->image_tiff($tiff_f, -nouseGT => 0); $gfx->image( $img, 0, 0, $width, $height ); $pdf->save(); $pdf->end(); # ---------- system("$gs -q -dNOPAUSE -dBATCH -sDEVICE=pnggray -g${width}x${height} -dPDFFitPage -dUseCropBox -sOutputFile=$pngout $pdfout"); $example = `$convert $pngout -depth 1 -alpha off txt:-`; $expected = `$convert $tiff_f -depth 1 -alpha off txt:-`; # ---------- is($example, $expected, 'single-strip lzw (not converted to flate) with GT') or show_diag(); } # 12 SKIP: { skip "Either ImageMagick, Ghostscript or Graphics::TIFF not available.", 1 unless defined $convert and defined $gs and $has_GT; system("$convert -depth 1 -gravity center -pointsize 78 -size ${width}x${height} caption:\"A caption for the image\" -background white -alpha off -define tiff:rows-per-strip=50 -compress lzw $tiff_f"); # ---------- $pdf = PDF::Builder->new(-file => $pdfout); $page = $pdf->page(); $page->mediabox( $width, $height ); $gfx = $page->gfx(); $img = $pdf->image_tiff($tiff_f, -nouseGT => 0); $gfx->image( $img, 0, 0, $width, $height ); $pdf->save(); $pdf->end(); # ---------- system("$gs -q -dNOPAUSE -dBATCH -sDEVICE=pnggray -g${width}x${height} -dPDFFitPage -dUseCropBox -sOutputFile=$pngout $pdfout"); $example = `$convert $pngout -depth 1 -alpha off txt:-`; $expected = `$convert $tiff_f -depth 1 -alpha off txt:-`; # ---------- is($example, $expected, 'multi-strip lzw (not converted to flate) with GT') or show_diag(); } # 13 SKIP: { skip "Either ImageMagick, Ghostscript or Graphics::TIFF not available.", 1 unless defined $convert and defined $gsX and $has_GT; $width = 20; $height = 20; system("$convert -depth 8 -size 2x2 pattern:gray50 -scale 1000% -alpha off -define tiff:predictor=2 -compress lzw $tiff_f"); # ---------- $pdf = PDF::Builder->new(-file => $pdfout); $page = $pdf->page(); $page->mediabox( $width, $height ); $gfx = $page->gfx(); $img = $pdf->image_tiff($tiff_f, -nouseGT => 0); $gfx->image( $img, 0, 0, $width, $height ); $pdf->save(); $pdf->end(); # ---------- system("$gs -q -dNOPAUSE -dBATCH -sDEVICE=pnggray -g${width}x${height} -dPDFFitPage -dUseCropBox -sOutputFile=$pngout $pdfout"); $example = `$convert $pngout -depth 8 -alpha off txt:-`; $expected = `$convert $tiff_f -depth 8 -alpha off txt:-`; # ---------- is($example, $expected, 'lzw+horizontal predictor (not converted to flate) with GT') or show_diag(); } # 14 SKIP: { skip "Either ImageMagick, Ghostscript or Graphics::TIFF not available.", 1 unless defined $convert and defined $gs and $has_GT; $width = 1000; $height = 100; system("$convert -depth 1 -gravity center -pointsize 78 -size ${width}x${height} caption:\"A caption for the image\" -compress lzw $tiff_f"); # ---------- $pdf = PDF::Builder->new(-file => $pdfout); $page = $pdf->page(); $page->mediabox( $width, $height ); $gfx = $page->gfx(); $img = $pdf->image_tiff($tiff_f, -nouseGT => $noGT); $gfx->image( $img, 0, 0, $width, $height ); $pdf->save(); $pdf->end(); # ---------- system("$gs -q -dNOPAUSE -dBATCH -sDEVICE=pngalpha -g${width}x${height} -dPDFFitPage -dUseCropBox -sOutputFile=$pngout $pdfout"); $example = `$convert $pngout -colorspace gray -depth 1 txt:-`; $expected = `$convert $tiff_f -depth 1 txt:-`; # ---------- is($example, $expected, 'alpha + lzw') or show_diag(); } # 15 SKIP: { skip "Either ImageMagick or Ghostscript not available.", 1 unless defined $convert and defined $gs; system("$convert -depth 1 -gravity center -pointsize 78 -size ${width}x${height} caption:\"A caption for the image\" -background white -alpha off -compress lzw $tiff_f"); # ---------- $pdf = PDF::Builder->new(-file => $pdfout); $page = $pdf->page(); $page->mediabox( $width, $height ); $gfx = $page->gfx(); $img = $pdf->image_tiff($tiff_f, -nouseGT => 1); $gfx->image( $img, 0, 0, $width, $height ); $pdf->save(); $pdf->end(); # ---------- system("$gs -q -dNOPAUSE -dBATCH -sDEVICE=pnggray -g${width}x${height} -dPDFFitPage -dUseCropBox -sOutputFile=$pngout $pdfout"); $example = `$convert $pngout -depth 1 -alpha off txt:-`; $expected = `$convert $tiff_f -depth 1 -alpha off txt:-`; # ---------- is($example, $expected, 'single-strip lzw (not converted to flate) without GT') or show_diag(); } SKIP: { skip "Either ImageMagick or Ghostscript not available.", 1 unless defined $convert and defined $gsX; # 16 $width = 20; $height = 20; system("$convert -depth 8 -size 2x2 pattern:gray50 -scale 1000% -alpha off -define tiff:predictor=2 -compress lzw $tiff_f"); # ---------- $pdf = PDF::Builder->new(-file => $pdfout); $page = $pdf->page(); $page->mediabox( $width, $height ); $gfx = $page->gfx(); $img = $pdf->image_tiff($tiff_f, -nouseGT => 1); $gfx->image( $img, 0, 0, $width, $height ); $pdf->save(); $pdf->end(); # ---------- system("$gs -q -dNOPAUSE -dBATCH -sDEVICE=pnggray -g${width}x${height} -dPDFFitPage -dUseCropBox -sOutputFile=$pngout $pdfout"); $example = `$convert $pngout -depth 1 -alpha off txt:-`; $expected = `$convert $tiff_f -depth 1 -alpha off txt:-`; # ---------- is($example, $expected, 'lzw+horizontal predictor (not converted to flate) without GT') or show_diag(); $width = 1000; $height = 100; } # 17 TODO SKIP: { skip "multi-strip lzw without GT is not currently supported", 1; system("$convert -depth 1 -gravity center -pointsize 78 -size ${width}x${height} caption:\"A caption for the image\" -background white -alpha off -define tiff:rows-per-strip=50 -compress lzw $tiff_f"); # ---------- $pdf = PDF::Builder->new(-file => $pdfout); $page = $pdf->page(); $page->mediabox( $width, $height ); $gfx = $page->gfx(); $img = $pdf->image_tiff($tiff_f, -nouseGT => 1); $gfx->image( $img, 0, 0, $width, $height ); $pdf->save(); $pdf->end(); # ---------- system("$gs -q -dNOPAUSE -dBATCH -sDEVICE=pnggray -g${width}x${height} -dPDFFitPage -dUseCropBox -sOutputFile=$pngout $pdfout"); $example = `$convert $pngout -depth 1 -alpha off txt:-`; $expected = `$convert $tiff_f -depth 1 -alpha off txt:-`; # ---------- is($example, $expected, 'multi-strip lzw (not converted to flate) without GT') or show_diag(); } # read TIFF with colormap ------------------ # convert and Graphics::TIFF needed for this test # 18 SKIP: { skip "Either ImageMagick or Graphics::TIFF not available.", 1 unless defined $convert and $has_GT; # .png file is temporary file (output, input, erased) my $colormap = File::Spec->catfile($directory, 'colormap.png'); system("$convert rose: -type palette -depth 2 $colormap"); system("$convert $colormap $tiff_f"); $pdf = PDF::Builder->new(-file => $pdfout); $page = $pdf->page; $page->mediabox( $width, $height ); $gfx = $page->gfx(); $img = $pdf->image_tiff($tiff_f, -nouseGT => $noGT); $gfx->image( $img, 0, 0, $width, $height ); $pdf->save(); $pdf->end(); pass 'successfully read TIFF with colormap'; } # 19 SKIP: { skip "Either ImageMagick, Ghostscript or Graphics::TIFF not available.", 1 unless defined $convert and defined $gs and $has_GT; $width = 6; $height = 1; system("$convert -depth 1 -size ${width}x${height} pattern:gray50 -alpha on $tiff_f"); $pdf = PDF::Builder->new(-file => $pdfout); $page = $pdf->page(); $page->mediabox( $width, $height ); $gfx = $page->gfx(); $img = $pdf->image_tiff($tiff_f, -nouseGT => 0); $gfx->image( $img, 0, 0, $width, $height ); $pdf->save(); $pdf->end(); # ---------- system("$gs -q -dNOPAUSE -dBATCH -sDEVICE=pnggray -g${width}x${height} -dPDFFitPage -dUseCropBox -sOutputFile=$pngout $pdfout"); $example = `$convert $pngout -depth 1 -alpha off txt:-`; $expected = `$convert $tiff_f -depth 1 -alpha off txt:-`; # "For reasons I don't understand, gs swaps the last two pixels here, so let's # ignore them." This glitch is reported by @carygravel ("gs consistently # swapped two pixels in the last byte of the first row" over multiple test # images), but the PDF produced appears to be OK -- it's just something odd # happening in producing the PNG for comparison. We'll keep an eye on it, as I # don't particularly like magic solutions. See PR #165. $example =~ s/(.*\n).*\n.*\n$/$1/; $expected =~ s/(.*\n).*\n.*\n$/$1/; # ---------- is($example, $expected, "bilevel and alpha when width not a whole number of bytes with GT") or show_diag(); } if (0) { ####################################### when TIFF changes in # 20 TODO SKIP: { skip "alpha layer without GT is not currently supported", 1; #SKIP: { # skip "Either ImageMagick or Ghostscript not available.", 1 unless # defined $convert and defined $gs; $width = 6; $height = 1; system("$convert -depth 1 -size ${width}x${height} pattern:gray50 -alpha on $tiff_f"); $pdf = PDF::Builder->new(-file => $pdfout); $page = $pdf->page(); $page->mediabox( $width, $height ); $gfx = $page->gfx(); $img = $pdf->image_tiff($tiff_f, -nouseGT => 1); $gfx->image( $img, 0, 0, $width, $height ); $pdf->save(); $pdf->end(); # ---------- system("$gs -q -dNOPAUSE -dBATCH -sDEVICE=pnggray -g${width}x${height} -dPDFFitPage -dUseCropBox -sOutputFile=$pngout $pdfout"); $example = `$convert $pngout -depth 1 -alpha off txt:-`; $expected = `$convert $tiff_f -depth 1 -alpha off txt:-`; # for reasons I don't understand, gs swaps the last two pixels here, so let's # ignore them $example =~ s/(.*\n).*\n.*\n$/$1/; $expected =~ s/(.*\n).*\n.*\n$/$1/; # ---------- is($example, $expected, "bilevel and alpha when width not a whole number of bytes without GT"); } # 21 SKIP: { skip "Either ImageMagick, Ghostscript or Graphics::TIFF not available.", 1 unless defined $convert and defined $gs and $has_GT; $width = 6; $height = 2; system("$convert -depth 1 -size ${width}x${height} pattern:gray50 -alpha off -define tiff:rows-per-strip=1 -compress fax $tiff_f"); $pdf = PDF::Builder->new(-file => $pdfout); $page = $pdf->page(); $page->mediabox( $width, $height ); $gfx = $page->gfx(); $img = $pdf->image_tiff($tiff_f, -nouseGT => 0); $gfx->image( $img, 0, 0, $width, $height ); $pdf->save(); $pdf->end(); # ---------- system("$gs -q -dNOPAUSE -dBATCH -sDEVICE=pnggray -g${width}x${height} -dPDFFitPage -dUseCropBox -sOutputFile=$pngout $pdfout"); $example = `$convert $pngout -depth 1 -alpha off txt:-`; $expected = `$convert $tiff_f -depth 1 -alpha off txt:-`; # ---------- is($example, $expected, 'multi-strip group 3 (not converted to flate) with GT'); } # 22 SKIP: { skip "Either ImageMagick, Ghostscript or Graphics::TIFF not available.", 1 unless defined $convert and defined $gs and $has_GT; $width = 6; $height = 2; system("$convert -depth 1 -size ${width}x${height} pattern:gray50 -alpha off -define tiff:rows-per-strip=1 -compress group4 $tiff_f"); $pdf = PDF::Builder->new(-file => $pdfout); $page = $pdf->page(); $page->mediabox( $width, $height ); $gfx = $page->gfx(); $img = $pdf->image_tiff($tiff_f, -nouseGT => 0); $gfx->image( $img, 0, 0, $width, $height ); $pdf->save(); $pdf->end(); # ---------- system("$gs -q -dNOPAUSE -dBATCH -sDEVICE=pnggray -g${width}x${height} -dPDFFitPage -dUseCropBox -sOutputFile=$pngout $pdfout"); $example = `$convert $pngout -depth 1 -alpha off txt:-`; $expected = `$convert $tiff_f -depth 1 -alpha off txt:-`; # ---------- is($example, $expected, 'multi-strip g4 (not converted to flate) with GT'); } # 23 SKIP: { skip "Either ImageMagick, Ghostscript or Graphics::TIFF not available.", 1 unless defined $convert and defined $gs and $has_GT; $width = 6; $height = 2; system("$convert -depth 1 -size ${width}x${height} pattern:gray50 -alpha off -define tiff:rows-per-strip=1 -define quantum:polarity=min-is-black -compress fax $tiff_f"); $pdf = PDF::Builder->new(-file => $pdfout); $page = $pdf->page(); $page->mediabox( $width, $height ); $gfx = $page->gfx(); $img = $pdf->image_tiff($tiff_f, -nouseGT => 0); $gfx->image( $img, 0, 0, $width, $height ); $pdf->save(); $pdf->end(); # ---------- system("$gs -q -dNOPAUSE -dBATCH -sDEVICE=pnggray -g${width}x${height} -dPDFFitPage -dUseCropBox -sOutputFile=$pngout $pdfout"); $example = `$convert $pngout -depth 1 -alpha off txt:-`; $expected = `$convert $tiff_f -depth 1 -alpha off txt:-`; # ---------- is($example, $expected, 'multi-strip g3 min-is-black (not converted to flate) with GT'); } # 24 SKIP: { skip "Either ImageMagick, Ghostscript or Graphics::TIFF not available.", 1 unless defined $convert and defined $gs and $has_GT; $width = 6; $height = 2; system("$convert -depth 1 -size ${width}x${height} pattern:gray50 -alpha off -define tiff:rows-per-strip=1 -define quantum:polarity=min-is-black -compress group4 $tiff_f"); $pdf = PDF::Builder->new(-file => $pdfout); $page = $pdf->page(); $page->mediabox( $width, $height ); $gfx = $page->gfx(); $img = $pdf->image_tiff($tiff_f, -nouseGT => 0); $gfx->image( $img, 0, 0, $width, $height ); $pdf->save(); $pdf->end(); # ---------- system("$gs -q -dNOPAUSE -dBATCH -sDEVICE=pnggray -g${width}x${height} -dPDFFitPage -dUseCropBox -sOutputFile=$pngout $pdfout"); $example = `$convert $pngout -depth 1 -alpha off txt:-`; $expected = `$convert $tiff_f -depth 1 -alpha off txt:-`; # ---------- is($example, $expected, 'multi-strip g4 min-is-black (not converted to flate) with GT'); } # 25 SKIP: { skip "Either ImageMagick, Ghostscript or Graphics::TIFF not available.", 1 unless defined $convert and defined $gs and $has_GT; $width = 6; $height = 2; system("$convert -depth 1 -size ${width}x${height} pattern:gray50 -alpha off -define tiff:fill-order=lsb -compress group4 $tiff_f"); $pdf = PDF::Builder->new(-file => $pdfout); $page = $pdf->page(); $page->mediabox( $width, $height ); $gfx = $page->gfx(); $img = $pdf->image_tiff($tiff_f, -nouseGT => 0); $gfx->image( $img, 0, 0, $width, $height ); $pdf->save(); $pdf->end(); # ---------- system("$gs -q -dNOPAUSE -dBATCH -sDEVICE=pnggray -g${width}x${height} -dPDFFitPage -dUseCropBox -sOutputFile=$pngout $pdfout"); $example = `$convert $pngout -depth 1 -alpha off txt:-`; $expected = `$convert $tiff_f -depth 1 -alpha off txt:-`; # ---------- is($example, $expected, 'LSB fillorder with GT'); } } ####################################### when TIFF changes in ############################################################## # cleanup. all tests involving these files skipped? # check non-Perl utility versions sub check_version { my ($cmd, $arg, $regex, $min_ver) = @_; # was the check routine already defined (installed)? if (defined $cmd) { # should match dotted version number my $output = `$cmd $arg`; $diag .= $output; if ($output =~ m/$regex/) { if (version->parse($1) >= version->parse($min_ver)) { return $cmd; } } } return; # cmd not defined (not installed) so return undef } # exclude specified non-Perl utility versions # do not call if don't have one or more exclusion ranges sub exclude_version { my ($cmd, $arg, $regex, $ex_ver_r) = @_; my (@ex_ver, $my_ver); if (defined $ex_ver_r) { @ex_ver = @$ex_ver_r; } else { return; # called w/o exclusion list: fail } # need 2, 4, 6,... dotted versions if (!scalar(@ex_ver) || scalar(@ex_ver)%2) { return; # called with zero or odd number of elements: fail } if (defined $cmd) { # dotted version number should not fall into an excluded range my $output = `$cmd $arg`; $diag .= $output; if ($output =~ m/$regex/) { $my_ver = version->parse($1); for (my $i=0; $i= version->parse($ex_ver[$i ]) && $my_ver <= version->parse($ex_ver[$i+1])) { return; # fell into one of the exclusion ranges } } return $cmd; # didn't hit any exclusions, so OK } } return; # cmd not defined (not installed) so return undef } sub show_diag { $failed = 1; return; } if ($failed) { diag($diag) } PDF-Builder-3.026/xt/0000755000000000000000000000000014534467617012673 5ustar rootrootPDF-Builder-3.026/xt/author-critic.t0000644000000000000000000000056614307706550015632 0ustar rootroot#!/usr/bin/perl use strict; use warnings; # Windows: SET AUTHOR_TESTING=1 # this test is a subset of tools/1_pc.pl BEGIN { unless ($ENV{'AUTHOR_TESTING'}) { print qq{1..0 # SKIP these tests are for testing by the author\n}; exit } } use strict; use warnings; use Test::Perl::Critic (-profile => "..\.perlcriticrc") x!! -e "..\.perlcriticrc"; all_critic_ok(); PDF-Builder-3.026/xt/author-pod-syntax.t0000644000000000000000000000053514307706550016457 0ustar rootroot#!/usr/bin/perl use strict; use warnings; # Windows: SET AUTHOR_TESTING=1 BEGIN { unless ($ENV{'AUTHOR_TESTING'}) { print qq{1..0 # SKIP these tests are for testing by the author\n}; exit } } # This file was automatically generated by Dist::Zilla::Plugin::PodSyntaxTests. use Test::More; use Test::Pod 1.41; all_pod_files_ok(); 1; PDF-Builder-3.026/Changes0000644000000000000000000007117714534425576013546 0ustar rootrootSee also INFO/Changes-ver_2 for changes released for PDF::API2, and incorporated into PDF::Builder. See also INFO/Changes_2021 for earlier version 3 release logs. 3.026 2023-12-07 lib/PDF/Builder/Content/Text.pm, examples/Column.pl Add HTML "reversed" (boolean) to
          tag to count down instead of up (needs "start" value to make any sense). I wanted to fix a few more minor problems with column(), including the color of the first text in a
        1. overriding the marker color, a bunch of redundant font and color change commands and some other inefficiencies, and some other stuff. Unfortunately, that looks like a considerable rewrite of column(), and I ran out of runway, so I'll have to put it off to the next release. lib/PDF/Builder/Content.pm Add some POD notes about the use of charspace for tracking adjustments, and the interaction with wordspace adjustments for a more balanced appearance of justified text. devtools/ A collection of various utilities I use to build PDF::Builder (the CPAN package), as well as do the PHP conversion of HTML code for the web page display of documentation (see catskilltech.com). Note that buildDoc.pl (to build all the HTML files from POD) is already shipped with the package. Further note that tools/1_pc.pl (Perl Critic) will complain a LOT about the code in devtools/ ... maybe some day I'll get around to cleaning it up. (many .pm files), META.yml, Makefile.PL, README.md, docs/buildDoc.pl, t/00-all-usable.t, tools/optional_update.pl, version Cleanup of POD so that unordered/bulleted lists, ordered/numbered lists, definition/description lists, and indented paragraphs are properly handled upon conversion to HTML. Change optional POD-to-HTML generation from the old pod2html to Pod::Simple::XHTML. lib/PDF/Builder/Content.pm The linedash() method was not properly handling a restore of a saved dash pattern, resulting in PDF "dash pattern" values that could be unusable by a Reader. lib/PDF/Builder.pm, lib/PDF/Builder/FontManager.pm, lib/PDF/Builder/Content/Text.pm, t/03-xrefstm-index.t Continuing Issue #197, clean up handling of newly-created PDF object in from_string() method (used by open() method). Also knock-on effects on some t-tests. lib/PDF/Basic/PDF/Pages.pm Issue #203 a new page was being inserted in the wrong place. Thanks to Vadim Repin for finding a "one off" index error that's apparently been there for at least a decade, and the fix. lib/PDF/Builder.pm, lib/PDF/Builder/Basic/PDF/File.pm Improve upon the Integrity Check, acknowledging that missing objects might be hidden in an object stream. The open() function was also sometimes seeing a class reference rather than a pure class, which has been fixed. See issue #196 and especially #197. lib/PDF/Builder.pm, lib/PDF/Builder/Content.pm, examples/060_transparency, INFO/KNOWN_INCOMP, tools/1_pc.pl Remove ability to generate save() ("q") and restore() ("Q") while in a text object. If attempted in text, it is now a no-op with a one-time (per run) warning message reminding users to update their code NOT to attempt save and restore in text mode. This was prompted by PDF::TableX t-tests using text save and restore, which isn't permitted by the PDF definition. Updated one PDF::Builder example that (unnecessarily) did a save/restore in text mode. Thanks to Vadim Repin for troubleshooting this and determining the problem and fix. While in here, make the warning message that a request for 'Times' core font is changed to 'Times-Roman' a one-time (per run) output, rather than every time. lib/PDF/Builder/Page.pm, INFO/DEPRECATED, t/deprecations-page.t Obsolete and deprecated methods get_mediabox(), get_cropbox(), get_bleedbox(), get_trimbox(), and get_artbox() have been removed. Please use the regular methods (in $pdf or $page) with no arguments, to retrieve the current box values. lib/PDF/Builder/Resource/XObject/Image.pm, INFO/DEPRECATED Deprecate Image object methods width() and height() ability to SET the width and height of an image. This setting apparently has never worked properly, but in case someone is actually using it for some purpose, it has not been immediately removed. It is planned to be removed after October, 2025, unless someone shows that they are using it. (most .pm files) Reformat POD to make navigation easier, including the listing of all user- accessible methods in a POD's Table of Contents at the top. lib/PDF/Builder/Content.pm, lib/PDF/Resource/XObject/Form/Hybrid.pm, lib/PDF/Builder/Lite.pm, INFO/DEPRECATED, examples/021_psfonts, t/content-deprecated.t, t/deprecations.t Remove long-deprecated method and global variable "lead". Use "leading" instead, which is the correct typographical term. Although the "Lite" subpackage isn't really maintained, "textlead()" has been replaced by "textleading()". lib/PDF/Builder/Basic/PDF/Array.pm, /lib/PDF/Builder/Basic/PDF/Objind.pm, INFO/DEPRECATED, t/deprecations.t Remove long-deprecated method "elementsof()" in favor of "elements()". Remove long-deprecated method "removeobj()" in favor of "remove_element()". README.md, Makefile.PL, META.yml, META.json, lib/PDF/Builder.pm, examples/Column.pl Minimum Perl version changed from 5.24 to 5.26. Update list of expected end-of-service against various Perl versions. lib/PDF/Builder/Content.pm Clarify description of "bogen()" method's "larger" and "reverse" options. lib/PDF/Builder/Content.pm, lib/PDF/Builder/Content/Text.pm Implement 'align' option for text() left/center/right, l/c/r. README.md, examples/020_textunderline Add pointer to README to online documentation, and clarify underline example (that first text is NOT underlined). lib/PDF/Builder.pm Clarify documentation on page_labels() versus pageLabel(), add code to check differences in starting page index and form of options, in response to PDF::API2 Issue #61. lib/PDF/Builder/Content/Text.pm A number of minor fixes: explicitly make paragraph

          a block level, any pending margin-bottom at the end of a column (if ran out of input) should be accounted for in the returned $start_y. INFO/ACKNOWLEDGE.md (new), README.md, MANIFEST Add acknowledgements and thanks. lib/PDF/Builder/Basic/PDF/Filter/LZWDecode.pm Revert an earlier change that broke some filtering. README.md Update to point to new PDF::Builder Home Page structure (on catskilltech.com). t/info.t Add test of modified() method. lib/PDF/Builder.pm Incorrect check on date format (missing last '). Reported by Johan Vromans against PDF::API2 #62. The _is_date() method has been updated to reflect a number of date/time formats found "in the wild", although the PDF documentation is a bit inconsistent over time, as well as ambiguous, so this may allow through some invalid formats. lib/PDF/Builder.pm, examples/050_pagelabels Fix an incompatibility with PDF::API2 recent changes (page_labels method). Now starts page index (for page_labels) at 1 instead of 0, and warns if 0 page index (page number) is given for page_labels (per API2 ticket #61). The old pageLabel method, kept for compatibility, is unaffected. The example script has been updated to show both styles. lib/PDF/Builder/Content/Text.pm Make paragraph() method compatible with PDF::API2's, i.e., $continue parameter is optional. It should make no difference in calls to paragraph whether there is a fourth parameter (continue) before the options. This incompatibility showed up in PDF::TableX t-tests. lib/PDF/Builder/Docs.pm Full writeup of what's supported for markup input (Markdown, HTML). tools/3_examples.pl, examples/020_corefonts, examples/021_synfonts, examples/023_cjkfonts Add -s flag to run a small subset of the lengthy test list for three of the examples, plus overall when running all examples. lib/PDF/Builder/Page.pm, lib/PDF/Builder/Resource/CIDFont.pm Clean up some typos preventing synfont t-test from running. lib/PDF/Builder.pm, lib/PDF/Builder/Resource/CIDFont.pm It has come to our attention (#193) that PDF Readers (Adobe Reader and a number of Third Party readers) do not properly handle the "Tw" operator with TrueType fonts. Other font types work as expected. This operator, set by the $text->wordspace(n) method, is ignored for TTF and OTF fonts ($pdf->ttfont()) because Tw works only for inputs in the stream where words are separated by ASCII spaces (x20). TrueType fonts, on the other hand, uses an input list of glyph IDs (4 digit hex numbers). Thus, there are never any ASCII spaces to detect and adjust their widths. We have updated the TTF/OTF handling code to honor the Tw operator value and emulate its actions, even though a native PDF Reader does not. In order to match the effects of the Tw operator on other font types, only ASCII spaces (x20) in the original text strings are affected, and not other flavors of spaces. Finally, TextHS() and advancewidthHS() still do not handle charspace or wordspace settings (perhaps in the future). lib/PDF/Builder/Content/Text.pm When linking to a page via Markdown or HTML (URL #p-x-y), the default zoom was 1 (100%) when given just the x and y coordinates on a page. This has been changed to leave the zoom factor unchanged by default (unless, of course, you choose to specify a zoom amount). Also, the thickness (height) of the horizontal rule defaulted to 1pt, which was a bit heavy in appearance. It has been changed to default to 0.5pt. lib/PDF/Builder.pm GD image call was not working in some circumstances, due to image_gd() being called incorrectly. Reported and fixed by Hakon Hagland against PDF::API2 (#60). lib/PDF/Builder/Resource/Font/Postscript.pm, lib/PDF/Builder/Docs.pm, examples/021_psfonts, t/font-type1.t Update Type 1 font (PS font) handling to allow T1 fonts (.t1 filetype, variant of .afm/.pfm). Also some new font paths to search on. Per request #194 from Red Hat packager (@ppisar). ===== IMPORTANT NOTICE ===== lib/PDF/Builder.pm, lib/PDF/Builder/Docs.pm, lib/PDF/Builder/Resource/Font/Postscript.pm Adobe has announced an end to support for Type 1 (Postscript/T1) fonts in its products. The announcement wordings are a bit vague, sometimes referring to "all products" and other times just to "authoring software". Presumably, Adobe PDF Readers (as well as Readers supplied by other parties) will continue to display PDFs with Type 1 fonts for quite some time, although this is by no means absolutely certain. Note that this does NOT mean that PDF::Builder or other Third Party authoring tools may not continue to support Type 1 fonts. This termination by Adobe of support of a now old and obsolete font format does not affect the use of PDF::Builder for authoring PDFs, nor is it binding on other non-Adobe readers and authoring tools. However, using Adobe products for editing of PDFs with Type 1 fonts, and possibly of displaying them, may soon no longer be possible. At any rate, users may want to consider starting to move away from Type 1 font usage (psfont), and switch to TTF/OTF (ttfont) or even core fonts (corefont), as it is unknown how long Type 1 Reader support will continue. ============================ 3.025 2023-01-19 ===== many thanks to Amtivo Group for sponsoring this work! see INFO/SPONSORS for more information lib/PDF/Builder/Content/Text.pm, examples/README, examples/examples_output, examples/Column.pl (new), MANIFEST, tools/3_examples.pl Add column() function to Content::Text, to support markup (none, Markdown, and HTML) in arbitrary columns. Note that PDF::Table will also support column(), but only when using PDF::Builder. lib/PDF/Builder.pm, lib/PDF/Builder/FontManager.pm (new), examples/README, examples/examples_output, examples/FontManager.pl (new), MANIFEST, tools/3_examples.pl Add a Font Manager to be able to select a font simply by giving the "face" and whether bold and/or italics are to be used. The actual font setting (with font size) is still done with $text->font($font, $size), but instead of having to explicitly create (or reuse) a $font, that part is all handled for you. It does not depend on any OS-provided font manager libraries (such as Linux provides, but Windows does not). Except for the core fonts, your application has to specify the base font and the files to use for italic, bold, etc. ===== end of sponsored work lib/PDF/Builder.pm, lib/PDF/Builder/FontManager.pm Update "font path" in Builder, make use of it in Font Manager. Note that at this time, only FontManager.pm makes use of the global font path settings (font_path() method). All other code, examples, and t tests give full paths to font files. At some point in the future, this may be changed, but the problem is that Linux and other non-Windows systems seem to store their font files all over the place, and even Windows is consistent only for TrueType files (it doesn't ship with any Type1 or other format fonts). Note that if you wish to modify the default font path list, you need to edit Builder.pm. lib/PDF/Builder/Content.pm, examples/042_links, examples/HarfBuzz.pl, examples/examples.output; MANIFEST, 040_annotation.pdf (new), examples/resources/HarfBuzz_example.pdf (removed) Remove the output of HarfBuzz Shaper's example from examples/resources (examples/resources/HarfBuzz_example.pdf), as this file is now available on the CTS website (Examples/PDF/Builder/HarfBuzz.pdf) and substitute a much smaller PDF, the output from 040_annotation, as the PDF sample for 042_links. This will cut the package size of PDF::Builder by about half! References to HarfBuzz_example.pdf as a sample to look at (should you not be able to run HarfBuzz.pl due to HarfBuzz::Shaper not being installed) have been updated to refer to the CTS website examples. README.md, LICENSE, lib/PDF/Builder.pm, examples/Column.pl Change copyright to 2023. META.json, META.yml Remove "provides" entries because 1) they do not seem to survive the packaging process, 2) no one seems to be able to state what this inform- ation is actually used for -- I see something vague about "search", and 3) how do I make "provides" entries that are better at doing whatever they're supposed to do better than what CPAN does by default? Also, there may be a META_ADD provides that I'm supposed to add to Makefile.PL, but again, documentation is quite scarce. I think I'll just ignore the whole "provides" thing until there's good documentation on it. README.md, Makefile.PL, META.json, META.yml, tools/optional_update.pl, t/00-all-usable.t, lib/PDF/Builder.pm, MANIFEST No longer automatically install Graphics::TIFF, Image::PNG::Libpng, and HarfBuzz::Shaper. This should lighten the installation and testing load on users, if they do not plan to use TIFF or PNG images, or do text shaping. Also list the new prerequisites for markup processing (HTML::TreeBuilder, Text::Markdown). optional_update.pl no longer needed and has been removed from the distribution. xt/author-critic.t, xt/author-pod-syntax.t, MANIFEST, tools/2_t-tests.pl Move a couple of specialty t tests from t/ to xt/ lib/PDF/Builder/Content/Hyphenate_basic.pm Add ability to split a word on Required Blanks (non-breaking spaces), as a last-ditch way to do basic hyphenation. Add ability to split a word to fit a given width (regardless of where the split ends up), as an even more last-ditch way. lib/PDF/Builder.pm Per PDF::API2 change, allow 'Times' as an alias for core font 'Times-Roman'. This was also done for 'corefont()', as well as the original 'font()'. A warning is given if Times is used. Also, change 'die' on errors to 'croak'. INFO/RoadMap, examples/020_corefonts Add discussion of /StructTreeRoot, remove Bank Gothic examples from core fonts (it appears to be just a partial alias for some other sans-serif font). LICENSE remove superfluous "59" from FSF address in license. From PDF::API2 #59. lib/PDF/Builder.pm open_page() clarify that default index is last page. lib/PDF/Builder/ViewerPreferences.pm Fix glitch in $pdf->viewer_preferences() for non-full-screen-page-mode. From PDF::API2 #50. lib/PDF/Builder.pm Fix page mode "SinglePage" unsupported. From PDF::API2 #49. lib/PDF/Builder/Page.pm Add documentation reminding users of rotation problems when using a crop box or other clipping. From PDF::API2 #58. lib/PDF/Builder.pm Add checks to page() method to see if the application is attempting to add a new page number that is too negative (more than one before the existing first page) or too positive (beyond the existing last page). The index value (page number) is clamped to be within possible values, with a warning. Ref: #190. lib/PDF/Builder/Annotation-NamedDestination-Outline.pm, lib/PDF/Builder.pm, t/named-destinations.t, t/042_links Remove new PDF::API2-style location+args interfaces, as I don't like the way they work, and that they are not backwards compatible with the old methods. Unfortunately, this may break any application changed (or recently written) to use the new PDF::API2 2.043 interfaces. If the new location+args list notation were to be used, only if the number of args was even could this be detected. An odd number of args, plus the location string, would be indistinguishable from a hash list, one of which may follow (as options) the location+args list. Ref: #190. lib/PDF/Builder/Resource/CIDFont/TrueType/FontFile.pm Typo fixed. 3.024 2022-09-12 lib/PDF/Builder/Resource/CIDFont/TrueType/FontFile.pm "loca" table in TTF is optional, so to fix PDFAPI2#47, return from subsetByCId() method early if no such table. According to PDFAPI2#37, it may be necessary to instruct ttfont() to NOT subset the font. Also, it appears that 'glyf' table may be missing in some fonts, so add check. Doesn't blow up any more, but problem #47 persists even with this fix. t/info.t (new), t/version.t (new), MANIFEST, tools/2_t-tests.pl New t-tests per PDF::API2. All "options" whose name begins with a dash (hyphen) "-" may now be given without a dash. E.g., "-translate => [30,25]" may now be given as "translate => [30,25]", or "'translate' => [30,25]". This is in keeping with the new practices on PDF::API2. The old (dashed) names are still valid, although they may be deprecated in the future. lib/PDF/Builder/Content.pm advancewidth() adds alias text_width(), per PDF::API2 changes. lib/PDF/Builder/Content.pm Fix problems in position() and textpos() methods reported by J Vromans, where the returned X coordinate was incorrect after being set twice. lib/PDF/Builder.pm New interfaces added for metadata query and set. INFO/RoadMap Add thoughts on an Environments package lib/PDF/Builder.pm, INFO/KNOWN_INCOMPAT Various changes to keep compatibility with latest PDF::API2, although not all old methods are deprecated. Some methods are added, some are renamed (alternate names added), and some may have minor changes or extended functionality. See KNOWN_INCOMPAT for a description of these minor differences. lib/PDF/Builder.pm, lib/PDF/Builder/ViewerPreferences.pm (new), MANIFEST Per PDF::API2 change, split up function of $pdf->preferences into several easier-to-use methods: page_mode(), page_layout(), viewer_preferences(), open_action(). lib/PDF/Builder/NamedDestination-Annotation.pm, t/named-destinations.t (new), MANIFEST, tools/2_t-tests.pl, examples/042_links Minor cleanup plus locations may now be given without leading dashes. 'link' is now alias for 'goto', 'file' is now alias for 'launch', 'url' is now alias for 'uri', and 'pdf_file' and 'pdfile' are now aliases for 'pdf' method names. lib/PDF/Builder/Dict.pm Fix doubled $class (per PDF::API2 fix). INFO/old/.travis.yml.HOLD Remove per PDF::API2 removal of .travis.yml lib/PDF/Builder/Content.pm For linejoin()/line_join() and linecap()/line_cap(), allow alpha strings ("miter" or "m", etc.) in addition to numeric values (0, etc.). For PDF::API2 compatibility, many alternate method names exist now, such as line_join() in addition to linejoin(). lib/PDF/Builder/Resource/XObject/Form/BarCode.pm Some minor fixes to improve spacing between bars and labels when both -lmzn and -fnsz are set and the font size is larger than -lmzn. Per PDF::API2 change. The barcode() convenience function has not been implemented. lib/PDF/Builder.pm, t/gif.t, t/jpg.t, t/png.t Add convenience image() method to simplify use of image_jpeg(), image_tiff(), image_pnm(), image_png(), image_gif(), and image_gd(). This is for PDF::API2 compatibility, and the original methods are unchanged. lib/PDF/Builder.pm, t/font-ttf.t, font-type1.t Add convenience font() method to combine corefont(), ttfont(), psfont(), and bdfont(). This is for PDF::API2 compatibility, and the original methods are unchanged. Font search path changes: add font_path() and set_font_path() for base search paths for fonts. Rename addFontDirs() to add_to_font_path() (keeping the old name around). Note that, unlike corefont(), font() requires the exact name of a standard core font. Kerning defaults to "on" when using font(), unlike other font methods. lib/PDF/Builder/Page.pm, lib/PDF/Builder.pm Deprecate unneeded update() method. Per PDF::API2 changes. lib/PDF/Builder.pm Rename method end() to close(). close should be used for new work. lib/PDF/Builder.pm, t/deprecations.t, t/pdf.t, t/rt67767.t Rename method open_scalar() to from_string(). from_string() should be used for new work. This is for compatibility with PDF::API2 changes renaming open_scalar() to from_string(). Although open_scalar() should still be supported for some time, it is possible that it may be deprecated and removed in the future. lib/PDF/Builder.pm Permit the save(filename) method to be used as an alias for saveas(filename). This is for compatibility with PDF::API2 changes combining save() and saveas(). Note that this is NOT good interface design, to use 'save' for both purposes. lib/PDF/Builder.pm, lib/PDF/Builder/Lite.pm, t/annotate.t, t/barcode.t, t/bbox.t, t/circular-references.t, t/content.t, t/cs-webcolor.t, t/deprecations.t, t/extgstate.t, t/gd.t, t/gif.t, t/jpg.t, t/outlines.t, t/pdf.t, t/png.t, t/pnm.t, t/rt120450.t, t/rt67767.t, t/69503.t, t/text.t, t/tiff.t, t/viewer-preferences.t, examples/011_open_update, t/resources/test-rgba.png (new), MANIFEST pdf->stringify() renamed to pdf->to_string() (original still available). Also catch up on some new t-tests from API2. lib/PDF/Builder/Basic/PDF/File-Objind.pm Per RT131657 PDF::API2 fix, Suppress recursion warnings while releasing (destroying) PDF indirect objects, which can be highly-interconnected (reported by Leon Winter). lib/PDF/Builder.pm Revise RT41971 fix per PDF::API2 change for outlines (no functional change) lib/PDF/Resource/Font/SynFont.pm Code cleanup per PDF::API2. This includes a number of renamed options (old ones are still supported) and changed behavior for 'bold' if coming through alternate name synthetic_font(). Read the documentation for synfont/synthetic_font to ensure that you won't be tripped up by any changes, or differences between the two. lib/PDF/Builder.pm per PDF::API2 fix, messages if fail to open input PDF CONTRIBUTING minor update docs/buildDoc.pl update to better handle non-PDF::Builder doc builds Makefile.PL, META.json, META.yml, README.md Perl 5.24 is the earliest supported version. README.md add manual build section t/tiff.t add exclude_version() function to exclude GhostScript or ImageMagick from all or selected uses, if your installed version falls with a range of excluded version numbers. This is to fix a problem where certain GhostScript versions were built with a bad library. Currently, the bad builds are believed to be limited to GhostScript 9.56.0 and 9.56.1. If you have this version, two of the tests in tiff.t (13 and 16, lzw+horizontal predictor, not converted to flate) will be skipped with "GhostScript not found". META.json, META.yml, MANIFEST add "provides" entry to make package sites happier. INFO/RoadMap add comments on PCF-format bitmapped fonts, and possible MathJax-based eqn support. INFO/LICENSE, MANIFEST License moved up to top level, to make package sites happier. examples/HarfBuzz.pl, examples/resources/HarfBuzz_example.pdf Add 'fj' and 'ij' ligatures, although Times doesn't appear to include them. examples/020_textrise add baselines and additional examples lib/PDF/Builder/Docs.pm, examples/HarfBuzz.pl Adobe Acrobat DC has changed its installed fonts location, so several non-Latin entries had to be updated. lib/PDF/Builder/Resource/CIDFont.pm Per PDF::API2 code style changes and uninitialized variable fix. INFO/Changes_2021, MANIFEST, README.md, lib/PDF/Builder.pm, INFO/LICENSE 2022 copyright. lib/PDF/Builder/Annotation.pm, t/annotate.t, examples/040_annotation, examples/041_annot_fileattach, examples/042_links Annotations revert to "no border" [#176] to match up with PDF::API2 behavior. lib/PDF/Builder.pm per #171, allow blank or prefix-only page label (on Reader's thumb slider) with -style => 'nocounter'. lib/PDF/Builder/Basic/PDF/File.pm Per RT 136648, PDF::API2 fix when writing xref streams. Note that while there is no longer an error message (fixed some time ago in PDF::Builder), there is still some new material (an XRef stream) added at the end of the PDF, at each save (for both PDF::API2 and PDF::Builder). Something still needs to be done about this, some time later. lib/PDF/Builder/Resource/XObject/Image/GD-GIF-JPEG-PNG-PNM-TIFF.pm Add -name option to name the image object if desired. In sync with PDF::API2, add -compress option for PNM. lib/PDF/Builder/Resource/XObject/Image/GIF-PNM.pm minor changes to sync with PDF::API2 changes. examples/HarfBuzz.pl, examples/resources/HarfBuzz_example.pdf show a better Chinese (CJK) example in vertical mode, which demonstrates rotation of punctuation such as ( ). Continuation of #144. INFO/RoadMap comments on page labeling (slider thumb) enhancements per #171, including possibly integrating with header() and footer() calls that place a page number on the paper, and any outline/bookmarks, so that they all give a consistent page label (number). optional_update.pl, MANIFEST, README.md optional_update moved to tools/, otherwise it was being placed in the PDF/ directory by the installer. Note that you should be in your PDF::Builder root (parent of tools/) and run tools/optional_update.pl. (see INFO/Changes_2021 for earlier changes) (see INFO/Changes-ver_2 for changes to PDF::API2 up through 2.034) PDF-Builder-3.026/CONTRIBUTING.md0000644000000000000000000000712214534467462014471 0ustar rootroot# Contributing to the development of PDF::Builder **Working on your first Pull Request?** You can learn how from this *free* series [How to Contribute to an Open Source Project on GitHub](https://kcd.im/pull-request) We would appreciate the community around us chipping in with code, tests, documentation, and even just bug reports and feature requests. It's better knowing what users of PDF::Builder want and need, than for us to guess. It's not good to spend a lot of time working on something that no one is interested in! You can contribute to the discussion by posting bug reports, feature requests, observations, etc. to the [GitHub issues area](https://github.com/PhilterPaper/Perl-PDF-Builder/issues?q=is%3Aissue+sort%3Aupdated-desc "issues") (please tag new threads accordingly, using ["Labels"], if possible). Please also read INFO/RoadMap to get an idea of where we would like for PDF::Builder to be heading, and may give you an idea of where you could usefully contribute. Don't be afraid to discuss or propose taking PDF::Builder off in a direction not in the RoadMap -- the worst that could happen is that we say, "thanks, but no thanks." First of all, please read the section "Sofware Development Kit" under PDF::Builder::Docs. This will be of interest if you want to do anything beyond simply installing PDF::Builder as a prerequisite for some other package. You can also get to this via "SOME SPECIAL NOTES" section of the root documentation (PDF::Builder). You should create all the HTML documentation by running "docs/buildDoc.pl --all" and read it before starting any serious work. For code changes, a GitHub pull request, a formal patch file (e.g., "diff"), or even a replacement file or manual patch will do, so long as it's clear where it goes and what it does. If the volume of such work becomes excessive (i.e., a burden to us), we reserve the right to limit the ways that code changes can be submitted. At this point, the volume is low enough that almost anything can be handled. Please DO NOT send us code changes "out of the blue" (without prior discussion), unless they are very small, so that you're not out a lot of effort if we decline the offer. ## Do NOT... Do NOT under ANY circumstances open a PR (Pull Request) to **report a _bug_.** It is a waste of both _your_ and _our_ time and effort. Instead, simply open a regular ticket (_issue_) in GitHub, and attach a Perl (.pl) program that illustrates the problem, if possible. If you believe that you have a program patch (i.e., a permanent change to the code), and offer to share it as a PR, we may give the go-ahead. Unsolicited PRs may be closed without further action. Please do not start on a massive project (especially, new function), without discussing it with us first (via email or one of the discussion areas). This will save you the disappointment of seeing your hard work rejected because it doesn't fit in with what's going on with the rest of the PDF::Builder project. You are free to try contributing anything you want, or even to fork the project if you don't like the direction it's taking (that's how PDF::Builder split off from PDF::API2). Keeping in touch and coordinating with us ensures that your work won't be wasted. If you have something dependent on PDF::Builder functionality, but it doesn't fit our roadmap for core functionality, we may suggest that you release it as a separate package on CPAN (dependent on PDF::Builder), or as a new sub-package under PDF::Builder (e.g., like PDF::API2::Ladder), under either our ownership or yours. Good luck, and best wishes using and helping with PDF::Builder! May, 2023 PDF-Builder-3.026/LICENSE0000644000000000000000000006242614354672251013247 0ustar rootrootThis software is Copyright (c) 2017-2023 by Phil M. Perry. Previous copyrights are held by Steve Simms, Alfred Reibenschuh, et al. Note that some files within this software are under DIFFERENT licenses (than LGPL 2.1). These include (but are not necessarily limited to) PDF::Builder::Matrix (same license as Perl itself), and PDF::Builder::Basic::PDF files (except for the Filters and Literal.pm), which are now under the MIT License (formerly under the Perl Artistic License, which is still permitted). If not otherwise stated in such a file, the overall license is LGPL 2.1, and you may redistribute and/or modify this software under the terms of the indicated license. For LGPL, you are permitted to redistribute and/or modify the software under a version higher than 2.1, at your option). This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. This is free software, licensed under: The GNU Lesser General Public License, Version 2.1, February 1999 ============================================================================= == Original LGPL 2.1 license text == ============================================================================= The GNU Lesser General Public License (LGPL) Version 2.1, February 1999 (The master copy of this license lives on the GNU website.) Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS PDF-Builder-3.026/contrib/0000755000000000000000000000000014534671356013675 5ustar rootrootPDF-Builder-3.026/contrib/combine_pdfs.pl0000644000000000000000000000146314534467444016667 0ustar rootroot#!/usr/bin/perl use strict; use warnings; our $VERSION = '3.026'; # VERSION our $LAST_UPDATE = '2.029'; # manually update whenever code is changed use PDF::Builder; unless (scalar @ARGV >= 3) { print qq{Usage: $0 ... Combine all pages from the input PDF files into a single output PDF file. }; exit; } my $output_file = pop(@ARGV); my $output_pdf = PDF::Builder->new(); foreach my $input_file (@ARGV) { print "Loading $input_file:"; my $input_pdf = PDF::Builder->open($input_file); foreach my $page_number (1 .. $input_pdf->pages()) { print " $page_number,"; $output_pdf->import_page($input_pdf, $page_number); } $input_pdf->close(); print " Done.\n\n"; } print "Writing $output_file\n"; $output_pdf->saveas($output_file); PDF-Builder-3.026/contrib/pdf-optimize.pl0000644000000000000000000000434114534467444016644 0ustar rootroot#!/usr/local/bin/perl use strict; use warnings; our $VERSION = '3.026'; # VERSION our $LAST_UPDATE = '3.016'; # manually update whenever code is changed use PDF::Builder::Basic::PDF::File; use PDF::Builder::Basic::PDF::Utils; use PDF::Builder; use Scalar::Util qw(blessed); sub walk_obj { my ($objs, $spdf, $tpdf, $obj, @keys) = @_; my $tobj; if (ref($obj) =~ /Objind$/) { $obj->realise(); } return ($objs->{scalar $obj}) if defined $objs->{scalar $obj}; die "object already copied" if $obj->{' copied'}; $tobj = $obj->copy($spdf); $obj->{' copied'} = 1; $tpdf->new_obj($tobj) if $obj->is_obj($spdf) && !$tobj->is_obj($tpdf); $objs->{scalar $obj} = $tobj; if (ref($obj) =~ /Array$/ || (blessed($obj) && $obj->isa('PDF::Builder::Basic::PDF::Array'))) { $tobj->{' val'} = []; foreach my $k ($obj->elements()) { $k->realise() if ref($k) =~ /Objind$/; $tobj->add_elements(walk_obj($objs, $spdf, $tpdf, $k)); } } elsif (ref($obj) =~ /Dict$/ || (blessed($obj) && $obj->isa('PDF::Builder::Basic::PDF::Dict'))) { @keys = keys(%{$tobj}) if scalar @keys < 1; foreach my $k (@keys) { next if $k =~ /^ /; next unless defined($obj->{$k}); $tobj->{$k} = walk_obj($objs, $spdf, $tpdf, $obj->{$k}); } if ($obj->{' stream'}) { if ($tobj->{'Filter'}) { $tobj->{' nofilt'} = 1; } else { delete $tobj->{' nofilt'}; $tobj->{'Filter'} = PDFArray(PDFName('FlateDecode')); } $tobj->{' stream'} = $obj->{' stream'}; } } else { $obj->realise(); return walk_obj($objs, $spdf, $tpdf, $obj); } delete $tobj->{' streamloc'}; delete $tobj->{' streamsrc'}; return $tobj; } if (scalar @ARGV < 2) { print "usage: $0 infile outfile\n"; exit(1); } my $spdf = PDF::Builder::Basic::PDF::File->open($ARGV[0]); my $tpdf = PDF::Builder::Basic::PDF::File->_new(); my $mycache = {}; $tpdf->{'Root'} = walk_obj($mycache, $spdf, $tpdf, $spdf->{'Root'}); $tpdf->{'Info'} = walk_obj($mycache, $spdf, $tpdf, $spdf->{'Info'}) if $spdf->{'Info'}; $tpdf->out_file($ARGV[1]); PDF-Builder-3.026/contrib/text2pdf.pl0000644000000000000000000006622214534467444016003 0ustar rootroot#!/usr/bin/perl # # RCS Comments. # $Author: hank $ # $Date: 2013/08/14 20:26:56 $ # $RCSfile: text2pdf.pl,v $ # # Revision: by Phil M Perry September 2023 # change textlead() reference to textleading() # Revision: by Phil M Perry June 2018 # make Perl::Critic happy over handling of bareword filehandles and loop # iterator declarations # Revision: by Phil M Perry March 2017 # cleanup: remove deprecated and commented-out old stuff # diagnostic/debug print statements under "debug" control --debug # restructured command line parameter handling, and input is now positional # with multiple file names or globs on command line # add named paper size --PGpaper=name # allow dimensions to have units (default units unchanged) # .PAGE=minsize; if more space left, don't paginate # --tabs="t1 t2 t3...tn" default 9 17 25 33... tab stops # wrap lines that don't fit, so they don't just run off right side # page numbering, file name each page # consider --duplex to swap left and right on even numbered pages # --header='l|c|r' and --footer='l|c|r' with &f = basename file, # &F = full file, &p = page number, etc. # right-justified text (have left and centered) # # $Revision: 1.6 $ hankivy # $Source: /home/hank/bin/RCS/text2pdf.pl,v $ # $Header: /home/hank/bin/RCS/text2pdf.pl,v 1.6 2013/08/14 20:26:56 hank Exp $ # $Id: text2pdf.pl,v 1.6 2013/08/14 20:26:56 hank Exp $ # $Log: text2pdf.pl,v $ # Revision 1.6 2013/08/14 20:26:56 hank # Improved documentation. # Removed, or commented out deprecated code. # # Revision 1.5 2013/07/20 02:30:41 hank # Add font name, font size, as parameters to the command line. # Add tests to validate the new parameters. # # Revision 1.4 2013/06/11 03:42:28 hank # Add debug switch for status messages. # # Revision 1.3 2013/06/10 23:05:28 hank # Added centering. # # Revision 1.2 2013/06/08 03:54:23 hank # Add changing fonts, sizes, and pictures. # # Revision 1.1 2013/05/30 20:31:54 hank # Initial revision # # # # txt2pdf.pl from mcollins@fcnetwork.com # # MC's Q&D text to PDF converter. # # FYI, # # I wrote a simple text file to PDF converter that uses PDF::Builder::Lite. # It isn't full-featured by any stretch but it does illustrate one of the # many uses of this cool module. I'm submitting it here for your perusal. # If you think of any useful things to add to it please let me know. # Fredo, please feel free to include it in the contributed items if you # would like. # # Thanks! (Sorry about the long comments that wrap around to the next # line...) # # -MC # use strict; use warnings; our $VERSION = '3.026'; # VERSION our $LAST_UPDATE = '3.021'; # manually update whenever code is changed use PDF::Builder; use PDF::Builder::Util; use Getopt::Long; use File::Basename; use diagnostics; $|++; # turn off buffering on output. # variables from the command line (set by flags) my $CLdestpath; # destination path my $DEFdestpath = './'; # default = current working directory my $CLleft; # left margin/starting point my $DEFleft = 72; # default = 72pt from page left my $CLright; # right margin my $DEFright = 72; # default = 72pt from page right my $CLtop; # top margin/starting point my $DEFtop = 36; # default = 36pt from page top my $CLbottom; # bottom margin/starting point my $DEFbottom = 36; # default = 36pt from page bottom my $CLPGpaper; # media (paper) by name # no default (so can set H and W) my $CLPGwidth; # Page width in inches my $DEFPGwidth = 612; # default = US letter 8.5in my $CLPGheight; # Page height in inches my $DEFPGheight = 792; # default = US letter 11in my $CLlandscape; # landscape cmd line flag my $CLportrait; # portrait cmd line flag my $CLFontType; # Font Type, C=Core, TT=TrueType my $DEFFontType = 'C'; # default = core fonts my $CLFontName; # cmd line fontname my $DEFFontName = 'Courier'; # default font Courier (fixed pitch) my $CLfontsize; # font size my $DEFfontsize = 7; # default = 7pt my $CLspacing; # text spacing ($pdf->textleading) # default = 115% of font size my $CLtabs; # tab expansion definition my $DEFtabs = '9 17'; # default = at 9, 17, 25, 33,... my $pdf; # main PDF document object my $page; # current page being processed my $text; # current page's text object my $font; # current font being used my ($hdrftr, $contline); # some special fixed fonts my $pointscount; # how many points have been processed on this page. # Starts with zero at the top of the page. my $PGpaper; # media (paper) size by NAME my $PGheight; # Physical sheet height in points. my $PGwidth; # Physical sheet height in points. my ($left, $right, $top, $bottom); # margins in points my ($LineStart, $LineBottom); my ($gfx, $txt, $gfx_border); our ($pageNum,$filename); # other variables my @FILES; # list of input files, in case of glob my @INFILES; # command line list of files and globs my $destpath; # destination path my $outfile; # output path & file my $help; # Flag for displaying help my $FontTypeStr; # C means Core, TT means TrueType. my $FontNameStr; # font name my $fontsize; # font size my $spacing; # spacing my $CenterTextMode = 0; # Center the text. my @tabs; # any tab definitions my $debug = 0; # no debug prints by default if ($#ARGV < 0) { usage(); exit(1); } # NOTE: A point is 1/72 inch (Adobe/PostScript Big Point). # Other environments use other slightly different values. # any dimension may specify units (e.g., .5in), default units shown # get those cmd line args! my $opts_okay = GetOptions( 'h' => \$help, 'help' => \$help, # Can use -h or --help 'debug' => \$debug, # print out diagnostic info 'left=s' => \$CLleft, # Left Margin - points 'right=s' => \$CLright, # Right Margin - points 'top=s' => \$CLtop, # Top Margin - points 'bottom=s' => \$CLbottom, # Bottom Margin - points 'PGpaper=s' => \$CLPGpaper, # named media (paper) size 'PGwidth=s' => \$CLPGwidth, # Page Width - inches 'PGheight=s' => \$CLPGheight, # Page Height - inches 'fontname=s' => \$CLFontName, # font name 'fonttype=s' => \$CLFontType, # font type, C=Core, TT=TrueType 'fontsize=s' => \$CLfontsize, # Nominal height of characters - points 'spacing=s' => \$CLspacing, # Spacing between successive lines - points 'l' => \$CLlandscape, # orientation 'p' => \$CLportrait, # default orientation 'tabs=s' => \$CLtabs, # tabs layout 'dir=s' => \$CLdestpath ); # positional parameters on command line: # currently only one or more input names should be left if ( 0 == @ARGV ) { warn "Expecting at least one positional parameter on command line: input file name or pattern\n"; @INFILES = (); usage(); exit(1); } else { @INFILES = @ARGV; } # if help, then display usage if ( !$opts_okay || $help ) { usage(); exit(0); } # convert explicit units to desired units, or set defaults if ( defined($CLleft) ) { $left = str2dim($CLleft, 'f[0,*)', 'pt'); } else { $left = $DEFleft; } if ( defined($CLright) ) { $right = str2dim($CLright, 'f[0,*)', 'pt'); } else { $right = $DEFright; } if ( defined($CLtop) ) { $top = str2dim($CLtop, 'f[0,*)', 'pt'); } else { $top = $DEFtop; } if ( defined($CLbottom) ) { $bottom = str2dim($CLbottom, 'f[0,*)', 'pt'); } else { $bottom = $DEFbottom; } if ( defined($CLPGwidth) ) { $PGwidth = str2dim($CLPGwidth, 'f(0,*)', 'in'); } else { $PGwidth = $DEFPGwidth; } if ( defined($CLPGheight) ) { $PGheight = str2dim($CLPGheight, 'f(0,*)', 'in'); } else { $PGheight = $DEFPGheight; } if ( defined($CLfontsize) ) { $fontsize = str2dim($CLfontsize, 'f[3,100)', 'pt'); } else { $fontsize = $DEFfontsize; } if ( defined($CLspacing) ) { $spacing = str2dim($CLspacing, 'f[4,115)', 'pt'); } else { $spacing = $fontsize * 1.15; } if ( !defined($CLFontType) ) { $CLFontType = 'C'; } if ( defined($CLFontName) ) { $FontNameStr = $CLFontName; } else { $FontNameStr = $DEFFontName; } # CLPGpaper may remain empty if user wants to give height and width if ( defined($CLPGpaper) ) { $PGpaper = $CLPGpaper; } if ( !defined($CLdestpath) ) { $destpath = $DEFdestpath; } if ( !defined($CLlandscape) ) { $CLportrait = 1; } # set default orientation if ( defined($CLtabs) ) { @tabs = tabDef($CLtabs); } else { @tabs = tabDef($DEFtabs); } # Check for filename vs. filespec(glob) * or ? # build up final @FILES from @INFILES @FILES = (); foreach my $infile (@INFILES) { if ( $infile =~ m/\*|\?/ ) { # it's a glob that may expand to 1 or more files my @globList = (); print "Found glob spec '$infile', checking...\n" if $debug; @globList = glob($infile); if ( ! @globList ) { warn "File pattern '$infile' matches no files!\n"; } if ($debug) { print "Found file"; if ( $#globList > 0 ) { print "s"; } # Be nice, use plural print ":\n"; foreach ( @globList ) { print "$_\n"; } } push( @FILES, @globList ); } else { # it's a filename that must exist if ( ! -f $infile ) { die "Could not locate file '$infile', exiting...\n"; } push( @FILES, $infile ); # single file name } } # loop through command line list of files and patterns # remove duplicates my %seen=(); # from StackOverflow 7651 @FILES = grep { ! $seen{$_} ++ } @FILES; # check for no files given (found) if (0 == @FILES) { die "Please specify at least one file name or glob on command line\n"; } # Validate remaining cmd line args if ($CLlandscape && $CLportrait) { die "ERROR: Had both portrait and landscape options on command line.\n"; } # gave media name to override any page width and height? # if named media not found, will return US Letter dimensions if ( defined($CLPGpaper) ) { my @PaperSize = page_size($PGpaper); $PGwidth = $PaperSize[2]; $PGheight = $PaperSize[3]; } # if landscape and height > width, rotate (swap height and width) if ( $CLlandscape ) { if ($PGheight > $PGwidth) { my $t = $PGheight; $PGheight = $PGwidth; $PGwidth = $t; } } # if portrait and height < width, rotate (swap height and width) if ( $CLportrait ) { if ($PGheight < $PGwidth) { my $t = $PGheight; $PGheight = $PGwidth; $PGwidth = $t; } } print "Page Width is $PGwidth.\n" if $debug; print "Page Height is $PGheight.\n" if $debug; ### Validate Left and Right margins. print "Left margin is $left.\n" if $debug; print "Right margin is $right.\n" if $debug; # The left and right margins need to leave some space to print. # Some space is arbitrarily set at 1/8 inch, or 9 points. die "ERROR: Left margin, right margin, and page width leave too little space to print.\n" if ( $PGwidth <= ($left +$right + 9)); ### Validate Top and Bottom margins. print "Top Margin is $top.\n" if $debug; print "Bottom Margin is $bottom.\n" if $debug; # The top and bottom margins need to leave some space to print. # Some space is arbitrarily set at 1/8 inch, or 9 points. die "ERROR: top margin, bottom margin, and page height leave too little space to print.\n" if ( $PGheight <= ($top +$bottom + 9)); my $PDFtop = $PGheight - $top; my $PDFbottom = $bottom; # Validate and set font type, font, font size, and spacing. if ($fontsize <= 3) { die "ERROR: Font size $fontsize on command line is less than 3.\n"; } if ($spacing < $fontsize) { die "ERROR: Line spacing $spacing on command line is less than font size.\n"; } if ($CLFontType eq "C" || $CLFontType eq "TT") { $FontTypeStr = $CLFontType; } else { die "ERROR: Font Type '$CLFontType' on command line is invalid.\n"; } # Set max, min spacing if ( $spacing > 720 ) { $spacing = 720; } # why would anyone want this much spacing? if ( $spacing < 1 ) { $spacing = 1; } # That's awfully crammed together... foreach my $file ( @FILES ) { print "Processing $file...\n"; # always output $pageNum = 0; $filename = $file; my ($name,$dir,$suf) = fileparse($file,qr/\.[^.]*/); # set output file name (always .pdf, remove .txt or .txt2pdf) if ( $suf =~ m/txt2pdf|txt/) { # replace .txt or .txt2pdf with .pdf $outfile = $destpath . $name . '.pdf'; } else { # just append .pdf to end of filename $outfile = $destpath . $name . $suf . '.pdf'; } $pdf = PDF::Builder->new(-file => $outfile); setfonts(); # Set the fonts. newpage(); # create first page in PDF document my $maxLineWidth = $PGwidth - $left - $right; # pts of line length print "Page Length data LineBottom $LineBottom - spacing $spacing - bottom $bottom \n" if $debug; my $minSpace; open (my $FILEIN, '<', "$file") or die "$file - $!\n"; ## no critic (RequireBriefOpen) while(<$FILEIN>) { # chomp is insufficient when dealing with EOL from different systems # this little regex will make things a bit easier s/(\r)|(\n)//g; if (m/^\.PAGE\s*=\s*([^;]+);/) { $minSpace = str2dim($1, 'f[0,*)', 'pt'); } else { $minSpace = 0; } # found explicit page break or ran out of space? if (m/\x0C/ || (m/^\.PAGE/ && $minSpace == 0) || (($LineBottom - $spacing - $bottom - $minSpace) < 0)) { FinishObjects(); newpage(); next if (m/\x0C/ || m/^\.PAGE/); # ignore anything else on line } my ($NewFontFound, $NewFont, $NewFontSizeFound, $NewFontSize, $NewFontSpacingFound, $NewFontSpacing, $NewFontTypeStrFound); # .FONT [= font_name] [LEFT|CENTER] SIZE = num SPACING = num [TYPE = C|TT] if (m/^\.FONT /) { $NewFontFound = 0; $NewFont = ''; $NewFontSizeFound = 0; $NewFontSize = 0; $NewFontSpacingFound = 0; $NewFontSpacing = 0; # Change Centering if asked. if (m/\sLEFT(\s|$)/) { $CenterTextMode = 0; } if (m/\sCENTER(\s|$)/) { $CenterTextMode = 1; } # Change the font. if (m/\.FONT\s*=\s*(\w+)(\W|$)/) { $NewFontFound = 1; $NewFont = $1; if (m/TYPE\s*\=\s*(\w+)(\W|$)/) { $NewFontTypeStrFound = 1; $FontTypeStr = $1; } } if (m/SIZE\s*=\s*(\d+)(\D|$)/) { $NewFontSizeFound = 1; $NewFontSize = $1; # default: pt } if (m/SIZE\s*=\s*'([^']+)'/) { $NewFontSizeFound = 1; $NewFontSize = str2dim($1, 'f(0,100)', 'pt'); } if (m/SIZE\s*=\s*"([^"]+)"/) { $NewFontSizeFound = 1; $NewFontSize = str2dim($1, 'f(0,100)', 'pt'); } if (m/SPACING\s*=\s*(\d+)(\D|$)/) { $NewFontSpacingFound = 1; $NewFontSpacing = $1; } if (m/SPACING\s*=\s*'([^']+)'/) { $NewFontSpacingFound = 1; $NewFontSpacing = str2dim($1, 'f(0,100)', 'pt'); } if (m/SPACING\s*=\s*"([^"]+)"/) { $NewFontSpacingFound = 1; $NewFontSpacing = str2dim($1, 'f(0,100)', 'pt'); } unless ($NewFontFound or $NewFontSizeFound or $NewFontSpacingFound) { warn "ERROR: No Font, Size, or Spacing given on .FONT line.\n"; warn "ERROR Line: $_\n"; } if ($NewFontFound) { $FontNameStr = $NewFont; setfonts(); } $fontsize = $NewFontSize if ($NewFontSizeFound); $spacing = $NewFontSpacing if ($NewFontSpacingFound); $txt->font($font,$fontsize); next; # .IMAGE FILE = image_filename HEIGHT = num WIDTH = num } elsif (m/^\.IMAGE /) { # Load a picture. The picture file name is all. my ($imageFileName, $ImageFileSuff, $imageObj) = (); my ($imageHeight, $imageWidth, $imageUpDown, $ImageLeftRight) = (); my $Debug_Image_Placement = 0; $imageFileName = ''; $ImageFileSuff = ''; $imageHeight = 0; $imageWidth = 0; if (m/FILE\s*=\s*(\S+)(\s|$)/) { $imageFileName = $1; } if (m/HEIGHT\s*=\s*(\d+)(\D|$)/) { $imageHeight = $1; } if (m/HEIGHT\s*=\s*'([^']+)'/) { $imageHeight = $1; } if (m/HEIGHT\s*=\s*"([^"]+)"/) { $imageHeight = $1; } if (m/WIDTH\s*=\s*(\d+)(\D|$)/) { $imageWidth = $1; } if (m/WIDTH\s*=\s*'([^']+)'/) { $imageWidth = $1; } if (m/WIDTH\s*=\s*"([^"]+)"/) { $imageWidth = $1; } $imageFileName =~ m/\.([^.]+)$/; $ImageFileSuff = $1 || ""; warn "ERROR: No image file name.\n" unless $imageFileName; warn "ERROR: No image width.\n" unless $imageWidth; warn "ERROR: No image height.\n" unless $imageHeight; warn "ERROR: No image file name suffix.\n" unless $ImageFileSuff; unless (-r $imageFileName && -s $_) { warn "ERROR: The file $imageFileName is either unreadable or empty.\n"; next; } if (($LineBottom - $imageHeight - $bottom) < 0) { # found page break - Not enough height for image. FinishObjects(); newpage(); } if ($ImageFileSuff =~ m/^jpg$|^jpeg$/i ) { $imageObj = $pdf->image_jpeg($imageFileName); } elsif ($ImageFileSuff =~ m/^tif$|^tiff$/i ) { $imageObj = $pdf->image_tiff($imageFileName); } elsif ($ImageFileSuff =~ m/^png$/i ) { $imageObj = $pdf->image_png($imageFileName); } elsif ($ImageFileSuff =~ m/^pnm$|^ppm$|^pgm$|^pbm$/i ) { $imageObj = $pdf->image_pnm($imageFileName); } else { warn "ERROR: The file $imageFileName is has an unsupported suffix.\n"; next; } $imageHeight = ${${$imageObj}{'Height'}}{'val'} unless ($imageHeight); $imageWidth = ${${$imageObj}{'Width'}}{'val'} unless ($imageWidth); $imageUpDown = $LineBottom - $imageHeight; $ImageLeftRight = int(($PGwidth -$imageWidth) / 2); if ($Debug_Image_Placement) { print "LineBottom $LineBottom \n"; print "imageHeight $imageHeight imageWidth $imageWidth \n"; print "imageUpDown $imageUpDown ImageLeftRight $ImageLeftRight \n"; } $gfx->image($imageObj, $ImageLeftRight, $imageUpDown, $imageWidth, $imageHeight ); $LineBottom -= $imageHeight; $pointscount += $imageHeight; next; # not .FONT or .IMAGE special processing } else { # Print the line in $_, after expanding tabs. if (@tabs) { my ($i, $j); for ($i=0; $i= $tabs[-1]) { $tabs[1+$#tabs] = $tabs[-1] + ($tabs[-1]-$tabs[-2]); } if (substr($_, $i, 1) eq "\x09") { # $i+1 is character column # find next tab position for ($j=0; $j<$#tabs; $j++) { if ($tabs[$j] > $i+1) { last; } } # jth tab entry is tab position to go to # (replace HT by tabs[j]-(i+1) spaces) $_ = substr($_, 0, $i) . (' ' x ($tabs[$j]-($i+1))) . substr($_, $i+1 ); } } } my $TextLineWidth = 0; my @overrides = (); # how much of line can fit at a time? $txt->font($font,$fontsize); my ($lineChunk, $char, $thisCont); my $continued = 0; # NEXT output line is a continuation if (!length($_)) { $_ = " "; } # empty lines still print # there are probably faster ways to do this, than # checking one character at a time, but in the spirit # of Quick'n'Dirty... while (length($_)) { $thisCont = $continued; $TextLineWidth = $txt->advancewidth($_, @overrides ); if ($TextLineWidth > $maxLineWidth) { # maybe start at TLW/mLW fraction of line, and go up or down by character until hit limit? $lineChunk = ''; $char = substr($_, 0, 1); $_ = substr($_, 1); while ($txt->advancewidth($lineChunk.$char, @overrides) <= $maxLineWidth) { $lineChunk .= $char; # prep for next loop $char = substr($_, 0, 1); $_ = substr($_, 1); } $_ = $char.$_; # restore $continued = 1; } else { $lineChunk = $_; $_ = ''; $continued = 0; } # mark a line as continued if ($thisCont) { #$txt->font($contline,$fontsize); if ($CenterTextMode <= 1) { $txt->textlabel($LineStart-1.7*$fontsize, $LineBottom-$spacing, $contline,$fontsize, chr(229)); } else { $txt->textlabel($LineStart+$maxLineWidth+.6*$fontsize, $LineBottom-$spacing, $contline,$fontsize, chr(229)); } #$txt->font($font,$fontsize); } if ($CenterTextMode == 1) { $txt->textlabel($LineStart+(int(($maxLineWidth - $TextLineWidth) /2 )), $LineBottom-$spacing,$font,$fontsize,$lineChunk); } else { $txt->textlabel($LineStart,$LineBottom-$spacing,$font,$fontsize,$lineChunk); } $LineBottom -= $spacing; $pointscount += $spacing; } } } # while(<$FILEIN>) close($FILEIN); FinishObjects(); $pdf->save(); $pdf->end(); } # foreach $file (@FILES) sub newpage { my ($Debug_newpage, $border_left, $border_bottom, $border_right, $border_top, $Draw_Border); my ($text, $TextLineWidth); our ($pageNum); $pageNum++; $Debug_newpage = 0; $Draw_Border = 0; $page = $pdf->page(); $page ->mediabox($PGwidth,$PGheight); $LineStart = $left; $LineBottom = $PGheight - $top; $pointscount = 0; $gfx=$page->gfx(); $txt=$page->text(); # Draw a border around the page. $border_left = int($left/2); $border_right = $PGwidth - int($right/2); $border_bottom = int($bottom/2); $border_top = $PGheight - int($top/2); if ($Debug_newpage) { warn "Debug newpage PGwidth $PGwidth PGheight $PGheight\n"; warn "Margins left $left right $right top $top bottom $bottom\n"; warn "Border left $border_left right $border_right top $border_top bottom $border_bottom\n"; } $gfx_border = $page->gfx(); if ( $Draw_Border ) { $gfx_border->strokecolor('black'); $gfx_border->move($border_left,$border_bottom); $gfx_border->line($border_left,$border_top); $gfx_border->line($border_right,$border_top); $gfx_border->line($border_right,$border_bottom); $gfx_border->close(); $gfx_border->stroke(); } setfonts(); $txt->font($hdrftr,6); # if only one of the top and bottom margins large enough, print $pageNum # header (if $top at least 20pt) $filename centered $text = "\x97 $pageNum \x97"; $TextLineWidth = $txt->advancewidth($text); if ($top >= 20 && $bottom < 20) { # top gets pageNum $txt->textlabel($left+(int(($PGwidth - $left - $right - $TextLineWidth) /2 )), $PGheight - $top + 8,$hdrftr,6,$text); } elsif ($bottom >= 20) { # bottom gets pageNum $txt->textlabel($left+(int(($PGwidth - $left - $right - $TextLineWidth) /2 )), $bottom - 14,$hdrftr,6,$text); } if ($top >= 20 && $bottom >= 20) { # top gets file $TextLineWidth = $txt->advancewidth($filename); $txt->textlabel($left+(int(($PGwidth - $left - $right - $TextLineWidth) /2 )), $PGheight - $top + 8,$hdrftr,6,$filename); } # body text font $txt->font($font,$fontsize); return; } # end of newpage() sub FinishObjects { $pdf->finishobjects($page,$gfx); return; } sub setfonts { if ($FontTypeStr eq "TT") { $font = $pdf->ttfont($FontNameStr, -encode => 'latin1'); } elsif ($FontTypeStr eq "C") { $font = $pdf->corefont($FontNameStr, -encode => 'latin1'); } else { die "ERROR: Incorrect Font Type string is $FontTypeStr.\n"; } # for headers and footers $hdrftr = $pdf->corefont("Helvetica-Bold", -encode => 'latin1'); # for continuation line $contline = $pdf->corefont("ZapfDingbats", -encode => 'latin1'); return; } # given a tab definition string such as '9 17', expand it into an array # 0 or more than 1 elements: 1 element not permitted sub tabDef { my ($string) = @_; my @tabs; $string =~ s/^\s+//; $string =~ s/\s+$//; @tabs = split /\s+/, $string; if (@tabs == 1) { die "Error: --tabs must have 0, or 2 or more elements\n"; } return @tabs; } sub usage { my $message = <<"END_OF_USAGE"; Options: ## values may be bare numbers (units are as described), or number with unit (mm, cm, in, pt, ppt, pc, dd, cc) ppt = printer's points 72.27/inch, dd = Didot points 67.5532/inch, cc = Ciceros 5.62943/inch -h, --help This help page --debug Print out internal data for diagnostic purposes --dir=pathname Specify destination pathname of the pdf file. --left=## Specify left margin in points. 72 points = 1 inch --right=## Specify right margin in points. 72 points = 1 inch --top=## Specify top margin in points. 36 points = .5 inch --bottom=## Specify bottom margin in points. 36 points = .5 inch --fontname=ss Specify the Fontname. Default is TimesBold. --fonttype=ss Specify the font type. C means Core. TT means TrueType. The default is C. --fontsize=## Specify font size, nominal height of characters (points). The default is 7. --spacing=## Specify spacing between lines (points). -l, -L Set doc to landscape, (wider than tall). Default is portrait. -p, -P Set doc to portrait, (taller than wide). This is the default. --PGpaper=name Specify the page dimensions by named paper (media) size, or --PGheight=## Specify the page height (inches). --PGwidth=## Specify the page width (inches). --tabs=ss Specify 0, or two or more tab stops (column numbers). The list will be automatically expanded as needed by the increment of the last two elements given. Forcing a form feed (new page). General form feed line: .PAGE [= minimum remaining space;] Note that semicolon required. .PAGE by itself always starts a new page. With a dimension, if the remaining vertical space is less than this (default unit: pt points), a new page will be started. A Form Feed character (0x0C) may be used instead of .PAGE. Any other text on the line with the form feed or .PAGE will be ignored. Changing fonts in the text file. General Font change line: .FONT [= font_name] [LEFT|CENTER] SIZE = ### SPACING = ### [TYPE = C|TT] All keywords and values are case sensitive. The keyword .FONT starts with the first character in the line. The "= font_name" must immediately follow the FONT keyword. It is optional. LEFT or CENTER are optional, and may be in any order. LEFT means left-justify the text. CENTER means center-justify the text. The SIZE parameter is the font size for the text (points). It may be an integer or number and unit in single ' or double " quotes. The SPACING paramter sets the space (leading) between lines (points). It may be an integer or number and unit in single ' or double " quotes. SIZE=8 SPACING=16 is like double line spacing. The TYPE keyword is for choosing a Core font, or True Type font. The TYPE keyword is ignored unless a "= font_name" is given. Using bold, italics, or going back to normal is done by changing the font name. There is no bold, or italics flag. Any extra text on the font change line is ignored. Inserting an image in the text file. General Image insertion line: .IMAGE FILE = image_filename HEIGHT = num WIDTH = num Errors in the image insertion line are written to the error output, and the line is ignored. The suffix of the image_filename is used to determine the image type. The suffixes jp[e]g, tif[f], png, pnm, ppm, pgm, and pbm are supported. The HEIGHT and WIDTH are in points, or 'number unit' or "number unit", and optional. The default values are the height and width of the image in pixels. The defaults are most useful if the images are at 72 pixels per inch. The images are always printed, center justified. Special thanks to Michael Collins for getting me started. Special thanks to Alfred Reibenschuh for such a cool Perl module! Also, many thanks to the PDF::API2 community for such great ideas. END_OF_USAGE print "\nUsage:\n\n"; print $0, " "; print "\[options\] \...\n"; print $message; return; } __END__ PDF-Builder-3.026/contrib/pdf-deoptimize.pl0000644000000000000000000000533714534467444017163 0ustar rootroot#!/usr/bin/perl use strict; use warnings; our $VERSION = '3.026'; # VERSION our $LAST_UPDATE = '3.016'; # manually update whenever code is changed use PDF::Builder::Basic::PDF::File; use PDF::Builder::Basic::PDF::Utils; use PDF::Builder; use Compress::Zlib; use Scalar::Util qw(blessed); sub walk_obj { my ($objs, $spdf, $tpdf, $obj, @keys) = @_; my $tobj; if(ref($obj) =~ /Objind$/) { $obj->realise(); } return ($objs->{scalar $obj}) if defined $objs->{scalar $obj}; die "object already copied" if $obj->{' copied'}; $tobj=$obj->copy($spdf); $obj->{' copied'} = 1; $tpdf->new_obj($tobj) if $obj->is_obj($spdf) && !$tobj->is_obj($tpdf); $objs->{scalar $obj}=$tobj; if (ref($obj) =~ /Array$/ || (blessed($obj) && $obj->isa('PDF::Builder::Basic::PDF::Array'))) { $tobj->{' val'}=[]; foreach my $k ($obj->elements()) { $k->realise if ref($k) =~ /Objind$/; $tobj->add_elements(walk_obj($objs, $spdf, $tpdf, $k)); } } elsif (ref($obj) =~ /Dict$/ || (blessed($obj) && $obj->isa('PDF::Builder::Basic::PDF::Dict'))) { @keys = keys(%{$tobj}) if scalar @keys <1; foreach my $k (@keys) { next if $k=~/^ /; next unless defined($obj->{$k}); $tobj->{$k} =walk_obj($objs, $spdf, $tpdf, $obj->{$k}); } if ($obj->{' stream'}) { if ($tobj->{Filter} && !$tobj->{DecodeParms}) { my $f = $tobj->{'Filter'}; $f = PDFArray($f) unless ref($f )=~ /Array/; if (scalar($f->elements()) == 1) { my ($t) = $f->elements(); if ($t->val() eq 'FlateDecode') { $tobj->{' stream'} = uncompress($obj->{' stream'}); delete $tobj->{'Filter'}; $tobj->{'Length'} = PDFNum(length($tobj->{' stream'})); } else { $tobj->{' stream'} = $obj->{' stream'}; } } else { $tobj->{' stream'} = $obj->{' stream'}; } $tobj->{' nofilt'} = 1; } else { $tobj->{' stream'} = $obj->{' stream'}; } } } delete $tobj->{' streamloc'}; delete $tobj->{' streamsrc'}; return($tobj); } if(scalar @ARGV<2) { print "usage: $0 infile outfile\n"; exit(1); } my $spdf = PDF::Builder::Basic::PDF::File->open($ARGV[0]); my $tpdf = PDF::Builder::Basic::PDF::File->_new(); my $mycache = {}; $tpdf->{'Root'} = walk_obj($mycache, $spdf, $tpdf, $spdf->{'Root'}); $tpdf->{'Info'} = walk_obj($mycache, $spdf, $tpdf, $spdf->{'Info'}) if $spdf->{'Info'}; $tpdf->out_file($ARGV[1]); PDF-Builder-3.026/contrib/pdf-debug.pl0000644000000000000000000002025514534467444016074 0ustar rootroot#!/usr/bin/perl use strict; use warnings; use PDF::Builder::Basic::PDF::File; our $VERSION = '3.026'; # VERSION our $LAST_UPDATE = '3.010'; # manually update whenever code is changed my $file = shift(@ARGV); unless ($file) { print "Usage: $0 \n\nDisplays information about a PDF file.\n"; exit; } my $pdf = PDF::Builder::Basic::PDF::File->open($file) or die "Unable to open $file: $!"; my $command = shift(@ARGV); unless ($command) { print "PDF Version: " . $pdf->{' version'} . "\n"; print "XRef Table: " . $pdf->{' xref_position'} . "\n"; print "Info: " . _obj_reference($pdf->{'Info'}) . "\n" if $pdf->{'Info'}; print "Root: " . _obj_reference($pdf->{'Root'}) . "\n" if $pdf->{'Root'}; print "\n"; print "To view an object:\n"; print "$0 obj [generation]\n"; print "\n"; print "To view a cross-reference dictionary (with optional offset in bytes):\n"; print "$0 xref [offset]\n"; print "\n"; } elsif ($command eq 'xref') { my $location = shift(@ARGV); $location = $pdf->{' xref_position'} unless defined $location; my $object = $pdf->readxrtr($location); print "XRef at $location\n"; print '--------' . ('-' x length($location)) . "\n"; _print_obj($object); } elsif ($command eq 'obj') { my $id = shift(@ARGV); die "Missing required object number" unless $id and $id =~ /^[0-9]+$/; my $generation = shift(@ARGV) || 0; my $location = $pdf->locate_obj($id, $generation); my $object = $pdf->read_objnum($id, $generation); print "Object $id"; unless (ref($location)) { print " (file position $location)\n"; } else { my ($obj_num, $obj_idx) = @$location; print " (object stream $obj_num index $obj_idx)\n"; } print '-------' . ('-' x length($id)) . "\n"; unless ($object) { print "[Unable to read object]\n"; } else { _print_obj($object); } } sub _print_obj { my $object = shift(); if ($object->isa('PDF::Builder::Basic::PDF::Dict')) { print _obj_dictionary($object); } elsif ($object->isa('PDF::Builder::Basic::PDF::Array')) { print _obj_array($object) . "\n"; } elsif ($object->isa('PDF::Builder::Basic::PDF::Name') or $object->isa('PDF::Builder::Basic::PDF::Number') or $object->isa('PDF::Builder::Basic::PDF::String')) { if ($object->val() =~ /^[[:print:]]+$/) { print $object->val() . "\n"; } else { print $object->as_pdf() . "\n"; } } elsif ($object->isa('PDF::Builder::Basic::PDF::Null')) { print "\n" } else { print "[" . ref($object) . "]\n"; } if ($object->{' stream'}) { print "\n"; print "Stream\n"; print "------\n"; eval { $object->read_stream(1) }; if ($@) { print "[Stream could not be read or decoded]\n"; } elsif ($ENV{'FORCE'} or $object->{' stream'} =~ /^[[:print:]\s]*$/) { print $object->{' stream'} . "\n"; } else { print "[Stream contains non-printable characters. Set environment FORCE=1 to show the stream anyway.]\n"; } } return; } sub _obj_reference { my $object = shift(); return '{' objnum'} . ($object->{' objgen'} ? ' ' . $object->{' objgen'} : '') . '>'; } sub _obj_dictionary { my $object = shift(); my $indent = shift() || 0; my $data = {}; foreach my $key (keys %$object) { next if $key =~ /^ /; if (ref($object->{$key})) { if ($object->{$key}->isa('PDF::Builder::Basic::PDF::Array')) { $data->{$key} = _obj_array($object->{$key}, $indent + 1); chomp $data->{$key}; } elsif ($object->{$key}->isa('PDF::Builder::Basic::PDF::Dict')) { if ($object->{$key}->{' objnum'}) { $data->{$key} = '{$key}->{' objnum'} . ($object->{$key}->{' objgen'} ? ' ' . $object->{$key}->{' objgen'} : '') . '>'; } else { unless (scalar grep { $_ !~ /^ / } keys %{$object->{$key}}) { $data->{$key} = ''; } else { $data->{$key} = "\n" . _obj_dictionary($object->{$key}, $indent + 1); chomp $data->{$key}; } } } elsif ($object->{$key}->isa('PDF::Builder::Basic::PDF::Name') or $object->{$key}->isa('PDF::Builder::Basic::PDF::Number') or $object->{$key}->isa('PDF::Builder::Basic::PDF::String')) { if ($object->{$key}->val() =~ /^[[:print:]]+$/) { $data->{$key} = $object->{$key}->val(); } else { $data->{$key} = $object->{$key}->as_pdf(); } } elsif ($object->{$key}->isa('PDF::Builder::Basic::PDF::Null')) { $data->{$key} = ''; } elsif ($object->{$key}->isa('PDF::Builder::Basic::PDF::Objind') and $object->{$key}->{' objnum'}) { $data->{$key} = '{$key}->{' objnum'} . ($object->{$key}->{' objgen'} ? ' ' . $object->{$key}->{' objgen'} : '') . '>'; } else { $data->{$key} = '[' . ref($object->{$key}) . ']'; } } else { $data->{$key} = $object->{$key}; } } my $longest_key = 0; foreach my $key (keys %$data) { next if $data->{$key} =~ /^\n/; $longest_key = length($key) if length($key) > $longest_key; } $longest_key++; my $value = ''; my $cr = sub { return 1 if substr($data->{$_[0]}, 0, 1) eq "\n"; return -1; }; foreach my $key (sort { &$cr($a) <=> &$cr($b) or $a cmp $b } keys %$data) { if ($indent) { $value .= ' ' x ($indent * 4); } $value .= sprintf("%-${longest_key}s ", $key . ':') . $data->{$key} . "\n"; } return $value; } sub _obj_array { my $object = shift(); my $indent = shift() || 0; return '[ ]' unless scalar $object->elements(); my @elements; my $is_complex = 0; foreach my $element ($object->elements()) { unless (ref($element)) { push @elements, $element; } else { if ($element->isa('PDF::Builder::Basic::PDF::Array')) { push @elements, _obj_array($element, $indent + 1); } elsif ($element->isa('PDF::Builder::Basic::PDF::Dict')) { if ($element->{' objnum'}) { push @elements, '{' objnum'} . ($element->{' objgen'} ? ' ' . $element->{' objgen'} : '') . '>'; } else { unless (scalar grep { $_ !~ /^ / } keys %$element) { push @elements, ""; } else { $is_complex = 1; push @elements, "Dictionary: \n" . _obj_dictionary($element, $indent + 1); chomp $elements[-1]; } } } elsif ($element->isa('PDF::Builder::Basic::PDF::Name') or $element->isa('PDF::Builder::Basic::PDF::Number') or $element->isa('PDF::Builder::Basic::PDF::String')) { if ($element->val() =~ /^[[:print:]]+$/) { push @elements, $element->val(); } else { push @elements, $element->as_pdf(); } } elsif ($element->isa('PDF::Builder::Basic::PDF::Null')) { push @elements, ''; } elsif ($element->isa('PDF::Builder::Basic::PDF::Objind') and $element->{' objnum'}) { push @elements, '{' objnum'} . ($element->{' objgen'} ? ' ' . $element->{' objgen'} : '') . '>'; } else { push @elements, '[' . ref($element) . ']'; } } } my $value; unless ($is_complex) { $value = '[ ' . join(' ', @elements) . ' ]'; } else { $value = "\n"; foreach my $element (@elements) { $value .= ' ' x ($indent * 4) if $indent; $value .= '- ' . $element . "\n"; } } return $value; } PDF-Builder-3.026/tools/0000755000000000000000000000000014534671355013374 5ustar rootrootPDF-Builder-3.026/tools/3_examples.pl0000644000000000000000000002630314534467446016001 0ustar rootroot#!/usr/bin/perl # run examples test suite # roughly equivalent to examples.bat # you will need to update the %args list before running # -s flag to run short lists for 020_corefonts, 021_synfonts, 023_cjkfonts # author: Phil M Perry use strict; use warnings; our $VERSION = '3.026'; # VERSION our $LAST_UPDATE = '3.026'; # manually update whenever code is changed # dependent on optional packages: my $HS_installed = 1; # HarfBuzz::Shaper IS installed and you want to use it. # will quit if Shaper not installed! # note that you will likely need to update font file list # command line: # -step = stop after each test to let the tester look at the PDF file # -cont = (default) run continuously to the end, to not tie up tester # -s = short list for corefont, synfont, cjkfont tests my $pause; my (@example_list, @example_results); push @example_list, "011_open_update"; push @example_results, "create examples/011_open_update.BASE.pdf with one 'Hello World' page\n examples/011_open_update.UPDATED.pdf with 'Hello World (2)' added\n examples/011_open_update.STRING.pdf with 'Hello World (3)' and (4) added.\n"; push @example_list, "012_pages"; push @example_results, "create examples/012_pages.pdf with pages i..iii, 1, 9, 2..8.\n"; push @example_list, "020_corefonts"; push @example_results, "create examples/020_corefonts...pdf for each core font,\n each of one or more pages of characters.\n"; push @example_list, "020_textrise"; push @example_results, "create examples/020_textrise.pdf, one page showing + and - text rise examples.\n"; push @example_list, "020_textunderline"; push @example_results, "create examples/020_textunderline.pdf, one page showing sample underlined text.\n"; # require provision of a Type 1 font in %args push @example_list, "021_psfonts"; push @example_results, "create examples/021_psfonts...pdf,\n showing one or more pages of characters and Lorem Ipsum text.\n"; push @example_list, "021_synfonts"; push @example_results, "create examples/021_synfonts..pdf, showing one or more pages\n of characters, for each of 4 variants, and Lorem Ipsum text.\n"; # require provision of a TTF font in %args push @example_list, "022_truefonts"; push @example_results, "create examples/022_truefonts..pdf, showing one or more pages\n of characters and Lorem Ipsum text.\n"; # require provision of a TTF font in %args push @example_list, "022_truefonts_diacrits_utf8"; push @example_results, "create examples/022_truefonts_diacrits_utf8..pdf, showing one\n page of characters and a page with a combining diacritic.\n"; push @example_list, "023_cjkfonts"; push @example_results, "create examples/023_cjkfonts..pdf, showing many pages of characters\n and a page of Lorem Ipsum text for each of 4 variants (regular, bold, italic,\n and bold-italic. Note that Latin text may be proportional or fixed pitch.\n"; # require provision of a BDF font in %args push @example_list, "024_bdffonts"; push @example_results, "create examples/024_bdffonts..pdf, showing one page of 256 glyphs\n and a page of Lorem Ipsum text.\n"; push @example_list, "025_unifonts"; push @example_results, "create examples/025_unifonts.pdf, with the first 45 lines of an attached PDF-J\n file in four different Western + CJK fonts. Don't worry about long lines\n running off the right margin.\n"; push @example_list, "026_unifont2"; push @example_results, "create examples/026_unifont2.pdf, showing pages with labeled sections and\n full descriptive name on each character.\n"; # push @example_list, "027_winfont"; # push @example_results, "create examples/027_winfont.pdf. It has been removed (put in Windows directory for now)"; push @example_list, "030_colorspecs"; push @example_results, "create examples/030_colorspecs.pdf, showing many color models with\n a large sample of colors each, including named colors.\n"; push @example_list, "031_color_hsv"; push @example_results, "create examples/031_color_hsv.pdf, showing the HSV color model\n a large sample of colors.\n"; push @example_list, "032_separation"; push @example_results, "create examples/032_separation.pdf, showing the CMYK color separations\n (on one page) for printer use.\n"; push @example_list, "040_annotation"; push @example_results, "create examples/040_annotation.pdf, showing some text annotations.\n If you interact with the page, you will be asked if you want to save it\n when leaving (no need to do so).\n"; push @example_list, "041_annot_fileattach"; push @example_results, "create examples/041_annot_fileattach.pdf, showing some attached file\n annotations. Depending on your OS, Reader, and permission settings,\n you may not be allowed to open some files, or have to select a reader.\n"; push @example_list, "042_links"; push @example_results, "create examples/042_links.pdf, showing some examples of linking from \na PDF to other pages, other PDFs, and even other things such as browser pages.\n"; push @example_list, "050_pagelabels"; push @example_results, "create examples/050_pagelabels.pdf, showing a number of pages, each with its\n own page label in different formats. You will see them when you drag the\n vertical scroll thumb and you see a thumbnail of each page,\n each with its own label.\n"; push @example_list, "055_outlines"; push @example_results, "create examples/055_outlines.sample_55.pdf, showing a 12 page document.\n Click on the \"bookmark\" or \"outline\" icon to see three pages in the\n outline, where you\n can click to jump to any of them.\n"; push @example_list, "060_transparency"; push @example_results, "create examples/060_transparency.pdf, showing 2 pages with red opaque text\n partly covered by 40% transparent black text.\n"; push @example_list, "BarCode.pl"; push @example_results, "create examples/BarCode.pdf, showing 1 page with some bar code samples.\n It appears that the BarCodes need some more work.\n"; push @example_list, "Boxes.pl"; push @example_results, "create examples/Boxes.pdf, showing multiple pages on the effect\n of different PDF \"boxes\".\n"; push @example_list, "Bspline.pl"; push @example_results, "create examples/Bspline.pdf, showing 4 pages with some annotated examples of\n using (cubic) B-splines to draw smoothly-connected lines through all the\n given points.\n"; push @example_list, "Column.pl"; push @example_results, "create examples/Column.pdf, showing multiple pages demonstrating the\n capabilities of the Content/Text.pm column() library methods\n"; push @example_list, "Content.pl"; push @example_results, "create examples/Content.pdf, showing multiple pages demonstrating the\n capabilities of the Content.pm library methods (graphics and text).\n"; push @example_list, "ContentText.pl"; push @example_results, "create examples/ContentText.pdf, showing multiple pages demonstrating the\n capabilities of the Content/Text.pm library advanced text methods.\nAlso see Column.pl for additional material.\n"; if ($HS_installed) { push @example_list, "HarfBuzz.pl"; push @example_results, "create examples/HarfBuzz.pdf, showing raw text output through text(), and\n the equivalent text output by textHS() after processing by HarfBuzz::Shaper.\n"; } push @example_list, "RMtutorial.pl"; push @example_results, "create examples/RMtutorial.pdf, demonstrating very basic usage of\n PDF::Builder text and graphics.\n"; push @example_list, "Rotated.pl"; push @example_results, "create examples/Rotated.pdf, showing a way of embedding rotated pages\n within a document of unrotated pages.\n"; # require provision of a core font in %args push @example_list, "ShowFont.pl"; push @example_results, "create examples/ShowFont...pdf, showing multiple pages\n demonstrating the display of various encodings.\n"; # hard coded with a number of fonts you may need to change push @example_list, "FontManager.pl"; push @example_results, "create examples/FontManager.pdf to demonstrate some switching between\n declared fonts within paragraphs.\n"; # push @example_list, "examples/Windows/027_winfont.pl"; # push @example_results, "create examples/Windows/027_winfont...pdf, showing multiple pages\n demonstrating the display of various encodings.\n"; # run with perl examples/ [args] my %args; # if you do not define a file for a test (leave it EMPTY ''), it will be skipped # if any spaces in a path, make sure double quoted or use escapes # # 021_psfonts needs T1 glyph and metrics files (not included) # assuming metrics file (.afm or .pfm) is in same directory $args{'021_psfonts'} = "/Users/Phil/fonts/T1fonts/URWPalladioL-Roma.pfb"; # 022_truefonts needs a TTF or OTF font to do its thing $args{'022_truefonts'} = "/WINDOWS/fonts/times.ttf"; # 022_truefonts_diacrits_utf8 needs a TTF or OTF font that includes a # diacritic (combining accent mark) to do its thing $args{'022_truefonts_diacrits_utf8'} = "/WINDOWS/fonts/tahoma.ttf"; # 024_bdffonts needs a sample BDF (bitmapped font), which is not # included with the distribution $args{'024_bdffonts'} = "/Users/Phil/fonts/BDFfonts/codec/codec.bdf"; # ShowFont.pl needs a corefont (by default) font name $args{'ShowFont.pl'} = "Helvetica"; my $type; my $short_list = 0; # no -s flag seen # one command line arg allowed (-cont is default) if (scalar @ARGV == 0) { $type = '-cont'; } elsif (scalar @ARGV == 1) { if ($ARGV[0] eq '-step') { $type = '-step'; } elsif ($ARGV[0] eq '-cont') { # default $type = '-cont'; } elsif ($ARGV[0] eq '-s') { $type = '-cont'; $short_list = 1; } else { die "Unknown command line argument '$ARGV[0]'\n"; } splice @ARGV, 0, 1; # remove command line arg so <> will work } else { die "0 or 1 argument permitted. -cont is default.\n"; } $pause = ''; # some warnings: foreach my $test (@example_list) { if ($test eq '023_cjkfonts') { print "$test: to display the resulting PDFs, you may need to install\n"; print " East Asian fonts for your PDF reader.\n"; $pause = ' '; } } if ($pause eq ' ') { print "Press Enter to continue: "; $pause = <>; } print STDERR "\nStarting example runs..."; my ($i, $arg); for ($i=0; $i; } print STDERR "\nAfter examining files (results), do NOT erase files \n"; print STDERR " examples/011_open_update.BASE.pdf\n"; print STDERR " examples/012_pages.pdf\n"; print STDERR " examples/011_open_update.UPDATED.pdf\n"; print STDERR "if you are going to run 4_contrib.pl\n"; print STDERR "\nAll other examples output PDF files may be erased.\n"; PDF-Builder-3.026/tools/2_t-tests.pl0000644000000000000000000000410614534467446015562 0ustar rootroot#!/usr/bin/perl # run all "t" tests # roughly equivalent to t-tests.bat # must be run from parent of t/ # author: Phil M Perry use strict; use warnings; our $VERSION = '3.026'; # VERSION our $LAST_UPDATE = '3.025'; # manually update whenever code is changed # command line flags, mutually exclusive: # -raw show full output of each t-test run # -noOK exclude "ok" lines so can easily spot error lines DEFAULT # add after filter-lzwdecode when new TIFF code finished # filter-ccittfaxdecode my @test_list = qw( 00-all-usable 01-basic 02-xrefstm 03-xrefstm-index annotate barcode bbox circular-references cmap content content-deprecated cs-webcolor deprecations extgstate filter-ascii85decode filter-asciihexdecode filter-lzwdecode filter-runlengthdecode font-corefont font-synfont font-ttf font-type1 gd gif info jpg lite named-destinations outline page papersizes pdf png pnm rt67767 rt69503 rt120397 rt120450 rt126274 string text tiff version viewer-preferences ); # override full list above, and run just one or two tests #@test_list = qw( barcode ); # moved to xt/ # author-critic # author-pod-syntax # perl t/.t will run it my $type; # one command line arg allowed (-noOK is default) if (scalar @ARGV == 0) { $type = '-noOK'; } elsif (scalar @ARGV == 1) { if ($ARGV[0] eq '-raw') { $type = '-raw'; } elsif ($ARGV[0] eq '-noOK') { # default $type = '-noOK'; } else { die "Unknown command line argument '$ARGV[0]'\n"; } } else { die "0 or 1 argument permitted. -noOK is default.\n"; } foreach my $file (@test_list) { if ($file eq 'tiff') { print "\nNote: t/tiff.t takes quite a bit longer than the others to run. Don't Panic!"; } my @results = `perl t/$file.t`; # TBD: detect if a FAILED test, and remark at end if any failures print "\nt/$file.t\n"; if ($type eq '-raw') { print "@results"; } else { # -noOK remove any lines which start with "ok" foreach my $line (@results) { if ($line !~ m/^ok/) { print $line; } } } } PDF-Builder-3.026/tools/4_contrib.pl0000644000000000000000000001025714534467446015625 0ustar rootroot#!/usr/bin/perl # run contributions test suite # roughly equivalent to contrib.bat # be sure to update the directory separator below # author: Phil M Perry use strict; use warnings; our $VERSION = '3.026'; # VERSION our $LAST_UPDATE = '3.013'; # manually update whenever code is changed # command line: # # for Linux and Unix systems, the directory separator is / # for Windows systems, the directory separator is \\ (doubled again) #my $dirSep = '/'; # Unixy my $dirSep = '\\\\'; # Windows, inserted into string as \\ # only used in command path; can always use / in arguments my $pause; # check if any of the needed PDF files (from examples run) have been erased # or not created yet. my $noRun = 0; my $createdAtTop = 0; # combine_pdfs fileCheck("examples/011_open_update.BASE.pdf"); fileCheck("examples/012_pages.pdf"); fileCheck("examples/011_open_update.UPDATED.pdf"); if ($noRun) { #die "One or more necessary files missing.\n"; print "One or more necessary files are missing.\n"; print "Shall I try to create them for you?[n]\n"; $pause = <>; if ($pause =~ m/^y/i) { system("perl examples/011_open_update"); system("perl examples/012_pages"); $noRun = 0; $createdAtTop = 1; } } if ($noRun) { exit(1); } print "===== run contrib/combine_pdfs.pl\n"; system("contrib".$dirSep."combine_pdfs.pl examples/011_open_update.BASE.pdf examples/012_pages.pdf examples/011_open_update.UPDATED.pdf combined.pdf"); print "combined.pdf should be 15 pages: \n"; print " Hello World\n"; print " page sequence i ii iii 1 9 2..8\n"; print " Hello World and Hello World (2)\n"; print "Note that different page sizes are produced within combined.\n"; print "Press Enter to continue\n"; $pause = <>; print "===== run contrib/pdf-debug.pl\n"; print " contrib/pdf-debug.pl combined.pdf\n"; print " lists version, some other information:\n"; system("contrib".$dirSep."pdf-debug.pl combined.pdf"); print "Press Enter to continue\n"; $pause = <>; print " contrib/pdf-debug.pl combined.pdf obj 2\n"; print " describes a Pages type object:\n"; system("contrib".$dirSep."pdf-debug.pl combined.pdf obj 2"); print "Press Enter to continue\n"; $pause = <>; print " contrib/pdf-debug.pl combined.pdf xref\n"; print " lists the cross reference:\n"; system("contrib".$dirSep."pdf-debug.pl combined.pdf xref"); print "Press Enter to continue\n"; $pause = <>; print "===== run contrib/pdf-deoptimize.pl\n"; print " contrib/pdf-deoptimize.pl combined.pdf combined.deopt.pdf\n"; print " outputs combined.deopt.pdf, smaller than the original\n"; print " other than it's a working PDF, no idea what \"de-optimize\" does\n"; system("contrib".$dirSep."pdf-deoptimize.pl combined.pdf combined.deopt.pdf"); print "Press Enter to continue\n"; $pause = <>; print "===== run contrib/pdf-optimize.pl\n"; print " contrib/pdf-optimize.pl combined.pdf combined.opt.pdf\n"; print " outputs combined.opt.pdf, same size as the original\n"; print " other than it's a working PDF, no idea what \"optimize\" does\n"; system("contrib".$dirSep."pdf-optimize.pl combined.pdf combined.opt.pdf"); print "Press Enter to continue\n"; $pause = <>; print "===== run contrib/text2pdf.pl\n"; print " output to text2pdf.pl.pdf a paginated listing of itself\n"; system("contrib".$dirSep."text2pdf.pl contrib/text2pdf.pl"); print "Press Enter to continue\n"; $pause = <>; print "I will NOT erase the input files from examples/ -- you have to do that\n"; print "\nIf you are done with the output files, should I erase them now?[n]\n"; $pause = <>; if ($pause =~ m/^y/i) { if ($createdAtTop) { unlink("examples/011_open_update.BASE.pdf"); unlink("examples/011_open_update.UPDATED.pdf"); if (-f "examples/011_open_update.STRING.pdf") { # left over from run of 011 at the top unlink("examples/011_open_update.STRING.pdf"); } unlink("examples/012_pages.pdf"); } unlink("combined.pdf"); unlink("combined.deopt.pdf"); unlink("combined.opt.pdf"); unlink("text2pdf.pl.pdf"); } # -------------------------------- sub fileCheck { my ($file) = @_; if (!-f $file || !-r $file) { print "$file either not created yet, or you erased it!\n"; $noRun = 1; } return; } PDF-Builder-3.026/tools/1_pc.pl0000644000000000000000000001514314534467446014563 0ustar rootroot#!/usr/bin/perl # run perlcritic test suite # needless to say, 'perlcritic' command must be installed # roughly equivalent to pc.bat # author: Phil M Perry use strict; use warnings; our $VERSION = '3.026'; # VERSION our $LAST_UPDATE = '3.026'; # manually update whenever code is changed # command line: # -5 run perlcritic -5 . (should be clean) # -5x exclude certain common errors (none at this time) # -4 run perlcritic -4 . should get a number of common errors # -4x exclude certain common errors ** DEFAULT ** # -3 run perlcritic -3 . should get a number of errors # -3x exclude certain common errors # -2 run perlcritic -2 . should get more errors # -2x exclude certain common errors # -1 run perlcritic -1 . should get even more errors # -1x exclude certain common errors # # level 5 is apparently the MOST severe set of errors (all should be fixed); # level 1 the LEAST severe (and most numerous) # levels 1,2,3 are only for the morbidly curious! # (although some warnings look like they should be addressed) # output OK is always ignored my @ignore_list = ( # should not ignore any level 5 warnings "Use IO::Interactive::is_interactive", # not a core module! # common level 4 warnings to ignore # removed 'no warnings' in 3.021. remove next line 3.022 or later # "Code before warnings", # due to use of "no warnings" pragma # removed 'no warnings' in 3.021. remove next line 3.022 or later # "Warnings disabled at", # due to use of "no warnings" pragma "Close filehandles as soon as possible", # it thinks there is no "close" on an open # filehandle, due to either too many lines for # it to buffer, or use of other code to close "Always unpack ", # Always unpack @_ first at line # not using @_ or $_[n] directly is good practice, # but it doesn't seem to recognize legitimate uses # 'default' in Builder.pm would have to be deprecated, and changed to defaultB # Perl 'default' (CORE::) not used # 'close' in Content-Lite.pm would have to be deprecated, and changed to # closePath. Perl 'close' (CORE::) not used in Content-Lite.pm # 'print' in Lite.pm would have to be deprecated, and changed to # printB. Perl 'print' (CORE::) not used in Lite.pm # 'link' in NamedDestination.pm would have to be deprecated, and changed to # linkPage. Perl 'link' (CORE::) not used in NamedDestination.pm # 'next', 'last' in Outline.pm is undocumented internal routine, can rename # 'open' in Outline.pm would have to be deprecated, and changed to openB. # Perl 'open' (CORE::) not used # 'open' in File.pm would have to be deprecated, and changed to openB # Perl 'open' (CORE::) is ALSO used "Subroutine name is a homonym for builtin function", # e.g., we define "open" when there is already a # system (CORE::) open (ambiguous unless CORE:: # added) TBD consider removing "Subroutine name is a homonym for builtin keyword", # e.g., "sub default" "Symbols are exported by default", # it doesn't like something about our use of # @EXPORT and @EXPORT_OK # 4 'use constant' for conversion factors in Boxes.pl, 3 in RMtutorial.pl "Pragma \"constant\" used at", # will have to investigate why "use constant" # is flagged. TBD # common level 3 warnings to ignore for now '"die" used instead of "croak"', # '"warn" used instead of "carp"', # 'Regular expression without "/x" flag', # "Backtick operator used", # what's the problem? "high complexity score", # "Cascading if-elsif chain", # "Hard tabs used at", # consider updating (ViM editor [ ] likes to #replace spaces with tabs) '"local" variable not initialized', # variable set in next line -- # no problem "Reused variable name in lexical scope", # what's the problem? 'in condition for an "unless"', # doesn't like inequality tests in "unless" for some reason # perhaps it's confusing in this "negative" test? "Unrestricted '## no critic' annotation", # need documentation [ ] on how to restrict policies "Ambiguously named variable", # bitches about last, left, right as "ambiguous". sigh. # Return value of eval not tested, can't depend on $@. should fix [ ] ); # Note that level 4 includes any level 5 errors, etc. # my $level; my @exclude; # leave empty unless "x" suffix # one command line arg allowed (-4x is default) if (scalar @ARGV == 0) { $level = '-4'; @exclude = @ignore_list; } elsif (scalar @ARGV == 1) { if ($ARGV[0] eq '-5') { $level = '-5'; } elsif ($ARGV[0] eq '-5x') { $level = '-5'; @exclude = @ignore_list; } elsif ($ARGV[0] eq '-4') { $level = '-4'; } elsif ($ARGV[0] eq '-4x') { # default $level = '-4'; @exclude = @ignore_list; } elsif ($ARGV[0] eq '-3') { $level = '-3'; } elsif ($ARGV[0] eq '-3x') { $level = '-3'; @exclude = @ignore_list; } elsif ($ARGV[0] eq '-2') { $level = '-2'; } elsif ($ARGV[0] eq '-2x') { $level = '-3'; @exclude = @ignore_list; } elsif ($ARGV[0] eq '-1') { $level = '-1'; } elsif ($ARGV[0] eq '-1x') { $level = '-1'; @exclude = @ignore_list; } else { die "Unknown command line argument '$ARGV[0]'\n"; } } else { die "0 or 1 argument permitted. -4 is default.\n"; } print STDERR "Calling perlcritic $level"; if (scalar @exclude > 0) { print STDERR ", with excluded warning list"; } print STDERR ". This can take several minutes to run!\n"; my @results = `perlcritic $level .`; # always remove " source OK" my @results2 = (); foreach my $line (@results) { if ($line !~ m/ source OK/) { push @results2, $line; } } if (scalar @exclude > 0 && scalar @results2 > 0) { @results = @results2; @results2 = (); # remove common errors foreach my $line (@results) { my $keep = 1; foreach (@exclude) { if ($line =~ m/$_/) { $keep = 0; last; } } if ($keep) { push @results2, $line; } } } if (scalar(@results2) == 0) { print STDERR "No errors reported.\n"; } else { print STDERR scalar(@results2)." errors reported:\n"; print "@results2"; } PDF-Builder-3.026/tools/TTFdump.pl0000644000000000000000000000645614534467446015273 0ustar rootroot#!/usr/bin/perl # given a .TTF file on the command line, dump its glyph list and widths # in PDF::Builder::Resource::Fonts::CoreFonts::[facename].pm format # All the glyphs and their widths are given in widths.[fontname] by glyph # name. e.g., for core font timesroman, file might be .../times.ttf # Replace the corresponding glyphs width table in [facename.pm] with the # updated one created here. # "combining" forms are usually 0 width. For example, to create your own # n+~ (if Times lacked it): # # use strict; # use warnings; # use PDF::Builder; # # my $pdf = PDF::Builder->new(-compress => 'none'); # my $font = $pdf->ttfont('/Windows/Fonts/times.ttf'); # # my $page = $pdf->page(); # my $text = $page->text(); # # $text->font($font, 25); # $text->translate(100,600); # # # n + ~ created manually # $text->text("Pin\x{0303}on nuts come from a pine tree."); # # $pdf->saveas('combo.pdf'); use strict; use warnings; use lib qw{ ../lib }; use File::Basename; use PDF::Builder; use PDF::Builder::Util; use Unicode::UCD 'charinfo'; my ($pdf); # loop through command line list of font file names die "Need one or more TTF file names on command line!\n" if !scalar(@ARGV); foreach my $fn (@ARGV) { if (!-r $fn) { print "$fn cannot be read. Skipping...\n\n"; next; } my $myName = basename($fn); $myName =~ s/\.[to]tf$//i; # remove .ttf/.otf (any case) open my $FH, ">", "widths.$myName" or die "can't open output file widths.$myName\n"; print $FH "# source: $fn\n"; $pdf = PDF::Builder->new(); my $font = $pdf->ttfont($fn); my $u = $font->underlineposition(); print $FH "# font underline position = $u\n"; my @cids = (0 .. $font->glyphNum()-1); print $FH "# CIDs 0 .. $#cids to be output\n"; # warning: apparently not all fonts have fontbbox my @fbbx = $font->fontbbox(); print $FH "# fontbbox = (@fbbx)\n"; my $missingwidth = $font->missingwidth(); #print $FH "# missingwidth = $missingwidth\n"; # TBD other settings from $font to be added later # CId list is simply 0..number of glyphs in font-1 my %wxList; while (scalar @cids>0) { my $xo = shift(@cids); # 0, 1, 2,... my $name = $font->glyphByCId($xo); if (!defined $name || $name eq '') { $name="No Name!"; next; } my $wx = $font->wxByCId($xo); # actual width of character #print "G+$xo width=$wx, "; $wxList{$name} = $wx; ## information about the character # if (defined $font->uniByCId($xo)) { # printf('U+%04X ', $font->uniByCId($xo)); #} else { # printf('U+???? '); #} #print "name='$name' "; #my $ci = charinfo($font->uniByCId($xo) || 0); #if (defined $ci->{'name'}) { # print " desc. $ci->{'name'} "; #} #print "\n"; } # loop through cids of font # now have list of widths for all glyphs in font (including those without # a Unicode point). output sorted by name into widths.[filename] my @keys = sort keys %wxList; print $FH " 'wx' => { # HORIZ. WIDTH TABLE\n"; foreach my $glyphName (@keys) { print $FH " '$glyphName' => $wxList{$glyphName},\n"; } print $FH " },\n"; close $FH; } # loop through a font name. go to next command line name. exit; __END__ PDF-Builder-3.026/META.json0000644000000000000000000000277714534467632013673 0ustar rootroot{ "abstract" : "Facilitates the creation and modification of PDF files", "author" : [ "Phil Perry" ], "dynamic_config" : 1, "generated_by" : "ExtUtils::MakeMaker version 7.70, CPAN::Meta::Converter version 2.150010", "license" : [ "lgpl_2_1" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : 2 }, "name" : "PDF-Builder", "no_index" : { "directory" : [ "t", "inc" ] }, "prereqs" : { "build" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "configure" : { "requires" : { "ExtUtils::MakeMaker" : "6.66" } }, "runtime" : { "requires" : { "Compress::Zlib" : "1", "Font::TTF" : "1.04", "perl" : "5.026000" } }, "test" : { "requires" : { "Test::Exception" : "0", "Test::Memory::Cycle" : "1" } } }, "release_status" : "stable", "resources" : { "bugtracker" : { "web" : "https://github.com/PhilterPaper/Perl-PDF-Builder/issues" }, "homepage" : "https://metacpan.org/pod/PDF::Builder", "repository" : { "type" : "git", "url" : "git://github.com/PhilterPaper/Perl-PDF-Builder.git", "web" : "https://github.com/PhilterPaper/Perl-PDF-Builder" } }, "version" : "3.026", "x_serialization_backend" : "JSON::PP version 4.16" } PDF-Builder-3.026/MANIFEST0000644000000000000000000002155414434153156013365 0ustar rootroot# This file is manually maintained # if add or delete a .pm file, also update META.yml and META.json files # if add or delete a .t file, also update tools/2_t-tests.pl # if add or delete an example file, also update tools/3_examples.pl # as well as the list of examples and expected results # if add or delete a contribution, also update tools/4_contrib.pl .perlcriticrc Changes CONTRIBUTING.md LICENSE Makefile.PL MANIFEST META.json META.yml README.md tools/1_pc.pl tools/2_t-tests.pl tools/3_examples.pl tools/4_contrib.pl #tools/optional_update.pl tools/TTFdump.pl INFO/ACKNOWLEDGE.md INFO/Changes_2017 INFO/Changes_2018 INFO/Changes_2019 INFO/Changes_2020 INFO/Changes_2021 INFO/Changes-ver_2 INFO/CONVERSION INFO/DEPRECATED INFO/KNOWN_INCOMP INFO/PATENTS INFO/RoadMap INFO/SPONSORS INFO/SUPPORT INFO/old/contrib.bat INFO/old/dist.ini.old INFO/old/examples.bat INFO/old/pc.bat INFO/old/t-tests.bat contrib/combine_pdfs.pl contrib/pdf-debug.pl contrib/pdf-deoptimize.pl contrib/pdf-optimize.pl contrib/text2pdf.pl docs/buildDoc.pl examples/resources/040_annotation.pdf examples/resources/aptfrontview.jpg examples/resources/sample_55.pdf examples/resources/sample.txt examples/resources/pod2htmd.temp examples/011_open_update examples/012_pages examples/020_corefonts examples/020_textrise examples/020_textunderline examples/021_psfonts examples/021_synfonts examples/022_truefonts examples/022_truefonts_diacrits_utf8 examples/023_cjkfonts examples/024_bdffonts examples/025_unifonts examples/026_unifont2 # examples/027_winfont examples/030_colorspecs examples/031_color_hsv examples/032_separation examples/040_annotation examples/041_annot_fileattach examples/042_links examples/050_pagelabels examples/055_outlines examples/060_transparency examples/BarCode.pl examples/Boxes.pl examples/Bspline.pl examples/Column.pl examples/Content.pl examples/ContentText.pl examples/examples.output examples/HarfBuzz.pl examples/README examples/RMtutorial.pl examples/Rotated.pl examples/ShowFont.pl examples/FontManager.pl examples/Windows/027_winfont examples/Windows/Win32.pm lib/PDF/Builder.pm lib/PDF/Builder/Basic/PDF.pm lib/PDF/Builder/Basic/PDF/Filter/ASCII85Decode.pm lib/PDF/Builder/Basic/PDF/Filter/ASCIIHexDecode.pm # lib/PDF/Builder/Basic/PDF/Filter/CCITTFaxDecode/Reader.pm # lib/PDF/Builder/Basic/PDF/Filter/CCITTFaxDecode/Writer.pm # lib/PDF/Builder/Basic/PDF/Filter/CCITTFaxDecode.pm lib/PDF/Builder/Basic/PDF/Filter/FlateDecode.pm lib/PDF/Builder/Basic/PDF/Filter/LZWDecode.pm lib/PDF/Builder/Basic/PDF/Filter/RunLengthDecode.pm lib/PDF/Builder/Basic/PDF/Array.pm lib/PDF/Builder/Basic/PDF/Bool.pm lib/PDF/Builder/Basic/PDF/Dict.pm lib/PDF/Builder/Basic/PDF/File.pm lib/PDF/Builder/Basic/PDF/Filter.pm lib/PDF/Builder/Basic/PDF/Literal.pm lib/PDF/Builder/Basic/PDF/Name.pm lib/PDF/Builder/Basic/PDF/Null.pm lib/PDF/Builder/Basic/PDF/Number.pm lib/PDF/Builder/Basic/PDF/Objind.pm lib/PDF/Builder/Basic/PDF/Page.pm lib/PDF/Builder/Basic/PDF/Pages.pm lib/PDF/Builder/Basic/PDF/String.pm lib/PDF/Builder/Basic/PDF/Utils.pm # lib/PDF/Builder/Content/Barcode/DataMatrix.pm lib/PDF/Builder/Content/Hyphenate_basic.pm lib/PDF/Builder/Content/Text.pm lib/PDF/Builder/Resource/CIDFont/CJKFont/adobemingstdlightacro.data lib/PDF/Builder/Resource/CIDFont/CJKFont/adobemyungjostdmediumacro.data lib/PDF/Builder/Resource/CIDFont/CJKFont/adobesongstdlightacro.data lib/PDF/Builder/Resource/CIDFont/CJKFont/kozgopromediumacro.data lib/PDF/Builder/Resource/CIDFont/CJKFont/kozminproregularacro.data lib/PDF/Builder/Resource/CIDFont/CMap/japanese.cmap lib/PDF/Builder/Resource/CIDFont/CMap/korean.cmap lib/PDF/Builder/Resource/CIDFont/CMap/simplified.cmap lib/PDF/Builder/Resource/CIDFont/CMap/traditional.cmap lib/PDF/Builder/Resource/CIDFont/TrueType/FontFile.pm lib/PDF/Builder/Resource/CIDFont/CJKFont.pm lib/PDF/Builder/Resource/CIDFont/TrueType.pm lib/PDF/Builder/Resource/ColorSpace/Indexed/ACTFile.pm lib/PDF/Builder/Resource/ColorSpace/Indexed/Hue.pm lib/PDF/Builder/Resource/ColorSpace/Indexed/WebColor.pm lib/PDF/Builder/Resource/ColorSpace/DeviceN.pm lib/PDF/Builder/Resource/ColorSpace/Indexed.pm lib/PDF/Builder/Resource/ColorSpace/Separation.pm lib/PDF/Builder/Resource/Font/CoreFont/bankgothic.pm lib/PDF/Builder/Resource/Font/CoreFont/courier.pm lib/PDF/Builder/Resource/Font/CoreFont/courierbold.pm lib/PDF/Builder/Resource/Font/CoreFont/courierboldoblique.pm lib/PDF/Builder/Resource/Font/CoreFont/courieroblique.pm lib/PDF/Builder/Resource/Font/CoreFont/georgia.pm lib/PDF/Builder/Resource/Font/CoreFont/georgiabold.pm lib/PDF/Builder/Resource/Font/CoreFont/georgiabolditalic.pm lib/PDF/Builder/Resource/Font/CoreFont/georgiaitalic.pm lib/PDF/Builder/Resource/Font/CoreFont/helvetica.pm lib/PDF/Builder/Resource/Font/CoreFont/helveticabold.pm lib/PDF/Builder/Resource/Font/CoreFont/helveticaboldoblique.pm lib/PDF/Builder/Resource/Font/CoreFont/helveticaoblique.pm lib/PDF/Builder/Resource/Font/CoreFont/symbol.pm lib/PDF/Builder/Resource/Font/CoreFont/timesbold.pm lib/PDF/Builder/Resource/Font/CoreFont/timesbolditalic.pm lib/PDF/Builder/Resource/Font/CoreFont/timesitalic.pm lib/PDF/Builder/Resource/Font/CoreFont/timesroman.pm lib/PDF/Builder/Resource/Font/CoreFont/trebuchet.pm lib/PDF/Builder/Resource/Font/CoreFont/trebuchetbold.pm lib/PDF/Builder/Resource/Font/CoreFont/trebuchetbolditalic.pm lib/PDF/Builder/Resource/Font/CoreFont/trebuchetitalic.pm lib/PDF/Builder/Resource/Font/CoreFont/verdana.pm lib/PDF/Builder/Resource/Font/CoreFont/verdanabold.pm lib/PDF/Builder/Resource/Font/CoreFont/verdanabolditalic.pm lib/PDF/Builder/Resource/Font/CoreFont/verdanaitalic.pm lib/PDF/Builder/Resource/Font/CoreFont/webdings.pm lib/PDF/Builder/Resource/Font/CoreFont/wingdings.pm lib/PDF/Builder/Resource/Font/CoreFont/zapfdingbats.pm lib/PDF/Builder/Resource/Font/BdFont.pm lib/PDF/Builder/Resource/Font/CoreFont.pm lib/PDF/Builder/Resource/Font/Postscript.pm lib/PDF/Builder/Resource/Font/SynFont.pm lib/PDF/Builder/Resource/XObject/Form/BarCode/codabar.pm lib/PDF/Builder/Resource/XObject/Form/BarCode/code128.pm lib/PDF/Builder/Resource/XObject/Form/BarCode/code3of9.pm lib/PDF/Builder/Resource/XObject/Form/BarCode/ean13.pm lib/PDF/Builder/Resource/XObject/Form/BarCode/int2of5.pm lib/PDF/Builder/Resource/XObject/Form/BarCode2D/placeholder lib/PDF/Builder/Resource/XObject/Form/QRCode/placeholder lib/PDF/Builder/Resource/XObject/Form/BarCode.pm lib/PDF/Builder/Resource/XObject/Form/Hybrid.pm lib/PDF/Builder/Resource/XObject/Image/TIFF/File.pm lib/PDF/Builder/Resource/XObject/Image/TIFF/File_GT.pm lib/PDF/Builder/Resource/XObject/Image/GD.pm lib/PDF/Builder/Resource/XObject/Image/GIF.pm lib/PDF/Builder/Resource/XObject/Image/JPEG.pm lib/PDF/Builder/Resource/XObject/Image/PNG.pm lib/PDF/Builder/Resource/XObject/Image/PNG_IPL.pm lib/PDF/Builder/Resource/XObject/Image/PNM.pm lib/PDF/Builder/Resource/XObject/Image/TIFF.pm lib/PDF/Builder/Resource/XObject/Image/TIFF_GT.pm lib/PDF/Builder/Resource/XObject/Form.pm lib/PDF/Builder/Resource/XObject/Image.pm lib/PDF/Builder/Resource/BaseFont.pm lib/PDF/Builder/Resource/CIDFont.pm lib/PDF/Builder/Resource/Colors.pm lib/PDF/Builder/Resource/ColorSpace.pm lib/PDF/Builder/Resource/ExtGState.pm lib/PDF/Builder/Resource/Font.pm lib/PDF/Builder/Resource/Glyphs.pm lib/PDF/Builder/Resource/PaperSizes.pm lib/PDF/Builder/Resource/Pattern.pm lib/PDF/Builder/Resource/Shading.pm lib/PDF/Builder/Resource/UniFont.pm lib/PDF/Builder/Resource/uniglyph.txt lib/PDF/Builder/Resource/XObject.pm lib/PDF/Builder/Annotation.pm lib/PDF/Builder/Content.pm lib/PDF/Builder/Docs.pm lib/PDF/Builder/FontManager.pm lib/PDF/Builder/Lite.pm lib/PDF/Builder/Matrix.pm lib/PDF/Builder/NamedDestination.pm lib/PDF/Builder/Outline.pm lib/PDF/Builder/Outlines.pm lib/PDF/Builder/Page.pm lib/PDF/Builder/Resource.pm lib/PDF/Builder/UniWrap.pm lib/PDF/Builder/Util.pm lib/PDF/Builder/ViewerPreferences.pm t/resources/1x1.gif t/resources/1x1.jpg t/resources/1x1.pbm t/resources/1x1.png t/resources/1x1.tif t/resources/1x1-lzw.tif t/resources/sample.pdf t/resources/sample-xrefstm.pdf t/resources/sample-xrefstm-index.pdf t/resources/test-rgba.png t/00-all-usable.t t/01-basic.t t/02-xrefstm.t t/03-xrefstm-index.t t/annotate.t t/barcode.t t/bbox.t t/circular-references.t t/cmap.t t/content.t t/content-deprecated.t t/cs-webcolor.t t/deprecations.t t/extgstate.t t/filter-ascii85decode.t t/filter-asciihexdecode.t # t/filter-ccittfaxdecode.t t/filter-lzwdecode.t t/filter-runlengthdecode.t t/font-corefont.t t/font-synfont.t t/font-ttf.t t/font-type1.t t/gd.t t/gif.t t/info.t t/jpg.t t/lite.t t/named-destinations.t t/outline.t t/page.t t/papersizes.t t/pdf.t t/png.t t/pnm.t t/rt67767.t t/rt69503.t t/rt120397.t t/rt120450.t t/rt126274.t t/string.t t/text.t t/tiff.t t/version.t t/viewer-preferences.t xt/author-critic.t xt/author-pod-syntax.t PDF-Builder-3.026/README.md0000644000000000000000000002450014522461504013502 0ustar rootroot# PDF::Builder A Perl library to facilitate the creation and modification of PDF files ## What is it? PDF::Builder is a **fork** of the popular PDF::API2 Perl library. It provides a library of modules and functions so that a PDF file (document) may be built and maintained from Perl programs. It is not a WYSIWYG editor; nor is it a canned utility or converter. It does _not_ have a GUI -- it is driven by your Perl program. It is a set of **building blocks** with which you can perform a wide variety of operations, ranging from basic operations such as selecting a font face, to defining an entire page at a time in the document, using a large subset of either Markdown or HTML markup languages. You can call it from arbitrary Perl programs, which may even create content on-the-fly (or read it in from other sources). Quite a few code examples are provided, to help you to get started with the process of creating a PDF document. Many enhancements are in the pipeline to make PDF::Builder even more powerful and versatile. [Home Page](https://www.catskilltech.com/FreeSW/product/PDF%2DBuilder/title/PDF%3A%3ABuilder/freeSW_full), including Documentation and Examples. [![Open Issues](https://img.shields.io/github/issues/PhilterPaper/Perl-PDF-Builder)](https://github.com/PhilterPaper/Perl-PDF-Builder/issues) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](https://makeapullrequest.com) [![Maintenance](https://img.shields.io/badge/Maintained%3F-yes-green.svg)](https://GitHub.com/PhilterPaper/Perl-PDF-Builder/graphs/commit-activity) This archive contains the distribution PDF::Builder. See **Changes** file for the version. ## Obtaining the Package The installable Perl package may be obtained from "https://metacpan.org/pod/PDF::Builder", or via a CPAN installer package. If you install this product, only the run-time modules will be installed. Download the full `.tar.gz` file and unpack it (hint: on Windows, **7-Zip File Manager** is an excellent tool) to get utilities, test buckets, example usage, etc. Alternatively, you can obtain the full source files from "https://github.com/PhilterPaper/Perl-PDF-Builder", where the ticket list (bugs, enhancement requests, etc.) is also kept. Unlike the installable CPAN version, this will have to be manually installed (copy files; there are no XS compiles at this time). Note that there are several "optional" libraries (Perl modules) used to extend and improve PDF::Builder. Read about the list of optional libraries in PDF::Builder::Docs, and decide whether or not you want to install any of them. By default, none are installed. ## Requirements ### Perl **Perl 5.26** or higher. It will likely run on somewhat earlier versions, but the CPAN installer may refuse to install it. The reason this version was chosen was so that LTS (Long Term Support) versions of Perl going back about 6 years are officially supported (by PDF::Builder), and older versions are not supported. The intent is to not waste time and effort trying to fix bugs which are an artifact of old Perl releases. #### Older Perls If you MUST install on an older (pre 5.26) Perl, you can try the following for Strawberry Perl (Windows). NO PROMISES! Something similar MAY work for other OS's and Perl installations: 1. Unpack installation file (`.tar.gz`, via a utility such as 7-Zip) into a directory, and cd to that directory 1. Edit META.json and change 5.026000 to 5.016000 or whatever level desired 1. Edit META.yml and change 5.026000 to 5.016000 or whatever level desired 1. Edit Makefile.PL and change `use 5.026000;` to `use 5.016000;`, change `$PERL_version` from `5.026000` to `5.016000` 1. `cpan .` Note that some Perl installers MAY have a means to override or suppress the Perl version check. That may be easier to use. Or, you may have to repack the edited directory back into a `.tar.gz` installable. YMMV. If all goes well, PDF::Builder will be installed on your system. Whether or not it will RUN is another matter. Please do NOT open a bug report (ticket) unless you're absolutely sure that the problem is not a result of using an old Perl release, e.g., PDF::Builder is using a feature introduced in Perl 5.018 and you're trying to run Perl 5.002! ### Libraries used These libraries are available from CPAN. #### REQUIRED These libraries should be automatically installed... * Compress::Zlib * Font::TTF * Test::Exception (needed only for installation tests) * Test::Memory::Cycle (needed only for installation tests) #### OPTIONAL These libraries are _recommended_ for improved functionality and performance. The default behavior is **not** to attempt to install them during PDF::Builder installation, in order to speed up the testing process and not clutter up matters, especially if an optional package fails to install. You can always manually install them later, if you desire to make use of their added functionality. * Perl::Critic (1.150 or higher, need if running tools/1\_pc.pl) * Graphics::TIFF (19 or higher, recommended if using TIFF image functions) * Image::PNG::Libpng (0.57 or higher, recommended for enhanced PNG image function processing) * HarfBuzz::Shaper (0.024 or higher, needed for Latin script ligatures and kerning, as well as for any complex script such as Arabic, Indic scripts, or Khmer) * Text::Markdown (1.000031 or higher, needed if using 'md1' markup) * HTML::TreeBuilder (5.07 or higher, needed if using 'html' or 'md1' markup) * Pod::Simple::XHTML (3.45 or higher, needed if using buildDoc utility to create HTML documentation) If an optional package is needed, but not installed, sometimes PDF::Builder will be able to fall back to built-in partial functionality (TIFF and PNG images), but other times will fail. After installing the missing package, you may wish to then run the t-test suite for that library to confirm that it is properly running, as well as running the examples. Other than an installer for standard CPAN packages (such as 'cpan' on Strawberry Perl for Windows), no other tools or manually-installed prereqs are needed (worst case, you can unpack the `.tar.gz` file and copy files into place yourself!). Currently there are no compiles and links (Perl extensions) done during the install process, only copying of .pm Perl module files. ## Manually building As is the usual practice with building such a package (from the command line), the steps are: 1. perl Makefile.PL 1. make 1. make test 1. make install If you have your system configured to run Perl for a .pl/.PL file, you may be able to omit "perl" from the first command, which creates a Makefile. "make" is the generic command to run (it feeds on the Makefile), but your system may have it under a different name, such as dmake (Strawberry Perl on Windows), gmake, or nmake. PDF::Builder does not currently compile and link anything, so `gcc`, `g++`, etc. will not be used. The build process merely copies .pm files around, and runs the "t" tests to confirm the proper installation. ## Copyright This software is Copyright (c) 2017-2023 by Phil M. Perry. Previous copyrights are held by others (Steve Simms, Alfred Reibenschuh, et al.). See The HISTORY section of the documentation for more information. We would like to acknowledge the efforts and contributions of a number of users of PDF::Builder (and its predecessor, PDF::API2), who have given their time to report issues, ask for new features, and have even contributed code. Generally, you will find their names listed in the Changes and/or issue tickets related to some particular item. ## License This is free software, licensed under: `The GNU Lesser General Public License, Version 2.1, February 1999` EXCEPT for some files which are explicitly under other, compatible, licenses (the Perl License and the MIT License). You are permitted (at your option) to redistribute and/or modify this software (those portions under LGPL) at an LGPL version greater than 2.1. See INFO/LICENSE for more information on the licenses and warranty statement. ### Carrying On... PDF::Builder is Open Source software, built upon the efforts not only of the current maintainer, but also of many people before me. Therefore, it's perfectly fair to make use of the algorithms and even code (within the terms of the LICENSE). That's exactly how the State of the Art progresses! Just please be considerate and acknowledge the work of others that you are building on, as well as pointing back to this package. Drop us a note with news of your project (if based on the code and algorithms in PDF::Builder, or even just heavily inspired by it) and we'll be happy to make a pointer to your work. The more cross-pollination, the better! ## See Also * CONTRIBUTING file for how to contribute to the project * LICENSE file for more on the license term * INFO/RoadMap file for the PDF::Builder road map * INFO/ACKNOWLEDGE.md for "thank yous" to those who contributed to this product * INFO/SUPPORT file for information on reporting bugs, etc. via GitHub Issues * INFO/DEPRECATED file for information on deprecated features * INFO/KNOWN\_INCOMP file for known incompatibilities with PDF::API2 * INFO/CONVERSION file for how to convert from PDF::API2 to PDF::Builder * INFO/Changes\* files for older change logs * INFO/PATENTS file for information on patents `INFO/old/` also has some build and test tool files that are not currently used. ## Documentation To build the full HTML documentation (all the POD), get the full installation and go to the `docs/` directory. Run `buildDoc.pl --all` to generate the full tree of documentation. There's a lot of additional information in the PDF::Builder::Docs module (it's all documentation). You may find it more convenient to point your browser to our [Home Page](https://www.catskilltech.com/FreeSW/product/PDF-Builder/title/PDF%3A%3ABuilder/freeSW_full) to see the full documentation build (as well as most of the example outputs). We admit that the documentation is a bit light on "how to" task orientation. We hope to more fully address this in the future, but for now, get the full installation and look at the `examples/` and `contrib/` directories for sample code that may help you figure out how to do things. The installation tests in the `t/` and `xt/` directories might also be useful to you. PDF-Builder-3.026/Makefile.PL0000644000000000000000000001007414534467444014212 0ustar rootroot#! perl use strict; use warnings; use 5.026000; use ExtUtils::MakeMaker 6.66; my $PERL_version = '5.026000'; # Both here and in "use" statement above, # PDFbuild.pl updates from 'version' file my $MakeMaker_version = '6.66'; my $version = '3.026'; # PDFbuild.pl updates from 'version' file # optional libraries... most users will attempt to install full set. they are # nice to have but not vital for many users. if one fails to install, it might # alarm the user, but installation of PDF::Builder can still proceed. the # user can remove any optional installed library if they don't need it and # want to reclaim the space. or, they can run optional_update.pl to select # optional libraries, before running Makefile.PL. # for future consideration #my $master = 'lib/PDF/Builder.pm'; #my $version = MM->parse_version($master); my %WriteMakefileArgs = ( NAME => "PDF::Builder", DISTNAME => "PDF-Builder", # VERSION_FROM => $master, VERSION => $version, # ABSTRACT_FROM => $master, ABSTRACT => "Facilitates the creation and modification of PDF files", AUTHOR => 'Phil Perry', LICENSE => "lgpl_2_1", # some files also MIT license MIN_PERL_VERSION => $PERL_version, INSTALLDIRS => "site", CONFIGURE_REQUIRES => { "ExtUtils::MakeMaker" => $MakeMaker_version, }, # BUILD_REQUIRES => { # mandatory prereqs listed here # }, TEST_REQUIRES => { "Test::Exception" => 0, "Test::Memory::Cycle" => 1.0, }, PREREQ_PM => { "Compress::Zlib" => 1.0, "Font::TTF" => 1.04, # "Readonly" => 0, use when TIFF changes go in # === found in CORE, so no need to explicitly list #"Carp" => 0, #"constant" => 0, #"Encode" => 0, #"Exporter" =>0, #"FileHandle" => 0, #"File::Find" => 0, #"File::Basename" => 0, #"File::Temp" => 0, #"IO::File" => 0, #"List::Util" => 0, #"Math::Trig" => 0, #"POSIX" => 0 #"Scalar::Util" => 0, #"strict" => 0, #"Unicode::UCD" => 0, #"utf8" => 0, #"vars" => 0, #"warnings" => 0, # === NOT core, but not currently used #"Win32::TieRegistry" => 0, # if manually use Win32, need to install }, META_MERGE => { "meta-spec" => { "version" => 2 }, "resources" => { "homepage" => "https://metacpan.org/pod/PDF::Builder", "repository" => { "type" => 'git', "url" => 'git://github.com/PhilterPaper/Perl-PDF-Builder.git', "web" => 'https://github.com/PhilterPaper/Perl-PDF-Builder', }, "bugtracker" => { "web" => 'https://github.com/PhilterPaper/Perl-PDF-Builder/issues', }, }, # recommends (optional prereqs) goes here # if remove or comment out any, also do so in META.json and META.yml #"recommends" => { # # fast TIFF image processing. # "Graphics::TIFF" => 19, # # advanced/fast PNG image processing. # "Image::PNG::Libpng" => 0.57, # # text shaping for Latin script ligatures and kerning, and for # # many complex scripts both LTR and RTL directions. # "HarfBuzz::Shaper" => 0.024, # # 'md1' markup # Text::Markdown => 1.000031, # # 'md1' and 'html' markup # HTML::TreeBuilder => 5.07, # # use of buildDoc.pl to build HTML documentation from POD # Pod::Simple::XHTML => 3.45, #}, } ); # restore if make use of Win32.pm again #if ( $^O eq 'MSWin32' ) { # $WriteMakefileArgs{PREREQ_PM}{'Win32::TieRegistry'} = '0'; #} # enable if required for build on Mac #if ( $^O eq 'MacOS' ) { # $WriteMakefileArgs{PREREQ_PM}{'MacPerl'} = '0'; #} #print <<'END'; #=========================================================================== #The installation process will attempt to install or update several OPTIONAL #prerequisite packages. If one or more should fail to install, Don't Panic #-- you will still be able to run PDF::Builder, but may not be able to use #some advanced features. See the README.md file for more information. #=========================================================================== #END WriteMakefile(%WriteMakefileArgs); PDF-Builder-3.026/lib/0000755000000000000000000000000014534671355013002 5ustar rootrootPDF-Builder-3.026/lib/PDF/0000755000000000000000000000000014534467617013417 5ustar rootrootPDF-Builder-3.026/lib/PDF/Builder.pm0000644000000000000000000050044714534467446015355 0ustar rootrootpackage PDF::Builder; use strict; use warnings; # $VERSION defined here so developers can run PDF::Builder from git. # it should be automatically updated as part of the CPAN build. our $VERSION = '3.026'; # VERSION our $LAST_UPDATE = '3.026'; # manually update whenever code is changed # updated during CPAN build my $GrTFversion = 19; # minimum version of Graphics::TIFF my $HBShaperVer = 0.024; # minimum version of HarfBuzz::Shaper my $LpngVersion = 0.57; # minimum version of Image::PNG::Libpng my $TextMarkdown = 1.000031; # minimum version of Text::Markdown my $HTMLTreeBldr = 5.07; # minimum version of HTML::TreeBuilder my $PodSimpleXHTML = 3.45; # minimum version of Pod::Simple::XHTML use Carp; use Encode qw(:all); use English; use FileHandle; use PDF::Builder::Basic::PDF::Utils; use PDF::Builder::Util; use PDF::Builder::Basic::PDF::File; use PDF::Builder::Basic::PDF::Pages; use PDF::Builder::Page; use PDF::Builder::Resource::XObject::Form::Hybrid; use PDF::Builder::Resource::ExtGState; use PDF::Builder::Resource::Pattern; use PDF::Builder::Resource::Shading; use PDF::Builder::NamedDestination; use PDF::Builder::FontManager; use List::Util qw(max); use Scalar::Util qw(weaken); # Note that every Linux distribution seems to put font files in a different # place, and even Windows is consistent only for TTF/OTF font files. my @font_path = __PACKAGE__->set_font_path( '.', # could a font ever be a security risk? '/usr/share/fonts', '/usr/local/share/fonts', '/usr/share/fonts/type1/gsfonts', '/usr/share/X11/fonts/urw-fonts', '/usr/share/fonts/urw-base35', '/usr/share/fonts/dejavu-sans-fonts', '/usr/share/fonts/truetype/ttf-dejavu', '/usr/share/fonts/truetype/dejavu', '/var/lib/defoma/gs.d/dirs/fonts', '/Windows/Fonts', '/Users/XXXX/AppData/Local/Microsoft/Windows/Fonts', '/WinNT/Fonts' ); our @MSG_COUNT = (0, # [0] Graphics::TIFF not installed 0, # [1] Image::PNG::Libpng not installed 0, # [2] save/restore in text mode 0, # [3] Times-Roman core font substituted for Times 0, # [4] TBD... ); our $outVer = 1.4; # desired PDF version for output, bump up w/ warning on read or feature output our $msgVer = 1; # 0=don't, 1=do issue message when PDF output version is bumped up our $myself; # holds self->pdf our $global_pdf; # holds self ($pdf) require PDF::Builder::FontManager; =head1 NAME PDF::Builder - Facilitates the creation and modification of PDF files =head1 SYNOPSIS use PDF::Builder; # Create a blank PDF file $pdf = PDF::Builder->new(); # Open an existing PDF file $pdf = PDF::Builder->open('some.pdf'); # Add a blank page $page = $pdf->page(); # Retrieve an existing page $page = $pdf->open_page($page_number); # Set the page size $page->size('Letter'); # or mediabox('Letter') # Add a built-in font to the PDF $font = $pdf->font('Helvetica-Bold'); # or corefont('Helvetica-Bold') # Add an external TrueType (TTF) font to the PDF $font = $pdf->font('/path/to/font.ttf'); # or ttfont() in this case # Add some text to the page $text = $page->text(); $text->font($font, 20); $text->position(200, 700); # or translate() $text->text('Hello World!'); # Save the PDF $pdf->saveas('/path/to/new.pdf'); =head1 SOME SPECIAL NOTES See the file README.md (in downloadable package and on CPAN) for a summary of prerequisites and tools needed to install PDF::Builder, both mandatory and optional. =head2 SOFTWARE DEVELOPMENT KIT There are four levels of involvement with PDF::Builder. Depending on what you want to do, different kinds of installs are recommended. See L for suggestions. =head2 OPTIONAL LIBRARIES PDF::Builder can make use of some optional libraries, which are not I for a successful installation, but improve speed and capabilities. See L for more information. =head2 STRINGS (CHARACTER TEXT) There are some things you should know about character encoding (for text), before you dive in to coding. Please go to L and have a read. =head2 RENDERING ORDER Invoking "text" and "graphics" methods can lead to unexpected results (a different ordering of output than intended). See L for more information. =head2 PDF VERSIONS SUPPORTED PDF::Builder is mostly PDF 1.4-compliant, but there I complications you should be aware of. Please read L for details. =head2 SUPPORTED PERL VERSIONS (BACKWARDS COMPATIBILITY GOALS) PDF::Builder intends to support all major Perl versions that were released in the past six years, plus one, in order to continue working for the life of most long-term-stable (LTS) server distributions. See the L table B x.xxxx0 "Major" release dates. For example, a version of PDF::Builder released on 2018-06-05 would support the last major version of Perl released I 2012-06-05 (5.18), and then one before that, which would be 5.16. Alternatively, the last major version of Perl released I 2012-06-05 is 5.16. The intent is to avoid expending unnecessary effort in supporting very old (obsolete) versions of Perl. =head3 Anticipated Support Cutoff Dates B that these are I hard and fast dates. In particular, we develop on Strawberry Perl, which sometimes falls a little behind the official Perl release! =over =item * 5.26 current minimum supported version, until next PDF::Builder release after 23 June, 2024. This is currently the minimum tested version. =item * 5.28 future minimum supported version, until next PDF::Builder release after 22 May, 2025 =item * 5.30 future minimum supported version, until next PDF::Builder release after 20 June, 2026 =item * 5.32 future minimum supported version, until next PDF::Builder release after 20 May, 2027. This is currently our primary development version. =item * 5.34 future minimum supported version, until next PDF::Builder release after 28 May, 2028 =item * 5.36 future minimum supported version, until next PDF::Builder release after 02 Jul, 2029 =item * 5.38 future minimum supported version, until next PDF::Builder release some time after 02 Jul, 2029. This is currently the maximum tested version. =back If you need to use this module on a server with an extremely out-of-date version of Perl, consider using either plenv or Perlbrew to run a newer version of Perl without needing admin privileges. On the other hand, any feature in PDF::Builder should continue to work unchanged for the life of most long-term-stable (LTS) server distributions. Their lifetime is usually about six (6) years. Note that this does B constitute a statement of warranty, but that we I to try to keep any particular release of PDF::Builder working for a period of years. Of course, it helps if you periodically update your Perl installation to something released in the recent past. =head2 KNOWN ISSUES This module does not work with perl's -l command-line switch. There is a file INFO/KNOWN_INCOMP which lists known incompatibilities with PDF::API2, in case you're thinking of porting over something from that world, or have experience there and want to try PDF::Builder. There is also a file INFO/DEPRECATED, which lists things which are planned to be removed at some point. =head2 HISTORY The history of PDF::Builder is a complex and exciting saga... OK, it may be mildly interesting. Have a look at L section. =head2 AUTHOR PDF::API2 was originally written by Alfred Reibenschuh. See the HISTORY section for more information. It was maintained by Steve Simms, who is still contributing new code to it (which often ends up in PDF::Builder). PDF::Builder is currently being maintained by Phil M. Perry. =head2 SUPPORT The full source is on https://github.com/PhilterPaper/Perl-PDF-Builder. The release distribution is on CPAN: https://metacpan.org/pod/PDF::Builder. Bug reports are on https://github.com/PhilterPaper/Perl-PDF-Builder/issues?q=is%3Aissue+sort%3Aupdated-desc (with "bug" label), feature requests have an "enhancement" label, and general discussions (architecture, roadmap, etc.) have a "general discussion" label. Do B under I circumstances open a PR (Pull Request) to report a bug. It is a waste of both your and our time and effort. Open a regular ticket (issue), and attach a Perl (.pl) program illustrating the problem, if possible. If you believe that you have a program patch, and offer to share it as a PR, we may give the go-ahead. Unsolicited PRs may be closed without further action. =head2 LICENSE This software is Copyright (c) 2017-2023 by Phil M. Perry. This is free software, licensed under: The GNU Lesser General Public License (LGPL) Version 2.1, February 1999 (The master copy of this license lives on the GNU website.) (A copy is provided in the INFO/LICENSE file for your convenience.) This section of Builder.pm is intended only as a very brief summary of the license; please consider INFO/LICENSE to be the controlling version, if there is any conflict or ambiguity between the two. This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License, as published by the Free Software Foundation, either version 2.1 of the License, or (at your option) any later version of this license. NOTE: there are several files in this distribution which were incorporated from outside sources and carry different licenses. If a file states that it is under a license different than LGPL 2.1, that license and its terms will apply to that file, and not LGPL 2.1. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. =head1 GENERAL PURPOSE METHODS =head2 new $pdf = PDF::Builder->new(%opts) =over Creates a new PDF object. B =back =over =item file If you will be saving it as a file and already know the filename, you can give the 'file' option to minimize possible memory requirements later on (the file is opened immediately for writing, rather than waiting until the C). The C may also be a filehandle. =item compress The 'compress' option can be given to specify stream compression: default is 'flate', 'none' (or 0) is no compression. No other compression methods are currently supported. =item outver The 'outver' option defaults to 1.4 as the output PDF version and the highest allowed feature version (attempts to use anything higher will give a warning). If an existing PDF with a higher version is read in, C will be increased to that version, with a warning. =item msgver The 'msgver' option value of 1 (default) gives a warning message if the 'outver' PDF level has to be bumped up due to either a higher PDF level file being read in, or a higher level feature was requested. A value of 0 suppresses the warning message. =item diaglevel The 'diaglevel' option can be given to specify the level of diagnostics given by IntegrityCheck(). The default is level 2 (errors and warnings). See L for more information. =back B $pdf = PDF::Builder->new(); ... print $pdf->to_string(); $pdf = PDF::Builder->new(compress => 'none'); # equivalent to $pdf->{'forcecompress'} = 'none'; (or older, 0) $pdf = PDF::Builder->new(); ... $pdf->saveas('our/new.pdf'); $pdf = PDF::Builder->new(file => 'our/new.pdf'); ... $pdf->save(); =cut sub new { my ($class, %opts) = @_; # copy dashed option names to preferred undashed names if (defined $opts{'-compress'} && !defined $opts{'compress'}) { $opts{'compress'} = delete($opts{'-compress'}); } if (defined $opts{'-diaglevel'} && !defined $opts{'diaglevel'}) { $opts{'diaglevel'} = delete($opts{'-diaglevel'}); } if (defined $opts{'-outver'} && !defined $opts{'outver'}) { $opts{'outver'} = delete($opts{'-outver'}); } if (defined $opts{'-msgver'} && !defined $opts{'msgver'}) { $opts{'msgver'} = delete($opts{'-msgver'}); } if (defined $opts{'-file'} && !defined $opts{'file'}) { $opts{'file'} = delete($opts{'-file'}); } my $self = {}; bless $self, $class; $self->{'pdf'} = PDF::Builder::Basic::PDF::File->new(); # make available to other routines $myself = $self->{'pdf'}; # default output version $self->{'pdf'}->{' version'} = $outVer; $self->{'pages'} = PDF::Builder::Basic::PDF::Pages->new($self->{'pdf'}); $self->{'pages'}->proc_set(qw(PDF Text ImageB ImageC ImageI)); $self->{'pages'}->{'Resources'} ||= PDFDict(); $self->{'pdf'}->new_obj($self->{'pages'}->{'Resources'}) unless $self->{'pages'}->{'Resources'}->is_obj($self->{'pdf'}); $self->{'catalog'} = $self->{'pdf'}->{'Root'}; weaken $self->{'catalog'}; $self->{'fonts'} = {}; $self->{'pagestack'} = []; $self->{'pdf'}->{' userUnit'} = 1.0; # default global User Unit $self->mediabox('letter'); # PDF defaults to US Letter 8.5in x 11in if (exists $opts{'compress'}) { $self->{'forcecompress'} = $opts{'compress'}; # at this point, no validation of given value! none/flate (0/1). # note that >0 is often used as equivalent to 'flate' } else { $self->{'forcecompress'} = 'flate'; # code should also allow integers 0 (= 'none') and >0 (= 'flate') # for compatibility with old usage where forcecompress is directly set. } if (exists $opts{'diaglevel'}) { my $diaglevel = $opts{'diaglevel'}; if ($diaglevel < 0 || $diaglevel > 5) { print "diaglevel must be in range 0-5. using 2\n"; $diaglevel = 2; } $self->{'diaglevel'} = $diaglevel; } else { $self->{'diaglevel'} = 2; # default: errors and warnings } $self->preferences(%opts); if (defined $opts{'outver'}) { if ($opts{'outver'} >= 1.4) { $self->{'pdf'}->{' version'} = $opts{'outver'}; } else { print STDERR "Invalid outver given, or less than 1.4. Ignored.\n"; } } if (defined $opts{'msgver'}) { if ($opts{'msgver'} == 0 || $opts{'msgver'} == 1) { $msgVer = $opts{'msgver'}; } else { print STDERR "Invalid msgver given, not 0 or 1. Ignored.\n"; } } if ($opts{'file'}) { $self->{'pdf'}->create_file($opts{'file'}); $self->{'partial_save'} = 1; } # used by info and infoMetaAttributes but not by their replacements $self->{'infoMeta'} = [qw(Author CreationDate ModDate Creator Producer Title Subject Keywords)]; my $version = eval { $PDF::Builder::VERSION } || '(Development Version)'; #$self->info('Producer' => "PDF::Builder $version [$^O]"); $self->info('Producer' => "PDF::Builder $version [see ". "https://github.com/PhilterPaper/Perl-PDF-Builder/blob/master/INFO/SUPPORT]"); $global_pdf = $self; # initialize Font Manager require PDF::Builder::FontManager; $self->{' FM'} = PDF::Builder::FontManager->new($self); return $self; } # end of new() =head2 default_page_size $pdf->default_page_size($size); # Set @rectangle = $pdf->default_page_size() # Get =over Set the default physical size for pages in the PDF. If called without arguments, return the coordinates of the rectangle describing the default physical page size. This is essentially an alternate method of defining the C call, and added for compatibility with PDF::API2. See L for possible values. =back =cut sub default_page_size { my $self = shift(); # Set if (@_) { return $self->default_page_boundaries(media => @_); } # Get my $boundaries = $self->default_page_boundaries(); return @{$boundaries->{'media'}}; } =head2 default_page_boundaries $pdf->default_page_boundaries(%boundaries); # Set %boundaries = $pdf->default_page_boundaries(); # Get =over Set default prepress page boundaries for pages in the PDF. If called without arguments, returns the coordinates of the rectangles describing each of the supported page boundaries. See the equivalent C method in L for details. =back =cut # Called by PDF::Builder::Page::boundaries via the default_page_* methods below sub _bounding_box { my $self = shift(); my $type = shift(); # Get unless (scalar @_) { unless ($self->{'pages'}->{$type}) { return if $type eq 'MediaBox'; # Use defaults per PDF 1.7 section 14.11.2 Page Boundaries return $self->_bounding_box('MediaBox') if $type eq 'CropBox'; return $self->_bounding_box('CropBox'); } return map { $_->val() } $self->{'pages'}->{$type}->elements(); } # Set $self->{'pages'}->{$type} = PDFArray(map { PDFNum(float($_)) } @_); return $self; } sub default_page_boundaries { return PDF::Builder::Page::boundaries(@_); } # Deprecated; use default_page_size or default_page_boundaries # alternate implementations of media, crop, etc. boxes #sub mediabox { # my $self = shift(); # return $self->_bounding_box('MediaBox') unless @_; # return $self->_bounding_box('MediaBox', page_size(@_)); #} # Deprecated; use default_page_boundaries #sub cropbox { # my $self = shift(); # return $self->_bounding_box('CropBox') unless @_; # return $self->_bounding_box('CropBox', page_size(@_)); #} # Deprecated; use default_page_boundaries #sub bleedbox { # my $self = shift(); # return $self->_bounding_box('BleedBox') unless @_; # return $self->_bounding_box('BleedBox', page_size(@_)); #} # Deprecated; use default_page_boundaries #sub trimbox { # my $self = shift(); # return $self->_bounding_box('TrimBox') unless @_; # return $self->_bounding_box('TrimBox', page_size(@_)); #} # Deprecated; use default_page_boundaries #sub artbox { # my $self = shift(); # return $self->_bounding_box('ArtBox') unless @_; # return $self->_bounding_box('ArtBox', page_size(@_)); #} =head1 INPUT/OUTPUT METHODS =head2 open $pdf = PDF::Builder->open($pdf_file, %opts) =over Opens an existing PDF file. See C for options. B =back $pdf = PDF::Builder->open('our/old.pdf'); ... $pdf->saveas('our/new.pdf'); $pdf = PDF::Builder->open('our/to/be/updated.pdf'); ... $pdf->update(); =cut sub open { ## no critic my ($class, $file, %opts) = @_; croak "File '$file' does not exist" unless -f $file; croak "File '$file' is not readable" unless -r $file; my $content; my $scalar_fh = FileHandle->new(); CORE::open($scalar_fh, '+<', \$content) or croak "Can't begin scalar IO"; binmode $scalar_fh, ':raw'; my $disk_fh = FileHandle->new(); CORE::open($disk_fh, '<', $file) or croak "Can't open $file for reading: $!"; binmode $disk_fh, ':raw'; $disk_fh->seek(0, 0); my $data; while (not $disk_fh->eof()) { $disk_fh->read($data, 512); $scalar_fh->print($data); } # check if final %%EOF lacks a carriage return on the end (add one) if ($data =~ m/%%EOF$/) { #print "open() says missing final EOF\n"; $scalar_fh->print("\n"); } $disk_fh->close(); $scalar_fh->seek(0, 0); my $self = $class->from_string($content, %opts); $self->{'pdf'}->{' fname'} = $file; return $self; } # end of open() =head2 from_string, open_scalar, openScalar $pdf = PDF::Builder->from_string($pdf_string, %opts) =over Opens a PDF contained in a string. See C for other options. =back =over =item diags => 1 Display warnings when non-conforming PDF structure is found, and fix up where possible. See L for more information. =back B # Read a PDF into a string, for the purpose of demonstration open $fh, 'our/old.pdf' or croak $@; undef $/; # Read the whole file at once $pdf_string = <$fh>; $pdf = PDF::Builder->from_string($pdf_string); ... $pdf->saveas('our/new.pdf'); =over B C C was formerly known as C (and even before that, as C), and this older name is still valid as an alternative to C. It is I that C will be deprecated and then removed some time in the future, so it may be advisable to use C in new work. =back =cut sub open_scalar { return from_string(@_); } ## no critic sub openScalar { return from_string(@_); } ## no critic sub from_string { my ($class, $content, %opts) = @_; # copy dashed option names to preferred undashed names if (defined $opts{'-diags'} && !defined $opts{'diags'}) { $opts{'diags'} = delete($opts{'-diags'}); } if (defined $opts{'-compress'} && !defined $opts{'compress'}) { $opts{'compress'} = delete($opts{'-compress'}); } if (defined $opts{'-diaglevel'} && !defined $opts{'diaglevel'}) { $opts{'diaglevel'} = delete($opts{'-diaglevel'}); } if (ref($class)) { $class = ref($class); } # my $self = {}; # bless $self, $class; # foreach my $parameter (keys %opts) { # $self->default($parameter, $opts{$parameter}); # } my $self = $class->new(%opts); $self->{'content_ref'} = \$content; my $diaglevel = 2; if (defined $self->{'diaglevel'}) { $diaglevel = $self->{'diaglevel'}; } if ($diaglevel < 0 || $diaglevel > 5) { $diaglevel = 2; } my $newVer = $self->IntegrityCheck($diaglevel, $content); # if Version override defined in PDF, need to overwrite the %PDF-x.y # statement with the new (if higher) value. it's too late to wait until # after File->open, as it's already complained about some >1.4 features. if (defined $newVer) { my ($verStr, $currentVer, $pos); $pos = index $content, "%PDF-"; if ($pos < 0) { croak "no PDF version found in PDF input!"; } # assume major and minor PDF version numbers max 2 digits each for now # (are 1 or 2 and 0-7 at this writing) $verStr = substr($content, $pos, 10); if ($verStr =~ m#^%PDF-(\d+)\.(\d+)#) { $currentVer = "$1.$2"; } else { croak "unable to get PDF input's version number."; } if ($newVer > $currentVer) { if (length($newVer) > length($currentVer)) { 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"; } else { if (length($newVer) < length($currentVer)) { # unlikely, but cover all the bases $newVer = substr($newVer, 0, length($currentVer)); } substr($content, $pos+5, length($newVer)) = $newVer; $self->version($newVer); } } } my $fh; CORE::open($fh, '+<', \$content) or croak "Can't begin scalar IO"; # this would replace any existing self->pdf with a new one $self->{'pdf'} = PDF::Builder::Basic::PDF::File->open($fh, 1, %opts); $self->{'pdf'}->{'Root'}->realise(); $self->{'pages'} = $self->{'pdf'}->{'Root'}->{'Pages'}->realise(); weaken $self->{'pages'}; $self->{'pdf'}->{' version'} ||= 1.4; # default minimum # if version higher than desired output PDF level, give warning and # bump up desired output PDF level $self->verCheckInput($self->{'pdf'}->{' version'}); my @pages = _proc_pages($self->{'pdf'}, $self->{'pages'}); $self->{'pagestack'} = [sort { $a->{' pnum'} <=> $b->{' pnum'} } @pages]; weaken $self->{'pagestack'}->[$_] for (0 .. scalar @{$self->{'pagestack'}}); $self->{'catalog'} = $self->{'pdf'}->{'Root'}; weaken $self->{'catalog'}; $self->{'opened_scalar'} = 1; if (exists $opts{'compress'}) { $self->{'forcecompress'} = $opts{'compress'}; # at this point, no validation of given value! none/flate (0/1). # note that >0 is often used as equivalent to 'flate' } else { $self->{'forcecompress'} = 'flate'; # code should also allow integers 0 (= 'none') and >0 (= 'flate') # for compatibility with old usage where forcecompress is directly set. } if (exists $opts{'diaglevel'}) { $self->{'diaglevel'} = $opts{'diaglevel'}; if ($self->{'diaglevel'} < 0 || $self->{'diaglevel'} > 5) { $self->{'diaglevel'} = 2; } } else { $self->{'diaglevel'} = 2; } $self->{'fonts'} = {}; $self->{'infoMeta'} = [qw(Author CreationDate ModDate Creator Producer Title Subject Keywords)]; return $self; } # end of from_string() =head2 to_string, stringify $string = $pdf->to_string() =over Return the document as a string and remove the object structure from memory. B Although the object C<$pdf> will still exist, it is no longer usable for any purpose after invoking this method! You will receive error messages about "can't call method new_obj on an undefined value". B =back $pdf = PDF::Builder->new(); ... print $pdf->to_string(); =over B C C was formerly known as C, and this older name is still valid as an alternative to C. It is I that C will be deprecated and then removed some time in the future, so it may be advisable to use C in new work. =back =cut # Maintainer's note: The object is being destroyed because it contains # circular references that would otherwise result in memory not being # freed if the object merely goes out of scope. If possible, the # circular references should be eliminated so that to_string doesn't # need to be destructive. See t/circular-references.t. # # I've opted not to just require a separate call to release() because # it would likely introduce memory leaks in many existing programs # that use this module. # - Steve S. (see bug RT 81530) sub stringify { return to_string(@_); } ## no critic sub to_string { my $self = shift(); my $string = ''; # is only set to 1 (within from_string()), otherwise is undef if ($self->{'opened_scalar'}) { $self->{'pdf'}->append_file(); $string = ${$self->{'content_ref'}}; } else { my $fh = FileHandle->new(); # we should be writing to the STRING $str CORE::open($fh, '>', \$string) || croak "Can't begin scalar IO"; $self->{'pdf'}->out_file($fh); $fh->close(); } # This can be eliminated once we're confident that circular references are # no longer an issue. See t/circular-references.t $self->end(); return $string; } =head2 finishobjects $pdf->finishobjects(@objects) =over Force objects to be written to file if possible. B =back $pdf = PDF::Builder->new(file => 'our/new.pdf'); ... $pdf->finishobjects($page, $gfx, $txt); ... $pdf->save(); =over B this method is now considered obsolete, and may be deprecated. It allows for objects to be written to disk in advance of finally saving and closing the file. Otherwise, it's no different than just calling C when all changes have been made. There's no memory advantage since C doesn't remove objects from memory. =back =cut # obsolete, use save instead # # This method allows for objects to be written to disk in advance of finally # saving and closing the file. Otherwise, it's no different than just calling # save when all changes have been made. There's no memory advantage since # ship_out doesn't remove objects from memory. sub finishobjects { my ($self, @objs) = @_; if ($self->{'opened_scalar'}) { croak "invalid method invocation: no file, use 'saveas' instead."; } elsif ($self->{'partial_save'}) { $self->{'pdf'}->ship_out(@objs); } else { croak "invalid method invocation: no file, use 'saveas' instead."; } return; } sub _proc_pages { my ($pdf, $object) = @_; if (defined $object->{'Resources'}) { eval { $object->{'Resources'}->realise(); }; } my @pages; $pdf->{' apipagecount'} ||= 0; foreach my $page ($object->{'Kids'}->elements()) { $page->realise(); if ($page->{'Type'}->val() eq 'Pages') { push @pages, _proc_pages($pdf, $page); } else { $pdf->{' apipagecount'}++; $page->{' pnum'} = $pdf->{' apipagecount'}; if (defined $page->{'Resources'}) { eval { $page->{'Resources'}->realise(); }; } push @pages, $page; } } return @pages; } # end of _proc_pages() =head2 update $pdf->update() =over Saves a previously opened document. B =back $pdf = PDF::Builder->open('our/to/be/updated.pdf'); ... $pdf->update(); =over B it is considered better to simply C the file, rather than calling C. They end up doing the same thing, anyway. This method may be deprecated in the future. =back =cut # obsolete, use save instead sub update { my $self = shift(); $self->saveas($self->{'pdf'}->{' fname'}); return; } =head2 saveas $pdf->saveas($file) =over Save the document to $file and remove the object structure from memory. B Although the object C<$pdf> will still exist, it is no longer usable for any purpose after invoking this method! You will receive error messages about "can't call method new_obj on an undefined value". B =back $pdf = PDF::Builder->new(); ... $pdf->saveas('our/new.pdf'); =cut sub saveas { my ($self, $file) = @_; if ($self->{'opened_scalar'}) { $self->{'pdf'}->append_file(); my $fh; CORE::open($fh, '>', $file) or croak "Can't open $file for writing: $!"; binmode($fh, ':raw'); print $fh ${$self->{'content_ref'}}; CORE::close($fh); } elsif ($self->{'partial_save'}) { $self->{'pdf'}->close_file(); } else { $self->{'pdf'}->out_file($file); } $self->end(); return; } =head2 save $pdf->save() $pdf->save(filename) =over Save the document to an already-defined file (or filename) and remove the object structure from memory. Optionally, a new filename may be given. B Although the object C<$pdf> will still exist, it is no longer usable for any purpose after invoking this method! You will receive error messages about "can't call method new_obj on an undefined value". B =back $pdf = PDF::Builder->new(file => 'file_to_output'); ... $pdf->save(); =over B now that C can take a filename as an argument, it effectively is interchangeable with C. This is strictly for compatibility with recent changes to PDF::API2. Unlike PDF::API2, we are not deprecating the C method, because in user interfaces, "save" normally means that the current filename is known and is to be used, while "saveas" normally means that (whether or not there is a current filename) a new filename is to be used. =back =cut sub save { my ($self, $file) = @_; if (defined $file) { return $self->saveas($file); } # NOTE: the current PDF::API2 version is quite different, but this may be # a consequence of merging save() and saveas(). Let's give this unchanged # version a try. if ($self->{'opened_scalar'}) { croak "Invalid method invocation: use 'saveas' instead of 'save'."; } elsif ($self->{'partial_save'}) { $self->{'pdf'}->close_file(); } else { croak "Invalid method invocation: use 'saveas' instead of 'save'."; } $self->end(); return; } =head2 close, release, end $pdf->close(); =over Close an open file (if relevant) and remove the object structure from memory. PDF::API2 contains circular references, so this call is necessary in long-running processes to keep from running out of memory. This will be called automatically when you save or stringify a PDF. You should only need to call it explicitly if you are reading PDF files and not writing them. B C and C =back =cut =head2 end $pdf->end() =over Remove the object structure from memory. PDF::Builder contains circular references, so this call is necessary in long-running processes to keep from running out of memory. This will be called automatically when you save or to_string a PDF. You should only need to call it explicitly if you are reading PDF files and not writing them. This (and I) are older and now deprecated names formerly used in PDF::API2 and PDF::Builder. You should try to avoid having to explicitly call them. =back =cut # Deprecated (renamed) sub release { return $_[0]->close(); } sub end { return $_[0]->close(); } sub close { my $self = shift(); $self->{'pdf'}->release() if defined $self->{'pdf'}; foreach my $key (keys %$self) { $self->{$key} = undef; delete $self->{$key}; } return; } =head2 METADATA METHODS =head3 title $title = $pdf->title(); $pdf = $pdf->title($title); =over Get/set/clear the document's title. =back =cut sub title { my $self = shift(); return $self->info_metadata('Title', @_); } =head3 author $author = $pdf->author(); $pdf = $pdf->author($author); =over Get/set/clear the name of the person who created the document. =back =cut sub author { my $self = shift(); return $self->info_metadata('Author', @_); } =head3 subject $subject = $pdf->subject(); $pdf = $pdf->subject($subject); =over Get/set/clear the subject of the document. =back =cut sub subject { my $self = shift(); return $self->info_metadata('Subject', @_); } =head3 keywords $keywords = $pdf->keywords(); $pdf = $pdf->keywords($keywords); =over Get/set/clear a space-separated string of keywords associated with the document. =back =cut sub keywords { my $self = shift(); return $self->info_metadata('Keywords', @_); } =head3 creator $creator = $pdf->creator(); $pdf = $pdf->creator($creator); =over Get/set/clear the name of the product that created the document prior to its conversion to PDF. =back =cut sub creator { my $self = shift(); return $self->info_metadata('Creator', @_); } =head3 producer $producer = $pdf->producer(); $pdf = $pdf->producer($producer); =over Get/set/clear the name of the product that converted the original document to PDF. PDF::Builder fills in this field when creating a PDF. =back =cut sub producer { my $self = shift(); return $self->info_metadata('Producer', @_); } =head3 created $date = $pdf->created(); $pdf = $pdf->created($date); =over Get/set/clear the document's creation date. The date format is C, where C is a static prefix identifying the string as a PDF date. The date may be truncated at any point after the year. C is one of C<+>, C<->, or C, with the following C representing an offset from UTC. See comments in the internal function C<_is_date()> for more information on the inconsistency of PDF standards on exactly what the date format should be! When setting the date, C will be prepended automatically if omitted. =back =cut sub created { my $self = shift(); return $self->info_metadata('CreationDate', @_); } =head3 modified $date = $pdf->modified(); $pdf = $pdf->modified($date); =over Get/set/clear the document's modification date. The date format is as described in C above. See comments in the internal function C<_is_date()> for more information on the inconsistency of PDF standards on exactly what the date format should be! =back =cut sub modified { my $self = shift(); return $self->info_metadata('ModDate', @_); } sub _is_date { my $value = shift(); # there are lists of leap seconds floating around, such as # https://www.ietf.org/timezones/data/leap-seconds.list # https://en.wikipedia.org/wiki/Leap_second my %leap_sec = ('06'=>{ 1972=>1, 1981=>1, 1982=>1, 1983=>1, 1985=>1, 1992=>1, 1993=>1, 1994=>1, 1997=>1, 2012=>1, 2015=>1}, '12'=>{ 1972=>1, 1973=>1, 1974=>1, 1975=>1, 1976=>1, 1977=>1, 1978=>1, 1979=>1, 1987=>1, 1989=>1, 1990=>1, 1995=>1, 1998=>1, 2005=>1, 2008=>1, 2016=>1}); # some sources list Dec 1971 as having a leap second, others don't # PDF 1.7 section 7.9.4 describes the required date format. Other than the # D: prefix and the year, all components are optional but must be present if # a later component is present. # # comments by PM Perry: # There is some conflict among various Adobe/ISO reference documents, as # well as ambiguity within them (e.g., the example drops the seconds # field, a trailing ' may or may not be required in a TZ offset). In # addition, the PDF format seems to be something of a subset of ISO 8601. # I have attempted to satisfy as many of the Adobe PDF reference documents # as I could, but there are no guarantees that all PDF editors and readers # will accept any given date/timestamp! # See https://www.rfc-editor.org/rfc/rfc3339#section-5.6, remembering that # many ISO 8601-compliant stamps will be considered invalid here. If there # is demand for it, additional formats might be supported, and even a # format or flag that says, "Here is my timestamp. Do not validate -- trust # me, I know what I'm doing!" my ($year, $month, $day, $hour, $minute, $second, $od, $oh, $om, $ts, $tz); if ($value =~ /([Z+-])/) { # should be only zero (leave od undef) or one $od = $1; } else { $od = undef; # in case value left over from previous data } # make sure od defined (and not empty) $od ||= 'Z'; # ts must always have something, tz might not ($ts, $tz) = split /[Z+-]/, $value; $tz ||= ''; return 0 unless $ts =~ /^D:([0-9]{4}) # D:YYYY (required) (?:([0-1][0-9]) # Month (01-12) (?:([0-3][0-9]) # Day (01-31) (?:([0-2][0-9]) # Hour (00-23) (?:([0-5][0-9]) # Minute (00-59) (?:([0-6][0-9]) # Second (00-59), also leap sec ?)?)?)?)?)?$/x; ($year, $month, $day, $hour, $minute, $second) = ($1, $2, $3, $4, $5, $6); $month ||= 1; $day ||= 1; $hour ||= 0; $minute ||= 0; $second ||= 0; # od is Z (tz s/b ''), or od is + or - with hh or more if ($od ne 'Z') { # must be + or -, and at least an hour given # ' before minutes (if given), optional ' after minutes # regexp should fail if tz is '' return 0 unless $tz =~ /^([0-2][0-9]) # UT Offset Hours (?:'?([0-5][0-9]) # UT Offset Minutes (?:' # optional ' ?)?)?$/x; ($oh, $om) = ($1, $2); $oh ||= 0; $om ||= 0; if ($oh == 0 && $om == 0) { # +/- 0 offset, so just make it Z $od = 'Z'; } } else { # explicit Z spec, shouldn't have an offset if ($tz ne '') { carp "Ignoring hour['minute] offset with Z timezone\n"; } $oh = $om = 0; } $oh ||= 0; $om ||= 0; if ($oh == 0 && $om == 0) { $od = 'Z'; } # Do some basic validation to catch accidental date formatting issues. # Complete date validation is out of scope. # add determination of leap year and leap day # treat ALL years as Gregorian calendar! my $is_leap; if ($year % 400 == 0) { $is_leap = 1; } elsif ($year % 100 == 0) { $is_leap = 0; } elsif ($year % 4 == 0) { $is_leap = 1; } else { $is_leap = 0; } my @mon_len = (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31); if ($is_leap) { $mon_len[1]++; } return 0 unless $month >= 1 and $month <= 12; return 0 unless $day >= 1 and $day <= 31; return 0 if $day > $mon_len[$month-1]; # added exact month length check return 0 unless $hour <= 23; return 0 unless $minute <= 59; return 0 unless $oh <= 23; return 0 unless $om <= 59; return 0 if $second > 60; if ($second == 60) { # claimed leap second -- verify # remember that +oh/om can place local date into next year! # correct local date and time (per offset) to UTC (Z) my $newy = $year; my $newM = $month; my $newd = $day; my $newh = $hour; my $newm = $minute; # assuming tz offset won't move more than 1 day either way # (max offset 12 or 13 hours?) # we're really only interested if date/time adjusted to Z is # June 30 or December 31 at 23:59:60Z, for certain years if ($od eq '+') { # sub h:m could put us in previous day (and month, but not year) # if not, it's not possibly 23:59:60Z $newh -= $oh; $newm -= $om; if ($newm < 0) { $newm += 60; $newh--; } if ($newh < 0) { $newh += 24; $newd--; if ($newd == 0) { # local was first day of Jan or Jul? $newM--; if ($newM == 0) { $newM = 12; $newd = 31; $newy--; } elsif ($newM == 6) { $newd = 30; } else { # last day of previous month, not Dec or Jun return 0; } } else { return 0; # wasn't last day of Dec or Jun (local date) } } else { # if got to here, didn't back up to previous day return 0; } } elsif ($od eq '-') { # add h:m could put us in next day (and month, and even year) $newh += $oh; $newm += $om; if ($newm > 59) { $newm -= 60; $newh++; } if ($newh > 23) { $newh -= 24; $newd++; if ($newd > $mon_len[$month-1]) { # local was last day of month, now (Z) 1st, wrong date $newM++; $newd = 1; if ($newM > 12) { $newM = 1; $newy++; } return 0; # ended up on 1st of a month, invalid leap second } } # only Dec 31 and Jun 30 are eligible for consideration if (!($newM == 6 && $newd == 30 || $newM == 12 && $newd == 31)) { return 0; } } else { # local time is already Z, just use newh and newm if (!($newM == 6 && $newd == 30 || $newM == 12 && $newd == 31)) { return 0; # not Dec 31 or Jun 30 } } # time newh:newm corrected to Z. check if 23:59. # date corrected to Z, is OK (Dec 31 or Jun 30), # check if is actual leap second date. if ($newh == 23 && $newm == 59 && # second is 60 defined $leap_sec{$newM}->{$newy} # assuming value is +1. if ever -1, need more code TBD # (23:59:58 would be last second of month) # already on last day of listed month. at 23:59:60Z? # valid leap second ) { } else { return 0; } } return 1; } =head3 info_metadata %info = $pdf->info_metadata(); # Get all keys and values $value = $pdf->info_metadata($key); # Get the value of one key $pdf = $pdf->info_metadata($key, $value); # Set the value of one key =over Get/set/clear a key in the document's information dictionary. The standard keys (title, author, etc.) have their own accessors, so this is primarily intended for interacting with custom metadata. Pass C as the value in order to remove the key from the dictionary. See comments in the internal function C<_is_date()> for more information on the inconsistency of PDF standards on exactly what the date format should be! This applies to CreationDate and ModDate keys. =back =cut sub info_metadata { my $self = shift(); my $field = shift(); # Return a hash of the Info table if called without arguments unless (defined $field) { return unless exists $self->{'pdf'}->{'Info'}; $self->{'pdf'}->{'Info'}->realise(); my %info; foreach my $key (keys %{$self->{'pdf'}->{'Info'}}) { next if $key =~ /^ /; next unless defined $self->{'pdf'}->{'Info'}->{$key}; $info{$key} = $self->{'pdf'}->{'Info'}->{$key}->val(); } return %info; } # Set if (@_) { my $value = shift(); $value = undef if defined($value) and not length($value); if ($field eq 'CreationDate' or $field eq 'ModDate') { if (defined ($value)) { # make sure date/timestamp starts with D: $value = 'D:' . $value unless $value =~ /^D:/; croak "Invalid date string: $value" unless _is_date($value); } } unless (exists $self->{'pdf'}->{'Info'}) { return $self unless defined $value; $self->{'pdf'}->{'Info'} = PDFDict(); $self->{'pdf'}->new_obj($self->{'pdf'}->{'Info'}); } else { $self->{'pdf'}->{'Info'}->realise(); } if (defined $value) { $self->{'pdf'}->{'Info'}->{$field} = PDFStr($value); } else { delete $self->{'pdf'}->{'Info'}->{$field}; } return $self; } # Get return unless $self->{'pdf'}->{'Info'}; $self->{'pdf'}->{'Info'}->realise(); return unless $self->{'pdf'}->{'Info'}->{$field}; return $self->{'pdf'}->{'Info'}->{$field}->val(); } =head3 info %infohash = $pdf->info() %infohash = $pdf->info(%infohash) =over Gets/sets the info structure of the document. See L section for an example of the use of this method. B this method is still available, for compatibility purposes. It is better to use individual accessors or C instead. =back =cut sub info { my ($self, %opt) = @_; if (not defined($self->{'pdf'}->{'Info'})) { $self->{'pdf'}->{'Info'} = PDFDict(); $self->{'pdf'}->new_obj($self->{'pdf'}->{'Info'}); } else { $self->{'pdf'}->{'Info'}->realise(); } # Maintenance Note: Since we're not shifting at the beginning of # this sub, this "if" will always be true if (scalar @_) { foreach my $k (@{$self->{'infoMeta'}}) { next unless defined $opt{$k}; $self->{'pdf'}->{'Info'}->{$k} = PDFString($opt{$k} || 'NONE', 'm'); } $self->{'pdf'}->out_obj($self->{'pdf'}->{'Info'}); } if (defined $self->{'pdf'}->{'Info'}) { %opt = (); foreach my $k (@{$self->{'infoMeta'}}) { next unless defined $self->{'pdf'}->{'Info'}->{$k}; $opt{$k} = $self->{'pdf'}->{'Info'}->{$k}->val(); if ((unpack('n', $opt{$k}) == 0xfffe) or (unpack('n', $opt{$k}) == 0xfeff)) { $opt{$k} = decode('UTF-16', $self->{'pdf'}->{'Info'}->{$k}->val()); } } } return %opt; } # end of info() =head3 infoMetaAttributes @metadata_attributes = $pdf->infoMetaAttributes() @metadata_attributes = $pdf->infoMetaAttributes(@metadata_attributes) =over Gets/sets the supported info-structure tags. B =back @attributes = $pdf->infoMetaAttributes; print "Supported Attributes: @attr\n"; @attributes = $pdf->infoMetaAttributes('CustomField1'); print "Supported Attributes: @attributes\n"; =over B this method is still available for compatibility purposes, but the use of C instead is encouraged. =back =cut sub infoMetaAttributes { my ($self, @attr) = @_; if (scalar @attr) { my %at = map { $_ => 1 } @{$self->{'infoMeta'}}, @attr; @{$self->{'infoMeta'}} = keys %at; } return @{$self->{'infoMeta'}}; } =head3 xml_metadata $xml = $pdf->xml_metadata(); $pdf = $pdf->xml_metadata($xml); =over Gets/sets the document's XML metadata stream. =back =cut sub xml_metadata { my ($self, $value) = @_; if (not defined($self->{'catalog'}->{'Metadata'})) { $self->{'catalog'}->{'Metadata'} = PDFDict(); $self->{'catalog'}->{'Metadata'}->{'Type'} = PDFName('Metadata'); $self->{'catalog'}->{'Metadata'}->{'Subtype'} = PDFName('XML'); $self->{'pdf'}->new_obj($self->{'catalog'}->{'Metadata'}); } else { $self->{'catalog'}->{'Metadata'}->realise(); $self->{'catalog'}->{'Metadata'}->{' stream'} = unfilter($self->{'catalog'}->{'Metadata'}->{'Filter'}, $self->{'catalog'}->{'Metadata'}->{' stream'}); delete $self->{'catalog'}->{'Metadata'}->{' nofilt'}; delete $self->{'catalog'}->{'Metadata'}->{'Filter'}; } my $md = $self->{'catalog'}->{'Metadata'}; if (defined $value) { $md->{' stream'} = $value; delete $md->{'Filter'}; delete $md->{' nofilt'}; $self->{'pdf'}->out_obj($md); $self->{'pdf'}->out_obj($self->{'catalog'}); } return $md->{' stream'}; } =head3 xmpMetadata $xml = $pdf->xmpMetadata() # Get $xml = $pdf->xmpMetadata($xml) # Set (also returns $xml value) =over Gets/sets the XMP XML data stream. See L section for an example of the use of this method. This method is considered B. Use C instead. =back =cut sub xmpMetadata { my ($self, $value) = @_; if (@_) { # Set my $value = shift(); $self->xml_metadata($value); return $value; } # Get return $self->xml_metadata(); } =head3 default $val = $pdf->default($parameter) $pdf->default($parameter, $value) =over Gets/sets the default value for a behavior of PDF::Builder. B =back =over =item nounrotate prohibits Builder from rotating imported/opened page to re-create a default pdf-context. =item pageencaps enables Builder's adding save/restore commands upon importing/opening pages to preserve graphics-state for modification. =item copyannots enables importing of annotations (B<*EXPERIMENTAL*>). =back =over B Perl::Critic (tools/1_pc.pl) has started flagging the name "default" as a reserved keyword in higher Perl versions. Use with caution, and be aware that this name I have to be changed in the future. =back =cut sub default { my ($self, $parameter, $value) = @_; # Parameter names may consist of lowercase letters, numbers, and underscores $parameter = lc $parameter; $parameter =~ s/[^a-z\d_]//g; my $previous_value = $self->{$parameter}; if (defined $value) { $self->{$parameter} = $value; } return $previous_value; } =head3 version $version = $pdf->version() # Get $version = $pdf->version($version) # Set (also returns newly set version) =over Gets/sets the PDF version (e.g., 1.5). For compatibility with earlier releases, if no decimal point is given, assume "1." precedes the number given. A warning message is given if you attempt to I the PDF version, as you might have already read in a higher level file, or used a higher level feature. See L for additional information on the C method. =back =cut sub version { my $self = shift(); # includes any %opts return $self->{'pdf'}->version(@_); # just pass it over to the "real" one } # when outputting a PDF feature, verCheckOutput(n, 'feature name') returns TRUE # if n > $pdf->{' version'), plus a warning message. It returns FALSE otherwise. # # a typical use: # # $PDF::Builder::global_pdf->verCheckOutput(1.6, "portzebie with foo-dangle"); # # if msgver defaults to 1, a message will be output if the output PDF version # has to be increased to 1.6 in order to use the "portzebie" feature # # this is still somewhat experimental, and as experience is gained, the code # might have to be modified. # sub verCheckOutput { my ($self, $PDFver, $featureName) = @_; # check if feature required PDF version is higher than planned output my $version = $self->version(); # current version if ($PDFver > $version) { if ($msgVer) { print "PDF version of requested feature '$featureName' is higher\n". " than current output version $version ". "(version reset to $PDFver)\n"; } $self->version($PDFver); return 1; } else { return 0; } } # when reading in a PDF, verCheckInput(n) gives a warning message if n (the PDF # version just read in) > version, and resets version to n. return TRUE if # version changed, FALSE otherwise. # # this is still somewhat experimental, and as experience is gained, the code # might have to be modified. # # WARNING: just because the PDF output version has been increased does NOT # guarantee that any particular content will be handled correctly! There are # many known cases of PDF 1.5 and up files being read in, that have content # that PDF::Builder does not handle correctly, corrupting the resulting PDF. # Pay attention to run-time warning messages that the PDF output level has # been increased due to a PDF file being read in, and check the resulting # file carefully. sub verCheckInput { my ($self, $PDFver) = @_; my $version = $self->version(); # warning message and bump up version if read-in PDF level higher if ($PDFver > $version) { if ($msgVer) { print "PDF version just read in is higher than version of $version (version reset to $PDFver)\n"; } $self->version($PDFver); return 1; } else { return 0; } } =head3 is_encrypted, isEncrypted $bool = $pdf->is_encrypted() =over Checks if the previously opened PDF is encrypted. B C This is the older name; it is kept for compatibility with PDF::API2. =back =cut sub isEncrypted { return is_encrypted(@_); } ## no critic sub is_encrypted { my $self = shift(); return defined($self->{'pdf'}->{'Encrypt'}) ? 1 : 0; } =head1 INTERACTIVE FEATURE METHODS =head2 outline, outlines $otls = $pdf->outline() =over Creates (if needed) and returns the document's 'outline' tree, which is also known as its 'bookmarks' or the 'table of contents', depending on the PDF reader being used. To examine or modify the outline tree, see L. B C This is the older name; it is kept for compatibility. =back =cut sub outlines { return outline(@_); } ## no critic sub outline { my $self = shift(); require PDF::Builder::Outlines; my $obj = $self->{'pdf'}->{'Root'}->{'Outlines'}; if ($obj) { $obj->realise(); bless $obj, 'PDF::Builder::Outlines'; $obj->{' api'} = $self; weaken $obj->{' api'}; } else { $obj = PDF::Builder::Outlines->new($self); $self->{'pdf'}->{'Root'}->{'Outlines'} = $obj; $self->{'pdf'}->new_obj($obj) unless $obj->is_obj($self->{'pdf'}); $self->{'pdf'}->out_obj($obj); $self->{'pdf'}->out_obj($self->{'pdf'}->{'Root'}); } return $obj; } #=item $pdf = $pdf->open_action($page, $location, @args); # #Set the destination in the PDF that should be displayed when the document is #opened. # #C<$page> may be either a page number or a page object. The other parameters are #as described in L. # #This has been split out from C for compatibility with PDF::API2. #It also can both set (assign) and get (query) the settings used. # #=cut # #sub open_action { # my ($self, $page, @args) = @_; # # # $page can be either a page number or a page object # $page = PDFNum($page) unless ref($page); # # require PDF::Builder::NamedDestination; # # PDF::API2 code incompatible with Builder! # #my $array = PDF::Builder::NamedDestination::_destination($page, @args); # # $self->{'catalog'}->{'OpenAction'} = $array; # $self->{'pdf'}->out_obj($self->{'catalog'}); # return $self; #} =head2 page_layout $layout = $pdf->page_layout(); $pdf = $pdf->page_layout($layout); =over Gets/sets the page layout that should be used when the PDF is opened. C<$layout> is one of the following: =back =over =item single_page (or undef) Display one page at a time. =item one_column Display the pages in one column (a.k.a. continuous). =item two_column_left Display the pages in two columns, with odd-numbered pages on the left. =item two_column_right Display the pages in two columns, with odd-numbered pages on the right. =item two_page_left Display two pages at a time, with odd-numbered pages on the left. =item two_page_right Display two pages at a time, with odd-numbered pages on the right. =back =over This has been split out from C for compatibility with PDF::API2. It also can both set (assign) and get (query) the settings used. =back =cut sub page_layout { my $self = shift(); unless (@_) { return 'single_page' unless $self->{'catalog'}->{'PageLayout'}; my $layout = $self->{'catalog'}->{'PageLayout'}->val(); return 'single_page' if $layout eq 'SinglePage'; return 'one_column' if $layout eq 'OneColumn'; return 'two_column_left' if $layout eq 'TwoColumnLeft'; return 'two_column_right' if $layout eq 'TwoColumnRight'; return 'two_page_left' if $layout eq 'TwoPageLeft'; return 'two_page_right' if $layout eq 'TwoPageRight'; warn "Unknown page layout: $layout"; return $layout; } my $name = shift() // 'single_page'; my $layout = ($name eq 'single_page' ? 'SinglePage' : $name eq 'one_column' ? 'OneColumn' : $name eq 'two_column_left' ? 'TwoColumnLeft' : $name eq 'two_column_right' ? 'TwoColumnRight' : $name eq 'two_page_left' ? 'TwoPageLeft' : $name eq 'two_page_right' ? 'TwoPageRight' : ''); croak "Invalid page layout: $name" unless $layout; $self->{'catalog'}->{'PageLayout'} = PDFName($layout); $self->{'pdf'}->out_obj($self->{'catalog'}); return $self; } =head2 page_mode $mode = $pdf->page_mode(); # Get $pdf = $pdf->page_mode($mode); # Set =over Gets/sets the page mode, which describes how the PDF should be displayed when opened. C<$mode> is one of the following: =back =over =item none (or undef) Neither outlines nor thumbnails should be displayed. =item outlines Show the document outline. =item thumbnails Show the page thumbnails. =item full_screen Open in full-screen mode, with no menu bar, window controls, or any other window visible. =item optional_content Show the optional content group panel. =item attachments Show the attachments panel. =back =over This has been split out from C for compatibility with PDF::API2. It also can both set (assign) and get (query) the settings used. =back =cut sub page_mode { my $self = shift(); unless (@_) { return 'none' unless $self->{'catalog'}->{'PageMode'}; my $mode = $self->{'catalog'}->{'PageMode'}->val(); return 'none' if $mode eq 'UseNone'; return 'outlines' if $mode eq 'UseOutlines'; return 'thumbnails' if $mode eq 'UseThumbs'; return 'full_screen' if $mode eq 'FullScreen'; return 'optional_content' if $mode eq 'UseOC'; return 'attachments' if $mode eq 'UseAttachments'; warn "Unknown page mode: $mode"; return $mode; } my $name = shift() // 'none'; my $mode = ($name eq 'none' ? 'UseNone' : $name eq 'outlines' ? 'UseOutlines' : $name eq 'thumbnails' ? 'UseThumbs' : $name eq 'full_screen' ? 'FullScreen' : $name eq 'optional_content' ? 'UseOC' : $name eq 'attachments' ? 'UseAttachments' : ''); croak "Invalid page mode: $name" unless $mode; $self->{'catalog'}->{'PageMode'} = PDFName($mode); $self->{'pdf'}->out_obj($self->{'catalog'}); return $self; } =head2 viewer_preferences %preferences = $pdf->viewer_preferences(); # Get $pdf = $pdf->viewer_preferences(%preferences); # Set =over Gets/sets PDF viewer preferences, as described in L. This has been split out from C for compatibility with PDF::API2. It also can both set (assign) and get (query) the settings used. =back =cut sub viewer_preferences { my $self = shift(); require PDF::Builder::ViewerPreferences; my $prefs = PDF::Builder::ViewerPreferences->new($self); unless (@_) { return $prefs->get_preferences(); } return $prefs->set_preferences(@_); } =head2 preferences $pdf->preferences(%opts) =over Controls viewing preferences for the PDF, including the B, B, B, and B Options. See L for details on all these option groups, and L for page positioning. B the various preferences have been split out into their own methods. It is preferred that you use these specific methods. =back =cut sub preferences { my ($self, %opts) = @_; # copy dashed option names to the preferred undashed format # Page Mode Options if (defined $opts{'-fullscreen'} && !defined $opts{'fullscreen'}) { $opts{'fullscreen'} = delete($opts{'-fullscreen'}); } if (defined $opts{'-thumbs'} && !defined $opts{'thumbs'}) { $opts{'thumbs'} = delete($opts{'-thumbs'}); } if (defined $opts{'-outlines'} && !defined $opts{'outlines'}) { $opts{'outlines'} = delete($opts{'-outlines'}); } # Page Layout Options if (defined $opts{'-singlepage'} && !defined $opts{'singlepage'}) { $opts{'singlepage'} = delete($opts{'-singlepage'}); } if (defined $opts{'-onecolumn'} && !defined $opts{'onecolumn'}) { $opts{'onecolumn'} = delete($opts{'-onecolumn'}); } if (defined $opts{'-twocolumnleft'} && !defined $opts{'twocolumnleft'}) { $opts{'twocolumnleft'} = delete($opts{'-twocolumnleft'}); } if (defined $opts{'-twocolumnright'} && !defined $opts{'twocolumnright'}) { $opts{'twocolumnright'} = delete($opts{'-twocolumnright'}); } # Viewer Preferences if (defined $opts{'-hidetoolbar'} && !defined $opts{'hidetoolbar'}) { $opts{'hidetoolbar'} = delete($opts{'-hidetoolbar'}); } if (defined $opts{'-hidemenubar'} && !defined $opts{'hidemenubar'}) { $opts{'hidemenubar'} = delete($opts{'-hidemenubar'}); } if (defined $opts{'-hidewindowui'} && !defined $opts{'hidewindowui'}) { $opts{'hidewindowui'} = delete($opts{'-hidewindowui'}); } if (defined $opts{'-fitwindow'} && !defined $opts{'fitwindow'}) { $opts{'fitwindow'} = delete($opts{'-fitwindow'}); } if (defined $opts{'-centerwindow'} && !defined $opts{'centerwindow'}) { $opts{'centerwindow'} = delete($opts{'-centerwindow'}); } if (defined $opts{'-displaytitle'} && !defined $opts{'displaytitle'}) { $opts{'displaytitle'} = delete($opts{'-displaytitle'}); } if (defined $opts{'-righttoleft'} && !defined $opts{'righttoleft'}) { $opts{'righttoleft'} = delete($opts{'-righttoleft'}); } if (defined $opts{'-afterfullscreenthumbs'} && !defined $opts{'afterfullscreenthumbs'}) { $opts{'afterfullscreenthumbs'} = delete($opts{'-afterfullscreenthumbs'}); } if (defined $opts{'-afterfullscreenoutlines'} && !defined $opts{'afterfullscreenoutlines'}) { $opts{'afterfullscreenoutlines'} = delete($opts{'-afterfullscreenoutlines'}); } if (defined $opts{'-printscalingnone'} && !defined $opts{'printscalingnone'}) { $opts{'printscalingnone'} = delete($opts{'-printscalingnone'}); } if (defined $opts{'-simplex'} && !defined $opts{'simplex'}) { $opts{'simplex'} = delete($opts{'-simplex'}); } if (defined $opts{'-duplexfliplongedge'} && !defined $opts{'duplexfliplongedge'}) { $opts{'duplexfliplongedge'} = delete($opts{'-duplexfliplongedge'}); } if (defined $opts{'-duplexflipshortedge'} && !defined $opts{'duplexflipshortedge'}) { $opts{'duplexflipshortedge'} = delete($opts{'-duplexflipshortedge'}); } # Open Action if (defined $opts{'-firstpage'} && !defined $opts{'firstpage'}) { $opts{'firstpage'} = delete($opts{'-firstpage'}); } if (defined $opts{'-fit'} && !defined $opts{'fit'}) { $opts{'fit'} = delete($opts{'-fit'}); } if (defined $opts{'-fith'} && !defined $opts{'fith'}) { $opts{'fith'} = delete($opts{'-fith'}); } if (defined $opts{'-fitb'} && !defined $opts{'fitb'}) { $opts{'fitb'} = delete($opts{'-fitb'}); } if (defined $opts{'-fitbh'} && !defined $opts{'fitbh'}) { $opts{'fitbh'} = delete($opts{'-fitbh'}); } if (defined $opts{'-fitv'} && !defined $opts{'fitv'}) { $opts{'fitv'} = delete($opts{'-fitv'}); } if (defined $opts{'-fitbv'} && !defined $opts{'fitbv'}) { $opts{'fitbv'} = delete($opts{'-fitbv'}); } if (defined $opts{'-fitr'} && !defined $opts{'fitr'}) { $opts{'fitr'} = delete($opts{'-fitr'}); } if (defined $opts{'-xyz'} && !defined $opts{'xyz'}) { $opts{'xyz'} = delete($opts{'-xyz'}); } # Page Mode Options if ($opts{'fullscreen'}) { $self->{'catalog'}->{'PageMode'} = PDFName('FullScreen'); } elsif ($opts{'thumbs'}) { $self->{'catalog'}->{'PageMode'} = PDFName('UseThumbs'); } elsif ($opts{'outlines'}) { $self->{'catalog'}->{'PageMode'} = PDFName('UseOutlines'); } else { $self->{'catalog'}->{'PageMode'} = PDFName('UseNone'); } # Page Layout Options if ($opts{'singlepage'}) { $self->{'catalog'}->{'PageLayout'} = PDFName('SinglePage'); } elsif ($opts{'onecolumn'}) { $self->{'catalog'}->{'PageLayout'} = PDFName('OneColumn'); } elsif ($opts{'twocolumnleft'}) { $self->{'catalog'}->{'PageLayout'} = PDFName('TwoColumnLeft'); } elsif ($opts{'twocolumnright'}) { $self->{'catalog'}->{'PageLayout'} = PDFName('TwoColumnRight'); } else { $self->{'catalog'}->{'PageLayout'} = PDFName('SinglePage'); } # Viewer Preferences $self->{'catalog'}->{'ViewerPreferences'} ||= PDFDict(); $self->{'catalog'}->{'ViewerPreferences'}->realise(); if ($opts{'hidetoolbar'}) { $self->{'catalog'}->{'ViewerPreferences'}->{'HideToolbar'} = PDFBool(1); } if ($opts{'hidemenubar'}) { $self->{'catalog'}->{'ViewerPreferences'}->{'HideMenubar'} = PDFBool(1); } if ($opts{'hidewindowui'}) { $self->{'catalog'}->{'ViewerPreferences'}->{'HideWindowUI'} = PDFBool(1); } if ($opts{'fitwindow'}) { $self->{'catalog'}->{'ViewerPreferences'}->{'FitWindow'} = PDFBool(1); } if ($opts{'centerwindow'}) { $self->{'catalog'}->{'ViewerPreferences'}->{'CenterWindow'} = PDFBool(1); } if ($opts{'displaytitle'}) { $self->{'catalog'}->{'ViewerPreferences'}->{'DisplayDocTitle'} = PDFBool(1); } if ($opts{'righttoleft'}) { $self->{'catalog'}->{'ViewerPreferences'}->{'Direction'} = PDFName('R2L'); } if ($opts{'afterfullscreenthumbs'}) { $self->{'catalog'}->{'ViewerPreferences'}->{'NonFullScreenPageMode'} = PDFName('UseThumbs'); } elsif ($opts{'afterfullscreenoutlines'}) { $self->{'catalog'}->{'ViewerPreferences'}->{'NonFullScreenPageMode'} = PDFName('UseOutlines'); } else { $self->{'catalog'}->{'ViewerPreferences'}->{'NonFullScreenPageMode'} = PDFName('UseNone'); } if ($opts{'printscalingnone'}) { $self->{'catalog'}->{'ViewerPreferences'}->{'PrintScaling'} = PDFName('None'); } if ($opts{'simplex'}) { $self->{'catalog'}->{'ViewerPreferences'}->{'Duplex'} = PDFName('Simplex'); } elsif ($opts{'duplexfliplongedge'}) { $self->{'catalog'}->{'ViewerPreferences'}->{'Duplex'} = PDFName('DuplexFlipLongEdge'); } elsif ($opts{'duplexflipshortedge'}) { $self->{'catalog'}->{'ViewerPreferences'}->{'Duplex'} = PDFName('DuplexFlipShortEdge'); } # Open Action if ($opts{'firstpage'}) { my ($page, %args) = @{$opts{'firstpage'}}; $args{'fit'} = 1 unless scalar keys %args; # $page can be either a page number (which needs to be wrapped # in PDFNum) or a page object (which doesn't). $page = PDFNum($page) unless ref($page); # copy dashed args names to preferred undashed names if (defined $args{'-fit'} && !defined $args{'fit'}) { $args{'fit'} = delete($args{'-fit'}); } if (defined $args{'-fith'} && !defined $args{'fith'}) { $args{'fith'} = delete($args{'-fith'}); } if (defined $args{'-fitb'} && !defined $args{'fitb'}) { $args{'fitb'} = delete($args{'-fitb'}); } if (defined $args{'-fitbh'} && !defined $args{'fitbh'}) { $args{'fitbh'} = delete($args{'-fitbh'}); } if (defined $args{'-fitv'} && !defined $args{'fitv'}) { $args{'fitv'} = delete($args{'-fitv'}); } if (defined $args{'-fitbv'} && !defined $args{'fitbv'}) { $args{'fitbv'} = delete($args{'-fitbv'}); } if (defined $args{'-fitr'} && !defined $args{'fitr'}) { $args{'fitr'} = delete($args{'-fitr'}); } if (defined $args{'-xyz'} && !defined $args{'xyz'}) { $args{'xyz'} = delete($args{'-xyz'}); } if (defined $args{'fit'}) { $self->{'catalog'}->{'OpenAction'} = PDFArray($page, PDFName('Fit')); } elsif (defined $args{'fith'}) { $self->{'catalog'}->{'OpenAction'} = PDFArray($page, PDFName('FitH'), PDFNum($args{'fith'})); } elsif (defined $args{'fitb'}) { $self->{'catalog'}->{'OpenAction'} = PDFArray($page, PDFName('FitB')); } elsif (defined $args{'fitbh'}) { $self->{'catalog'}->{'OpenAction'} = PDFArray($page, PDFName('FitBH'), PDFNum($args{'fitbh'})); } elsif (defined $args{'fitv'}) { $self->{'catalog'}->{'OpenAction'} = PDFArray($page, PDFName('FitV'), PDFNum($args{'fitv'})); } elsif (defined $args{'fitbv'}) { $self->{'catalog'}->{'OpenAction'} = PDFArray($page, PDFName('FitBV'), PDFNum($args{'fitbv'})); } elsif (defined $args{'fitr'}) { croak 'insufficient parameters to fitr => []' unless scalar @{$args{'fitr'}} == 4; $self->{'catalog'}->{'OpenAction'} = PDFArray($page, PDFName('FitR'), map { PDFNum($_) } @{$args{'fitr'}}); } elsif (defined $args{'xyz'}) { croak 'insufficient parameters to xyz => []' unless scalar @{$args{'xyz'}} == 3; $self->{'catalog'}->{'OpenAction'} = PDFArray($page, PDFName('XYZ'), map { PDFNum($_) } @{$args{'xyz'}}); } } $self->{'pdf'}->out_obj($self->{'catalog'}); return $self; } # end of preferences() sub proc_pages { my ($pdf, $object) = @_; if (defined $object->{'Resources'}) { eval { $object->{'Resources'}->realise(); }; } my @pages; $pdf->{' apipagecount'} ||= 0; foreach my $page ($object->{'Kids'}->elements()) { $page->realise(); if ($page->{'Type'}->val() eq 'Pages') { push @pages, proc_pages($pdf, $page); } else { $pdf->{' apipagecount'}++; $page->{' pnum'} = $pdf->{' apipagecount'}; if (defined $page->{'Resources'}) { eval { $page->{'Resources'}->realise(); }; } push @pages, $page; } } return @pages; } =head1 PAGE METHODS =head2 page $page = $pdf->page() $page = $pdf->page($page_number) =over Returns a I page object. By default, the page is added to the end of the document. If you give an existing page number, the new page will be inserted in that position, pushing existing pages back by 1 (e.g., C would insert an empty page 5, with the old page 5 now page 6, etc. If $page_number is -1, the new page is inserted as the second-to-last page; if $page_number is 0, the new page is inserted as the last page. B $pdf = PDF::Builder->new(); # Add a page. This becomes page 1. $page = $pdf->page(); # Add a new first page. $page becomes page 2. $another_page = $pdf->page(1); =back =cut sub page { my $self = shift(); my $index = shift() || 0; # default to new "last" page my $page; if ($index == 0) { $page = PDF::Builder::Page->new($self->{'pdf'}, $self->{'pages'}); } else { $page = PDF::Builder::Page->new($self->{'pdf'}, $self->{'pages'}, $index-1); } $page->{' apipdf'} = $self->{'pdf'}; $page->{' api'} = $self; weaken $page->{' apipdf'}; weaken $page->{' api'}; $self->{'pdf'}->out_obj($page); $self->{'pdf'}->out_obj($self->{'pages'}); # fix any bad $index value my $pgs_size = @{$self->{'pagestack'}}; if ($pgs_size == 0) { # empty page list, can only add at end warn "page($index) on empty page stack is out of range, use page() or page(0)" if ($index != 0); $index = 0; } elsif ($pgs_size < -$index) { # index < 0 warn "page($index) out of range, set to page(1) (before first)"; $index = 1; } elsif ($pgs_size < $index) { # index > 0 warn "page($index) out of range, set to page(0) (after last)"; $index = 0; } if ($index == 0) { push @{$self->{'pagestack'}}, $page; weaken $self->{'pagestack'}->[-1]; } elsif ($index < 0) { # note that the new element's number is one less than $index, # since we inserted _before_ $index value! splice @{$self->{'pagestack'}}, $index, 0, $page; weaken $self->{'pagestack'}->[$index-1]; } else { # index > 0 splice @{$self->{'pagestack'}}, $index-1, 0, $page; weaken $self->{'pagestack'}->[$index-1]; } # $page->{'Resources'}=$self->{'pages'}->{'Resources'}; return $page; } # end of page() =head2 open_page, openpage $page = $pdf->open_page($page_number) =over Returns the L object of page $page_number. This is similar to C<< $page = $pdf->page() >>, except that C<$page> is I a new, empty page; but contains the contents of that existing page. If C<$page_number> is 0, -1, or unspecified, it will return the last page in the document. If the requested page is out of range, the C<$page> returned will be undefined. B =back $pdf = PDF::Builder->open('our/99page.pdf'); $page = $pdf->open_page(1); # returns the first page $page = $pdf->open_page(99); # returns the last page $page = $pdf->open_page(-1); # returns the last page $page = $pdf->open_page(999); # returns undef $page = $pdf->open_page(0); # returns the last page $page = $pdf->open_page(); # returns the last page =over B C This is the older name; it is kept for compatibility until after June 2023 (deprecated, as previously announced). =back =cut sub openpage { return open_page(@_); } ## no critic sub open_page { my $self = shift(); my $index = shift() || 0; my ($page, $rotate, $media, $trans); if ($index == 0) { $page = $self->{'pagestack'}->[-1]; } elsif ($index < 0) { $page = $self->{'pagestack'}->[$index]; } else { $page = $self->{'pagestack'}->[$index - 1]; } return unless ref($page); if (ref($page) ne 'PDF::Builder::Page') { bless $page, 'PDF::Builder::Page'; $page->{' apipdf'} = $self->{'pdf'}; $page->{' api'} = $self; weaken $page->{' apipdf'}; weaken $page->{' api'}; $self->{'pdf'}->out_obj($page); if (($rotate = $page->find_prop('Rotate')) and not $page->{' opened'}) { $rotate = ($rotate->val() + 360) % 360; if ($rotate != 0 and not $self->default('nounrotate')) { $page->{'Rotate'} = PDFNum(0); foreach my $mediatype (qw(MediaBox CropBox BleedBox TrimBox ArtBox)) { if ($media = $page->find_prop($mediatype)) { $media = [ map { $_->val() } $media->elements() ]; } else { $media = [0, 0, 612, 792]; # US Letter default next if $mediatype ne 'MediaBox'; } if ($rotate == 90) { $trans = "0 -1 1 0 0 $media->[2] cm" if $mediatype eq 'MediaBox'; $media = [$media->[1], $media->[0], $media->[3], $media->[2]]; } elsif ($rotate == 180) { $trans = "-1 0 0 -1 $media->[2] $media->[3] cm" if $mediatype eq 'MediaBox'; } elsif ($rotate == 270) { $trans = "0 1 -1 0 $media->[3] 0 cm" if $mediatype eq 'MediaBox'; $media = [$media->[1], $media->[0], $media->[3], $media->[2]]; } $page->{$mediatype} = PDFArray(map { PDFNum($_) } @$media); } } else { $trans = ''; } } else { $trans = ''; } if (defined $page->{'Contents'} and not $page->{' opened'}) { $page->fixcontents(); my $uncontent = delete $page->{'Contents'}; my $content = $page->gfx(); $content->add(" $trans "); if ($self->default('pageencaps')) { $content->{' stream'} .= ' q '; } foreach my $k ($uncontent->elements()) { $k->realise(); $content->{' stream'} .= ' ' . unfilter($k->{'Filter'}, $k->{' stream'}) . ' '; } if ($self->default('pageencaps')) { $content->{' stream'} .= ' Q '; } # if we like compress we will do it now to do quicker saves if ($self->{'forcecompress'} eq 'flate' || $self->{'forcecompress'} =~ m/^[1-9]\d*$/) { $content->{' stream'} = dofilter($content->{'Filter'}, $content->{' stream'}); $content->{' nofilt'} = 1; delete $content->{'-docompress'}; $content->{'Length'} = PDFNum(length($content->{' stream'})); } } $page->{' opened'} = 1; } $self->{'pdf'}->out_obj($page); $self->{'pdf'}->out_obj($self->{'pages'}); $page->{' apipdf'} = $self->{'pdf'}; $page->{' api'} = $self; weaken $page->{' apipdf'}; weaken $page->{' api'}; return $page; } # end of open_page() =head2 import_page, importpage $page = $pdf->import_page($source_pdf) $page = $pdf->import_page($source_pdf, $source_page_number) $page = $pdf->import_page($source_pdf, $source_page_number, $target_page_number) $page = $pdf->import_page($source_pdf, $source_page_number, $target_page_object) =over Imports a page from $source_pdf and adds it to the specified position in $pdf. If the C<$source_page_number> is omitted, 0, or -1; the last page of the source is imported. If the C<$target_page_number> is omitted, 0, or -1; the imported page will be placed as the new last page of the target (C<$pdf>). Otherwise, as with the C method, the page will be inserted before an existing page of that number. B If you pass a page I instead of a page I for C<$target_page_number>, the contents of the page will be B into the existing page. B =back my $pdf = PDF::Builder->new(); my $source = PDF::Builder->open('source.pdf'); # Add page 2 from the old PDF as page 1 of the new PDF my $page = $pdf->import_page($source, 2); $pdf->saveas('sample.pdf'); =over B You can only import a page from an existing PDF file. B importpage This name is still valid in PDF::API2, so it is included here for compatiblity. =back =cut # removed years ago, but is still in API2, so for code compatibility... sub importpage{ return import_page(@_); } ## no critic sub import_page { my ($self, $s_pdf, $s_idx, $t_idx) = @_; $s_idx ||= 0; # default to last page $t_idx ||= 0; # default to last page my ($s_page, $t_page); unless (ref($s_pdf) and $s_pdf->isa('PDF::Builder')) { croak "Invalid usage: first argument must be PDF::Builder instance, not: " . ref($s_pdf); } if (ref($s_idx) eq 'PDF::Builder::Page') { $s_page = $s_idx; } else { $s_page = $s_pdf->open_page($s_idx); croak "Unable to open page '$s_idx' in source PDF" unless defined $s_page; } if (ref($t_idx) eq 'PDF::Builder::Page') { $t_page = $t_idx; } else { if ($self->pages() < $t_idx) { $t_page = $self->page(); } else { $t_page = $self->page($t_idx); } } $self->{'apiimportcache'} = $self->{'apiimportcache'} || {}; $self->{'apiimportcache'}->{$s_pdf} = $self->{'apiimportcache'}->{$s_pdf} || {}; # we now import into a form to keep # all those nasty resources from polluting # our very own resource naming space. my $xo = $self->importPageIntoForm($s_pdf, $s_page); # copy all page dimensions foreach my $k (qw(MediaBox ArtBox TrimBox BleedBox CropBox)) { my $prop = $s_page->find_prop($k); next unless defined $prop; my $box = _walk_obj({}, $s_pdf->{'pdf'}, $self->{'pdf'}, $prop); my $method = lc $k; $t_page->$method(map { $_->val() } $box->elements()); } $t_page->gfx()->formimage($xo, 0, 0, 1); # copy annotations and/or form elements as well if (exists $s_page->{'Annots'} and $s_page->{'Annots'} and $self->{'copyannots'}) { # first set up the AcroForm, if required my $AcroForm; if (my $a = $s_pdf->{'pdf'}->{'Root'}->realise()->{'AcroForm'}) { $a->realise(); $AcroForm = _walk_obj({}, $s_pdf->{'pdf'}, $self->{'pdf'}, $a, qw(NeedAppearances SigFlags CO DR DA Q)); } my @Fields = (); my @Annots = (); foreach my $a ($s_page->{'Annots'}->elements()) { $a->realise(); my $t_a = PDFDict(); $self->{'pdf'}->new_obj($t_a); # these objects are likely to be both annotations and Acroform fields # key names are copied from PDF Reference 1.4 (Tables) my @k = ( qw( Type Subtype Contents P Rect NM M F BS Border AP AS C CA T Popup A AA StructParent Rotate ), # Annotations - Common (8.10) qw( Subtype Contents Open Name ), # Text Annotations (8.15) qw( Subtype Contents Dest H PA ), # Link Annotations (8.16) qw( Subtype Contents DA Q ), # Free Text Annotations (8.17) qw( Subtype Contents L BS LE IC ), # Line Annotations (8.18) qw( Subtype Contents BS IC ), # Square and Circle Annotations (8.20) qw( Subtype Contents QuadPoints ), # Markup Annotations (8.21) qw( Subtype Contents Name ), # Rubber Stamp Annotations (8.22) qw( Subtype Contents InkList BS ), # Ink Annotations (8.23) qw( Subtype Contents Parent Open ), # Popup Annotations (8.24) qw( Subtype FS Contents Name ), # File Attachment Annotations (8.25) qw( Subtype Sound Contents Name ), # Sound Annotations (8.26) qw( Subtype Movie Contents A ), # Movie Annotations (8.27) qw( Subtype Contents H MK ), # Widget Annotations (8.28) # Printers Mark Annotations (none) # Trap Network Annotations (none) ); push @k, ( qw( Subtype FT Parent Kids T TU TM Ff V DV AA ), # Fields - Common (8.49) qw( DR DA Q ), # Fields containing variable text (8.51) qw( Opt ), # Checkbox field (8.54) qw( Opt ), # Radio field (8.55) qw( MaxLen ), # Text field (8.57) qw( Opt TI I ), # Choice field (8.59) ) if $AcroForm; # sorting out dupes my %ky = map { $_ => 1 } @k; # we do P separately, as it points to the page the Annotation is on delete $ky{'P'}; # copy everything else foreach my $k (keys %ky) { next unless defined $a->{$k}; $a->{$k}->realise(); $t_a->{$k} = _walk_obj({}, $s_pdf->{'pdf'}, $self->{'pdf'}, $a->{$k}); } $t_a->{'P'} = $t_page; push @Annots, $t_a; push @Fields, $t_a if ($AcroForm and $t_a->{'Subtype'}->val() eq 'Widget'); } $t_page->{'Annots'} = PDFArray(@Annots); $AcroForm->{'Fields'} = PDFArray(@Fields) if $AcroForm; $self->{'pdf'}->{'Root'}->{'AcroForm'} = $AcroForm; } $t_page->{' imported'} = 1; $self->{'pdf'}->out_obj($t_page); $self->{'pdf'}->out_obj($self->{'pages'}); return $t_page; } # end of import_page() =head2 embed_page, importPageIntoForm $xoform = $pdf->embed_page($source_pdf, $source_page_number) =over Returns a Form XObject created by extracting the specified page from C<$source_pdf>. This is useful if you want to transpose the imported page somewhat differently onto a page (e.g. two-up, four-up, etc.). If C<$source_page_number> is 0 or -1, it will return the last page in the document. The B value for the C<$source_page_number> is 0 (return last page). B =back # take page 2 of source.pdf and add to empty doc sample.pdf at half size # note that sample.pdf could be an existing document! # my $pdf = PDF::Builder->new(); # so far, empty document my $source = PDF::Builder->open('source.pdf'); # content to copy over my $page = $pdf->page(); # place to be actually updated # Import Page 2 from the source PDF my $xo = $pdf->embed_page($source, 2); # Add it to the new PDF's first page at 1/2 scale my ($x, $y) = (0, 0); $page->object($xo, $x, $y, 0.5); $pdf->save('sample.pdf'); =over B You can only import a page from an existing PDF file. B C This is the older name; it is kept for compatibility. =back =cut sub importPageIntoForm { return embed_page(@_); } ## no critic sub embed_page { my ($self, $s_pdf, $s_idx) = @_; $s_idx ||= 0; unless (ref($s_pdf) and $s_pdf->isa('PDF::Builder')) { croak "Invalid usage: first argument must be PDF::Builder instance, not: " . ref($s_pdf); } my ($s_page, $xo); $xo = $self->xo_form(); if (ref($s_idx) eq 'PDF::Builder::Page') { $s_page = $s_idx; } else { $s_page = $s_pdf->open_page($s_idx); croak "Unable to open page '$s_idx' in source PDF" unless defined $s_page; } $self->{'apiimportcache'} ||= {}; $self->{'apiimportcache'}->{$s_pdf} ||= {}; # This should never get past MediaBox, since it's a required object. foreach my $k (qw(MediaBox ArtBox TrimBox BleedBox CropBox)) { #next unless defined $s_page->{$k}; #my $box = _walk_obj($self->{'apiimportcache'}->{$s_pdf}, $s_pdf->{'pdf'}, # $self->{'pdf'}, $s_page->{$k}); next unless defined $s_page->find_prop($k); my $box = _walk_obj($self->{'apiimportcache'}->{$s_pdf}, $s_pdf->{'pdf'}, $self->{'pdf'}, $s_page->find_prop($k)); $xo->bbox(map { $_->val() } $box->elements()); last; } $xo->bbox(0,0, 612,792) unless defined $xo->{'BBox'}; # US Letter default foreach my $k (qw(Resources)) { $s_page->{$k} = $s_page->find_prop($k); next unless defined $s_page->{$k}; $s_page->{$k}->realise() if ref($s_page->{$k}) =~ /Objind$/; foreach my $sk (qw(XObject ExtGState Font ProcSet Properties ColorSpace Pattern Shading)) { next unless defined $s_page->{$k}->{$sk}; $s_page->{$k}->{$sk}->realise() if ref($s_page->{$k}->{$sk}) =~ /Objind$/; foreach my $ssk (keys %{$s_page->{$k}->{$sk}}) { next if $ssk =~ /^ /; $xo->resource($sk, $ssk, _walk_obj($self->{'apiimportcache'}->{$s_pdf}, $s_pdf->{'pdf'}, $self->{'pdf'}, $s_page->{$k}->{$sk}->{$ssk})); } } } # create a whole content stream ## technically it is possible to submit an unfinished ## (e.g., newly created) source-page, but that's nonsense, ## so we expect a page fixed by open_page and croak otherwise unless ($s_page->{' opened'}) { croak "Pages may only be imported from a complete PDF. Save and reopen the source PDF object first."; } if (defined $s_page->{'Contents'}) { $s_page->fixcontents(); $xo->{' stream'} = ''; # open_page pages only contain one stream my ($k) = $s_page->{'Contents'}->elements(); $k->realise(); if ($k->{' nofilt'}) { # we have a finished stream here, so we unfilter $xo->add('q', unfilter($k->{'Filter'}, $k->{' stream'}), 'Q'); } else { # stream is an unfinished/unfiltered content # so we just copy it and add the required "qQ" $xo->add('q', $k->{' stream'}, 'Q'); } $xo->compressFlate() if $self->{'forcecompress'} eq 'flate' || $self->{'forcecompress'} =~ m/^[1-9]\d*$/; } return $xo; } # end of embed_page() # internal utility used by embed_page and import_page sub _walk_obj { my ($object_cache, $source_pdf, $target_pdf, $source_object, @keys) = @_; if (ref($source_object) =~ /Objind$/) { $source_object->realise(); } return $object_cache->{scalar $source_object} if defined $object_cache->{scalar $source_object}; #croak "infinite loop while copying objects" if $source_object->{' copied'}; my $target_object = $source_object->copy($source_pdf); ## thanks to: yaheath // Fri, 17 Sep 2004 #$source_object->{' copied'} = 1; $target_pdf->new_obj($target_object) if $source_object->is_obj($source_pdf); $object_cache->{scalar $source_object} = $target_object; if (ref($source_object) =~ /Array$/) { $target_object->{' val'} = []; foreach my $k ($source_object->elements()) { $k->realise() if ref($k) =~ /Objind$/; $target_object->add_elements(_walk_obj($object_cache, $source_pdf, $target_pdf, $k)); } } elsif (ref($source_object) =~ /Dict$/) { @keys = keys(%$target_object) unless scalar @keys; foreach my $k (@keys) { next if $k =~ /^ /; next unless defined $source_object->{$k}; $target_object->{$k} = _walk_obj($object_cache, $source_pdf, $target_pdf, $source_object->{$k}); } if ($source_object->{' stream'}) { if ($target_object->{'Filter'}) { $target_object->{' nofilt'} = 1; } else { delete $target_object->{' nofilt'}; $target_object->{'Filter'} = PDFArray(PDFName('FlateDecode')); } $target_object->{' stream'} = $source_object->{' stream'}; } } delete $target_object->{' streamloc'}; delete $target_object->{' streamsrc'}; return $target_object; } # end of _walk_obj() =head2 page_count, pages $count = $pdf->page_count() =over Returns the number of pages in the document. B C This is the old name; it is kept for compatibility. =back =cut sub pages { return page_count(@_); } ## no critic sub page_count { my $self = shift(); return scalar @{$self->{'pagestack'}}; } =head2 page_labels, pageLabel $pdf->page_labels($page_number, %opts) =over Sets page label numbering format, for the PDF Reader's page-selection slider thumb (I the outline/bookmarks). At this time, there is no method to automatically synchronize a page's label with the outline/bookmarks, or to somewhere on the printed page. Depending on the PDF Reader you are using, this formatted page label I show up in the reader control area as the current page number. B =back =over =item 1. The given page index started at 0 for the old method (C), which is the internal PDF array index, while for the new method (C) it starts with 1, the visible page number! Don't get confused. =item 2. Options for the old method (C) were a hashref, while for the new method (C) it is a hash. This permits pageLabel() to accept I page number schemes in one call, rather than one per call as per page_labels(). =item 3. Many PDF readers do not support page labels; they simply (at most) label the sliding thumb with the physical page number. Adobe Acrobat Reader (free version) appears to have a bug in some versions, where if the only page label is 'decimal' (the default), it labels the thumb as though no page labels were defined ("Page I of I"). You may be able to get around this problem by using an explicit B option value, e.g., C<'start' =E 1>. =back # Generate a 30-page PDF my $pdf = PDF::Builder->new(); $pdf->page() for 1..30; # Number pages i to v, 1 to 20, and A-1 to A-5, respectively $pdf->page_labels(1, 'style' => 'roman'); $pdf->page_labels(6, 'style' => 'decimal'); $pdf->page_labels(26, 'style' => 'decimal', 'prefix' => 'A-'); or... $pdf->pageLabel(0, { style => 'roman' }, 5, { style => 'decimal' }, 25, { style => 'decimal', prefix => 'A-' }); $pdf->save('sample.pdf'); B =over =item style B (I,II,III,...), B (i,ii,iii,...), B (1,2,3,...), B (A,B,C,...), B (a,b,c,...), or B. This is the styling of the counter part of the label (unless C, in which case there is no counter output). =item start (Re)start numbering the I at given page number (this is a decimal integer, I the styled counter). By default it starts at 1, and B to 1 at each call to C! You need to explicitly give C if you want to I counting at the current page number when you call C, whether or not you are changing the format. Also note that the counter starts at physical page B<1>, while the page C<$index> number in the C call (as well as the PDF PageLabels dictionary) starts at logical page (index) B<0>. =item prefix Text prefix for numbering, such as an Appendix letter B. If C, and an existing $style # hashref, update $style and return it sub _process_style_tag { my ($style, $text) = @_; # expect sets of selector { property: value; ... } # break up into selector => { property => value, ... } # replace or add to existing $style # note that a selector may be a tagName, a .className, or an #idName $text =~ s/\n/ /sg; # replace end-of-lines with spaces while ($text ne '') { my $selector; if ($text =~ s/^\s+//) { # remove leading whitespace if ($text eq '') { last; } } if ($text =~ s/([^\s]+)//) { # extract selector $selector = $1; } if ($text =~ s/^\s*{//) { # remove whitespace up through { if ($text eq '') { last; } } # one or more property-name: value; sets (; might be missing on last) # go into %prop_val. we don't expect to see any } within a property # value string. if ($text =~ s/([^}]+)//) { $style->{$selector} = _process_style_string({}, $1); } if ($text =~ s/^}\s*//) { # remove closing } and whitespace if ($text eq '') { last; } } } return $style; } # end of _process_style_tag() # decompose a style string into property-value pairs. used for both