PDF-FromHTML-0.33/000755 000765 000024 00000000000 13554103476 014266 5ustar00audreytstaff000000 000000 PDF-FromHTML-0.33/inc/000755 000765 000024 00000000000 13554103473 015034 5ustar00audreytstaff000000 000000 PDF-FromHTML-0.33/SIGNATURE000644 000765 000024 00000014737 13554103476 015566 0ustar00audreytstaff000000 000000 This file contains message digests of all files listed in MANIFEST, signed via the Module::Signature module, version 0.83. To verify the content in this distribution, first make sure you have Module::Signature installed, then type: % cpansign -v It will check each file's integrity, as well as the signature's validity. If "==> Signature verified OK! <==" is not displayed, the distribution may already have been compromised, and you should not run its Makefile.PL or Build.PL. -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA256 SHA256 da03ce7583499aac306665321ec6cb5b9f46b82fd94f4677c6b04f92b549dead Changes SHA256 7ed753d78c572d9bd67f289e056c8aeb817b4a3dd7220317c0a88f10fab5dc94 MANIFEST SHA256 0641d458c217049205d3b0ff8fda3e1594297e2ca6b4e266d55419ac9ffcac6b META.yml SHA256 07bb7f4541d6fe645a3be776359f3d701e825e7e4ab38cd8939190c082be27e8 Makefile.PL SHA256 863890c26b848b0fb1d8ad0a26bd039599bb9a921d5af521e2dee757df542f83 README SHA256 7fe8013fad8ecb0b9ef8bad3fd7287486c1c61c776f76beb7d9d24e06ee3ab44 inc/Module/AutoInstall.pm SHA256 67d139199c03b8bf8447a5a62f0d0b6dc1bd5bf6dbe04de6d21998c577823ed6 inc/Module/Install.pm SHA256 1e48ae2cb24e1d16193d476e735579dfcd0eefb3685921ad4736390df75d939b inc/Module/Install/AutoInstall.pm SHA256 6ebcc53a161dd5dc0aae69e4704575f2b00181901d768a82e26722a309cfdbe4 inc/Module/Install/Base.pm SHA256 d3f8c839d03fd21c197d05362dbb277cd7cadb15da6390d124b61e851f15146e inc/Module/Install/Can.pm SHA256 e9e72e18921c10c87bc4ea4c20af83e52015b9f5775d00ac64073042403717ca inc/Module/Install/Fetch.pm SHA256 a97bf661b739643c3adee064addf7a85f22e25e1bbffc137974cd8754ffa5c66 inc/Module/Install/Include.pm SHA256 a7a681bf2c9eee58a372cb642ffe42b0301d1200432ba8de9f7791cd1ecc9827 inc/Module/Install/Makefile.pm SHA256 aa887fa65a5eb6bbd1805706ce298b3f3cd55b353ecfd37aa7d35ae419331a49 inc/Module/Install/Metadata.pm SHA256 751bc4e2f98074c05c9e23d484f2406cef042099664b6c87a73d6530bbeda427 inc/Module/Install/Scripts.pm SHA256 26b166ff62aacdb55317d1659f160aa4935097eea9810ea980e6d747206b5dc0 inc/Module/Install/Win32.pm SHA256 5f73a6851a91ea44e65b924f918743ad6e860620ad7a38a39d0295e0c5652a9f inc/Module/Install/WriteAll.pm SHA256 6c060e68e70f4888b77d104b77dd932b3df0ce37acfc821fdab1740f09ed6ca8 lib/PDF/FromHTML.pm SHA256 b2872ea10d6151ca230aaa4f529869ebe08a2cc231e3a3ccba5673110b81e39e lib/PDF/FromHTML/Template.pm SHA256 2ea963d7f5544dfab9cb2059660a25e5ae81fbf976d13fc46ae37cb9b3ff9abe lib/PDF/FromHTML/Template/Base.pm SHA256 bd574889f7258359c6b248fd94ef67f829ade0cd3b2d937debf4494797bb37ea lib/PDF/FromHTML/Template/Constants.pm SHA256 bb7aadc849d0d364dc96c3533b48a916e99940a8f24746837e7b703a7784dc12 lib/PDF/FromHTML/Template/Container.pm SHA256 2885b7cbfc4e9e20324568d1051bce19809e58f6bc6a69c771f1b59ccc8281b4 lib/PDF/FromHTML/Template/Container/Always.pm SHA256 379e61f91d5e7f01a49321feb416c78037c44bcaa8ffd7f370ffe02c005204a5 lib/PDF/FromHTML/Template/Container/Conditional.pm SHA256 f81b37f23f6f968837c123095e4854c2c1a2eaab6aec4518274428297835bdb7 lib/PDF/FromHTML/Template/Container/Font.pm SHA256 4d7a6d8b39ccbd6f3ec456120d14c2518a61c47fb09b64afea66b90794f19a3b lib/PDF/FromHTML/Template/Container/Footer.pm SHA256 851a6fb2579eba6c33589038e8ca836054469944180f3681e9d70594a427e6c6 lib/PDF/FromHTML/Template/Container/Header.pm SHA256 c1f5dffb5ee954b4f5b9542d06706b7b9be0d07db77660c0035e02ab5e8f619e lib/PDF/FromHTML/Template/Container/Loop.pm SHA256 01c231a09903b72950b530a14f6037ee946dfc5945ea8194fe2b762fc593dcfd lib/PDF/FromHTML/Template/Container/Margin.pm SHA256 e610ccb39307c1430aed7d28c611474d15099ace99d13eb17c6dcdfea276033c lib/PDF/FromHTML/Template/Container/PageDef.pm SHA256 5b91342df9a428c172d67169bb51ebbc76a4743f585468bc88de2c065ce1e6cc lib/PDF/FromHTML/Template/Container/PdfTemplate.pm SHA256 ff51ed6f020c6e6d3b10e9b858da3734c6ab702e087a90b49f666f3d460c37da lib/PDF/FromHTML/Template/Container/Row.pm SHA256 607d69d923f8a161796703bc48af1ece854da59d723968985b982d583efcfcb6 lib/PDF/FromHTML/Template/Container/Scope.pm SHA256 5c37328bc75290e38900a24a338f27b54bce67bcd5740525ba642b15b22ad582 lib/PDF/FromHTML/Template/Container/Section.pm SHA256 cfe13cdba7c9cb23acecef215f17b88ca6f5ea02dfa2b823a9384a79e2c4f208 lib/PDF/FromHTML/Template/Context.pm SHA256 c2d677d5ba21f483cf46ea9a6189c864922a5f9cedcaa8a02abd87dfc71f2ac2 lib/PDF/FromHTML/Template/Element.pm SHA256 5d5e94e777d79f9b5ce40ddcd2a0acc4ed01a29ff43adc166e38d388e7029d7b lib/PDF/FromHTML/Template/Element/Bookmark.pm SHA256 0c3a3728066fa0c86c1deb8b8b5f55f1a029b784344a4af505609ec19a0425ab lib/PDF/FromHTML/Template/Element/Circle.pm SHA256 8cd2a7084163edf01ca208a186a54e6d6b4ea8f6137a39b3c452d228abe6fd62 lib/PDF/FromHTML/Template/Element/HorizontalRule.pm SHA256 4901dfa7f4f0a0110747b711d868bd81ea4e76390aec7c37f0d7fb5172059f82 lib/PDF/FromHTML/Template/Element/Image.pm SHA256 ddeb64b8091ac8939e4ca9b83e34d01cb34e5059ed8ef3c980ad4b5e66837c8f lib/PDF/FromHTML/Template/Element/Line.pm SHA256 40b8b0ecd59a764b01a42c2aae5251b04803a1e0e708956c90ada89d102faa6f lib/PDF/FromHTML/Template/Element/PageBreak.pm SHA256 e603aa69243746f5c588cfe2cadf950750090c472e76435420f7b515b3b11c4d lib/PDF/FromHTML/Template/Element/TextBox.pm SHA256 90c89488f88746798d8845598a9ce46eca47e645a96e3b5c9a2db7e5eeb253db lib/PDF/FromHTML/Template/Element/Var.pm SHA256 ab7567c4f417488a753258e15aa51fa1a753bb8ed632473ec7ba801d7b80f1ff lib/PDF/FromHTML/Template/Element/Weblink.pm SHA256 8670b209e9ad584ce05dd856b0b80ac688370d96a4be8c264a07bcc645893ce9 lib/PDF/FromHTML/Template/Factory.pm SHA256 6defcb6e75ebd231a2fccf8beb1968ab8434880e33c04a45339c0fff61141305 lib/PDF/FromHTML/Template/Iterator.pm SHA256 162fdfe77337671e4a4a01701c5f085a61758bfc99eaadfced8c26e0568ed9bf lib/PDF/FromHTML/Template/TextObject.pm SHA256 3d711f9bdc01058228f6403724faa036cde704d43364019208708efad72576e7 lib/PDF/FromHTML/Twig.pm SHA256 42217fa5145974b0487a44325ebb4b892cdc695c6294b5d4bb40b82c43503a7f script/html2pdf.pl SHA256 79377cdae6e45062eddabd317e52a7f00c1ac81240f8b566d2df58cb1b2a4ccb t/1-basic.t -----BEGIN PGP SIGNATURE----- iQGzBAEBCAAdFiEE8/4umVyeYRTFU5r09ePPSwnTf6gFAl2whzwACgkQ9ePPSwnT f6jHqQv/Y3a4DitRDf2rjbDy6Sry5kSfA4P9PdVkaNI+JD+mk7L+yu+cvXSdIW6U 8r3oD73b9Gmxb2E0h/Iows3uI+g3upg6PJ0s350LKy3IeK9pcDNPELJipe78SZ5p oCBbQIKjtxR1CAzJ2pv+3bkg3Ha5BiWheV5SgF/MmYIK878A5FeTmIA5+8h3BL+D WS7pAA1j7J/Il6Lcb2WFcTOAg9h1rHf6ZTw4MZsBhMHQz1ywldy6w2xrhBrci6QP z1NI0ItHk0KRzWBLksW5rER7oY5mgjekuKPCvxoSwUIun22t2MXcy88HQut030YU cd6z52OoIFayIphjmY9pK2aB6SG4GtuOgsfUu2XvNZi/XI6+ltcEw6X5ZLEqkKhC PFveAGr9MfaIwXqabDmSU2FnI8C0L5+0ToC+V4SKCIqjn2fxboRwb7pAb8OH4MED giUccdYN5KWq8hqB6+Bqg7BGNqEQ6/gjgw2+ghMCMeKoIDAcfwhEVpbBgQCIwj8o Zh4arEl7 =TUwr -----END PGP SIGNATURE----- PDF-FromHTML-0.33/PaxHeader/Changes000644 000765 000024 00000000036 13554103466 017530 xustar00audreytstaff000000 000000 30 mtime=1571850038.610429738 PDF-FromHTML-0.33/Changes000644 000765 000024 00000007327 13554103466 015571 0ustar00audreytstaff000000 000000 [Changes for 0.33 - Wed Oct 23 20:00:23 EAT 2019] * Fix META.yml and README; no functional changes. [Changes for 0.32 - Wed Oct 23 19:36:25 EAT 2019] * Fix an arbitrary 10-page limitation. [Changes for 0.31 - 2010年 1月 8日 周五 18時58分48秒 CST] * Fix an incorrect MANIFEST leading to installation failure. Reported by: Montaseri. [Changes for 0.30 - 2009年11月17日 周二 16時46分49秒 CST] * LICENSING CHANGE: This compilation and all individual files in it are now under the nullary CC0 1.0 Universal terms: To the extent possible under law, 唐鳳 has waived all copyright and related or neighboring rights to PDF-FromHTML. * Updated Module::Install to 0.91, prompted by Florian Ragwitz. [Changes for 0.25 - 2009-01-01] * Added -l, -e, -f and -s flags to html2pdf.pl; see its POD for details. * Running "html2pdf.pl foo.html" now writes to "foo.html.pdf" instead of STDOUT. However, "html2pdf.pl foo.html > foo.pdf" is still supported. [Changes for 0.24 - 2007-02-14] * The "landscape" option to ->convert() now work as documented. [Changes for 0.23 - 2007-02-05] * Updated CAVEATS section to note that there is currently no plan to support CSS for this module. Contributed by: Craig Chant * Updated license info in scripts/html2pdf to MIT. * Various code warning/stricture/tidying up; no function changes. [Changes for 0.22 - 2007-01-25] * LICENSING CHANGE: This compilation and all individual files in it are now under the permissive "MIT" license. See the COPYRIGHT section in README for the new terms. * PDF::FromHTML no longer fails when contains width percentages that are narrower than the widths of its
elements, or when contains no
elements at all. Reported by: Craig Chant [Changes for 0.21 - 2006-12-07] Slight tweaks to PDF::FromHTML::Template to allow border lines with user-specified width. [Changes for 0.20 - 2006-09-11] Bundle our private fork of PDF::Template as PDF::FromHTML::Template to work around the bug that PDF::Template 0.30 is no longer available no CPAN. Redesigned the table layout engine, so that tables with borders, colspan settings, and per-td widths are all respected. [Changes for 0.12 - 2005-12-01] For Perl 5.8.1, "use constant" alone seems not enough to pass use strict subs. Reported by Christian Pipi. Updateded to Module::Install 0.40 for better installation support. [Changes for 0.11 - 2005-12-01] For Perl 5.6.x, we have to use PDFLib as PDF::API2 only supports Perl 5.8+. Reported by Jessie Chen. [Changes for 0.10 - 2005-11-29] Chase new versions of PDF::Template and PDF::Writer. Add support for PDFLib based rendering engine, in addition to PDF::API2. [Changes for 0.08 - 2005-05-06] Fix image handler bug in Twig.pm for zero-width and missing image files, contributed by Charleston Software Associates. [Changes for 0.07 - 2004-12-08] Heading fonts are made much bigger. Prelminary support for via LWP. Use Image::Size to determine image size correctly. Correct layout for mixed colspan and rowspan. Variable support via a plain $__PAGE__ in text (this interface may change into the future). [Changes for 0.06 - 2004-11-23] Correctly fallback to XML::Clean if HTML::Tidy is unavailable. Rowspan was only renfered properly on leading columns; now it should work on all columns. [Changes for 0.05 - 2004-11-18] HTML::Tidy is now preferred over XML::Clean. Graphics::ColorNames now replaces Color::Rgb. Dropped dependency on Spiffy and Hook::LexWrap. TD and TH's "rowspan" and "colspan" is now handled, albeit imperfectly. Widths in TD and TH in the same TR now always adds back to 100%. [Changes for 0.04 - 2004-09-23] Adds parameters to ->convert() so page size, font height etc can be tweaked. PDF-FromHTML-0.33/MANIFEST000644 000765 000024 00000003373 13554101354 015416 0ustar00audreytstaff000000 000000 Changes inc/Module/AutoInstall.pm inc/Module/Install.pm inc/Module/Install/AutoInstall.pm inc/Module/Install/Base.pm inc/Module/Install/Can.pm inc/Module/Install/Fetch.pm inc/Module/Install/Include.pm inc/Module/Install/Makefile.pm inc/Module/Install/Metadata.pm inc/Module/Install/Scripts.pm inc/Module/Install/Win32.pm inc/Module/Install/WriteAll.pm lib/PDF/FromHTML.pm lib/PDF/FromHTML/Template.pm lib/PDF/FromHTML/Template/Base.pm lib/PDF/FromHTML/Template/Constants.pm lib/PDF/FromHTML/Template/Container.pm lib/PDF/FromHTML/Template/Container/Always.pm lib/PDF/FromHTML/Template/Container/Conditional.pm lib/PDF/FromHTML/Template/Container/Font.pm lib/PDF/FromHTML/Template/Container/Footer.pm lib/PDF/FromHTML/Template/Container/Header.pm lib/PDF/FromHTML/Template/Container/Loop.pm lib/PDF/FromHTML/Template/Container/Margin.pm lib/PDF/FromHTML/Template/Container/PageDef.pm lib/PDF/FromHTML/Template/Container/PdfTemplate.pm lib/PDF/FromHTML/Template/Container/Row.pm lib/PDF/FromHTML/Template/Container/Scope.pm lib/PDF/FromHTML/Template/Container/Section.pm lib/PDF/FromHTML/Template/Context.pm lib/PDF/FromHTML/Template/Element.pm lib/PDF/FromHTML/Template/Element/Bookmark.pm lib/PDF/FromHTML/Template/Element/Circle.pm lib/PDF/FromHTML/Template/Element/HorizontalRule.pm lib/PDF/FromHTML/Template/Element/Image.pm lib/PDF/FromHTML/Template/Element/Line.pm lib/PDF/FromHTML/Template/Element/PageBreak.pm lib/PDF/FromHTML/Template/Element/TextBox.pm lib/PDF/FromHTML/Template/Element/Var.pm lib/PDF/FromHTML/Template/Element/Weblink.pm lib/PDF/FromHTML/Template/Factory.pm lib/PDF/FromHTML/Template/Iterator.pm lib/PDF/FromHTML/Template/TextObject.pm lib/PDF/FromHTML/Twig.pm Makefile.PL MANIFEST This list of files META.yml README script/html2pdf.pl SIGNATURE t/1-basic.t PDF-FromHTML-0.33/t/000755 000765 000024 00000000000 13554103473 014526 5ustar00audreytstaff000000 000000 PDF-FromHTML-0.33/PaxHeader/README000644 000765 000024 00000000036 13554103411 017103 xustar00audreytstaff000000 000000 30 mtime=1571849993.267114463 PDF-FromHTML-0.33/README000644 000765 000024 00000005105 13554103411 015134 0ustar00audreytstaff000000 000000 NAME PDF::FromHTML - Convert HTML documents to PDF SYNOPSIS my $pdf = PDF::FromHTML->new( encoding => 'utf-8' ); # Loading from a file: $pdf->load_file('source.html'); # Or from a scalar reference: # $pdf->load_file(\$input); # Perform the actual conversion: $pdf->convert( # With PDF::API2, font names such as 'traditional' also works Font => 'font.ttf', LineHeight => 10, Landscape => 1, ); # Write to a file: $pdf->write_file('target.pdf'); # Or to a scalar reference: # $pdf->write_file(\$output); DESCRIPTION This module transforms HTML into PDF, using an assortment of XML transformations implemented in PDF::FromHTML::Twig. There is also a command-line utility, html2pdf.pl, that comes with this distribution. PUBLIC METHODS convert(%params) Convert the loaded file to PDF. Valid parameters are: PageWidth 640 PageResolution 540 FontBold 'HelveticaBold' FontOblique 'HelveticaOblique' FontBoldOblique 'HelveticaBoldOblique' LineHeight 12 FontUnicode 'Helvetica' Font (same as FontUnicode) PageSize 'A4' Landscape 0 HINTS & TIPS tags Add the height and width attributes if you are creating the source HTML, it keeps PDF::FromHTML from having to open and read the source image file to get the real size. Less file I/O means faster processing. CAVEATS Although PDF::FromHTML will work with both HTML and XHTML formats, it is not designed to utilise CSS. This means any HTML using external or inline CSS for design and layout, including but not limited to: images, backgrounds, colours, fonts etc... will not be converted into the PDF. To get an idea of the likely resulting PDF, you may wish to use an non-CSS capable browser for testing first. There is currently no plan to adapt this module to utilise CSS. (Patches welcome, though!) SEE ALSO html2pdf.pl is a simple command-line interface to this module. PDF::FromHTML::Twig, PDF::Template, XML::Twig. CONTRIBUTORS Charleston Software Associates AUTHORS Audrey Tang CC0 1.0 Universal To the extent possible under law, 唐鳳 has waived all copyright and related or neighboring rights to PDF-FromHTML. This work is published from Taiwan. PDF-FromHTML-0.33/script/000755 000765 000024 00000000000 13554103473 015567 5ustar00audreytstaff000000 000000 PDF-FromHTML-0.33/META.yml000644 000765 000024 00000007106 13554103473 015540 0ustar00audreytstaff000000 000000 --- abstract: 'Convert HTML documents to PDF' author: - 'Audrey Tang ' build_requires: ExtUtils::MakeMaker: 6.59 configure_requires: ExtUtils::MakeMaker: 6.59 distribution_type: module dynamic_config: 1 generated_by: 'Module::Install version 1.19' license: unrestricted meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: 1.4 name: PDF-FromHTML no_index: directory: - inc - t provides: PDF::FromHTML: file: lib/PDF/FromHTML.pm version: '0.33' PDF::FromHTML::Template: file: lib/PDF/FromHTML/Template.pm version: '0.33' PDF::FromHTML::Template::Base: file: lib/PDF/FromHTML/Template/Base.pm PDF::FromHTML::Template::Constants: file: lib/PDF/FromHTML/Template/Constants.pm PDF::FromHTML::Template::Container: file: lib/PDF/FromHTML/Template/Container.pm PDF::FromHTML::Template::Container::Always: file: lib/PDF/FromHTML/Template/Container/Always.pm PDF::FromHTML::Template::Container::Conditional: file: lib/PDF/FromHTML/Template/Container/Conditional.pm PDF::FromHTML::Template::Container::Font: file: lib/PDF/FromHTML/Template/Container/Font.pm PDF::FromHTML::Template::Container::Footer: file: lib/PDF/FromHTML/Template/Container/Footer.pm PDF::FromHTML::Template::Container::Header: file: lib/PDF/FromHTML/Template/Container/Header.pm PDF::FromHTML::Template::Container::Loop: file: lib/PDF/FromHTML/Template/Container/Loop.pm PDF::FromHTML::Template::Container::Margin: file: lib/PDF/FromHTML/Template/Container/Margin.pm PDF::FromHTML::Template::Container::PageDef: file: lib/PDF/FromHTML/Template/Container/PageDef.pm PDF::FromHTML::Template::Container::PdfTemplate: file: lib/PDF/FromHTML/Template/Container/PdfTemplate.pm PDF::FromHTML::Template::Container::Row: file: lib/PDF/FromHTML/Template/Container/Row.pm PDF::FromHTML::Template::Container::Scope: file: lib/PDF/FromHTML/Template/Container/Scope.pm PDF::FromHTML::Template::Container::Section: file: lib/PDF/FromHTML/Template/Container/Section.pm PDF::FromHTML::Template::Context: file: lib/PDF/FromHTML/Template/Context.pm PDF::FromHTML::Template::Element: file: lib/PDF/FromHTML/Template/Element.pm PDF::FromHTML::Template::Element::Bookmark: file: lib/PDF/FromHTML/Template/Element/Bookmark.pm PDF::FromHTML::Template::Element::Circle: file: lib/PDF/FromHTML/Template/Element/Circle.pm PDF::FromHTML::Template::Element::HorizontalRule: file: lib/PDF/FromHTML/Template/Element/HorizontalRule.pm PDF::FromHTML::Template::Element::Image: file: lib/PDF/FromHTML/Template/Element/Image.pm PDF::FromHTML::Template::Element::Line: file: lib/PDF/FromHTML/Template/Element/Line.pm PDF::FromHTML::Template::Element::PageBreak: file: lib/PDF/FromHTML/Template/Element/PageBreak.pm PDF::FromHTML::Template::Element::TextBox: file: lib/PDF/FromHTML/Template/Element/TextBox.pm PDF::FromHTML::Template::Element::Var: file: lib/PDF/FromHTML/Template/Element/Var.pm PDF::FromHTML::Template::Element::Weblink: file: lib/PDF/FromHTML/Template/Element/Weblink.pm PDF::FromHTML::Template::Factory: file: lib/PDF/FromHTML/Template/Factory.pm PDF::FromHTML::Template::Iterator: file: lib/PDF/FromHTML/Template/Iterator.pm PDF::FromHTML::Template::TextObject: file: lib/PDF/FromHTML/Template/TextObject.pm PDF::FromHTML::Twig: file: lib/PDF/FromHTML/Twig.pm requires: Graphics::ColorNames: 0 HTML::Tidy: 0 Image::Size: 0 LWP::Simple: 0 List::Util: 0 PDF::API2: 0 PDF::Writer: '0.05' XML::Twig: 0 perl: 5.6.0 version: '0.33' PDF-FromHTML-0.33/lib/000755 000765 000024 00000000000 13554103473 015031 5ustar00audreytstaff000000 000000 PDF-FromHTML-0.33/Makefile.PL000644 000765 000024 00000002320 13554103377 016235 0ustar00audreytstaff000000 000000 #!/usr/local/bin/perl use inc::Module::Install; name 'PDF-FromHTML'; license 'unrestricted'; all_from 'lib/PDF/FromHTML.pm'; install_script 'script/html2pdf.pl'; requires qw( List::Util 0 XML::Twig 0 Graphics::ColorNames 0 LWP::Simple 0 Image::Size 0 PDF::Writer 0.05 ); unless (can_use('PDF::API2') or can_use('pdflib_pl')) { if ($] >= 5.008) { requires 'PDF::API2'; print << '.'; *** If you cannot install PDF::API2, you may use the pdflib_pl module instead, available as a separate download on PDFLib homepage. . } else { requires 'pdflib_pl'; print << '.'; *** Perl 5.6.x users needs the pdflib_pl module, available as a separate download on PDFLib homepage. Alternatively, upgrade to Perl 5.8 and use PDF::API2 from CPAN. . } } unless (can_use('HTML::Tidy') or can_use('XML::Clean')) { requires 'HTML::Tidy'; print << '.'; *** If you cannot install HTML::Tidy, you may use the XML::Clean module instead; however, you will run probably run into more "XML not well-formed" errors that way. . } auto_install; auto_provides; sign; WriteAll; PDF-FromHTML-0.33/lib/PDF/000755 000765 000024 00000000000 13554103473 015442 5ustar00audreytstaff000000 000000 PDF-FromHTML-0.33/lib/PDF/FromHTML/000755 000765 000024 00000000000 13554103473 017032 5ustar00audreytstaff000000 000000 PDF-FromHTML-0.33/lib/PDF/PaxHeader/FromHTML.pm000644 000765 000024 00000000036 13554103430 021331 xustar00audreytstaff000000 000000 30 mtime=1571850008.903101983 PDF-FromHTML-0.33/lib/PDF/FromHTML.pm000644 000765 000024 00000013722 13554103430 017366 0ustar00audreytstaff000000 000000 package PDF::FromHTML; use 5.006; use strict; use warnings; our $VERSION = '0.33'; BEGIN { foreach my $method ( qw( pdf twig tidy args ) ) { no strict 'refs'; *$method = sub { $#_ ? ($_[0]{$method} = $_[1]) : $_[0]{$method} }; } } use Cwd; use File::Temp; use File::Basename; use PDF::Writer; use PDF::FromHTML::Twig; use PDF::FromHTML::Template; use constant HAS_UNICODE_SUPPORT => ($] >= 5.008); use constant PDF_WRITER_BACKEND => do { local $@; # For Perl 5.6.x, we have to use pdflib PDF::Writer->import('pdflib') unless HAS_UNICODE_SUPPORT(); eval { ref(PDF::Writer->new) } or die( "Please install PDF::API2 (preferred) or pdflib_pl first" ); }; use constant HAS_HTML_TIDY => do { local $@; eval { require HTML::Tidy; 1 } or do { unless ( eval { require XML::Clean; 1 } ) { die( "Please install HTML::Tidy (preferred) or XML::Clean first" ); } 0; # Has XML::Clean but no HTML::Tidy }; }; =head1 NAME PDF::FromHTML - Convert HTML documents to PDF =head1 SYNOPSIS my $pdf = PDF::FromHTML->new( encoding => 'utf-8' ); # Loading from a file: $pdf->load_file('source.html'); # Or from a scalar reference: # $pdf->load_file(\$input); # Perform the actual conversion: $pdf->convert( # With PDF::API2, font names such as 'traditional' also works Font => 'font.ttf', LineHeight => 10, Landscape => 1, ); # Write to a file: $pdf->write_file('target.pdf'); # Or to a scalar reference: # $pdf->write_file(\$output); =head1 DESCRIPTION This module transforms HTML into PDF, using an assortment of XML transformations implemented in L. There is also a command-line utility, L, that comes with this distribution. =head1 PUBLIC METHODS =cut sub new { my $class = shift; bless({ twig => PDF::FromHTML::Twig->new, args => { @_ }, }, $class); } sub load_file { my ($self, $file) = @_; $self->{file} = $file; } sub parse_file { my $self = shift; my $file = $self->{file}; my $content = ''; my $dir = Cwd::getcwd(); if (!ref $file) { open my $fh, '<', $file or die $!; chdir File::Basename::dirname($file); $content = do { local $/; <$fh> }; } else { $content = $$file; } my $encoding = ($self->args->{encoding} || 'utf8'); if (HAS_UNICODE_SUPPORT() and $self->args) { require Encode; $content = Encode::decode($encoding, $content, Encode::FB_XMLCREF()); } $content =~ s{ }{}g; $content =~ s{}{}gs; if (HAS_HTML_TIDY()) { if (HAS_UNICODE_SUPPORT()) { $content = Encode::encode( ascii => $content, Encode::FB_XMLCREF()); } $content = HTML::Tidy->new->clean( '', '', $content, ); } else { $content =~ s{&#(\d+);}{chr $1}eg; $content =~ s{&#x([\da-fA-F]+);}{chr hex $1}eg; $content = XML::Clean::clean($content, '1.0', { encoding => 'UTF-8' }); $content =~ s{<(/?\w+)}{<\L$1}g; } $self->twig->parse( $content ); chdir $dir; } =head2 convert(%params) Convert the loaded file to PDF. Valid parameters are: PageWidth 640 PageResolution 540 FontBold 'HelveticaBold' FontOblique 'HelveticaOblique' FontBoldOblique 'HelveticaBoldOblique' LineHeight 12 FontUnicode 'Helvetica' Font (same as FontUnicode) PageSize 'A4' Landscape 0 =cut sub convert { my ($self, %args) = @_; { # import arguments into Twig parameters no strict 'refs'; ${"PDF::FromHTML::Twig::$_"} = $args{$_} foreach keys %args; } $self->parse_file; my ($fh, $filename) = File::Temp::tempfile( SUFFIX => '.xml', UNLINK => 1, ); binmode($fh); if (HAS_UNICODE_SUPPORT()) { binmode($fh, ':utf8'); } # use File::Copy; # copy($filename => '/tmp/foo.xml'); # XXX HACK! XXX my $text = $self->twig->sprint; $text =~ s{\$(__[A-Z_]+__)}{}g; print $fh $text; close $fh; # print STDERR "==> Temp file written to $filename\n"; local $@; local $^W; $self->pdf(eval { PDF::FromHTML::Template->new( filename => $filename ) }) or die "$filename: $@"; $self->pdf->param(@_); } sub write_file { my $self = shift; local $^W; if (@_ and ref($_[0]) eq 'SCALAR') { ${$_[0]} = $self->pdf->get_buffer; } else { $self->pdf->write_file(@_); } } 1; =head1 HINTS & TIPS =head2 EimgE tags Add the height and width attributes if you are creating the source HTML, it keeps PDF::FromHTML from having to open and read the source image file to get the real size. Less file I/O means faster processing. =head1 CAVEATS Although B will work with both HTML and XHTML formats, it is not designed to utilise CSS. This means any HTML using external or inline CSS for design and layout, including but not limited to: images, backgrounds, colours, fonts etc... will not be converted into the PDF. To get an idea of the likely resulting PDF, you may wish to use an non-CSS capable browser for testing first. There is currently no plan to adapt this module to utilise CSS. (Patches welcome, though!) =head1 SEE ALSO L is a simple command-line interface to this module. L, L, L. =head1 CONTRIBUTORS Charleston Software Associates Einfo@charletonsw.comE =head1 AUTHORS Audrey Tang Ecpan@audreyt.orgE =head1 CC0 1.0 Universal To the extent possible under law, 唐鳳 has waived all copyright and related or neighboring rights to PDF-FromHTML. This work is published from Taiwan. L =cut PDF-FromHTML-0.33/lib/PDF/FromHTML/Template/000755 000765 000024 00000000000 13554103473 020605 5ustar00audreytstaff000000 000000 PDF-FromHTML-0.33/lib/PDF/FromHTML/PaxHeader/Twig.pm000644 000765 000024 00000000036 13554101202 022236 xustar00audreytstaff000000 000000 30 mtime=1571848834.243349246 PDF-FromHTML-0.33/lib/PDF/FromHTML/Twig.pm000644 000765 000024 00000044160 13554101202 020273 0ustar00audreytstaff000000 000000 package PDF::FromHTML::Twig; use strict; use warnings; use XML::Twig; use base 'XML::Twig'; use charnames ':full'; use Graphics::ColorNames qw( hex2tuple ); use File::Spec; use File::Basename; use List::Util qw( sum first reduce ); =head1 NAME PDF::FromHTML::Twig - PDF::FromHTML guts =head1 SYNOPSIS (internal use only) =head1 DESCRIPTION No user-serviceable parts inside. =cut sub new { my $class = shift; XML::Twig::new($class, $class->TwigArguments, @_); } our $PageWidth = 640; our $PageResolution = 540; our $FontBold = 'HelveticaBold'; our $FontOblique = 'HelveticaOblique'; our $FontBoldOblique = 'HelveticaBoldOblique'; our $LineHeight = 12; our $FontUnicode = 'Helvetica'; our $Font = $FontUnicode; # $Font = '/usr/local/share/fonts/TrueType/minguni.ttf'; our $PageSize = 'A4'; our $Landscape = 0; use constant SuperScript => [ "\N{SUPERSCRIPT ZERO}", "\N{SUPERSCRIPT ONE}", "\N{SUPERSCRIPT TWO}", "\N{SUPERSCRIPT THREE}", "\N{SUPERSCRIPT FOUR}", "\N{SUPERSCRIPT FIVE}", "\N{SUPERSCRIPT SIX}", "\N{SUPERSCRIPT SEVEN}", "\N{SUPERSCRIPT EIGHT}", "\N{SUPERSCRIPT NINE}", ]; use constant SubScript => [ "\N{SUBSCRIPT ZERO}", "\N{SUBSCRIPT ONE}", "\N{SUBSCRIPT TWO}", "\N{SUBSCRIPT THREE}", "\N{SUBSCRIPT FOUR}", "\N{SUBSCRIPT FIVE}", "\N{SUBSCRIPT SIX}", "\N{SUBSCRIPT SEVEN}", "\N{SUBSCRIPT EIGHT}", "\N{SUBSCRIPT NINE}", ]; use constant InlineTags => { map { $_ => 1 } '#PCDATA', 'font' }; use constant DeleteTags => { map { $_ => 1 } qw( head style applet script ) }; use constant IgnoreTags => { map { $_ => 1 } qw( title a ul del address blockquote colgroup fieldset input form frameset object noframes noscript small optgroup isindex area textarea col pre frame param menu acronym abbr bdo label basefont big caption option cite dd dfn dt base code map iframe ins kbd legend samp span dir strike meta link tbody q tfoot button thead tt select s var ) }; use constant TwigArguments => ( twig_handlers => { html => sub { $_->del_atts; $_->set_gi('pdftemplate'); }, map(( "h$_" => ( sub { my $size = 4 + shift; sub { $_->insert_new_elt(before => 'textbox') ->wrap_in('row') ->wrap_in(font => { face => $FontBold }); $_->wrap_in( font => { h => $LineHeight + 6 - $size }); $_->wrap_in( row => { h => $LineHeight + 8 - $size }); $_->set_tag('textbox'), $_->set_att(w => '100%'); }; } )->($_) ), 1 .. 6), center => sub { foreach my $child ($_->children('p')) { # XXX - revert other blocklevel to left/original alignment $child->set_att(align => 'center'); } $_->erase; }, sup => sub { my $digits = $_->text; my $text = ''; $text .= +SuperScript->[$1] while $digits =~ s/(\d)//; $_->set_text($text); $_->erase; }, sub => sub { my $digits = $_->text; my $text = ''; $text .= +SubScript->[$1] while $digits =~ s/(\d)//; $_->set_text($text); $_->erase; }, u => sub { _set(underline => 1, $_); $_->erase; }, em => sub { _set(font => $FontOblique, $_); $_->erase; }, i => sub { _set(font => $FontOblique, $_); $_->erase; }, strong => sub { _set(font => $FontBold, $_); $_->erase; }, b => sub { _set(font => $FontBold, $_); $_->erase; }, div => sub { if (my $tag = (_type(header => $_) || _type(footer => $_))) { $_->set_tag($tag); $_->set_att( "${tag}_height" => int( sum( $LineHeight * 2, grep defined, map $_->att('h'), $_->descendants ) ), ); } else { $_->erase; } }, hr => sub { $_->insert_new_elt(first_child => (_type(pagebreak => $_) || 'hr')); $_->erase; }, img => sub { my $src = $_->att('src'); my $file = File::Spec->rel2abs($src); if ($src =~ m{^(\w+):/}) { require LWP::Simple; require File::Basename; require File::Spec; $file = File::Spec->catfile(File::Spec->tmpdir, File::Basename::basename($src)); LWP::Simple::mirror($src => $file); } # CSA - check for real file first # if (-e $file) { my $w = $_->att('width'); my $h = $_->att('height'); if (($w eq '') or ($h eq '')) { require Image::Size; my ($iw, $ih) = Image::Size::imgsize($file); # CSA - catch this now, before we crash # warn "unable to read image file '$file' ($w x $h)" unless (defined $iw && defined $ih); $iw ||= 1; $ih ||= 1; if (!$w and !$h) { ($w, $h) = ($iw, $ih); } elsif (!$w) { $w = $iw * ($h / $ih); } else { $h = $ih * ($w / $iw); } } my $image = $_->insert_new_elt( first_child => image => { filename => $file, w => ($w / $PageWidth * $PageResolution), h => ($h / $PageWidth * $PageResolution), type => '', } ); $image->wrap_in('row'); # CSA - File has gone missing # } else { warn "image file '$file' does not exist"; } $_->erase; }, body => sub { $_->wrap_in( pagedef => { pagesize => $PageSize, landscape => $Landscape, margins => $LineHeight - 2, }, ); $_->wrap_in( font => { face => $Font, h => $LineHeight - 2, } ); my $pagedef = $_->parent->parent; my $head = ($pagedef->descendants('header'))[0] || $pagedef->insert_new_elt( first_child => header => { header_height => $LineHeight * 2 }); my $row = $head->insert_new_elt(first_child => 'row'); $row->insert_new_elt( first_child => textbox => { w => '100%', text => '' }); foreach my $child ($_->children('#PCDATA')) { $child->set_text( join(' ', grep length, split(/\n+/, $child->text))); if ($child->text =~ /[^\x00-\x7f]/) { $child->wrap_in(font => { face => $FontUnicode }); } $child->wrap_in('row'); $child->wrap_in(textbox => { w => '100%' }); $child->insert_new_elt(after => 'textbox')->wrap_in('row'); } $_->erase; }, p => \&_p, li => \&_p, table => sub { our @RowSpan = (); my $cols = $_->root->att('#total_cols') or do { $_->erase for $_->children('tr'); $_->erase; return; }; my $widths = $_->root->att('#widths'); if (!$widths) { $widths = []; $_->root->set_att('#widths', $widths); } my $table_width = $_->root->att('#total_width'); if (!$table_width) { $table_width = _percentify($_->att('width'), $PageWidth); $_->root->set_att('#total_width', $table_width); } my $unallocated_sum = 100; my $unallocated_cols = 0; foreach my $idx (0..$cols-1) { if (my $w = $widths->[$idx]) { $unallocated_sum -= $w; } else { $unallocated_cols++; } } if ($unallocated_cols and $unallocated_sum > 0) { # warn "UNALLOC: $unallocated_cols, $unallocated_sum\n"; # Populate unallocated columns my $w = int($unallocated_sum / $unallocated_cols); $widths->[$_] ||= $w for (0..$cols-1); } elsif ($unallocated_cols) { # Redistribute all columns. my $w = int(100 / $cols); $widths->[$_] = $w for (0..$cols-1); } elsif ($unallocated_sum < 0) { # warn "WIDTHS: @$widths ($unallocated_sum)\n"; # Redistribute all columns, part 2. -- not sure we should do it actually. my $overflow = (100-$unallocated_sum); $widths->[$_] = int($widths->[$_] * 100 / $overflow) for (0..$cols-1); } for ($_->children('tr')) { return $_->erase if $_->descendants('row'); my @children = $_->descendants('textbox'); my @cells = @{ shift(@RowSpan) || [] }; foreach my $i (1 .. $#cells) { my $cell = $cells[$i] or next; my $child; if ($child = $children[ $i - 1 ]) { $child->insert_new_elt(before => 'textbox', $cell); } elsif ($child = $children[ $i - 2 ]) { $child->insert_new_elt(after => 'textbox', $cell); } else { next; } @children = $_->descendants('textbox'); } my $cols = sum(map { $_->att('colspan') || 1 } @children); # print STDERR "==> Total cols: $cols :".@children.$/; my $sum = 100; my $last_child = pop(@children); my $col_idx = 0; foreach my $child (@children) { my $colspan = $child->att('colspan') || 1; my $w = 0; foreach my $idx ($col_idx .. $col_idx+$colspan-1) { $w += $widths->[$idx]; } $col_idx += $colspan; $child->set_att(w => "$w%"); $sum -= $w; } $last_child->set_att(w => "$sum%") if $last_child; $_->set_tag('row'); $_->set_att(lmargin => '3'); $_->set_att(rmargin => '3'); $_->set_att(border => $_->parent('table')->att('border')); $_->set_att(h => $LineHeight); } $_->root->del_att('#widths'); $_->root->set_att('#total_width' => undef); $_->root->set_att('#total_cols' => undef); $_->insert_new_elt(last_child => row => { h => $LineHeight }); $_->erase; }, ol => sub { my $count = 1; foreach my $child ($_->descendants('counter')) { $child->set_tag('textbox'); $child->set_text("$count. "); $count++; } $_->insert_new_elt(last_child => row => { h => $LineHeight }); $_->erase; }, br => sub { $_->insert_new_elt(last_child => row => { h => $LineHeight }); $_->erase; }, ul => sub { foreach my $child ($_->descendants('counter')) { $child->set_tag('textbox'); $child->set_text("* "); } $_->insert_new_elt(last_child => row => { h => $LineHeight }); $_->erase; }, dl => sub { foreach my $child ($_->descendants('counter')) { $child->delete; } $_->insert_new_elt(last_child => row => { h => $LineHeight }); $_->erase; }, td => \&_td, th => \&_td, font => sub { $_->del_att('face'); if ($_->att_names) { $_->set_att(face => $Font); $_->erase; # XXX } else { $_->erase; } }, var => sub { # XXX - Proper variable support }, _default_ => sub { $_->erase if +IgnoreTags->{ $_->tag }; $_->delete if +DeleteTags->{ $_->tag }; } }, pretty_print => 'indented', empty_tags => 'html', start_tag_handlers => { _all_ => sub { if (my $h = $_->att('size')) { $_->set_att(h => $LineHeight + (2 * ($h - 4))); } if (my $bgcolor = $_->att('bgcolor')) { $_->set_att(bgcolor => _to_color($bgcolor)); } $_->del_att( qw( color bordercolor bordercolordark bordercolorlight cellpadding cellspacing size href ) ); }, } ); sub _set { my ($key, $value, $elt) = @_; my $att = $elt->root->att("#$key") || {}; $att->{ $elt->parent } = $value; $elt->root->set_att("#$key", $att); } sub _get { my ($key, $elt) = @_; my $att = $elt->root->att("#$key") || {}; return $att->{$elt}; } sub _p { my @children; foreach my $child ($_->children) { +InlineTags->{ $child->tag } or last; push @children, $child->cut; } if (@children) { my $textbox = $_->insert_new_elt( before => textbox => { w => (($_->tag eq 'p') ? '100%' : '97%'), align => $_->att('align') }, ); $textbox->wrap_in('row'); if ($_->tag eq 'li') { $textbox->insert_new_elt( before => counter => { w => '3%', align => 'right' }); } foreach my $child (@children) { $child->paste(last_child => $textbox); $child->set_text( join(' ', grep { length and $_ ne 1 } split(/\n+/, $child->text)) ); } my $font = _get(font => $_); if ($textbox->text =~ /[^\x00-\x7f]/) { $font = $FontUnicode; } elsif ($_->parent('i') and $_->parent('b')) { $font ||= $FontBoldOblique; } elsif ($_->parent('i')) { $font ||= $FontOblique; } elsif ($_->parent('b')) { $font ||= $FontBold; } my %attr; $attr{face} = $font if $font; if (_get(underline => $_)) { my $align = $textbox->att('align'); $align .= '_underline'; $textbox->del_att('align'); require PDF::FromHTML::Template::Constants; $PDF::FromHTML::Template::Constants::Verify{ALIGN}{$align} = 1 if %PDF::FromHTML::Template::Constants::Verify; $attr{align} = $align; } $textbox->wrap_in('font' => \%attr) if %attr; } $_->insert_new_elt(first_child => 'textbox')->wrap_in('row') if $_->tag eq 'p'; $_->erase; } sub _td { return $_->erase if $_->descendants('row'); $_->set_tag('textbox'); if (my $font = _get(font => $_)) { $_->wrap_in(font => { face => $font }); } my $cols = $_->parent->att('_cols') || 0; no warnings 'uninitialized'; if ($_->att('colspan') <= 1 and my $width = $_->att('width')) { my $table_width = $_->root->att('#total_width') || 100; my $cell_width = _percentify($width, int($table_width * $PageWidth / 100)); # Register us in the width table my $widths = $_->root->att('#widths'); if (!$widths) { $widths = []; $_->root->set_att('#widths', $widths); } # warn "[$cols] = $widths->[$cols] vs $cell_width\n"; $widths->[$cols] = $cell_width if $widths->[$cols] < $cell_width; } $cols += ($_->att('colspan') || 1); $_->parent->set_att(_cols => $cols); $_->root->set_att('#total_cols', $cols) if $_->root->att('#total_cols') < $cols; if (my $rowspan = $_->att('rowspan')) { # ok, we can't really do this. # what we can do, though, is to add 'fake' cells in the next row. our @RowSpan; foreach my $i (1 .. ($rowspan - 1)) { $RowSpan[$i][$cols] = $_->atts; } } } sub _percentify { my $num = shift or return '100'; my $total_width = shift or Carp::confess( '100') ; return $1 if $num =~ /(\d+)%/; return int($num / $total_width * 100); } sub _type { my ($val, $elt) = @_; return first { $_ eq $val } grep defined, map $elt->att($_), qw(type class); } sub _to_color { my ($color) = @_; if ($color !~ s/^#//) { $color = Graphics::ColorNames->new('Netscape')->hex($color); } return join ',', hex2tuple($color); } 1; =head1 AUTHORS 唐鳳 Ecpan@audreyt.orgE =head1 CC0 1.0 Universal To the extent possible under law, 唐鳳 has waived all copyright and related or neighboring rights to PDF-FromHTML. This work is published from Taiwan. L =cut PDF-FromHTML-0.33/lib/PDF/FromHTML/PaxHeader/Template.pm000644 000765 000024 00000000036 13554103427 023112 xustar00audreytstaff000000 000000 30 mtime=1571850007.000528651 PDF-FromHTML-0.33/lib/PDF/FromHTML/Template.pm000644 000765 000024 00000031426 13554103427 021150 0ustar00audreytstaff000000 000000 package PDF::FromHTML::Template; use strict; use warnings; use base 'PDF::FromHTML::Template::Base'; our $VERSION = '0.33'; use PDF::Writer; use File::Basename qw( fileparse ); use XML::Parser (); #----------------------------------------------- # TODO #----------------------------------------------- # PDF_set_info - find out more about this # Providers - I need to create some provider classes that abstract # the process of PDF creation. This will enable P::T to work with # different PDF providers. A provider could be passed in to the # constructor. If non is passed, P::T should try to instantiate a # sensible provider depending on what is installed. #----------------------------------------------- sub new { my $class = shift; my $self = $class->SUPER::new(@_); $self->{TEMPLATES} = [] unless UNIVERSAL::isa($self->{TEMPLATES}, 'ARRAY'); $self->{PARAM_MAP} = {} unless UNIVERSAL::isa($self->{PARAM_MAP}, 'HASH'); $self->{PDF_VERSION} = 0; $self->_validate_option($_) for qw(OPENACTION OPENMODE); if ( !defined $self->{FILE} && defined $self->{FILENAME} ) { $self->{FILE} = $self->{FILENAME}; } $self->parse_xml($self->{FILE}) if defined $self->{FILE}; return $self; } sub param { my $self = shift; # Allow an arbitrary number of hashrefs, so long as they're the first things # into param(). Put each one onto the end, de-referenced. push @_, %{shift @_} while UNIVERSAL::isa($_[0], 'HASH'); (@_ % 2) && die __PACKAGE__, "->param() : Odd number of parameters to param()\n"; my %params = @_; $params{uc $_} = delete $params{$_} for keys %params; @{$self->{PARAM_MAP}}{keys %params} = @params{keys %params}; return 1; } sub write_file { my $self = shift; my ($fname) = @_; my $p = PDF::Writer->new; $p->open($fname) or die "Could not open file '$fname'.", $/; $self->_prepare_output($p); $p->save(); return 1; } sub get_buffer { my $self = shift; my $p = PDF::Writer->new; $p->open() or die "Could not open buffer.", $/; $self->_prepare_output($p); return $p->stringify(); } *output = \&get_buffer; sub parse { my $self = shift; my ($file) = @_; my %Has_TextObject = map { $_ => undef } qw( BOOKMARK IMAGE TEXTBOX ); my @stack; my @params = ( Handlers => { Start => sub { shift; my $name = uc shift; # Pass the PDF encoding in. if ($name eq 'PDFTEMPLATE') { if (exists $self->{PDF_ENCODING}) { push @_, ( PDF_ENCODING => $self->{PDF_ENCODING}, ); } } my $node = PDF::FromHTML::Template::Factory->create_node($name, @_); die "'$name' (@_) didn't make a node!\n" unless defined $node; if ($name eq 'VAR') { return unless @stack; if (exists $stack[-1]{TXTOBJ} && $stack[-1]{TXTOBJ}->isa('TEXTOBJECT')) { push @{$stack[-1]{TXTOBJ}{STACK}}, $node; } } elsif ($name eq 'PDFTEMPLATE') { push @{$self->{TEMPLATES}}, $node; } else { push @{$stack[-1]{ELEMENTS}}, $node if @stack; } push @stack, $node; }, Char => sub { shift; return unless @stack; my $parent = $stack[-1]; if (exists $parent->{TXTOBJ} && $parent->{TXTOBJ}->isa('TEXTOBJECT')) { push @{$parent->{TXTOBJ}{STACK}}, @_; } }, End => sub { shift; return unless @stack; pop @stack if $stack[-1]->isa(uc $_[0]); }, }, ); if ( exists $self->{PDF_ENCODING} ) { push @params, ProtocolEncoding => $self->{PDF_ENCODING}; } if ( ref $file ) { *INFILE = $file; } else { my ($filename, $dirname) = fileparse($file); push @params, Base => $dirname; open( INFILE, '<', $file ) || die "Cannot open '$file' for reading: $!\n"; } my $parser = XML::Parser->new( @params ); $parser->parse(do { local $/ = undef; }); close INFILE unless ref $file; return 1; } *parse_xml = \&parse; my %NoSetProperty = map { $_ => 1 } qw( CreationDate Producer ModDate Trapped ); sub _prepare_output { my $self = shift; my ($p) = @_; $p->parameter('openaction' => $self->{OPENACTION}); $p->parameter('openmode' => $self->{OPENMODE}); if (UNIVERSAL::isa($self->{INFO}, 'HASH')) { foreach my $key ( keys %{$self->{INFO}} ) { if ($NoSetProperty{$key}) { warn "Document property '$key' cannot be set.", $/; next; } $p->info($key, $self->{INFO}{$key}); } } else { $p->info($_, __PACKAGE__) for qw/Creator Author/; } # __PAGE__ is incremented after the page is done. $self->{PARAM_MAP}{__PAGE__} = 1; # __PAGEDEF__ is incremented when the pagedef begins. $self->{PARAM_MAP}{__PAGEDEF__} = 0; my $context = PDF::FromHTML::Template::Factory->create( 'CONTEXT', # Un-scoped variables X => 0, Y => 0, # Other variables PDF => $p, PARAM_MAP => [ $self->{PARAM_MAP} ], PDF_VERSION => $self->{PDF_VERSION}, DIE_ON_NO_PARAM => $self->{DIE_ON_NO_PARAM}, ); # Do a first pass through, noting important values # $_->preprocess($context) for @{$self->{TEMPLATES}}; # Do a second pass through, for actual rendering $_->render($context) for @{$self->{TEMPLATES}}; $context->close_images; return 1; } sub register { shift; PDF::FromHTML::Template::Factory::register(@_) } 1; __END__ =head1 NAME PDF::FromHTML::Template - PDF::FromHTML::Template =head1 SYNOPSIS use PDF::FromHTML::Template; my $pdf = PDF::FromHTML::Template->new({ file => 'some_template.xml', }); $pdf->param(%my_params); print "Content/type: application/pdf\n\n", $pdf->get_buffer; $pdf->write_file('some_file.pdf'); =head1 DESCRIPTION B: This is a fork of L 0.30, originally released by Rob Kinyon, but (as of September 11, 2006) currently not available on CPAN. Use of this module outside L is not advised. PDF::FromHTML::Template is a PDF layout system that uses the same data structures as L. =head1 OVERVIEW PDF::FromHTML::Template is a PDF layout system that uses the same data structures as L. Unlike L, this is a full layout system. This means you will have to describe where each item will be on the page. (This is in contrast to L, which adds on to Lut is determined by the HTML, not L.) PDF::FromHTML::Template uses an XML document as the template. However, the XML is not completely compliant. The only difference (that I'm aware of) is that any node can have any parameter. (This prevents the creation of a DTD.) The reason for this is to allow scoping by parents for parameters used by children. (More on this later.) Each node in the document corresponds to an object, with each parameter mapping (mostly) 1 to 1 to an object attribute. Parent-child relationships are strictly preserved. Each parent provides a scope (similar to variable scope) to its children. (This is why any node can have any parameter.) If a child needs the value of a parameter and it doesn't have that value as an attribute, it will ask its parent for the value. If the parent doesn't have it, it will ask its parent, and so on. =head1 METHODS =over 4 =item * C This will create a new instance of PDF::FromHTML::Template. $opts is an optional hashref that can contain the following parameters: =over 4 =item * file This is either the name of the file or the filehandle of the open file. If it is present, C will be called upon that filename/filehandle. Otherwise, after new() is called, you will have to call C yourself. filename is a synonym for file. =item * openaction This is the action that the PDF reader will take when it opens this file. The valid values are: =over 4 =item * fitbox =item * fitheight =item * fitpage (default) =item * fitwidth =item * retain =back =item * openmode This is the mode that the PDF reader will use when it opens this file. The valid values are: =over 4 =item * bookmarks =item * fullscreen =item * none (default) =item * thumbnails =back =item * info This is a hashref of information that you wish to have the PDF retain as metadata. If this is not present, both Author and Creator will be set to PDF::FromHTML::Template. The following keys are not supported: =over 4 =item * CreationDate =item * Producer =item * ModDate =item * Trapped =back =item * pdf_encoding This is the encoding that the template is in. It defaults to the host encoding. This is different from the encoding parameter for the pdftemplate tag. =back =item * C This will parse the XML template into the appropriate datastructure(s) needed for PDF::FromHTML::Template to function. =item * C This is a deprecated synonym for C. =item * C value, [ key => value, ... ] )> This will set the parameters that PDF::FromHTML::Template will use to merge the template with. This method is identical to the HTML::Template or Template Toolkit method of the same name. =item * C This will write the rendered PDF to the file specified in $filename. =item * C This will return the rendered PDF stringified in a form appropriate for returning over an HTTP connection. =item * C This is a synonym for C provided for HTML::Template compatibility. =item * C XXX =back =head1 USAGE There are a few consistency rules that that every PDF::FromHTML::Template has to follow: =over 4 =item 1 The root node is called PDFTEMPLATE =item 2 There must be at least one PAGEDEF (which does not have to be a direct child of the PDFTEMPLATE node) =item 3 All rendering elements (include FONT tags) must be within a PAGEDEF node =item 4 There must be a FONT tag as an ancestor of every TEXTBOX node =item 5 Within a PAGEDEF, there can only be one HEADER node and one FOOTER node =back For more information about each node, please see the POD for that class. =head1 WWW CAVEATS When taking an HTML page and adding a PDF option, there are a few differences to take into account. The primary one is the idea of pagebreaks. HTML is displayed as a single page, with scrolling. Paper doesn't scroll, so when there should be a new page is something PDF::FromHTML::Template works very hard at determining. It will take into account any header and footer information you've provided, as well as page sizes. The second is that you have to determine how wide you want your text to be. One of the most common activities is to take a tabular report and covert it to a PDF. In HTML, the browser handles text width for you. Right now, there isn't a TABLE tag (though work is being done on it). So, you have to layout out your TEXTBOX nodes by hand. (See the EXAMPLES for some ideas on this.) That said, it really isn't that hard. TR/TH tags convert to ROW tags easily, and TD tags are basically TEXTBOX tags. Add a few width="20%" (or whatever) and you're fine. =head1 BUGS None, that I'm aware of. =head1 LIMITATIONS Currently, the only PDF renderer PDF::FromHTML::Template supports is PDFlib (available at www.pdflib.com). The next release of PDF::FromHTML::Template will also support PDF::API2. Unless you need Unicode support, PDFlib Lite is sufficient (and free). Please see L for more details. I am aware that PDFlib will not compile under AIX or Cygwin. These are problems that PDFlib has acknowledged to me. =head1 AUTHOR/MAINTAINER Originally written by Dave Ferrance (dave@ferrance.org) Taken over after v0.05 by Rob Kinyon (rob.kinyon@iinteractive.com) =head1 CONTRIBUTORS Patches and ideas provided by: =over 4 =item * Audrey Tang Provided the impetus to move to L (which she also wrote). =item * Michael Kiwala Aided in the design and testing of the transition from Dave Ferrance's version. =item * Nathan Byrd Provided nearly all the initial doublebyte expertise. =back Additionally, there is a mailing list at L =head1 COPYRIGHT This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO perl(1). =cut PDF-FromHTML-0.33/lib/PDF/FromHTML/Template/PaxHeader/Constants.pm000644 000765 000024 00000000036 13554101202 025053 xustar00audreytstaff000000 000000 30 mtime=1571848834.230957531 PDF-FromHTML-0.33/lib/PDF/FromHTML/Template/Constants.pm000644 000765 000024 00000004431 13554101202 023105 0ustar00audreytstaff000000 000000 package PDF::FromHTML::Template::Constants; use strict; BEGIN { use Exporter (); use vars qw(@ISA @EXPORT_OK); @ISA = qw(Exporter); @EXPORT_OK = qw( %PointsPer %Verify ); } # This is a list of conversions from various units of measure to points. # The key will be the first letter of the unit. our %PointsPer = ( I => 72.27, # Inches P => 1, # Points ); $PointsPer{C} = ($PointsPer{I} / 2.54); # Centimeters #GGG Add: # PDFTemplate properties (to go with %NoSetProperty) our %Verify = ( #GGG This also needs improvement ... Not all available fonts are listed 'FACE' => { '__DEFAULT__' => 'Times-Bold', ( map { $_ => 1 } qw( Courier Courier-Bold Courier-Oblique Courier-BoldOblique Helvetica Helvetica-Bold Helvetica-Oblique Helvetica-BoldOblique Times-Roman Times-Bold Times-Italic Times-BoldItalic Symbol ZapfDingbats )), }, 'ALIGN' => { '__DEFAULT__' => 'left', #GGG Add a full-justify option - this requires a lot of coding prowess ( map { $_ => 1 } qw( center left right )), }, 'OPENACTION' => { '__DEFAULT__' => 'fitpage', ( map { $_ => 1 } qw( fitbox fitheight fitpage fitwidth retain )), }, 'OPENMODE' => { '__DEFAULT__' => 'none', ( map { $_ => 1 } qw( bookmarks fullscreen none thumbnails )), }, # Pagesize is specified in points 'PAGESIZE' => { '__DEFAULT__' => 'Letter', 'Letter' => { PAGE_WIDTH => 8.5 * $PointsPer{I}, PAGE_HEIGHT => 11 * $PointsPer{I}, }, 'Legal' => { PAGE_WIDTH => 8.5 * $PointsPer{I}, PAGE_HEIGHT => 14 * $PointsPer{I}, }, 'A0' => { PAGE_WIDTH => 2380, PAGE_HEIGHT => 3368, }, 'A1' => { PAGE_WIDTH => 1684, PAGE_HEIGHT => 2380, }, 'A2' => { PAGE_WIDTH => 1190, PAGE_HEIGHT => 1684, }, 'A3' => { PAGE_WIDTH => 842, PAGE_HEIGHT => 1190, }, 'A4' => { PAGE_WIDTH => 595, PAGE_HEIGHT => 842, }, }, ); 1; __END__ PDF-FromHTML-0.33/lib/PDF/FromHTML/Template/Element/000755 000765 000024 00000000000 13554103473 022176 5ustar00audreytstaff000000 000000 PDF-FromHTML-0.33/lib/PDF/FromHTML/Template/PaxHeader/Element.pm000644 000765 000024 00000000036 13554101202 024470 xustar00audreytstaff000000 000000 30 mtime=1571848834.236203596 PDF-FromHTML-0.33/lib/PDF/FromHTML/Template/Element.pm000644 000765 000024 00000002124 13554101202 022517 0ustar00audreytstaff000000 000000 package PDF::FromHTML::Template::Element; use strict; BEGIN { use vars qw(@ISA); @ISA = qw(PDF::FromHTML::Template::Base); use PDF::FromHTML::Template::Base; } sub set_color { my $self = shift; my ($context, $attr, $mode, $depth) = @_; my $color = $context->get($self, $attr, $depth); return 1 unless $color; my @colors = map { $_ / 255 } split /,\s*/, $color, 3; $context->{PDF}->color($mode, 'rgb', @colors); return 1; } 1; __END__ =head1 NAME PDF::FromHTML::Template::Element =head1 PURPOSE To provide a base class for all rendering nodes. =head1 COLORS This is the class that handles colors. Colors in PDF::FromHTML::Template are specified in RGB format, comma-separated. Each number is from 0 to 255, with 0 being none and 255 being most. If a color is not specified, 0 is assumed. Thus, "255,0,0", "255,0", and "255" will all result in a red color. Colors should be used for all attributes that have the word "COLOR" in the name. This includes (but may not be limited to): =over 4 =item * COLOR =item * FILLCOLOR =back =head1 SEE ALSO =cut PDF-FromHTML-0.33/lib/PDF/FromHTML/Template/PaxHeader/Factory.pm000644 000765 000024 00000000036 13554101202 024506 xustar00audreytstaff000000 000000 30 mtime=1571848834.236687933 PDF-FromHTML-0.33/lib/PDF/FromHTML/Template/Factory.pm000644 000765 000024 00000007127 13554101202 022545 0ustar00audreytstaff000000 000000 package PDF::FromHTML::Template::Factory; use strict; BEGIN { use vars qw(%Manifest %isBuildable); } %Manifest = ( # These are the instantiable nodes 'ALWAYS' => 'PDF::FromHTML::Template::Container::Always', 'CONDITIONAL' => 'PDF::FromHTML::Template::Container::Conditional', 'FONT' => 'PDF::FromHTML::Template::Container::Font', 'IF' => 'PDF::FromHTML::Template::Container::Conditional', 'LOOP' => 'PDF::FromHTML::Template::Container::Loop', 'PAGEDEF' => 'PDF::FromHTML::Template::Container::PageDef', 'PDFTEMPLATE' => 'PDF::FromHTML::Template::Container::PdfTemplate', 'ROW' => 'PDF::FromHTML::Template::Container::Row', 'SCOPE' => 'PDF::FromHTML::Template::Container::Scope', 'SECTION' => 'PDF::FromHTML::Template::Container::Section', 'HEADER' => 'PDF::FromHTML::Template::Container::Header', 'FOOTER' => 'PDF::FromHTML::Template::Container::Footer', 'BOOKMARK' => 'PDF::FromHTML::Template::Element::Bookmark', 'CIRCLE' => 'PDF::FromHTML::Template::Element::Circle', 'HR' => 'PDF::FromHTML::Template::Element::HorizontalRule', 'IMAGE' => 'PDF::FromHTML::Template::Element::Image', 'PAGEBREAK' => 'PDF::FromHTML::Template::Element::PageBreak', 'LINE' => 'PDF::FromHTML::Template::Element::Line', 'TEXTBOX' => 'PDF::FromHTML::Template::Element::TextBox', 'VAR' => 'PDF::FromHTML::Template::Element::Var', 'WEBLINK' => 'PDF::FromHTML::Template::Element::Weblink', # These are the helper objects 'TEXTOBJECT' => 'PDF::FromHTML::Template::TextObject', 'CONTEXT' => 'PDF::FromHTML::Template::Context', 'ITERATOR' => 'PDF::FromHTML::Template::Iterator', 'MARGIN' => 'PDF::FromHTML::Template::Container::Margin', 'CONTAINER' => 'PDF::FromHTML::Template::Container', 'ELEMENT' => 'PDF::FromHTML::Template::Element', 'BASE' => 'PDF::FromHTML::Template::Base', ); %isBuildable = map { $_ => 1 } qw( ALWAYS BOOKMARK CIRCLE CONDITIONAL FONT FOOTER HEADER HR IF IMAGE LINE LOOP PAGEBREAK PAGEDEF PDFTEMPLATE ROW SCOPE SECTION TEXTBOX VAR WEBLINK ); sub register { my %params = @_; my @param_names = qw(name class isa); for (@param_names) { unless ($params{$_}) { warn "$_ was not supplied to register()\n"; return 0; } } my $name = uc $params{name}; if (exists $Manifest{$name}) { warn "$params{name} already exists in the manifest.\n"; return 0; } my $isa = uc $params{isa}; unless (exists $Manifest{$isa}) { warn "$params{isa} does not exist in the manifest.\n"; return 0; } $Manifest{$name} = $params{class}; $isBuildable{$name} = 1; { no strict 'refs'; unshift @{"$params{class}::ISA"}, $Manifest{$isa}; } return 1; } sub create { my $class = shift; my $name = uc shift; return unless exists $Manifest{$name}; (my $filename = $Manifest{$name}) =~ s!::!/!g; eval { require "$filename.pm"; }; if ($@) { die "Cannot find or compile PM file for '$name' ($filename)\n"; } return $Manifest{$name}->new(@_); } sub create_node { my $class = shift; my $name = uc shift; return unless exists $isBuildable{$name}; return $class->create($name, @_); } sub isa { return UNIVERSAL::isa($_[0], $Manifest{uc $_[1]}) if @_ >= 2 && exists $Manifest{uc $_[1]}; UNIVERSAL::isa(@_) } 1; __END__ PDF-FromHTML-0.33/lib/PDF/FromHTML/Template/PaxHeader/Iterator.pm000644 000765 000024 00000000036 13554101202 024670 xustar00audreytstaff000000 000000 30 mtime=1571848834.237090293 PDF-FromHTML-0.33/lib/PDF/FromHTML/Template/Iterator.pm000644 000765 000024 00000010331 13554101202 022716 0ustar00audreytstaff000000 000000 package PDF::FromHTML::Template::Iterator; use strict; BEGIN { use vars qw(@ISA); @ISA = qw(PDF::FromHTML::Template::Base); use PDF::FromHTML::Template::Base; } sub new { my $class = shift; my $self = $class->SUPER::new(@_); unless (PDF::FromHTML::Template::Factory::isa($self->{CONTEXT}, 'CONTEXT')) { die "Internal Error: No context object passed to ", __PACKAGE__, $/; } $self->{MAXITERS} ||= 0; # This is the index we will work on NEXT, in whatever direction the # iterator is going. $self->{INDEX} = -1; # This will always increment because it's tracking how many iterations # have happened on this page, regardless of the direction the iterator # is traveling. $self->{ITERS_THIS_PAGE} = 0; # This is a short-circuit parameter to let the iterator function in a # null state. $self->{NO_PARAMS} = 0; unless ($self->{NAME} =~ /\w/) { $self->{NO_PARAMS} = 1; warn "INTERNAL ERROR: 'NAME' was blank was blank when passed to ", __PACKAGE__, $/; return $self; } # Cache the reference to the appropriate data. $self->{DATA} = $self->{CONTEXT}->param($self->{NAME}); unless (UNIVERSAL::isa($self->{DATA}, 'ARRAY')) { $self->{NO_PARAMS} = 1; warn "'$self->{NAME}' does not have a list of parameters", $/; return $self; } unless (@{$self->{DATA}}) { $self->{NO_PARAMS} = 1; } $self->{MAX_INDEX} = $#{$self->{DATA}}; return $self; } sub enter_scope { my $self = shift; return 0 if $self->{NO_PARAMS}; for my $x ($self->{DATA}[$self->{INDEX}]) { $x->{uc $_} = delete $x->{$_} for keys %$x; } push @{$self->{CONTEXT}{PARAM_MAP}}, $self->{DATA}[$self->{INDEX}]; return 1; } sub exit_scope { my $self = shift; return 0 if $self->{NO_PARAMS}; # There has to be the base parameter map and at least the one that # Iterator::enter_scope() added on top. @{$self->{CONTEXT}{PARAM_MAP}} > 1 || die "Internal Error: ", __PACKAGE__, "'s internal param_map off!", $/; pop @{$self->{CONTEXT}{PARAM_MAP}}; return 1; } sub can_continue { my $self = shift; return 0 if $self->{NO_PARAMS}; return 1 if $self->more_params && $self->more_space && $self->more_iters; return 0; } sub more_iters { my $self = shift; return 0 if $self->{NO_PARAMS}; return 1 unless $self->{MAXITERS}; return 1 if $self->{MAXITERS} > $self->{ITERS_THIS_PAGE}; return 0; } sub more_params { my $self = shift; return 0 if $self->{NO_PARAMS}; return 1 if $self->{MAX_INDEX} > $self->{INDEX}; return 0; } sub more_space { my $self = shift; return 0 if $self->{NO_PARAMS}; return 1 if $self->{CONTEXT}->get($self, 'Y') >= ($self->{CONTEXT}->get($self, 'END_Y')); return 0; } # Call this method BEFORE incrementing the index to the next value. sub _do_globals { my $self = shift; my $data = $self->{DATA}[$self->{INDEX}]; # Perl's arrays are 0-indexed. Thus, the first element is at index "0". # This means that odd-numbered elements are at even indices, and vice-versa. # This also means that MAX (the number of elements in the array) can never # be the value of an index. It is NOT the last index in the array. $data->{'__FIRST__'} ||= ($self->{INDEX} == 0); $data->{'__INNER__'} ||= (0 < $self->{INDEX} && $self->{INDEX} < $self->{MAX_INDEX}); $data->{'__LAST__'} ||= ($self->{INDEX} == $self->{MAX_INDEX}); $data->{'__ODD__'} ||= !($self->{INDEX} % 2); return 1; } sub next { my $self = shift; return 0 if $self->{NO_PARAMS}; return 0 unless $self->more_params; $self->exit_scope; $self->{INDEX}++; $self->{ITERS_THIS_PAGE}++; $self->_do_globals; $self->enter_scope; return 1; } sub back_up { my $self = shift; return 0 if $self->{NO_PARAMS}; $self->exit_scope; $self->{INDEX}--; $self->{ITERS_THIS_PAGE}++; $self->_do_globals; $self->enter_scope; return 1; } sub reset { my $self = shift; return 0 if $self->{NO_PARAMS}; $self->{INDEX} = -1; $self->{ITERS_THIS_PAGE} = 0; return 1; } 1; __END__ PDF-FromHTML-0.33/lib/PDF/FromHTML/Template/PaxHeader/Context.pm000644 000765 000024 00000000036 13554101202 024523 xustar00audreytstaff000000 000000 30 mtime=1571848834.237565024 PDF-FromHTML-0.33/lib/PDF/FromHTML/Template/Context.pm000644 000765 000024 00000015034 13554101202 022556 0ustar00audreytstaff000000 000000 package PDF::FromHTML::Template::Context; use strict; BEGIN { use vars qw(@ISA); @ISA = qw(PDF::FromHTML::Template::Base); use PDF::FromHTML::Template::Base; use PDF::FromHTML::Template::Constants qw( %PointsPer ); } # This is a helper object. It is not instantiated by the user, # nor does it represent an XML object. Rather, every container # will use this object to maintain the context for its children. sub new { my $class = shift; my $self = $class->SUPER::new(@_); $self->{FONTS} = {} unless UNIVERSAL::isa($self->{FONTS}, 'HASH'); $self->{IMAGES} = {} unless UNIVERSAL::isa($self->{IMAGES}, 'HASH'); $self->{PARAM_MAP} = [] unless UNIVERSAL::isa($self->{PARAM_MAP}, 'ARRAY'); $self->{STACK} = [] unless UNIVERSAL::isa($self->{STACK}, 'ARRAY'); $self->reset_pagebreak; return $self; } sub param { my $self = shift; my ($param, $depth) = @_; $param = uc $param; $depth ||= 0; my $val = undef; my $found = 0; for my $map (reverse @{$self->{PARAM_MAP}}) { next unless exists $map->{$param}; $depth--, next if $depth; $found = 1; $val = $map->{$param}; last; } die "Parameter '$param' not found", $/ if !$found && $self->{DIE_ON_NO_PARAM}; return $val; } #GGG This is god-awful my %isDimension = map { $_ => 1 } qw( X Y W H R START_Y END_Y X1 X2 Y1 Y2 PAGE_HEIGHT PAGE_WIDTH HEADER_HEIGHT FOOTER_HEIGHT LEFT_MARGIN RIGHT_MARGIN LMARGIN RMARGIN SIZE WIDTH SCALE ); sub resolve { my $self = shift; my ($obj, $key, $depth) = @_; $key = uc $key; $depth ||= 0; my $obj_val = $obj->{$key}; my $is_param = 0; $is_param = 1 if $obj_val =~ s/\$(\w+)/$self->param($1)/eg; return $obj_val unless $isDimension{$key}; #GGG Does this adequately test values to make sure they're legal?? # A value is defined as: # 1) An optional operator (+, -, *, or /) # 2) A decimal number # 3) An optional unit (currently I, P, or C) or % (indicating percentage) #GGG Convert this to use //x my ($op, $val, $unit) = $obj_val =~ m!^\s*([\+\*\/\-])?\s*([\d.]*\d)\s*([a-z%]+)?\s*$!oi; $op ||= ''; if ($unit) { # Only the first character of the unit is useful, and it needs to be uppercase to key # into %PointsPer. my $uom = uc substr($unit, 0, 1); if ($uom eq '%') { #GGG Is this all that's needed? if ($key eq 'W') { $val *= ($self->get($obj, 'PAGE_WIDTH') - $self->get($obj, 'LEFT_MARGIN') - $self->get($obj, 'RIGHT_MARGIN')); } elsif ($key eq 'H') { $val *= ($self->get($obj, 'PAGE_HEIGHT') - $self->get($obj, 'HEADER_HEIGHT') - $self->get($obj, 'FOOTER_HEIGHT')); } $val /= 100; } elsif (exists $PointsPer{$uom}) { $val *= $PointsPer{$uom}; } else { warn "'$unit' is not a recognized unit of measurement.", $/; } $obj->{$key} = $op . $val unless $is_param; $obj_val = $val; } return $obj_val unless $op; my $prev_val = $key eq 'X' || $key eq 'Y' ? $self->{$key} : $self->get($obj, $key, $depth + 1); return $obj_val unless defined $prev_val; return $prev_val unless defined $obj_val; # Prevent divide-by-zero issues. return $val if $op eq '/' and $val == 0; my $new_val; for ($op) { /^\+$/ && do { $new_val = ($prev_val + $val); last; }; /^\-$/ && do { $new_val = ($prev_val - $val); last; }; /^\*$/ && do { $new_val = ($prev_val * $val); last; }; /^\/$/ && do { $new_val = ($prev_val / $val); last; }; die "Unknown operator '$op' in arithmetic resolve", $/; } return $new_val if defined $new_val; return; } sub enter_scope { my $self = shift; my ($obj) = @_; push @{$self->{STACK}}, $obj; for my $key (qw(X Y)) { next unless exists $obj->{$key}; $self->{$key} = $self->resolve($obj, $key); } return 1; } sub exit_scope { my $self = shift; my ($obj, $no_delta) = @_; unless ($no_delta) { my $deltas = $obj->deltas($self); $self->{$_} += $deltas->{$_} for keys %$deltas; } pop @{$self->{STACK}}; return 1; } sub get { my $self = shift; my ($dummy, $key, $depth) = @_; $depth ||= 0; $key = uc $key; return unless @{$self->{STACK}}; my $obj = $self->{STACK}[-1]; if (exists $obj->{"TEMP_$key"}) { my $val = delete $obj->{"TEMP_$key"}; return $val; } return $self->{$key} if $key eq 'X' || $key eq 'Y'; my $val = undef; my $this_depth = $depth; foreach my $e (reverse @{$self->{STACK}}) { next unless exists $e->{$key}; next if $this_depth-- > 0; $val = $self->resolve($e, $key, $depth); last; } $val = $self->{$key} unless defined $val; return $val unless defined $val; return $self->param($1, $depth) if $val =~ /^\$(\S+)$/o; return $val; } sub should_render { my $self = shift; my ($obj) = @_; # The objects for which this would be bad are going to bypass this check as they # see fit. All other objects should not render if the pagebreak has been tripped. return 0 if $self->pagebreak_tripped; return $self->check_end_of_page($obj); } sub check_end_of_page { my $self = shift; my ($obj) = @_; my $deltas = $obj->deltas($self); if ( ($self->get($obj, 'Y') || 0) + ($deltas->{Y} || 0) < ($self->get($obj, 'END_Y') || 0) ) { $self->trip_pagebreak; return 0; } return 1; } sub close_images { my $self = shift; my $p = $self->{PDF}; $p->close_image($_) for values %{$self->{IMAGES}}; } sub new_page_def { my $self = shift; $self->{PARAM_MAP}[0]{__PAGEDEF__}++; $self->{PARAM_MAP}[0]{__PAGEDEF_PAGE__} = 1; } sub trip_pagebreak { $_[0]{PB_TRIP} = 1 } sub reset_pagebreak { $_[0]{PB_TRIP} = 0 } sub pagebreak_tripped { $_[0]{PB_TRIP} = $_[1] if defined $_[1]; $_[0]{PB_TRIP} } sub store_font { $_[0]{FONTS}{$_[1]} ||= $_[2] } sub retrieve_font { $_[0]{FONTS}{$_[1]} } sub delete_fonts { $_[0]{FONTS} = {}; } sub store_image { $_[0]{IMAGES}{$_[1]} ||= $_[2] } sub retrieve_image { $_[0]{IMAGES}{$_[1]} } sub increment_pagenumber { $_[0]{PARAM_MAP}[0]{$_}++ for qw(__PAGE__ __PAGEDEF_PAGE__) } 1; __END__ PDF-FromHTML-0.33/lib/PDF/FromHTML/Template/Container/000755 000765 000024 00000000000 13554103473 022527 5ustar00audreytstaff000000 000000 PDF-FromHTML-0.33/lib/PDF/FromHTML/Template/PaxHeader/Container.pm000644 000765 000024 00000000036 13554101202 025021 xustar00audreytstaff000000 000000 30 mtime=1571848834.242111096 PDF-FromHTML-0.33/lib/PDF/FromHTML/Template/Container.pm000644 000765 000024 00000005272 13554101202 023057 0ustar00audreytstaff000000 000000 package PDF::FromHTML::Template::Container; use strict; BEGIN { use vars qw(@ISA); @ISA = qw(PDF::FromHTML::Template::Base); use PDF::FromHTML::Template::Base; } # Containers are objects that can contain arbitrary elements, such as # PageDefs or Loops. sub new { my $class = shift; my $self = $class->SUPER::new(@_); $self->{ELEMENTS} = [] unless UNIVERSAL::isa($self->{ELEMENTS}, 'ARRAY'); return $self; } sub _do_page { my $self = shift; my ($context, $method) = @_; for my $e (@{$self->{ELEMENTS}}) { $e->enter_scope($context); $e->$method($context); $e->exit_scope($context, 1); } return 1; } sub begin_page { _do_page @_, 'begin_page' } #{ # my $self = shift; # my ($context) = @_; # # for my $e (@{$self->{ELEMENTS}}) # { # $e->enter_scope($context); # $e->begin_page($context); # $e->exit_scope($context, 1); # } # # return 1; #} sub end_page { _do_page @_, 'end_page' } #{ # my $self = shift; # my ($context) = @_; # # for my $e (@{$self->{ELEMENTS}}) # { # $e->enter_scope($context); # $e->end_page($context); # $e->exit_scope($context, 1); # } # # return 1; #} sub reset { my $self = shift; $self->SUPER::reset; $_->reset for @{$self->{ELEMENTS}}; } sub iterate_over_children { my $self = shift; my ($context) = @_; my $continue = 1; for my $e (grep !$_->has_rendered, @{$self->{ELEMENTS}}) { $e->enter_scope($context); my $rc; if ($rc = $e->render($context)) { $e->mark_as_rendered; } $continue = $rc if $continue; $e->exit_scope($context); } return $continue; } sub render { my $self = shift; my ($context) = @_; return 0 unless $self->should_render($context); return $self->iterate_over_children($context); } sub max_of { my $self = shift; my ($context, $attr) = @_; my $max = $context->get($self, $attr); ELEMENT: foreach my $e (@{$self->{ELEMENTS}}) { $e->enter_scope($context); my $v = $e->isa('CONTAINER') ? $e->max_of($context, $attr) : $e->calculate($context, $attr); $max = $v if $max < $v; $e->exit_scope($context, 1); } return $max; } sub total_of { my $self = shift; my ($context, $attr) = @_; my $total = 0; ELEMENT: foreach my $e (@{$self->{ELEMENTS}}) { $e->enter_scope($context); $total += $e->isa('CONTAINER') ? $e->total_of($context, $attr) : $e->calculate($context, $attr); $e->exit_scope($context, 1); } return $total; } 1; __END__ PDF-FromHTML-0.33/lib/PDF/FromHTML/Template/PaxHeader/Base.pm000644 000765 000024 00000000036 13554101202 023751 xustar00audreytstaff000000 000000 30 mtime=1571848834.242480758 PDF-FromHTML-0.33/lib/PDF/FromHTML/Template/Base.pm000644 000765 000024 00000005430 13554101202 022003 0ustar00audreytstaff000000 000000 package PDF::FromHTML::Template::Base; use strict; BEGIN { } use PDF::FromHTML::Template::Constants qw( %Verify ); use PDF::FromHTML::Template::Factory; sub new { my $class = shift; push @_, %{shift @_} while UNIVERSAL::isa($_[0], 'HASH'); (@_ % 2) && die "$class->new() called with odd number of option parameters", $/; my %x = @_; # Do not use a hashref-slice here because of the uppercase'ing my $self = {}; $self->{uc $_} = $x{$_} for keys %x; $self->{__THIS_HAS_RENDERED__} = 0; bless $self, $class; } sub isa { PDF::FromHTML::Template::Factory::isa(@_) } # These functions are used in the P::T::Container & P::T::Element hierarchies sub _validate_option { my $self = shift; my ($option, $val_ref) = @_; $option = uc $option; return 1 unless exists $Verify{$option} && UNIVERSAL::isa($Verify{$option}, 'HASH'); if (defined $val_ref) { if (!defined $$val_ref) { $$val_ref = $Verify{$option}{'__DEFAULT__'}; } elsif (!exists $Verify{$option}{$$val_ref}) { my $name = ucfirst lc $option; warn "$name '$$val_ref' unsupported. Defaulting to '$Verify{$option}{'__DEFAULT__'}'", $/; $$val_ref = $Verify{$option}{'__DEFAULT__'}; } } elsif (!defined $self->{$option}) { $self->{$option} = $Verify{$option}{'__DEFAULT__'}; } elsif (!exists $Verify{$option}{$self->{$option}}) { my $name = ucfirst lc $option; warn "$name '$self->{$option}' unsupported. Defaulting to '$Verify{$option}{'__DEFAULT__'}'", $/; $self->{$option} = $Verify{$option}{'__DEFAULT__'}; } return 1; } sub calculate { ($_[1])->get(@_[0,2]) } #{ # my $self = shift; # my ($context, $attr) = @_; # # return $context->get($self, $attr); #} sub enter_scope { ($_[1])->enter_scope($_[0]) } #{ # my $self = shift; # my ($context) = @_; # # return $context->enter_scope($self); #} sub exit_scope { ($_[1])->exit_scope(@_[0, 2]) } #{ # my $self = shift; # my ($context, $no_delta) = @_; # # return $context->exit_scope($self, $no_delta); #} sub deltas { # my $self = shift; # my ($context) = @_; return {}; } sub reset { $_[0]{__THIS_HAS_RENDERED__} = 0 } sub mark_as_rendered { $_[0]{__THIS_HAS_RENDERED__} = 1 } sub has_rendered { $_[0]{__THIS_HAS_RENDERED__} } sub should_render { ($_[0]{__THIS_HAS_RENDERED__}) || (($_[1])->should_render($_[0])) } sub resolve { # my $self = shift; # my ($context) = @_; ''; } sub render { # my $self = shift; # my ($context) = @_; return 1; } sub begin_page { # my $self = shift; # my ($context) = @_; return 1; } sub end_page { # my $self = shift; # my ($context) = @_; return 1; } 1; __END__ PDF-FromHTML-0.33/lib/PDF/FromHTML/Template/PaxHeader/TextObject.pm000644 000765 000024 00000000036 13554101202 025152 xustar00audreytstaff000000 000000 30 mtime=1571848834.242904624 PDF-FromHTML-0.33/lib/PDF/FromHTML/Template/TextObject.pm000644 000765 000024 00000002101 13554101202 023174 0ustar00audreytstaff000000 000000 package PDF::FromHTML::Template::TextObject; use strict; BEGIN { use vars qw(@ISA); @ISA = qw(PDF::FromHTML::Template::Base); use PDF::FromHTML::Template::Base; use Encode; } # This is a helper object. It is not instantiated by the user, # nor does it represent an XML object. Rather, certain elements, # such as , can use this object to do text with variable # substitutions. sub new { my $class = shift; my $self = $class->SUPER::new(@_); $self->{STACK} = [] unless UNIVERSAL::isa($self->{STACK}, 'ARRAY'); return $self; } sub resolve { my $self = shift; my ($context) = @_; my $t = ''; for my $tok (@{$self->{STACK}}) { my $val = $tok; $val = $val->resolve($context) if PDF::FromHTML::Template::Factory::isa($val, 'VAR'); my $encoding = $context->get($self, 'PDF_ENCODING'); if ($encoding) { if (Encode::is_utf8($val)) { $val = Encode::encode($encoding,$val); } } $t .= $val; } return $t; } 1; __END__ PDF-FromHTML-0.33/lib/PDF/FromHTML/Template/Container/PaxHeader/Header.pm000644 000765 000024 00000000036 13554101202 026211 xustar00audreytstaff000000 000000 30 mtime=1571848834.238126524 PDF-FromHTML-0.33/lib/PDF/FromHTML/Template/Container/Header.pm000644 000765 000024 00000002365 13554101202 024247 0ustar00audreytstaff000000 000000 package PDF::FromHTML::Template::Container::Header; use strict; BEGIN { use vars qw(@ISA); @ISA = qw(PDF::FromHTML::Template::Container::Margin); use PDF::FromHTML::Template::Container::Margin; } sub enter_scope { my $self = shift; my ($context) = @_; $self->SUPER::enter_scope( $context ); @{$self}{qw/OLD_X OLD_Y/} = map { $context->get($self, $_) } qw(X Y); $context->{X} = 0; $context->{Y} = $context->get($self, 'PAGE_HEIGHT'); return 1; } 1; __END__ =head1 NAME PDF::FromHTML::Template::Container::Header =head1 PURPOSE To provide header text and to specify where the header starts, for looping. =head1 NODE NAME HEADER =head1 INHERITANCE PDF::FromHTML::Template::Container::Margin =head1 ATTRIBUTES =over 4 =item * HEADER_HEIGHT - the amount reserved for the header from the bottom of the page. =back =head1 CHILDREN None =head1 AFFECTS Indicates to the PAGEDEF tag where all children may start rendering. =head1 DEPENDENCIES None =head1 USAGE
... Children here will render on every page ...
... Stuff here ...
=head1 AUTHOR Rob Kinyon (rkinyon@columbus.rr.com) =head1 SEE ALSO ALWAYS, FOOTER, PAGEDEF =cut PDF-FromHTML-0.33/lib/PDF/FromHTML/Template/Container/PaxHeader/Always.pm000644 000765 000024 00000000036 13554101202 026261 xustar00audreytstaff000000 000000 30 mtime=1571848834.238530779 PDF-FromHTML-0.33/lib/PDF/FromHTML/Template/Container/Always.pm000644 000765 000024 00000003071 13554101202 024312 0ustar00audreytstaff000000 000000 package PDF::FromHTML::Template::Container::Always; use strict; BEGIN { use vars qw(@ISA); @ISA = qw(PDF::FromHTML::Template::Container); use PDF::FromHTML::Template::Container; } sub enter_scope { my $self = shift; my ($context) = @_; $self->SUPER::enter_scope($context); $self->{OLD_TRIP} = $context->pagebreak_tripped; $context->reset_pagebreak; return 1; } sub exit_scope { my $self = shift; my ($context) = @_; $context->pagebreak_tripped($self->{OLD_TRIP}); $self->reset; return $self->SUPER::exit_scope($context); } sub mark_as_rendered {} 1; __END__ =head1 NAME PDF::FromHTML::Template::Container::Always =head1 PURPOSE To require that any child of this node will always render on every page. Normally, a node will not render on a given page if a node before it has triggered a pagebreak. ALWAYS nodes will always render on every page. Primarily, this is used as a base class for HEADER and FOOTER. However, you might want something to always render on every page outside the header and footer areas. For example, a watermark. =head1 NODE NAME ALWAYS =head1 INHERITANCE PDF::FromHTML::Template::Container =head1 ATTRIBUTES None =head1 CHILDREN PDF::FromHTML::Template::Container::Margin PDF::FromHTML::Template::Container::Header PDF::FromHTML::Template::Container::Footer =head1 AFFECTS Nothing =head1 DEPENDENCIES None =head1 USAGE ... Children will render on every page ... =head1 AUTHOR Rob Kinyon (rkinyon@columbus.rr.com) =head1 SEE ALSO HEADER, FOOTER =cut PDF-FromHTML-0.33/lib/PDF/FromHTML/Template/Container/PaxHeader/Margin.pm000644 000765 000024 00000000036 13554101202 026236 xustar00audreytstaff000000 000000 30 mtime=1571848834.238835766 PDF-FromHTML-0.33/lib/PDF/FromHTML/Template/Container/Margin.pm000644 000765 000024 00000003407 13554101202 024272 0ustar00audreytstaff000000 000000 package PDF::FromHTML::Template::Container::Margin; use strict; BEGIN { use vars qw(@ISA); @ISA = qw(PDF::FromHTML::Template::Container::Always); use PDF::FromHTML::Template::Container::Always; } # This is the common parent for
and