#======================================================================= # ____ ____ _____ _ ____ ___ ____ # | _ \| _ \| ___| _ _ / \ | _ \_ _| |___ \ # | |_) | | | | |_ (_) (_) / _ \ | |_) | | __) | # | __/| |_| | _| _ _ / ___ \| __/| | / __/ # |_| |____/|_| (_) (_) /_/ \_\_| |___| |_____| # # A Perl Module Chain to faciliate the Creation and Modification # of High-Quality "Portable Document Format (PDF)" Files. # # Copyright 1999-2005 Alfred Reibenschuh . # #======================================================================= # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the # Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. # # $Id: Page.pm,v 2.1 2007/05/08 18:32:09 areibens Exp $ # #======================================================================= package PDF::API2::Page; BEGIN { use strict; use vars qw(@ISA %pgsz $VERSION); @ISA = qw(PDF::API2::Basic::PDF::Pages); use PDF::API2::Basic::PDF::Pages; use PDF::API2::Basic::PDF::Utils; use PDF::API2::Util; use PDF::API2::Annotation; use PDF::API2::Content; use PDF::API2::Content::Text; use PDF::API2::Util; use POSIX qw(floor ceil); use Math::Trig; ( $VERSION ) = sprintf '%i.%03i', split(/\./,('$Revision: 2.1 $' =~ /Revision: (\S+)\s/)[0]); # $Date: 2007/05/08 18:32:09 $ } no warnings qw[ deprecated recursion uninitialized ]; =head1 $page = PDF::API2::Page->new $pdf, $parent, $index Returns a page object (called from $pdf->page). =cut sub new { my ($class, $pdf, $parent, $index) = @_; my ($self) = {}; $class = ref $class if ref $class; $self = $class->SUPER::new($pdf, $parent); $self->{'Type'} = PDFName('Page'); $self->proc_set(qw( PDF Text ImageB ImageC ImageI )); delete $self->{'Count'}; delete $self->{'Kids'}; $parent->add_page($self, $index); $self; } =item $page = PDF::API2::Page->coerce $pdf, $pdfpage Returns a page object converted from $pdfpage (called from $pdf->openpage). =cut sub coerce { my ($class, $pdf, $page) = @_; my $self = $page; bless($self,$class); $self->{' apipdf'}=$pdf; return($self); } =item $page->update Marks a page to be updated (by $pdf->update). =cut sub update { my ($self) = @_; $self->{' apipdf'}->out_obj($self); $self; } =item $page->mediabox $w, $h =item $page->mediabox $llx, $lly, $urx, $ury =item $page->mediabox $alias Sets the mediabox. This method supports the following aliases: '4A', '2A', 'A0', 'A1', 'A2', 'A3', 'A4', 'A5', 'A6', '4B', '2B', 'B0', 'B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'LETTER', 'BROADSHEET', 'LEDGER', 'TABLOID', 'LEGAL', 'EXECUTIVE', and '36X36'. =cut sub mediabox { my ($self,$x1,$y1,$x2,$y2) = @_; if(defined $x2) { $self->{'MediaBox'}=PDFArray( map { PDFNum(float($_)) } ($x1,$y1,$x2,$y2) ); } elsif(defined $y1) { $self->{'MediaBox'}=PDFArray( map { PDFNum(float($_)) } (0,0,$x1,$y1) ); } else { $self->{'MediaBox'}=PDFArray( (map { PDFNum(float($_)) } page_size($x1)) ); } return($self); } =item ($llx, $lly, $urx, $ury) = $page->get_mediabox Gets the mediabox based one best estimates or the default. =cut sub get_mediabox { my ($self) = @_; my $media = [ 0, 0, 612, 792 ]; foreach my $mediatype ( qw( MediaBox CropBox BleedBox TrimBox ArtBox ) ) { my $mediaobj = undef; if($mediaobj = $self->find_prop($mediatype)) { $media = [ map{ $_->val } $mediaobj->elementsof ]; last; } } return(@{$media}); } =item $page->cropbox $w, $h =item $page->cropbox $llx, $lly, $urx, $ury =item $page->cropbox $alias Sets the cropbox. This method supports the same aliases as mediabox. =cut sub cropbox { my ($self,$x1,$y1,$x2,$y2) = @_; if(defined $x2) { $self->{'CropBox'}=PDFArray( map { PDFNum(float($_)) } ($x1,$y1,$x2,$y2) ); } elsif(defined $y1) { $self->{'CropBox'}=PDFArray( map { PDFNum(float($_)) } (0,0,$x1,$y1) ); } else { $self->{'CropBox'}=PDFArray( (map { PDFNum(float($_)) } page_size($x1)) ); } $self; } =item ($llx, $lly, $urx, $ury) = $page->get_cropbox Gets the cropbox based one best estimates or the default. =cut sub get_cropbox { my ($self) = @_; my $media = [ 0, 0, 612, 792 ]; foreach my $mediatype (qw[CropBox BleedBox TrimBox ArtBox MediaBox]) { my $mediaobj = undef; if($mediaobj = $self->find_prop($mediatype)) { $media = [ map{ $_->val } $mediaobj->elementsof ]; last; } } return(@{$media}); } =item $page->bleedbox $w, $h =item $page->bleedbox $llx, $lly, $urx, $ury =item $page->bleedbox $alias Sets the bleedbox. This method supports the same aliases as mediabox. =cut sub bleedbox { my ($self,$x1,$y1,$x2,$y2) = @_; if(defined $x2) { $self->{'BleedBox'}=PDFArray( map { PDFNum(float($_)) } ($x1,$y1,$x2,$y2) ); } elsif(defined $y1) { $self->{'BleedBox'}=PDFArray( map { PDFNum(float($_)) } (0,0,$x1,$y1) ); } else { $self->{'BleedBox'}=PDFArray( (map { PDFNum(float($_)) } page_size($x1)) ); } $self; } =item ($llx, $lly, $urx, $ury) = $page->get_bleedbox Gets the bleedbox based one best estimates or the default. =cut sub get_bleedbox { my ($self) = @_; my $media = [ 0, 0, 612, 792 ]; foreach my $mediatype (qw[BleedBox TrimBox ArtBox MediaBox CropBox]) { my $mediaobj = undef; if($mediaobj = $self->find_prop($mediatype)) { $media = [ map{ $_->val } $mediaobj->elementsof ]; last; } } return(@{$media}); } =item $page->trimbox $w, $h =item $page->trimbox $llx, $lly, $urx, $ury Sets the trimbox. This method supports the same aliases as mediabox. =cut sub trimbox { my ($self,$x1,$y1,$x2,$y2) = @_; if(defined $x2) { $self->{'TrimBox'}=PDFArray( map { PDFNum(float($_)) } ($x1,$y1,$x2,$y2) ); } elsif(defined $y1) { $self->{'TrimBox'}=PDFArray( map { PDFNum(float($_)) } (0,0,$x1,$y1) ); } else { $self->{'TrimBox'}=PDFArray( (map { PDFNum(float($_)) } page_size($x1)) ); } $self; } =item ($llx, $lly, $urx, $ury) = $page->get_trimbox Gets the trimbox based one best estimates or the default. =cut sub get_trimbox { my ($self) = @_; my $media = [ 0, 0, 612, 792 ]; foreach my $mediatype (qw[TrimBox ArtBox MediaBox CropBox BleedBox]) { my $mediaobj = undef; if($mediaobj = $self->find_prop($mediatype)) { $media = [ map{ $_->val } $mediaobj->elementsof ]; last; } } return(@{$media}); } =item $page->artbox $w, $h =item $page->artbox $llx, $lly, $urx, $ury =item $page->artbox $alias Sets the artbox. This method supports the same aliases as mediabox. =cut sub artbox { my ($self,$x1,$y1,$x2,$y2) = @_; if(defined $x2) { $self->{'ArtBox'}=PDFArray( map { PDFNum(float($_)) } ($x1,$y1,$x2,$y2) ); } elsif(defined $y1) { $self->{'ArtBox'}=PDFArray( map { PDFNum(float($_)) } (0,0,$x1,$y1) ); } else { $self->{'ArtBox'}=PDFArray( (map { PDFNum(float($_)) } page_size($x1)) ); } $self; } =item ($llx, $lly, $urx, $ury) = $page->get_artbox Gets the artbox based one best estimates or the default. =cut sub get_artbox { my ($self) = @_; my $media = [ 0, 0, 612, 792 ]; foreach my $mediatype (qw[ArtBox TrimBox BleedBox CropBox MediaBox]) { my $mediaobj = undef; if($mediaobj = $self->find_prop($mediatype)) { $media = [ map{ $_->val } $mediaobj->elementsof ]; last; } } return(@{$media}); } =item $page->rotate $deg Rotates the page by the given degrees, which must be a multiple of 90. (This allows you to auto-rotate to landscape without changing the mediabox!) =cut sub rotate { my ($self,$deg) = @_; $deg=floor($deg/90); while($deg>4) { $deg-=4; } while($deg<0) { $deg+=4; } if($deg==0) { delete $self->{Rotate}; } else { $self->{Rotate}=PDFNum($deg*90); } return($self); } =item $gfx = $page->gfx $prepend Returns a graphics content object. If $prepend is true the content will be prepended to the page description. =cut sub fixcontents { my ($self) = @_; $self->{'Contents'} = $self->{'Contents'} || PDFArray(); if(ref($self->{'Contents'})=~/Objind$/) { $self->{'Contents'}->realise; } if(ref($self->{'Contents'})!~/Array$/) { $self->{'Contents'} = PDFArray($self->{'Contents'}); } } sub content { my ($self,$obj,$dir) = @_; if(defined($dir) && $dir>0) { $self->precontent($obj); } else { $self->addcontent($obj); } $self->{' apipdf'}->new_obj($obj) unless($obj->is_obj($self->{' apipdf'})); $obj->{' apipdf'}=$self->{' apipdf'}; $obj->{' api'}=$self->{' api'}; $obj->{' apipage'}=$self; return($obj); } sub addcontent { my ($self,@objs) = @_; $self->fixcontents; $self->{'Contents'}->add_elements(@objs); } sub precontent { my ($self,@objs) = @_; $self->fixcontents; unshift(@{$self->{'Contents'}->val},@objs); } sub gfx { my ($self,$dir) = @_; my $gfx=PDF::API2::Content->new(); $self->content($gfx,$dir); $gfx->compressFlate() if($self->{' api'}->{forcecompress}); return($gfx); } =item $txt = $page->text $prepend Returns a text content object. If $prepend is true the content will be prepended to the page description. =cut sub text { my ($self,$dir) = @_; my $text=PDF::API2::Content::Text->new(); $self->content($text,$dir); $text->compressFlate() if($self->{' api'}->{forcecompress}); return($text); } =item $ant = $page->annotation Returns a new annotation object. =cut sub annotation { my ($self, $type, $key, $obj) = @_; $self->{'Annots'}||=PDFArray(); $self->{'Annots'}->realise if(ref($self->{'Annots'})=~/Objind/); if($self->{'Annots'}->is_obj($self->{' apipdf'})) { $self->{'Annots'}->update(); } else { $self->update(); } my $ant=PDF::API2::Annotation->new; $self->{'Annots'}->add_elements($ant); $self->{' apipdf'}->new_obj($ant); $ant->{' apipdf'}=$self->{' apipdf'}; $ant->{' apipage'}=$self; if($self->{'Annots'}->is_obj($self->{' apipdf'})) { $self->{' apipdf'}->out_obj($self->{'Annots'}); } return($ant); } =item $page->resource $type, $key, $obj Adds a resource to the page-inheritance tree. B $co->resource('Font',$fontkey,$fontobj); $co->resource('XObject',$imagekey,$imageobj); $co->resource('Shading',$shadekey,$shadeobj); $co->resource('ColorSpace',$spacekey,$speceobj); B You only have to add the required resources, if they are NOT handled by the *font*, *image*, *shade* or *space* methods. =cut sub resource { my ($self, $type, $key, $obj, $force) = @_; my ($dict) = $self->find_prop('Resources'); $dict = $dict || $self->{Resources} || PDFDict(); $dict->realise if(ref($dict)=~/Objind$/); $dict->{$type} = $dict->{$type} || PDFDict(); $dict->{$type}->realise if(ref($dict->{$type})=~/Objind$/); unless(defined $obj) { return($dict->{$type}->{$key} || undef); } else { if($force) { $dict->{$type}->{$key} = $obj; } else { $dict->{$type}->{$key} = $dict->{$type}->{$key} || $obj; } $self->{' apipdf'}->out_obj($dict) if($dict->is_obj($self->{' apipdf'})); $self->{' apipdf'}->out_obj($dict->{$type}) if($dict->{$type}->is_obj($self->{' apipdf'})); $self->{' apipdf'}->out_obj($obj) if($obj->is_obj($self->{' apipdf'})); $self->{' apipdf'}->out_obj($self); return($dict); } } sub ship_out { my ($self, $pdf) = @_; $pdf->ship_out($self); if (defined $self->{'Contents'}) { $pdf->ship_out($self->{'Contents'}->elementsof); } $self; } sub outobjdeep { my ($self, @opts) = @_; foreach my $k (qw/ api apipdf /) { $self->{" $k"}=undef; delete($self->{" $k"}); } $self->SUPER::outobjdeep(@opts); } 1; __END__ =head1 AUTHOR alfred reibenschuh =head1 HISTORY $Log: Page.pm,v $ Revision 2.1 2007/05/08 18:32:09 areibens renamed compress to compressFlate Revision 2.0 2005/11/16 02:16:00 areibens revision workaround for SF cvs import not to screw up CPAN Revision 1.2 2005/11/16 01:27:48 areibens genesis2 Revision 1.1 2005/11/16 01:19:24 areibens genesis Revision 1.15 2005/11/02 18:18:20 fredo added get_(crop/bleed/trim/art)box methods Revision 1.14 2005/08/06 20:59:10 fredo fixed anotation pdf-array again for other braindead softs Revision 1.13 2005/06/17 19:43:47 fredo fixed CPAN modulefile versioning (again) Revision 1.12 2005/06/17 18:53:33 fredo fixed CPAN modulefile versioning (dislikes cvs) Revision 1.11 2005/06/14 12:54:16 fredo fix for existing annotation dictionary (ex. ScanSoft PDF) Revision 1.10 2005/03/14 22:01:05 fredo upd 2005 Revision 1.9 2004/12/16 00:30:52 fredo added no warn for recursion Revision 1.8 2004/09/13 15:27:59 fredo added rotate for acrobat-wise pdf-creators Revision 1.7 2004/06/15 09:11:38 fredo removed cr+lf Revision 1.6 2004/06/09 16:29:12 fredo fixed named page size handling for *box methods Revision 1.5 2004/06/07 19:44:12 fredo cleaned out cr+lf for lf Revision 1.4 2003/12/08 13:05:19 Administrator corrected to proper licencing statement Revision 1.3 2003/11/30 17:17:37 Administrator merged into default Revision 1.2.2.1 2003/11/30 16:56:22 Administrator merged into default Revision 1.2 2003/11/30 11:32:33 Administrator added CVS id/log =cut