📄 api2.pm
字号:
#==================================================================
#
# Copyright 1999-2001 Alfred Reibenschuh <areibens@cpan.org>.
#
# This library is free software; you can redistribute it and/or
# modify it under the same terms as Perl itself.
#
#==================================================================
package PDF::API2;
BEGIN {
use vars qw( $VERSION $hasWeakRef );
( $VERSION ) = '$Revisioning: 20020423.125629 $ ' =~ /\$Revisioning:\s+([^\s]+)/;
eval " use WeakRef; ";
$hasWeakRef= $@ ? 0 : 1;
}
=head1 PDF::API2
=head1 NAME
PDF::API2 - The Next Generation API for creating and modifing PDFs.
=head1 SYNOPSIS
use PDF::API2;
$pdf = PDF::API2->new;
$pdf = PDF::API2->open('some.pdf');
$page = $pdf->page;
$page = $pdf->openpage($pagenum);
$img = $pdf->image('some.jpg');
$font = $pdf->corefont('Times-Roman');
$font = $pdf->psfont('Times-Roman.pfb','Times-Roman.afm');
$font = $pdf->ttfont('TimesNewRoman.ttf');
=cut
use Text::PDF::FileAPI;
use Text::PDF::AFont;
use Text::PDF::Page;
use Text::PDF::Utils;
use Text::PDF::TTFont;
use Text::PDF::TTFont0;
use PDF::API2::Util;
use POSIX qw( ceil floor );
=head1 METHODS
=head2 PDF::API2
=item $pdf = PDF::API->new %opts
Creates a new pdf-file object. If you know beforehand
to save the pdf to file you can give the '-file' option,
to minimize possible memory requirements.
B<Example:>
$pdf = PDF::API2->new();
$pdf = PDF::API2->new(-file => 'ournew.pdf');
=cut
sub new {
my $class=shift(@_);
my %opt=@_;
my $self={};
bless($self,$class);
$self->{pdf}=Text::PDF::FileAPI->new();
$self->{time}='_'.pdfkey(time());
# foreach my $para (keys(%opt)) {
# $self->{$para}=$opt{$para};
# }
$self->{pdf}->{' version'} = 3;
$self->{pages} = Text::PDF::Pages->new($self->{pdf});
weaken($self->{pages}) if($hasWeakRef);
$self->{pages}->proc_set(qw( PDF Text ImageB ImageC ImageI ));
$self->{catalog}=$self->{pdf}->{Root};
weaken($self->{catalog}) if($hasWeakRef);
$self->{pagestack}=[];
my $dig=digest16(digest32($class,$self,%opt));
$self->{pdf}->{'ID'}=PDFArray(PDFStr($dig),PDFStr($dig));
$self->{pdf}->{' id'}=$dig;
if($opt{-file}) {
$self->{' filed'}=$opt{-file};
$self->{pdf}->create_file($opt{-file});
}
return $self;
}
sub proc_pages {
my ($pdf, $pgs) = @_;
my ($pg, $pgref, @pglist);
if(defined($pgs->{Resources})) {
eval {
$pgs->{Resources}->realise;
};
}
foreach $pgref ($pgs->{'Kids'}->elementsof) {
$pg = $pdf->read_obj($pgref);
if ($pg->{'Type'}->val =~ m/^Pages$/o) {
push(@pglist, proc_pages($pdf, $pg));
} else {
$pgref->{' pnum'} = $pcount++;
if(defined($pg->{Resources})) {
eval {
$pg->{Resources}->realise;
};
}
weaken($pgref) if($hasWeakRef);
push (@pglist, $pgref);
}
}
return(@pglist);
}
=item $pdf = PDF::API->open $pdffile
Opens an existing PDF.
=cut
sub open {
my $class=shift(@_);
my $file=shift(@_);
my %opt=@_;
my $self={};
bless($self,$class);
$self->default('Compression',1);
$self->default('subset',1);
$self->default('update',1);
foreach my $para (keys(%opt)) {
$self->default($para,$opt{$para});
}
my $fh=PDF::API2::IOString->new();
$fh->import($file);
$self->{pdf}=Text::PDF::FileAPI->open($fh,1);
$self->{pdf}->{' fname'}=$file;
$self->{pdf}->{'Root'}->realise;
$self->{pages}=$self->{pdf}->{'Root'}->{'Pages'}->realise;
weaken($self->{pages}) if($hasWeakRef);
$self->{pdf}->{' version'} = 3;
my @pages=proc_pages($self->{pdf},$self->{pages});
$self->{pagestack}=[sort {$a->{' pnum'} <=> $b->{' pnum'}} @pages];
$self->{reopened}=1;
my $dig=digest16(digest32($class,$file,%opt));
if(defined $self->{pdf}->{'ID'}){
$self->{pdf}->{'ID'}->realise;
$self->{pdf}->{' id'}=$self->{pdf}->{'ID'}->val->[0]->val;
$self->{pdf}->{'ID'}=PDFArray(PDFStr($self->{pdf}->{' id'}),PDFStr($dig));
} else {
$self->{pdf}->{'ID'}=PDFArray(PDFStr($dig),PDFStr($dig));
$self->{pdf}->{' id'}=$dig;
}
return $self;
}
=item $page = $pdf->page
=item $page = $pdf->page $index
Returns a new page object or inserts-and-returns a new page at $index.
B<Note:> on $index
-1 ... is inserted before the last page
1 ... is inserted before page number 1
0 ... is simply appended
=cut
sub page {
my $self=shift;
my $index=shift || 0;
my $page;
if($index==0) {
$page=PDF::API2::Page->new($self->{pdf},$self->{pages});
} else {
$page=PDF::API2::Page->new($self->{pdf},$self->{pages},$index);
}
$page->{' apipdf'}=$self->{pdf};
weaken($page->{' apipdf'}) if($hasWeakRef);
$page->{' api'}=$self;
weaken($page->{' api'}) if($hasWeakRef);
$self->{pdf}->out_obj($page);
$self->{pdf}->out_obj($self->{pages});
if($index==0) {
push(@{$self->{pagestack}},$page);
} elsif($index<0) {
splice(@{$self->{pagestack}},$index,0,$page);
} else {
splice(@{$self->{pagestack}},$index-1,0,$page);
}
weaken($page) if($hasWeakRef);
return $page;
}
=item $pageobj = $pdf->openpage $index
Returns the pageobject of page $index.
B<Note:> on $index
-1,0 ... returns the last page
1 ... returns page number 1
=cut
sub openpage {
my $self=shift @_;
my $index=shift @_||0;
my $page;
if($index==0) {
$page=@{$self->{pagestack}}[-1];
} elsif($index<0) {
$page=@{$self->{pagestack}}[$index];
} else {
$page=@{$self->{pagestack}}[$index-1];
}
$page=PDF::API2::Page->coerce($self->{pdf},$page) if(ref($page) ne 'PDF::API2::Page');
# $self->{pdf}->out_obj($page);
# $self->{pdf}->out_obj($self->{pages});
$page->{' api'}=$self;
weaken($page->{' api'}) if($hasWeakRef);
$page->{' reopened'}=1;
return($page);
}
=item $pageobj = $pdf->clonepage $sourceindex, $targetindex
Returns the pageobject of page $targetindex, cloned from $sourceindex.
B<Note:> on $index
-1,0 ... returns the last page
1 ... returns page number 1
B<Beware:>
Under some circumstances, this method may cause $pdf->update to die.
These circumstances remain unresolved but previously generated pdfs
via API2 remain unaffected so far.
=cut
sub clonepage {
my $self=shift @_;
my $s_idx=shift @_||0;
my $t_idx=shift @_||0;
$t_idx=0 if($self->pages<$t_idx);
my ($s_page,$t_page);
$s_page=$self->openpage($s_idx);
$t_page=$self->page($t_idx);
$s_page->copy($self->{pdf},$t_page);
####################################################################
if(defined($t_page->{Resources})) {
$t_page->{Resources}->realise if($t_page->{Resources}->is_obj($self->{pdf}));
$t_page->{Resources}=$t_page->{Resources}->copy($self->{pdf});
## $self->{pdf}->new_obj($t_page->{Resources});
$t_page->{Resources}->{' realised'}=1;
}
if(defined($t_page->{Contents})) {
$t_page->fixcontents;
$s_page->fixcontents;
# foreach my $content ($t_page->{Contents}->elementsof) {
# $content->realise;
# }
#
# my $tempobj=$t_page->{Contents};
#
# $t_page->{Contents}=$t_page->{Contents}->copy;
# $self->{pdf}->remove_obj($tempobj);
# foreach my $content ($t_page->{Contents}->elementsof) {
# $self->{pdf}->new_obj($content);
# }
$t_page->{Contents}->{' val'}=[];
$t_page->{Contents}->add_elements($s_page->{Contents}->elementsof);
}
####################################################################
delete $t_page->{' reopened'};
$self->{pdf}->out_obj($t_page);
$self->{pdf}->out_obj($self->{pages});
return($t_page);
}
sub walk_obj {
my ($objs,$spdf,$tpdf,$obj,@key)=@_;
my $tobj;
return($objs->{$obj}) if(defined $objs->{$obj});
if(ref($obj)=~/Objind$/) {
$obj->realise;
}
$tobj=$obj->copy;
$tpdf->new_obj($tobj) if($obj->is_obj($spdf));
$objs->{$obj}=$tobj;
if(ref($obj)=~/Array$/) {
$tobj->{' val'}=[];
foreach my $k ($obj->elementsof) {
$k->realise if(ref($k)=~/Objind$/);
$tobj->add_elements(walk_obj($objs,$spdf,$tpdf,$k));
}
} elsif(ref($obj)=~/Dict$/) {
@key=keys(%{$tobj}) if(scalar @key <1);
foreach my $k (@key) {
$tobj->{$k}=$obj->{$k} if(($k eq ' stream') || ($k eq ' nofilt'));
next if($k=~/^ /);
$tobj->{$k}=walk_obj($objs,$spdf,$tpdf,$obj->{$k});
}
}
delete $tobj->{' streamloc'};
delete $tobj->{' streamsrc'};
return($tobj);
}
=item $pageobj = $pdf->importpage $sourcepdf, $sourceindex, $targetindex
Returns the pageobject of page $targetindex, imported from $sourcepdf,$sourceindex.
B<Note:> on $index
-1,0 ... returns the last page
1 ... returns page number 1
=cut
sub importpage {
my $self=shift @_;
my $s_pdf=shift @_;
my $s_idx=shift @_||0;
my $t_idx=shift @_||0;
$t_idx=0 if($self->pages<$t_idx);
my ($s_page,$t_page);
$s_page=$s_pdf->openpage($s_idx);
$t_page=$self->page($t_idx);
$self->{apiimportcache}=$self->{apiimportcache}||{};
$self->{apiimportcache}->{$s_pdf}=$self->{apiimportcache}->{$s_pdf}||{};
foreach my $k (qw( MediaBox ArtBox TrimBox BleedBox CropBox Rotate B Dur Hid Trans AA PieceInfo LastModified SeparationInfo ID PZ )) {
next unless(defined $s_page->{$k});
$t_page->{$k} = walk_obj($self->{apiimportcache}->{$s_pdf},$s_pdf->{pdf},$self->{pdf},$s_page->{$k});
}
foreach my $k (qw( Thumb Annots )) {
next unless(defined $s_page->{$k});
$t_page->{$k} = walk_obj({},$s_pdf->{pdf},$self->{pdf},$s_page->{$k});
}
foreach my $k (qw( Resources )) {
$s_page->{$k}=$s_page->find_prop($k);
next unless(defined $s_page->{$k});
$t_page->{$k}=PDFDict();
foreach my $sk (qw( ColorSpace XObject ExtGState Font Pattern ProcSet Properties Shading )) {
next unless(defined $s_page->{$k}->{$sk});
$t_page->{$k}->{$sk}=PDFDict();
foreach my $ssk (keys %{$s_page->{$k}->{$sk}}) {
next if($ssk=~/^ /);
$t_page->{$k}->{$sk}->{$ssk} = walk_obj($self->{apiimportcache}->{$s_pdf},$s_pdf->{pdf},$self->{pdf},$s_page->{$k}->{$sk}->{$ssk});
}
}
}
if(defined $s_page->{Contents}) {
$s_page->fixcontents;
$t_page->{Contents}=PDFArray();
my $content=PDFDict();
$self->{pdf}->new_obj($content);
$t_page->{Contents}->add_elements($content);
foreach my $k ($s_page->{Contents}->elementsof) {
$k->realise;
if($k->{Filter}){
$k->{Filter}->realise;
foreach my $flt ($k->{Filter}->elementsof) {
my $fn=$flt->{val};
my $f="Text::PDF::$fn"->new();
$k->{' stream'}=$f->infilt($k->{' stream'},1) if($f);
}
}
$k->{' stream'}=~s/[\x0a\x0d]+/ /gm if($k->{' stream'});
$content->{' stream'}.=$k->{' stream'}." \n";
$content->{'Filter'}=PDFArray(PDFName('FlateDecode'));
}
}
$self->{pdf}->out_obj($t_page);
$self->{pdf}->out_obj($self->{pages});
return($t_page);
}
=item $pagenumber = $pdf->pages
Returns the number of pages in the document.
=cut
sub pages {
my $self=shift @_;
return scalar @{$self->{pagestack}};
}
=item $pdf->mediabox $w, $h
=item $pdf->mediabox $llx, $lly, $urx, $ury
Sets the global mediabox.
=cut
sub mediabox {
my ($self,$x1,$y1,$x2,$y2) = @_;
if(defined $x2) {
$self->{pages}->{'MediaBox'}=PDFArray(
map { PDFNum(float($_)) } ($x1,$y1,$x2,$y2)
);
} else {
$self->{pages}->{'MediaBox'}=PDFArray(
map { PDFNum(float($_)) } (0,0,$x1,$y1)
);
}
$self;
}
=item $pdf->update
Updates a previously "opened" document after all changes have been applied.
=cut
sub update {
my $self=shift @_;
$self->saveas($self->{pdf}->{' fname'});
}
=item $pdf->saveas $file
Saves the document.
=cut
sub saveas {
my ($self,$file)=@_;
if($self->{reopened}) {
$self->{pdf}->append_file;
CORE::open(OUTF,">$file");
binmode(OUTF);
print OUTF ${$self->{pdf}->{' OUTFILE'}->string_ref};
CORE::close(OUTF);
} elsif($self->{' filed'}) {
$self->{pdf}->close_file;
} else {
$self->{pdf}->out_file($file);
}
}
sub save {
my ($self,$file)=@_;
if($self->{reopened}) {
die "invalid method invokation: use 'saveas' instead.";
} elsif($self->{' filed'}) {
$self->{pdf}->close_file;
} else {
die "invalid method invokation: use 'saveas' instead.";
}
}
=item $string = $pdf->stringify
Returns the document in a string.
=cut
sub stringify {
my ($self)=@_;
my $str;
if((defined $self->{reopened}) && ($self->{reopened}==1)) {
$self->{pdf}->append_file;
$str=${$self->{pdf}->{' OUTFILE'}->string_ref};
} else {
my $fh = PDF::API2::IOString->new();
$fh->open();
eval {
$self->{pdf}->out_file($fh);
};
$str=${$fh->string_ref};
$fh->realclose;
}
return($str);
}
sub release {return(undef);}
=item $pdf->end
Destroys the document.
=cut
sub end {
my $self=shift(@_);
$self->{pdf}->release;
foreach my $key (keys %{$self})
{
my $ref = ref($self->{$key});
if ($ref eq '')
{
# Remove scalar value.
delete $self->{$key};
}
elsif ($ref =~ /^Text::PDF::/o)
{
if ($key =~ /parent/io)
{
# Potential circular reference.
delete $self->{$key};
}
else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -