PDF-Create-1.08/000755 000765 000024 00000000000 12251772757 013530 5ustar00gaborstaff000000 000000 PDF-Create-1.08/CHANGES000644 000765 000024 00000002304 12251772645 014516 0ustar00gaborstaff000000 000000 1.08 2013.12.11 Eliminate pipe from CGI test script t/09 Filehandle => FileHandle typo fixed #91312 1.07 2013.12.10 New maintainer SZABGAB Tried to reconstruct entries in the CHANGES file Some more test case Code clean-up (remove indirect calls) Remove Build.PL use warnings; Officially require perl 5.006. Move example file to the eg/ directory 1.06 2010.07.06 1.05 2010.02.26 1.04 2009.07.13 1.03 200 2009.03.24 1.02 208.07.10 1.01 2008.06.03 1.00 2008.05.31 0.10 2008.05.31 0.09 2007.09.30 - Markus Baertschi, markus@markus.org - Added stringml for multi-line strings - Changed get_page_size to case-independent 0.08 2007.09.03 - Markus Baertschi, markus@markus.org - Get back in sync with CPAN/PAUSE - Fixed check for open file in Create.pm - Touched up the README 0.07 - Markus Baertschi, markus@markus.org - Added image samples to sample.pl - Touched up the README - Added check for open file in JPEG/GIFImages 0.06 - Fabien Tassin - Added support for JPEG and GIF images - Markus Baertschi, markus@markus.org - Packaged for release on CPAN 0.01 - Fabien Tassin - Original Release PDF-Create-1.08/eg/000755 000765 000024 00000000000 12251772756 014122 5ustar00gaborstaff000000 000000 PDF-Create-1.08/lib/000755 000765 000024 00000000000 12251772756 014275 5ustar00gaborstaff000000 000000 PDF-Create-1.08/Makefile.PL000644 000765 000024 00000001165 12251766376 015505 0ustar00gaborstaff000000 000000 # # Makefile.PL for PDF::Create # use 5.006; use ExtUtils::MakeMaker; WriteMakefile( NAME => "PDF::Create", VERSION_FROM => "lib/PDF/Create.pm", ABSTRACT_FROM => "lib/PDF/Create.pm", 'PREREQ_PM' => { 'Carp' => 0, 'FileHandle' => 0, 'Data::Dumper' => 0, }, LICENSE => "perl", dist => { COMPRESS => "gzip", SUFFIX => "gz" }, clean => { FILES => '*.bak *.old mibs/*.dump *.pdf' . 'lib/*/*~ lib/*/*/*~' }, META_MERGE => { resources => { repository => 'http://github.com/szabgab/pdf-create', } }, ); PDF-Create-1.08/MANIFEST000644 000765 000024 00000001136 12251772757 014662 0ustar00gaborstaff000000 000000 CHANGES eg/sample-cgi.pl eg/sample.pl lib/PDF/Create.pm lib/PDF/Create/Outline.pm lib/PDF/Create/Page.pm lib/PDF/Image/GIF.pm lib/PDF/Image/JPEG.pm Makefile.PL MANIFEST This list of files MANIFEST.SKIP pdf-logo.svg README t/01-basic.t t/02-string.t t/03-image.t t/04-drawing.t t/05-outline.t t/06-annotation.t t/07-fonts.t t/09-cgi-script.pl t/09-cgi.t t/11-encode.t t/50-versioning.t t/99-wifi-parabola.t t/pdf-logo.gif t/pdf-logo.jpg META.yml Module YAML meta-data (added by MakeMaker) META.json Module JSON meta-data (added by MakeMaker) PDF-Create-1.08/MANIFEST.SKIP000644 000765 000024 00000000215 12251676677 015430 0ustar00gaborstaff000000 000000 ^Makefile(\.old)?$ ^MANIFEST\.bak$ ^Maintenance-.* .*~$ (^|/)TAGS$ .*\.tar\.gz$ blib/ pm_to_blib \.pdf$ \.tmp$ ^devel/ .git/ ^\..* ^MYMETA.* PDF-Create-1.08/META.json000644 000765 000024 00000001761 12251772757 015156 0ustar00gaborstaff000000 000000 { "abstract" : "create PDF files", "author" : [ "unknown" ], "dynamic_config" : 1, "generated_by" : "ExtUtils::MakeMaker version 6.78, CPAN::Meta::Converter version 2.132661", "license" : [ "perl_5" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : "2" }, "name" : "PDF-Create", "no_index" : { "directory" : [ "t", "inc" ] }, "prereqs" : { "build" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "configure" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "runtime" : { "requires" : { "Carp" : "0", "Data::Dumper" : "0", "FileHandle" : "0" } } }, "release_status" : "stable", "resources" : { "repository" : { "url" : "http://github.com/szabgab/pdf-create" } }, "version" : "1.08" } PDF-Create-1.08/META.yml000644 000765 000024 00000001031 12251772757 014774 0ustar00gaborstaff000000 000000 --- abstract: 'create PDF files' author: - unknown build_requires: ExtUtils::MakeMaker: 0 configure_requires: ExtUtils::MakeMaker: 0 dynamic_config: 1 generated_by: 'ExtUtils::MakeMaker version 6.78, CPAN::Meta::Converter version 2.132661' license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: 1.4 name: PDF-Create no_index: directory: - t - inc requires: Carp: 0 Data::Dumper: 0 FileHandle: 0 resources: repository: http://github.com/szabgab/pdf-create version: 1.08 PDF-Create-1.08/pdf-logo.svg000644 000765 000024 00000012203 12251673270 015744 0ustar00gaborstaff000000 000000 image/svg+xml PDF PDF-Create-1.08/README000644 000765 000024 00000007613 12251673270 014405 0ustar00gaborstaff000000 000000 NAME PDF::Create - create PDF files DESCRIPTION PDF::Create allows you to create PDF documents using a large number of primitives, and emit the result as a PDF file or stream. PDF stands for Portable Document Format. Documents can have several pages, a table of content, an information section and many other PDF elements. More functionnalities will be added as needs arise. Documents are constructed on the fly so the memory footprint is not tied to the size of the pages but only to their number. It's main advantage over the other PDF modules is that it does not depend on other modules and is perl only (no compiler needed). If you want a quick and dirty way of creating pdf's, PDF::Create is for you. If you need a complete Framework to create complex PDF stuff, you better dive into the PDF::API2 based modules. More information about this module is included in this package. SYNOPSIS use PDF::Create; my $pdf = new PDF::Create('filename' => 'mypdf.pdf', 'Version' => 1.2, 'PageMode' => 'UseOutlines', 'Author' => 'Fabien Tassin', 'Title' => 'My title', ); my $root = $pdf->new_page('MediaBox' => [ 0, 0, 612, 792 ]); # Add a page which inherits its attributes from $root my $page = $root->new_page; # Prepare 2 fonts my $f1 = $pdf->font('Subtype' => 'Type1', 'Encoding' => 'WinAnsiEncoding', 'BaseFont' => 'Helvetica'); my $f2 = $pdf->font('Subtype' => 'Type1', 'Encoding' => 'WinAnsiEncoding', 'BaseFont' => 'Helvetica-Bold'); # Prepare a Table of Content my $toc = $pdf->new_outline('Title' => 'Document', 'Destination' => $page); $toc->new_outline('Title' => 'Section 1'); my $s2 = $toc->new_outline('Title' => 'Section 2'); $s2->new_outline('Title' => 'Subsection 1'); $page->stringc($f2, 40, 306, 426, "PDF::Create"); $page->stringc($f1, 20, 306, 396, "version $PDF::Create::VERSION"); # Add another page my $page2 = $root->new_page; $page2->line(0, 0, 612, 792); $page2->line(0, 792, 612, 0); $toc->new_outline('Title' => 'Section 3'); $pdf->new_outline('Title' => 'Summary'); # Add something to the first page $page->stringc($f1, 20, 306, 300, 'by Fabien Tassin '); # Add the missing PDF objects and a the footer then close the file $pdf->close; INSTALLATION Quick answer: perl -MCPAN -e 'install PDF::Create' Long answer: To install manually, cd to the directory containing the unpacked distribution and do one of the following: a. Create a makefile by running Makefile.PL using the perl program into whose library you want to install and then run make three times: perl Makefile.PL make make test make install b. To install into a private library, for example your home directory: perl Makefile.PL INSTALLSITELIB=$HOME/lib INSTALLMAN3DIR=$HOME/man make make test make pure_install AUTHORS - Fabien Tassin Original Author of PDF::Create - Markus Baertschi, markus@markus.org I have taken over maintenence of PDF::Create as Fabien has disappeared and did no longer maintain it in the last years. The last version of PDF::Create from Fabien is 0.06. All never versions have been modified by me. I maintain PDF::Create in git. You can access the repository directly at http://github.com/markusb/pdf-create. PDF-Create-1.08/t/000755 000765 000024 00000000000 12251772756 013772 5ustar00gaborstaff000000 000000 PDF-Create-1.08/t/01-basic.t000755 000765 000024 00000004236 12251673270 015455 0ustar00gaborstaff000000 000000 #!/usr/bin/perl -w # # PDF::Create - Test Script # # Copyright 2010- Markus Baertschi # # Please see the CHANGES and Changes file for the detailed change log # # Testing basic stuff # - open / close # - page root / new page # - comment # BEGIN { unshift @INC, "lib", "../lib" } use strict; use PDF::Create; use Test::More tests => 11; # we want the resulting pdf file to have the same name as the test my $pdfname = $0; $pdfname =~ s/\.t/\.pdf/; ################################################################### # # start testing # my $pdf = PDF::Create->new( 'filename' => "$pdfname", 'Version' => 1.2, 'PageMode' => 'UseOutlines', 'Author' => 'Markus Baertschi', 'Title' => 'Testing Basic Stuff', ); isa_ok( $pdf, 'PDF::Create' ); ok( $pdf->add_comment("Testing Basic Stuff"), "Add a comment" ); my $root = $pdf->new_page( 'MediaBox' => $pdf->get_page_size('A4') ); #ok( defined $root, "Create page root" ); isa_ok( $root, 'PDF::Create::Page' ); # Prepare font my $f1 = $pdf->font( 'Subtype' => 'Type1', 'Encoding' => 'WinAnsiEncoding', 'BaseFont' => 'Helvetica' ); ok( defined $f1, "Define Font" ); # Add a page which inherits its attributes from $root my $page = $root->new_page; ok( defined $page, "Page defined" ); # Page title and description ok( $page->stringc( $f1, 40, 306, 700, 'PDF::Create' ), "stringc" ); ok( $page->stringc( $f1, 20, 306, 650, "version $PDF::Create::VERSION" ), "stringc" ); ok( $page->stringc( $f1, 20, 306, 600, "Test: $0" ), "stringc" ); ok( $page->stringc( $f1, 20, 306, 550, 'Markus Baertschi (markus@markus.org)' ), "stringc" ); # Wrap up the PDF and close the file ok( !$pdf->close(), "Close PDF" ); ################################################################ # # Check the resulting pdf for errors with pdftotext # SKIP: { skip '/usr/bin/pdftotext not installed', 1 if (! -x '/usr/bin/pdftotext'); my $out = `/usr/bin/pdftotext $pdfname /dev/null 2>&1`; ok( $out eq "", "pdftotext $out"); } # # TODO: Add test with ghostscript # #echo | gs -q -sDEVICE=bbox 06-wifi-parabola-broken.pdf PDF-Create-1.08/t/02-string.t000755 000765 000024 00000006173 12251673270 015705 0ustar00gaborstaff000000 000000 #!/usr/bin/perl -w # # PDF::Create - Test Script # # Copyright 2010- Markus Baertschi # # Please see the CHANGES and Changes file for the detailed change log # # Testing string functions # - string l/r/c # - string_underline # BEGIN { unshift @INC, "lib", "../lib" } use strict; use PDF::Create; use Test::More tests => 19; # we want the resulting pdf file to have the same name as the test my $pdfname = $0; $pdfname =~ s/\.t/\.pdf/; ################################################################### # # start testing # my $pdf = PDF::Create->new( 'filename' => "$pdfname", 'Version' => 1.2, 'PageMode' => 'UseOutlines', 'Author' => 'Markus Baertschi', 'Title' => 'Testing String Functions', 'Debug' => 0, ); ok( defined $pdf, "Create new PDF" ); ok( $pdf->add_comment("The is a PDF for testing"), "Add a comment" ); my $root = $pdf->new_page( 'MediaBox' => $pdf->get_page_size('A4') ); ok( defined $root, "Create page root" ); # Prepare font my $f1 = $pdf->font( 'Subtype' => 'Type1', 'Encoding' => 'WinAnsiEncoding', 'BaseFont' => 'Helvetica' ); ok( defined $f1, "Define Font" ); # Add a page which inherits its attributes from $root my $page = $root->new_page; ok( defined $root, "Page root defined" ); # Page title and description $page->stringc( $f1, 40, 306, 700, 'PDF::Create' ); $page->stringc( $f1, 20, 306, 650, "version $PDF::Create::VERSION" ); $page->stringc( $f1, 20, 306, 600, "Test: $0" ); $page->stringc( $f1, 20, 306, 550, 'Markus Baertschi (markus@markus.org)' ); # Use the string functions ok( $page->string( $f1, 15, 306, 380, 'Default string' ), "string" ); ok( $page->stringc( $f1, 15, 306, 360, 'Centered string (stringc)' ), "stringc" ); ok( $page->stringl( $f1, 15, 306, 340, 'Left aligned string (stringl)' ), "stringl" ); ok( $page->stringr( $f1, 15, 306, 320, 'Right aligned string (stringr)' ), "stringr" ); ok( $page->string( $f1, 15, 306, 280, 'Default string underlined' ), "string" ); ok( $page->string_underline( $f1, 15, 306, 280, 'Default string underlined' ), "string_underline" ); ok( $page->string( $f1, 15, 306, 260, 'Left string underlined', 'l' ), "string l" ); ok( $page->string_underline( $f1, 15, 306, 260, 'Left string underlined', 'l' ), "string_underline l" ); ok( $page->string( $f1, 15, 306, 240, 'Right string underlined', 'r' ), "string r" ); ok( $page->string_underline( $f1, 15, 306, 240, 'Right string underlined', 'r' ), "string_underline r" ); ok( $page->string( $f1, 15, 306, 220, 'Centered string underlined', 'c' ), "string c" ); ok( $page->string_underline( $f1, 15, 306, 220, 'Centered string underlined', 'c' ), "string_underline c" ); # Wrap up the PDF and close the file ok( !$pdf->close(), "Close PDF" ); ################################################################ # # Check the resulting pdf for errors with pdftotext # SKIP: { skip '/usr/bin/pdftotext not installed', 1 if (! -x '/usr/bin/pdftotext'); my $out = `/usr/bin/pdftotext $pdfname /dev/null 2>&1`; ok( $out eq "", "pdftotext $out"); } # # TODO: Add test with ghostscript # #echo | gs -q -sDEVICE=bbox 06-wifi-parabola-broken.pdf PDF-Create-1.08/t/03-image.t000755 000765 000024 00000005047 12251673270 015461 0ustar00gaborstaff000000 000000 #!/usr/bin/perl -w # # PDF::Create - Test Script # # Copyright 2010- Markus Baertschi # # Please see the CHANGES and Changes file for the detailed change log # # Testing image-related functions # - image # - JPEG/GIF # BEGIN { unshift @INC, "lib", "../lib" } use strict; use PDF::Create; use File::Basename; use Test::More tests => 9; # we want the resulting pdf file to have the same name as the test my $pdfname = $0; $pdfname =~ s/\.t/\.pdf/; my $gifname = dirname($0) . "/pdf-logo.gif"; my $jpgname = dirname($0) . "/pdf-logo.jpg"; ################################################################### # # start testing # my $pdf = PDF::Create->new( 'filename' => "$pdfname", 'Version' => 1.2, 'PageMode' => 'UseOutlines', 'Author' => 'Markus Baertschi', 'Title' => 'Testing Images (jpg, gif)', ); ok( defined $pdf, "Create new PDF" ); ok( $pdf->add_comment("The is a PDF for testing"), "Add a comment" ); my $root = $pdf->new_page( 'MediaBox' => $pdf->get_page_size('A4') ); ok( defined $root, "Create page root" ); # Prepare font my $f1 = $pdf->font( 'Subtype' => 'Type1', 'Encoding' => 'WinAnsiEncoding', 'BaseFont' => 'Helvetica' ); ok( defined $f1, "Define Font" ); # Add a page which inherits its attributes from $root my $page = $root->new_page; ok( defined $root, "Page root defined" ); # Write some text to the page $page->stringc( $f1, 40, 306, 700, 'PDF::Create' ); $page->stringc( $f1, 20, 306, 650, "version $PDF::Create::VERSION" ); $page->stringc( $f1, 20, 306, 600, "Test: $0" ); $page->stringc( $f1, 20, 306, 550, 'Markus Baertschi (markus@markus.org)' ); # Add a JPEG image $page->string( $f1, 20, 200, 400, 'JPEG Image:' ); my $jpg1 = $pdf->image($jpgname); ok( $page->image( 'image' => $jpg1, 'xscale' => 0.2, 'yscale' => 0.2, 'xpos' => 350, 'ypos' => 400 ), "jpg created" ); # Add a GIF image $page->string( $f1, 20, 200, 200, 'GIF Image:' ); my $gif1 = $pdf->image($gifname); ok( $page->image( 'image' => $gif1, 'xscale' => 0.2, 'yscale' => 0.2, 'xpos' => 350, 'ypos' => 200 ), "gif created" ); # Wrap up the PDF and close the file ok( !$pdf->close(), "Close PDF" ); ################################################################ # # Check the resulting pdf for errors with pdftotext # SKIP: { skip '/usr/bin/pdftotext not installed', 1 if (! -x '/usr/bin/pdftotext'); my $out = `/usr/bin/pdftotext $pdfname /dev/null 2>&1`; ok( $out eq "", "pdftotext $out"); } # # TODO: Add test with ghostscript # #echo | gs -q -sDEVICE=bbox 06-wifi-parabola-broken.pdf PDF-Create-1.08/t/04-drawing.t000755 000765 000024 00000006427 12251673270 016036 0ustar00gaborstaff000000 000000 #!/usr/bin/perl -w # # PDF::Create - Test Script # # Copyright 2010- Markus Baertschi # # Please see the CHANGES and Changes file for the detailed change log # # Testing drawing-related functions # - line, path, stroke # - color # BEGIN { unshift @INC, "lib", "../lib" } use strict; use PDF::Create; use Test::More tests => 21; # we want the resulting pdf file to have the same name as the test my $pdfname = $0; $pdfname =~ s/\.t/\.pdf/; ################################################################### # # start testing # my $pdf = PDF::Create->new( 'filename' => "$pdfname", 'Version' => 1.2, 'PageMode' => 'UseOutlines', 'Author' => 'Markus Baertschi', 'Title' => 'Simple Test Document', ); ok( defined $pdf, "Create new PDF" ); ok( $pdf->add_comment("The is a PDF for testing"), "Add a comment" ); my $root = $pdf->new_page( 'MediaBox' => $pdf->get_page_size('A4') ); ok( defined $root, "Create page root" ); # Prepare font my $f1 = $pdf->font( 'Subtype' => 'Type1', 'Encoding' => 'WinAnsiEncoding', 'BaseFont' => 'Helvetica' ); ok( defined $f1, "Define Font" ); # Add a page which inherits its attributes from $root my $page = $root->new_page; ok( defined $root, "Page root defined" ); # Write some text to the page $page->stringc( $f1, 40, 306, 700, 'PDF::Create' ); $page->stringc( $f1, 20, 306, 650, "version $PDF::Create::VERSION" ); $page->stringc( $f1, 20, 306, 620, "Test: $0" ); $page->stringc( $f1, 20, 306, 590, 'Markus Baertschi (markus@markus.org)' ); # Draw some graphics ok( $page->line( 100, 200, 100, 600 ), "line" ); $page->line( 100, 200, 500, 200 ); $page->line( 100, 600, 500, 600 ); $page->line( 500, 200, 500, 600 ); $page->line( 300, 200, 300, 600 ); $page->line( 100, 400, 500, 400 ); for ( my $x = 100 ; $x <= 500 ; $x = $x + 25 ) { $page->line( $x, 395, $x, 405 ); } for ( my $y = 200 ; $y <= 600 ; $y = $y + 25 ) { $page->line( 295, $y, 305, $y ); } #ok($page->newpath(),"newp0ath"); #ok($page->setrgbcolorstroke(1, 0.0, 0.0),"setrgbcolorstroke"); ok($page->setrgbcolor(0.1, 0.3, 0.8),"setrgbcolor"); ok($page->set_width(10),"setwidth"); ok($page->moveto(270,100),"moveto"); ok($page->lineto(300,160),"lineto"); ok($page->lineto(330,100),"lineto"); ok($page->lineto(270,100),"lineto"); #ok($page->closepath(),"closepath"); #ok($page->closestroke(),"stroke"); ok($page->fill(),"fill"); ok($page->stroke(),"stroke"); ok( $page->set_width(2), "set_width" ); my ( $x, $y, $x2, $y2 ); ok( $page->newpath, "newpath" ); ok( $page->setrgbcolorstroke( 0.1, 0.2, 1 ), "setrgbcolorstroke" ); ok( $page->moveto( 100, 400 ), "moveto" ); for ( $x = -3.14 ; $x <= 3.14 ; $x = $x + 0.03 ) { $y = sin($x); $y2 = 400 + int( $y * 2000 ) / 10; $x2 = 300 + int( $x * 2000 / 3.14 ) / 10; $page->lineto( $x2, $y2 ); } ok( $page->stroke, "stroke" ); # Wrap up the PDF and close the file ok( !$pdf->close(), "Close PDF" ); ################################################################ # # Check the resulting pdf for errors with pdftotext # SKIP: { skip '/usr/bin/pdftotext not installed', 1 if (! -x '/usr/bin/pdftotext'); my $out = `/usr/bin/pdftotext $pdfname /dev/null 2>&1`; ok( $out eq "", "pdftotext $out"); } # # TODO: Add test with ghostscript # #echo | gs -q -sDEVICE=bbox 06-wifi-parabola-broken.pdf PDF-Create-1.08/t/05-outline.t000755 000765 000024 00000006055 12251673270 016060 0ustar00gaborstaff000000 000000 #!/usr/bin/perl -w # # PDF::Create - Test Script # # Copyright 2010- Markus Baertschi # # Please see the CHANGES and Changes file for the detailed change log # # Testing TOC/Outline # BEGIN { unshift @INC, "lib", "../lib" } use strict; use PDF::Create; use Test::More tests => 13; # we want the resulting pdf file to have the same name as the test my $pdfname = $0; $pdfname =~ s/\.t/\.pdf/; ################################################################### # # start testing # my $pdf = PDF::Create->new( 'filename' => "$pdfname", 'Version' => 1.2, 'PageMode' => 'UseOutlines', 'Author' => 'Markus Baertschi', 'Title' => 'Simple Test Document', ); ok( defined $pdf, "Create new PDF" ); ok( $pdf->add_comment("The is a PDF for testing"), "Add a comment" ); my $root = $pdf->new_page( 'MediaBox' => $pdf->get_page_size('A4') ); ok( defined $root, "Create page root" ); # Prepare font my $f1 = $pdf->font( 'Subtype' => 'Type1', 'Encoding' => 'WinAnsiEncoding', 'BaseFont' => 'Helvetica' ); ok( defined $f1, "Define Font" ); # Add a page which inherits its attributes from $root my $page = $root->new_page; ok( defined $root, "Page root defined" ); # Write some text to the page $page->stringc( $f1, 40, 306, 700, 'PDF::Create' ); $page->stringc( $f1, 20, 306, 650, "version $PDF::Create::VERSION" ); $page->stringc( $f1, 20, 306, 600, "Test: $0" ); $page->stringc( $f1, 20, 306, 550, 'Markus Baertschi (markus@markus.org)' ); # Create a Outline/TOC ok( my $out0 = $pdf->new_outline( 'Title' => 'Title page', 'Destination' => $page ), "new_outline" ); # Some more pages with outline $page = $root->new_page; $page->stringc( $f1, 40, 306, 700, 'Section 1' ); ok( my $out1 = $pdf->new_outline( 'Title' => 'Section 1', 'Destination' => $page ), "new_outline" ); $page = $root->new_page; $page->stringc( $f1, 40, 306, 700, 'Section 2' ); ok( my $out2 = $pdf->new_outline( 'Title' => 'Section 2', 'Destination' => $page ), "new_outline" ); $page = $root->new_page; $page->stringc( $f1, 40, 306, 700, 'Section 2.1' ); ok( my $out21 = $pdf->new_outline( 'Title' => 'Section 2.1', 'Destination' => $page, 'Parent' => $out2 ), "new_outline with parent" ); $page = $root->new_page; $page->stringc( $f1, 40, 306, 700, 'Section 2.2' ); ok( my $out22 = $pdf->new_outline( 'Title' => 'Section 2.2', 'Destination' => $page, 'Parent' => $out2 ), "new_outline with parent" ); $page = $root->new_page; $page->stringc( $f1, 40, 306, 700, 'Appendix' ); ok( my $app = $pdf->new_outline( 'Title' => 'Appendix', 'Destination' => $page ), "new_outline" ); # Wrap up the PDF and close the file ok( !$pdf->close(), "Close PDF" ); ################################################################ # # Check the resulting pdf for errors with pdftotext # SKIP: { skip '/usr/bin/pdftotext not installed', 1 if (! -x '/usr/bin/pdftotext'); my $out = `/usr/bin/pdftotext $pdfname /dev/null 2>&1`; ok( $out eq "", "pdftotext $out"); } # # TODO: Add test with ghostscript # #echo | gs -q -sDEVICE=bbox 06-wifi-parabola-broken.pdf PDF-Create-1.08/t/06-annotation.t000755 000765 000024 00000006062 12251673270 016552 0ustar00gaborstaff000000 000000 #!/usr/bin/perl -w # # PDF::Create - Test Script # # Copyright 2010- Markus Baertschi # # Please see the CHANGES and Changes file for the detailed change log # # Testing annitations # - Link # BEGIN { unshift @INC, "lib", "../lib" } use strict; use PDF::Create; use Test::More tests => 13; # we want the resulting pdf file to have the same name as the test my $pdfname = $0; $pdfname =~ s/\.t/\.pdf/; ################################################################### # # start testing # my $pdf = PDF::Create->new( 'filename' => "$pdfname", 'Version' => 1.2, 'PageMode' => 'UseOutlines', 'Author' => 'Markus Baertschi', 'Title' => 'Testing Basic Stuff', ); ok( defined $pdf, "Create new PDF" ); ok( $pdf->add_comment("Testing Basic Stuff"), "Add a comment" ); my $root = $pdf->new_page( 'MediaBox' => $pdf->get_page_size('A4') ); ok( defined $root, "Create page root" ); # Prepare font my $f1 = $pdf->font( 'Subtype' => 'Type1', 'Encoding' => 'WinAnsiEncoding', 'BaseFont' => 'Helvetica' ); ok( defined $f1, "Define Font" ); # Add a page which inherits its attributes from $root my $page = $root->new_page; ok( defined $root, "Page root defined" ); # Write some text to the page $page->stringc( $f1, 40, 306, 700, 'PDF::Create' ); $page->stringc( $f1, 20, 306, 650, "version $PDF::Create::VERSION" ); $page->stringc( $f1, 20, 306, 600, "Test: $0" ); $page->stringc( $f1, 20, 306, 550, 'Markus Baertschi (markus@markus.org)' ); my $uri = 'http://search.cpan.org/~markusb/PDF-Create/'; # Clickable URI with visible box around it $page->string( $f1, 15, 150, 440, "Clickable Link" ); ok( $page->string( $f1, 15, 150, 400, "$uri" ), "string" ); ok( $page->string_underline( $f1, 15, 150, 400, "$uri" ), "string_underline" ); ok( $pdf->annotation( 'Subtype' => 'Link', 'x' => 145, 'y' => 395, 'w' => 321, 'h' => 25, 'URI' => 'http://search.cpan.org/~markusb/PDF-Create', 'Border' => [ 1, 1, 1 ] ), "annotation" ); # Clickable URI with invisible box around it $page->stringc( $f1, 15, 306, 240, "Clickable Link Centered" ); ok( $page->string( $f1, 15, 306, 200, "$uri", 'c' ), "string" ); ok( my $len = $page->string_underline( $f1, 15, 306, 200, "$uri", 'c' ), "string_underline" ); ok( $pdf->annotation( 'Subtype' => 'Link', 'x' => 306 - ( $len / 2 ), 'y' => 200, 'w' => $len, 'h' => 15, 'URI' => 'http://search.cpan.org/~markusb/PDF-Create', 'Border' => [ 0, 0, 0 ] ), "annotation" ); # Wrap up the PDF and close the file ok( !$pdf->close(), "Close PDF" ); ################################################################ # # Check the resulting pdf for errors with pdftotext # SKIP: { skip '/usr/bin/pdftotext not installed', 1 if (! -x '/usr/bin/pdftotext'); my $out = `/usr/bin/pdftotext $pdfname /dev/null 2>&1`; ok( $out eq "", "pdftotext $out"); } # # TODO: Add test with ghostscript # #echo | gs -q -sDEVICE=bbox 06-wifi-parabola-broken.pdf PDF-Create-1.08/t/07-fonts.t000755 000765 000024 00000006411 12251673270 015530 0ustar00gaborstaff000000 000000 #!/usr/bin/perl -w # # PDF::Create - Test Script # # Copyright 2010- Markus Baertschi # # Please see the CHANGES and Changes file for the detailed change log # # Testing fonts # BEGIN { unshift @INC, "lib", "../lib" } use strict; use PDF::Create; use Test::More tests => 32; # we want the resulting pdf file to have the same name as the test my $pdfname = $0; $pdfname =~ s/\.t/\.pdf/; ################################################################### # # start testing # my $pdf = PDF::Create->new( 'filename' => "$pdfname", 'Version' => 1.2, 'PageMode' => 'UseOutlines', 'Author' => 'Markus Baertschi', 'Title' => 'Testing Basic Stuff', ); ok( defined $pdf, "Create new PDF" ); ok( $pdf->add_comment("Testing Fonts"), "Add a comment" ); my $root = $pdf->new_page( 'MediaBox' => $pdf->get_page_size('A4') ); ok( defined $root, "Create page root" ); # Prepare font my $f1 = $pdf->font( 'Subtype' => 'Type1', 'Encoding' => 'WinAnsiEncoding', 'BaseFont' => 'Helvetica' ); ok( defined $f1, "Define Font" ); # Add a page which inherits its attributes from $root my $page = $root->new_page; ok( defined $root, "Page root defined" ); # Write some text to the page $page->stringc( $f1, 40, 306, 700, 'PDF::Create' ); $page->stringc( $f1, 20, 306, 650, "version $PDF::Create::VERSION" ); $page->stringc( $f1, 20, 306, 600, "Test: $0" ); $page->stringc( $f1, 20, 306, 550, 'Markus Baertschi (markus@markus.org)' ); # Prepare fonts my %font; my $f_helv = define_font('Helvetica'); $font{'Courier'} = define_font('Courier'); $font{'Courier-Bold'} = define_font('Courier-Bold'); $font{'Courier-Oblique'} = define_font('Courier-Oblique'); $font{'Courier-BoldOblique'} = define_font('Courier-BoldOblique'); $font{'Helvetica'} = define_font('Helvetica'); $font{'Helvetica-Bold'} = define_font('Helvetica-Bold'); $font{'Helvetica-Oblique'} = define_font('Helvetica-Oblique'); $font{'Helvetica-BoldOblique'} = define_font('Helvetica-BoldOblique'); $font{'Times-Roman'} = define_font('Times-Roman'); $font{'Times-Bold'} = define_font('Times-Bold'); $font{'Times-Italic'} = define_font('Times-Italic'); $font{'Times-BoldItalic'} = define_font('Times-BoldItalic'); my $y = 500; foreach my $f ( sort keys %font ) { ok( $page->stringc( $font{$f}, 20, 300, $y, $f ), "Writing with font $f" ); $y -= 30; } # Wrap up the PDF and close the file ok( !$pdf->close(), "Close PDF" ); ################################################################ # # Check the resulting pdf for errors with pdftotext # SKIP: { skip '/usr/bin/pdftotext not installed', 1 if (! -x '/usr/bin/pdftotext'); my $out = `/usr/bin/pdftotext $pdfname /dev/null 2>&1`; ok( $out eq "", "pdftotext $out"); } # # TODO: Add test with ghostscript # #echo | gs -q -sDEVICE=bbox 06-wifi-parabola-broken.pdf exit; sub define_font { my $fname = shift; my $ftype = shift; my $fencoding = shift; if ( !defined $ftype ) { $ftype = 'Type1'; } if ( !defined $fencoding ) { $fencoding = 'WinAnsiEncoding'; } ok( my $f = $pdf->font( 'BaseFont' => $fname, 'Subtype' => $ftype, 'Encoding' => $fencoding ), "Defining font $fname" ); return $f; } PDF-Create-1.08/t/09-cgi-script.pl000755 000765 000024 00000002625 12251673270 016620 0ustar00gaborstaff000000 000000 #!/usr/bin/perl -w # # sample cgi-script to produce a PDF on the fly # # Markus Baertschi, markus@markus.org # BEGIN { unshift @INC, "lib", "../lib" } use strict; use PDF::Create; use CGI; # # Write HTTP header with application/pdf as doc type # # If you want the PDF to open in an external application # You should change this to # -type => 'application/x-pdf', -attachment => $pdfname # print CGI::header( -type => 'application/pdf' ); # # Start the pdf with '-' (stdout) as filename # my $pdf = PDF::Create->new( 'filename' => "-", 'Version' => 1.2, 'PageMode' => 'UseOutlines', 'Author' => 'Markus Baertschi', 'Title' => 'Simple Test Document', ); # create the document root my $root = $pdf->new_page( 'MediaBox' => $pdf->get_page_size('A4') ); # Prepare 2 fonts my $f1 = $pdf->font( 'Subtype' => 'Type1', 'Encoding' => 'WinAnsiEncoding', 'BaseFont' => 'Helvetica' ); # Add a page which inherits its attributes from $root my $page = $root->new_page; # Write some text to the page $page->stringc( $f1, 40, 306, 700, 'PDF::Create' ); $page->stringc( $f1, 20, 306, 650, "version $PDF::Create::VERSION" ); $page->stringc( $f1, 20, 306, 600, 'Simple Test Document' ); $page->stringc( $f1, 20, 300, 300, 'Fabien Tassin' ); $page->stringc( $f1, 20, 300, 250, 'Markus Baertschi (markus@markus.org)' ); # Wrap up the PDF and close the file $pdf->close; PDF-Create-1.08/t/09-cgi.t000755 000765 000024 00000001601 12251701537 015135 0ustar00gaborstaff000000 000000 #!/usr/bin/perl -w # # 09-cgi.t # # cgi test script # # run the cgi-test and check the resulting output # BEGIN { unshift @INC, "lib", "../lib" } use strict; use File::Basename qw(dirname); use File::Spec; use PDF::Create; use Test::More tests => 2; use Config; my $pdfname = $0; $pdfname =~ s/\.t/\.pdf/; my $cginame = File::Spec->catfile(dirname($0) . "/09-cgi-script.pl"); # # run the cgi # my @out = `$Config{"perlpath"} $cginame`; shift @out; shift @out; #diag $out; diag $pdfname; if (open my $fh, '>', $pdfname) { print $fh @out; close $fh; } ok scalar(@out), "CGI executes"; ################################################################ # # Check the resulting pdf for errors with pdftotext # SKIP: { skip '/usr/bin/pdftotext not installed', 1 if (! -x '/usr/bin/pdftotext'); my $out = `/usr/bin/pdftotext $pdfname /dev/null 2>&1`; ok( $out eq "", "pdftotext $out"); } PDF-Create-1.08/t/11-encode.t000644 000765 000024 00000006452 12251673270 015631 0ustar00gaborstaff000000 000000 #!/usr/bin/perl -w use strict; use PDF::Create; use Test::More; # The cases array contains test-cases # In each triple the first value is the expected return value # of the encode() method. # The second and third values are the two parameters # of the encode() method. # The third parameter is optional but it can also be a complex # data structure. # expected, type, value my @cases = ( [undef, 'null'], ['anything', 'null', 'anything'], # any value [undef, 'number'], ['value', 'number', 'value'], # any value ["\n", 'cr'], ["\n", 'cr', 'abc'], # TODO: probably should complain that a 2nd, unnecesssary param was given ['true', 'boolean', 'true'], ['false', 'boolean', 'false'], ['false', 'boolean', '0'], ['true', 'boolean', '42'], # any other value as the 3rd item # ['true', 'boolean', undef], # TODO: give error or eliminate warnings ['any string', 'verbatim', 'any string'], # anything ['x', 'verbatim', 'x'], # anything # [undef, 'verbatim', undef], # TODO should give error, now fails with unknown type as the do{} fails # [0, 'verbatim', 0], # TODO should work?, now fails with unknown type as the do{} fails ['(any string)', 'string', 'any string'], # anything ['(x)', 'string', 'x'], # anything ['()', 'string', undef], # TODO what should happen? eliminate warnings ['(0)', 'string', 0], # TODO: shouldn't this check if the given value was indeed a number? ['any string', 'number', 'any string'], # anything ['x', 'number', 'x'], # anything [undef, 'number', undef], # TODO eliminate warnngs [0, 'number', 0], ['/any string', 'name', 'any string'], # anything ['/x', 'name', 'x'], # anything ['/', 'name', undef], # TODO ???, eliminate warnings ['/0', 'name', 0], ['[/anything]', 'array', [ ['name', 'anything'], ] ], ['[/42 abc]', 'array', [ ['name', 42], ['verbatim', 'abc'], ] ], # TODO more complex test cases for dictionary ["<<\n/42 /text\n/abc (qwe)\n>>", 'dictionary', { 42 => ['name', 'text'], abc => ['string', 'qwe'], } ], # TODO more complex test cases for object ["abc 43 obj\n/qwe\nendobj", 'object', [ 'abc', 43, ['name', 'qwe'] ] ], ["abc 45 R", 'ref', ['abc', 45]], ["<<\n/abc 46\n/23 /qwe\n>>\nstream\nsome data\nendstream\n", 'stream', { Data => 'some data', abc => ['number', 46], 23 => ['name', 'qwe'], } ], ); plan tests => 2 + @cases; { my @warn; local $SIG{__WARN__} = sub { push @warn, @_ }; PDF::Create::encode(); # TODO eliminat warning from code caused by undef in $type like $warn[1], qr/PDF::Create::encode: empty argument, called by/, 'no params'; }; eval { PDF::Create::encode('something'); }; like $@, qr{Error: unknown type 'something'}, 'exception'; my %too_random = map { $_ => 1 } qw(dictionary stream); foreach my $c (@cases) { my ($expected, $type, $value) = @$c; SKIP: { if ($too_random{$type}) { if (defined $ENV{PERL_PERTURB_KEYS} and $ENV{PERL_PERTURB_KEYS} == 2 and defined $ENV{PERL_HASH_SEED} and $ENV{PERL_HASH_SEED} == 1) { } else { skip 'PERL_PERTURB_KEYS=2 and PERL_HASH_SEED=1 has to be in order to have predictable Hashes', 1; } } my $name = $type . (defined $value ? ",$value" : ''); is PDF::Create::encode($type, $value), $expected, $name; } } PDF-Create-1.08/t/50-versioning.t000644 000765 000024 00000001554 12251673270 016560 0ustar00gaborstaff000000 000000 #!/usr/bin/perl -w # # PDF::Create - Test Script # # Copyright 2010- Markus Baertschi # # Please see the CHANGES and Changes file for the detailed change log # # Check module versions against PDF::Create version # BEGIN { unshift @INC, "lib", "../lib" } use strict; use PDF::Create; use Test::More tests => 5; my $version = $PDF::Create::VERSION; ok($version eq $PDF::Create::VERSION,"PDF::Create version is $PDF::Create::VERSION"); ok($version eq $PDF::Create::Page::VERSION,"PDF::Create::Page version is $PDF::Create::Page::VERSION"); ok($version eq $PDF::Create::Outline::VERSION,"PDF::Create::Outline version is $PDF::Create::Outline::VERSION"); ok($version eq $PDF::Image::GIF::VERSION,"PDF::Image::GIF version is $PDF::Image::GIF::VERSION"); ok($version eq $PDF::Image::JPEG::VERSION,"PDF::Image::JPEG version is $PDF::Image::JPEG::VERSION"); PDF-Create-1.08/t/99-wifi-parabola.t000755 000765 000024 00000011560 12251673270 017130 0ustar00gaborstaff000000 000000 #!/usr/bin/perl -w # # PDF::Create - Test Script # # Copyright 2010- Markus Baertschi # # Please see the CHANGES and Changes file for the detailed change log # # As example we draw a parabola which can be used to focus wifi signals # # This has not much to do with testing, but I like it, so it remains :-). # BEGIN { unshift @INC, "lib", "../lib" } use strict; use PDF::Create; use Test::More tests => 1; my $pdfname = $0; $pdfname =~ s/\.t/\.pdf/; my $pdf = PDF::Create->new( 'filename' => "$pdfname", 'Version' => 1.2, 'PageMode' => 'UseOutlines', 'Author' => 'Markus Baertschi', 'Title' => 'Parabolic WiFi Antenna' ); my $root = $pdf->new_page( 'MediaBox' => $pdf->get_page_size('A4') ); # Prepare 2 fonts my $f1 = $pdf->font( 'Subtype' => 'Type1', 'Encoding' => 'WinAnsiEncoding', 'BaseFont' => 'Helvetica' ); my $f2 = $pdf->font( 'Subtype' => 'Type1', 'Encoding' => 'WinAnsiEncoding', 'BaseFont' => 'Helvetica-Bold' ); # Add a page which inherits its attributes from $root my $page = $root->new_page; # Write the title $page->stringc( $f2, 25, 300, 770, 'Parabolic WiFi Reflector Template' ); $page->stringc( $f1, 12, 300, 740, 'Markus Baertschi (markus@markus.org)' ); # General parameters my $dy = 310; # y offset from page origin my $ay = 280; # y amplitude my $dx = 100; # x offset from page origin my $p = 100; # distance from back to focal point $page->stringl( $f2, 10, 100, 710, 'Introduction' ); $page->stringl( $f1, 10, 100, 700, 'This template allows you to build a simple, but effective WiFi range extender. The reflector described' ); $page->stringl( $f1, 10, 100, 690, 'here will concentrate the signal of your access point in one direction. THe range in this direction will' ); $page->stringl( $f1, 10, 100, 680, 'be much better at the expense of the range in all other directions.' ); # Write instructions $page->stringl( $f2, 10, 100, 660, 'Instructions:' ); $page->stringl( $f1, 10, 100, 650, '- Make square or rectangular reflector from metallic material (Tin foil, etc)' ); $page->stringl( $f1, 10, 100, 640, '- Bend reflector to parabolic shape' ); $page->stringl( $f1, 10, 100, 630, '- Fix reflector with the antenna at the focal point' ); # Write the labels $page->stringl( $f1, 12, $dx + $p + 10, 460, 'Parabola (The reflector must be shaped like this)' ); $page->stringl( $f1, 10, $dx + $p + 30, $ay - 10, 'Focal Point (Antenna goes here)' ); # Draw the focal point my $l = 30; # Length of cross $page->line( $dx + $p - $l, $dy, $dx + $p + $l, $dy ); $page->line( $dx + $p, $dy - $l, $dx + $p, $dy + $l ); $page->newpath; $page->set_width(0.5); $page->setrgbcolorstroke( 0, 0, 0 ); $page->moveto( $dx + $p - $l / 2, $dy ); $page->curveto( $dx + $p - $l / 2, $dy + $l / 2 * 0.55, $dx + $p - $l / 2 * 0.55, $dy + $l / 2, $dx + $p, $dy + $l / 2 ); $page->curveto( $dx + $p + $l / 2 * 0.55, $dy + $l / 2, $dx + $p + $l / 2, $dy + $l / 2 * 0.55, $dx + $p + $l / 2, $dy ); $page->curveto( $dx + $p + $l / 2, $dy - $l / 2 * 0.55, $dx + $p + $l / 2 * 0.55, $dy - $l / 2, $dx + $p, $dy - $l / 2 ); $page->curveto( $dx + $p - $l / 2 * 0.55, $dy - $l / 2, $dx + $p - $l / 2, $dy - $l / 2 * 0.55, $dx + $p - $l / 2, $dy ); $page->stroke; $ay = 50; # y amplitude $dy = 100; # y offset from page origin $dx = 300; # x offset from page origin $p = 10; # distance from back to focal point $page->newpath; $page->set_width(2); $page->setrgbcolorstroke( 0.1, 0.2, 1 ); $page->moveto( $ay * $ay / ( 4 * $p ), -$ay ); for ( my $y = -$ay ; $y <= $ay ; $y = $y + 2 ) { my $x = $y * $y / ( 4 * $p ); $page->lineto( $x + $dx, $y + $dy ); } $page->stroke; my $i = 0; $page->newpath; $page->set_width(1); $page->setrgbcolorstroke( 0.1, 0.2, 1 ); $page->moveto( $ay * $ay / ( 4 * $p ), -$ay ); for ( my $y = -$ay ; $y <= $ay ; $y = $y + 2 ) { my $x = $y * $y / ( 4 * $p ); $page->lineto( $x + $dx + $i, $y + $dy ); $i++; $i++; } $page->stroke; $page->newpath; $i = 0; $page->moveto( $ay * $ay / ( 4 * $p ), -$ay ); for ( my $y = -$ay ; $y <= $ay ; $y = $y + 2 ) { my $x = $y * $y / ( 4 * $p ); $page->lineto( $x + $dx + $i, $y + $dy + $ay * 2 ); $i++; $i++; } $page->stroke; $page->line( $dx + $ay + 12, $dy - $ay, $dx + $ay + 12, $dy + $ay ); $page->line( $dx + $ay - 10, $dy - $ay + 30, $dx + $ay - 10, $dy + $ay + 30 ); $page->line( $dx + $ay * 3 + 12, $dy + $ay, $dx + $ay * 3 + 12, $dy + $ay * 3 ); $page->set_width(3); $page->line( $dx + $ay * 2, $dy, $dx + $ay * 2, $dy + $ay * 2 ); # Wrap up the PDF and close the file $pdf->close; ################################################################ # # Check the resulting pdf for errors with pdftotext # SKIP: { skip '/usr/bin/pdftotext not installed', 1 if (! -x '/usr/bin/pdftotext'); my $out = `/usr/bin/pdftotext $pdfname /dev/null 2>&1`; ok( $out eq "", "pdftotext $out"); } PDF-Create-1.08/t/pdf-logo.gif000755 000765 000024 00000060620 12251673270 016166 0ustar00gaborstaff000000 000000 GIF89a,qçÿ  !"$"')&*,),-+-/,342796=>åÙé˦KŸî›õêR­Y¿Ž ûu©Dh(¹·ïß%ÁV)[Êlªã}‘—Rž*tçâG«žîšºlëµ±Ó†]Š4nÈHþdN¾¼y”«œ-•KÖ*³¿d¥z—þò¶z5w>ø´íî Í& vVgàu}­ö 8ãŒðvÞ„:–«,‡Yq‚ æ!g—=×ÙsF‡hž ¨bi+žÈ"‚)v÷Ý3Í8³HV¨ãŽ/5,¿ÀµÞ|Í­ÒÜrG^¶Ê\žÝ5âg ^FÚjSrWeŠWH–r¹¥–V–Èh¸5øŒƒ®ìÆl¶ùÑ…G7Ö/¬¤’ ný’¡žìy†h"žÖ_€„޹—†žx¨˜ˆŽek§”yæ3Ð8ˆÂxnfª)za—${€ 9¤^p "ˆ§š¨ê‹.¶ê¨«þÜI£‹eVêÌ3g:#F„knê+›`iQœ+©è)—†mљᱧÒU* ‡1iÛ´±v)eµ_>z-¢§ÌÚ]£Œ5­Í4ƒL$ äøëºçQ6…+¿$Û—¼wµ‡Üq$nfg¾©¦úZ•QRùmÀ1NYðÀÖ²*Ý‚ Œ Í™å:ÃÌ,¨Ëîž]˜aqF.k¤†©°ÂÊ*ĵ•ËÇfæ“ù 媯Æ\í«Þ¦0–³†›3“[#2*`Šñйoqe­² +ðåR¬Ó÷ÂE/_NBYµ~b^+]¢\‡)¢16Zb™ÚìbZ±žØ'©Ég_Q¼ßü޶ƒ‚ªc¤KΑ"ÊBÃx1k4„¡‰ ø†}ãvß(Ûí4i¶‡A¬F@D3t:þ“hÂa!ãs<¥‰ _zrb)F†È™Æ8îÉõ¤ç7è ð?¡ùR;µ70ï¼³áæ%s×Àð±‘Fc†>‡1 !ˆ’m/u›»`Á´ žå¬© ’ÒlÊDY0Í>õR!WiQ¾ô/u‰Ò 1:˜Ùn‡ÝÀ¤øÄ×@ÇݳFÌ(Wã`†US¦T–+2·4¥õqOK:š77Ÿ:áMz…ü "=ó,é °0wqÙÖ0 ©0®’äÈþÆ8FXÜͳl<³U›¡Õc(c¥p€cÛ&áë=ñ:îÝ#¯ =ë‰ó{kh9„Ð%1÷¹†é"ÕN\îU٠âUÚâ®âëa'Q*1eƒ«ºÐ€K‰›©;+tÇ«)+°©Jj6„g¡+q9×ÀôM‘ö˦åK+%îáȆ0Ë[Ûóòw»-W}ËU¯—¾Ò |’;·(æ.$;«+ *ŸB* ¡Ç!]|¢ø,ÍÌGiB-ª6³`Uu”A–m7>ªCLB£ãêaùÊÅÛÞ"uhl3A ¬°Ü×~£ÓZæCY™z9„+ ê„eã§9Fžþ^<èÅ‹¶pµ§á(—6rÄö’³Å<ÑKÏc6ˆÌ@Æ1Ž\¬L™Ê:JÓ4›¿Ù/HsÓ\AÅŽçNù㋨î2c|¡4\¤¨3*&€‰—AßGeŽ ËSw;#,ï˜\®OrxºàÀ|}ž;VZ„cŽG§fÐÞéNz ±9¦DÑJtO& çR˜×‹ºð‹í´„Ãqg¨¹˜H>£ŸÛ¨Ï@CÃÆ¾ÊëQfƒ$¾or‘¯U®x§ £n|–xiúXTl%Ýtœ‚'†DçÌR†ŽlCÕwvøT‡i¶5Žˆ¶&´0Ž‘|¸Ýæþ* ì=¹’š›5¤Çâ´¤…ƒÍ;ŽgñÓEìâé9ò"§Õ˜ÚÕ>òï´slS-ôlÙ¶òta}æ ­>ùÜè…, V›Ç]µ “ÖzœxyÝnAâ7•t×µìóû˜+© *ƒ(ÆVáô¼ëœ0(ïÈ39¾ñÙ¶°„Eòír{XŒ?YÈF1tÑ][=ä•Ѻt»~rûwsû ²Á>Ð5WÌñ;óØGÈ麱Íuц’ »2=œèhøíTá!W¸ªô<Ûn¤ÏcÝÃ(ƺ?þxš¼[òZÿ±¼þ_FYœEÚÒV¹ÇœkAºÛ‘ þœ*¾¥ŽÇצ!idÁ0;·zèˆíl#n{Û–|÷l£Ó‘áÞtã?tñߦù_YÉ:Ø×?ÅB?™5Òr|BHÅâ ¡fÓ¦€$ä$¢£!k5ª÷2 t `gï [ß{ 8­v;¯vFJÆFnÔ{O÷^ABuû'˜ƒ|ÁÆ|ò†<^GMò³Se§b`VZóÂg„d×DZ”RQÐÁ:—‘ v×u[ïÐ äàw|W‚—d‚&ØC·¼¥ ¾‡ Å µ0 ¿Àă$!d%y‹ÆSKte"ôh„D2ȃlDÇórÏ£JÔ4y4H8çŸRTúñ/þ}Áï{‹qÙ {æm•C"EU”‚6ùÔ{„6 bX ê¶6jèX/o¸h^÷8x4¢s2u"oQ”P8v< ™6ó'†À›Ã°+éÙ&Y©šº©œÚ©žú© ª¢:ª¤Zª¦ªh@˜vÚvð#QuƒÑÙ<Ê£ J¨…ŠwA¶w¤™jC6OÖ¯ ‘u\ÕéÂì™pªÎú¬Ð­Ò ­m0™† k×7F"X¤§}Ñx Ðë°ž{ ú™éWgÅ[ÊÈwÛO·µ3ŽƒR_h¿|h›mQ1•ª#—:­°;°¡*ïy§<½Øv¯Š¹ £áÚêà§ïP« *t³UŒã ¤—Dd|†¡]ØFá¹Uc|̧ìÖ6ñÉÍJþ°.û²0kªf‘¡ssׄ„¸,n¡ˆõÐï@«ØÙ ¡9´²g¨ª6[kzv6´Ödƒv¯éF†µ ³0©µ949 Œ€©1Ûµ^ëµmà˜ØÚ'ãØ‹ãôË è0®;«<úš±úQQ•gRu^<Ã…¹²[qDã9†\ÅUe8 ÈÚ¯çÑŸŠÐ²_»¸Œ °Õê–†À x£°É¡<—Á'ÍÁí°¹›;®Kpë™)qF‚Ua;ä Tu+ŠqâižRuðò üª¬–šµ\Û¸º»»¥:§„i }²}-}ËÅ" ëíPï°¹kû¹¢«±E—•Êx¨ þuºŠz¡ªéC>ätÔÈUÅ0¸³0 ñ’>† ”©¸¼»¾ì»©3 ˜Ø*s„øŠ9U†Á³ ʹ@K*´²µj²ugò4XŒãë…R­ùdۉO: °/gpµ¾œ[;­r œÁœÁÉÐ “/0ª—°Á| ÀÐ ¢p Œ`;àpª#LÂ2LÂr­fÀœ4:e…4Ì„ÈË ›ëÌ»¼Ë£èŠQØpº±#u:”d¶‚UM§‰ù· /à 9çÛŒ0 ƒ©¾ÏÊþPÆf|ÆeŒû°Æk¼ [ðŸ* kìllÆûàøpÆûp‚p¥j þwLÇu<ÈwÌÆkœÑ:§ƒÉ rc‡®:fvNð ®«ë§:¨C»wišN,aZ(¯ KkŸôdø¸±9¾@" sÔÅñž“»Ðªh|˸|ÇÉŸÚ ¸üËtLÇøð ~,ª¶ÌÈŒˆ ­©Š‘¨ 9<%5ruP¨OõàÚ¼¼Í˼ ºä@½ïÀ  É®ÊHšEñTd•r6Ú­ù·Š©³@µ¿€)›)Ì:­‰€ÌȼòÀËêËþüËø F ª]з,ѶzÉ É27…Ä­ŽæyË®=[É=« ~:±k ´áì ä°WΑ¨þÎYha¸õÎêdÁ|«uà¸L°ìÿ­`Ë ýËç@Ë™ºÐ=mÇk|¡zÌCmÇ ­¾˜c›€b·9,ç9A±”\ë€ÕBŒÉ™¬É ‹wØjçGš²‰[8>&õgMÖš1í¡eXµ^ÇŶk)ÆÎÚÏIÆøÐ×·ŒfªBÔËü¬7Œ‘ŒÌ_¸­ž/ìÁôгʫ¼ëÀ¹›û³äú™¢k~:¤êÇ«º…ò:–Kª‰‹ndèÀ<» ¥å—³,­;ËaP¦F`çpËû€ïÐ×·|f`m ŸðþÜŸŠÔh,ÁÝÜÎÝÜÈÍÔŠþ‰ n7¼óFS;ur¿° ô@ÉØÜBܼâ*®Ï‹®V™ ä[ëaî Xœ;º³·"Û·Ô¾‚k²°$¿ ùì¯_,˜v}ªxÆÑM\{¢ðË3À©ƒ]Æ#©¹û—Ǹ|pìà¸,£ Ô2{œ¦p\d6$õÉ›ó„ß]‘½¹X-±=ûX½¿éw®U{·Ã®BÆŒz&R…5.n亾ljÅuõ,lðÌD¢›nª³Æû0Z`Ü·Ø›úàûá›ÊµC`ågœÇ^à©ÊmÇÞµû»Oƒ\˜ “…cU³Ý RØìá­ÍõpÉ[þk{®BK°GFÞÖŒ(¨ddé´õ¢À7¾Ì÷ •ÐOsÝuÍϸ|à]þ ¸lÔYŽË\î©-`áh,þàþpæ1û¾Œp­f!vÛWMÙ4SàjßMô`çðàë ¼—íÑ[±áÜ™yÒ§~îý®£¬ºˆς桂;¸«½D¿ÐR7 ø˜M^ªO®ÇRî©w ÛŒ á·üéž Þ©e^Æû€ê0k°o9 ÌåVÙGPO42¬PEÜݶŽÍûNç¹NÙD Ò»ÙŒè[ì´ßš”{cÙ8¶ö[çö^ l†Ê·h?ð߯}‘Z;à¦ZàgŒé›ÊÓh¬âŽþÆä>åì€Ë5\ògÌî/«êŒÀȱÞ<€$Í–'ÙWÍØ\ÙlÉ] ¨4èáÐÙ…j¨ç«&Ø8hô÷^©\ ã; ³›JH^í%ÁŸÙNªÛnÇÝÞ©Àð×+¯©¦~ò*Ý è®ÛmnÿöpK ­i˜¦K’vE…t$¢ó [´îï‘MÙÚŒçêç?« çê£ÜÉW·ËX[«KUiÍ{§LP7äTÿè• \“ŽÓ•Éñ¥êñf ò™º¿ ,oÆÅ ªF€Ë½½úêþËwŒÀ ­3;˜wê_ó¸4iq'™§|Å¡k p´Nëß ÞBìóâZ±âþ:®™-ºVi~&Ýp²‚¦« ºÒÚðú†Ö8†P/õfH?7/Ôþù[‘µ¬Ó"oǦï`ŽÆ._ö¢škŸ×¶O÷4ûb±êW)V¬\­X*ÕÀU¥~åZÈ@ƒ{õìÙ£WÞFxîÖ­«×®»zêÚÕC‡n]JuäR¾#3&ºq1³Ë.ÛÎn=µAƒæ,ÛÏ Ïž9k挙2eȆVkذZ³†ýÂú‹•À_EûOìX²eÍžE{–‘¢µŠ.P€Wî\ºùÛ×_«I}'Ùz‡ŸÞ¼­è¶"ŒwD]¹ãõ0ñcÊym1Æ,× £¶¡þþZ%+Öе¦Ê•«¡¬_4À—Ï^=‹iÃëØ.÷ºvïÐÕû¨î:u)]¦Dgsf6rÌÉáº3[· ÙœMÚL;³cʦ&lê¬Y°`±"½°Ž°Ò¾‡í$Î2߯ (ñ>þøö ®ÌŸ{l1Ì*¨à±}D˜Ë–)Øû23ƒ­µLh!…B5‡dIEC„~Ù`¢{b»H#zàá7ÜÜñhu@JIFä`j¦äœ{N§pÆù&›o¾éF›é !ÊgžI )¥˜:ªð¾»ê¼¬ªäöÜ‹¯K/9³ð­ 1»ëÁù¨k2ÂN¸OÊ"“KM3õ2þl̺äàŒ³PLs¥”ÑF+È!„Zˆ‡\£èž{.ÚˆžÙn£­žŽÜi8‘ÖÎ7r„S‡˜|c.Ôæ†Ä©§éŒ”î'%µcu©c¦¯YÉKoVÊeƒ-½äõ=0é³ÏNºò›“²Dà”¬ÀûRx ºLŒs¦¥¶Zv>–.4òTdÏ…2Ô¡\dùLC¬*1Ñ1j·z`<é]y©Ð™¹–žsÉ¥lh‚.ÔévҦࠀ‚æ(¤´Sª™W…)ªñf¹4da€özå¸, q+[ºÊ,6¯w¤ÀLμ Ä ŠÇÎ!01¤¹æ`E–« 1„“…RþAÏÖVI…PÓR‘E!Ö:0Q0E#u”]Üì¥ ÞÞB²WFßKpplN¦qÂùqºn¤ë^µe˜áîÕ©dϼ­H[¥–?Ø «ãŽ-¬縈-[¶“1•»‘ÄðåÙÇ|L<×bÄôŽÞœ rqHÐÓUôÄ|ò¹ÇÑFÛõF‰I¸•ðÕ49~eú7œ u§'ŸŠ4É¢FêmW!¦Jª©°r½ÍÉrW¿yÅœ³Ä'Y/AÂà> /¤Ø¡…›3[Ü–ëò@žÇ̈™0Ê+¿o309ù%î+A+Z«C':]éžFÛHjE$‰¥þ,õ‘àÜ8‡¦šó¯èäTÑ‰Ž’‚²$ViçmÈpJ1æFžY¸‚4õkV: ½éɇ-À‚áÓ¹ŒoLå;]ѬHŽ0 ‚ß„*”§=™¦~ú3ׇîfšt9­tT‘m6B©ŒD$%©”ÀöÀçÔd&^tÎNJe$møDUFYUñ $±) £"õ(¼«#ÀñHHŒ ßä´$9ã#:˜0 뤵ù]ÛûÛ%·±¿hÞBR¨o™`ÊËSàš©ŸÄDg~Ð;äÐRÀî‡Ô¾ÈĹ93g=ÊÐ/XÓDÿô“N¬ì¢ì‘ºŒ°¨jöÄb½JbãÙé(ÇãtKþe …£'‡†íu6è$¸5%bà±íw{±ÏH _±ãôÖÊ+ +¹Cøã–åa‹0þ è†`3\äÇ™Q˜ðÌÎËÊ«»›BðòGØœ,eÔzÚ!q]oH¹ÏLu-ÇM´j4AœHhs†‘®sdú7„Tª Å\!éöï‡H@‚©Ìf ®ehEÌeÞ /WŽ3Ÿù'è#ˆ;´a j°qsdÅÛ –Xë(œ,b絺¢«p…•À«I¾Fv¼”Íê¢(¯ƒ§^öªñìf·)ÜGT5ae{âZ hcã¶l¨¥$žñT Ž@³ˆr‰\ºK˜Y¹íôx>†ñŽ ‘§Qà±ø¦hb+–®½òU“þééåODÀÚÜE^ŸÖ.Ú­9þÐvþ" ›íléäIT4’uÉËlÓÊ„ß:—QàwøÌGÓˆ~ðïaÌÑ<¸u5Í\WŒ¦°ùw0OEÎ"¢§>¯¯g_Å9}64EAç$'»ëÆ}ƒW0iE«KXüÅc'Ïb+”Ÿd!àbºz‚¾Àl™7EPº¥s2ÄR¾ë.ðRÿˆÉz"FaZÚ¸š¬Q*ß𕈠jŽˆ#ß!¨³±·3²…Q#¯š›¯Zº+A†H…EH¹pû;ß3¼äÁÌ™i¼ãs2ó°7¦+ˆçi"¼Ð¤è[±x‡NÒ{躎Xxþ¥Q¢1‘­ù'n‰ÓC â Y*#Ø …i’†¡­ð(†Zˆ 7 +t»ÏOè;•‹Ñ#äÃ>œ‹yc¥ÃŠ!Ì Ú6Ô°½ ŸÚ$ÊšF±À# *ú:~2Ž}IY%A+›Ór¶2"˜ â¸íÈ%¤Š«¨˜Ï(…R_`Þó˜LÛA?ÔÅx#>zBÜúÅÜ:Âç!‘‰°¦Ê 8ÊzÄOb1¸‘ЬΒ{ášVjupÝ’ ’³)’„b(&Y\ò¯cpè9»¹;Y+š¤É1€:ú;ÀÀ]ÄÇ0Û ¶0ÀAD>þ\:´˜ˆ˜ˆ¬éc1ª^ÛH!*x1‰z/¥Ê±NäPœ A#,Z2˜¶é¸¦ø/º£’*¨3”¤ù…F¸ÁàR¦b„\ÌÇ™„E¢7úFBB"œ}C¡ÐÉO[“À£É¶D¼ëb„Pøª‰B>¼’t"È6{@¾ò‡7ã©)Mj”Iì5Ð{‰ö:ª}Ú—OñšUZ¥oÀ ²¡¨*T¹*#ë ·ñ8ÚûŽÔ-G ¤ à½eŠIþ·TÍêJµn© 7¢•!”ÍãëIèƒZûžzDE‘ÄË z08<ƒ,¢±~š?£J´{@“ŽŒ˜Ž,˜ØJÃjÓ¥‡yCœÜ›¢4?)…37—‹*[ÍñD¤ ±Q¨»º³Ë¬0°BÊ« c¿¸’¢(N={=S̉?.ª‰ä€ªe@#RŒTùÈbŠs<º“ «°7s1”úY…FP€)·Ô$ÏÅÊK‰"¹¤˜öŒÁ+IÂÊXÂÜÔMsšÓ‰Ž¥<‹z™‘°#cCŽ/ì" ¢Ì1ŒáA˜¢ ¶\!a°N©X:}†ˆÅ MþK<ü‡áâ–DÀÒ,ÕÒ-åÒ,U.ýÒ.Ó1õRI„0%Ó4=Ó-ýÒ1Ó0ES4íR9•Óµ…×ì%<µ ölO±‚Ïø”ÏÈš¾ú\—I”_›š{Š={¯-ôQù #1² YB›¸Ž%¹%-†}Á:¢I£(¤‰Å_¨ŒZ+0É´TUU7uÓL;UV…ÕVU~öã?Ί?yˆAäB&äC6dÖPdYcäEG—H†dÑE ÅÐ µdK®äMVI!ÀA"æÆ®<Ò#cA'ÉŽf¨¶U†›Vvåÿ¡XŽeXIfø¯’›ˆa#’”clÃæ:¹;þà<æXEf"L§a|ˆÔš‚ š‘æi–æ†(škVˆlÆæmÖæl¾ÐlŽÅpçq&çrNšq>çrVgYðdðe^I^&Hþòb†I#þÜÌlÐ}æg ãè0î…0ÞÔ]z Ú“?ððe‰iÅXqCªÈ6*ÙX‰Þc@^V„X"‹æcAfÞäŽfd ¤Q ‡€æ­@i[QéáfnVçu~é)âwöQ^˜Tî ›vRnUN²~~›}Ö¥êꢦ-d`]>è©x¥¦;°”㨎¿†–^&ææÝ¬>ædîSt"F[Æ#Œfj¦fkç³.šXLkp 1"väFndI–d‘5ý“ż&ͼŽÅSèëRðëR8‚O¦é.I^! ž4´%œÞL|öiWneãYeXãÊ!Úºe¦~•¦~ _þާVèþ_~C…®j7–h¦hfhVm@Ž2a"Ñ8±Õf­H"—~éÜçüKg˜ÖëpnçÂîQ†bÆNe|Þi†QnVéçŸægË®ì£nЮ’›ÍîªMmW°ôå¨þŽ6ŒÛÊXb6f­&®Fæ» ëô†f²žf‹)°÷†Ò‡ +FæÎÔ€²æI'•Né“¶jˆX–q‹êq? ×ó£!+„àèfnfÖ@`¿äþ¹?•ÜóhFòßæëT@pE›ž6#s¿JÏéåžp†j’U¦âLÇ¥¸™åËã §n*©îÎŽc6–’ƒFsÔ–h5ÏjÚÄdF§7þ‡óƒ{çŸÏ°o»6ËÐA'(Uë€WëÿôÐYzU½…øot.ð®Htg/ (GâSD#åNîã¶r*çÌåvçŽOwÚJcêÆìP_jXqíVùÒVõUïV+XõeŽYÇùG"«þ†GB‘m?dØd“ÎñIƒA™¤q^w,iCgvŽx‰ €FÇ&^ECeJWì ïz%aå ¾ðV¦ì0æôOg×.ÿð5Vj6þl¨†_u™oÞmqóîjzOoH»•:§sÜ M•~R\çñ÷NkÓ u—¼nk‚ÏóùŽÒsæí§UDor©ŸúªGb†Ú þ‹ßøÏ},Ïò£>êN—nµ/÷vÝå6¢hvyðŽù%¡šçã×ΊœßFšm¤wæEF ¹”œæÕhÕÐñ¦—ŵðµNgfz̧úF7Š$f›hŸr´ôjGnMÏôŸîþè6j’gצöpëvW^Šc¨†Š×WGºÏjÃÍc¼GQ¯ëä3’3šÛ/±Ðèïüáq ˆT¥¦ÊUêW©U«ºr…0Â\² –’upં %Z4ˆ°TEY²V àÊ”*W²léòåJ„dsfÓÙ3h8AË íç³gΚ5Zô&Ò¡H‹eZT™2fÌ J*•ê1dY·fEþæµë±aņ‰=V,¬X±Å„ æ–,\¶pç’­e×-^»zí›Õwî¯À‚.ÌJðáÀ SL¥ðDˆ¿Xf%kò*W¬^nHù ÄÍÌh±”Aƒ#+þZUÑ HQÇþ%Ä$Ìܺw«”)D›¶Ÿ8uöÜ)§ÐgN‰2gn´¹s¢J‰R…•ªÕ¨Ç¶sÝ®5«²ïpφ5»v,Y¼o‹±w«W½0¾tçîeÿ¾}Xú÷óçïy2eVàb¤AÙ*‡e¶Ù/—ý’‹B’åÒ EäB–"ÚGY¤A©Pl²‘„o)ªØÛL6ý¤ O:ñ4£p3î”ÔRþ8ÞÔ”R7EuÕUÖMÕWZ}w¤wÜÁ…Ygµ‡W[ðÍGß]yÉ7%`…i˜C%6™` 9öXd‚I&&Hn6PBŽ¥b†¹äò¦cš]öæœ"^tà*²Ìi‘Ÿ½vÐm'­x(o¾A“MM0ÆÈSNATPÊAw)¦™2gØqº’`©$wLÒ%×\ì­µ|WÖUË,°â7ë}ýÙ Ë/°4$ ¯_¶v ›B¶«†9ak É)P›"!E‡ êQš1˦l©”d(¢Ý¾$ÀL=åä p‹ÊˆÔqéV ÝsLÕcSñ63$™dwIjåä’¥:¹|ꡇeþ•µ°ÅÖ^Xµ%—‚u ¦—*˜!c“ÆÊEÌbšž*Æ&Æ^²òfk©æÚ]Vš ¶¡è-Ì++„‹:=“MNÁý$Ïçâx”MîNçTÐ@U]vôVÞ¨_qW¤’ªžª°Zî½gåÁÃÔ2­]Ïrk®úåº+e• f¶+:† „‹I¸ç„« Ôàbs4aB2ûPÆÛHÛÆf€êi¥]LEóœN`t1Ø^€˜—Ö¹K¹ŒìŽØ0ÍÈlŠy"iÈ´ãA6ºÓÊüÖšßyéN¨¡m.â'Í­PŒÙÌÌå¨ë‘Ë&7Cœ‹*%ÇäTj'• ZÑŠF´¡¹ks×ù£òµ¾íXÇ}¥r_{R7Ÿ' þc,sÏëòç—¯ùoû {UWH‚Ù“¬•‘…Èb3S<%ñ´¡THë!ä¢Ïè­™1Àö‚ƒœlÜRG6rш&Ì‘o:CsÆÒê$¨@ _ìCFZÆÃB)kpa•ÁˆDºø…,Iüfÿ’ɈýŠ1Z[BÄô¬2IÆ”{êSDä2…LQejcSjJáŠXÊQ´4/µQ9Ê„'„\Œ&)œ¸ë…Ñ _»ÚE¯?. +7lß1£ŒCú+‘TSÏê IµYáo’_ëŸã?6q@_JL'AóÉ 9bÊHcw±O…jTaͽ¨ž«»Þþý®xÅ ´-3†é»(Œ1ʉºØÆFÃ/æÓHöìÇíµ_ï[—¿´ɵuk“X»Ö@9X²PÞ,R¬>¸rQQ “4.Ìd®e ËÙI©Y¡‘«,œ‡©Y:ã::*®JW½úUÓ -06Nz¹ &”¶5¹1Ñž$µa§ÄoŠlMìU9ƒW±ÆP"£T^DBÖ •¡œ•§V7K+Ð0·zQ¯®0Œ¨ â ˆpªê¢ãvÁQ:ƒ÷…6‰!Ò?ìË"‚f¸21 Y¡Ødx]!yµ¶@[­ô¥¶}}íH§tœÛcJ}n3{"Ô¢þ[a ·_ æžI7Ü-PÆÂ;…Ò0£ÂìFí‘‹{ç2üŒ¨zbˆF”C1Þâ£W`¸RÐ ƒc (6 „1VCÏUj­K|Šlß"w“ã• ›8A¾Ê¨L¢dçÆ"2¦sgäweì²Ýe«±3w÷Í­÷\ÇÝò8MÕYBE#äHΡuÖãäìܹ¤Ë˜}²P8F ƒÁ…U¿ª€¼HÖEI­ñi¯ÕmÒX…=?ØgøRN:y02]ÐÛUÈÜŒD=Mºߺ €tcíÍќ߽[à1ŠM\qLWSŒŒKq]®‰ítÜäþUÅ ,€A/@ÓF¹E Âx˜ıW”´¥G¥ÕÞ%… JùÙ,ÚUÚCìÞ·ÑT^†i螥½þC5 ÍñÝÍí †ÅÛõøDOôD.é ¥ G͈Ë1é›ãÝÏHž!"œ B1lÔ¾ô¨`!ü‹G)Œ5µŽÖÑ[œžýÐßü±ÙéW¤Ð\ a”É€ÈpL]eH'I!c= ™qØ ­ZòaX‡-Ê/IŠô¹Ù¬®Ý‘º÷ñÀ *< ƒ‹!C1ø Ζ0’”HÉZÄ…Å¥Â(Z}™} !JůDŒ‚(ÄþÈ@"ÛUˆeP"fÐÆ³¬‚%¸è@60`»ÍÜ'¾ÈBÎ]Ø3Ìœ-Ù„‡ñÌN\ºàZã]ŽsäÈM°aÒ™…ˆ€ ¹y&_ºXè 4•… »0ûª.jéû â¶Ÿ ÎÊZÝ—‰"bCà®KÙD(²,Ù+K01 o6Xô$ç,|žå7æèrr}ÒÜÞ]ð°¾Qnö eq0¢&ê1|É$43\® uB¤œ¯Y‡žÉ23Ašî1`(ü]h "Â|k&ÌAÏîë!³ì±EBô1rK826pFƒ£@i´òª¿þkàÉfR!®†íÅ'³™1«o¢3ôþ‚[8G1ì@ÃÃxµ"EÁ±hÉ¿\é’¥?7R\üâ.%ìÒ‡ˆ®f""’Åží\å>5³X@ À„#³¦R3Þhë«¿Zò¯®%âΜd!ņIUJ«4I2àB±Sà Ú*×£=ZÅæì´¾€ .µéæq\„¬[v0s]•X Úª­©Fåý±¬îJõItn\tE[56.à¯5®Ï¶ÛXo¡&‡³¼ÉQ½Moäz°BgÑ@ ¥€R ƒ ZLNN—h XiÅF©E.ÿvú²¯tZgÙBæ|⇆¨_L¥%ÑÖBKöd§ÛG¢UëÆßoEþoµ5ÿ-‹6Ꭴ»4ó–uTÝ&ÅjŸË€2H)ˆÀ(Å1@¨ í»ØDä%ÍæÐÖ iyüü7Zdé ‡-[üb1`稂ÔÙÚ—¬€Ýs'щž&e§¦e«ˆug6g#1Yoà]˜†ù¬ˆ¯Z7sâžãAÍÑmš™o*ƒÛÅ0@ ÊBR@ÇŽß7µâ oǘz·¦Öò.w4õ#¹¨úÅé]&ºv§ÛÊd4„tKO…§Hv o.qvµ5‹v'[¡&{ó:JÖÈqœ8R«vs<ƒ*å+s–Ó@ (ƒ )Ž'“ Õ" ¿¤þtâ±jYç€O›tž¬}m'[tâ0T:á\:¦ÓªuoØÍv÷[;nJâêóéêR˜§ùyW ˆ¡ÐR ƒƒ@ …,è£ [÷Ñöá÷æÞ³3·â2 ÿu9Ö€*vÂn‚/ÚSò0Øð‡´µ«Hf[·E_´­úm%ƒ6ñ²%“zI–dpHª«#¬AJá3l¯,0Cœ/Üà5å² žµav8“¾ó·éúôxX¨{eèÛ0¢ÙO£—*1k\íFãÈ@ÌØjE0¾nµ—K½Ó[2™ó©6.Š»(ª¸ÔÛ‡*w „2ÜœG­ …ÂoZþÕÑ MEé6ë·¨h… Û2P »{…,³%ù€“¬ü.[™*%YÛ~$ýô,=áPü–K³†g;ßiu®XÇ[©Lpàa…“1_¶œù°ÆÃÚ6Rt–ÍCƒ¥-n RDH'b΄);¦F–²mòä‰SgP D =¶ôXÒßM“Z={•yÕ©bµB×úºÙY×±§Å‹;,·pÿ†ŸwoßñçÿMîVXñ7m’)+¨~>å \˜p¿þÁýµè™‰@ëh Ñ&B­´‰lŠÁµ€P¦”Xr©¥Ø.t‰&f8äM·ÜŠ j¨ß‚êi¸âœ:n¸§ ªŠ¹èº*f,±ÂRjƲ¼2K©´–[ë;ô€¯¼ Ï3,1Á#(²Ã«¬1ú&« ³Ï8›L³…:;hÀŸ "ÐJ˨#gÈ0É$Þ°m& i“m¶ÛtŠS·v"QÄߊ:j)¥ŒÛ“Ũ®âj+§šúJ¹®¼šÊPåv¼Ž¬ì°û‘ÈIïÚ JÅ ,±#‹ ¾$?«¯Iû :ˆ2ÿê¯!SÅ$(AŠ"*KeN éÌS:‚¨Í [âÕÂÛdʨCwûÐ7Gþñ(=OÜó¬¤^|n+¨š¢.ÚjsÌQ:³tüERLÁýgÈpÿZ¬SÈ6mr0)ëSrÊÍ¢¬Þ…æƒè ƒ4²H"ƒ<ºÁÖT²íÂ`ݼ­W _ú0'béL–¨…S¦˜â(&‘¸¬š ´EE»¢‘F—³N»a"}‹\p-=9¼õ4MÒÈP= õ1iþo RUíKÍP;¨Àg,K0eÒp-Š-ùµhWÛd3Ø9夓Ã{x(B—[Qã¬}ñ*mdnQE?Ö¶©oU2å´ÿ,æt™¼TÅÞuw^»±ÜlUVDh# O}& ×^€H¥W f“ÂÄŽmØÜx‹ÓDªþFÆD;'v¶9¹‚6Ðê䦲C›íóÖ>Ý/&‘½[UÐ0ãŒ7œé -‰^qŸÓÐüT^óv,€²R“älâ°c%ËrX[JþæœMç„ocÙêJÇ>æÉpŠë›-W’æv®sÊN•´kçC…CxªJÔð™Bñ3}A«ò¥J’§D! XƬK(='âD8„Øå0Häð‰ƒZ„Vr8É(nzT/`UËe$Á ‰¤¶C':ówÃXºêûÉŒ,né0­"Áh,BÖ?úq"IÍò&ôÓæ 2#|¢äz£ÐFúÆŠÓTÑŠ¨ÕE«PË*‹ T'чոì媒]H1ƒ®‘&©v3c',ÃjÖœe£h!!C4ž¡פ)@@ëah X׿) ozS†zº¿&’X e&žî„ ÏER)ZÛ×þ´X(MÕ²”µ¬û´Ê26Ƨ]õ3g+eÑÍ_!Á•32Áš€)4r}ÕFdwe²3Œz˜?T*‰]írReR•W´Æ9^3º+GV®5]ëÊ/@ÞÖ¶ÅœÍ^[2T¡Þä(ÖûÉÃŽqÃBóYÇ(Ÿ»ÍÈ Øªë “®ÎÁ½ô 3+=£h&!~¨¡‡ „$úÊWgH#Û ¯—<]¢@æå Eðq‘£²¬†AÏ‘{Ða÷º¢ÑpØÇâélÊr¦RÏ^)€.þ ïb?¥!P1 G¤Ka²k÷ùÚ¼ž˜6z-`Ÿ¨H…ÖW'Éꢟ Ê9k1—Ç*¨óyÎUrÊŽòIeÜRŸ±º*€!ñ]†’ˆà "ïFräýmL ²k!q{H¦i„a*3\ÌÐiÏb†Ýït´"#9ws/¦>5ªAúUW;øÈþŒÏ>£k“¼AgϸÅ-E‚e,¤KÁ¾#Dv¦Ðð«ËJã)!JHÙÔÙÔK3e¼ÁâvÑ¿’ꎱJçoÿ8º«Îì‘ˉsGI 18Ó.ph h¨V"X«¶ŒÔøo_¨áHˆÿV[7NàcñPÆþH)’È‚¿)¬ÏÝlImCœªÝžx<5· jÏڅϽ¤´[Ó«!É„™bPšÊô’ùJÉ«râ•[ÚÄ”N`ãvóœC»‚hJ±öLüýáŽ8¼}t ©g«æÒxì>ƒ.tÞ $%y»²œ\ 5ˆèí€ýËVú1x`×òšÈ^°B>MÅòítÕõHe(õDÓ¼X¶L`£ëHžzÙë䳤s2©‡±ñN@Œ`Ͼ#{h€0š ‰h™­BŒ^#¦74›_¶Jj.“Ü tz8¡àÎ-çó¤>´¸ ˆîÑÕ³¾õIWgã¦äøu¢$ ðAX}Wþ0Æ‹¥½S³Ït ù\Ò7?í½fp½â+‚ OŒªçŽƒ8 ¥8„aÛDiüÈH6EÕ&ÃHb¨2Lêœ Oæ@?.£2ªa DÀ€/hFÐU­6"º¤Ðü)xÉ®üí`zŠÄÌ®¯‚ÊóéÅvNÆænÅ(ü6j/P 1nZÇ=ff• ìÉF â…†$XÃxzÇ•H#4@#y\Ëoö ì)æÎWg¯ iaÊ,çd¬z(Èr$†!P? •\Z¦”hOãŒL2â\Z Â,ª! èöç2„Ã4Àh2Âo@Œß$_”þGórЧ>™¢Gaˆ…r~‹E”üì®è ÷ ~@eT£ lE®0Ö²´ñ:žðƒ4bÃ_LåU^îåH q°i’H·<俤§™„CYTñpÎ^1É…nÜFSè@áB¢(œÜ%?´ Z q^Æ @ò¥@t½$"L8‌ˆOl½(mÒ:o·JïÆTQÇZQüÀÀñd–nY 3æ)$ 2äF»,#‚±þP%–RÅgÂPŸ)ËöIAüïòm¨ìfBNà°xNÚð„8Rï¹ö"#òd"#È2¤nàL:a>þ4Ë>x!$o¶kgè…4$ËDŽzˆŸMßvʘjNM²R#6Å´a JNÕ‰B²¬Ï2¬ ìe_BlKz)yÓ¶1Sl‘"‡7Bu8u”mÆÀV²€eÐE‡L~R‰9ïÒ9o§Pò>bP4îHøª”ØhIßÔ6’³»”C€B2}Ó'tLÙÆãBdMñÌ3/ÀàHþà ©Ëvp¨¥*‘q*c%%aÓ*­ÔE?q§&”P¡mtàFÑ3GUe6áLn .ÒåÀ¸ kÇ›sÃbÍ]äH3ƒoü3§¸„#dEËdó ;‘y4A¥¯U#çγŒöbQk•\'$è`.~2ÜðÇ3B)EÀD”S«Î4ÇjÑ@(ãIã@R’ò6Q½pËy@1ÌÇZ9VeU[iµ[Ãå–@`ìT¬”^F>±¡tibÏnF°ºQo-VÐ+"„‘Æ^ŒÈ0³ô½”ˆ \•'²5…¶Õ`Ãå"E  ðÂÀjQH%öàPPˆäÉ\ÅJt‡þyg4¶®—¸d*ñ¶8Ñÿ ¯0‰¾,e6QÑ’[]vRvÀV6A… ƒ= Ã0Œ²¬áB[ã (Õ~‚öÜ.cm±s–|‡¼úò^íµRòˆ† údÎ_gTVÖ„ö"®–RbáA  LC9¥…°aNPF`Œ’•L³]B’)3ã@’'Ø’‡4äJùÂnËV•ZËNohj#Ôj=43$ÀàÇÞ'0¸*1  î Ü2ÐãœDo>ìSÿÇÊ@—h™Q_íˆhÎ_óCr[–epS7HŠSaÑãÏ/2°áF äœ3fä³f`††ê^ÑM4ðQKæðuþˆ¾KT+Y‚L7LQ7zÃ\ÃZo=(’I°¡ ¸×àƒC*wWPJEòXññf^E÷ôÃlði*yk‹o›×oŸ×~уté(%Rù—IÜ÷`Ä©kXßeIåhc‘ ßÎÍÑ´ËByGw‰!V©–2¡WƒÃƒqKÂpÁ%Ü ã=Þ€p`Gý’SNIR?,#P®ØfKÑÖ7!Ò7Wà׆³8&˜w‡qô|XZmJb´¨ÄSµî×`0K¬ØpÆnåþé}µ8#rø‚Û28Œÿ_#mºÖ=¾¡\cŒ!v¾þJT6Ðq|sgÖR³3’õ9±Þö)¶¾î®n8y‘9}ö¢V9/HÂ$F!}4ð-uÉÏÈìG~šøp¦Sï%^)‘ Ë+ßd“ò4‘‚Mì”ÃT•Ÿ¹.úàLv …’ä øúîºÈU8ÎU0–N݉õ±ë¤T’¦ˆRÃ뇕ًgՙ߹.rÀ5ºaRà÷ a•رvæ’Õ‘“ã¸w}ÙT`0"†Wÿ~©Ø4Q¡Õ™› :¢ç‚ÂR ›Ðàž…(—$wþ€´ŸI²\øXï…ŽîÈ;x¬xؘZ@J9™—Yuš™¦çCâ Â)¦Œ×0l;:•ƒñgò8.Âæô?rE_l°hYº­ýx‹_¦yl¦©úLâ6jÚo†±uNI9¡D†„Ú¤ñg$ë1Kˆ–烩[ºØtÅ_¡Ú¡ –¨:.ÔÀ5‚À£¢ 5. Hià†£ƒ4næ8h†ŸÁ9UN˜‡hŽÛ­ƒ§ì:B)»²‰G4Á£˜ó÷8“u~tTº븺,C"ô©X}¹3â¡»©ó @²·¶iZlEˆ=ª7 5º@E¬,J2Ž]|fþÖ˜’?ñCµO?ŠíTž»±Y®ïκ#úBK$KDâbI03R)¬–¸°õ#m¯Âf-V›hÉP¾ÅDx˜¡¢útö¾߹»-K{ï¹äâ”&¤äæ…¬‹1r7^ÔV/Áy"â ú5!Üåf;L1|•W¨à¹š,Þ¦A\]ǯ–ÁøìÈt CK–f á[ë,a;#¤›º1Xêz×|,¸7 ê"vÑ4ã4²>„¤Êµ¸w™I#ÌøühûïÉ ¢ú¶}öbhz \cž L¯Yƒì‚öÆQãææ{ïýlN÷ÇX)#ÿð®\;ÆÂ¥Îþ€Ê#šx<`êì <€ñ^/f±Ï¡ð…zvÌÛ©†(·ÐSEåä½ù%º#f<¦%ý™A—6ýÔ^`«[wf/°u6Å>ܘÏmyyØ!ŒÁUýÁ¥8Ê#TÎß9~/ ¾Í8[L0^&À¿ ìÆÄU©M=‡2ÙØóÍâÕy,ÖWÙ5nzâ‚ äÔ*«þ=i§"±+Èœ¨X…o*/0Ѽѧ[õQñÛ¸@ïбärÝ/îŒe܈LéIš$ÖL»ÔßÕ¤_³ÅIx ÂÜ#nàÇ”p©÷èð÷ž¶6VèHÐô”¾|Ìë½Ü)æ—|ɵd4ä-\þ2à™›àL^Yïô¨äZÕ\ö:‹€}SlŽe–À9¥ŽúÁ»Äã]ñväY/£KNˉvë†é"ž«ëå‡úÛ/6A¨N#j àÃô™¹ÀV2»A$¦Ì€„«‚,Èv÷WÛWݵ…Ÿ^yñ$ƒêÅçƒS‘= 7»$ÖH0«k{]n¾º +N®.Óœnö¹ÍšÐ¶çÛ›z' f#@$Bwå˜ñH†Á!ZÐY·ØLýñ´’MÙ|ç[*hWyí@¢])8%B šEèœVÕUØR…0e×X‡Â•â?#ö`©)W'Ê©Ö}[mEÛX`UtÛUæÓK öø#‘H™ŠZFEUN©áÙ…1~•X3áçá2m`ŠY~ÙÑM%HgTWxpFï•yáVV†ûQÖ†/Á0§þpæÙ— äiT;ˆ¹Wi^¹æag©ôœJ×My <Êb¥ ‰§ª ‚‡]DA„9Üš "ðéà­>ìð«Md‘FWauIÕ‘Tu6zÅæ‡–6­«IJi¥}ŒÑ;ÜðB #TÕÔyU[‹»®+¦ºTÐB Â^ñF'-ÙÚ’õíešR–z*‰ÕZKЉÇMäð¸貫œFN ÑêZhíîÚ'U©±êÁ11Ʊ Eˆ/…úm§˜¨8]‰*Á-q^¶áÑÁÅ9´àðUõ9qjî¶;ñCÅW^"8ÜgÅíy<1ÄTÄ»œÜþ©|*××›5fcjªê ,ó y Ç…-<¼qÔ?$ñÒ)¼pƒHD‘…s ²Ð ç° AÐ1ÆMøƒ¸NU,4¯¼ÆðÖ"1‰(u,±6Ùšiî*ÛÌ×KÄàðÏkltÜsçÐDsȵ"D#PôJ.¦ÇU@E, ™©u„:æ vÀ r®jq ÜE)<ÜñÇ»R¼ô 9ñ¤™íÔƒÅBGÏG,æj mM¡ÕÝ—¹Øä!©y¡Ž¸;-±ô‹¯“—œªx(øÂ Ä¢ ¢!•ƒÍ7j¢•â¹/<ðË“ò’‚„ä®=QCƒnÐþíõ€ÑH  B ä¥bæ;_|ò5£³¸ ‚u¡¡–œú5ÄkûXŸ¤·¼`ÐÖ¸R#˜¨DAyHšÈ䜣Ÿ°„ K”YÁ26‘1ì`|;šÇR*XñxÈ‹¢²‰PL#W HXBÅ•±À†X¡cˆÃ…ä`¨)aj$¦‘ c,È3t¦£Ìi-5B¤3`ù„„l"% NK"T2ânŠ6ËD'µü™“â’rRñ '8Oj.J•3+_hFÆÐPªA.,`¦€bžµ%­A#HäFïbj)›(Nä"QJŽÑ—LÚ úR¾´ÀiµHâ2a¥¤õ JI³¶t•k€Aí OÛ“‚?U䈙ÂJNÖÔùÀN|ÈÙªú›%Jï A‚€ª¦NTUQý£ÑÔ U8t8ÇZ°@†"0D]æÖÍ%v8Ïóà»–€þíõ8a\ Â=\6)rÕ©–ÆÇ'iTéd‡s©#‰à 5ŠãÚEO-Jm•ò<ü”QÚió‡µu¬*ÖkBb€‘ótµ.*0騫™œ "ËH ÎÃËßþf •}Ú‘:‚ÀÚ±sM3;„dŒªÚΤËÉ\‚@ ši.tïr[‹t½ ¹`{Ô„†©kˆZå mïk—üNÄOÓÈrh²÷¿¶oyÉsÝÅ­–!k…?,_ø8ôpBð ‚Í‚ø·ö¬p¤«aU„§™ðе‹oÁE9ШBÿÞÄ-ëqJçþdEM)êÿ›cËEÇ1›˜T|h¦÷É.òñ¤L;UÌ"9—Aåkæg˜¤ˆJA Û3SÎ}˜¢R “y]r&2•'ògN®ª8}Fs)xçþâ²#¤n¡?œfß…TQrB(fæGCùÐÇÑñǶd§xÀ¥šn¯ þl”D/Ùc¹.Ký_pz8 &luÒhãÀʨfH~]mâ†$m×–µª“’_AWDyN&öd#mä¾LÌÒácSníì½[ÍrÉË (âj]g[»§>6RòÛ±ezܦžõ9û_yÝì&w¯’l=3DH©w»Ím[€ ¤þ„ )¡¸ý}ZÜ8ÇK¥r^„ÿ›ÛXÑÈ@méJ¼½ o¸Eò{Ä`„“mÞxÂÝýçÎ \Էɾð„(˜ÒúnÜ4òrŽ£üŸž©æ¹þ(l缪§x]Jøãª ý¿$Ø9i®©-é1GH¯Å…ñ©ÿ¶éß±Ö¿ŽTý cûoCàt§vÝì7.º¤Ù>u´¯Ðs‡;…Å^w_çÝîÚ•»Ñù¾q¼ÿð÷ûÛ ø²‹gïˆGëÒÞÅ7>›‚?üäëýxÆË\ó—?è$?Ðw~Œ™üèwýyΓ]õ§¯d ¯ØÖK<õ¦—ý£_ÏúÅÛÞß˽r¿{kqö}ñ}ðóÔ{à‡^ùLJÔð™ÿûæg›¾7¾ô‰ôüÚ_ÿÆÔ‡¾õ·Ÿ¢ì[üOÞ@õ¡Oþm€ø|ù~ú¤ó¿ÿÑë÷>úçÿóßü˜€þ€ø@€H€€€ ¨€ ¨ Øì‡_Baˆ¨Èè‚!(‚#H‚%h‚)¨‚+È‚-è‚/ƒ*¨'Hƒ5hƒ7ˆƒ9¨ƒ˜‚(ƒЂ>¸‚BX„B;PDF-Create-1.08/t/pdf-logo.jpg000755 000765 000024 00000030654 12251673270 016205 0ustar00gaborstaff000000 000000 ÿØÿàJFIF,,ÿÛC  !"$"$ÿÛCÿÀq,"ÿÄ ÿÄ\ !1At"28QUWa“”³´Ñ7BTVq‘¡±Òá#6sv’–²'3Rbr‚•Áâ$5Su¢4CcG„ÂÓðÿÄÿÄD !1QARaq¡±Ñ23‘Á#Bb¢ð"%4r’á5‚Â$6T²ÒÿÚ ?Ü´!BB€Ó»ƒN-mDÝ[©ð.yHó ’‡M| ;¡àºV9Þññ÷Îæ}&îLÿŸÄö¯£iŒîµÕÏÐRýYŠÕ!KÍOÜ™ÿ?‰íHîhÒ~äÏùüOjº0¢B˜;št£¹3þÚ‘ÜեɞóøžÕs¢B™;š´§¹3ÞÚ¢w5éOrg¼þ'µ\ä(€¦¿“f”÷&{Ïâ{RþMšSÜ™ï?‰íW! €§?“f”÷&{Ïâ{Qü›4§¹3ÞÚ®$÷òlÒžäÏyüOj?“f”÷&{Ïâ{U„­jæ“Rl›–Ç:o39A®Têÿ‚Á3qМ@ 9ã'n9 Øx•í£Úç;ÂZq¬píë؇-6ì6R©È×1Ýk^îÐê\v :–¼{ i?ëD/­ªÎÔý>¶u€êEÇ$"†äËÌÃÃcK<ûæ;““#h8Ú ÛBÕ›KRo= ªKZz±b»fň!RîˆpÜø’ã’q´&× €vz™=%S§À¨ÓfàNIÌà G>Fæ¸l ö„!!@B„„!!@B„„!!@ke¢3º×WAKõf+\Œ*ªÏÝm«¿ ¥z«°BQ ¬¤(€Ç…RQ# d(²¢B ²‘ D(²¢B )¢B¢×t&ýi…õµ_®j õ×ÝIZa}l[æ >Mv“N­Ò¦)Ui(²3,,3˜ñáÿ`ª Sïε(õ›1³W>œÅy‹?Cˆòèôðvº$ÚyåxØ6ÍXžÔ/M/Ë_Qmˆ7 «Rdä«ú˜°ÏS]øÛ#8Úáó0H žÎµv÷ÒÚý§s¿QtVi”šàꧨçdI™Énó {[v‚Ç ›;Bõ®ƒ©p£R¦ D Ý²9mB‰6w±Xæìs¡çíÏÌ·” ‚@µ„ !BB€„ ! ¦ðîs_凱;…Ü×ùaì^>±OyeÅœÎõæw$.›Ã¸]Í–Äpîs_凱=bžñÅœÎõæw$.›Ã¸]Í–Äpîs_凱=bžñÅœÎõæT6oe¶®þ‚•êÌVÑ ¸¢R;X/õÑ„Hw9F6P7@„!œ»ßgâ]¿ñë~ oîOX§¼qEç3½yŸX„ˆ_+ñë> oîKñã> oîOX§¼qEç3½yŸP„ˆ_/ñÛ> oîGã¦üþ×Üž±Oxâ‹Îgzó>‘ …óMe¿?·÷%øå¿?µ÷'¬SÞ8¢ó™Þ¼Ï¢BD/œk ø9ý¯¹Ûÿ@þÒzÅ=ãŠ/9ëÌç‘ øÙ¿ôí,²sÂf7C‹vg9ÊåVƒy&t©†]S‹œ¡©t¯3B‰ ) $/ROë¨þq4“õ¦ÖŰoj×ývÎ.‘þµBúضí@qÕ‰Í\§µa{PW5Vä”ÛÖ$*õ&n%¿wÈùÄ©,xszÑ{‚Ghñ·“fAµÕ‰Í@UÚG®•) ŠœkL´*ÎdS²u1ľkïNGRì4ì"¨u"Ķïë}ôkŽE±ám0c7©‹.ÿëÃw!ú(!Uöž ÞºP•¶5%ó7… ƒN¸a°¾4‹}ì8£i-Þí gx\ðµÈ\J5NZ¥KUi3ÒóÒ3L L@ˆ#O(#a\´„!!@B„¯ë=J~—j@˜§MÆ•ŒgÂøNÁ-,yÇÐ?Ã+«»óþX«W^ÿ3%ùû?êŒX«ùÊ5rLý7Á;Zpõ)Á7›Ú“>÷ ®®ïÏùbŽ]]ߟòÅ|oîe²m»Ò­ZqÈ:r¬o‚wÃÞ’âXFx¹WV½EN2ÖúK\Z¥†g;ºÔ“Œ2Ï(¬õ´¹rß¼¯¸euw~ËpÊêîüÿ–+m:DiÅèží®%Osî›ÍKº¼ŒôƒÈÙãÜG‰ûáô+'„^/¼¾/ÈÃÃ郒y:_ìÊLÕn]]ߟòÅ2º»¿?åŠì˦U-;ªÁlHâv™7¾üh7zr8ØñÈá‘à#‹”ÿ¹§N- ÎÓ©OÜTÇÍÌ@žè0Ü&bCÃ:N0ׯJ…NÞâu½yK¥š{ÌgµÃV& §IåìÅg­å±å±íÏaPpÊêîüÿ–(á•ÕÝùÿ,VÙ?A´ÁÞ=ý^¾-ws‘9ÿ‹&ê”ÈØêŠ"ÃÂ× Ÿ‚™,&ñ-Rϵ™º?H<©,¥IÇ¥Â?&ßq¬ü2º»¿?åŠ8euw~Ëõ5GN«ÚTd½M­'ŸÁ§aÉÅÇþˇ(>,ª5E¦ÜZ™F¢Õà‰¨lXaîfønpÚÒڮѮªªRm<ò6¾› •Œ¯éÆ3¦¢åšKZK7—N­-{OÃ+«»óþX£†WWwçü±[iÒ#Kþ/Dóøÿm"4¿âôO?öÕŸ^s×Åù_¬^ÿãËû!ÿÑ©|2º»¿?åŠ8euw~Ë`nš²m».¯F—·$)j^#âƒñ7Ä8דŽ5Pªºê­ Žœ¥­t›¬&¥†)g º4’Œögž¦×&{·Ÿ{†WWwçü±[Am’èÜã’adŸ™j Ûû_¯…úõe„NR¨ó{ŒWÒ5 Tm!èâ–j[[¼B‰ )oiD…ª>SÚì?œ}"ýj…õ±lKÚµç]Çó‘¤?­p¾¶-‹sPWµa{W-íXžÔ íXžÕË{VµÄ{W±M‘ªÓ£Óªrpg$æYf1í<„õÕ‰í@kÔJ=ó¹î«3péëf.4C¥nƈ]T{èNÒ0=ðãàà7Ãc4³Q-]J¶¡×mZ€˜…°LK¿ *ò:ÈŒÏRxöí«„öªRýÒºÕç:‹£“­¡ÜŒÍS†)Qo˜æõ žÑêIÁê\7È ¥B¨ô#\(ºÑ(5YW[פžY;F™Ë\ç7®t-ö×7”·®nÜäaÆÜ@B„„!ªš÷ù™/ÏÙüTb¼õïó2_Ÿ³ø¨ÅˆÄ=÷aú‹ÿé«­‚ØÅ¿óëšÁþ'-~[¸·þ}qóX?ÄåÛ þn®Fypïþß¹ê_ûDû›³£FƒI¶Œ±!“>wŽ#=K;K­nE®ÜoyºC§&¦iN’|X°â<¹žÐ× ñ’<>%°÷•*ѪB–mÙ-Kœ` âÐ8ßowÇä_2J­¦vlŒQ#Q¶hðÕDl¼hLtB< 9qùʾ©fýsÓ¹¤¿Áò[>S|â˜ÛJsy¤òÍk“y­¯5âu]Ö`EÒH‘#bBž‚ø$ò8å§á._qŸæ%cþæ}mº/UeoˆÒÔJDüM'Åtg´´ÌÅÁÁ§hhã8'|rÅdî3üĬÜÏ¢bN¼+bYÃZK"âï ¹Ãx*w+)JjY=©6²Oáž];Σºö§R‘Ô S$ªr­4¶¸ˆ1œÁž‹nÃÆ¾ŠkÉD¹äi•Ú¤ÍN7°" ¨†#àoŽÚã´HÈâÆve}-Ù^èTŸûK},UMPäæ*© V¹Ó3áBŒ¹Î}%W]שJöN”ÙàU•ÿhÓ¹‚iÁëif¶ëO‘­æõjµ³/vØUZ4hAñ_Ñ%Ž6²3A,#µ·að9V¤nv÷g·MнnÜÔhrÒÑf#86&½Ç’V“ny!ÚÕo8àr~IêÏ„UÍr·óF#€·eât_³6ºÜ%Ÿ‚6«[¤ªõ.­IСLŨÄl.‚ÉrDBDVŒxZ±À}aîMËå_ö–à_£kNÜU3¥¤ÃLF@¼ïžÖ @ãpåU_ò—²»pù?þÅëˆÑ¶DêÔÑy8ˆã6¶S……¢« &ÛkcÉjÚ¹2}¦´]Ôë’•Qd•Ñ ~ ؆Èso.pa'hÉ; æ_wÝu½i—åé·J–›——lœ8“-h~ù®y'©qê‡*èK/]F5ƒÍo>é…Ô¯VΜî!¡6µÅr=À·Õ‰ ô#ê OÖàZŸÒÂýú‚´Á½ãì0I_Éê_ñ; $,˜H…¬??”jN~µÁúض9ÍZç¯ùÉÑÿÖÈ?[ȸ 8®jÄæ®Sš±9¨+š±9‹”æ¬nj†ö,/b潫 ڀཫÚ¹¯jÂö *ÝaÒjMöØ5YIˆ”K¢H‡ÈV%IdV9»Z[‚àÎ[ÈxÁãi>ºÕè7=:×Pé5±†ÈW66R Þ \íkõ¶4í0ŒQì]_P¬«zù·âÑn9ÌË»&A²$ò>½ë‡Ìxˆ#!q!jM«|ÞûžjÖõòé«›Nb8A‘¬CatÅ4q5e£ú§“¬;7‹iíêÍ*á¢ÊÖ¨u z…:mć1ãåíƒG ƒµÏB€„ 5S^ÿ3%ùû?êŒWž½þfKóöÕ±‡¾ì?Qp?ý5u°[¸·þ}qóX?Äå¯Ë¶i¾ Wl©Éš$Üù¶5‘?„^0ÒHÆí®–5£F¼jKbò%p£ ­‰áU­(e¥$²ÏRÔÓùníOùM³úyábÖeÝu'S.;þ^Jv‹[&÷¾àЋ\9Ëh.”»_×zî¤6<¼.áUðœ&¥ÆZqÒÏ-k\›ù‚ڭƘ•û™ôLZª»Öœê¥ÍaÒæ)´8t÷A˜ÑßøD=ÛíènÂ6`Îq zêsØyðǸÅð¹ZÛe¤ÚzÞKS6[´~wPîi*´½n^B¼˜—s"A/$‡½ÙØGõ¾…ÈÒ¡Y56VfçbV*è1C…‘‚ZÌž«i? ™~è½BpÀež*ïõzø•ÝmÔŠ´Àu|ÉBxÁlœB>'¾"­%}`ª:Ú-ËõÒa)p_…³²Xs¯QK,“×–ìÔs}Yëå/=Òú‘#@¶&íjlÓ"Öª0Ì­c³ø4¨»´ç4à=¹ä¡w;{³Û¿¦‰è^ºx±cÆ|hÑ+ÉsÞ÷çÆI—5~o#Kx3r|_«yœOb83r|_«yœObÝ.?ºmòîGÝ6ù÷'K€úÏ¥Í_›ÈÒÞ ÜŸêÞgØŽ ÜŸêÞgضFPmZ»¬  ºÛ‡*ó9¾ß ŽDÆóÞã8ã9ð.ãÁg|4y/½8’[üÖ}.jüÞFžðfäø¿Vó8žÄpfäø¿Vó8žÅ¸\wÃG’ûÒ໾<—ÞœI-þë>—5~o#O¸3r|_«yœOb83r|_«yœObÜ ;á£Éýépaß OïN$–ÿõŸKš¿7‘§ü¹>/Õ¼Î'±¹>/Õ¼Î'±mÿ]ðÁäþôpiß OïN$–ÿõŸKš¿7‘¨¹>/Õ¼Î'±¹>/Õ¼Î'±m÷ðÁäþôpmß OïN$–ÿõŸKš¿7‘¨<¹>/Õ¼Î'±mu ˜„ ˆAñ.ð±äþõÊ¥Ò ”×F1ÄN¤Œo1þªe–+iæf¸Mà 8;†¤Òyež¼òÞº¡„ˆYQ!]3)½|Ô­ýmƒõ±l¢¢µ§Nê·ÓíÙº-Ì-ê… {ðÙyŸÀÄÁÒpÎܯ‹Àxïÿ÷zÚ@lk‚ÆàµÔÙ:ïßú7îô´¢lvïý÷zÚ@lC‚Äæ­{6Fº÷ý‹û½í(›#];þEýÞöBÆæ­6>¹òëÜ_Ýèi#ck—¨¿»ð>ÒüsVµPæÆ×ÿ1wà}¥bkyã׈¿»ð>Òõ{VµQΰõ»—]âþïÁûJ&ÂÖÃÿ×hŸä~Òí{VµRÆÁÖ¾]u‹þAí(›Z{ùÄÿ ƒö+Ú«}`ÒŠ-ÿëbĤ\Rxt…ZW©‹ Í9hv.h;FÐAÚÛŸ€tûYϹDÿ ƒö”Nžë/Ÿä0~ÒèiVºW-ô;×V2B;ÊuÅÅ+:Î b;ÅÕìz°Ò ;.×49¤‘AØVžÝú)¨—u+ñ]É«PªR›ððȶü,µÃß5ÁÀ´òd°‘ʪ í]Õ½ªÎéÅóü2B¡Á|Ä”8„4µ¤5½8µ£;œD¤HB„„!¯Z}Ùu¬Ú•ê¬W1 šÓÎË­`æÔ¯Ubº@c!,,„(€†!L„°€ §„ˆ@cÂK! $ BD)á$2YQ!HY0’!d!D„2!d!"ÈQ!d!"ÈQ-í,„$BQ-í,¤(–öˆí¤BÈR-í 1¢BÈGm"ˆ^yî˜÷uº¹Ó}¡ä/ªÅvaRšmÙy¬<Ö“ê¬WnÂXSKa XI$¥„ÂJxI $Bž@@…L$BÝ)+á—ÙFl³>柞Ò»†¢VáAÒÊ•b°Ù™ œÿÖ­?ù‚ž³RÍWMêðZÍôH0„Ã06ƒ ‡üC‡S×%ÍøÇDmÊ$˜“‘&Œ´F §{­oÌøJ¢æ§ ©SñG>݇Ððk>5³²[}Wý/÷þš,ý§~¦²q pùÈ‘&>WoGþ- ¾apíÚp¤Ð)ôÆà‰Ihpr9KZ?BçaYP§èéF‘ŒÅnýrúµÇ:Mö7«¸ ¦BD/R¼‚D)¢B$BšD ¢BÈB‰£…‘"ÈH…… 1¼æÝ?î÷vs¶ú&/G^qî ÷|»9Û}§!@B„¦½—ºÃÍi>ªÅwaRZiÙ{¬<Ö“ê¬W~F’Â8K HÂIO a $§„°’8IK 1ņÈÝ#CØðZæ‘°ƒÆ²YV» kŒ*WµÐ)óÑ"·.Îù°Á{B×8ªŒMÁN›kcϳVgÑx Nâv÷‘§,´£¢³å›RÑ˧,þ&Ø‘ JLA›”ƒ7-DbCxâsHÈ?1YVûO´âò{LxK d$B!"ÒÂ(²‘ i¦BX@@…Dˆ@cH…… 1¼âÝEîùvó¶ú&/H›û¨ýßnÞvßDÄ©¨B„„!AiŸeî°óZOª±]øT†™v_k5¤ú«ã„0Œ)a, #„”°„ž@G )a, #„”°’8IO +=ÑU¿ÅV ä!?êqDðuO?@oø–h6"è¼;QðÚÙÃ+Ñv*úpUêÔ”¶{>fÆö⦇ÙФò›~™õ½Pî[:J·s­Àú§…6\'):õÝwBq%¿1o€¬ü*BåΜël è[ÈŽGZÒâ:'ÌíëþC…x r]ì¦ô)mޝ.â' -àî#}E}u¦ºÞ]j^$HQ!OšfLd$BÈB‰%…2!!M, 1–B!"ÈK d/7·R{¿]¼í¾‰‹ÒEæÞê_wû»·Ñ1êb„„!!@PzeÙ}¬<Ö“ê¬WŠ£´Ç²ûXy­'ÕX¯$ÂIáá,)á$0’ž@G )a$p’ž@C çÜuHJ õ^kú)HŠFzì €xIÀñ¯¥…PÆ4še¥!—ÍÕ¦] ¼ep oä~É^5½ )Oõ™k‚aücJß‘½}ZÛø&aÜßJ3±yÔún§0æ1äq´;|ò<çàWùÖ¥ Û§Ñ¥ðY)°ÉùÞùÞ3“ã_H®-húJ¼½glwãú— Ùo(ôEj]È麽k ®Êš“… :vüD¡ÆÞˆÐzŸñ ”ŽÒùZ t‚ÌdŒÓÉŸ¥â^.zç3“wÌùZU…E\úc¬P«ÐØ[B­&FÆGD+]‡ / °«ëfÇò}…¶ üR®ýµûôú×µ÷-ioY—–Âls^ƽŽc†Zàrí§…<ÉK ia!M, BXS!"K d(áHY ÍÔÝw;o¢bô§ Í}Ôý7w;o¢bÔ´!BB€¡4òÿXy¥'ÕX¯,*7L;/õ‡šR}UŠó@$°¥„Â’Â8Bh@G )a$p’ž@@…FY¤ßúë?q»ò”º(ÞK6’2ØxùNþ"ïºßqðkOçb‰¼›œ‚Kàíx;çx›¾9íábЫoƒº)Ñ¡ïfçÿâãämà7ñ7;d¨¾Ú¼irG[ùÌ3øv^ùûu~Î[fþ³Þw¬$¥„)æL†YÔËZ ÝhÍRœ&@貯>ò+zßÚ€•Ú0‘]g8¸Ëc=ínjZÖzO)E¦ºÑUn}º#T(±íj¡s*tsÐÃ×@à•‡©> ê´p©M_§NY܆¢Ña/ ‡? »q9ð=¼¼Žã!\4Z”f“+TŠ"ËLÃ!»ÀyhŽ"9Q,æãízäf‡„v´ê¸bvË*uµµÍŸÞÇZÞ¶¬%…,%…4Ë‘K XFK ia!M, 1–L$Bó_uGd ßÏ蘽*!y«º§² ïçôL@z”„!!@B.—ö_ë4¤ú«ç…Fiwf±sJOª±^˜@,$¤– )$€IaK "…$°€ŽR_ þ¸ ÚöB·z]/ô&ìc|dWYIB.Ob=hPÅXÒ¦³”šK­•-þz`k}2Ó„z%2‘ÕÍã­$aÑ3ó1ž•y€ ÄO¹²Þ‡9vÔwÏŸ¬Eqkß×t0ã—‰ù>&•m(–Qn.¬¶Ë_g!¢áEhB´0ú/8PZ=rÛ7ÚõvÂJXBšfa%<$€ùõúLn5I¨Cè’ÓPÌ8ƒ”vˆípAí…Né Rrɽgtâ½ò1"—Sâ»cKŽÑÆÜr8ÆUã…Zë½—á¢C­RXáY¥þR‡±ñ!¥£wÀõMðär¨Wtä²­OÚzåF›ƒ×”d§†Ý¼©UåæÏîËäú6ì,|%…Òôzõ‡y[-‰ÍmRSç!™<‘í;#»± M*‘«8ìeõ•k‰ÛÖYJ/'úÜö¢K xK ЊARK¥…$°€ŠD)¥„0¼ÒÝUÙwóÆú&/Kך;ªû îþxßDÄ©(B„„!Ciwf°óJOª±^Š‹ÒîÌ b攟Ub½p€XI4 XRÂH¡I, M¨Ýs›˜»¯Ú&œÓ"èŠØÓŽnÝëˆÎO÷aïþ%p]5‰KzÞž­Nœ@”„bœzÑá'|ª©ÜëG›©ÎÕõ°7ÓU¯‡.Häßf#‡ƒ 4v·¤(ÒJ4.·Ô¼Íg"¬©VŦ½ÚчMIlþÕ›}…¿O“—§ÈKÈÊC¥åá6&&µ£|ÁgMSÒËR2’““ro[#„”‡0…,$€Ž–ˆÔZ\î™ß/ºiS‘7“ÒìØÐ\ræø±¾§+¢‰S’¬Òeª”øÂ4¬Ì1ÇhòÑDr¥\¥ÉV©4ªŒVf‡§µÛ¢ÐyTTŸÒkÚ%£pFtJë÷ò“NëY“€ÿäpä;x¸ëŸý%\þ仟“6Q_´6*+]ÍÛR ÆQøµ½—ÆÂ`‚v‚…bcHá,)a, "–Ò aM, ¼ÐÝYÙ xsÆú&/LW™û«;!oxßDÄ©B„„!Ciof°óJOª±^ʉÒîÌa攟Ub½Âh@E XI°’h@$°¥…ò®ºÜ¹nÎ֧݈°‹ÈÎ ÝÄÖ $ò®%%›=)RiªpY¶òK{eE¯µ9»–ê£é­ù‹+bδ4‘–ƒàkrò?»ÚW™)F£ÊR¤aï%¥!61Ë€1“ổYoZœt«Õy9lêä6ضu[Ña6ÜãGÚiju´ÛÙ«bÏf²ÌÂÓCRn=–¥Šè0ŸÖÇŒÇÄ'ã)p3Yî]µë±”¨ë¡A½p­ì|n^Þ¼¥îàåÙ’ø²¿öZt5ÞÜS¥Ðå¥/íŽ~%ËQªS)¬ßÔj2’mãßGŒØcé!uJ®ªØ숗¼w&Ë1ѳãh#é]J›¹þ„×tZÅz§?íq†8øs¾?JíT­$°)ø- C˜x÷Ó1_>"w¿BiÝÏdTzÞ~­ÁÛnµJ¿Óù›}ÇX¨ëý­Ų4º¬ÙùÍd6Ÿü‰ú§MËQÙCÓÙÈùë]¾‰>&°}já§QhôÖ†Ó©R2`qì‡õÎÂz ™{U2êHq¦ KÝÙ9tʤ¼H¤8W®5?ý-&ÓÅ¿¼w¢ÄÿDo7AÌñÄ’’Ï58ú®äa=M½µ%ñÈ~ÒÓ†ªvTRé‹“ïe#Á}t›þží’—Ïÿ6÷ø!/™^ÒmN¯A‡ ³uS'™ ÅÐÄiˆ®Þ“°ãò{À%…İúrYJMöépÆòŒ”èÒ§·SŠ5Vƒ3¨pîqd¾î‹F›—ü„ssl2GZÆÓÆ:ÞB1Ž@»çµÚCÿOsIMcÿ‘Ï”†»Ž®éä­çMÛÉjÔ³á¦8·ã¡¼ö³ÄyŒ…£ú…516ë2ðßÊ×e]СD°Çǽwöü>ømãã‡uJ§£©&“Øóîë4•ñ™b^¹gBœ¥öpM¯Æ¹\_/*>Q¨ëå;«J“Ÿcxú˜.ωŽ&ëÉFˆÖ]ö<Ì£IÁ‹ ¯„Ì+Ô§5N²Û±­Ÿàâë ²ºµÞ'ûšå {IoMj’ï\¥¬Œ)%…4Ë‘^fî­ì…¼9ã}¦kÌÍÕÝׇõ£ç'À©»žòºu‚³'jÓið$eÝÅdûOUøâÝÞº—A”‡¼Q¢7¢ÅÏl9Ù#Å…ÙЬ)YÐ¥ìÄÇßð¿ÍW¬òܵ/‚É|D–°’’RB’X@GM@E,)a¥…,$€K ê®›S¯8rÄj qh Ç_Ž1ÚN#Ê ªº\ê=™αnOÂ䋉±œF{l~XO„`¨i×¶ÔÖœwò¯3IRž}¤&­ë=©û¹=éëÑêz·sˆh%Ä6’U§Ñ›tn…®ÜTýë¤%a£k_†6H?ÚÞ¹ÃÀž¤ë…×ÒjÑ%©2:ˆïlHMß·—= —àYúygÓ¬ºi’'¢ÅqßÌL9¸tgöÏh 9>\“Æsº©Ýj1yëÕ›ä;ªvøué£RµXè%¤£Ó“ofo,’;XRK ÄÆ‘^eî¯ì†¼9ã}¦ËÌÕý÷« ^êˆÒÎÌ-aætŸU†¯t„“B˜ÝhØÆÇ¥¹§ò"¤Çöº÷¿þ_:¶-÷À‰A§Ä•Çàî•„a`äow£BùÚ…lK]öœåa£7})èQÖ»çãð5F®6½1¶>‡jrÓ¦~ñ¼›×—ï{[ñ‘ÅàÕ$íî%7Ô’Ù¯Z6V´)âØM+XUŒ*R”›Rz)ÆYkÏ¡­}¬‰%dQ ™µ2Â%%ø÷¼ã‘£é#²>„XS4¸qo”>-~¥˜èÛ_ŽÚIÏÝËÚ6mQÓM''Wá]ï9øÖ¸çtFCsº# »‘Äž¹Ã“‘¼™ØE¶»Ò¥:ÕZ«,¶-Ý/¤ð¿¾¶Ã­%‡áòÒr÷•9߆?…r¾^¡a%$)ÆPŠÂHBa%$ "Œ'„ M@G )!a<$€HM, RB)aK "¼ÆÝcÙxóÆú&/Nט›¬»"oxÏDĨÈB„„!Digf°ó:OªÃWº¢4·³Xy'Õa«Ý!@B M„aBa%$ "„ð’B€XII@EM$BhÂ8II¥…,$€I)%„ÂóuŸdMãÏ蘽=^aî³ìм¹ã=¢¡@B„¥½˜zÃÌé>« ^ëZ-ûÒÓ³w^êÌkªà£Ãš•¥6¦â†…²°É # Copyright 2010 Gary Lieberman # # Please see the CHANGES and Changes file for the detailed change log # package PDF::Create; use strict; use warnings; use Carp qw(confess croak cluck carp); use FileHandle; use PDF::Create::Page; use PDF::Create::Outline; use PDF::Image::GIF; use PDF::Image::JPEG; our $VERSION = '1.08'; my $DEBUG = 0; # # Create a new PDF file # sub new { my $this = shift; my %params = @_; my $class = ref($this) || $this; my $self = {}; bless $self, $class; $self->{'data'} = ''; $self->{'version'} = $params{'Version'} || "1.2"; $self->{'trailer'} = {}; $self->{'pages'} = PDF::Create::Page->new(); $self->{'current_page'} = $self->{'pages'}; $self->{'pages'}->{'pdf'} = $self; # circular reference $self->{'page_count'} = 0; $self->{'outline_count'} = 0; $self->{'crossreftblstartaddr'} = 0; # cross-reference table start address $self->{'generation_number'} = 0; $self->{'object_number'} = 0; if ( defined $params{'fh'} ) { $self->{'fh'} = $params{'fh'}; } elsif ( defined $params{'filename'} ) { $self->{'filename'} = $params{'filename'}; my $fh = FileHandle->new( "> $self->{'filename'}" ); carp "PDF::Create.pm: $self->{'filename'}: $!\n" unless defined $fh; binmode $fh; $self->{'fh'} = $fh; } $self->{'catalog'} = {}; $self->{'catalog'}{'PageMode'} = $params{'PageMode'} if defined $params{'PageMode'}; # Header: add version $self->add_version; # Info $self->{'Author'} = $params{'Author'} if defined $params{'Author'}; $self->{'Creator'} = $params{'Creator'} if defined $params{'Creator'}; $self->{'Title'} = $params{'Title'} if defined $params{'Title'}; $self->{'Subject'} = $params{'Subject'} if defined $params{'Subject'}; $self->{'Keywords'} = $params{'Keywords'} if defined $params{'Keywords'}; # TODO: Default creation date from system date if ( defined $params{'CreationDate'} ) { $self->{'CreationDate'} = sprintf "D:%4u%0.2u%0.2u%0.2u%0.2u%0.2u", $params{'CreationDate'}->[5] + 1900, $params{'CreationDate'}->[4] + 1, $params{'CreationDate'}->[3], $params{'CreationDate'}->[2], $params{'CreationDate'}->[1], $params{'CreationDate'}->[0]; } if ( defined $params{'Debug'} ) { print "DEBUG\n"; $DEBUG = $params{'Debug'}; # Enable stack trace for PDF::Create internal routines $Carp::Internal{ ('PDF::Create') }++; } debug( 1, "Debugging level $DEBUG" ); return $self; } # # Close does the work of creating the PDF data from the # objects collected before. # sub close { my $self = shift; my %params = @_; debug( 2, "Closing PDF" ); $self->page_stream; $self->add_outlines if defined $self->{'outlines'}; $self->add_catalog; $self->add_pages; $self->add_info; $self->add_crossrefsection; $self->add_trailer; $self->{'fh'}->close if defined $self->{'fh'} && defined $self->{'filename'}; $self->{'data'}; } # # Helper function for debugging # Prints the passed message if debug level is sufficiently high # sub debug { my $level = shift; my $msg = shift; return unless ( $DEBUG >= $level ); my $s = scalar @_ ? sprintf $msg, @_ : $msg; warn "DEBUG ($level): $s\n"; } # # Set/Return the PDF version # sub version { my $self = shift; my $v = shift; if ( defined $v ) { # TODO: should test version (1.0 to 1.3) $self->{'version'} = $v; } $self->{'version'}; } # Add some data to the current PDF structure. sub add { my $self = shift; my $data = join '', @_; $self->{'size'} += length $data; if ( defined $self->{'fh'} ) { my $fh = $self->{'fh'}; print $fh $data; } else { $self->{'data'} .= $data; } } # Get the current position in the PDF sub position { my $self = shift; $self->{'size'}; } # Reserve the next object number for the given object type. sub reserve { my $self = shift; my $name = shift; my $type = shift || $name; confess "Error: an object has already been reserved using this name '$name' " if defined $self->{'reservations'}{$name}; $self->{'object_number'}++; debug( 2, "reserve(): name=$name type=$type number=$self->{'object_number'} generation=$self->{'generation_number'}" ); $self->{'reservations'}{$name} = [ $self->{'object_number'}, $self->{'generation_number'}, $type ]; # # Annotations added here by Gary Lieberman # # Store the Object ID and the Generation Number for later use when we write out the /Page object # if ( $type eq 'Annotation' ) { $self->{'Annots'}{ $self->{'object_number'} } = $self->{'generation_number'}; } # # Annotations code ends here # [ $self->{'object_number'}, $self->{'generation_number'} ]; } sub add_version { my $self = shift; debug( 2, "add_version(): $self->{'version'}" ); $self->add( "%PDF-" . $self->{'version'} ); $self->cr; } sub add_comment { my $self = shift; my $comment = shift || ''; debug( 2, "add_comment(): $comment" ); $self->add( "%" . $comment ); $self->cr; } sub encode { my $type = shift; my $val = shift; if ($val) { debug( 4, "encode(): $type $val" ); } else { debug( 4, "encode(): $type (no val)" ); } if ( !$type ) { cluck "PDF::Create::encode: empty argument, called by "; return 1 } ( $type eq 'null' || $type eq 'number' ) && do { 1; # do nothing } || $type eq 'cr' && do { $val = "\n"; } || $type eq 'boolean' && do { $val = $val eq 'true' ? $val : $val eq 'false' ? $val : $val eq '0' ? 'false' : 'true'; } || $type eq 'verbatim' && do { $val = "$val"; } || $type eq 'string' && do { $val = '' if not defined $val; $val = "($val)"; # TODO: split it. Quote parentheses. } || $type eq 'number' && do { $val = "$val"; } || $type eq 'name' && do { $val = '' if not defined $val; $val = "/$val"; } || $type eq 'array' && do { # array, encode contents individually my $s = '['; for my $v (@$val) { $s .= &encode( $$v[0], $$v[1] ) . " "; } chop $s; # remove the trailing space $val = $s . "]"; } || $type eq 'dictionary' && do { my $s = '<<' . &encode('cr'); for my $v ( keys %$val ) { $s .= &encode( 'name', $v ) . " "; $s .= &encode( ${ $$val{$v} }[0], ${ $$val{$v} }[1] ); # . " "; $s .= &encode('cr'); } $val = $s . ">>"; } || $type eq 'object' && do { my $s = &encode( 'number', $$val[0] ) . " " . &encode( 'number', $$val[1] ) . " obj"; $s .= &encode('cr'); $s .= &encode( $$val[2][0], $$val[2][1] ); # . " "; $s .= &encode('cr'); $val = $s . "endobj"; } || $type eq 'ref' && do { my $s = &encode( 'number', $$val[0] ) . " " . &encode( 'number', $$val[1] ) . " R"; $val = $s; } || $type eq 'stream' && do { my $data = delete $$val{'Data'}; my $s = '<<' . &encode('cr'); for my $v ( keys %$val ) { $s .= &encode( 'name', $v ) . " "; $s .= &encode( ${ $$val{$v} }[0], ${ $$val{$v} }[1] ); # . " "; $s .= &encode('cr'); } $s .= ">>" . &encode('cr') . "stream" . &encode('cr'); $s .= $data . &encode('cr'); $val = $s . "endstream" . &encode('cr'); } || confess "Error: unknown type '$type'"; # TODO: add type 'text'; $val; } sub add_object { my $self = shift; my $v = shift; my $val = &encode(@$v); $self->add($val); $self->cr; debug( 3, "add_object(): $v -> $val" ); [ $$v[1][0], $$v[1][1] ]; } sub null { my $self = shift; [ 'null', 'null' ]; } sub boolean { my $self = shift; my $val = shift; [ 'boolean', $val ]; } sub number { my $self = shift; my $val = shift; [ 'number', $val ]; } sub name { my $self = shift; my $val = shift; [ 'name', $val ]; } sub string { my $self = shift; my $val = shift; [ 'string', $val ]; } sub verbatim { my $self = shift; my $val = shift; [ 'verbatim', $val ]; } sub array { my $self = shift; [ 'array', [@_] ]; } sub dictionary { my $self = shift; [ 'dictionary', {@_} ]; } sub indirect_obj { my $self = shift; my ( $id, $gen, $type, $name ); $name = $_[1]; $type = $_[0][1]{'Type'}[1] if defined $_[0][1] && ref $_[0][1] eq 'HASH' && defined $_[0][1]{'Type'}; if ( defined $name && defined $self->{'reservations'}{$name} ) { ( $id, $gen ) = @{ $self->{'reservations'}{$name} }; delete $self->{'reservations'}{$name}; } elsif ( defined $type && defined $self->{'reservations'}{$type} ) { ( $id, $gen ) = @{ $self->{'reservations'}{$type} }; delete $self->{'reservations'}{$type}; } else { $id = ++$self->{'object_number'}; $gen = $self->{'generation_number'}; } debug( 3, "indirect_obj(): " . $self->position ); push @{ $self->{'crossrefsubsection'}{$gen} }, [ $id, $self->position, 1 ]; [ 'object', [ $id, $gen, @_ ] ]; } sub indirect_ref { my $self = shift; [ 'ref', [@_] ]; } sub stream { my $self = shift; [ 'stream', {@_} ]; } sub add_info { my $self = shift; debug( 2, "add_info():" ); my %params = @_; $params{'Author'} = $self->{'Author'} if defined $self->{'Author'}; $params{'Creator'} = $self->{'Creator'} if defined $self->{'Creator'}; $params{'Title'} = $self->{'Title'} if defined $self->{'Title'}; $params{'Subject'} = $self->{'Subject'} if defined $self->{'Subject'}; $params{'Keywords'} = $self->{'Keywords'} if defined $self->{'Keywords'}; $params{'CreationDate'} = $self->{'CreationDate'} if defined $self->{'CreationDate'}; $self->{'info'} = $self->reserve('Info'); my $content = { 'Producer' => $self->string("PDF::Create version $VERSION"), 'Type' => $self->name('Info') }; $$content{'Author'} = $self->string( $params{'Author'} ) if defined $params{'Author'}; $$content{'Creator'} = $self->string( $params{'Creator'} ) if defined $params{'Creator'}; $$content{'Title'} = $self->string( $params{'Title'} ) if defined $params{'Title'}; $$content{'Subject'} = $self->string( $params{'Subject'} ) if defined $params{'Subject'}; $$content{'Keywords'} = $self->string( $params{'Keywords'} ) if defined $params{'Keywords'}; $$content{'CreationDate'} = $self->string( $params{'CreationDate'} ) if defined $params{'CreationDate'}; $self->add_object( $self->indirect_obj( $self->dictionary(%$content) ), 'Info' ); $self->cr; } # Catalog specification. sub add_catalog { my $self = shift; debug( 2, "add_catalog" ); my %params = %{ $self->{'catalog'} }; # Type (mandatory) $self->{'catalog'} = $self->reserve('Catalog'); my $content = { 'Type' => $self->name('Catalog') }; # Pages (mandatory) [indirected reference] my $pages = $self->reserve('Pages'); $$content{'Pages'} = $self->indirect_ref(@$pages); $self->{'pages'}{'id'} = $$content{'Pages'}[1]; # Outlines [indirected reference] $$content{'Outlines'} = $self->indirect_ref( @{ $self->{'outlines'}->{'id'} } ) if defined $self->{'outlines'}; # PageMode $$content{'PageMode'} = $self->name( $params{'PageMode'} ) if defined $params{'PageMode'}; $self->add_object( $self->indirect_obj( $self->dictionary(%$content) ) ); $self->cr; } sub add_outlines { my $self = shift; debug( 2, "add_outlines" ); my %params = @_; my $outlines = $self->reserve("Outlines"); my ( $First, $Last ); my @list = $self->{'outlines'}->list; my $i = -1; for my $outline (@list) { $i++; my $name = $outline->{'name'}; $First = $outline->{'id'} unless defined $First; $Last = $outline->{'id'}; my $content = { 'Title' => $self->string( $outline->{'Title'} ) }; if ( defined $outline->{'Kids'} && scalar @{ $outline->{'Kids'} } ) { my $t = $outline->{'Kids'}; $$content{'First'} = $self->indirect_ref( @{ $$t[0]->{'id'} } ); $$content{'Last'} = $self->indirect_ref( @{ $$t[$#$t]->{'id'} } ); } my $brothers = $outline->{'Parent'}->{'Kids'}; my $j = -1; for my $brother (@$brothers) { $j++; last if $brother == $outline; } $$content{'Next'} = $self->indirect_ref( @{ $$brothers[ $j + 1 ]->{'id'} } ) if $j < $#$brothers; $$content{'Prev'} = $self->indirect_ref( @{ $$brothers[ $j - 1 ]->{'id'} } ) if $j; $outline->{'Parent'}->{'id'} = $outlines unless defined $outline->{'Parent'}->{'id'}; $$content{'Parent'} = $self->indirect_ref( @{ $outline->{'Parent'}->{'id'} } ); $$content{'Dest'} = $self->array( $self->indirect_ref( @{ $outline->{'Dest'}->{'id'} } ), $self->name('Fit'), $self->null, $self->null, $self->null ); my $count = $outline->count; $$content{'Count'} = $self->number($count) if $count; my $t = $self->add_object( $self->indirect_obj( $self->dictionary(%$content), $name ) ); $self->cr; } # Type (required) my $content = { 'Type' => $self->name('Outlines') }; # Count my $count = $self->{'outlines'}->count; $$content{'Count'} = $self->number($count) if $count; $$content{'First'} = $self->indirect_ref(@$First); $$content{'Last'} = $self->indirect_ref(@$Last); $self->add_object( $self->indirect_obj( $self->dictionary(%$content) ) ); $self->cr; } sub new_outline { my $self = shift; my %params = @_; unless ( defined $self->{'outlines'} ) { $self->{'outlines'} = PDF::Create::Outline->new(); $self->{'outlines'}->{'pdf'} = $self; # circular reference $self->{'outlines'}->{'Status'} = 'opened'; } my $parent = $params{'Parent'} || $self->{'outlines'}; my $name = "Outline " . ++$self->{'outline_count'}; $params{'Destination'} = $self->{'current_page'} unless defined $params{'Destination'}; my $outline = $parent->add( $self->reserve( $name, "Outline" ), $name, %params ); $outline; } sub get_page_size { my $self = shift; my $name = lc(shift); my %pagesizes = ( 'A0' => [ 0, 0, 2380, 3368 ], 'A1' => [ 0, 0, 1684, 2380 ], 'A2' => [ 0, 0, 1190, 1684 ], 'A3' => [ 0, 0, 842, 1190 ], 'A4' => [ 0, 0, 595, 842 ], 'A4L' => [ 0, 0, 842, 595 ], 'A5' => [ 0, 0, 421, 595 ], 'A6' => [ 0, 0, 297, 421 ], 'LETTER' => [ 0, 0, 612, 792 ], 'BROADSHEET' => [ 0, 0, 1296, 1584 ], 'LEDGER' => [ 0, 0, 1224, 792 ], 'TABLOID' => [ 0, 0, 792, 1224 ], 'LEGAL' => [ 0, 0, 612, 1008 ], 'EXECUTIVE' => [ 0, 0, 522, 756 ], '36X36' => [ 0, 0, 2592, 2592 ], ); if ( !$pagesizes{ uc($name) } ) { $name = "A4"; } $pagesizes{ uc($name) }; } sub new_page { my $self = shift; my %params = @_; my $parent = $params{'Parent'} || $self->{'pages'}; my $name = "Page " . ++$self->{'page_count'}; my $page = $parent->add( $self->reserve( $name, "Page" ), $name ); $page->{'resources'} = $params{'Resources'} if defined $params{'Resources'}; $page->{'mediabox'} = $params{'MediaBox'} if defined $params{'MediaBox'}; $page->{'cropbox'} = $params{'CropBox'} if defined $params{'CropBox'}; $page->{'artbox'} = $params{'ArtBox'} if defined $params{'ArtBox'}; $page->{'trimbox'} = $params{'TrimBox'} if defined $params{'TrimBox'}; $page->{'bleedbox'} = $params{'BleedBox'} if defined $params{'BleedBox'}; $page->{'rotate'} = $params{'Rotate'} if defined $params{'Rotate'}; $self->{'current_page'} = $page; $page; } sub add_pages { my $self = shift; debug( 2, "add_pages():" ); # $self->page_stream; my %params = @_; # Type (required) my $content = { 'Type' => $self->name('Pages') }; # Kids (required) my $t = $self->{'pages'}->kids; confess "Error: document MUST contains at least one page. Abort." unless scalar @$t; my $kids = []; map { push @$kids, $self->indirect_ref(@$_) } @$t; $$content{'Kids'} = $self->array(@$kids); $$content{'Count'} = $self->number( $self->{'pages'}->count ); $self->add_object( $self->indirect_obj( $self->dictionary(%$content) ) ); $self->cr; for my $font ( sort keys %{ $self->{'fonts'} } ) { debug( 2, "add_pages(): font: $font" ); $self->{'fontobj'}{$font} = $self->reserve('Font'); $self->add_object( $self->indirect_obj( $self->dictionary( %{ $self->{'fonts'}{$font} } ), 'Font' ) ); $self->cr; } for my $xobject ( sort keys %{ $self->{'xobjects'} } ) { debug( 2, "add_pages(): xobject: $xobject" ); $self->{'xobj'}{$xobject} = $self->reserve('XObject'); $self->add_object( $self->indirect_obj( $self->stream( %{ $self->{'xobjects'}{$xobject} } ), 'XObject' ) ); $self->cr; if ( defined $self->{'reservations'}{"ImageColorSpace$xobject"} ) { $self->add_object( $self->indirect_obj( $self->stream( %{ $self->{'xobjects_colorspace'}{$xobject} } ), "ImageColorSpace$xobject" ) ); $self->cr; } } for my $annotation ( sort keys %{ $self->{'annotations'} } ) { $self->{'annot'}{$annotation}{'object_info'} = $self->reserve('Annotation'); $self->add_object( $self->indirect_obj( $self->dictionary( %{ $self->{'annotations'}{$annotation} } ), 'Annotation' ) ); $self->cr; } for my $page ( $self->{'pages'}->list ) { my $name = $page->{'name'}; debug( 2, "add_pages: page: $name" ); my $type = 'Page' . ( defined $page->{'Kids'} && scalar @{ $page->{'Kids'} } ? 's' : '' ); # Type (required) my $content = { 'Type' => $self->name($type) }; # Resources (required, may be inherited). See page 195. my $resources = {}; for my $k ( keys %{ $page->{'resources'} } ) { my $v = $page->{'resources'}{$k}; ( $k eq 'ProcSet' ) && do { my $l = []; if ( ref($v) eq 'ARRAY' ) { map { push @$l, $self->name($_) } @$v; } else { push @$l, $self->name($v); } $$resources{'ProcSet'} = $self->array(@$l); } || ( $k eq 'fonts' ) && do { my $l = {}; map { $$l{"F$_"} = $self->indirect_ref( @{ $self->{'fontobj'}{$_} } ); } keys %{ $page->{'resources'}{'fonts'} }; $$resources{'Font'} = $self->dictionary(%$l); } || ( $k eq 'xobjects' ) && do { my $l = {}; map { $$l{"Image$_"} = $self->indirect_ref( @{ $self->{'xobj'}{$_} } ); } keys %{ $page->{'resources'}{'xobjects'} }; $$resources{'XObject'} = $self->dictionary(%$l); }; } if ( defined( $$resources{'Annotation'} ) ) { my $r = $self->add_object( $self->indirect_obj( $self->dictionary(%$resources) ) ); $self->cr; $$content{'Resources'} = [ 'ref', [ $$r[0], $$r[1] ] ]; } if ( defined( $$resources{'XObject'} ) ) { my $r = $self->add_object( $self->indirect_obj( $self->dictionary(%$resources) ) ); $self->cr; $$content{'Resources'} = [ 'ref', [ $$r[0], $$r[1] ] ]; } else { $$content{'Resources'} = $self->dictionary(%$resources) if scalar keys %$resources; } for my $K ( 'MediaBox', 'CropBox', 'ArtBox', 'TrimBox', 'BleedBox' ) { my $k = lc $K; if ( defined $page->{$k} ) { my $l = []; map { push @$l, $self->number($_) } @{ $page->{$k} }; $$content{$K} = $self->array(@$l); } } $$content{'Rotate'} = $self->number( $page->{'rotate'} ) if defined $page->{'rotate'}; if ( $type eq 'Page' ) { $$content{'Parent'} = $self->indirect_ref( @{ $page->{'Parent'}{'id'} } ); # Content if ( defined $page->{'contents'} ) { my $contents = []; map { push @$contents, $self->indirect_ref(@$_); } @{ $page->{'contents'} }; $$content{'Contents'} = $self->array(@$contents); } # # Annotations added here by Gary Lieberman # # Tell the /Page object that annotations need to be drawn. # if ( defined $self->{'annot'} ) { my $Annots = '[ '; my $is_annots = 0; foreach my $annot_number ( keys %{ $self->{'annot'} } ) { next if ( $self->{'annot'}{$annot_number}{'page_name'} ne $name ); $is_annots = 1; debug( 2, sprintf "annotation number: $annot_number, page name: $self->{'annot'}{$annot_number}{'page_name'}" ); my $object_number = $self->{'annot'}{$annot_number}{'object_info'}[0]; my $generation_number = $self->{'annot'}{$annot_number}{'object_info'}[1]; debug( 2, sprintf "object_number: $object_number, generation_number: $generation_number" ); $Annots .= sprintf( "%s %s R ", $object_number, $generation_number ); } $$content{'Annots'} = $self->verbatim( $Annots . ']' ) if ($is_annots); } # # Annotations code ends here # } else { my $kids = []; map { push @$kids, $self->indirect_ref(@$_) } @{ $page->kids }; $$content{'Kids'} = $self->array(@$kids); $$content{'Parent'} = $self->indirect_ref( @{ $page->{'Parent'}{'id'} } ) if defined $page->{'Parent'}; $$content{'Count'} = $self->number( $page->count ); } $self->add_object( $self->indirect_obj( $self->dictionary(%$content), $name ) ); $self->cr; } } sub add_crossrefsection { my $self = shift; debug( 2, "add_crossrefsection():" ); # ::= # xref # + $self->{'crossrefstartpoint'} = $self->position; $self->add('xref'); $self->cr; confess "Fatal error: should contains at least one cross reference subsection." unless defined $self->{'crossrefsubsection'}; for my $subsection ( sort keys %{ $self->{'crossrefsubsection'} } ) { $self->add_crossrefsubsection($subsection); } } sub add_crossrefsubsection { my $self = shift; my $subsection = shift; debug( 2, "add_crossrefsubsection():" ); # ::= # # # + # # ::= | # # ::= n # # ::= # | # | # # ::= # # f $self->add( 0, ' ', 1 + scalar @{ $self->{'crossrefsubsection'}{$subsection} } ); $self->cr; $self->add( sprintf "%010d %05d %s ", 0, 65535, 'f' ); $self->cr; for my $entry ( sort { $$a[0] <=> $$b[0] } @{ $self->{'crossrefsubsection'}{$subsection} } ) { $self->add( sprintf "%010d %05d %s ", $$entry[1], $subsection, $$entry[2] ? 'n' : 'f' ); # printf "%010d %010x %05d n\n", $$entry[1], $$entry[1], $subsection; $self->cr; } } sub add_trailer { my $self = shift; debug( 2, "add_trailer():" ); # ::= trailer # << # + # >> # startxref # # %%EOF my @keys = ( 'Size', # integer (required) 'Prev', # integer (req only if more than one cross-ref section) 'Root', # dictionary (required) 'Info', # dictionary (optional) 'ID', # array (optional) (PDF 1.1) 'Encrypt' # dictionary (req if encrypted) (PDF 1.1) ); # TODO: should check for required fields $self->add('trailer'); $self->cr; $self->add('<<'); $self->cr; $self->{'trailer'}{'Size'} = 1; map { $self->{'trailer'}{'Size'} += scalar @{ $self->{'crossrefsubsection'}{$_} } } keys %{ $self->{'crossrefsubsection'} }; $self->{'trailer'}{'Root'} = &encode( @{ $self->indirect_ref( @{ $self->{'catalog'} } ) } ); $self->{'trailer'}{'Info'} = &encode( @{ $self->indirect_ref( @{ $self->{'info'} } ) } ) if defined $self->{'info'}; for my $k (@keys) { next unless defined $self->{'trailer'}{$k}; $self->add( "/$k ", ref $self->{'trailer'}{$k} eq 'ARRAY' ? join( ' ', @{ $self->{'trailer'}{$k} } ) : $self->{'trailer'}{$k} ); $self->cr; } $self->add('>>'); $self->cr; $self->add('startxref'); $self->cr; $self->add( $self->{'crossrefstartpoint'} ); $self->cr; $self->add('%%EOF'); $self->cr; } sub cr { my $self = shift; debug( 3, "cr():" ); $self->add( &encode('cr') ); } sub page_stream { my $self = shift; my $page = shift; debug( 2, "page_stream():" ); if ( defined $self->{'reservations'}{'stream_length'} ) { ## If it is the same page, use the same stream. $self->cr, return if defined $page && defined $self->{'stream_page'} && $page == $self->{'current_page'} && $self->{'stream_page'} == $page; # Remember the position my $len = $self->position - $self->{'stream_pos'} + 1; # Close the stream and the object $self->cr; $self->add('endstream'); $self->cr; $self->add('endobj'); $self->cr; $self->cr; # Add the length $self->add_object( $self->indirect_obj( $self->number($len), 'stream_length' ) ); $self->cr; } # open a new stream if needed if ( defined $page ) { # get an object id for the stream my $obj = $self->reserve('stream'); # release it delete $self->{'reservations'}{'stream'}; # get another one for the length of this stream my $stream_length = $self->reserve('stream_length'); push @$stream_length, 'R'; push @{ $page->{'contents'} }, $obj; # write the beginning of the object push @{ $self->{'crossrefsubsection'}{ $$obj[1] } }, [ $$obj[0], $self->position, 1 ]; $self->add("$$obj[0] $$obj[1] obj"); $self->cr; $self->add('<<'); $self->cr; $self->add( '/Length ', join( ' ', @$stream_length ) ); $self->cr; $self->add('>>'); $self->cr; $self->add('stream'); $self->cr; $self->{'stream_pos'} = $self->position; $self->{'stream_page'} = $page; # $self->{'current_page'}; } } sub font { my $self = shift; my %params = @_; my $num = 1 + scalar keys %{ $self->{'fonts'} }; $self->{'fonts'}{$num} = { 'Subtype' => $self->name( $params{'Subtype'} || 'Type1' ), 'Encoding' => $self->name( $params{'Encoding'} || 'WinAnsiEncoding' ), 'BaseFont' => $self->name( $params{'BaseFont'} || 'Helvetica' ), 'Name' => $self->name("F$num"), 'Type' => $self->name("Font"), }; $num; } # # Add an annotation object # # for the time beeing we only do the 'Link' - 'URI' kind # sub annotation { my $self = shift; my %params = @_; debug( 2, "annotation(): Subtype=$params{'Subtype'}" ); if ( $params{'Subtype'} eq 'Link' ) { confess "Must specify 'URI' for Link" unless defined $params{'URI'}; confess "Must specify 'x' for Link" unless defined $params{'x'}; confess "Must specify 'y' for Link" unless defined $params{'y'}; confess "Must specify 'w' for Link" unless defined $params{'w'}; confess "Must specify 'h' for Link" unless defined $params{'h'}; my $num = 1 + scalar keys %{ $self->{'annotations'} }; my $action = { 'Type' => $self->name('Action'), 'S' => $self->name('URI'), 'URI' => $self->string( $params{'URI'} ), }; my $x2 = $params{'x'} + $params{'w'}; my $y2 = $params{'y'} + $params{'h'}; $self->{'annotations'}{$num} = { 'Subtype' => $self->name('Link'), 'Rect' => $self->verbatim( sprintf "[%f %f %f %f]", $params{'x'}, $params{'y'}, $x2, $y2 ), 'A' => $self->dictionary(%$action), }; if ( defined $params{'Border'} ) { $self->{'annotations'}{$num}{'Border'} = $self->verbatim( sprintf "[%f %f %f]", $params{'Border'}[0], $params{'Border'}[1], $params{'Border'}[2] ); } $self->{'annot'}{$num}{'page_name'} = "Page " . $self->{'page_count'}; debug( 2, "annotation(): annotation number: $num, page name: $self->{'annot'}{$num}{'page_name'}" ); 1; } else { confess "Only Annotations with Subtype 'Link' are supported for now\n"; } } sub image { my $self = shift; my $filename = shift; my $num = 1 + scalar keys %{ $self->{'xobjects'} }; my $image; my $colorspace; my @a; if ( $filename =~ /\.gif$/i ) { $self->{'images'}{$num} = PDF::Image::GIF->new(); } elsif ( $filename =~ /\.jpg$/i || $filename =~ /\.jpeg$/i ) { $self->{'images'}{$num} = PDF::Image::JPEG->new(); } $image = $self->{'images'}{$num}; if ( !$image->Open($filename) ) { print $image->{error} . "\n"; return 0; } $self->{'xobjects'}{$num} = { 'Subtype' => $self->name('Image'), 'Name' => $self->name("Image$num"), 'Type' => $self->name('XObject'), 'Width' => $self->number( $image->{width} ), 'Height' => $self->number( $image->{height} ), 'BitsPerComponent' => $self->number( $image->{bpc} ), 'Data' => $image->ReadData(), 'Length' => $self->number( $image->{imagesize} ), }; #indexed colorspace ? if ( $image->{colorspacesize} ) { $colorspace = $self->reserve("ImageColorSpace$num"); $self->{'xobjects_colorspace'}{$num} = { 'Data' => $image->{colorspacedata}, 'Length' => $self->number( $image->{colorspacesize} ), }; $self->{'xobjects'}{$num}->{'ColorSpace'} = $self->array( $self->name('Indexed'), $self->name( $image->{colorspace} ), $self->number(255), $self->indirect_ref(@$colorspace) ); } else { $self->{'xobjects'}{$num}->{'ColorSpace'} = $self->array( $self->name( $image->{colorspace} ) ); } #set Filter $#a = -1; foreach my $s ( @{ $image->{filter} } ) { push @a, $self->name($s); } if ( $#a >= 0 ) { $self->{'xobjects'}{$num}->{'Filter'} = $self->array(@a); } #set additional DecodeParms $#a = -1; foreach my $s ( keys %{ $image->{decodeparms} } ) { push @a, $s; push @a, $self->number( $image->{decodeparms}{$s} ); } $self->{'xobjects'}{$num}->{'DecodeParms'} = $self->array( $self->dictionary(@a) ); #transparent ? if ( $image->{transparent} ) { $self->{'xobjects'}{$num}->{'Mask'} = $self->array( $self->number( $image->{mask} ), $self->number( $image->{mask} ) ); } { 'num' => $num, 'width' => $image->{width}, 'height' => $image->{height} }; } sub uses_font { my $self = shift; my $page = shift; my $font = shift; $page->{'resources'}{'fonts'}{$font} = 1; $page->{'resources'}{'ProcSet'} = [ 'PDF', 'Text' ]; $self->{'fontobj'}{$font} = 1; } sub uses_xobject { my $self = shift; my $page = shift; my $xobject = shift; $page->{'resources'}{'xobjects'}{$xobject} = 1; $page->{'resources'}{'ProcSet'} = [ 'PDF', 'Text' ]; $self->{'xobj'}{$xobject} = 1; } sub get_data { shift->{'data'}; } 1; __END__ =encoding utf8 =head1 NAME PDF::Create - create PDF files =head1 SYNOPSIS C provides an easy module to create PDF output from your perl programs. It is designed to be easy to use and simple to install and maintain. It provides a couple of subroutines to handle text, fonts, images and drawing primitives. Simple documents are easy to create with the supplied routines. In addition to be reasonable simple C is written in pure Perl and has no external dependencies (libraries, other modules, etc.). It should run on any platform where perl is available. For complex stuff some understanding of the underlying Postscript/PDF format is necessary. In this case it might be better go with the more complete L modules to gain more features at the expense of a steeper learning curve. Example PDF creation with C: use PDF::Create; # initialize PDF my $pdf = PDF::Create->new('filename' => 'mypdf.pdf', 'Author' => 'John Doe', 'Title' => 'Sample PDF', 'CreationDate' => [ localtime ], ); # add a A4 sized page my $a4 = $pdf->new_page('MediaBox' => $pdf->get_page_size('A4')); # Add a page which inherits its attributes from $a4 my $page = $a4->new_page; # Prepare a font my $f1 = $pdf->font('BaseFont' => 'Helvetica'); # Prepare a Table of Content my $toc = $pdf->new_outline('Title' => 'Title Page', 'Destination' => $page); # Write some text $page->stringc($f1, 40, 306, 426, "PDF::Create"); $page->stringc($f1, 20, 306, 396, "version $PDF::Create::VERSION"); $page->stringc($f1, 20, 306, 300, 'by John Doe '); # Add another page my $page2 = $a4->new_page; # Draw some lines $page2->line(0, 0, 612, 792); $page2->line(0, 792, 612, 0); $toc->new_outline('Title' => 'Second Page', 'Destination' => $page2); # Close the file and write the PDF $pdf->close; =head1 DESCRIPTION PDF::Create allows you to create PDF documents using a number of primitives. The result is as a PDF file or stream. PDF stands for Portable Document Format. Documents can have several pages, a table of content, an information section and many other PDF elements. =head1 Methods =over 5 =item * new([parameters]) Create a new pdf structure for your PDF. Example: my $pdf = PDF::Create->new('filename' => 'mypdf.pdf', 'Version' => 1.2, 'PageMode' => 'UseOutlines', 'Author' => 'John Doe', 'Title' => 'My title', 'CreationDate' => [ localtime ], ); C returns an object handle used to add more stuff to the PDF. =over 10 =item 'filename' destination file that will contain the resulting PDF or '-' for stdout. =item 'fh' an already opened filehandle that will contain the resulting PDF. =item 'Version' PDF Version to claim, can be 1.0 to 1.3 (default: 1.2) =item 'PageMode' how the document should appear when opened. Allowed values are - 'UseNone' Open document with neither outline nor thumbnails visible. This is the default value. - 'UseOutlines' Open document with outline visible. - 'UseThumbs' Open document with thumbnails visible. - 'FullScreen' Open document in full-screen mode. In full-screen mode, there is no menu bar, window controls, nor any other window present. =item 'Author' the name of the person who created this document =item 'Creator' If the document was converted into a PDF document from another form, this is the name of the application that created the document. - 'Title' the title of the document - 'Subject' the subject of the document - 'Keywords' keywords associated with the document - 'CreationDate' the date the document was created. This is passed as an anonymous array in the same format as localtime returns. (ie. a struct tm). =back If you are writing a CGI you can send your PDF on the fly to stdout or directly to the browser using '-' as filename. CGI Example: use CGI; use PDF::Create; print CGI::header( -type => 'application/x-pdf', -attachment => 'sample.pdf' ); my $pdf = PDF::Create->new('filename' => '-', # Stdout 'Author' => 'John Doe', 'Title' => 'My title', 'CreationDate' => [ localtime ], ); =item * close() You must call close() after you have added all the contents as most of the real work building the PDF is performed there. If omit calling close you get no PDF output ! =item * get_data() If you didn't ask the $pdf object to write its output to a file, you can pick up the pdf code by calling this method. It returns a big string. You need to call C first, mind. =item * add_comment([string]) Add a comment to the document. The string will show up in the PDF as postscript-stype comment: % this is a postscript comment =item * new_outline([parameters]) Add an outline to the document using the given parameters. Return the newly created outline. Parameters can be: - 'Title' the title of the outline. Mandatory. - 'Destination' the Destination of this outline item. In this version, it is only possible to give a page as destination. The default destination is the current page. - 'Parent' the parent of this outline in the outlines tree. This is an outline object. This way you represent the tree of your outlines. Example: my $outline = $pdf->new_outline('Title' => 'Item 1'); $pdf->new_outline('Title' => 'Item 1.1', 'Parent' => $outline); $pdf->new_outline('Title' => 'Item 1.2', 'Parent' => $outline); $pdf->new_outline('Title' => 'Item 2'); =item * new_page([parameters]) Add a page to the document using the given parameters. C must be called first to initialize a root page, used as model for further pages. Example: my $a4 = $pdf->new_page( 'MediaBox' => $pdf->get_page_size('A4') ); my $page1 = $a4->new_page; $page1->string($f1, 20, 306, 396, "some text on page 1"); my $page2 = $a4->new_page; $page2->string($f1, 20, 306, 396, "some text on page 2"); Returns a handle to the newly created page. Parameters can be: - 'Parent' the parent of this page in the pages tree. This is a page object. - 'Resources' Resources required by this page. - 'MediaBox' Rectangle specifying the natural size of the page, for example the dimensions of an A4 sheet of paper. The coordinates are measured in default user space units. It must be the reference of a 4 values array. You can use C to get the size of standard paper sizes. C knows about A0-A6, A4L (landscape), Letter, Legal, Broadsheet, Ledger, Tabloid, Executive and 36x36. - 'CropBox' Rectangle specifying the default clipping region for the page when displayed or printed. The default is the value of the MediaBox. - 'ArtBox' Rectangle specifying an area of the page to be used when placing PDF content into another application. The default is the value of the CropBox. [PDF 1.3] - 'TrimBox' Rectangle specifying the intended finished size of the page (for example, the dimensions of an A4 sheet of paper). In some cases, the MediaBox will be a larger rectangle, which includes printing instructions, cut marks, or other content. The default is the value of the CropBox. [PDF 1.3]. - 'BleedBox' Rectangle specifying the region to which all page content should be clipped if the page is being output in a production environment. In such environments, a bleed area is desired, to accommodate physical limitations of cutting, folding, and trimming equipment. The actual printed page may include printer's marks that fall outside the bleed box. The default is the value of the CropBox. [PDF 1.3] - 'Rotate' Specifies the number of degrees the page should be rotated clockwise when it is displayed or printed. This value must be zero (the default) or a multiple of 90. The entire page, including contents is rotated. =item * get_page_size() Returns the size of standard paper sizes to use for MediaBox-parameter of C. C has one required parameter to specify the paper name. Possible values are a0-a6, letter, broadsheet, ledger, tabloid, legal, executive and 36x36. Default is a4. my $root = $pdf->new_page( 'MediaBox' => $pdf->get_page_size('A4') ); =item * font([parameters]) Prepare a font using the given arguments. This font will be added to the document only if it is used at least once before the close method is called. my $f1 = $pdf->font('BaseFont' => 'Helvetica'); Parameters can be: - 'Subtype' Type of font. PDF defines some types of fonts. It must be one of the predefined type Type1, Type3, TrueType or Type0. In this version, only Type1 is supported. This is the default value. - 'Encoding' Specifies the encoding from which the new encoding differs. It must be one of the predefined encodings MacRomanEncoding, MacExpertEncoding or WinAnsiEncoding. In this version, only WinAnsiEncoding is supported. This is the default value. - 'BaseFont' The PostScript name of the font. It can be one of the following base fonts: Courier, Courier-Bold, Courier-BoldOblique, Courier-Oblique, Helvetica, Helvetica-Bold, Helvetica-BoldOblique, Helvetica-Oblique, Times-Roman, Times-Bold, Times-Italic or Times-BoldItalic. The Symbol or ZapfDingbats fonts are not supported in this version. The default font is Helvetica. =item * image() Prepare an XObject (image) using the given arguments. This image will be added to the document if it is referenced at least once before the close method is called. In this version GIF, interlaced GIF and JPEG is supported. Usage of interlaced GIFs are slower because they are decompressed, modified and compressed again. The gif support is limited to images with a LZW minimum code size of 8. Small images with few colors can have a smaller minimum code size and will not work. Parameters: - filename: file name of image (required). =back =head2 URI links URI links have two components, the text or graphics object and the area where the mouseclick should occur. For the object to be clicked on you'll use standard text of drawing methods. To define the click-sensitive area and the destination URI you use the C method. =over 5 =item * annotation([parameters]) Define an annotation. This is a sensitive area in the PDF document where text annotations are shown or links launched. C only supports URI links at this time. Example: # Draw a string and undeline it to show it is a link $pdf->string($f1,10,450,200,'http://www.cpan.org') $l=$pdf->string_underline($f1,10,450,200,'http://www.cpan.org') # Create the hot area with the link to open on click $pdf->annotation( Subtype => 'Link', URI => 'http://www.cpan.org', x => 450, y => 200, w => $l, h => 15, Border => [0,0,0] ); The point (x, y) is the bottom left corner of the rectangle containing hotspot rectangle, (w, h) are the width and height of the hotspot rectangle. The Border describes the thickness of the border surrounding the rectangle hotspot. The function C returns the width of the string, this can be used directly for the width of the hotspot rectangle. =back =head2 Page methods Page methods are used to draw stuff on a page. Although these methods are packaged in the separate module C you should call them always through the $page handler you get from the C method. There are internal changes on the horizon who will break code calling methods differently ! =over 5 =item * new_page() Add a sub-page to the current page. See C above =item * string(font, size, x, y, text [,alignment] ) Add text to the current page using the font object at the given size and position. The point (x, y) is the bottom left corner of the rectangle containing the text. The optional alignment can be 'r' for right-alignment and 'c' for centered. Example : my $f1 = $pdf->font('Subtype' => 'Type1', 'Encoding' => 'WinAnsiEncoding', 'BaseFont' => 'Helvetica'); $page->string($f1, 20, 306, 396, "some text"); =item * string_underline(font, size, x, y, text [,alignment] ) Draw a line for underlining. The parameters are the same as for the string function, but only the line is drawn. To draw an underlined string you must call both, string and string_underline. Example : $page->string($f1, 20, 306, 396, "some underlined text"); $page->string_underline($f1, 20, 306, 396, "some underlined text"); To change the color of your text use the C function. C returns the length of the string. So its return value can be used directly for the bounding box of an annotation. =item * stringl(font size x y text) Same as C. =item * stringr(font size x y text) Same as C but right aligned (alignment 'r'). =item * stringc(font size x y text) Same as C but centered (alignment 'c'). =item * printnl(text font size x y) Similar to C but parses the string for newline and prints each part on a separate line. Lines spacing is the same as the font-size. Returns the number of lines. Note the different parameter sequence. The first call should specify all parameters, font is the absolute minimum, a warning will be given for the missing y position and 800 will be assumed. All subsequent invocations can omit all but the string parameters. Attention: There is no provision for changing pages. If you run out of space on the current page this will draw the string(s) outside the page and it will be invisble ! =item * string_width(font,text) Return the size of the text using the given font in default user space units. This does not contain the size of the font yet, to get the length you must multiply by the font size. =item * line(x1, y1, x2, y2) Draw a line between (x1, y1) and (x2, y2). =item * set_width(w) Set the width of subsequent lines to C points. =item * setrgbcolor(r, g, b) =item * setrgbcolorstroke(r, g, b) Set the color of the subsequent drawing operations. Each color ranges from 0.0 to 1.0, that is, darkest red (0.0) to brightest red (1.0). The same holds for green and blue. These three colors mix additively to produce the colors between black (0.0, 0.0, 0.0) and white (1.0, 1.0, 1.0). PDF distinguishes between the stroke and fill operations and provides separate color settings for each. - C sets the fill colors used for normal text or filled objects. - C sets the stroke color used for lines. =item * moveto(x, y) Moves the current point to (x, y), omitting any connecting line segment. =item * lineto(x, y) Appends a straight line segment from the current point to (x, y). The current point is then set to (x, y). =item * curveto(x1, y1, x2, y2, x3, y3) Appends a Bezier curve to the path. The curve extends from the current point to (x3 ,y3) using (x1 ,y1) and (x2 ,y2) as the Bezier control points. The new current point is the set to (x3 ,y3). =item * rectangle(x, y, w, h) Draws a rectangle. =item * closepath() Closes the current subpath by appending a straight line segment from the current point to the starting point of the path. =item * newpath() Ends the current path. The next drawing operation will start a new path. =item * stroke() Strokes (draws) the path. =item * closestroke() Closes and strokes the path. =item * fill() Fills the path using the non-zero winding number rule. =item * fill2() Fills the path using the even-odd rule Example drawing: # draw a filled triangle $page->newpath; $page->setrgbcolor 0.1 0.3 0.8; $page->moveto 100 100; $page->lineto 260 300; $page->lineto 300 100; $page->lineto 100 100; $page->fill; =item * image( image_id, xpos, ypos, xalign, yalign, xscale, yscale, rotate, xskew, yskew) Inserts an image. Parameters can be: - image: Image id returned by PDF::image (required). - xpos, ypos: Position of image (required). - xalign, yalign: Alignment of image. 0 is left/bottom, 1 is centered and 2 is right, top. - xscale, yscale: Scaling of image. 1.0 is original size. - rotate: Rotation of image. 0 is no rotation, 2*pi is 360° rotation. - xskew, yskew: Skew of image. Example jpeg image: # include a jpeg image with scaling to 20% size my $jpg = $pdf->image("image.jpg"); $page->image( 'image' => $jpg, 'xscale' => 0.2, 'yscale' => 0.2, 'xpos' => 350, 'ypos' => 400 ); =back =head1 Limitations C comes with a couple of limitations or known caveats: =over 5 =item PDF Size / Memory C assembles the entire PDF in memory if you create very large documents on a machine with a small amount of memory your program can fail because it runs out of memory. =item Small GIF images Some gif images get created with a minimal lzw code size of less than 8. C can not decode those and they must be converted. =back =head1 Support I support C in my spare time between work and family, so the amount of work I put in is limited. If you experience a problem make sure you are at the latest version first many things have already been fixed. Please register bug at the CPAN bug tracking system at L or send email to C Be sure to include the following information: - PDF::Create Version you are running - Perl version (perl -v) - Operating System vendor and version - Details about your operating environment that might be related to the issue being described - Exact cut and pasted error or warning messages - The shortest, clearest code you can manage to write which reproduces the bug described. I appreciate patches against the latest released version of C which fix the bug. B can be submitted like bugs. If you provide patch for a feature which does not go against the C philosophy (keep it simple) then you have a good chance for it to be accepted. =head1 SEE ALSO Adobe PDF reference L My git repository for C L =head2 Other PDF procesing CPAN modules L Routines to produce formatted pages of mailing labels in PDF, uses PDF::Create internally L Perl interface to Haru Free PDF Library L PDF creation from a one-file module, similar to PDF::Create L Yet another PDF creation module L A wrapper written for PDF::API2 =head1 AUTHORS Fabien Tassin GIF and JPEG-support: Michael Gross (info@mdgrosse.net) Maintenance since 2007: Markus Baertschi (markus@markus.org) =head1 COPYRIGHT Copyright 1999-2001, Fabien Tassin. All rights reserved. It may be used and modified freely, but I do request that this copyright notice remain attached to the file. You may modify this module as you wish, but if you redistribute a modified version, please attach a note listing the modifications you have made. Copyright 2007-, Markus Baertschi Copyright 2010, Gary Lieberman =cut PDF-Create-1.08/lib/PDF/Image/000755 000765 000024 00000000000 12251772756 015730 5ustar00gaborstaff000000 000000 PDF-Create-1.08/lib/PDF/Image/GIF.pm000644 000765 000024 00000027322 12251772477 016701 0ustar00gaborstaff000000 000000 # # PDF::Image::GIF - GIF image support for PDF::Create # # Author: Michael Gross # # Copyright 1999-2001 Fabien Tassin # Copyright 2007- Markus Baertschi # # Please see the CHANGES and Changes file for the detailed change log # # Please do not use any of the methods here directly. You will be # punished with your application no longer working after an upgrade ! # package PDF::Image::GIF; use strict; use warnings; use FileHandle; our $VERSION = '1.08'; our $DEBUG = 0; sub new { my $self = {}; $self->{private} = {}; $self->{colorspace} = 0; $self->{width} = 0; $self->{height} = 0; $self->{colorspace} = "DeviceRGB"; $self->{colorspacedata} = ""; $self->{colorspacesize} = 0; $self->{filename} = ""; $self->{error} = ""; $self->{imagesize} = 0; $self->{transparent} = 0; $self->{filter} = ["LZWDecode"]; $self->{decodeparms} = { 'EarlyChange' => 0 }; $self->{private}->{interlaced} = 0; bless($self); return $self; } sub LZW { my $self = shift; my $data = shift; my $result = ""; my $prefix = ""; my $c; my %hash; my $num; my $codesize = 9; #init hash-table for ( $num = 0 ; $num < 256 ; $num++ ) { $hash{ chr($num) } = $num; } #start with a clear $num = 258; my $currentvalue = 256; my $bits = 9; my $pos = 0; while ( $pos < length($data) ) { $c = substr( $data, $pos, 1 ); if ( exists( $hash{ $prefix . $c } ) ) { $prefix .= $c; } else { #save $hash{$prefix} $currentvalue <<= $codesize; $currentvalue |= $hash{$prefix}; $bits += $codesize; while ( $bits >= 8 ) { $result .= chr( ( $currentvalue >> ( $bits - 8 ) ) & 255 ); $bits -= 8; $currentvalue &= ( 1 << $bits ) - 1; } $hash{ $prefix . $c } = $num; $prefix = $c; $num++; #increase code size? if ( $num == 513 || $num == 1025 || $num == 2049 ) { $codesize++; } #hash table overflow? if ( $num == 4097 ) { #save clear $currentvalue <<= $codesize; $currentvalue |= 256; $bits += $codesize; while ( $bits >= 8 ) { $result .= chr( ( $currentvalue >> ( $bits - 8 ) ) & 255 ); $bits -= 8; $currentvalue &= ( 1 << $bits ) - 1; } #reset hash table $codesize = 9; %hash = (); for ( $num = 0 ; $num < 256 ; $num++ ) { $hash{ chr($num) } = $num; } $num = 258; } } $pos++; } #save value for prefix $currentvalue <<= $codesize; $currentvalue |= $hash{$prefix}; $bits += $codesize; while ( $bits >= 8 ) { $result .= chr( ( $currentvalue >> ( $bits - 8 ) ) & 255 ); $bits -= 8; $currentvalue &= ( 1 << $bits ) - 1; } #save eoi $currentvalue <<= $codesize; $currentvalue |= 257; $bits += $codesize; while ( $bits >= 8 ) { $result .= chr( ( $currentvalue >> ( $bits - 8 ) ) & 255 ); $bits -= 8; $currentvalue &= ( 1 << $bits ) - 1; } #save remainder in $currentvalue if ( $bits > 0 ) { $currentvalue = $currentvalue << ( 8 - $bits ); $result .= chr( $currentvalue & 255 ); } $result; } sub UnLZW { my $self = shift; my $data = shift; my $result = ""; my $bits = 0; my $currentvalue = 0; my $codesize = 9; my $pos = 0; my $prefix = ""; my $suffix; my @table; #initialize lookup-table my $num; for ( $num = 0 ; $num < 256 ; $num++ ) { $table[$num] = chr($num); } $table[256] = ""; $num = 257; my $c1; #get first word while ( $bits < $codesize ) { my $d = ord( substr( $data, $pos, 1 ) ); $currentvalue = ( $currentvalue << 8 ) + $d; $bits += 8; $pos++; } my $c2 = $currentvalue >> ( $bits - $codesize ); $bits -= $codesize; my $mask = ( 1 << $bits ) - 1; $currentvalue = $currentvalue & $mask; DECOMPRESS: while ( $pos < length($data) ) { $c1 = $c2; #get next word while ( $bits < $codesize ) { my $d = ord( substr( $data, $pos, 1 ) ); $currentvalue = ( $currentvalue << 8 ) + $d; $bits += 8; $pos++; } $c2 = $currentvalue >> ( $bits - $codesize ); $bits -= $codesize; $mask = ( 1 << $bits ) - 1; $currentvalue = $currentvalue & $mask; #clear code? if ( $c2 == 256 ) { $result .= $table[$c1]; $#table = 256; $codesize = 9; $num = 257; next DECOMPRESS; } #End Of Image? if ( $c2 == 257 ) { last DECOMPRESS; } #get prefix if ( $c1 < $num ) { $prefix = $table[$c1]; } else { print "Compression Error ($c1>=$num)\n"; } #write prefix $result .= $prefix; #get suffix if ( $c2 < $num ) { $suffix = substr( $table[$c2], 0, 1 ); } elsif ( $c2 == $num ) { $suffix = substr( $prefix, 0, 1 ); } else { print "Compression Error ($c2>$num)\n"; } #new table entry is prefix.suffix $table[$num] = $prefix . $suffix; #next table entry $num++; #increase code size? if ( $num == 512 || $num == 1024 || $num == 2048 ) { $codesize++; } } $result .= $table[$c1]; $result; } sub UnInterlace { my $self = shift; my $data = shift; my $row; my @result; my $width = $self->{width}; my $height = $self->{height}; my $idx = 0; #Pass 1 - every 8th row, starting with row 0 $row = 0; while ( $row < $height ) { $result[$row] = substr( $data, $idx * $width, $width ); $row += 8; $idx++; } #Pass 2 - every 8th row, starting with row 4 $row = 4; while ( $row < $height ) { $result[$row] = substr( $data, $idx * $width, $width ); $row += 8; $idx++; } #Pass 3 - every 4th row, starting with row 2 $row = 2; while ( $row < $height ) { $result[$row] = substr( $data, $idx * $width, $width ); $row += 4; $idx++; } #Pass 4 - every 2th row, starting with row 1 $row = 1; while ( $row < $height ) { $result[$row] = substr( $data, $idx * $width, $width ); $row += 2; $idx++; } join( '', @result ); } sub GetDataBlock { my $self = shift; my $fh = shift; my $s; my $count; my $buf; read $fh, $s, 1; $count = unpack( "C", $s ); if ($count) { read $fh, $buf, $count; } ( $count, $buf ); } sub ReadColorMap { my $self = shift; my $fh = shift; read $fh, $self->{'colorspacedata'}, 3 * $self->{'colormapsize'}; 1; } sub DoExtension { my $self = shift; my $label = shift; my $fh = shift; my $res; my $buf; my $c; my $c2; my $c3; if ( $label eq "\001" ) { #Plain Text Extension } elsif ( ord($label) == 0xFF ) { #Application Extension } elsif ( ord($label) == 0xFE ) { #Comment Extension } elsif ( ord($label) == 0xF9 ) { #Grapgic Control Extension ( $res, $buf ) = $self->GetDataBlock($fh); #(p, image, (unsigned char*) buf); ( $c, $c2, $c2, $c3 ) = unpack( "CCCC", $buf ); if ( $c && 0x1 != 0 ) { $self->{transparent} = 1; $self->{mask} = $c3; } } BLOCK: while (1) { ( $res, $buf ) = $self->GetDataBlock($fh); if ( $res == 0 ) { last BLOCK; } } 1; } sub Open { my $self = shift; my $filename = shift; my $PDF_STRING_GIF = "\107\111\106"; my $PDF_STRING_87a = "\070\067\141"; my $PDF_STRING_89a = "\070\071\141"; my $LOCALCOLORMAP = 0x80; my $INTERLACE = 0x40; my $s; my $c; my $ar; my $flags; $self->{filename} = $filename; my $fh = FileHandle->new("$filename"); if ( !defined $fh ) { $self->{error} = "PDF::Image::GIF.pm: $filename: $!"; return 0 } binmode $fh; read $fh, $s, 3; if ( $s ne $PDF_STRING_GIF ) { close $fh; $self->{error} = "PDF::Image::GIF.pm: Not a gif file."; return 0; } read $fh, $s, 3; if ( $s ne $PDF_STRING_87a && $s ne $PDF_STRING_89a ) { close $fh; $self->{error} = "PDF::Image::GIF.pm: GIF version $s not supported."; return 0; } read $fh, $s, 7; ( $self->{width}, $self->{height}, $flags, $self->{private}->{background}, $ar ) = unpack( "vvCCC", $s ); $self->{colormapsize} = 2 << ( $flags & 0x07 ); $self->{colorspacesize} = 3 * $self->{colormapsize}; if ( $flags & $LOCALCOLORMAP ) { if ( !$self->ReadColorMap($fh) ) { close $fh; $self->{error} = "PDF::Image::GIF.pm: Cant read color map."; return 0; } } if ( $ar != 0 ) { $self->{private}->{dpi_x} = -( $ar + 15.0 ) / 64.0; $self->{private}->{dpi_y} = -1.0; } my $imageCount = 0; IMAGES: while (1) { read $fh, $c, 1; if ( $c eq ";" ) { #GIF file terminator close $fh; $self->{error} = "PDF::Image::GIF.pm: Cant find image in gif file."; return 0; } if ( $c eq "!" ) { #Extension read $fh, $c, 1; $self->DoExtension( $c, $fh ); next; } if ( $c ne "," ) { #must be comma next; #ignore } $imageCount++; read $fh, $s, 9; my $x; ( $x, $c, $self->{width}, $self->{height}, $flags ) = unpack( "vvvvC", $s ); if ( $flags && $INTERLACE ) { $self->{private}->{interlaced} = 1; } if ( $flags & $LOCALCOLORMAP ) { if ( !$self->ReadColorMap($fh) ) { close $fh; $self->{error} = "PDF::Image::GIF.pm: Cant read color map."; return 0; } } read $fh, $s, 1; #read "LZW initial code size" $self->{bpc} = unpack( "C", $s ); if ( $self->{bpc} != 8 ) { close $fh; $self->{error} = "PDF::Image::GIF.pm: LZW minimum code size is " . $self->{bpc} . ", must be 8 to be supported."; return 0; } if ( $imageCount == 1 ) { last IMAGES; } } $self->{private}->{datapos} = tell($fh); close $fh; 1; } sub ReadData { my $self = shift; # init the LZW transformation vars my $c_size = 9; # initial code size my $t_size = 257; # initial "table" size my $i_buff = 0; # input buffer my $i_bits = 0; # input buffer empty my $o_bits = 0; # output buffer empty my $o_buff = 0; my $c_mask; my $bytes_available = 0; my $n_bytes; my $s; my $c; my $flag13; my $code; my $w_bits; my $result = ""; my $fh = FileHandle->new($self->{filename}); if ( !defined $fh ) { $self->{error} = "PDF::Image::GIF.pm: $self->{filename}: $!"; return 0 } binmode $fh; seek( $fh, $self->{private}->{datapos}, 0 ); my $pos = 0; my $data; read $fh, $data, ( -s $self->{filename} ); use integer; $self->{imagesize} = 0; BLOCKS: while (1) { $s = substr( $data, $pos, 1 ); $pos++; $n_bytes = unpack( "C", $s ); if ( !$n_bytes ) { last BLOCKS; } $c_mask = ( 1 << $c_size ) - 1; $flag13 = 0; BLOCK: while (1) { $w_bits = $c_size; # number of bits to write $code = 0; #get at least c_size bits into i_buff while ( $i_bits < $c_size ) { if ( $n_bytes == 0 ) { last BLOCK; } $n_bytes--; $s = substr( $data, $pos, 1 ); $pos++; $c = unpack( "C", $s ); $i_buff |= $c << $i_bits; #EOF will be caught later $i_bits += 8; } $code = $i_buff & $c_mask; $i_bits -= $c_size; $i_buff >>= $c_size; if ( $flag13 && $code != 256 && $code != 257 ) { $self->{error} = "PDF::Image::GIF.pm: LZW code size overflow."; return 0; } if ( $o_bits > 0 ) { $o_buff |= $code >> ( $c_size - 8 + $o_bits ); $w_bits -= 8 - $o_bits; $result .= chr( $o_buff & 255 ); } if ( $w_bits >= 8 ) { $w_bits -= 8; $result .= chr( ( $code >> $w_bits ) & 255 ); } $o_bits = $w_bits; if ( $o_bits > 0 ) { $o_buff = $code << ( 8 - $o_bits ); } $t_size++; if ( $code == 256 ) { #clear code $c_size = 9; $c_mask = ( 1 << $c_size ) - 1; $t_size = 257; $flag13 = 0; } if ( $code == 257 ) { #end code last BLOCK; } if ( $t_size == ( 1 << $c_size ) ) { if ( ++$c_size > 12 ) { $c_size--; $flag13 = 1; } else { $c_mask = ( 1 << $c_size ) - 1; } } } # while () for block } # while () for all blocks #interlaced? if ( $self->{private}->{interlaced} ) { #when interlaced first uncompress image $result = $self->UnLZW($result); #remove interlacing $result = $self->UnInterlace($result); #compress image again $result = $self->LZW($result); } $self->{imagesize} = length($result); $result; } 1; PDF-Create-1.08/lib/PDF/Image/JPEG.pm000644 000765 000024 00000022110 12251772477 017007 0ustar00gaborstaff000000 000000 # # PDF::Image::JPEG - JPEG image support for PDF::Create # # Author: Michael Gross # # Copyright 1999-2001 Fabien Tassin # Copyright 2007- Markus Baertschi # # Please see the CHANGES and Changes file for the detailed change log # # Please do not use any of the methods here directly. You will be # punished with your application no longer working after an upgrade ! # package PDF::Image::JPEG; use strict; use warnings; use FileHandle; our $VERSION = '1.08'; our $DEBUG = 0; sub new { my $self = {}; $self->{private} = {}; $self->{width} = 0; $self->{height} = 0; $self->{colorspacedata} = ""; $self->{colorspace} = ""; $self->{colorspacesize} = 0; $self->{filename} = ""; $self->{error} = ""; $self->{imagesize} = 0; $self->{transparent} = 0; $self->{filter} = ["DCTDecode"]; $self->{decodeparms} = {}; bless($self); return $self; } sub pdf_next_jpeg_marker { my $self = shift; my $fh = shift; my $c = 0; my $s; my $M_ERROR = 0x100; #dummy marker, internal use only #my $dbg = ""; while ( $c == 0 ) { while ( $c != 0xFF ) { if ( eof($fh) ) { #print "EOF in next_marker ($dbg)\n"; return $M_ERROR; } read $fh, $s, 1; $c = unpack( "C", $s ); #$dbg.=" " . sprintf("%x", $c); } while ( $c == 0xFF ) { if ( eof($fh) ) { #print "EOF in next_marker ($dbg)\n"; return $M_ERROR; } read $fh, $s, 1; $c = unpack( "C", $s ); #$dbg.=" " . sprintf("%x", $c); } } #print "next_marker: $dbg\n"; return $c; } sub Open { my $self = shift; my $filename = shift; $self->{filename} = $filename; my $M_SOF0 = 0xc0; # baseline DCT my $M_SOF1 = 0xc1; # extended sequential DCT my $M_SOF2 = 0xc2; # progressive DCT my $M_SOF3 = 0xc3; # lossless (sequential) my $M_SOF5 = 0xc5; # differential sequential DCT my $M_SOF6 = 0xc6; # differential progressive DCT my $M_SOF7 = 0xc7; # differential lossless my $M_JPG = 0xc8; # JPEG extensions my $M_SOF9 = 0xc9; # extended sequential DCT my $M_SOF10 = 0xca; # progressive DCT my $M_SOF11 = 0xcb; # lossless (sequential) my $M_SOF13 = 0xcd; # differential sequential DCT my $M_SOF14 = 0xce; # differential progressive DCT my $M_SOF15 = 0xcf; # differential lossless my $M_DHT = 0xc4; # define Huffman tables my $M_DAC = 0xcc; # define arithmetic conditioning table my $M_RST0 = 0xd0; # restart my $M_RST1 = 0xd1; # restart my $M_RST2 = 0xd2; # restart my $M_RST3 = 0xd3; # restart my $M_RST4 = 0xd4; # restart my $M_RST5 = 0xd5; # restart my $M_RST6 = 0xd6; # restart my $M_RST7 = 0xd7; # restart my $M_SOI = 0xd8; # start of image my $M_EOI = 0xd9; # end of image my $M_SOS = 0xda; # start of scan my $M_DQT = 0xdb; # define quantization tables my $M_DNL = 0xdc; # define number of lines my $M_DRI = 0xdd; # define restart interval my $M_DHP = 0xde; # define hierarchical progression my $M_EXP = 0xdf; # expand reference image(s) my $M_APP0 = 0xe0; # application marker, used for JFIF my $M_APP1 = 0xe1; # application marker my $M_APP2 = 0xe2; # application marker my $M_APP3 = 0xe3; # application marker my $M_APP4 = 0xe4; # application marker my $M_APP5 = 0xe5; # application marker my $M_APP6 = 0xe6; # application marker my $M_APP7 = 0xe7; # application marker my $M_APP8 = 0xe8; # application marker my $M_APP9 = 0xe9; # application marker my $M_APP10 = 0xea; # application marker my $M_APP11 = 0xeb; # application marker my $M_APP12 = 0xec; # application marker my $M_APP13 = 0xed; # application marker my $M_APP14 = 0xee; # application marker, used by Adobe my $M_APP15 = 0xef; # application marker my $M_JPG0 = 0xf0; # reserved for JPEG extensions my $M_JPG13 = 0xfd; # reserved for JPEG extensions my $M_COM = 0xfe; # comment my $M_TEM = 0x01; # temporary use my $M_ERROR = 0x100; #dummy marker, internal use only my $b; my $c; my $s; my $i; my $length; my $APP_MAX = 255; my $appstring; my $SOF_done = 0; my $mask = -1; my $adobeflag = 0; my $components = 0; my $fh = FileHandle->new($filename); if ( !defined $fh ) { $self->{error} = "PDF::Image::JPEG.pm: $filename: $!"; return 0 } binmode $fh; #Tommy's special trick for Macintosh JPEGs: simply skip some # hundred bytes at the beginning of the file! MACTrick: while ( !eof($fh) ) { $c = 0; while ( !eof($fh) && $c != 0xFF ) { # skip if not FF read $fh, $s, 1; $c = unpack( "C", $s ); } if ( eof($fh) ) { close($fh); $self->{error} = "PDF::Image::JPEG.pm: Not a JPEG file."; return 0; } while ( !eof($fh) && $c == 0xFF ) { # skip repeated FFs read $fh, $s, 1; $c = unpack( "C", $s ); } $self->{private}->{datapos} = tell($fh) - 2; if ( $c == $M_SOI ) { seek( $fh, $self->{private}->{datapos}, 0 ); last MACTrick; } } my $BOGUS_LENGTH = 768; #Heuristics: if we are that far from the start chances are # it is a TIFF file with embedded JPEG data which we cannot # handle - regard as hopeless... if ( eof($fh) || $self->{private}->{datapos} > $BOGUS_LENGTH ) { close($fh); $self->{error} = "PDF::Image::JPEG.pm: Not a JPEG file."; return 0; } #process JPEG markers */ JPEGMarkers: while ( !$SOF_done && ( $c = $self->pdf_next_jpeg_marker($fh) ) != $M_EOI ) { #print "Marker: " . sprintf("%x", $c) . "\n"; if ( $c == $M_ERROR || $c == $M_SOF3 || $c == $M_SOF5 || $c == $M_SOF6 || $c == $M_SOF7 || $c == $M_SOF9 || $c == $M_SOF11 || $c == $M_SOF13 || $c == $M_SOF14 || $c == $M_SOF15 ) { close($fh); $self->{error} = "PDF::Image::JPEG.pm: JPEG compression " . ord($c) . " not supported in PDF 1.3.", return 0; } if ( $c == $M_SOF2 || $c == $M_SOF10 ) { close($fh); $self->{error} = "PDF::Image::JPEG.pm: JPEG compression " . ord($c) . " not supported in PDF 1.2.", return 0; } if ( $c == $M_SOF0 || $c == $M_SOF1 ) { read $fh, $s, 12; ( $c, $self->{bpc}, $self->{height}, $self->{width}, $components ) = unpack( "nCnnC", $s ); $SOF_done = 1; last JPEGMarkers; } elsif ( $c == $M_APP0 ) { read $fh, $s, 2; $length = unpack( "n", $s ) - 2; read $fh, $appstring, $length; #Check for JFIF application marker and read density values # per JFIF spec version 1.02. my $ASPECT_RATIO = 0; #JFIF unit byte: aspect ratio only my $DOTS_PER_INCH = 1; #JFIF unit byte: dots per inch my $DOTS_PER_CM = 2; #JFIF unit byte: dots per cm if ( $length >= 12 && $appstring =~ /^JFIF/ ) { ( $c, $c, $c, $c, $c, $c, $c, $self->{private}->{unit}, $self->{dpi_x}, $self->{dpi_y} ) = unpack( "CCCCCCCCnn", $appstring ); if ( $self->{dpi_x} <= 0 || $self->{dpi_y} <= 0 ) { $self->{dpi_x} = 0; $self->{dpi_y} = 0; } elsif ( $self->{private}->{unit} == $DOTS_PER_INCH ) { } elsif ( $self->{private}->{unit} == $DOTS_PER_CM ) { $self->{dpi_x} *= 2.54; $self->{dpi_y} *= 2.54; } elsif ( $self->{private}->{unit} == $ASPECT_RATIO ) { $self->{dpi_x} *= -1; $self->{dpi_y} *= -1; } } } elsif ( $c == $M_APP14 ) { #check for Adobe marker read $fh, $s, 2; $length = unpack( "n", $s ) - 2; read $fh, $appstring, $length; #Check for Adobe application marker. It is known (per Adobe's TN5116) #to contain the string "Adobe" at the start of the APP14 marker. if ( $length >= 10 && $appstring =~ /^Adobe/ ) { $adobeflag = 1; } } elsif ( $c == $M_SOI || $c == $M_EOI || $c == $M_TEM || $c == $M_RST0 || $c == $M_RST1 || $c == $M_RST2 || $c == $M_RST3 || $c == $M_RST4 || $c == $M_RST5 || $c == $M_RST6 || $c == $M_RST7 ) { #no parameters --> ignore } else { #skip variable length markers read $fh, $s, 2; $length = unpack( "n", $s ) - 2; read $fh, $s, $length; } } if ( $self->{height} <= 0 || $self->{width} <= 0 || $components <= 0 ) { close($fh); $self->{error} = "PDF::Image::JPEG.pm: Bad image parameters in JPEG file."; return 0; } if ( $self->{bpc} != 8 ) { close($fh); $self->{error} = "PDF::Image::JPEG.pm: Bad bpc in JPEG file."; return 0; } if ( $components == 1 ) { $self->{colorspace} = "DeviceGray"; } elsif ( $components == 3 ) { $self->{colorspace} = "DeviceRGB"; } elsif ( $components == 4 ) { $self->{colorspace} = "DeviceCMYK"; #special handling of Photoshop-generated CMYK JPEG files if ($adobeflag) { $self->{invert} = 1; } } else { close($fh); $self->{error} = "PDF::Image::JPEG.pm: Unknown number of color components in JPEG file.", return 0; } close($fh); 1; } sub ReadData { my $self = shift; my $s = ""; my $result; my $JPEG_BUFSIZE = 1024; my $fh = FileHandle->new($self->{filename}); if ( !defined $fh ) { $self->{error} = "PDF::Image::JPEG.pm: $self->{filename}: $!"; return 0 } binmode $fh; seek( $fh, $self->{private}->{datapos}, 0 ); while ( read( $fh, $s, $JPEG_BUFSIZE ) > 0 ) { $result .= $s; } $self->{imagesize} = length($result); close $fh; $result; } 1; PDF-Create-1.08/lib/PDF/Create/Outline.pm000644 000765 000024 00000003627 12251772476 020075 0ustar00gaborstaff000000 000000 # # PDF::Create::Outline - PDF outline support for PDF::Create # # Author: Fabien Tassin # # Copyright 1999-2001 Fabien Tassin # Copyright 2007- Markus Baertschi # Copyright 2010 Gary Lieberman # # Please see the CHANGES and Changes file for the detailed change log # # Please do not use any of the methods here directly. You will be # punished with your application no longer working after an upgrade ! # package PDF::Create::Outline; use strict; use warnings; use Carp; use FileHandle; use Data::Dumper; our $VERSION = '1.08'; our $DEBUG = 0; sub new { my $this = shift; my $class = ref($this) || $this; my $self = {}; bless $self, $class; $self->{'Kids'} = []; $self; } sub add { my $self = shift; my $outline = PDF::Create::Outline->new(); $outline->{'id'} = shift; $outline->{'name'} = shift; $outline->{'Parent'} = $self; $outline->{'pdf'} = $self->{'pdf'}; my %params = @_; $outline->{'Title'} = $params{'Title'} if defined $params{'Title'}; $outline->{'Action'} = $params{'Action'} if defined $params{'Action'}; $outline->{'Status'} = defined $params{'Status'} && ( $params{'Status'} eq 'closed' || !$params{'Status'} ) ? 0 : 1; $outline->{'Dest'} = $params{'Destination'} if defined $params{'Destination'}; push @{ $self->{'Kids'} }, $outline; $outline; } sub count { my $self = shift; my $c = scalar @{ $self->{'Kids'} }; return $c unless $c; for my $outline ( @{ $self->{'Kids'} } ) { my $v = $outline->count; $c += $v if $outline->{'Status'}; } $c *= -1 unless $self->{'Status'}; $c; } sub kids { my $self = shift; my $t = []; map { push @$t, $_->{'id'} } @{ $self->{'Kids'} }; $t; } sub list { my $self = shift; my @l; for my $e ( @{ $self->{'Kids'} } ) { my @t = $e->list; push @l, $e; push @l, @t if scalar @t; } @l; } sub new_outline { my $self = shift; $self->{'pdf'}->new_outline( 'Parent' => $self, @_ ); } 1; PDF-Create-1.08/lib/PDF/Create/Page.pm000644 000765 000024 00000071620 12251772477 017331 0ustar00gaborstaff000000 000000 # # PDF::Create::Page - PDF pages tree for PDF::Create # # Author: Fabien Tassin # # Copyright 1999-2001 Fabien Tassin # Copyright 2007- Markus Baertschi # Copyright 2010 Gary Lieberman # # Please see the CHANGES and Changes file for the detailed change log # # Please do not use any of the methods here directly. You will be # punished with your application no longer working after an upgrade ! # package PDF::Create::Page; use strict; use warnings; use Carp; use FileHandle; use Data::Dumper; use POSIX qw(setlocale LC_NUMERIC); our $VERSION = '1.08'; our $DEBUG = 0; my $font_widths = &init_widths; my $ptext = ""; # Global variable for text function sub new { my $this = shift; my $class = ref($this) || $this; my $self = {}; bless $self, $class; $self->{'Kids'} = []; $self->{'Content'} = []; $self; } sub add { my $self = shift; my $page = PDF::Create::Page->new(); $page->{'pdf'} = $self->{'pdf'}; $page->{'Parent'} = $self; $page->{'id'} = shift; $page->{'name'} = shift; push @{ $self->{'Kids'} }, $page; $page; } sub count { my $self = shift; my $c = 0; $c++ unless scalar @{ $self->{'Kids'} }; for my $page ( @{ $self->{'Kids'} } ) { $c += $page->count; } $c; } sub kids { my $self = shift; my $t = []; map { push @$t, $_->{'id'} } @{ $self->{'Kids'} }; $t; } sub list { my $self = shift; my @l; for my $e ( @{ $self->{'Kids'} } ) { my @t = $e->list; push @l, $e; push @l, @t if scalar @t; } @l; } sub new_page { my $self = shift; $self->{'pdf'}->new_page( 'Parent' => $self, @_ ); } ####################################################################### # Drawing functions # # x y m: moves the current point to (x, y), omitting any connecting line # segment sub moveto { my $self = shift; my ( $x, $y ) = @_; $self->{'pdf'}->page_stream($self); $self->{'pdf'}->add("$x $y m"); } # x y l: appends a straight line segment from the current point to (x, y). # The current point is (x, y). sub lineto { my $self = shift; my ( $x, $y ) = @_; $self->{'pdf'}->page_stream($self); $self->{'pdf'}->add("$x $y l"); } # x1 y1 x2 y2 x3 y3 c: appends a Bezier curve to the path. The curve extends # from the current point to (x3 ,y3) using (x1 ,y1) and (x2 ,y2) # as the Bezier control points. The new current point is (x3 ,y3). sub curveto { my $self = shift; my ( $x1, $y1, $x2, $y2, $x3, $y3 ) = @_; $self->{'pdf'}->page_stream($self); $self->{'pdf'}->add("$x1 $y1 $x2 $y2 $x3 $y3 c"); } # omit 'v' and 'y' # x y w h re: adds a rectangle to the current path sub rectangle { my $self = shift; my ( $x, $y, $w, $h ) = @_; $self->{'pdf'}->page_stream($self); $self->{'pdf'}->add("$x $y $w $h re"); } # h: closes the current subpath by appending a straight line segment # from the current point to the starting point of the subpath. sub closepath { my $self = shift; $self->{'pdf'}->page_stream($self); $self->{'pdf'}->add("h"); } # n: ends the path without filling or stroking it sub newpath { my $self = shift; $self->{'pdf'}->page_stream($self); $self->{'pdf'}->add("n"); } # S: strokes the path sub stroke { my $self = shift; $self->{'pdf'}->page_stream($self); $self->{'pdf'}->add("S"); } # s: closes and strokes the path sub closestroke { my $self = shift; $self->{'pdf'}->page_stream($self); $self->{'pdf'}->add("s"); } # f: fills the path using the non-zero winding number rule sub fill { my $self = shift; $self->{'pdf'}->page_stream($self); $self->{'pdf'}->add("f"); } # f*: fills the path using the even-odd rule sub fill2 { my $self = shift; $self->{'pdf'}->page_stream($self); $self->{'pdf'}->add("f*"); } # combined moveto/lineto/stroke command sub line { my $self = shift; my ( $x1, $y1, $x2, $y2 ) = @_; $self->{'pdf'}->page_stream($self); $self->{'pdf'}->add("$x1 $y1 m $x2 $y2 l S"); } sub set_width { my $self = shift; my $w = shift; $self->{'pdf'}->page_stream($self); $self->{'pdf'}->add("$w w"); } ####################################################################### # Color functions # # g: Sets the color space to DeviceGray and sets the gray tint to use # for filling paths. [0, 1] sub setgray { my $self = shift; my $val = shift; $self->{'pdf'}->page_stream($self); $self->{'pdf'}->add("$val g"); } # G: Sets the color space to DeviceGray and sets the gray tint to use # for stroking paths. [0, 1] sub setgraystroke { my $self = shift; my $val = shift; $self->{'pdf'}->page_stream($self); $self->{'pdf'}->add("$val G"); } # rg: Sets the color space to DeviceRGB and sets the color to use for # filling paths. [0, 1] * 3. sub setrgbcolor { my $self = shift; my $r = shift; my $g = shift; my $b = shift; $self->{'pdf'}->page_stream($self); $self->{'pdf'}->add("$r $g $b rg"); } # rg: Sets the color space to DeviceRGB and sets the color to use for # stroking paths. [0, 1] * 3. sub setrgbcolorstroke { my $self = shift; my $r = shift; my $g = shift; my $b = shift; croak "Error setting colors, need three values" if !defined $b; $self->{'pdf'}->page_stream($self); $self->{'pdf'}->add("$r $g $b RG"); } ####################################################################### # # Text functions ####################################################################### # experimental text function with functionality aligned with the PDF structure # my $pi = atan2( 1, 1 ) * 4; my $piover180 = $pi / 180; sub text { my $self = shift; my %params = @_; PDF::Create::debug( 2, "text(%params):" ); if ( defined $params{'start'} ) { $ptext = "BT "; } if ( defined $params{'Ts'} ) { $ptext .= " $params{'Ts'} Ts "; } # Text Rise (Super/Subscript) if ( defined $params{'Tr'} ) { $ptext .= " $params{'Tr'} Tr "; } # Rendering Mode if ( defined $params{'TL'} ) { $ptext .= " $params{'TL'} TL "; } # Text Leading if ( defined $params{'Tc'} ) { $ptext .= " $params{'Tc'} Tc "; } # Character spacing if ( defined $params{'Tw'} ) { $ptext .= " $params{'Tw'} Tw "; } # Word Spacing if ( defined $params{'Tz'} ) { $ptext .= " $params{'Tz'} Tz "; } # Horizontal Scaling if ( defined $params{'rot'} ) { # Moveto and rotate my ( $r, $x, $y ) = split( /\s+/, $params{'rot'}, 3 ); $x = 0 unless ( $x > 0 ); $y = 0 unless ( $y > 0 ); my $cos = cos( $r * $piover180 ); my $sin = sin( $r * $piover180 ); $ptext .= sprintf( " %.5f %.5f -%.5f %.5f %s %s Tm ", $cos, $sin, $sin, $cos, $x, $y ); } if ( defined $params{'Tf'} ) { $ptext .= "/F$params{'Tf'} Tf "; } # Font size if ( defined $params{'Td'} ) { $ptext .= " $params{'Td'} Td "; } # Moveto if ( defined $params{'TD'} ) { $ptext .= " $params{'TD'} TD "; } # Moveto and set TL if ( defined $params{'T*'} ) { $ptext .= " T* "; } # New line if ( defined $params{'text'} ) { $params{'text'} =~ s|([()])|\\$1|g; $ptext .= "($params{'text'}) Tj "; } if ( defined $params{'end'} ) { $ptext .= " ET"; $self->{'pdf'}->page_stream($self); $self->{'pdf'}->add("$ptext"); } PDF::Create::debug( 3, "text(): $ptext" ); 1; } sub string { my $self = shift; my $font = shift; my $size = shift; my $x = shift; my $y = shift; my $s = shift; my $align = shift || 'L'; if ( uc($align) eq "R" ) { $x -= $size * $self->string_width( $font, $s ); } elsif ( uc($align) eq "C" ) { $x -= $size * $self->string_width( $font, $s ) / 2; } $self->{'pdf'}->page_stream($self); $self->{'pdf'}->uses_font( $self, $font ); $s =~ s|([()])|\\$1|g; $self->{'pdf'}->add("BT /F$font $size Tf $x $y Td ($s) Tj ET"); } sub string_underline { my $self = shift; my $font = shift; my $size = shift; my $x = shift; my $y = shift; my $string = shift; my $align = shift || 'L'; my $len = $self->string_width( $font, $string ) * $size; my $len2 = $len / 2; if ( uc($align) eq "R" ) { $self->line( $x - $len, $y - 1, $x, $y - 1 ); } elsif ( uc($align) eq "C" ) { $self->line( $x - $len2, $y - 1, $x + $len2, $y - 1 ); } else { $self->line( $x, $y - 1, $x + $len, $y - 1 ); } return $len; } sub stringl { my $self = shift; my $font = shift; my $size = shift; my $x = shift; my $y = shift; my $s = shift; $self->{'pdf'}->page_stream($self); $self->{'pdf'}->uses_font( $self, $font ); $s =~ s|([()])|\\$1|g; $self->{'pdf'}->add("BT /F$font $size Tf $x $y Td ($s) Tj ET"); } sub stringr { my $self = shift; my $font = shift; my $size = shift; my $x = shift; my $y = shift; my $s = shift; $self->{'pdf'}->page_stream($self); $self->{'pdf'}->uses_font( $self, $font ); $x -= $size * $self->string_width( $font, $s ); $s =~ s|([()])|\\$1|g; $self->{'pdf'}->add(" BT /F$font $size Tf $x $y Td ($s) Tj ET"); } sub stringc { my $self = shift; my $font = shift; my $size = shift; my $x = shift; my $y = shift; my $s = shift; $self->{'pdf'}->page_stream($self); $self->{'pdf'}->uses_font( $self, $font ); $x -= $size * $self->string_width( $font, $s ) / 2; $s =~ s|([()])|\\$1|g; $self->{'pdf'}->add(" BT /F$font $size Tf $x $y Td ($s) Tj ET"); } sub string_width { my $self = shift; my $font = shift; my $string = shift; croak 'No string given' unless defined $string; my $fname = $self->{'pdf'}{'fonts'}{$font}{'BaseFont'}[1]; croak('Unknown font: ' . $fname) unless defined $$font_widths{$fname}[ ord "M" ]; my $w = 0; for my $c ( split '', $string ) { $w += $$font_widths{$fname}[ ord $c ]; } $w / 1000; } sub printnl { my $self = shift; my $s = shift; my $font = shift; my $size = shift; my $x = shift; my $y = shift; # set up current_x/y used in stringml $self->{'current_y'} = $y if defined $y; carp 'No starting position given, using 800' if !defined $self->{'current_y'}; $self->{'current_y'} = 800 if !defined $self->{'current_y'}; $self->{'current_x'} = $x if defined $x; $self->{'current_x'} = 20 if !defined $self->{'current_x'}; $self->{'current_size'} = $size if defined $size; $self->{'current_size'} = 12 if !defined $self->{'current_size'}; $self->{'current_font'} = $font if defined $font; croak 'No font found !' if !defined $self->{'current_font'}; # print the line(s) my $n = 0; for my $line ( split '\n', $s ) { $n++; $self->string( $self->{'current_font'}, $self->{'current_size'}, $self->{'current_x'}, $self->{'current_y'}, $line ); $self->{'current_y'} = $self->{'current_y'} - $self->{'current_size'}; } return $n; } ####################################################################### # Place an image on the current page # sub image { my $self = shift; my %params = @_; # Switch to the 'C' locale, we need printf floats with a '.', not a ',' my $savedLocale = setlocale(LC_NUMERIC); setlocale(LC_NUMERIC,'C'); my $img = $params{'image'} || "1.2"; my $image = $img->{num}; my $xpos = $params{'xpos'} || 0; my $ypos = $params{'ypos'} || 0; my $xalign = $params{'xalign'} || 0; my $yalign = $params{'yalign'} || 0; my $xscale = $params{'xscale'} || 1; my $yscale = $params{'yscale'} || 1; my $rotate = $params{'rotate'} || 0; my $xskew = $params{'xskew'} || 0; my $yskew = $params{'yskew'} || 0; $xscale *= $img->{width}; $yscale *= $img->{height}; if ( $xalign == 1 ) { $xpos -= $xscale / 2; } elsif ( $xalign == 2 ) { $xpos -= $xscale; } if ( $yalign == 1 ) { $ypos -= $yscale / 2; } elsif ( $yalign == 2 ) { $ypos -= $yscale; } $self->{'pdf'}->page_stream($self); $self->{'pdf'}->uses_xobject( $self, $image ); $self->{'pdf'}->add("q\n"); # TODO: image: Merge position with rotate $self->{'pdf'}->add("1 0 0 1 $xpos $ypos cm\n") if ( $xpos || $ypos ); if ($rotate) { my $sinth = sin($rotate); my $costh = cos($rotate); $self->{'pdf'}->add("$costh $sinth -$sinth $costh 0 0 cm\n"); } if ( $xscale || $yscale ) { $self->{'pdf'}->add("$xscale 0 0 $yscale 0 0 cm\n"); } if ( $xskew || $yskew ) { my $tana = sin($xskew) / cos($xskew); my $tanb = sin($yskew) / cos($xskew); $self->{'pdf'}->add("1 $tana $tanb 1 0 0 cm\n"); } $self->{'pdf'}->add("/Image$image Do\n"); $self->{'pdf'}->add("Q\n"); # Switch to the 'C' locale, we need printf floats with a '.', not a ',' setlocale(LC_NUMERIC,$savedLocale); } ####################################################################### # Table with font widths for the supported fonts # sub init_widths { { 'Courier' => [ 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599 ], 'Courier-Bold' => [ 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599 ], 'Courier-BoldOblique' => [ 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599 ], 'Courier-Oblique' => [ 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599 ], 'Helvetica' => [ 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 354, 555, 555, 888, 666, 220, 332, 332, 388, 583, 277, 332, 277, 277, 555, 555, 555, 555, 555, 555, 555, 555, 555, 555, 277, 277, 583, 583, 583, 555, 1014, 666, 666, 721, 721, 666, 610, 777, 721, 277, 499, 666, 555, 832, 721, 777, 666, 777, 721, 666, 610, 721, 666, 943, 666, 666, 610, 277, 277, 277, 468, 555, 221, 555, 555, 499, 555, 555, 277, 555, 555, 221, 221, 499, 221, 832, 555, 555, 555, 555, 332, 499, 277, 555, 499, 721, 499, 499, 499, 333, 259, 333, 583, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 332, 555, 555, 166, 555, 555, 555, 555, 190, 332, 555, 332, 332, 499, 499, 277, 555, 555, 555, 277, 277, 536, 349, 221, 332, 332, 555, 999, 999, 277, 610, 277, 332, 332, 332, 332, 332, 332, 332, 332, 277, 332, 332, 277, 332, 332, 332, 999, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 999, 277, 369, 277, 277, 277, 277, 555, 777, 999, 364, 277, 277, 277, 277, 277, 888, 277, 277, 277, 277, 277, 277, 221, 610, 943, 610, 277, 277, 277, 277 ], 'Helvetica-Bold' => [ 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 332, 473, 555, 555, 888, 721, 277, 332, 332, 388, 583, 277, 332, 277, 277, 555, 555, 555, 555, 555, 555, 555, 555, 555, 555, 332, 332, 583, 583, 583, 610, 974, 721, 721, 721, 721, 666, 610, 777, 721, 277, 555, 721, 610, 832, 721, 777, 666, 777, 721, 666, 610, 721, 666, 943, 666, 666, 610, 332, 277, 332, 583, 555, 277, 555, 610, 555, 610, 555, 332, 610, 610, 277, 277, 555, 277, 888, 610, 610, 610, 610, 388, 555, 332, 610, 555, 777, 555, 555, 499, 388, 279, 388, 583, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 332, 555, 555, 166, 555, 555, 555, 555, 237, 499, 555, 332, 332, 610, 610, 277, 555, 555, 555, 277, 277, 555, 349, 277, 499, 499, 555, 999, 999, 277, 610, 277, 332, 332, 332, 332, 332, 332, 332, 332, 277, 332, 332, 277, 332, 332, 332, 999, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 999, 277, 369, 277, 277, 277, 277, 610, 777, 999, 364, 277, 277, 277, 277, 277, 888, 277, 277, 277, 277, 277, 277, 277, 610, 943, 610, 277, 277, 277, 277 ], 'Helvetica-BoldOblique' => [ 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 332, 473, 555, 555, 888, 721, 277, 332, 332, 388, 583, 277, 332, 277, 277, 555, 555, 555, 555, 555, 555, 555, 555, 555, 555, 332, 332, 583, 583, 583, 610, 974, 721, 721, 721, 721, 666, 610, 777, 721, 277, 555, 721, 610, 832, 721, 777, 666, 777, 721, 666, 610, 721, 666, 943, 666, 666, 610, 332, 277, 332, 583, 555, 277, 555, 610, 555, 610, 555, 332, 610, 610, 277, 277, 555, 277, 888, 610, 610, 610, 610, 388, 555, 332, 610, 555, 777, 555, 555, 499, 388, 279, 388, 583, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 332, 555, 555, 166, 555, 555, 555, 555, 237, 499, 555, 332, 332, 610, 610, 277, 555, 555, 555, 277, 277, 555, 349, 277, 499, 499, 555, 999, 999, 277, 610, 277, 332, 332, 332, 332, 332, 332, 332, 332, 277, 332, 332, 277, 332, 332, 332, 999, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 999, 277, 369, 277, 277, 277, 277, 610, 777, 999, 364, 277, 277, 277, 277, 277, 888, 277, 277, 277, 277, 277, 277, 277, 610, 943, 610, 277, 277, 277, 277 ], 'Helvetica-Oblique' => [ 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 354, 555, 555, 888, 666, 221, 332, 332, 388, 583, 277, 332, 277, 277, 555, 555, 555, 555, 555, 555, 555, 555, 555, 555, 277, 277, 583, 583, 583, 555, 1014, 666, 666, 721, 721, 666, 610, 777, 721, 277, 499, 666, 555, 832, 721, 777, 666, 777, 721, 666, 610, 721, 666, 943, 666, 666, 610, 277, 277, 277, 468, 555, 221, 555, 555, 499, 555, 555, 277, 555, 555, 221, 221, 499, 221, 832, 555, 555, 555, 555, 332, 499, 277, 555, 499, 721, 499, 499, 499, 333, 259, 333, 583, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 332, 555, 555, 166, 555, 555, 555, 555, 190, 332, 555, 332, 332, 499, 499, 277, 555, 555, 555, 277, 277, 536, 349, 221, 332, 332, 555, 999, 999, 277, 610, 277, 332, 332, 332, 332, 332, 332, 332, 332, 277, 332, 332, 277, 332, 332, 332, 999, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 999, 277, 369, 277, 277, 277, 277, 555, 777, 999, 364, 277, 277, 277, 277, 277, 888, 277, 277, 277, 277, 277, 277, 221, 610, 943, 610, 277, 277, 277, 277 ], 'Times-Bold' => [ 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 332, 554, 499, 499, 999, 832, 332, 332, 332, 499, 569, 249, 332, 249, 277, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 332, 332, 569, 569, 569, 499, 929, 721, 666, 721, 721, 666, 610, 777, 777, 388, 499, 777, 666, 943, 721, 777, 610, 777, 721, 555, 666, 721, 721, 999, 721, 721, 666, 332, 277, 332, 580, 499, 332, 499, 555, 443, 555, 443, 332, 499, 555, 277, 332, 555, 277, 832, 555, 499, 555, 555, 443, 388, 332, 555, 499, 721, 499, 499, 443, 393, 219, 393, 519, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 332, 499, 499, 166, 499, 499, 499, 499, 277, 499, 499, 332, 332, 555, 555, 249, 499, 499, 499, 249, 249, 539, 349, 332, 499, 499, 499, 999, 999, 249, 499, 249, 332, 332, 332, 332, 332, 332, 332, 332, 249, 332, 332, 249, 332, 332, 332, 999, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 999, 249, 299, 249, 249, 249, 249, 666, 777, 999, 329, 249, 249, 249, 249, 249, 721, 249, 249, 249, 277, 249, 249, 277, 499, 721, 555, 249, 249, 249, 249 ], 'Times-BoldItalic' => [ 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 388, 554, 499, 499, 832, 777, 332, 332, 332, 499, 569, 249, 332, 249, 277, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 332, 332, 569, 569, 569, 499, 831, 666, 666, 666, 721, 666, 666, 721, 777, 388, 499, 666, 610, 888, 721, 721, 610, 721, 666, 555, 610, 721, 666, 888, 666, 610, 610, 332, 277, 332, 569, 499, 332, 499, 499, 443, 499, 443, 332, 499, 555, 277, 277, 499, 277, 777, 555, 499, 499, 499, 388, 388, 277, 555, 443, 666, 499, 443, 388, 347, 219, 347, 569, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 388, 499, 499, 166, 499, 499, 499, 499, 277, 499, 499, 332, 332, 555, 555, 249, 499, 499, 499, 249, 249, 499, 349, 332, 499, 499, 499, 999, 999, 249, 499, 249, 332, 332, 332, 332, 332, 332, 332, 332, 249, 332, 332, 249, 332, 332, 332, 999, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 943, 249, 265, 249, 249, 249, 249, 610, 721, 943, 299, 249, 249, 249, 249, 249, 721, 249, 249, 249, 277, 249, 249, 277, 499, 721, 499, 249, 249, 249, 249 ], 'Times-Italic' => [ 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 332, 419, 499, 499, 832, 777, 332, 332, 332, 499, 674, 249, 332, 249, 277, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 332, 332, 674, 674, 674, 499, 919, 610, 610, 666, 721, 610, 610, 721, 721, 332, 443, 666, 555, 832, 666, 721, 610, 721, 610, 499, 555, 721, 610, 832, 610, 555, 555, 388, 277, 388, 421, 499, 332, 499, 499, 443, 499, 443, 277, 499, 499, 277, 277, 443, 277, 721, 499, 499, 499, 499, 388, 388, 277, 499, 443, 666, 443, 443, 388, 399, 274, 399, 540, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 388, 499, 499, 166, 499, 499, 499, 499, 213, 555, 499, 332, 332, 499, 499, 249, 499, 499, 499, 249, 249, 522, 349, 332, 555, 555, 499, 888, 999, 249, 499, 249, 332, 332, 332, 332, 332, 332, 332, 332, 249, 332, 332, 249, 332, 332, 332, 888, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 888, 249, 275, 249, 249, 249, 249, 555, 721, 943, 309, 249, 249, 249, 249, 249, 666, 249, 249, 249, 277, 249, 249, 277, 499, 666, 499, 249, 249, 249, 249 ], 'Times-Roman' => [ 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 332, 407, 499, 499, 832, 777, 332, 332, 332, 499, 563, 249, 332, 249, 277, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 277, 277, 563, 563, 563, 443, 920, 721, 666, 666, 721, 610, 555, 721, 721, 332, 388, 721, 610, 888, 721, 721, 555, 721, 666, 555, 610, 721, 721, 943, 721, 721, 610, 332, 277, 332, 468, 499, 332, 443, 499, 443, 499, 443, 332, 499, 499, 277, 277, 499, 277, 777, 499, 499, 499, 499, 332, 388, 277, 499, 499, 721, 499, 499, 443, 479, 199, 479, 540, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 332, 499, 499, 166, 499, 499, 499, 499, 179, 443, 499, 332, 332, 555, 555, 249, 499, 499, 499, 249, 249, 452, 349, 332, 443, 443, 499, 999, 999, 249, 443, 249, 332, 332, 332, 332, 332, 332, 332, 332, 249, 332, 332, 249, 332, 332, 332, 999, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 888, 249, 275, 249, 249, 249, 249, 610, 721, 888, 309, 249, 249, 249, 249, 249, 666, 249, 249, 249, 277, 249, 249, 277, 499, 721, 499, 249, 249, 249, 249 ], }; } 1; PDF-Create-1.08/eg/sample-cgi.pl000755 000765 000024 00000002530 12251673270 016472 0ustar00gaborstaff000000 000000 #!/usr/bin/perl -w # # sample PDF::Create usage for a Web CGI # # Inpired by alr with a CPAN annotation # use strict; use PDF::Create; use CGI; # CGI Header designating the pdf data print CGI::header( -type => 'application/x-pdf', -attachment => 'sample.pdf' ); # Open pdf to stdout my $pdf = new PDF::Create('filename' => '-', # STDOUT 'Version' => 1.2, 'PageMode' => 'UseOutlines', 'Author' => 'John Doe', 'Title' => 'Sample Document', ); my $page = $pdf->new_page('MediaBox' => $pdf->get_page_size('a4')); # Prepare 2 fonts my $f1 = $pdf->font('Subtype' => 'Type1', 'Encoding' => 'WinAnsiEncoding', 'BaseFont' => 'Helvetica'); my $f2 = $pdf->font('Subtype' => 'Type1', 'Encoding' => 'WinAnsiEncoding', 'BaseFont' => 'Helvetica-Bold'); # Prepare a Table of Content my $toc = $pdf->new_outline('Title' => 'Sample Document'); # Add a entry to the outline $toc->new_outline('Title' => 'Page 1', 'Destination' => $page); # Write some text to the page $page->stringc($f2, 40, 306, 426, "PDF::Create"); $page->stringc($f1, 20, 306, 396, "version $PDF::Create::VERSION"); $page->stringc($f1, 20, 300, 300, 'Fabien Tassin'); $page->stringc($f1, 20, 300, 250, 'Markus Baertschi (markus@markus.org)'); $page->stringc($f1, 20, 300, 200, 'sample-cgi.pl'); # Wrap up the PDF and close the file $pdf->close; PDF-Create-1.08/eg/sample.pl000755 000765 000024 00000003644 12251673270 015741 0ustar00gaborstaff000000 000000 #!/usr/bin/perl -w # # sample PDF::Create usage # use strict; use PDF::Create; my $pdf = new PDF::Create('filename' => 'sample.pdf', 'Version' => 1.2, 'PageMode' => 'UseOutlines', 'Author' => 'John Doe', 'Title' => 'Sample Document', ); my $root = $pdf->new_page('MediaBox' => $pdf->get_page_size('a4')); # Prepare 2 fonts my $f1 = $pdf->font('Subtype' => 'Type1', 'Encoding' => 'WinAnsiEncoding', 'BaseFont' => 'Helvetica'); my $f2 = $pdf->font('Subtype' => 'Type1', 'Encoding' => 'WinAnsiEncoding', 'BaseFont' => 'Helvetica-Bold'); # Prepare a Table of Content my $toc = $pdf->new_outline('Title' => 'Sample Document'); # Add a page which inherits its attributes from $root my $page = $root->new_page; # Add a entry to the outline $toc->new_outline('Title' => 'Page 1', 'Destination' => $page); # Write some text to the page $page->stringc($f2, 40, 306, 426, "PDF::Create"); $page->stringc($f1, 20, 306, 396, "version $PDF::Create::VERSION"); $page->stringc($f1, 20, 300, 300, 'Fabien Tassin'); $page->stringc($f1, 20, 300, 250, 'Markus Baertschi (markus@markus.org)'); # add another page my $page2 = $root->new_page; my $s2 = $toc->new_outline('Title' => 'Page 2', 'Destination' => $page2); $s2->new_outline('Title' => 'GIF'); $s2->new_outline('Title' => 'JPEG'); # Draw a border around the page (A4 max is 595/842) $page2->line(10, 10, 10, 832); $page2->line(10, 10, 585, 10); $page2->line(10, 832, 585, 832); $page2->line(585, 10, 585, 832); # Add a gif image $page2->string($f1, 20, 50, 600, 'GIF Image:'); my $img1 = $pdf->image('pdf-logo.gif'); $page2->image('image'=>$img1, 'xscale'=>0.2,'yscale'=>0.2,'xpos'=>200,'ypos'=>600); # Add a jpeg image $page2->string($f1, 20, 50, 500, 'JPEG Image:'); my $img2 = $pdf->image('pdf-logo.jpg'); $page2->image('image'=>$img2, 'xscale'=>0.2,'yscale'=>0.2,'xpos'=>200,'ypos'=>500); # Wrap up the PDF and close the file $pdf->close;