summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/scripts/xetex
diff options
context:
space:
mode:
authorJonathan Kew <jfkthame@googlemail.com>2006-12-07 15:27:30 +0000
committerJonathan Kew <jfkthame@googlemail.com>2006-12-07 15:27:30 +0000
commit45d904fd3b3bd4be3646271b5294010c37ae8223 (patch)
treeed8bcc8099b58284985bfc0fc2e84f6547201b1e /Master/texmf-dist/scripts/xetex
parent53e3fa47b557118c2af7b5c3f8d150b91723bb6f (diff)
update to xdv2pdf (for xetex, macosx only)
git-svn-id: svn://tug.org/texlive/trunk@2609 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/scripts/xetex')
-rwxr-xr-xMaster/texmf-dist/scripts/xetex/perl/lib/PDF/Reuse.pm6005
-rw-r--r--Master/texmf-dist/scripts/xetex/perl/lib/PDF/Reuse/Util.pm326
-rwxr-xr-xMaster/texmf-dist/scripts/xetex/perl/xdv2pdf_mergemarks205
3 files changed, 6536 insertions, 0 deletions
diff --git a/Master/texmf-dist/scripts/xetex/perl/lib/PDF/Reuse.pm b/Master/texmf-dist/scripts/xetex/perl/lib/PDF/Reuse.pm
new file mode 100755
index 00000000000..e4dc259da61
--- /dev/null
+++ b/Master/texmf-dist/scripts/xetex/perl/lib/PDF/Reuse.pm
@@ -0,0 +1,6005 @@
+package PDF::Reuse;
+
+use 5.006;
+use strict;
+use warnings;
+
+require Exporter;
+require Digest::MD5;
+use autouse 'Carp' => qw(carp
+ cluck
+ croak);
+
+# commented out avoid dependency for XeTeX installation
+# use Compress::Zlib qw(compress inflateInit);
+
+use autouse 'Data::Dumper' => qw(Dumper);
+
+# changed for xetex installation to remove file system clutter
+# use AutoLoader 'AUTOLOAD';
+use SelfLoader;
+
+our $VERSION = '0.292';
+our @ISA = qw(Exporter);
+our @EXPORT = qw(prFile
+ prPage
+ prId
+ prIdType
+ prInitVars
+ prEnd
+ prExtract
+ prForm
+ prImage
+ prJpeg
+ prDoc
+ prDocForm
+ prFont
+ prFontSize
+ prGraphState
+ prGetLogBuffer
+ prAdd
+ prBar
+ prText
+ prDocDir
+ prLogDir
+ prLog
+ prVers
+ prCid
+ prJs
+ prInit
+ prField
+ prTouchUp
+ prCompress
+ prMbox
+ prBookmark
+ prStrWidth
+ prLink);
+
+our ($utfil, $slutNod, $formCont, $imSeq, $duplicateInits, $page, $sidObjNr, $sida,
+ $interActive, $NamesSaved, $AARootSaved, $AAPageSaved, $root,
+ $AcroFormSaved, $id, $ldir, $checkId, $formNr, $imageNr,
+ $filnamn, $interAktivSida, $taInterAkt, $type, $runfil, $checkCs,
+ $confuseObj, $compress, $pos, $fontNr, $objNr,
+ $defGState, $gSNr, $pattern, $shading, $colorSpace, $totalCount);
+
+our (@kids, @counts, @formBox, @objekt, @parents, @aktuellFont, @skapa,
+ @jsfiler, @inits, @bookmarks, @annots);
+
+our ( %old, %oldObject, %resurser, %form, %image, %objRef, %nyaFunk, %fontSource,
+ %sidFont, %sidXObject, %sidExtGState, %font, %intAct, %fields, %script,
+ %initScript, %sidPattern, %sidShading, %sidColorSpace, %knownToFile,
+ %processed, %embedded, %dummy, %behandlad, %unZipped, %links, %prefs);
+
+our $stream = '';
+our $idTyp = '';
+our $ddir = '';
+our $log = '';
+
+#########################
+# Konstanter för objekt
+#########################
+
+use constant oNR => 0;
+use constant oPOS => 1;
+use constant oSTREAMP => 2;
+use constant oKIDS => 3;
+use constant oFORM => 4;
+use constant oIMAGENR => 5;
+use constant oWIDTH => 6;
+use constant oHEIGHT => 7;
+use constant oTYPE => 8;
+use constant oNAME => 9;
+
+###################################
+# Konstanter för formulär
+###################################
+
+use constant fOBJ => 0;
+use constant fRESOURCE => 1;
+use constant fBBOX => 2;
+use constant fIMAGES => 3;
+use constant fMAIN => 4;
+use constant fKIDS => 5;
+use constant fNOKIDS => 6;
+use constant fID => 7;
+use constant fVALID => 8;
+
+####################################
+# Konstanter för images
+####################################
+
+use constant imWIDTH => 0;
+use constant imHEIGHT => 1;
+use constant imXPOS => 2;
+use constant imYPOS => 3;
+use constant imXSCALE => 4;
+use constant imYSCALE => 5;
+use constant imIMAGENO => 6;
+
+#####################################
+# Konstanter för interaktiva objekt
+#####################################
+
+use constant iNAMES => 1;
+use constant iACROFORM => 2;
+use constant iAAROOT => 3;
+use constant iANNOTS => 4;
+use constant iSTARTSIDA => 5;
+use constant iAAPAGE => 6;
+
+#####################################
+# Konstanter för fonter
+#####################################
+
+use constant foREFOBJ => 0;
+use constant foINTNAMN => 1;
+use constant foEXTNAMN => 2;
+use constant foORIGINALNR => 3;
+use constant foSOURCE => 4;
+
+##########
+# Övrigt
+##########
+
+use constant IS_MODPERL => $ENV{MOD_PERL}; # For mod_perl 1.
+ # For mod_perl 2 pass $r to prFile()
+our $touchUp = 1;
+
+our %stdFont =
+ ('Times-Roman' => 'Times-Roman',
+ 'Times-Bold' => 'Times-Bold',
+ 'Times-Italic' => 'Times-Italic',
+ 'Times-BoldItalic' => 'Times-BoldItalic',
+ 'Courier' => 'Courier',
+ 'Courier-Bold' => 'Courier-Bold',
+ 'Courier-Oblique' => 'Courier-Oblique',
+ 'Courier-BoldOblique' => 'Courier-BoldOblique',
+ 'Helvetica' => 'Helvetica',
+ 'Helvetica-Bold' => 'Helvetica-Bold',
+ 'Helvetica-Oblique' => 'Helvetica-Oblique',
+ 'Helvetica-BoldOblique' => 'Helvetica-BoldOblique',
+ 'Symbol' => 'Symbol',
+ 'ZapfDingbats' => 'ZapfDingbats',
+ 'TR' => 'Times-Roman',
+ 'TB' => 'Times-Bold',
+ 'TI' => 'Times-Italic',
+ 'TBI' => 'Times-BoldItalic',
+ 'C' => 'Courier',
+ 'CB' => 'Courier-Bold',
+ 'CO' => 'Courier-Oblique',
+ 'CBO' => 'Courier-BoldOblique',
+ 'H' => 'Helvetica',
+ 'HB' => 'Helvetica-Bold',
+ 'HO' => 'Helvetica-Oblique',
+ 'HBO' => 'Helvetica-BoldOblique',
+ 'S' => 'Symbol',
+ 'Z' => 'ZapfDingbats');
+
+our $genLowerX = 0;
+our $genLowerY = 0;
+our $genUpperX = 595,
+our $genUpperY = 842;
+our $genFont = 'Helvetica';
+our $fontSize = 12;
+
+keys(%resurser) = 10;
+
+sub prFont
+{ my $nyFont = shift;
+ my ($intnamn, $extnamn, $objektnr, $oldIntNamn, $oldExtNamn);
+
+ if (! $pos)
+ { errLog("No output file, you have to call prFile first");
+ }
+ $oldIntNamn = $aktuellFont[foINTNAMN];
+ $oldExtNamn = $aktuellFont[foEXTNAMN];
+ if ($nyFont)
+ { ($intnamn, $extnamn, $objektnr) = findFont($nyFont);
+ }
+ else
+ { $intnamn = $aktuellFont[foINTNAMN];
+ $extnamn = $aktuellFont[foEXTNAMN];
+ }
+ if ($runfil)
+ { $log .= "Font~$nyFont\n";
+ }
+ if (wantarray)
+ { return ($intnamn, $extnamn, $oldIntNamn, $oldExtNamn);
+ }
+ else
+ { return $intnamn;
+ }
+}
+
+sub prFontSize
+{ my $fSize = shift || 12;
+ my $oldFontSize = $fontSize;
+ if ($fSize =~ m'\d+\.?\d*'o)
+ { $fontSize = $fSize;
+ if ($runfil)
+ { $log .= "FontSize~$fontSize\n";
+ }
+ }
+ if (! $pos)
+ { errLog("No output file, you have to call prFile first");
+ }
+
+ return ($fontSize, $oldFontSize);
+}
+
+sub prFile
+{ if ($pos)
+ { prEnd();
+ close UTFIL;
+ }
+ %prefs = ();
+ my $param = shift;
+ if (ref($param) eq 'HASH')
+ { $filnamn = '-';
+ for (keys %{$param})
+ { my $key = lc($_);
+ if ($key eq 'name')
+ { $filnamn = $param->{$_}; }
+ elsif (($key eq 'hidetoolbar')
+ || ($key eq 'hidemenubar')
+ || ($key eq 'hidewindowui')
+ || ($key eq 'fitwindow')
+ || ($key eq 'centerwindow'))
+ { $prefs{$key} = $param->{$_};
+ }
+ }
+ }
+ else
+ { $filnamn = $param || '-';
+ $prefs{hidetoolbar} = $_[1] if defined $_[1];
+ $prefs{hidemenubar} = $_[2] if defined $_[2];
+ $prefs{hidewindowui} = $_[3] if defined $_[3];
+ $prefs{fitwindow} = $_[4] if defined $_[4];
+ $prefs{centerwindow} = $_[5] if defined $_[5];
+ }
+ my $kortNamn;
+ if ($filnamn ne '-')
+ { my $ri = rindex($filnamn,'/');
+ if ($ri > 0)
+ { $kortNamn = substr($filnamn, ($ri + 1));
+ $utfil = $ddir ? $ddir . $kortNamn : $filnamn;
+ }
+ else
+ { $utfil = $ddir ? $ddir . $filnamn : $filnamn;
+ }
+ $ri = rindex($utfil,'/');
+ if ($ri > 0)
+ { my $dirdel = substr($utfil,0,$ri);
+ if (! -e $dirdel)
+ { mkdir $dirdel || errLog("Couldn't create dir $dirdel, $!");
+ }
+ }
+ else
+ { $ri = rindex($utfil,'\\');
+ if ($ri > 0)
+ { my $dirdel = substr($utfil,0,$ri);
+ if (! -e $dirdel)
+ { mkdir $dirdel || errLog("Couldn't create dir $dirdel, $!");
+ }
+ }
+ }
+ }
+ else
+ { $utfil = $filnamn;
+ }
+ if (ref $utfil eq 'Apache::RequestRec') # mod_perl 2
+ { tie *UTFIL, $utfil;
+ }
+ elsif (IS_MODPERL && $utfil eq '-') # mod_perl 1
+ { tie *UTFIL, 'Apache';
+ }
+ else
+ { open (UTFIL, ">$utfil") || errLog("Couldn't open file $utfil, $!");
+ }
+ binmode UTFIL;
+ my $utrad = "\%PDF-1.4\n\%\â\ã\Ï\Ó\n";
+
+ $pos = syswrite UTFIL, $utrad;
+
+ if (defined $ldir)
+ { if ($utfil eq '-')
+ { $kortNamn = 'stdout';
+ }
+ if ($kortNamn)
+ { $runfil = $ldir . $kortNamn . '.dat';
+ }
+ else
+ { $runfil = $ldir . $filnamn . '.dat';
+ }
+ open (RUNFIL, ">>$runfil") || errLog("Couldn't open loggfile $runfil, $!");
+ $log .= "Vers~$VERSION\n";
+ }
+
+
+ @parents = ();
+ @kids = ();
+ @counts = ();
+ @objekt = ();
+ $objNr = 2; # Reserverat objekt 1 för root och 2 för initial sidnod
+ $parents[0] = 2;
+ $page = 0;
+ $formNr = 0;
+ $imageNr = 0;
+ $fontNr = 0;
+ $gSNr = 0;
+ $pattern = 0;
+ $shading = 0;
+ $colorSpace = 0;
+ $sida = 0;
+ %font = ();
+ %resurser = ();
+ %fields = ();
+ @jsfiler = ();
+ @inits = ();
+ %nyaFunk = ();
+ %objRef = ();
+ %knownToFile = ();
+ @aktuellFont = ();
+ %old = ();
+ %behandlad = ();
+ @bookmarks = ();
+ %links = ();
+ undef $defGState;
+ undef $interActive;
+ undef $NamesSaved;
+ undef $AARootSaved;
+ undef $AcroFormSaved;
+ $checkId = '';
+ undef $duplicateInits;
+ undef $confuseObj;
+ $fontSize = 12;
+ $genLowerX = 0;
+ $genLowerY = 0;
+ $genUpperX = 595,
+ $genUpperY = 842;
+
+ prPage(1);
+ $stream = ' ';
+ if ($runfil)
+ { $filnamn = prep($filnamn);
+ $log .= "File~$filnamn";
+ $log .= (exists $prefs{hidetoolbar}) ? "~$prefs{hidetoolbar}" : '~';
+ $log .= (exists $prefs{hidemenubar}) ? "~$prefs{hidemenubar}" : '~';
+ $log .= (exists $prefs{hidewindowui}) ? "~$prefs{hidewindowui}" : '~';
+ $log .= (exists $prefs{fitwindow}) ? "~$prefs{fitwindow}" : '~';
+ $log .= (exists $prefs{centerwindow}) ? "~$prefs{centerwindow}" : "~\n";
+ }
+ 1;
+}
+
+
+sub prPage
+{ my $noLogg = shift;
+ if ((defined $stream) && (length($stream) > 0))
+ { skrivSida();
+ }
+
+ $page++;
+ $objNr++;
+ $sidObjNr = $objNr;
+
+ #
+ # Resurserna nollställs
+ #
+
+ %sidXObject = ();
+ %sidExtGState = ();
+ %sidFont = ();
+ %sidPattern = ();
+ %sidShading = ();
+ %sidColorSpace = ();
+ @annots = ();
+
+ undef $interAktivSida;
+ undef $checkCs;
+ if (($runfil) && (! $noLogg))
+ { $log .= "Page~\n";
+ print RUNFIL $log;
+ $log = '';
+ }
+ if (! $pos)
+ { errLog("No output file, you have to call prFile first");
+ }
+ 1;
+
+}
+
+sub prText
+{ my $xFrom = shift;
+ my $y = shift;
+ my $TxT = shift;
+ my $how = shift || '';
+
+ my ($xTo, $rotate);
+ if (! defined $TxT)
+ { $TxT = '';
+ }
+
+ if (($xFrom !~ m'[\d\.]+'o) || (! defined $xFrom))
+ { errLog("Illegal x-position for text: $xFrom");
+ }
+ if (($y !~ m'[\d\.]+'o) || (! defined $y))
+ { errLog("Illegal y-position for text: $y");
+ }
+
+ if ($runfil)
+ { my $Texten = prep($TxT);
+ $log .= "Text~$xFrom~$y~$Texten~$how\n";
+ }
+
+ if (! $aktuellFont[foINTNAMN])
+ { findFont();
+ }
+ my $Font = $aktuellFont[foINTNAMN]; # Namn i strömmen
+ $sidFont{$Font} = $aktuellFont[foREFOBJ];
+
+ if ($how)
+ { $how = lc($how);
+ if ($how eq 'right')
+ { $xTo = $xFrom;
+ $xFrom -= prStrWidth($TxT, $aktuellFont[foEXTNAMN], $fontSize);
+ }
+ elsif ($how eq 'center')
+ { my $width = prStrWidth($TxT, $aktuellFont[foEXTNAMN], $fontSize);
+ $xTo = $xFrom + ($width / 2);
+ $xFrom = $xTo - $width;
+ }
+ elsif (($how ne 'left') && ($how =~ m'\d'o))
+ { $rotate = $how;
+ }
+ elsif (wantarray)
+ { $xTo = $xFrom + prStrWidth($TxT, $Font, $fontSize);
+ }
+ }
+ elsif (wantarray)
+ { $xTo = $xFrom + prStrWidth($TxT, $Font, $fontSize);
+ }
+
+ $TxT =~ s|\(|\\(|gos;
+ $TxT =~ s|\)|\\)|gos;
+
+ unless ($rotate)
+ { $stream .= "\nBT /$Font $fontSize Tf ";
+ $stream .= "$xFrom $y Td \($TxT\) Tj ET\n";
+ }
+ else
+ { if ($rotate =~ m'q(\d)'oi)
+ { if ($1 eq '1')
+ { $rotate = 270;
+ }
+ elsif ($1 eq '2')
+ { $rotate = 180;
+ }
+ else
+ { $rotate = 90;
+ }
+ }
+ my $radian = sprintf("%.6f", $rotate / 57.2957795); # approx.
+ my $Cos = sprintf("%.6f", cos($radian));
+ my $Sin = sprintf("%.6f", sin($radian));
+ my $negSin = $Sin * -1;
+ $stream .= "BT /$Font $fontSize Tf\n"
+ . "$Cos $Sin $negSin $Cos $xFrom $y Tm\n"
+ . "($TxT) Tj ET\n";
+ }
+
+ if (! $pos)
+ { errLog("No output file, you have to call prFile first");
+ }
+
+ if (wantarray)
+ { return ($xFrom, $xTo);
+ }
+ else
+ { return 1;
+ }
+}
+
+
+sub prAdd
+{ my $contents = shift;
+ $stream .= "\n$contents\n";
+ if ($runfil)
+ { $contents = prep($contents);
+ $log .= "Add~$contents\n";
+ }
+ $checkCs = 1;
+ if (! $pos)
+ { errLog("No output file, you have to call prFile first");
+ }
+ 1;
+}
+
+##########################
+# Ett grafiskt "formulär"
+##########################
+
+sub prForm
+{ my ($sidnr, $adjust, $effect, $tolerant, $infil, $x, $y, $size, $xsize,
+ $ysize, $rotate);
+ my $param = shift;
+ if (ref($param) eq 'HASH')
+ { $infil = $param->{'file'};
+ $sidnr = $param->{'page'} || 1;
+ $adjust = $param->{'adjust'} || '';
+ $effect = $param->{'effect'} || 'print';
+ $tolerant = $param->{'tolerant'} || '';
+ $x = $param->{'x'} || 0;
+ $y = $param->{'y'} || 0;
+ $rotate = $param->{'rotate'} || 0;
+ $size = $param->{'size'} || 1;
+ $xsize = $param->{'xsize'} || 1;
+ $ysize = $param->{'ysize'} || 1;
+ }
+ else
+ { $infil = $param;
+ $sidnr = shift || 1;
+ $adjust = shift || '';
+ $effect = shift || 'print';
+ $tolerant = shift || '';
+ $x = shift || 0;
+ $y = shift || 0;
+ $rotate = shift || 0;
+ $size = shift || 1;
+ $xsize = shift || 1;
+ $ysize = shift || 1;
+ }
+
+ my $refNr;
+ my $namn;
+ $type = 'form';
+ my $fSource = $infil . '_' . $sidnr;
+ if (! exists $form{$fSource})
+ { $formNr++;
+ $namn = 'Fm' . $formNr;
+ $knownToFile{$fSource} = $namn;
+ my $action;
+ if ($effect eq 'load')
+ { $action = 'load'
+ }
+ else
+ { $action = 'print'
+ }
+ $refNr = getPage($infil, $sidnr, $action);
+ if ($refNr)
+ { $objRef{$namn} = $refNr;
+ }
+ else
+ { if ($tolerant)
+ { if ((defined $refNr) && ($refNr eq '0')) # Sidnumret existerar inte, men ok
+ { $namn = '0';
+ }
+ else
+ { undef $namn; # Sidan kan inte användas som form
+ }
+ }
+ elsif (! defined $refNr)
+ { my $mess = "$fSource can't be used as a form. Try e.g. to\n"
+ . "save the file as postscript, and redistill\n";
+ errLog($mess);
+ }
+ else
+ { errLog("File : $infil Page: $sidnr doesn't exist");
+ }
+ }
+ }
+ else
+ { if (exists $knownToFile{$fSource})
+ { $namn = $knownToFile{$fSource};
+ }
+ else
+ { $formNr++;
+ $namn = 'Fm' . $formNr;
+ $knownToFile{$fSource} = $namn;
+ }
+ if (exists $objRef{$namn})
+ { $refNr = $objRef{$namn};
+ }
+ else
+ { if (! $form{$fSource}[fVALID])
+ { my $mess = "$fSource can't be used as a form. Try e.g. to\n"
+ . "save the file as postscript, and redistill\n";
+ if ($tolerant)
+ { cluck $mess;
+ undef $namn;
+ }
+ else
+ { errLog($mess);
+ }
+ }
+ elsif ($effect ne 'load')
+ { $refNr = byggForm($infil, $sidnr);
+ $objRef{$namn} = $refNr;
+ }
+ }
+ }
+ my @BBox = @{$form{$fSource}[fBBOX]} if ($refNr);
+ if (($effect eq 'print') && ($form{$fSource}[fVALID]) && ($refNr))
+ { if (! defined $defGState)
+ { prDefaultGrState();
+ }
+
+ if ($adjust)
+ { $stream .= "q\n";
+ $stream .= fillTheForm(@BBox, $adjust);
+ $stream .= "\n/Gs0 gs\n";
+ $stream .= "/$namn Do\n";
+ $stream .= "Q\n";
+ }
+ elsif (($x) || ($y) || ($rotate) || ($size != 1)
+ || ($xsize != 1) || ($ysize != 1))
+ { $stream .= "q\n";
+ $stream .= calcMatrix($x, $y, $rotate, $size,
+ $xsize, $ysize, $BBox[2], $BBox[3]);
+ $stream .= "\n/Gs0 gs\n";
+ $stream .= "/$namn Do\n";
+ $stream .= "Q\n";
+ }
+ else
+ { $stream .= "\n/Gs0 gs\n";
+ $stream .= "/$namn Do\n";
+
+ }
+ $sidXObject{$namn} = $refNr;
+ $sidExtGState{'Gs0'} = $defGState;
+ }
+ if ($runfil)
+ { $infil = prep($infil);
+ $log .= "Form~$infil~$sidnr~$adjust~$effect~$tolerant";
+ $log .= "~$x~$y~$rotate~$size~$xsize~$ysize\n";
+ }
+ if (! $pos)
+ { errLog("No output file, you have to call prFile first");
+ }
+ if (($effect ne 'print') && ($effect ne 'add'))
+ { undef $namn;
+ }
+ if (wantarray)
+ { my $images = 0;
+ if (exists $form{$fSource}[fIMAGES])
+ { $images = scalar(@{$form{$fSource}[fIMAGES]});
+ }
+ return ($namn, $BBox[0], $BBox[1], $BBox[2],
+ $BBox[3], $images);
+ }
+ else
+ { return $namn;
+ }
+}
+
+
+
+##########################################################
+sub prDefaultGrState
+##########################################################
+{ $objNr++;
+ $defGState = $objNr;
+ if (! $pos)
+ { errLog("No output file, you have to call prFile first");
+ }
+
+ $objekt[$objNr] = $pos;
+ my $utrad = "$objNr 0 obj" . '<</Type/ExtGState/SA false/SM 0.02/TR2 /Default'
+ . ">>endobj\n";
+ $pos += syswrite UTFIL, $utrad;
+ $objRef{'Gs0'} = $objNr;
+ return ('Gs0', $defGState);
+}
+
+######################################################
+# En font lokaliseras och fontobjektet skrivs ev. ut
+######################################################
+
+sub findFont()
+{ no warnings;
+ my $Font = shift || '';
+
+ if (! (exists $fontSource{$Font})) # Fonten måste skapas
+ { if (exists $stdFont{$Font})
+ { $Font = $stdFont{$Font};}
+ else
+ { $Font = $genFont; } # Helvetica sätts om inget annat finns
+ if (! (exists $font{$Font}))
+ { $objNr++;
+ $fontNr++;
+ my $fontAbbr = 'Ft' . $fontNr;
+ my $fontObjekt = "$objNr 0 obj<</Type/Font/Subtype/Type1" .
+ "/BaseFont/$Font/Encoding/WinAnsiEncoding>>endobj\n";
+ $font{$Font}[foINTNAMN] = $fontAbbr;
+ $font{$Font}[foREFOBJ] = $objNr;
+ $objRef{$fontAbbr} = $objNr;
+ $fontSource{$Font}[foSOURCE] = 'Standard';
+ $objekt[$objNr] = $pos;
+ $pos += syswrite UTFIL, $fontObjekt;
+ }
+ }
+ else
+ { if (defined $font{$Font}[foREFOBJ]) # Finns redan i filen
+ { ; }
+ else
+ { if ($fontSource{$Font}[foSOURCE] eq 'Standard')
+ { $objNr++;
+ $fontNr++;
+ my $fontAbbr = 'Ft' . $fontNr;
+ my $fontObjekt = "$objNr 0 obj<</Type/Font/Subtype/Type1" .
+ "/BaseFont/$Font/Encoding/WinAnsiEncoding>>endobj\n";
+ $font{$Font}[foINTNAMN] = $fontAbbr;
+ $font{$Font}[foREFOBJ] = $objNr;
+ $objRef{$fontAbbr} = $objNr;
+ $objekt[$objNr] = $pos;
+ $pos += syswrite UTFIL, $fontObjekt;
+ }
+ else
+ { my $fSource = $fontSource{$Font}[foSOURCE];
+ my $ri = rindex($fSource, '_');
+ my $Source = substr($fSource, 0, $ri);
+ my $Page = substr($fSource, ($ri + 1));
+
+ if (! $fontSource{$Font}[foORIGINALNR])
+ { errLog("Couldn't find $Font, aborts");
+ }
+ else
+ { my $namn = extractObject($Source, $Page,
+ $fontSource{$Font}[foORIGINALNR], 'Font');
+ }
+ }
+ }
+ }
+
+ $aktuellFont[foEXTNAMN] = $Font;
+ $aktuellFont[foREFOBJ] = $font{$Font}[foREFOBJ];
+ $aktuellFont[foINTNAMN] = $font{$Font}[foINTNAMN];
+
+ $sidFont{$aktuellFont[foINTNAMN]} = $aktuellFont[foREFOBJ];
+ if (! $pos)
+ { errLog("No output file, you have to call prFile first");
+ }
+
+ return ($aktuellFont[foINTNAMN], $aktuellFont[foEXTNAMN], $aktuellFont[foREFOBJ]);
+}
+
+sub skrivSida
+{ my ($compressFlag, $streamObjekt, @extObj);
+ if ($checkCs)
+ { @extObj = ($stream =~ m'/(\S+)\s*'gso);
+ checkContentStream(@extObj);
+ }
+ if (( $compress ) && ( length($stream) > 99 ))
+ { my $output = compress($stream);
+ if ((length($output) > 25) && (length($output) < (length($stream))))
+ { $stream = $output;
+ $compressFlag = 1;
+ }
+ }
+
+ if (! $parents[0])
+ { $objNr++;
+ $parents[0] = $objNr;
+ }
+ my $parent = $parents[0];
+
+ ##########################################
+ # Interaktiva funktioner läggs ev. till
+ ##########################################
+
+ if ($interAktivSida)
+ { my ($infil, $sidnr) = split(/\s+/, $interActive);
+ ($NamesSaved, $AARootSaved, $AAPageSaved, $AcroFormSaved)
+ = AcroFormsEtc($infil, $sidnr);
+ }
+
+ ##########################
+ # Skapa resursdictionary
+ ##########################
+ my $resursDict = "/ProcSet[/PDF/Text]";
+ if (scalar %sidFont)
+ { $resursDict .= '/Font << ';
+ my $i = 0;
+ for (keys %sidFont)
+ { $resursDict .= "/$_ $sidFont{$_} 0 R";
+ }
+
+ $resursDict .= " >>";
+ }
+ if (scalar %sidXObject)
+ { $resursDict .= '/XObject<<';
+ for (keys %sidXObject)
+ { $resursDict .= "/$_ $sidXObject{$_} 0 R";
+ }
+ $resursDict .= ">>";
+ }
+ if (scalar %sidExtGState)
+ { $resursDict .= '/ExtGState<<';
+ for (keys %sidExtGState)
+ { $resursDict .= "\/$_ $sidExtGState{$_} 0 R";
+ }
+ $resursDict .= ">>";
+ }
+ if (scalar %sidPattern)
+ { $resursDict .= '/Pattern<<';
+ for (keys %sidPattern)
+ { $resursDict .= "/$_ $sidPattern{$_} 0 R";
+ }
+ $resursDict .= ">>";
+ }
+ if (scalar %sidShading)
+ { $resursDict .= '/Shading<<';
+ for (keys %sidShading)
+ { $resursDict .= "/$_ $sidShading{$_} 0 R";
+ }
+ $resursDict .= ">>";
+ }
+ if (scalar %sidColorSpace)
+ { $resursDict .= '/ColorSpace<<';
+ for (keys %sidColorSpace)
+ { $resursDict .= "/$_ $sidColorSpace{$_} 0 R";
+ }
+ $resursDict .= ">>";
+ }
+
+
+ my $resursObjekt;
+
+ if (exists $resurser{$resursDict})
+ { $resursObjekt = $resurser{$resursDict}; # Fanns ett identiskt,
+ } # använd det
+ else
+ { $objNr++;
+ if ( keys(%resurser) < 10)
+ { $resurser{$resursDict} = $objNr; # Spara 10 första resursobjekten
+ }
+ $resursObjekt = $objNr;
+ $objekt[$objNr] = $pos;
+ $resursDict = "$objNr 0 obj<<$resursDict>>endobj\n";
+ $pos += syswrite UTFIL, $resursDict ;
+ }
+ my $sidObjekt;
+
+ if (! $touchUp)
+ { #
+ # Contents objektet skapas
+ #
+
+ my $devX = "900";
+ my $devY = "900";
+
+ my $mellanObjekt = '<</Type/XObject/Subtype/Form/FormType 1';
+ if (defined $resursObjekt)
+ { $mellanObjekt .= "/Resources $resursObjekt 0 R";
+ }
+ $mellanObjekt .= "/BBox \[$genLowerX $genLowerY $genUpperX $genUpperY\]" .
+ "/Matrix \[ 1 0 0 1 -$devX -$devY \]";
+
+ my $langd = length($stream);
+
+ $objNr++;
+ $objekt[$objNr] = $pos;
+ if (! $compressFlag)
+ { $mellanObjekt = "$objNr 0 obj\n$mellanObjekt/Length $langd>>stream\n"
+ . $stream;
+ $mellanObjekt .= "endstream\nendobj\n";
+ }
+ else
+ { $stream = "\n" . $stream . "\n";
+ $langd++;
+ $mellanObjekt = "$objNr 0 obj\n$mellanObjekt/Filter/FlateDecode"
+ . "/Length $langd>>stream" . $stream;
+ $mellanObjekt .= "endstream\nendobj\n";
+ }
+
+ $pos += syswrite UTFIL, $mellanObjekt;
+ $mellanObjekt = $objNr;
+
+ if (! defined $confuseObj)
+ { $objNr++;
+ $objekt[$objNr] = $pos;
+
+ $stream = "\nq\n1 0 0 1 $devX $devY cm\n/Xwq Do\nq\n";
+ $langd = length($stream);
+ $confuseObj = $objNr;
+ $stream = "$objNr 0 obj<</Length $langd>>stream\n" . "$stream";
+ $stream .= "\nendstream\nendobj\n";
+ $pos += syswrite UTFIL, $stream;
+ }
+ $sidObjekt = "$sidObjNr 0 obj\n<</Type/Page/Parent $parent 0 R/Contents $confuseObj 0 R"
+ . "/MediaBox \[$genLowerX $genLowerY $genUpperX $genUpperY\]"
+ . "/Resources <</ProcSet[/PDF/Text]/XObject<</Xwq $mellanObjekt 0 R>>>>";
+ }
+ else
+ { my $langd = length($stream);
+
+ $objNr++;
+ $objekt[$objNr] = $pos;
+ if (! $compressFlag)
+ { $streamObjekt = "$objNr 0 obj<</Length $langd>>stream\n" . $stream;
+ $streamObjekt .= "\nendstream\nendobj\n";
+ }
+ else
+ { $stream = "\n" . $stream . "\n";
+ $langd++;
+
+ $streamObjekt = "$objNr 0 obj<</Filter/FlateDecode"
+ . "/Length $langd>>stream" . $stream;
+ $streamObjekt .= "endstream\nendobj\n";
+ }
+
+ $pos += syswrite UTFIL, $streamObjekt;
+ $streamObjekt = $objNr;
+ ##################################
+ # Så skapas och skrivs sidobjektet
+ ##################################
+
+ $sidObjekt = "$sidObjNr 0 obj<</Type/Page/Parent $parent 0 R/Contents $streamObjekt 0 R"
+ . "/MediaBox \[$genLowerX $genLowerY $genUpperX $genUpperY\]"
+ . "/Resources $resursObjekt 0 R";
+ }
+
+ $stream = '';
+
+ my $tSida = $sida + 1;
+ if ((@annots)
+ || (defined @{$links{'-1'}})
+ || (defined @{$links{$tSida}}))
+ { $sidObjekt .= '/Annots ' . mergeLinks() . ' 0 R';
+ }
+ if (defined $AAPageSaved)
+ { $sidObjekt .= "/AA $AAPageSaved";
+ undef $AAPageSaved;
+ }
+ $sidObjekt .= ">>endobj\n";
+ $objekt[$sidObjNr] = $pos;
+ $pos += syswrite UTFIL, $sidObjekt;
+ push @{$kids[0]}, $sidObjNr;
+ $sida++;
+ $counts[0]++;
+ if ($counts[0] > 9)
+ { ordnaNoder(8); }
+}
+
+
+sub prEnd
+{ if (! $pos)
+ { return;
+ }
+ if ($stream)
+ { skrivSida(); }
+ skrivUtNoder();
+
+ ###################
+ # Skriv root
+ ###################
+
+ if (! defined $objekt[$objNr])
+ { $objNr--; # reserverat sidobjektnr utnyttjades aldrig
+ }
+
+ my $utrad = "1 0 obj<</Type/Catalog/Pages $slutNod 0 R";
+ if (defined $NamesSaved)
+ { $utrad .= "\/Names $NamesSaved 0 R\n";
+ }
+ elsif ((scalar %fields) || (scalar @jsfiler))
+ { $utrad .= "\/Names " . behandlaNames() . " 0 R\n";
+ }
+ if (defined $AARootSaved)
+ { $utrad .= "/AA $AARootSaved\n";
+ }
+ if ((scalar @inits) || (scalar %fields))
+ { my $nyttANr = skrivKedja();
+ $utrad .= "/OpenAction $nyttANr 0 R";
+ }
+
+ if (defined $AcroFormSaved)
+ { $utrad .= "/AcroForm $AcroFormSaved\n";
+ }
+
+ if (scalar @bookmarks)
+ { my $outLine = ordnaBookmarks();
+ $utrad .= "/Outlines $outLine 0 R\n";
+ }
+ if (scalar %prefs)
+ { $utrad .= '/ViewerPreferences << ';
+ if (exists $prefs{hidetoolbar})
+ { $utrad .= ($prefs{hidetoolbar}) ? '/HideToolbar true'
+ : '/HideToolbar false';
+ }
+ if (exists $prefs{hidemenubar})
+ { $utrad .= ($prefs{hidemenubar}) ? '/HideMenubar true'
+ : '/HideMenubar false';
+ }
+ if (exists $prefs{hidewindowui})
+ { $utrad .= ($prefs{hidewindowui}) ? '/HideWindowUI true'
+ : '/HideWindowUI false';
+ }
+ if (exists $prefs{fitwindow})
+ { $utrad .= ($prefs{fitwindow}) ? '/FitWindow true'
+ : '/FitWindow false';
+ }
+ if (exists $prefs{centerwindow})
+ { $utrad .= ($prefs{centerwindow}) ? '/CenterWindow true'
+ : '/CenterWindow false';
+ }
+ $utrad .= '>> ';
+ }
+
+ $utrad .= ">>endobj\n";
+
+ $objekt[1] = $pos;
+ $pos += syswrite UTFIL, $utrad;
+ my $antal = $#objekt;
+ my $startxref = $pos;
+ my $xrefAntal = $antal + 1;
+ $pos += syswrite UTFIL, "xref\n";
+ $pos += syswrite UTFIL, "0 $xrefAntal\n";
+ $pos += syswrite UTFIL, "0000000000 65535 f \n";
+
+ for (my $i = 1; $i <= $antal; $i++)
+ { $utrad = sprintf "%.10d 00000 n \n", $objekt[$i];
+ $pos += syswrite UTFIL, $utrad;
+ }
+
+ $utrad = "trailer\n<<\n/Size $xrefAntal\n/Root 1 0 R\n";
+ if ($idTyp ne 'None')
+ { my ($id1, $id2) = definieraId();
+ $utrad .= "/ID [<$id1><$id2>]\n";
+ $log .= "IdType~rep\n";
+ $log .= "Id~$id1\n";
+ }
+ $utrad .= ">>\nstartxref\n$startxref\n";
+ $pos += syswrite UTFIL, $utrad;
+ $pos += syswrite UTFIL, "%%EOF\n";
+ close UTFIL;
+
+ if ($runfil)
+ { if ($log)
+ { print RUNFIL $log;
+ }
+ close RUNFIL;
+ }
+ $log = '';
+ $runfil = '';
+ $pos = 0;
+ 1;
+}
+
+sub ordnaNoder
+{ my $antBarn = shift;
+ my $i = 0;
+ my $j = 1;
+ my $vektor;
+
+ while ($antBarn < $#{$kids[$i]})
+ { #
+ # Skriv ut aktuell förälder
+ # flytta till nästa nivå
+ #
+ $vektor = '[';
+
+ for (@{$kids[$i]})
+ { $vektor .= "$_ 0 R "; }
+ $vektor .= ']';
+
+ if (! $parents[$j])
+ { $objNr++;
+ $parents[$j] = $objNr;
+ }
+
+ my $nodObjekt;
+ $nodObjekt = "$parents[$i] 0 obj<</Type/Pages/Parent $parents[$j] 0 R\n/Kids $vektor\n/Count $counts[$i]>>endobj\n";
+
+ $objekt[$parents[$i]] = $pos;
+ $pos += syswrite UTFIL, $nodObjekt;
+ $counts[$j] += $counts[$i];
+ $counts[$i] = 0;
+ $kids[$i] = [];
+ push @{$kids[$j]}, $parents[$i];
+ undef $parents[$i];
+ $i++;
+ $j++;
+ }
+}
+
+sub skrivUtNoder
+{ no warnings;
+ my ($i, $j, $vektor, $nodObjekt);
+ my $si = -1;
+ #
+ # Hitta slutnoden
+ #
+ for (@parents)
+ { $slutNod = $_;
+ $si++;
+ }
+
+ for ($i = 0; $parents[$i] ne $slutNod; $i++)
+ { if (defined $parents[$i]) # Bara definierat om det finns kids
+ { $vektor = '[';
+ for (@{$kids[$i]})
+ { $vektor .= "$_ 0 R "; }
+ $vektor .= ']';
+ ########################################
+ # Hitta förälder till aktuell förälder
+ ########################################
+ my $nod;
+ for ($j = $i + 1; (! $nod); $j++)
+ { if ($parents[$j])
+ { $nod = $parents[$j];
+ $counts[$j] += $counts[$i];
+ push @{$kids[$j]}, $parents[$i];
+ }
+ }
+
+ $nodObjekt = "$parents[$i] 0 obj<</Type/Pages/Parent $nod 0 R\n/Kids $vektor/Count $counts[$i]>>endobj\n";
+
+ $objekt[$parents[$i]] = $pos;
+ $pos += syswrite UTFIL, $nodObjekt;
+ }
+ }
+ #####################################
+ # Så ordnas och skrivs slutnoden ut
+ #####################################
+ $vektor = '[';
+ for (@{$kids[$si]})
+ { $vektor .= "$_ 0 R "; }
+ $vektor .= ']';
+ $nodObjekt = "$slutNod 0 obj<</Type/Pages/Kids $vektor/Count $counts[$si]";
+ $nodObjekt .= "/MediaBox \[$genLowerX $genLowerY $genUpperX $genUpperY\]";
+ $nodObjekt .= " >>endobj\n";
+ $objekt[$slutNod] = $pos;
+ $pos += syswrite UTFIL, $nodObjekt;
+
+}
+
+sub findGet
+{ my ($fil, $cid) = @_;
+ $fil =~ s|\s+$||o;
+ my ($req, $extFil, $tempFil, $fil2, $tStamp, $res);
+
+ if (-e $fil)
+ { $tStamp = (stat($fil))[9];
+ if ($cid)
+ {
+ if ($cid eq $tStamp)
+ { return ($fil, $cid);
+ }
+ }
+ else
+ { return ($fil, $tStamp);
+ }
+ }
+ if ($cid)
+ { $fil2 = $fil . $cid;
+ if (-e $fil2)
+ { return ($fil2, $cid);
+ }
+ }
+ errLog("The file $fil can't be found, aborts");
+}
+
+sub definieraId
+{ if ($idTyp eq 'rep')
+ { if (! defined $id)
+ { errLog("Can't replicate the id if is missing, aborting");
+ }
+ my $tempId = $id;
+ undef $id;
+ return ($tempId, $tempId);
+ }
+ elsif ($idTyp eq 'add')
+ { $id++;
+ return ($id, $id);
+ }
+ else
+ { my $str = time();
+ $str .= $filnamn . $pos;
+ $str = Digest::MD5::md5_hex($str);
+ return ($str, $str);
+ }
+}
+1;
+
+__DATA__
+
+=head1 NAME
+
+PDF::Reuse - Reuse and mass produce PDF documents
+
+=head1 SYNOPSIS
+
+=for SYNOPSIS.pl begin
+
+ use PDF::Reuse;
+ prFile('myFile.pdf'); # Mandatory function
+ prText(100, 500, 'Hello World !');
+ prEnd(); # Mandatory function to flush buffers
+
+=for end
+
+=head1 DESCRIPTION
+
+This module could be used when you want to mass produce similar (but not identical)
+PDF documents and reuse templates, JavaScripts and some other components. It is
+functional to be fast, and to give your programs capacity to produce many pages
+per second and very big PDF documents if necessary.
+
+The module produces PDF-1.4 files. Some features of PDF-1.5, like "object streams"
+and "cross reference streams", are supported, but only at an experimental level. More
+testing is needed. (If you get problems with a new document from Acrobat 6.0, try to
+save it or recreate it as a PDF-1.4 document first, before using it together with
+this module.)
+
+=over 2
+
+=item Templates
+
+Use your favorite program, probably a commercial visual tool, to produce single
+PDF-files to be used as templates, and then use this module to B<mass produce> files
+from them.
+
+(If you want small PDF-files or want special graphics, you can use this module also,
+but visual tools are often most practical.)
+
+=item Lists
+
+The module uses "XObjects" extensively. This is a format that makes it possible
+create big lists, which are compact at the same time.
+
+=item JavaScript
+
+You can attach JavaScripts to your PDF-files, and "initiate" them (Acrobat 5.0,
+Acrobat Reader 5.0.5 or higher).
+
+You can have libraries of JavaScripts. No cutting or pasting, and those who include
+the scripts in documents only need to know how to initiate them. (Of course those
+who write the scripts have to know Acrobat JavaScript well.)
+
+See Remarks about Javascript
+
+=item PDF-operators
+
+The module gives you a good possibility to program at a "low level" with the basic
+graphic operators of PDF, if that is what you want to do. You can build your
+own libraries of low level routines, with PDF-directives "controlled" by Perl.
+
+=item Archive-format
+
+If you want, you get your new documents logged in a format suitable for archiving
+or transfer.
+
+=back
+
+PDF::Reuse::Tutorial might show you best what you can do with this module.
+
+=head2 Remarks about Javascript
+
+If your user has Acrobat Reader 5.0.5 or higher, he/she should be able to use the
+functions with JavaScript. The Reader should have the option "Allow File Open
+Actions and Launching File Attachments" checked under "Preferences".
+
+If he/she uses Acrobat there is a complication. Everything should work fine as long
+as new files are not read via the web. Acrobat has a plug in, "webpdf.api", which
+converts documents, also PDF-documents, when they are fetched over the net.
+That is probably a good idea in some cases, but B<it changes the documents, and
+there is a great risk that JavaScripts are lost>.
+
+(In cases of real emergency, you can disable the plug in simply by removing it
+from the directory Plug_ins under Acrobat, put it in a safe place, and start Acrobat.
+And put it back before you need it next time.)
+
+Anyway, almost every computer has the Reader somewhere, and if it is not of the
+right version, it can be downloaded. So with a little effort, it should be possible
+to use also the functions with JavaScrips on most computers.
+
+=head1 FUNCTIONS
+
+All functions which are successful return specified values or 1.
+
+The module doesn't make any attempt to import anything from encrypted files.
+
+=head1 Mandatory Functions
+
+=head2 prFile - define output
+
+Alternative 1:
+
+ prFile ( $fileName );
+
+Alternative 2 with parameters in an anonymous hash:
+
+ prFile ( { Name => $fileName,
+ HideToolbar => 1, # 1 | 0
+ HideMenubar => 1, # 1 | 0
+ HideWindowUI => 1, # 1 | 0
+ FitWindow => 1, # 1 | 0
+ CenterWindow => 1 } ); # 1 | 0
+
+Alternative 3:
+
+ prFile ( $r ); # For mod_perl 2 pass the request object
+
+$fileName is optional, just like the rest of the parameters.
+File to create. If another file is current when this function is called, the first
+one is written and closed. Only one file is processed at a single moment. If
+$fileName is undefined, output is written to STDOUT.
+
+HideToolbar, HideMenubar, HideWindowUI, FitWindow and CenterWindow control the
+way the document is initially displayed.
+
+Look at any program in this documentation for examples. prInitVars() shows how
+this function could be used together with a web server.
+
+=head2 prEnd - end/flush buffers
+
+ prEnd ()
+
+When the processing is going to end, the buffers of the B<last> file has to be written to the disc.
+If this function is not called, the page structure, xref part and so on will be
+lost.
+
+Look at any program in this documentation for an example.
+
+=head1 Optional Functions
+
+=head2 prAdd - add "low level" instructions
+
+ prAdd ( $string )
+
+With this command you can add whatever you want to the current content stream.
+No syntactical checks are made, but if you use an internal name, the module tries
+to add the resource of the "name object" to the "Resources" of current page.
+"Name objects" always begin with a '/'.
+
+(In this documentation I often use talk about an "internal name". It denotes a
+"name object". When PDF::Reuse creates these objects, it assigns Ft1, Ft2, Ft3 ...
+for fonts, Im1, Im2, Im3 for images, Fo1 .. for forms, Cs1 .. for Color spaces,
+Pt1 .. for patterns, Sh1 .. for shading directories, Gs0 .. for graphic state
+parameter dictionaries. These names are kept until the program finishes,
+and my ambition is also to keep the resources available in internal tables.)
+
+This is a simple and very powerful function. You should study the examples and
+the "PDF-reference manual", if you want to use it.(When this text is written,
+a possible link to download it is:
+http://partners.adobe.com/asn/developer/acrosdk/docs.html)
+
+This function is intended to give you detail control at a low level.
+
+ use PDF::Reuse;
+ use strict;
+
+ prFile('myFile.pdf');
+ my $string = "150 600 100 50 re\n"; # a rectangle
+ $string .= "0 0 1 rg\n"; # blue (to fill)
+ $string .= "b\n"; # fill and stroke
+ prAdd($string);
+ prEnd();
+
+
+=head2 prBookmark - define bookmarks
+
+ prBookmark($reference)
+
+Defines a "bookmark". $reference refers to a hash or array of hashes which look
+something like this:
+
+ { text => 'Document',
+ act => 'this.pageNum = 0; this.scroll(40, 500);',
+ kids => [ { text => 'Chapter 1',
+ act => '1, 40, 600'
+ },
+ { text => 'Chapter 2',
+ act => '10, 40, 600'
+ }
+ ]
+ }
+
+Each hash can have these components:
+
+ text the text shown beside the bookmark
+ act the action to be triggered. Has to be a JavaScript action.
+ (Three simple numbers are translated to page, x and y in the
+ sentences: this.pageNum = page; this.scroll(x, y); )
+ pdfact an alternative to act: the raw PDF action to be triggered
+ (act will be used if present, otherwise pdfact)
+ kids will have a reference to another hash or array of hashes
+ close if this component is present, the bookmark will be closed
+ when the document is opened
+ color 3 numbers, RGB-colors e.g. '0.5 0.5 1' for light blue
+ style 0, 1, 2, or 3. 0 = Normal, 1 = Italic, 2 = Bold, 3 = Bold Italic
+
+Creating bookmarks for a document:
+
+ use PDF::Reuse;
+ use strict;
+
+ my @pageMarks;
+
+ prFile('myDoc.pdf');
+
+ for (my $i = 0; $i < 100; $i++)
+ { prText(40, 600, 'Something is written');
+ # ...
+ my $page = $i + 1;
+ my $bookMark = { text => "Page $page",
+ act => "$i, 40, 700" };
+ push @pageMarks, $bookMark;
+ prPage();
+ }
+ prBookmark( { text => 'Document',
+ close => 1,
+ kids => \@pageMarks } );
+ prEnd();
+
+
+Traditionally bookmarks have mainly been used for navigation within a document,
+but they can be used for many more things. You can e.g. use them to navigate within
+your data. You can let your users go to external links also, so they can "drill down"
+to other documents.
+
+B<See "Remarks about Javascript">
+
+=head2 prCompress - compress/zip added streams
+
+ prCompress (1)
+
+'1' here is a directive to compress all B<new> streams of the current file. Streams
+which are included with prForm, prDocForm and prDoc are not changed. New
+JavaScripts are also created as streams and compressed, if they are at least 100
+bytes long. The streams are compressed in memory, so probably there is a limit of
+how big they can be.
+
+prCompress(); is a directive not to compress. This is default.
+
+See e.g. "Starting to reuse" in the tutorial for an example.
+
+=head2 prDoc - include pages from a document
+
+ prDoc ( $documentName, $firstPage, $lastPage )
+
+or with the parameters in an anonymous hash:
+
+ prDoc ( { file => $documentName,
+ first => $firstPage,
+ last => $lastPage } );
+
+Returns number of extracted pages.
+
+If "first" is not given, 1 is assumed. If "last" is not given, you don't have any upper
+limit. N.B. The numbering of the pages differs from Acrobat JavaScript. In JavaScript
+the first page has index 0.
+
+Adds pages from a document to the one you are creating. If it is the first interactive
+component ( prDoc() or prDocForm() ) the interactive functions are kept and also merged
+with JavaScripts you have added, if any. But, if you specify a first page different than 1
+or a last page, no JavaScript are extracted from the document, because then there is a
+risk that an included JavaScript function might refer to something not included.
+
+ use PDF::Reuse;
+ use strict;
+
+ prFile('myFile.pdf'); # file to make
+ prJs('customerResponse.js'); # include a JavaScript file
+ prInit('nameAddress(12, 150, 600);'); # init a JavaScript function
+ prForm('best.pdf'); # page 1 from best.pdf
+ prPage(); # page break
+ prDoc('long.pdf'); # a document with 11 pages
+ prPage(); # page break
+ prForm('best.pdf'); # page 1 from best.pdf
+ prText(150, 700, 'Customer Data'); # a line of text
+ prEnd();
+
+To extract pages 2-3 and 5-7 from a document and create a new document:
+
+ use PDF::Reuse;
+ use strict;
+
+ prFile('new.pdf');
+ prDoc( { file => 'old.pdf',
+ first => 2,
+ last => 3 });
+ prDoc( { file => 'old.pdf',
+ first => 5,
+ last => 7 });
+ prEnd();
+
+=head2 prDocDir - set directory for produced documents
+
+ prDocDir ( $directoryName )
+
+Sets directory for produced documents
+
+ use PDF::Reuse;
+ use strict;
+
+ prDocDir('C:/temp/doc');
+ prFile('myFile.pdf'); # writes to C:\temp\doc\myFile.pdf
+ prForm('myFile.pdf'); # page 1 from ..\myFile.pdf
+ prText(200, 600, 'New text');
+ prEnd();
+
+=head2 prDocForm - use an interactive page as a form
+
+Alternative 1) You put your parameters in an anonymous hash (only B<file> is really
+necessary, the others get default values if not given).
+
+ prDocForm ( { file => $pdfFile, # template file
+ page => $page, # page number (of imported template)
+ adjust => $adjust, # try to fill the media box
+ effect => $effect, # action to be taken
+ tolerant => $tolerant, # continue even with an invalid form
+ x => $x, # $x pixels from the left
+ y => $y, # $y pixels from the bottom
+ rotate => $degree, # rotate
+ size => $size, # multiply everything by $size
+ xsize => $xsize, # multiply horizontally by $xsize
+ ysize => $ysize } ) # multiply vertically by $ysize
+Ex.:
+ my $internalName = prDocForm ( {file => 'myFile.pdf',
+ page => 2 } );
+
+Alternative 2) You put your parameters in this order
+
+ prDocForm ( $pdfFile, [$page, $adjust, $effect, $tolerant, $x, $y, $degree,
+ $size, $xsize, $ysize] )
+
+
+Anyway the function returns in list context: B<$intName, @BoundingBox,
+$numberOfImages>, in scalar context: B<$internalName> of the form.
+
+Look at prForm() for an explanation of the parameters.
+
+N.B. Usually you shouldn't adjust or change size and proportions of an interactive
+page. The graphic and interactive components are independent of each other and there
+is a great risk that any coordination is lost.
+
+This function redefines a page to an "XObject" (the graphic parts), then the
+page can be reused in a much better way. Unfortunately there is an important
+limitation here. "XObjects" can only have single streams. If the page consists
+of many streams, you should concatenate them first. Adobe Acrobat can do that.
+(If it is an important file, take a copy of it first. Sometimes the procedure fails.)
+You open the file with Acrobat and choose the "Touch Up" tool and change anything
+graphic in the page. You could e.g. remove 1 space and put it back. Then you
+save the file.
+
+ use PDF::Reuse;
+ use strict;
+
+ prDocDir('C:/temp/doc');
+ prFile('newForm.pdf');
+ prField('Mr/Ms', 'Mr');
+ prField('First_Name', 'Lars');
+ prDocForm('myFile.pdf');
+ prFontSize(24);
+ prText(75, 790, 'This text is added');
+ prEnd();
+
+(You can use the output from the example in prJs() as input to this example.
+Remember to save that file before closing it.)
+
+B<See Remarks about Javascript>
+
+=head2 prExtract - extract an object group
+
+ prExtract ( $pdfFile, $pageNo, $oldInternalName )
+
+B<oldInternalName>, a "name"-object. This is the internal name you find in the original file.
+Returns a B<$newInternalName> which can be used for "low level" programming. You
+have better look at graphObj_pl and modules it has generated for the tutorial,
+e.g. thermometer.pm, to see how this function can be used.
+
+When you call this function, the necessary objects will be copied to your new
+PDF-file, and you can refer to them with the new name you receive.
+
+=head2 prField - assign a value to an interactive field
+
+ prField ( $fieldName, $value )
+
+B<$fieldName> is an interactive field in the document you are creating.
+It has to be spelled exactly the same way here as it spelled in the document.
+B<$value> is what you want to assigned to the field.
+Put all your sentences with prField early in your script. After prFile and B<before>
+prDoc or prDocForm and of course before prEnd. Each sentence with prField is
+translated to JavaScript and merged with old JavaScript
+
+See prDocForm() for an example
+
+If you are going to assign a value to a field consisting of several lines, you
+can write like this:
+
+ my $string = "This is the first line \r second line \n 3:rd line";
+ prField('fieldName', $string);
+
+You can also let '$value' be a snippet of JavaScript-code that assigns something
+to the field. Then you have to put 'js:' first in "$value" like this:
+
+ my $sentence = encrypt('This will be decrypted by "unPack"(JavaScript) ');
+ prField('Interest_9', "js: unPack('$sentence')");
+
+If you refer to a JavaScript function, it has to be included with prJs first. (The
+JavaScript interpreter will simply not be aware of old functions in the PDF-document,
+when the initiation is done.)
+
+B<The function prField uses JavaScript, so see "Remarks about Javascript">
+
+=head2 prFont - set current font
+
+ prFont ( $fontName )
+
+$fontName is an "external" font name. The parameter is optional.
+In list context returns B<$internalName, $externalName, $oldInternalName,
+$oldExternalname> The first two variables refer to the current font, the two later
+to the font before the change. In scalar context returns b<$internalName>
+
+If a font wasn't found, Helvetica will be set.
+These names are always recognized:
+B<Times-Roman, Times-Bold, Times-Italic, Times-BoldItalic, Courier, Courier-Bold,
+Courier-Oblique, Courier-BoldOblique, Helvetica, Helvetica-Bold, Helvetica-Oblique,
+Helvetica-BoldOblique> or abbreviated
+B<TR, TB, TI, TBI, C, CB, CO, CBO, H, HB, HO, HBO>.
+(B<Symbol and ZapfDingbats> or abbreviated B<S, Z>, also belong to the predefined
+fonts, but there is something with them that I really don't understand. You should
+print them first on a page, and then use other fonts, otherwise they are not displayed.)
+
+You can also use a font name from an included page. It has to be spelled exactly as
+it is done there. Look in the file and search for "/BaseFont" and the font
+name. But take care, e.g. the PDFMaker which converts to PDF from different
+Microsoft programs, only defines exactly those letters you can see on the page. You
+can use the font, but perhaps some of your letters were not defined.
+
+In the distribution there is an utility program, 'reuseComponent_pl', which displays
+included fonts in a PDF-file and prints some letters. Run it to see the name of the
+font and if it is worth extracting.
+
+ use PDF::Reuse;
+ use strict;
+ prFile('myFile.pdf');
+
+ ####### One possibility #########
+
+ prFont('Times-Roman'); # Just setting a font
+ prFontSize(20);
+ prText(180, 790, "This is a heading");
+
+ ####### Another possibility #######
+
+ my $font = prFont('C'); # Setting a font, getting an
+ # internal name
+ prAdd("BT /$font 12 Tf 25 760 Td (This is some other text)Tj ET");
+ prEnd();
+
+The example above shows you two ways of setting and using a font. One simple, and
+one complicated with a possibility to detail control.
+
+
+=head2 prFontSize - set current font size
+
+ prFontSize ( $size )
+
+Returns B<$actualSize, $fontSizeBeforetheChange>. Without parameters
+prFontSize() sets the size to 12 pixels, which is default.
+
+=head2 prForm - use a page from an old document as a form/background
+
+Alternative 1) You put your parameters in an anonymous hash (only B<file> is really
+necessary, the others get default values if not given).
+
+ prForm ( { file => $pdfFile, # template file
+ page => $page, # page number (of imported template)
+ adjust => $adjust, # try to fill the media box
+ effect => $effect, # action to be taken
+ tolerant => $tolerant, # continue even with an invalid form
+ x => $x, # $x pixels from the left
+ y => $y, # $y pixels from the bottom
+ rotate => $degree, # rotate
+ size => $size, # multiply everything by $size
+ xsize => $xsize, # multiply horizontally by $xsize
+ ysize => $ysize } ) # multiply vertically by $ysize
+Ex.:
+ my $internalName = prForm ( {file => 'myFile.pdf',
+ page => 2 } );
+
+Alternative 2) You put your parameters in this order
+
+ prForm ( $pdfFile, $page, $adjust, $effect, $tolerant, $x, $y, $degree,
+ $size, $xsize, $ysize )
+
+
+Anyway the function returns in list context: B<$intName, @BoundingBox,
+$numberOfImages>, in scalar context: B<$internalName> of the form.
+
+if B<page> is excluded 1 is assumed.
+
+B<adjust>, could be 1, 2 or 0/nothing. If it is 1, the program tries to adjust the
+form to the current media box (paper size) and keeps the proportions unchanged.
+If it is 2, the program tries to fill as much of the media box as possible, without
+regards to the original proportions.
+If this parameter is given, "x", "y", "rotate", "size", "xsize" and "ysize"
+will be ignored.
+
+B<effect> can have 3 values: B<'print'>, which is default, loads the page in an internal
+table, adds it to the document and prints it to the current page. B<'add'>, loads the
+page and adds it to the document. (Now you can "manually" manage the way you want to
+print it to different pages within the document.) B<'load'> just loads the page in an
+internal table. (You can now take I<parts> of a page like fonts and objects and manage
+them, without adding all the page to the document.)You don't get any defined
+internal name of the form, if you let this parameter be 'load'.
+
+B<tolerant> can be nothing or something. If it is undefined, you will get an error if your program tries to load
+a page which the system cannot really handle, if it e.g. consists of many streams.
+If it is set to something, you have to test the first return value $internalName to
+know if the function was successful. Look at the program 'reuseComponent_pl' for an
+example of usage.
+
+B<x> where to start along the x-axis (cannot be combined with "adjust")
+
+B<y> where to start along the y-axis (cannot be combined with "adjust")
+
+B<rotate> A degree 0-360 to rotate the form counter-clockwise. (cannot be combined
+with "adjust") Often the form disappears out of the media box if degree >= 90.
+Then you can move it back with the x and y-parameters. If degree == 90, you can
+add the width of the form to x, If degree == 180 add both width and height to x
+and y, and if degree == 270 you can add the height to y.
+
+B<rotate> can also by one of 'q1', 'q2' or 'q3'. Then the system rotates the form
+clockwise 90, 180 or 270 degrees and tries to keep the form within the media box.
+
+The rotation takes place after the form has been resized or moved.
+
+ Ex. To rotate from portrait (595 x 842 pt) to landscape (842 x 595 pt)
+
+ use PDF::Reuse;
+ use strict;
+
+ prFile('New_Report.pdf');
+ prMbox(0, 0, 842, 595);
+
+ prForm({file => 'cert1.pdf',
+ rotate => 'q1' } );
+ prEnd();
+
+The same rotation can be achieved like this:
+
+ use PDF::Reuse;
+ use strict;
+
+ prFile('New_Report.pdf');
+ prMbox(0, 0, 842, 595);
+
+ prForm({file => 'cert1.pdf',
+ rotate => 270,
+ y => 595 } );
+ prEnd();
+
+B<size> multiply every measure by this value (cannot be combined with "adjust")
+
+B<xsize> multiply horizontally by this value (cannot be combined with "adjust")
+
+B<ysize> multiply vertically by $ysize (cannot be combined with "adjust")
+
+This function redefines a page to an "XObject" (the graphic parts), then the
+page can be reused and referred to as a unit. Unfortunately there is an important
+limitation here. "XObjects" can only have single streams. If the page consists
+of many streams, you should concatenate them first. Adobe Acrobat can do that.
+(If it is an important file, take a copy of it first. Sometimes the procedure fails.)
+You open the file with Acrobat and choose the "Touch Up" tool and change anything
+graphic in the page. You could e.g. remove 1 space and put it back. Then you
+save the file. You could alternatively save the file as Postscript and redistill it with the
+distiller or with Ghost script, but this is a little more risky. You might loose fonts
+or something else. An other alternative could be to use prDoc() , but then you get all
+the document, and you can only change the appearance of the page with the help of
+JavaScript.
+
+ use PDF::Reuse;
+ use strict;
+
+ prFile('myFile.pdf');
+ prForm('best.pdf'); # Takes page No 1
+ prText(75, 790, 'Dear Mr Gates');
+ # ...
+ prPage();
+ prMbox(0, 0, 900, 960);
+ my @vec = prForm( { file => 'EUSA.pdf',
+ adjust => 1 } );
+ prPage();
+ prMbox();
+ prText(35, 760, 'This is the final page');
+
+ # More text ..
+
+ #################################################################
+ # We want to put a miniature of EUSA.pdf, 35 pixels from the left
+ # 85 pixels up, and in the format 250 X 200 pixels
+ #################################################################
+
+ my $xScale = 250 / ($vec[3] - $vec[1]);
+ my $yScale = 200 / ($vec[4] - $vec[2]);
+
+ prForm ({ file => 'EUSA.pdf',
+ xsize => $xScale,
+ ysize => $yScale,
+ x => 35,
+ y => 85 });
+
+ prEnd();
+
+The first prForm(), in the code, is a simple and "normal" way of using the
+the function. The second time it is used, the size of the imported page is
+changed. It is adjusted to the media box which is current at that moment.
+Also data about the form is taken, so you can control more in detail how it
+will be displayed.
+
+=head2 prGetLogBuffer - get the log buffer.
+
+prGetLogBuffer ()
+
+returns a B<$buffer> of the log of the current page. (It could be used
+e.g. to calculate a MD5-digest of what has been registered that far, instead of
+accumulating the single values) A log has to be active, see prLogDir() below
+
+Look at "Using the template" and "Restoring a document from the log" in the
+tutorial for examples of usage.
+
+=head2 prGraphState - define a graphic state parameter dictionary
+
+ prGraphState ( $string )
+
+This is a "low level" function. Returns B<$internalName>. The B<$string> has to
+be a complete dictionary with initial "<<" and terminating ">>". No syntactical
+checks are made. Perhaps you will never have to use this function.
+
+ use PDF::Reuse;
+ use strict;
+
+ prFile('myFile.pdf');
+
+ ###################################################
+ # Draw a triangle with Gs0 (automatically defined)
+ ###################################################
+
+ my $str = "q\n";
+ $str .= "/Gs0 gs\n";
+ $str .= "150 700 m\n";
+ $str .= "225 800 l\n";
+ $str .= "300 700 l\n";
+ $str .= "150 700 l\n";
+ $str .= "S\n";
+ $str .= "Q\n";
+ prAdd($str);
+
+ ########################################################
+ # Define a new graph. state param. dic. and draw a new
+ # triangle further down
+ ########################################################
+
+ $str = '<</Type/ExtGState/SA false/SM 0.02/TR2 /Default'
+ . '/LW 15/LJ 1/ML 1>>';
+ my $gState = prGraphState($str);
+ $str = "q\n";
+ $str .= "/$gState gs\n";
+ $str .= "150 500 m\n";
+ $str .= "225 600 l\n";
+ $str .= "300 500 l\n";
+ $str .= "150 500 l\n";
+ $str .= "S\n";
+ $str .= "Q\n";
+ prAdd($str);
+
+ prEnd();
+
+
+=head2 prImage - reuse an image from an old PDF document
+
+Alternative 1) You put your parameters in an anonymous hash (only B<file> is really
+necessary, the others get default values if not given).
+
+ prImage( { file => $pdfFile, # template file
+ page => $page, # page number
+ imageNo => $imageNo # image number
+ adjust => $adjust, # try to fill the media box
+ effect => $effect, # action to be taken
+ x => $x, # $x pixels from the left
+ y => $y, # $y pixels from the bottom
+ rotate => $degree, # rotate
+ size => $size, # multiply everything by $size
+ xsize => $xsize, # multiply horizontally by $xsize
+ ysize => $ysize } ) # multiply vertically by $ysize
+Ex.:
+ prImage( { file => 'myFile.pdf',
+ page => 10,
+ imageNo => 2 } );
+
+Alternative 2) You put your parameters in this order
+
+ prImage ( $pdfFile, [$page, $imageNo, $effect, $adjust, $x, $y, $degree,
+ $size, $xsize, $ysize] )
+
+Returns in scalar context B<$internalName> As a list B<$internalName, $width,
+$height>
+
+Assumes that $pageNo and $imageNo are 1, if not specified. If $effect is given and
+anything else then 'print', the image will be defined in the document,
+but not shown at this moment.
+
+For all other parameters, look at prForm().
+
+ use PDF::Reuse;
+ use strict;
+
+ prFile('myFile.pdf');
+ my @vec = prImage({ file => 'best.pdf',
+ x => 10,
+ y => 400,
+ xsize => 0.9,
+ ysize => 0.8 } );
+ prText(35, 760, 'This is some text');
+ # ...
+ prPage();
+ my @vec2 = prImage( { file => 'destiny.pdf',
+ page => 1,
+ imageNo => 1,
+ effect => 'add' } );
+ prText(25, 760, "There shouldn't be any image on this page");
+ prPage();
+ ########################################################
+ # Now we make both images so that they could fit into
+ # a box 300 X 300 pixels, and they are displayed
+ ########################################################
+
+ prText(25, 800, 'This is the first image :');
+
+ my $xScale = 300 / $vec[1];
+ my $yScale = 300 / $vec[2];
+ if ($xScale < $yScale)
+ { $yScale = $xScale;
+ }
+ else
+ { $xScale = $yScale;
+ }
+ prImage({ file => 'best.pdf',
+ x => 25,
+ y => 450,
+ xsize => $xScale,
+ ysize => $yScale} );
+
+ prText(25, 400, 'This is the second image :');
+
+ $xScale = 300 / $vec2[1];
+ $yScale = 300 / $vec2[2];
+ if ($xScale < $yScale)
+ { $yScale = $xScale;
+ }
+ else
+ { $xScale = $yScale;
+ }
+ prImage({ file => 'destiny.pdf',
+ x => 25,
+ y => 25,
+ xsize => $xScale,
+ ysize => $yScale} );
+
+ prEnd();
+
+On the first page an image is displayed in a simple way. While the second page
+is processed, prImage(), loads an image, but it is not shown here. On the 3:rd
+page, the two images are scaled and shown.
+
+In the distribution there is an utility program, 'reuseComponent_pl', which displays
+included images in a PDF-file and their "names".
+
+=head2 prInit - add JavaScript to be executed at initiation
+
+ prInit ( $string, $duplicateCode )
+
+B<$string> can be any JavaScript code, but you can only refer to functions included
+with prJs. The JavaScript interpreter will not know other functions in the document.
+Often you can add new things, but you can't remove or change interactive fields,
+because the interpreter hasn't come that far, when initiation is done.
+
+B<$duplicateCode> is undefined or anything. It duplicates the JavaScript code
+which has been used at initiation, so you can look at it from within Acrobat and
+debug it. It makes the document bigger. This parameter is B<deprecated>.
+
+See prJs() for an example
+
+Remark: Avoid to use "return" in the code you use at initiation. If your user has
+downloaded a page with Web Capture, and after that opens a PDF-document where a
+JavaScript is run at initiation and that JavaScript contains a return-statement,
+a bug occurs. The JavaScript interpreter "exits" instead of returning, the execution
+of the JavaScript might finish to early. This is a bug in Acrobat/Reader 5.
+
+B<The function prInit uses JavaScript, so see "Remarks about Javascript">
+
+=head2 prInitVars - initiate global variables and internal tables
+
+ prInitVars(1)
+
+If you run programs with PDF::Reuse as persistent procedures, you probably need to
+initiate global variables. If you have '1' or anything as parameter, internal tables for forms, images, fonts
+and interactive functions are B<not> initiated. The module "learns" offset and sizes of
+used objects, and can process them faster, but at the same time the size of the
+program grows.
+
+ use PDF::Reuse;
+ use strict;
+ prInitVars(); # To initiate ALL global variables and tables
+ # prInitVars(1); # To make it faster, but more memory consuming
+
+ $| = 1;
+ print STDOUT "Content-Type: application/pdf \n\n";
+
+ prFile(); # To send the document uncatalogued to STDOUT
+
+ prForm('best.pdf');
+ prText(25, 790, 'Dear Mr. Anders Persson');
+ # ...
+ prEnd();
+
+If you call this function without parameters all global variables, including the
+internal tables, are initiated.
+
+
+=head2 prJpeg - import a jpeg-image
+
+ prJpeg ( $imageFile, $width, $height )
+
+B<$imageFile> contains 1 single jpeg-image. B<$width> and B<$height>
+also have to be specified. Returns the B<$internalName>
+
+ use PDF::Reuse;
+ use Image::Info qw(image_info dim);
+ use strict;
+
+ my $file = 'myImage.jpg';
+ my $info = image_info($file);
+ my ($width, $height) = dim($info); # Get the dimensions
+
+ prFile('myFile.pdf');
+ my $intName = prJpeg("$file", # Define the image
+ $width, # in the document
+ $height);
+
+ my $str = "q\n";
+ $str .= "$width 0 0 $height 10 10 cm\n";
+ $str .= "/$intName Do\n";
+ $str .= "Q\n";
+ prAdd($str);
+ prEnd();
+
+This is a little like an extra or reserve routine to add images to the document.
+The most simple way is to use prImage()
+
+=head2 prJs - add JavaScript
+
+ prJs ( $string|$fileName )
+
+To add JavaScript to your new document. B<$string> has to consist only of
+JavaScript functions: function a (..){ ... } function b (..) { ...} and so on
+If B<$string> doesn't contain '{', B<$string> is interpreted as a filename.
+In that case the file has to consist only of JavaScript functions.
+
+ use PDF::Reuse;
+ use strict;
+
+ prFile('myFile.pdf');
+ prJs('customerResponse.js');
+ prInit('nameAddress(0, 100, 700);');
+ prEnd();
+
+
+B<See "Remarks about Javascript">
+
+=head2 prLink - add a hyperlink
+
+ prLink( { page => $pageNo, # Starting with 1 !
+ x => $x,
+ y => $y,
+ width => $width,
+ height => $height,
+ URI => $URI } );
+
+You can also call prLink like this:
+
+ prLink($page, $x, $y, $width, $height, $URI);
+
+You have to put prLink B<after prFile and before the sentences where its' page
+is created>. The links are created at the page-breaks. If the page is already
+created, no new link will be inserted.
+
+Here is an example where the links of a 4 page document are preserved, and a link is
+added at the end of the document. We assume that there is some suitable text at that
+place (x = 400, y = 350):
+
+ use strict;
+ use PDF::Reuse;
+
+ prFile('test.pdf');
+
+ prLink( {page => 4,
+ x => 400,
+ y => 350,
+ width => 105,
+ height => 15,
+ URI => 'http://www.purelyInvented.com/info.html' } );
+
+ prDoc('fourPages.pdf');
+
+ prEnd();
+
+( If you are creating each page of a document separately, you can also use 'hyperLink'
+from PDF::Reuse::Util. Then you get an external text in Helvetica-Oblique, underlined
+and in blue.
+
+ use strict;
+ use PDF::Reuse;
+ use PDF::Reuse::Util;
+
+ prFile('test.pdf');
+ prForm('template.pdf', 5);
+ my ($from, $pos) = prText(25, 700, 'To get more information ');
+
+ $pos = hyperLink( $pos, 700, 'Press this link',
+ 'http://www.purelyInvented.com/info.html' );
+ ($from, $pos) = prText( $pos, 700, ' And get connected');
+ prEnd();
+
+'hyperLink' has a few parameters: $x, $y, $textToBeShown, $hyperLink and
+$fontSize (not shown in the example). It returns current x-position. )
+
+=head2 prLog - add a string to the log
+
+ prLog ( $string )
+
+Adds whatever you want to the current log (a reference No, a commentary, a tag ?)
+A log has to be active see prLogDir()
+
+Look at "Using the template" and "Restoring the document from the log" in
+the tutorial for an example.
+
+=head2 prLogDir - set directory for the log
+
+ prLogDir ( $directory )
+
+Sets a directory for the logs and activates the logging.
+A little log file is created for each PDF-file. Normally it should be much, much
+more compact then the PDF-file, and it should be possible to restore or verify
+a document with the help of it. (Of course you could compress or store the logs in a
+database to save even more space.)
+
+ use PDF::Reuse;
+ use strict;
+
+ prDocDir('C:/temp/doc');
+ prLogDir('C:/run');
+
+ prFile('myFile.pdf');
+ prForm('best.pdf');
+ prText(25, 790, 'Dear Mr. Anders Persson');
+ # ...
+ prEnd();
+
+In this example a log file with the name 'myFile.pdf.dat' is created in the
+directory 'C:\run'. If that directory doesn't exist, the system tries to create it.
+(But, just as mkdir does, it only creates the last level in a directory tree.)
+
+=head2 prMbox - define the format (MediaBox) of the current page.
+
+ prMbox ( $lowerLeftX, $lowerLeftY, $upperRightX, $upperRightY )
+
+If the function or the parameters are missing, they are set to 0, 0, 595, 842 pixels respectively.
+
+See prForm() for an example.
+
+
+=head2 prPage - insert a page break
+
+ prPage ($noLog)
+
+Don't use the optional parameter, it is only used internally, not to clutter the log,
+when automatic page breaks are made.
+
+See prForm() for an example.
+
+=head2 prStrWidth - calculate the string width
+
+ prStrWidth($string, $font, $fontSize)
+
+Returns string width in pixels.
+Should be used in conjunction with one of these predefined fonts of Acrobat/Reader:
+Times-Roman, Times-Bold, Times-Italic, Times-BoldItalic, Courier, Courier-Bold, Courier-Oblique,
+Courier-BoldOblique, Helvetica, Helvetica-Bold, Helvetica-Oblique,
+Helvetica-BoldOblique. If some other font is given, Helvetica is used, and the
+returned value will at the best be approximate.
+
+=head2 prText - add a text-string
+
+ prText ( $x, $y, $string, $how )
+
+Puts B<$string> at position B<$x, $y>
+Returns 1 in scalar context. Returns ($xFrom, $xTo) in list context. $xTo will not
+be defined if $how is a rotation. prStrWidth() is used to calculate the length of the
+strings, so only the predefined fonts together with Acrobat/Reader will give
+reliable values for $xTo.
+
+$how can be 'left' (= default), 'center', 'right', a degree 0 - 360, 'q1', 'q2'
+or 'q3'. The parameter is optional.
+
+Current font and font size are used. (If you use prAdd() before this function,
+many other things could also influence the text.)
+
+ use strict;
+ use PDF::Reuse;
+
+ prFile('test.pdf');
+
+ #####################################
+ # Use a "curser" ($pos) along a line
+ #####################################
+
+ my ($from, $pos) = prText(25, 800, 'First write this. ');
+ ($from, $pos) = prText($pos, 800, 'Then write this. ');
+ prText($pos, 800, 'Finally write this.');
+
+ #####################################
+ # Right adjust and center sentences
+ #####################################
+
+ prText( 200, 750, 'A short sentence', 'right');
+ prText( 200, 735, 'This is a longer sentence', 'right');
+ prText( 200, 720, 'A word', 'right');
+
+ prText( 200, 705, 'Centered around a point 200 pixels from the left', 'center');
+ prText( 200, 690, 'The same center', 'center');
+ prText( 200, 675, '->.<-', 'center');
+
+ ############
+ # Rotation
+ ############
+
+ prText( 200, 550, ' Rotate 0 degrees', 0);
+ prText( 200, 550, ' Rotate 60 degrees', 60);
+ prText( 200, 550, ' Rotate 120 degrees', 120);
+ prText( 200, 550, ' Rotate 180 degrees', 180);
+ prText( 200, 550, ' Rotate 240 degrees', 240);
+ prText( 200, 550, ' Rotate 300 degrees', 300);
+
+ prText( 400, 430, 'Rotate 90 degrees clock-wise', 'q1');
+ prText( 400, 430, 'Rotate 180 degrees clock-wise', 'q2');
+ prText( 400, 430, 'Rotate 270 degrees clock-wise', 'q3');
+
+ prEnd();
+
+
+=head2 prTouchUp - make changes and reuse more difficult
+
+ prTouchUp (1);
+
+By default and after you have issued prTouchUp(1), you can change the document
+with the TouchUp tool from within Acrobat.
+If you want to switch off this possibility, you use prTouchUp() without any
+parameter. Then the user shouldn't be able to change anything graphic by mistake.
+He has to do something premeditated and perhaps with a little effort.
+He could still save it as Postscript and redistill, or he could remove or add single pages.
+(Here is a strong reason why the log files, and perhaps also check sums, are needed.
+It would be very difficult to forge a document unless the forger also has access to your
+computer and knows how the check sums are calculated.)
+
+B<Avoid to switch off the TouchUp tool for your templates.> It creates an
+extra level within the PDF-documents . Use this function for your final documents.
+
+See "Using the template" in the tutorial for an example.
+
+(To encrypt your documents: use the batch utility within Acrobat)
+
+
+=head1 INTERNAL OR DEPRECATED FUNCTIONS
+
+=over 2
+
+=item prBar - define and paint bars for bar fonts
+
+ prBar ($x, $y, $string)
+
+Prints a bar font pattern at the current page.
+Returns $internalName for the font.
+$x and $y are coordinates in pixels and $string should consist of the characters
+'0', '1' and '2' (or 'G'). '0' is a white bar, '1' is a dark bar. '2' and 'G' are
+dark, slightly longer bars, guard bars.
+You can use e.g. GD::Barcode or one module in that group to calculate the barcode
+pattern. prBar "translates" the pattern to white and black bars.
+
+ use PDF::Reuse;
+ use GD::Barcode::Code39;
+ use strict;
+
+ prFile('myFile.pdf');
+ my $oGdB = GD::Barcode::Code39->new('JOHN DOE');
+ my $sPtn = $oGdB->barcode();
+ prBar(100, 600, $sPtn);
+ prEnd();
+
+Internally the module uses a font for the bars, so you might want to change the font size before calling
+this function. In that case, use prFontSize() .
+If you call this function without arguments it defines the bar font but does
+not write anything to the current page.
+
+B<An easier and often better way to produce barcodes is to use PDF::Reuse::Barcode.>
+Look at that module!
+
+=item prCid - define timestamp/checkid
+
+ prCid ( $timeStamp )
+
+An internal function. Don't bother about it. It is used in automatic
+routines when you want to restore a document. It gives modification time of
+the next PDF-file or JavaScript.
+See "Restoring a document from the log" in the tutorial for more about the
+time stamp
+
+=item prId - define id-string of a PDF document
+
+ prId ( $string )
+
+An internal function. Don't bother about it. It is used e.g. when a document is
+restored and an id has to be set, not calculated.
+
+=item prIdType - define id-type
+
+ prIdType ( $string )
+
+An internal function. Avoid using it. B<$string> could be "Rep" for replace or
+"None" to avoid calculating an id.
+
+Normally you don't use this function. Then an id is calculated with the help of
+Digest::MD5::md5_hex and some data from the run.
+
+=item prMoveTo
+
+ prMoveTo ( $x, $y )
+
+B<Deprecated> This function will be removed during 2004. You can define positions
+with parameters directly to prImage(), prForm() and prDocForm().
+
+Defines positions where to put e.g. next image
+
+=item prScale
+
+ prScale ( $xSize, $ySize )
+
+B<Deprecated> This function will be removed during 2004. You can define sizes
+with parameters directly to prImage(), prForm() and prDocForm().
+
+Each of $xSize and $ySize are set to 1 if missing. You can use this function to
+scale an image before showing it.
+
+
+=item prVers - check version of log and program
+
+ prVers ( $versionNo )
+
+To check version of this module in case a document has to be
+restored.
+
+=back
+
+=head1 SEE ALSO
+
+ PDF::Reuse::Tutorial
+ PDF::Reuse::Barcode
+ PDF::Reuse::Scramble
+ PDF::Reuse::OverlayChart
+
+To program with PDF-operators, look at "The PDF-reference Manual" which probably
+is possible to download from http://partners.adobe.com/asn/developer/acrosdk/docs.html
+Look especially at chapter 4 and 5, Graphics and Text, and the Operator summary.
+
+Technical Note # 5186 contains the "Acrobat JavaScript Object Specification". I
+downloaded it from http://partners.adobe.com/asn/developer/technotes/acrobatpdf.html
+
+If you are serious about producing PDF-files, you probably need Adobe Acrobat sooner
+or later. It has a price tag. Other good programs are GhostScript and GSview.
+I got them via http://www.cs.wisc.edu/~ghost/index.html Sometimes they can replace Acrobat.
+A nice little detail is e.g. that GSview shows the x- and y-coordinates better then Acrobat. If you need to convert HTML-files to PDF, HTMLDOC is a possible tool. Download it from
+http://www.easysw.com . A simple tool for vector graphics is Mayura Draw 2.04, download
+it from http://www.mayura.com. It is free. I have used it to produce the graphic
+OO-code in the tutorial. It produces postscript which the Acrobat Distiller (you get it together with Acrobat)
+or Ghostscript can convert to PDF.(The commercial product, Mayura Draw 4.01 or something
+higher can produce PDF-files straight away)
+
+If you want to import jpeg-images, you might need
+
+ Image::Info
+
+To get definitions for e.g. colors, take them from
+
+ PDF::API2::Util
+
+=head1 LIMITATIONS
+
+Metadata, info and many other features of the PDF-format have not been
+implemented in this module.
+
+Many things can be added afterwards, after creating the files. If you e.g. need
+files to be encrypted, you can use a standard batch routine within Adobe Acrobat.
+
+=head1 TODO
+
+I have been experimenting a little with a helper application for Netscape or
+Internet Explorer and it is quite obvious that you could get very good performance
+and high reliability if you transferred the logs and constructed the documents at
+the target computer, instead of the transferring formatted documents.
+The reasons are:
+
+The size of a log is usually only a fraction of the formatted document. The logs
+keep a time stamp for all source files, so you could have a simple cashing. It is
+possible to put a time stamp on the log file and then you get a hierarchal structure.
+When the system reads a log file it could quickly find out which source files are
+missing. If it encounters the URL and time stamp of cashed log file, that would be
+sufficient. It would not be necessary to get it over the net.
+You would minimize the number of conversations and you would also increase the
+possibilities to complete a task even if the connections are bad.
+
+The cash could function as a secondary library for forms and JavaScripts.
+When you work with HTML you are usually interested in the most recent version of
+of a component. With PDF the emphasis is usually more on exactness, and PDF-documents
+tend to be more stable. This strengthens the motive for a functioning cash.
+
+(Also I think you could skip some holy rules from HTML-processing. E.g. if an
+international body has forms and JavaScripts for booking a hotel room, any
+affiliated hotel should have the right to use the common files, so they could be
+used via the cash regardless of if you are booking a room in Agadir or Shanghai.
+That would create libraries and rational reuse of code. I think security and
+legal problems would be possible to handle.)
+
+At the present time PDF cannot compete with HTML, but if you used the log files
+and a simple cash, PDF would be just superior for repeated tasks.
+
+=head1 THANKS TO
+
+Martin Langhoff and others who have contributed with code, suggestions and error
+reports.
+
+=head1 AUTHOR
+
+Lars Lundberg elkelund @ worldonline . se
+
+=head1 COPYRIGHT
+
+Copyright (C) 2003 - 2004 Lars Lundberg, Solidez HB. All rights reserved.
+This program is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+=head1 DISCLAIMER
+
+You get this module free as it is, but nothing is guaranteed to work, whatever
+implicitly or explicitly stated in this document, and everything you do,
+you do at your own risk - I will not take responsibility
+for any damage, loss of money and/or health that may arise from the use of this module.
+
+=cut
+
+sub prLink
+{ my %link;
+ my $param = shift;
+ if (ref($param) eq 'HASH')
+ { $link{page} = $param->{'page'} || -1;
+ $link{x} = $param->{'x'} || 100;
+ $link{y} = $param->{'y'} || 100;
+ $link{width} = $param->{width} || 75;
+ $link{height} = $param->{height} || 15;
+ $link{action} = $param->{action} || undef;
+ $link{border} = $param->{border} || undef;
+ $link{color} = $param->{color} || undef;
+ $link{URI} = $param->{URI};
+ }
+ else
+ { $link{page} = $param || -1;
+ $link{x} = shift || 100;
+ $link{y} = shift || 100;
+ $link{width} = shift || 75;
+ $link{height} = shift || 15;
+ $link{URI} = shift;
+ }
+
+ if (! $pos)
+ { errLog("No output file, you have to call prFile first");
+ }
+
+ if ($runfil)
+ { $log .= "Link~$link{page}~$link{x}~$link{y}~$link{width}~"
+ . "$link{height}~$link{URI}\n";
+ }
+
+ if ($link{URI} || $link{action})
+ { push @{$links{$link{page}}}, \%link;
+ }
+ 1;
+}
+
+sub mergeLinks
+{ my $tSida = $sida + 1;
+ my $rad;
+ my ($linkObject, $linkObjectNo);
+ for my $link (@{$links{'-1'}}, @{$links{$tSida}} )
+ { my $x2 = $link->{x} + $link->{width};
+ my $y2 = $link->{y} + $link->{height};
+ if (defined $link->{action})
+ {
+ if (exists $links{$link->{action}})
+ { $linkObjectNo = $links{$link->{action}};
+ }
+ else
+ { $objNr++;
+ $objekt[$objNr] = $pos;
+ $rad = "$objNr 0 obj<<$link->{action}>>endobj\n";
+ $linkObjectNo = $objNr;
+ $links{$link->{action}} = $objNr;
+ $pos += syswrite UTFIL, $rad;
+ }
+ }
+ else
+ {
+ if (exists $links{$link->{URI}})
+ { $linkObjectNo = $links{$link->{URI}};
+ }
+ else
+ { $objNr++;
+ $objekt[$objNr] = $pos;
+ $rad = "$objNr 0 obj<</S/URI/URI($link->{URI})>>endobj\n";
+ $linkObjectNo = $objNr;
+ $links{$link->{URI}} = $objNr;
+ $pos += syswrite UTFIL, $rad;
+ }
+ }
+ $rad = "/Subtype/Link/Rect[$link->{x} $link->{y} "
+ . "$x2 $y2]/A $linkObjectNo 0 R";
+ if (defined $link->{border})
+ { $rad .= "/Border$link->{border}";
+ }
+ else
+ { $rad .= "/Border[0 0 0]";
+ }
+ if (defined $link->{color})
+ { $rad .= "/C$link->{color}";
+ }
+ if (exists $links{$rad})
+ { push @annots, $links{$rad};
+ }
+ else
+ { $objNr++;
+ $objekt[$objNr] = $pos;
+ $links{$rad} = $objNr;
+ $rad = "$objNr 0 obj<<$rad>>endobj\n";
+ $pos += syswrite UTFIL, $rad;
+ push @annots, $objNr;
+ }
+ }
+ @{$links{'-1'}} = ();
+ @{$links{$tSida}} = ();
+ $objNr++;
+ $objekt[$objNr] = $pos;
+ $rad = "$objNr 0 obj[\n";
+ for (@annots)
+ { $rad .= "$_ 0 R\n";
+ }
+ $rad .= "]endobj\n";
+ $pos += syswrite UTFIL, $rad;
+ @annots = ();
+ return $objNr;
+}
+
+sub prStrWidth
+{ require PDF::Reuse::Util;
+ my $string = shift;
+ my $Font = shift;
+ my $FontSize = shift || $fontSize;
+ my $w = 0;
+
+ if (! $Font)
+ { if (! $aktuellFont[foEXTNAMN])
+ { findFont();
+ }
+ $Font = $aktuellFont[foEXTNAMN];
+ }
+
+ if (! exists $PDF::Reuse::Util::font_widths{$Font})
+ { if (exists $stdFont{$Font})
+ { $Font = $stdFont{$Font};
+ }
+ if (! exists $PDF::Reuse::Util::font_widths{$Font})
+ { $Font = 'Helvetica';
+ }
+ }
+
+ if (ref($PDF::Reuse::Util::font_widths{$Font}) eq 'ARRAY')
+ { my @font_table = @{ $PDF::Reuse::Util::font_widths{$Font} };
+ for (unpack ("C*", $string))
+ { $w += $font_table[$_];
+ }
+ }
+ else
+ { $w = length($string) * $PDF::Reuse::Util::font_widths{$Font};
+ }
+ $w = $w / 1000 * $FontSize;
+
+ return $w;
+}
+
+
+sub prBookmark
+{ my $param = shift;
+ if (! ref($param))
+ { $param = eval ($param);
+ }
+ if (! ref($param))
+ { return undef;
+ }
+ if (! $pos)
+ { errLog("No output file, you have to call prFile first");
+ }
+ if (ref($param) eq 'HASH')
+ { push @bookmarks, $param;
+ }
+ else
+ { push @bookmarks, (@$param);
+ }
+ if ($runfil)
+ { local $Data::Dumper::Indent = 0;
+ $param = Dumper($param);
+ $param =~ s/^\$VAR1 = //;
+ $param = prep($param);
+ $log .= "Bookmark~$param\n";
+ }
+ return 1;
+}
+
+sub ordnaBookmarks
+{ my ($first, $last, $me, $entry, $rad);
+ $totalCount = 0;
+ if (defined $objekt[$objNr])
+ { $objNr++;
+ }
+ $me = $objNr;
+
+ my $number = $#bookmarks;
+ for (my $i = 0; $i <= $number ; $i++)
+ { my %hash = %{$bookmarks[$i]};
+ $objNr++;
+ $hash{'this'} = $objNr;
+ if ($i == 0)
+ { $first = $objNr;
+ }
+ if ($i == $number)
+ { $last = $objNr;
+ }
+ if ($i < $number)
+ { $hash{'next'} = $objNr + 1;
+ }
+ if ($i > 0)
+ { $hash{'previous'} = $objNr - 1;
+ }
+ $bookmarks[$i] = \%hash;
+ }
+
+ for $entry (@bookmarks)
+ { my %hash = %{$entry};
+ descend ($me, %hash);
+ }
+
+ $objekt[$me] = $pos;
+
+ $rad = "$me 0 obj<<";
+ $rad .= "/Type/Outlines";
+ $rad .= "/Count $totalCount";
+ if (defined $first)
+ { $rad .= "/First $first 0 R";
+ }
+ if (defined $last)
+ { $rad .= "/Last $last 0 R";
+ }
+ $rad .= ">>endobj\n";
+ $pos += syswrite UTFIL, $rad;
+
+ return $me;
+
+}
+
+sub descend
+{ my ($parent, %entry) = @_;
+ my ($first, $last, $count, $me, $rad, $jsObj);
+ if (! exists $entry{'close'})
+ { $totalCount++; }
+ $count = $totalCount;
+ $me = $entry{'this'};
+ if (exists $entry{'kids'})
+ { if (ref($entry{'kids'}) eq 'ARRAY')
+ { my @array = @{$entry{'kids'}};
+ my $number = $#array;
+ for (my $i = 0; $i <= $number ; $i++)
+ { $objNr++;
+ $array[$i]->{'this'} = $objNr;
+ if ($i == 0)
+ { $first = $objNr;
+ }
+ if ($i == $number)
+ { $last = $objNr;
+ }
+
+ if ($i < $number)
+ { $array[$i]->{'next'} = $objNr + 1;
+ }
+ if ($i > 0)
+ { $array[$i]->{'previous'} = $objNr - 1;
+ }
+ if (exists $entry{'close'})
+ { $array[$i]->{'close'} = 1;
+ }
+ }
+
+ for my $element (@array)
+ { descend($me, %{$element})
+ }
+ }
+ else # a hash
+ { my %hash = %{$entry{'kids'}};
+ $objNr++;
+ $hash{'this'} = $objNr;
+ $first = $objNr;
+ $last = $objNr;
+ descend($me, %hash)
+ }
+ }
+
+ if (exists $entry{'act'})
+ { my $code = $entry{'act'};
+ if ($code =~ m/^\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*$/os)
+ { $code = "this.pageNum = $1; this.scroll($2, $3);";
+ }
+ $jsObj = skrivJS($code);
+ }
+
+ $objekt[$me] = $pos;
+ $rad = "$me 0 obj<<";
+ if (exists $entry{'text'})
+ { $rad .= "/Title ($entry{'text'})";
+ }
+ $rad .= "/Parent $parent 0 R";
+ if (defined $jsObj)
+ { $rad .= "/A $jsObj 0 R";
+ }
+ elsif (exists $entry{'pdfact'})
+ { $rad .= "/A << $entry{'pdfact'} >>";
+ }
+ if (exists $entry{'previous'})
+ { $rad .= "/Prev $entry{'previous'} 0 R";
+ }
+ if (exists $entry{'next'})
+ { $rad .= "/Next $entry{'next'} 0 R";
+ }
+ if (defined $first)
+ { $rad .= "/First $first 0 R";
+ }
+ if (defined $last)
+ { $rad .= "/Last $last 0 R";
+ }
+ if ($count != $totalCount)
+ { $count = $totalCount - $count;
+ $rad .= "/Count $count";
+ }
+ if (exists $entry{'color'})
+ { $rad .= "/C [$entry{'color'}]";
+ }
+ if (exists $entry{'style'})
+ { $rad .= "/F $entry{'style'}";
+ }
+
+ $rad .= ">>endobj\n";
+ $pos += syswrite UTFIL, $rad;
+}
+
+sub prInitVars
+{ my $exit = shift;
+ $genLowerX = 0;
+ $genLowerY = 0;
+ $genUpperX = 595,
+ $genUpperY = 842;
+ $fontSize = 12;
+ ($utfil, $slutNod, $formCont, $imSeq,
+ $page, $sidObjNr, $interActive, $NamesSaved, $AARootSaved, $AAPageSaved,
+ $root, $AcroFormSaved, $id, $ldir, $checkId, $formNr, $imageNr,
+ $filnamn, $interAktivSida, $taInterAkt, $type, $runfil, $checkCs,
+ $confuseObj, $compress,$pos, $fontNr, $objNr,
+ $defGState, $gSNr, $pattern, $shading, $colorSpace) = '';
+
+ (@kids, @counts, @formBox, @objekt, @parents, @aktuellFont, @skapa,
+ @jsfiler, @inits, @bookmarks, @annots) = ();
+
+ ( %resurser, %objRef, %nyaFunk,%oldObject, %unZipped,
+ %sidFont, %sidXObject, %sidExtGState, %font, %fields, %script,
+ %initScript, %sidPattern, %sidShading, %sidColorSpace, %knownToFile,
+ %processed, %dummy) = ();
+
+ $stream = '';
+ $idTyp = '';
+ $ddir = '';
+ $log = '';
+
+ if ($exit)
+ { return 1;
+ }
+
+ ( %form, %image, %fontSource, %intAct) = ();
+
+ return 1;
+}
+
+####################
+# Behandla en bild
+####################
+
+sub prImage
+{ my $param = shift;
+ my ($infil, $sidnr, $bildnr, $effect, $adjust, $x, $y, $size, $xsize,
+ $ysize, $rotate);
+
+ if (ref($param) eq 'HASH')
+ { $infil = $param->{'file'};
+ $sidnr = $param->{'page'} || 1;
+ $bildnr = $param->{'imageNo'} || 1;
+ $effect = $param->{'effect'} || 'print';
+ $adjust = $param->{'adjust'} || '';
+ $x = $param->{'x'} || 0;
+ $y = $param->{'y'} || 0;
+ $rotate = $param->{'rotate'} || 0;
+ $size = $param->{'size'} || 1;
+ $xsize = $param->{'xsize'} || 1;
+ $ysize = $param->{'ysize'} || 1;
+ }
+ else
+ { $infil = $param;
+ $sidnr = shift || 1;
+ $bildnr = shift || 1;
+ $effect = shift || 'print';
+ $adjust = shift || '';
+ $x = shift || 0;
+ $y = shift || 0;
+ $rotate = shift || 0;
+ $size = shift || 1;
+ $xsize = shift || 1;
+ $ysize = shift || 1;
+ }
+
+ my ($refNr, $inamn, $bildIndex, $xc, $yc, $xs, $ys);
+ $type = 'image';
+
+ $bildIndex = $bildnr - 1;
+ my $fSource = $infil . '_' . $sidnr;
+ my $iSource = $fSource . '_' . $bildnr;
+ if (! exists $image{$iSource})
+ { $imageNr++;
+ $inamn = 'Im' . $imageNr;
+ $knownToFile{'Im:' . $iSource} = $inamn;
+ $image{$iSource}[imXPOS] = 0;
+ $image{$iSource}[imYPOS] = 0;
+ $image{$iSource}[imXSCALE] = 1;
+ $image{$iSource}[imYSCALE] = 1;
+ if (! exists $form{$fSource} )
+ { $refNr = getPage($infil, $sidnr, '');
+ if ($refNr)
+ { $formNr++;
+ my $namn = 'Fm' . $formNr;
+ $knownToFile{$fSource} = $namn;
+ }
+ elsif ($refNr eq '0')
+ { errLog("File: $infil Page: $sidnr can't be found");
+ }
+ }
+ my $in = $form{$fSource}[fIMAGES][$bildIndex];
+ $image{$iSource}[imWIDTH] = $form{$fSource}->[fOBJ]->{$in}->[oWIDTH];
+ $image{$iSource}[imHEIGHT] = $form{$fSource}->[fOBJ]->{$in}->[oHEIGHT];
+ $image{$iSource}[imIMAGENO] = $form{$fSource}[fIMAGES][$bildIndex];
+ }
+ if (exists $knownToFile{'Im:' . $iSource})
+ { $inamn = $knownToFile{'Im:' . $iSource};
+ }
+ else
+ { $imageNr++;
+ $inamn = 'Im' . $imageNr;
+ $knownToFile{'Im:' . $iSource} = $inamn;
+ }
+ if (! exists $objRef{$inamn})
+ { $refNr = getImage($infil, $sidnr,
+ $bildnr, $image{$iSource}[imIMAGENO]);
+ $objRef{$inamn} = $refNr;
+ }
+ else
+ { $refNr = $objRef{$inamn};
+ }
+
+ my @iData = @{$image{$iSource}};
+
+ if (($effect eq 'print') && ($refNr))
+ { if (! defined $defGState)
+ { prDefaultGrState();}
+ $stream .= "\n/Gs0 gs\n";
+ $stream .= "q\n";
+
+ if ($adjust)
+ { $stream .= fillTheForm(0, 0, $iData[imWIDTH], $iData[imHEIGHT],$adjust);
+ }
+ else
+ { my $tX = ($x + $iData[imXPOS]);
+ my $tY = ($y + $iData[imYPOS]);
+ $stream .= calcMatrix($tX, $tY, $rotate, $size,
+ $xsize, $ysize, $iData[imWIDTH], $iData[imHEIGHT]);
+ }
+ $stream .= "$iData[imWIDTH] 0 0 $iData[imHEIGHT] 0 0 cm\n";
+ $stream .= "/$inamn Do\n";
+ $sidXObject{$inamn} = $refNr;
+ $stream .= "Q\n";
+ $sidExtGState{'Gs0'} = $defGState;
+ }
+ if ($runfil)
+ { $infil = prep($infil);
+ $log .= "Image~$infil~$sidnr~$bildnr~$effect~$adjust";
+ $log .= "$x~$y~$size~$xsize~$ysize~$rotate\n";
+ }
+ if (! $pos)
+ { errLog("No output file, you have to call prFile first");
+ }
+
+ if (wantarray)
+ { return ($inamn, $iData[imWIDTH], $iData[imHEIGHT]);
+ }
+ else
+ { return $inamn;
+ }
+}
+
+
+
+sub prMbox
+{ my $lx = shift || 0;
+ my $ly = shift || 0;
+ my $ux = shift || 595;
+ my $uy = shift || 842;
+
+ if ((defined $lx) && ($lx =~ m'^[\d\-\.]+$'o))
+ { $genLowerX = $lx; }
+ if ((defined $ly) && ($ly =~ m'^[\d\-\.]+$'o))
+ { $genLowerY = $ly; }
+ if ((defined $ux) && ($ux =~ m'^[\d\-\.]+$'o))
+ { $genUpperX = $ux; }
+ if ((defined $uy) && ($uy =~ m'^[\d\-\.]+$'o))
+ { $genUpperY = $uy; }
+ if ($runfil)
+ { $log .= "Mbox~$lx~$ly~$ux~$uy\n";
+ }
+ if (! $pos)
+ { errLog("No output file, you have to call prFile first");
+ }
+ 1;
+}
+
+sub prField
+{ my ($fieldName, $fieldValue) = @_;
+ if (($interAktivSida) || ($interActive))
+ { errLog("Too late, has already tried to INITIATE FIELDS within an interactive page");
+ }
+ elsif (! $pos)
+ { errLog("Too early INITIATE FIELDS, create a file first");
+ }
+ $fields{$fieldName} = $fieldValue;
+ if ($fieldValue =~ m'^\s*js\s*\:(.*)'oi)
+ { my $code = $1;
+ my @fall = ($code =~ m'([\w\d\_\$]+)\s*\(.*?\)'gs);
+ for (@fall)
+ { if (! exists $initScript{$_})
+ { $initScript{$_} = 0;
+ }
+ }
+ }
+ if ($runfil)
+ { $fieldName = prep($fieldName);
+ $fieldValue = prep($fieldValue);
+ $log .= "Field~$fieldName~$fieldValue\n";
+ }
+ 1;
+}
+############################################################
+sub prBar
+{ my ($xPos, $yPos, $TxT) = @_;
+
+ $TxT =~ tr/G/2/;
+
+ my @fontSpar = @aktuellFont;
+
+ findBarFont();
+
+ my $Font = $aktuellFont[foINTNAMN]; # Namn i strömmen
+
+ if (($xPos) && ($yPos))
+ { $stream .= "\nBT /$Font $fontSize Tf ";
+ $stream .= "$xPos $yPos Td \($TxT\) Tj ET\n";
+ }
+ if ($runfil)
+ { $log .= "Bar~$xPos~$yPos~$TxT\n";
+ }
+ if (! $pos)
+ { errLog("No output file, you have to call prFile first");
+ }
+ @aktuellFont = @fontSpar;
+ return $Font;
+
+}
+
+
+sub prExtract
+{ my $name = shift;
+ my $form = shift;
+ my $page = shift || 1;
+ if ($name =~ m'^/(\w+)'o)
+ { $name = $1;
+ }
+ my $fullName = "$name~$form~$page";
+ if (exists $knownToFile{$fullName})
+ { return $knownToFile{$fullName};
+ }
+ else
+ { if ($runfil)
+ { $log = "Extract~$fullName\n";
+ }
+ if (! $pos)
+ { errLog("No output file, you have to call prFile first");
+ }
+
+ if (! exists $form{$form . '_' . $page})
+ { prForm($form, $page, undef, 'load', 1);
+ }
+ $name = extractName($form, $page, $name);
+ if ($name)
+ { $knownToFile{$fullName} = $name;
+ }
+ return $name;
+ }
+}
+
+
+########## Extrahera ett dokument ####################
+sub prDoc
+{ my ($infil, $first, $last);
+ my $param = shift;
+ if (ref($param) eq 'HASH')
+ { $infil = $param->{'file'};
+ $first = $param->{'first'} || 1;
+ $last = $param->{'last'} || '';
+ }
+ else
+ { $infil = $param;
+ $first = shift || 1;
+ $last = shift || '';
+ }
+
+ if ($stream)
+ { if ($stream =~ m'\S+'os)
+ { skrivSida();}
+ else
+ { undef $stream; }
+ }
+
+ if (! $objekt[$objNr]) # Objektnr behöver inte reserveras här
+ { $objNr--;
+ }
+
+ my ($sidor, $Names, $AARoot, $AcroForm) = analysera($infil, $first, $last);
+ if (($Names) || ($AARoot) || ($AcroForm))
+ { $NamesSaved = $Names;
+ $AARootSaved = $AARoot;
+ $AcroFormSaved = $AcroForm;
+ $interActive = 1;
+ }
+ if ($runfil)
+ { $infil = prep($infil);
+ $log .= "Doc~$infil~$first~$last\n";
+ }
+ if (! $pos)
+ { errLog("No output file, you have to call prFile first");
+ }
+ return $sidor;
+}
+
+############# Ett interaktivt + grafiskt "formulär" ##########
+
+sub prDocForm
+{my ($sidnr, $adjust, $effect, $tolerant, $infil, $x, $y, $size, $xsize,
+ $ysize, $rotate);
+ my $param = shift;
+ if (ref($param) eq 'HASH')
+ { $infil = $param->{'file'};
+ $sidnr = $param->{'page'} || 1;
+ $adjust = $param->{'adjust'} || '';
+ $effect = $param->{'effect'} || 'print';
+ $tolerant = $param->{'tolerant'} || '';
+ $x = $param->{'x'} || 0;
+ $y = $param->{'y'} || 0;
+ $rotate = $param->{'rotate'} || 0;
+ $size = $param->{'size'} || 1;
+ $xsize = $param->{'xsize'} || 1;
+ $ysize = $param->{'ysize'} || 1;
+ }
+ else
+ { $infil = $param;
+ $sidnr = shift || 1;
+ $adjust = shift || '';
+ $effect = shift || 'print';
+ $tolerant = shift || '';
+ $x = shift || 0;
+ $y = shift || 0;
+ $rotate = shift || 0;
+ $size = shift || 1;
+ $xsize = shift || 1;
+ $ysize = shift || 1;
+ }
+ my $namn;
+ my $refNr;
+ $type = 'docform';
+ my $fSource = $infil . '_' . $sidnr;
+ my $action;
+ if (! exists $form{$fSource})
+ { $formNr++;
+ $namn = 'Fm' . $formNr;
+ $knownToFile{$fSource} = $namn;
+ if ($effect eq 'load')
+ { $action = 'load'
+ }
+ else
+ { $action = 'print'
+ }
+ $refNr = getPage($infil, $sidnr, $action);
+ if ($refNr)
+ { $objRef{$namn} = $refNr;
+ }
+ else
+ { if ($tolerant)
+ { if ((defined $refNr) && ($refNr eq '0')) # Sidnumret existerar inte, men ok
+ { $namn = '0';
+ }
+ else
+ { undef $namn; # Sidan kan inte användas som form
+ }
+ }
+ elsif (! defined $refNr)
+ { my $mess = "$fSource can't be used as a form. Try e.g. to\n"
+ . "save the file as postscript, and redistill\n";
+ errLog($mess);
+ }
+ else
+ { errLog("File : $infil Page: $sidnr doesn't exist");
+ }
+ }
+ }
+ else
+ { if (exists $knownToFile{$fSource})
+ { $namn = $knownToFile{$fSource};
+ }
+ else
+ { $formNr++;
+ $namn = 'Fm' . $formNr;
+ $knownToFile{$fSource} = $namn;
+ }
+ if (exists $objRef{$namn})
+ { $refNr = $objRef{$namn};
+ }
+ else
+ { if (! $form{$fSource}[fVALID])
+ { my $mess = "$fSource can't be used as a form. Try e.g. to\n"
+ . "concatenate the streams of the page\n";
+ if ($tolerant)
+ { cluck $mess;
+ undef $namn;
+ }
+ else
+ { errLog($mess);
+ }
+ }
+ elsif ($effect ne 'load')
+ { $refNr = byggForm($infil, $sidnr);
+ $objRef{$namn} = $refNr;
+ }
+ }
+ }
+ my @BBox = @{$form{$fSource}[fBBOX]} if ($refNr);
+ if (($effect eq 'print') && ($form{$fSource}[fVALID]) && ($refNr))
+ { if ((! defined $interActive)
+ && ($sidnr == 1)
+ && (defined %{$intAct{$fSource}[0]}) )
+ { $interActive = $infil . ' ' . $sidnr;
+ $interAktivSida = 1;
+ }
+ if (! defined $defGState)
+ { prDefaultGrState();
+ }
+ if ($adjust)
+ { $stream .= "q\n";
+ $stream .= fillTheForm(@BBox, $adjust);
+ $stream .= "\n/Gs0 gs\n";
+ $stream .= "/$namn Do\n";
+ $stream .= "Q\n";
+ }
+ elsif (($x) || ($y) || ($rotate) || ($size != 1)
+ || ($xsize != 1) || ($ysize != 1))
+ { $stream .= "q\n";
+ $stream .= calcMatrix($x, $y, $rotate, $size,
+ $xsize, $ysize, $BBox[2], $BBox[3]);
+ $stream .= "\n/Gs0 gs\n";
+ $stream .= "/$namn Do\n";
+ $stream .= "Q\n";
+ }
+ else
+ { $stream .= "\n/Gs0 gs\n";
+ $stream .= "/$namn Do\n";
+ }
+ $sidXObject{$namn} = $refNr;
+ $sidExtGState{'Gs0'} = $defGState;
+ }
+ if ($runfil)
+ { $infil = prep($infil);
+ $log .= "Form~$infil~$sidnr~$adjust~$effect~$tolerant";
+ $log .= "~$x~$y~$rotate~$size~$xsize~$ysize\n";
+ }
+ if (! $pos)
+ { errLog("No output file, you have to call prFile first");
+ }
+ if (($effect ne 'print') && ($effect ne 'add'))
+ { undef $namn;
+ }
+ if (wantarray)
+ { my $images = 0;
+ if (exists $form{$fSource}[fIMAGES])
+ { $images = scalar(@{$form{$fSource}[fIMAGES]});
+ }
+ return ($namn, $BBox[0], $BBox[1], $BBox[2],
+ $BBox[3], $images);
+ }
+ else
+ { return $namn;
+ }
+}
+
+sub calcMatrix
+{ my ($x, $y, $rotate, $size, $xsize, $ysize, $upperX, $upperY) = @_;
+ my ($str, $xSize, $ySize);
+ $size = 1 if ($size == 0);
+ $xsize = 1 if ($xsize == 0);
+ $ysize = 1 if ($ysize == 0);
+ $xSize = $xsize * $size;
+ $ySize = $ysize * $size;
+ $str = "$xSize 0 0 $ySize $x $y cm\n";
+ if ($rotate)
+ { if ($rotate =~ m'q(\d)'oi)
+ { my $tal = $1;
+ if ($tal == 1)
+ { $upperY = $upperX;
+ $upperX = 0;
+ $rotate = 270;
+ }
+ elsif ($tal == 2)
+ { $rotate = 180;
+ }
+ else
+ { $rotate = 90;
+ $upperX = $upperY;
+ $upperY = 0;
+ }
+ }
+ else
+ { $upperX = 0;
+ $upperY = 0;
+ }
+ my $radian = sprintf("%.6f", $rotate / 57.2957795); # approx.
+ my $Cos = sprintf("%.6f", cos($radian));
+ my $Sin = sprintf("%.6f", sin($radian));
+ my $negSin = $Sin * -1;
+ $str .= "$Cos $Sin $negSin $Cos $upperX $upperY cm\n";
+ }
+ return $str;
+}
+
+sub fillTheForm
+{ my $left = shift || 0;
+ my $bottom = shift || 0;
+ my $right = shift || 0;
+ my $top = shift || 0;
+ my $how = shift || 1;
+ my $image = shift;
+ my $str;
+ my $scaleX = 1;
+ my $scaleY = 1;
+
+ my $xDim = $genUpperX - $genLowerX;
+ my $yDim = $genUpperY - $genLowerY;
+ my $xNy = $right - $left;
+ my $yNy = $top - $bottom;
+ $scaleX = $xDim / $xNy;
+ $scaleY = $yDim / $yNy;
+ if ($how == 1)
+ { if ($scaleX < $scaleY)
+ { $scaleY = $scaleX;
+ }
+ else
+ { $scaleX = $scaleY;
+ }
+ }
+ $str = "$scaleX 0 0 $scaleY $left $bottom cm\n";
+ return $str;
+}
+
+sub prJpeg
+{ my ($iFile, $iWidth, $iHeight) = @_;
+ my ($iLangd, $namnet, $utrad);
+ if (! $pos) # If no output is active, it is no use to continue
+ { return undef;
+ }
+ my $checkidOld = $checkId;
+ ($iFile, $checkId) = findGet($iFile, $checkidOld);
+ if ($iFile)
+ { $iLangd = (stat($iFile))[7];
+ $imageNr++;
+ $namnet = 'Im' . $imageNr;
+ $objNr++;
+ $objekt[$objNr] = $pos;
+ open (BILDFIL, "<$iFile") || errLog("Couldn't open $iFile, $!, aborts");
+ binmode BILDFIL;
+ my $iStream;
+ sysread BILDFIL, $iStream, $iLangd;
+ $utrad = "$objNr 0 obj\n<</Type/XObject/Subtype/Image/Name/$namnet" .
+ "/Width $iWidth /Height $iHeight /BitsPerComponent 8 /Filter/DCTDecode/ColorSpace/DeviceRGB"
+ . "/Length $iLangd >>stream\n$iStream\nendstream\nendobj\n";
+ close BILDFIL;
+ $pos += syswrite UTFIL, $utrad;
+ if ($runfil)
+ { $log .= "Cid~$checkId\n";
+ $log .= "Jpeg~$iFile~$iWidth~$iHeight\n";
+ }
+ $objRef{$namnet} = $objNr;
+ }
+ if (! $pos)
+ { errLog("No output file, you have to call prFile first");
+ }
+ undef $checkId;
+ return $namnet;
+}
+
+sub checkContentStream
+{ for (@_)
+ { if (my $value = $objRef{$_})
+ { my $typ = substr($_, 0, 2);
+ if ($typ eq 'Ft')
+ { $sidFont{$_} = $value;
+ }
+ elsif ($typ eq 'Gs')
+ { $sidExtGState{$_} = $value;
+ }
+ elsif ($typ eq 'Pt')
+ { $sidPattern{$_} = $value;
+ }
+ elsif ($typ eq 'Sh')
+ { $sidShading{$_} = $value;
+ }
+ elsif ($typ eq 'Cs')
+ { $sidColorSpace{$_} = $value;
+ }
+ else
+ { $sidXObject{$_} = $value;
+ }
+ }
+ elsif (($_ eq 'Gs0') && (! defined $defGState))
+ { my ($dummy, $oNr) = prDefaultGrState();
+ $sidExtGState{'Gs0'} = $oNr;
+ }
+ }
+}
+
+sub prGraphState
+{ my $string = shift;
+ $gSNr++;
+ my $name = 'Gs' . $gSNr ;
+ $objNr++;
+ $objekt[$objNr] = $pos;
+ my $utrad = "$objNr 0 obj\n" . $string . "\nendobj\n";
+ $pos += syswrite UTFIL, $utrad;
+ $objRef{$name} = $objNr;
+ if ($runfil)
+ { $log .= "GraphStat~$string\n";
+ }
+ if (! $pos)
+ { errLog("No output file, you have to call prFile first");
+ }
+ return $name;
+}
+
+##############################################################
+# Streckkods fonten lokaliseras och objekten skrivs ev. ut
+##############################################################
+
+sub findBarFont()
+{ my $Font = 'Bar';
+
+ if (exists $font{$Font}) # Objekt är redan definierat
+ { $aktuellFont[foEXTNAMN] = $Font;
+ $aktuellFont[foREFOBJ] = $font{$Font}[foREFOBJ];
+ $aktuellFont[foINTNAMN] = $font{$Font}[foINTNAMN];
+ }
+ else
+ { $objNr++;
+ $objekt[$objNr] = $pos;
+ my $encodObj = $objNr;
+ my $fontObjekt = "$objNr 0 obj\n<< /Type /Encoding\n" .
+ '/Differences [48 /tomt /streck /lstreck]' . "\n>>\nendobj\n";
+ $pos += syswrite UTFIL, $fontObjekt;
+ my $charProcsObj = createCharProcs();
+ $objNr++;
+ $objekt[$objNr] = $pos;
+ $fontNr++;
+ my $fontAbbr = 'Ft' . $fontNr;
+ $fontObjekt = "$objNr 0 obj\n<</Type/Font/Subtype/Type3\n" .
+ '/FontBBox [0 -250 75 2000]' . "\n" .
+ '/FontMatrix [0.001 0 0 0.001 0 0]' . "\n" .
+ "\/CharProcs $charProcsObj 0 R\n" .
+ "\/Encoding $encodObj 0 R\n" .
+ '/FirstChar 48' . "\n" .
+ '/LastChar 50' . "\n" .
+ '/Widths [75 75 75]' . "\n>>\nendobj\n";
+
+ $font{$Font}[foINTNAMN] = $fontAbbr;
+ $font{$Font}[foREFOBJ] = $objNr;
+ $objRef{$fontAbbr} = $objNr;
+ $objekt[$objNr] = $pos;
+ $aktuellFont[foEXTNAMN] = $Font;
+ $aktuellFont[foREFOBJ] = $objNr;
+ $aktuellFont[foINTNAMN] = $fontAbbr;
+ $pos += syswrite UTFIL, $fontObjekt;
+ }
+ if (! $pos)
+ { errLog("No output file, you have to call prFile first");
+ }
+
+ $sidFont{$aktuellFont[foINTNAMN]} = $aktuellFont[foREFOBJ];
+}
+
+sub createCharProcs()
+{ #################################
+ # Fonten (objektet) för 0 skapas
+ #################################
+
+ $objNr++;
+ $objekt[$objNr] = $pos;
+ my $tomtObj = $objNr;
+ my $str = "\n75 0 d0\n6 0 69 2000 re\n1.0 g\nf\n";
+ my $strLength = length($str);
+ my $obj = "$objNr 0 obj\n<< /Length $strLength >>\nstream" .
+ $str . "\nendstream\nendobj\n";
+ $pos += syswrite UTFIL, $obj;
+
+ #################################
+ # Fonten (objektet) för 1 skapas
+ #################################
+
+ $objNr++;
+ $objekt[$objNr] = $pos;
+ my $streckObj = $objNr;
+ $str = "\n75 0 d0\n4 0 71 2000 re\n0.0 g\nf\n";
+ $strLength = length($str);
+ $obj = "$objNr 0 obj\n<< /Length $strLength >>\nstream" .
+ $str . "\nendstream\nendobj\n";
+ $pos += syswrite UTFIL, $obj;
+
+ ###################################################
+ # Fonten (objektet) för 2, ett långt streck skapas
+ ###################################################
+
+ $objNr++;
+ $objekt[$objNr] = $pos;
+ my $lStreckObj = $objNr;
+ $str = "\n75 0 d0\n4 -250 71 2250 re\n0.0 g\nf\n";
+ $strLength = length($str);
+ $obj = "$objNr 0 obj\n<< /Length $strLength >>\nstream" .
+ $str . "\nendstream\nendobj\n";
+ $pos += syswrite UTFIL, $obj;
+
+ #####################################################
+ # Objektet för "CharProcs" skapas
+ #####################################################
+
+ $objNr++;
+ $objekt[$objNr] = $pos;
+ my $charProcsObj = $objNr;
+ $obj = "$objNr 0 obj\n<</tomt $tomtObj 0 R\n/streck $streckObj 0 R\n" .
+ "/lstreck $lStreckObj 0 R>>\nendobj\n";
+ $pos += syswrite UTFIL, $obj;
+ return $charProcsObj;
+}
+
+
+
+sub prCid
+{ $checkId = shift;
+ if ($runfil)
+ { $log .= "Cid~$checkId\n";
+ }
+ 1;
+}
+
+sub prIdType
+{ $idTyp = shift;
+ if ($runfil)
+ { $log .= "IdType~rep\n";
+ }
+ 1;
+}
+
+
+sub prId
+{ $id = shift;
+ if ($runfil)
+ { $log .= "Id~$id\n";
+ }
+ if (! $pos)
+ { errLog("No output file, you have to call prFile first");
+ }
+ 1;
+}
+
+sub prJs
+{ my $filNamnIn = shift;
+ my $filNamn;
+ if ($filNamnIn !~ m'\{'os)
+ { my $checkIdOld = $checkId;
+ ($filNamn, $checkId) = findGet($filNamnIn, $checkIdOld);
+ if (($runfil) && ($checkId) && ($checkId ne $checkIdOld))
+ { $log .= "Cid~$checkId\n";
+ }
+ $checkId = '';
+ }
+ else
+ { $filNamn = $filNamnIn;
+ }
+ if ($runfil)
+ { my $filnamn = prep($filNamn);
+ $log .= "Js~$filnamn\n";
+ }
+ if (($interAktivSida) || ($interActive))
+ { errLog("Too late, has already tried to merge JAVA SCRIPTS within an interactive page");
+ }
+ elsif (! $pos)
+ { errLog("Too early for JAVA SCRIPTS, create a file first");
+ }
+ push @jsfiler, $filNamn;
+ 1;
+}
+
+sub prInit
+{ my $initText = shift;
+ my $duplicate = shift || '';
+ my @fall = ($initText =~ m'([\w\d\_\$]+)\s*\(.*?\)'gs);
+ for (@fall)
+ { if (! exists $initScript{$_})
+ { $initScript{$_} = 0;
+ }
+ }
+ if ($duplicate)
+ { $duplicateInits = 1;
+ }
+ push @inits, $initText;
+ if ($runfil)
+ { $initText = prep($initText);
+ $log .= "Init~$initText~$duplicate\n";
+ }
+ if (($interAktivSida) || ($interActive))
+ { errLog("Too late, has already tried to create INITIAL JAVA SCRIPTS within an interactive page");
+ }
+ elsif (! $pos)
+ { errLog("Too early for INITIAL JAVA SCRIPTS, create a file first");
+ }
+ 1;
+
+}
+
+sub prVers
+{ my $vers = shift;
+ ############################################################
+ # Om programmet körs om så kontrolleras VERSION
+ ############################################################
+ if ($vers ne $VERSION)
+ { warn "$vers \<\> $VERSION might give different results, if comparing two runs \n";
+ return undef;
+ }
+ else
+ { return 1;
+ }
+}
+
+sub prDocDir
+{ $ddir = findDir(shift);
+ 1;
+}
+
+sub prLogDir
+{ $ldir = findDir(shift);
+ 1;
+}
+
+sub prLog
+{ my $mess = shift;
+ if ($runfil)
+ { $mess = prep($mess);
+ $log .= "Log~$mess\n";
+ return 1;
+ }
+ else
+ { errLog("You have to give a directory for the logfiles first : prLogDir <dir> , aborts");
+ }
+
+}
+
+sub prGetLogBuffer
+{
+ return $log;
+}
+
+sub findDir
+{ my $dir = shift;
+ if ($dir eq '.')
+ { return undef; }
+ if (! -e $dir)
+ { mkdir $dir || errLog("Couldn't create directory $dir, $!");
+ }
+
+ if ((-e $dir) && (-d $dir))
+ { if (substr($dir, length($dir), 1) eq '/')
+ { return $dir; }
+ else
+ { return ($dir . '/');
+ }
+ }
+ else
+ { errLog("Error finding/creating directory $dir, $!");
+ }
+}
+
+sub prTouchUp
+{ $touchUp = shift;
+ if ($runfil)
+ { $log .= "TouchUp~$touchUp\n";
+ }
+ if (! $pos)
+ { errLog("No output file, you have to call prFile first");
+ }
+ 1;
+}
+
+sub prCompress
+{ $compress = shift;
+ if ($runfil)
+ { $log .= "Compress~$compress\n";
+ }
+ if (! $pos)
+ { errLog("No output file, you have to call prFile first");
+ }
+ 1;
+
+}
+
+sub prep
+{ my $indata = shift;
+ $indata =~ s/[\n\r]+/ /sgo;
+ $indata =~ s/~/<tilde>/sgo;
+ return $indata;
+}
+
+
+sub xRefs
+{ my ($bytes, $infil) = @_;
+ my ($j, $nr, $xref, $i, $antal, $inrad, $Root, $tempRoot, $referens);
+ my $buf = '';
+ %embedded =();
+
+ my $res = sysseek INFIL, -50, 2;
+ if ($res)
+ { sysread INFIL, $buf, 100;
+ if ($buf =~ m'Encrypt'o)
+ { errLog("The file $infil is encrypted, cannot be used, aborts");
+ }
+ if ($buf =~ m'\bstartxref\s+(\d+)'o)
+ { $xref = $1;
+ while ($xref)
+ { $res = sysseek INFIL, $xref, 0;
+ $res = sysread INFIL, $buf, 200;
+ if ($buf =~ m '^\d+\s\d+\sobj'os)
+ { ($xref, $tempRoot, $nr) = crossrefObj($nr, $xref);
+ }
+ else
+ { ($xref, $tempRoot, $nr) = xrefSection($nr, $xref, $infil);
+ }
+ if (($tempRoot) && (! $Root))
+ { $Root = $tempRoot;
+ }
+ }
+ }
+ }
+
+ ($Root) || errLog("The Root object in $infil couldn't be found, aborting");
+
+ ##############################################################
+ # Objekten sorteras i fallande ordning (efter offset i filen)
+ ##############################################################
+
+ my @offset = sort { $oldObject{$b} <=> $oldObject{$a} } keys %oldObject;
+
+ my $saved;
+
+ for (@offset)
+ { $saved = $oldObject{$_};
+ $bytes -= $saved;
+
+ if ($_ !~ m'^xref'o)
+ { if ($saved == 0)
+ { $oldObject{$_} = [ 0, 0, $embedded{$_}];
+ }
+ else
+ { $oldObject{$_} = [ $saved, $bytes];
+ }
+ }
+ $bytes = $saved;
+ }
+ %embedded = ();
+ return $Root;
+}
+
+sub crossrefObj
+{ my ($nr, $xref) = @_;
+ my ($buf, %param, $len, $tempRoot);
+ my $from = $xref;
+ sysseek INFIL, $xref, 0;
+ sysread INFIL, $buf, 400;
+ my $str;
+ if ($buf =~ m'^(.+>>\s*)stream'os)
+ { $str = $1;
+ $from = length($str) + 7;
+ if (substr($buf, $from, 1) eq "\n")
+ { $from++;
+ }
+ $from += $xref;
+ }
+
+ for (split('/',$str))
+ { if ($_ =~ m'^(\w+)(.*)'o)
+ { $param{$1} = $2 || ' ';
+ }
+ }
+ if ((exists $param{'Root'}) && ($param{'Root'} =~ m'^\s*(\d+)'o))
+ { $tempRoot = $1;
+ }
+ my @keys = ($param{'W'} =~ m'(\d+)'og);
+ my $keyLength = 0;
+ for (@keys)
+ { $keyLength += $_;
+ }
+ my $recLength = $keyLength + 1;
+ my $upTo = 1 + $keys[0] + $keys[1];
+ if ((exists $param{'Length'}) && ($param{'Length'} =~ m'(\d+)'o))
+ { $len = $1;
+ sysseek INFIL, $from, 0;
+ sysread INFIL, $buf, $len;
+ my $x = inflateInit()
+ || die "Cannot create an inflation stream\n" ;
+ my ($output, $status) = $x->inflate(\$buf) ;
+ die "inflation failed\n"
+ unless $status == 1;
+
+ my $i = 0;
+ my @last = (0, 0, 0, 0, 0, 0, 0);
+ my @word = ('0', '0', '0', '0', '0', '0', '0');
+ my $recTyp;
+ my @intervall = ($param{'Index'} =~ m'(\d+)\D'osg);
+ my $m = 0;
+ my $currObj = $intervall[$m];
+ $m++;
+ my $max = $currObj + $intervall[$m];
+
+ for (unpack ("C*", $output))
+ { if (($_ != 0) && ($i > 0) && ($i < $upTo))
+ { my $tal = $_ + $last[$i] ;
+ if ($tal > 255)
+ {$tal -= 256;
+ }
+
+ $last[$i] = $tal;
+ $word[$i] = sprintf("%x", $tal);
+ if (length($word[$i]) == 1)
+ { $word[$i] = '0' . $word[$i];
+ }
+ }
+ $i++;
+ if ($i == $recLength)
+ { $i = 0;
+ my $j = 0;
+ my $offsObj; # offset or object
+ if ($keys[0] == 0)
+ { $recTyp = 1;
+ $j = 1;
+ }
+ else
+ { $recTyp = $word[1];
+ $j = 2;
+ }
+ my $k = 0;
+ while ($k < $keys[1])
+ { $offsObj .= $word[$j];
+ $k++;
+ $j++;
+ }
+
+ if ($recTyp == 1)
+ { if (! (exists $oldObject{$currObj}))
+ { $oldObject{$currObj} = hex($offsObj); }
+ else
+ { $nr++;
+ $oldObject{'xref' . "$nr"} = hex($offsObj);
+ }
+ }
+ elsif ($recTyp == 2)
+ { if (! (exists $oldObject{$currObj}))
+ { $oldObject{$currObj} = 0;
+ }
+ $embedded{$currObj} = hex($offsObj);
+ }
+ if ($currObj < $max)
+ { $currObj++;
+ }
+ else
+ { $m++;
+ $currObj = $intervall[$m];
+ $m++;
+ $max = $currObj + $intervall[$m];
+ }
+ }
+ }
+ }
+ return ($param{'Prev'}, $tempRoot, $nr);
+}
+
+sub xrefSection
+{ my ($nr, $xref, $infil) = @_;
+ my ($i, $root, $antal);
+ $nr++;
+ $oldObject{('xref' . "$nr")} = $xref; # Offset för xref sparas
+ $xref += 5;
+ sysseek INFIL, $xref, 0;
+ $xref = 0;
+ my $inrad = '';
+ my $buf = '';
+ my $c;
+ sysread INFIL, $c, 1;
+ while ($c =~ m!\s!s)
+ { sysread INFIL, $c, 1; }
+
+ while ( (defined $c)
+ && ($c ne "\n")
+ && ($c ne "\r") )
+ { $inrad .= $c;
+ sysread INFIL, $c, 1;
+ }
+
+ if ($inrad =~ m'^(\d+)\s+(\d+)'o)
+ { $i = $1;
+ $antal = $2;
+ }
+
+ while ($antal)
+ { for (my $l = 1; $l <= $antal; $l++)
+ { sysread INFIL, $inrad, 20;
+ if ($inrad =~ m'^\s?(\d+) \d+ (\w)\s*'o)
+ { if ($2 eq 'n')
+ { if (! (exists $oldObject{$i}))
+ { $oldObject{$i} = int($1); }
+ else
+ { $nr++;
+ $oldObject{'xref' . "$nr"} = int($1);
+ }
+ }
+ }
+ $i++;
+ }
+ undef $antal;
+ undef $inrad;
+ sysread INFIL, $c, 1;
+ while ($c =~ m!\s!s)
+ { sysread INFIL, $c, 1; }
+
+ while ( (defined $c)
+ && ($c ne "\n")
+ && ($c ne "\r") )
+ { $inrad .= $c;
+ sysread INFIL, $c, 1;
+ }
+ if ($inrad =~ m'^(\d+)\s+(\d+)'o)
+ { $i = $1;
+ $antal = $2;
+ }
+
+ }
+
+ while ($inrad)
+ { if ($buf =~ m'Encrypt'o)
+ { errLog("The file $infil is encrypted, cannot be used, aborts");
+ }
+ if ((! $root) && ($buf =~ m'\/Root\s+(\d+)\s{1,2}\d+\s{1,2}R'so))
+ { $root = $1;
+ if ($xref)
+ { last; }
+ }
+
+ if ((! $xref) && ($buf =~ m'\/Prev\s+(\d+)\D'so))
+ { $xref = $1;
+ if ($root)
+ { last; }
+ }
+
+ if ($buf =~ m'xref'so)
+ { last; }
+
+ sysread INFIL, $inrad, 30;
+ $buf .= $inrad;
+ }
+ return ($xref, $root, $nr);
+}
+
+sub getObject
+{ my ($nr, $noId, $noEnd) = @_;
+
+ my $buf;
+ my ($offs, $siz, $embedded) = @{$oldObject{$nr}};
+
+ if ($offs)
+ { sysseek INFIL, $offs, 0;
+ sysread INFIL, $buf, $siz;
+ if (($noId) && ($noEnd))
+ { if ($buf =~ m'^\d+ \d+ obj\s*(.*)endobj'os)
+ { if (wantarray)
+ { return ($1, $offs, $siz, $embedded);
+ }
+ else
+ { return $1;
+ }
+ }
+ }
+ elsif ($noId)
+ { if ($buf =~ m'^\d+ \d+ obj\s*(.*)'os)
+ { if (wantarray)
+ { return ($1, $offs, $siz, $embedded);
+ }
+ else
+ { return $1;
+ }
+ }
+ }
+ if (wantarray)
+ { return ($buf, $offs, $siz, $embedded)
+ }
+ else
+ { return $buf;
+ }
+ }
+ elsif (exists $unZipped{$nr})
+ { ;
+ }
+ elsif ($embedded)
+ { unZipPrepare($embedded);
+ }
+ if ($noEnd)
+ { if (wantarray)
+ { return ($unZipped{$nr}, $offs, $siz, $embedded)
+ }
+ else
+ { return $unZipped{$nr};
+ }
+ }
+ else
+ { if (wantarray)
+ { return ("$unZipped{$nr}endobj\n", $offs, $siz, $embedded)
+ }
+ else
+ { return "$unZipped{$nr}endobj\n";
+ }
+ }
+}
+
+sub getKnown
+{ my ($p, $nr) = @_;
+ my ($del1, $del2);
+ my @objData = @{$$$p[0]->{$nr}};
+ if (defined $objData[oSTREAMP])
+ { sysseek INFIL, ($objData[oNR][0] + $objData[oPOS]), 0;
+ sysread INFIL, $del1, ($objData[oSTREAMP] - $objData[oPOS]);
+ sysread INFIL, $del2, ($objData[oNR][1] - $objData[oSTREAMP]);
+ }
+ else
+ { my $buf;
+ my ($offs, $siz, $embedded) = @{$objData[oNR]};
+ if ($offs)
+ { sysseek INFIL, $offs, 0;
+ sysread INFIL, $buf, $siz;
+ if ($buf =~ m'^\d+ \d+ obj\s*(.*)'os)
+ { $del1 = $1;
+ }
+ }
+ elsif (exists $unZipped{$nr})
+ { $del1 = "$unZipped{$nr} endobj";
+ }
+ elsif ($embedded)
+ { @objData = @{$$$p[0]->{$embedded}};
+ unZipPrepare($embedded, $objData[oNR][0], $objData[oNR][1]);
+ $del1 = "$unZipped{$nr} endobj";
+ }
+ }
+ return (\$del1, \$del2, $objData[oKIDS], $objData[oTYPE]);
+}
+
+
+sub unZipPrepare
+{ my ($nr, $offs, $size) = @_;
+ my $buf;
+ if ($offs)
+ { sysseek INFIL, $offs, 0;
+ sysread INFIL, $buf, $size;
+ }
+ else
+ { $buf = getObject($nr);
+ }
+ my (%param, $stream, $str);
+
+ if ($buf =~ m'^(\d+ \d+ obj\s*<<[\w\d\/\s\[\]<>]+)stream\b'os)
+ { $str = $1;
+ $offs = length($str) + 7;
+ if (substr($buf, $offs, 1) eq "\n")
+ { $offs++;
+ }
+
+ for (split('/',$str))
+ { if ($_ =~ m'^(\w+)(.*)'o)
+ { $param{$1} = $2 || ' ';
+ }
+ }
+ $stream = substr($buf, $offs, $param{'Length'});
+ my $x = inflateInit()
+ || die "Cannot create an inflation stream\n";
+ my ($output, $status) = $x->inflate($stream);
+ die "inflation failed\n"
+ unless $status == 1;
+
+ my $first = $param{'First'};
+ my @oOffsets = (substr($output, 0, $first) =~ m'(\d+)\b'osg);
+ my $i = 0;
+ my $j = 1;
+ my $bytes;
+ while ($oOffsets[$i])
+ { my $k = $j + 2;
+ if ($oOffsets[$k])
+ { $bytes = $oOffsets[$k] - $oOffsets[$j];
+ }
+ else
+ { $bytes = length($output) - $first - $oOffsets[$j];
+ }
+ $unZipped{$oOffsets[$i]} = substr($output,($first + $oOffsets[$j]), $bytes);
+ $i += 2;
+ $j += 2;
+ }
+ }
+}
+
+############################################
+# En definitionerna för en sida extraheras
+############################################
+
+sub getPage
+{ my ($infil, $sidnr, $action) = @_;
+
+ my ($res, $i, $referens,$objNrSaved,$validStream, $formRes, @objData,
+ @underObjekt, @sidObj, $strPos, $startSida, $sidor, $filId, $del1, $del2,
+ $offs, $siz, $embedded, $vektor, $utrad, $robj, $valid, $Annots, $Names,
+ $AcroForm, $AARoot, $AAPage);
+
+ my $sidAcc = 0;
+ my $seq = 0;
+ $imSeq = 0;
+ @skapa = ();
+ undef $formCont;
+
+
+ $objNrSaved = $objNr;
+ my $fSource = $infil . '_' . $sidnr;
+ my $checkidOld = $checkId;
+ ($infil, $checkId) = findGet($infil, $checkidOld);
+ if (($ldir) && ($checkId) && ($checkId ne $checkidOld))
+ { $log .= "Cid~$checkId\n";
+ }
+ $form{$fSource}[fID] = $checkId;
+ $checkId = '';
+ $behandlad{$infil}->{old} = {}
+ unless (defined $behandlad{$infil}->{old});
+ $processed{$infil}->{oldObject} = {}
+ unless (defined $processed{$infil}->{oldObject});
+ $processed{$infil}->{unZipped} = {}
+ unless (defined $processed{$infil}->{unZipped});
+
+ if ($action eq 'print')
+ { *old = $behandlad{$infil}->{old};
+ }
+ else
+ { $behandlad{$infil}->{dummy} = {};
+ *old = $behandlad{$infil}->{dummy};
+ }
+
+ *oldObject = $processed{$infil}->{oldObject};
+ *unZipped = $processed{$infil}->{unZipped};
+ $root = (exists $processed{$infil}->{root})
+ ? $processed{$infil}->{root} : 0;
+
+
+ my @stati = stat($infil);
+ open (INFIL, "<$infil") || errLog("Couldn't open $infil, $!");
+ binmode INFIL;
+
+ if (! $root)
+ { $root = xRefs($stati[7], $infil);
+ }
+
+ #############
+ # Hitta root
+ #############
+
+ my $objektet = getObject($root);;
+
+ if ($sidnr == 1)
+ { if ($objektet =~ m'/AcroForm(\s+\d+\s{1,2}\d+\s{1,2}R)'so)
+ { $AcroForm = $1;
+ }
+ if ($objektet =~ m'/Names\s+(\d+)\s{1,2}\d+\s{1,2}R'so)
+ { $Names = $1;
+ }
+ #################################################
+ # Finns ett dictionary för Additional Actions ?
+ #################################################
+ if ($objektet =~ m'/AA\s*\<\<\s*[^\>]+[^\>]+'so) # AA är ett dictionary
+ { my $k;
+ my ($dummy, $obj) = split /\/AA/, $objektet;
+ $obj =~ s/\<\</\#\<\</gs;
+ $obj =~ s/\>\>/\>\>\#/gs;
+ my @ord = split /\#/, $obj;
+ for ($i = 0; $i <= $#ord; $i++)
+ { $AARoot .= $ord[$i];
+ if ($ord[$i] =~ m'\S+'os)
+ { if ($ord[$i] =~ m'<<'os)
+ { $k++; }
+ if ($ord[$i] =~ m'>>'os)
+ { $k--; }
+ if ($k == 0)
+ { last; }
+ }
+ }
+ }
+ }
+
+ #
+ # Hitta pages
+ #
+
+ if ($objektet =~ m'/Pages\s+(\d+)\s{1,2}\d+\s{1,2}R'os)
+ { $objektet = getObject($1);
+ if ($objektet =~ m'/Count\s+(\d+)'os)
+ { $sidor = $1;
+ if ($sidnr <= $sidor)
+ { ($formRes, $valid) = kolla($objektet);
+ }
+ else
+ { return 0;
+ }
+ if ($sidor > 1)
+ { undef $AcroForm;
+ undef $Names;
+ undef $AARoot;
+ if ($type eq 'docform')
+ { errLog("prDocForm can only be used for single page documents - try prDoc or reformat $infil");
+ }
+ }
+ }
+ }
+ else
+ { errLog("Didn't find Pages in $infil - aborting"); }
+
+ if ($objektet =~ m'/Kids\s*\[([^\]]+)'os)
+ { $vektor = $1; }
+ while ($vektor =~ m'(\d+)\s{1,2}\d+\s{1,2}R'go)
+ { push @sidObj, $1;
+ }
+
+ my $bryt1 = -20; # Hängslen
+ my $bryt2 = -20; # Svångrem för att undvika oändliga loopar
+
+ while ($sidAcc < $sidnr)
+ { @underObjekt = @sidObj;
+ @sidObj = ();
+ $bryt1++;
+ for my $uO (@underObjekt)
+ { $objektet = getObject($uO);
+ if ($objektet =~ m'/Count\s+(\d+)'os)
+ { if (($sidAcc + $1) < $sidnr)
+ { $sidAcc += $1; }
+ else
+ { ($formRes, $valid) = kolla($objektet, $formRes);
+ if ($objektet =~ m'/Kids\s*\[([^\]]+)'os)
+ { $vektor = $1; }
+ while ($vektor =~ m'(\d+)\s{1,2}\d+\s{1,2}R'gso)
+ { push @sidObj, $1; }
+ last;
+ }
+ }
+ else
+ { $sidAcc++; }
+ if ($sidAcc == $sidnr)
+ { $seq = $uO;
+ last; }
+ $bryt2++;
+ }
+ if (($bryt1 > $sidnr) || ($bryt2 > $sidnr)) # Bryt oändliga loopar
+ { last; }
+ }
+
+ ($formRes, $validStream) = kolla($objektet, $formRes);
+ $startSida = $seq;
+
+ if ($sidor == 1)
+ { #################################################
+ # Kontrollera Page-objektet för annoteringar
+ #################################################
+
+ if ($objektet =~ m'/Annots\s*([^\/]+)'so)
+ { $Annots = $1;
+ }
+ #################################################
+ # Finns ett dictionary för Additional Actions ?
+ #################################################
+ if ($objektet =~ m'/AA\s*\<\<\s*[^\>]+[^\>]+'so) # AA är ett dictionary. Hela kopieras
+ { my $k;
+ my ($dummy, $obj) = split /\/AA/, $objektet;
+ $obj =~ s/\<\</\#\<\</gs;
+ $obj =~ s/\>\>/\>\>\#/gs;
+ my @ord = split /\#/, $obj;
+ for ($i = 0; $i <= $#ord; $i++)
+ { $AAPage .= $ord[$i];
+ if ($ord[$i] =~ m'\S+'s)
+ { if ($ord[$i] =~ m'<<'s)
+ { $k++; }
+ if ($ord[$i] =~ m'>>'s)
+ { $k--; }
+ if ($k == 0)
+ { last; }
+ }
+ }
+ }
+ }
+
+ my $rform = \$form{$fSource};
+ @$$rform[fRESOURCE] = $formRes;
+ my @BBox;
+ if (defined $formBox[0])
+ { $BBox[0] = $formBox[0]; }
+ else
+ { $BBox[0] = $genLowerX; }
+
+ if (defined $formBox[1])
+ { $BBox[1] = $formBox[1]; }
+ else
+ { $BBox[1] = $genLowerY; }
+
+ if (defined $formBox[2])
+ { $BBox[2] = $formBox[2]; }
+ else
+ { $BBox[2] = $genUpperX; }
+
+ if (defined $formBox[3])
+ { $BBox[3] = $formBox[3]; }
+ else
+ { $BBox[3] = $genUpperY; }
+
+ @{$form{$fSource}[fBBOX]} = @BBox;
+
+ if ($formCont)
+ { $seq = $formCont;
+ ($objektet, $offs, $siz, $embedded) = getObject($seq);
+
+ $robj = \$$$rform[fOBJ]->{$seq};
+ @{$$$robj[oNR]} = ($offs, $siz, $embedded);
+ $$$robj[oFORM] = 'Y';
+ $form{$fSource}[fMAIN] = $seq;
+ if ($objektet =~ m'^(\d+ \d+ obj\s*<<)(.+)(>>\s*stream)'so)
+ { $del1 = $2;
+ $strPos = length($1) + length($2) + length($3);
+ $$$robj[oPOS] = length($1);
+ $$$robj[oSTREAMP] = $strPos;
+ my $nyDel1;
+ $nyDel1 = '<</Type/XObject/Subtype/Form/FormType 1';
+ $nyDel1 .= "/Resources $formRes" .
+ "/BBox \[ $BBox[0] $BBox[1] $BBox[2] $BBox[3]\]" .
+ # "/Matrix \[ 1 0 0 1 0 0 \]" .
+ $del1;
+ if ($action eq 'print')
+ { $objNr++;
+ $objekt[$objNr] = $pos;
+ }
+ $referens = $objNr;
+
+ $res = ($nyDel1 =~ s/\b(\d+)\s{1,2}\d+\s{1,2}R\b/xform() . ' 0 R'/oegs);
+ if ($res)
+ { $$$robj[oKIDS] = 1; }
+ if ($action eq 'print')
+ { $utrad = "$referens 0 obj\n" . "$nyDel1" . ">>\nstream";
+ $del2 = substr($objektet, $strPos);
+ $utrad .= $del2;
+ $pos += syswrite UTFIL, $utrad;
+ }
+ $form{$fSource}[fVALID] = $validStream;
+ }
+ else # Endast resurserna kan behandlas
+ { $formRes =~ s/\b(\d+)\s{1,2}\d+\s{1,2}R\b/xform() . ' 0 R'/oegs;
+ }
+ }
+ else # Endast resurserna kan behandlas
+ { $formRes =~ s/\b(\d+)\s{1,2}\d+\s{1,2}R\b/xform() . ' 0 R'/oegs;
+ }
+
+ my $preLength;
+ while (scalar @skapa)
+ { my @process = @skapa;
+ @skapa = ();
+ for (@process)
+ { my $Font;
+ my $gammal = $$_[0];
+ my $ny = $$_[1];
+ ($objektet, $offs, $siz, $embedded) = getObject($gammal);
+ $robj = \$$$rform[fOBJ]->{$gammal};
+ @{$$$robj[oNR]} = ($offs, $siz, $embedded);
+ if ($objektet =~ m'^(\d+ \d+ obj\s*<<)(.+)(>>\s*stream)'os)
+ { $del1 = $2;
+ $strPos = length ($1) + length($2) + length($3);
+ $$$robj[oPOS] = length($1);
+ $$$robj[oSTREAMP] = $strPos;
+
+ ######## En bild ########
+ if ($del1 =~ m'/Subtype\s*/Image'so)
+ { $imSeq++;
+ $$$robj[oIMAGENR] = $imSeq;
+ push @{$$$rform[fIMAGES]}, $gammal;
+
+ if ($del1 =~ m'/Width\s+(\d+)'os)
+ { $$$robj[oWIDTH] = $1; }
+ if ($del1 =~ m'/Height\s+(\d+)'os)
+ { $$$robj[oHEIGHT] = $1; }
+ }
+ $res = ($del1 =~ s/\b(\d+)\s{1,2}\d+\s{1,2}R\b/xform() . ' 0 R'/oegs);
+ if ($res)
+ { $$$robj[oKIDS] = 1; }
+ if ($action eq 'print')
+ { $objekt[$ny] = $pos;
+ $utrad = "$ny 0 obj\n<<" . "$del1" . '>>stream';
+ $del2 = substr($objektet, $strPos);
+ $utrad .= $del2;
+ }
+ }
+ else
+ { if ($objektet =~ m'^(\d+ \d+ obj\s*)'os)
+ { $preLength = length($1);
+ $$$robj[oPOS] = $preLength;
+ $objektet = substr($objektet, $preLength);
+ }
+ else
+ { $$$robj[oPOS] = 0;
+ }
+ $res = ($objektet =~ s/\b(\d+)\s{1,2}\d+\s{1,2}R\b/xform() . ' 0 R'/oegs);
+ if ($res)
+ { $$$robj[oKIDS] = 1; }
+ if ($objektet =~ m'/Subtype\s*/Image'so)
+ { $imSeq++;
+ $$$robj[oIMAGENR] = $imSeq;
+ push @{$$$rform[fIMAGES]}, $gammal;
+ ###################################
+ # Sparar dimensionerna för bilden
+ ###################################
+ if ($del1 =~ m'/Width\s+(\d+)'os)
+ { $$$robj[oWIDTH] = $1; }
+
+ if ($del1 =~ m'/Height\s+(\d+)'os)
+ { $$$robj[oHEIGHT] = $1; }
+ }
+ elsif ($objektet =~ m'/BaseFont\s*/([^\s\/]+)'os)
+ { $Font = $1;
+ $$$robj[oTYPE] = 'Font';
+ $$$robj[oNAME] = $Font;
+ if ((! exists $font{$Font})
+ && ($action))
+ { $fontNr++;
+ $font{$Font}[foINTNAMN] = 'Ft' . $fontNr;
+ $font{$Font}[foORIGINALNR] = $gammal;
+ $fontSource{$Font}[foSOURCE] = $fSource;
+ $fontSource{$Font}[foORIGINALNR] = $gammal;
+ if ($action eq 'print')
+ { $font{$Font}[foREFOBJ] = $ny;
+ $objRef{'Ft' . $fontNr} = $ny;
+ }
+ }
+ }
+
+ if ($action eq 'print')
+ { $objekt[$ny] = $pos;
+ $utrad = "$ny 0 obj $objektet";
+ }
+ }
+ if ($action eq 'print')
+ { $pos += syswrite UTFIL, $utrad;
+ }
+ }
+ }
+
+ my $ref = \$form{$fSource};
+ my @kids;
+ my @nokids;
+
+ #################################################################
+ # lägg upp vektorer över vilka objekt som har KIDS eller NOKIDS
+ #################################################################
+
+ for my $key (keys %{$$$ref[fOBJ]})
+ { $robj = \$$$ref[fOBJ]->{$key};
+ if (! defined $$$robj[oFORM])
+ { if (defined $$$robj[oKIDS])
+ { push @kids, $key; }
+ else
+ { push @nokids, $key; }
+ }
+ if ((defined $$$robj[0]->[2]) && (! exists $$$ref[fOBJ]->{$$$robj[0]->[2]}))
+ { $$$ref[fOBJ]->{$$$robj[0]->[2]}->[0] = $oldObject{$$$robj[0]->[2]};
+ }
+ }
+ if (scalar @kids)
+ { $form{$fSource}[fKIDS] = \@kids;
+ }
+ if (scalar @nokids)
+ { $form{$fSource}[fNOKIDS] = \@nokids;
+ }
+
+ if ($action ne 'print')
+ { $objNr = $objNrSaved; # Restore objNo if nothing was printed
+ }
+
+ $behandlad{$infil}->{dummy} = {};
+ *old = $behandlad{$infil}->{dummy};
+
+ $objNrSaved = $objNr; # Save objNo
+
+ if ($sidor == 1)
+ { @skapa = ();
+ $old{$startSida} = $sidObjNr;
+ my $ref = \$intAct{$fSource};
+ @$$ref[iSTARTSIDA] = $startSida;
+ if (defined $Names)
+ { @$$ref[iNAMES] = $Names;
+ quickxform($Names);
+ }
+ if (defined $AcroForm)
+ { @$$ref[iACROFORM] = $AcroForm;
+ $AcroForm =~ s/\b(\d+)\s{1,2}\d+\s{1,2}R\b/xform() . ' 0 R'/oegs;
+ }
+ if (defined $AARoot)
+ { @$$ref[iAAROOT] = $AARoot;
+ $AARoot =~ s/\b(\d+)\s{1,2}\d+\s{1,2}R\b/xform() . ' 0 R'/oegs;
+ }
+ if (defined $AAPage)
+ { @$$ref[iAAPAGE] = $AAPage;
+ $AAPage =~ s/\b(\d+)\s{1,2}\d+\s{1,2}R\b/xform() . ' 0 R'/oegs;
+ }
+ if (defined $Annots)
+ { my @array;
+ if ($Annots =~ m'\[([^\[\]]*)\]'os)
+ { $Annots = $1;
+ @array = ($Annots =~ m'\b(\d+)\s{1,2}\d+\s{1,2}R\b'ogs);
+ }
+ else
+ { if ($Annots =~ m'\b(\d+)\s{1,2}\d+\s{1,2}R\b'os)
+ { $Annots = getObject($1);
+ @array = ($Annots =~ m'\b(\d+)\s{1,2}\d+\s{1,2}R\b'ogs);
+ }
+ }
+ @$$ref[iANNOTS] = \@array;
+ $Annots =~ s/\b(\d+)\s{1,2}\d+\s{1,2}R\b/xform() . ' 0 R'/oegs;
+ }
+
+ while (scalar @skapa)
+ { my @process = @skapa;
+ @skapa = ();
+ for (@process)
+ { my $gammal = $$_[0];
+ my $ny = $$_[1];
+ ($objektet, $offs, $siz, $embedded) = getObject($gammal);
+ $robj = \$$$ref[fOBJ]->{$gammal};
+ @{$$$robj[oNR]} = ($offs, $siz, $embedded);
+ if ($objektet =~ m'^(\d+ \d+ obj\s*<<)(.+)(>>\s*stream)'os)
+ { $del1 = $2;
+ $$$robj[oPOS] = length($1);
+ $$$robj[oSTREAMP] = length($1) + length($2) + length($3);
+
+ $res = ($del1 =~ s/\b(\d+)\s{1,2}\d+\s{1,2}R\b/xform() . ' 0 R'/oegs);
+ if ($res)
+ { $$$robj[oKIDS] = 1; }
+ }
+ else
+ { if ($objektet =~ m'^(\d+ \d+ obj)'os)
+ { my $preLength = length($1);
+ $$$robj[oPOS] = $preLength;
+ $objektet = substr($objektet, $preLength);
+
+ $res = ($objektet =~ s/\b(\d+)\s{1,2}\d+\s{1,2}R\b/xform() . ' 0 R'/oegs);
+ if ($res)
+ { $$$robj[oKIDS] = 1; }
+ }
+ }
+ }
+ }
+ for my $key (keys %{$$$ref[fOBJ]})
+ { $robj = \$$$ref[fOBJ]->{$key};
+ if ((defined $$$robj[0]->[2]) && (! exists $$$ref[fOBJ]->{$$$robj[0]->[2]}))
+ { $$$ref[fOBJ]->{$$$robj[0]->[2]}->[0] = $oldObject{$$$robj[0]->[2]};
+ }
+ }
+ }
+
+ $objNr = $objNrSaved;
+ $processed{$infil}->{root} = $root;
+ close INFIL;
+ return $referens;
+}
+
+##################################################
+# Översätter ett gammalt objektnr till ett nytt
+# och sparar en tabell med vad som skall skapas
+##################################################
+
+sub xform
+{ if (exists $old{$1})
+ { $old{$1};
+ }
+ else
+ { push @skapa, [$1, ++$objNr];
+ $old{$1} = $objNr;
+ }
+}
+
+sub kolla
+{ #
+ # Resurser
+ #
+ my $obj = shift;
+ my $resources = shift;
+ my $valid;
+
+ if ($obj =~ m'MediaBox\s*\[\s*([\-\.\d]+)\s+([\-\.\d]+)\s+([\-\.\d]+)\s+([\-\.\d]+)'os)
+ { $formBox[0] = $1;
+ $formBox[1] = $2;
+ $formBox[2] = $3;
+ $formBox[3] = $4;
+ }
+
+ if ($obj =~ m'/Contents\s+(\d+)'so)
+ { $formCont = $1;
+ $valid = 1;
+ }
+
+ if ($obj =~ m'^(.+/Resources)'so)
+ { if ($obj =~ m'Resources(\s+\d+\s{1,2}\d+\s{1,2}R)'os) # Hänvisning
+ { $resources = $1; }
+ else # Resurserna är ett dictionary. Hela kopieras
+ { my $dummy;
+ my $i;
+ my $k;
+ undef $resources;
+ ($dummy, $obj) = split /\/Resources/, $obj;
+ $obj =~ s/\<\</\#\<\</gs;
+ $obj =~ s/\>\>/\>\>\#/gs;
+ my @ord = split /\#/, $obj;
+ for ($i = 0; $i <= $#ord; $i++)
+ { $resources .= $ord[$i];
+ if ($ord[$i] =~ m'\S+'s)
+ { if ($ord[$i] =~ m'<<'s)
+ { $k++; }
+ if ($ord[$i] =~ m'>>'s)
+ { $k--; }
+ if ($k == 0)
+ { last; }
+ }
+ }
+ }
+ }
+ return ($resources, $valid);
+}
+
+##############################
+# Ett formulär (åter)skapas
+##############################
+
+sub byggForm
+{ no warnings;
+ my ($infil, $sidnr) = @_;
+
+ my ($res, $corr, $nyDel1, $formRes, $del1, $del2, $kids, $typ, $nr,
+ $utrad);
+
+ my $fSource = $infil . '_' . $sidnr;
+ my @stati = stat($infil);
+
+ $behandlad{$infil}->{old} = {}
+ unless (defined $behandlad{$infil}->{old});
+ $processed{$infil}->{oldObject} = {}
+ unless (defined $processed{$infil}->{oldObject});
+ $processed{$infil}->{unZipped} = {}
+ unless (defined $processed{$infil}->{unZipped});
+
+ *old = $behandlad{$infil}->{old};
+ *oldObject = $processed{$infil}->{oldObject};
+ *unZipped = $processed{$infil}->{unZipped};
+
+ if ($form{$fSource}[fID] != $stati[9])
+ { errLog("$stati[9] ne $form{$fSource}[fID] aborts");
+ }
+ if ($checkId)
+ { if ($checkId ne $stati[9])
+ { my $mess = "$checkId \<\> $stati[9] \n"
+ . "The Pdf-file $fSource has not the correct modification time. \n"
+ . "The program is aborted";
+ errLog($mess);
+ }
+ undef $checkId;
+ }
+ if ($ldir)
+ { $log .= "Cid~$stati[9]\n";
+ }
+
+ open (INFIL, "<$infil") || errLog("The file $infil couldn't be opened, aborting $!");
+ binmode INFIL;
+
+ ####################################################
+ # Objekt utan referenser kopieras och skrivs
+ ####################################################
+
+ for my $key (@{$form{$fSource}->[fNOKIDS]})
+ { if ((defined $old{$key}) && ($objekt[$old{$key}])) # already processed
+ { next;
+ }
+
+ if (! defined $old{$key})
+ { $old{$key} = ++$objNr;
+ }
+ $nr = $old{$key};
+ $objekt[$nr] = $pos;
+
+ ($del1, $del2, $kids, $typ) = getKnown(\$form{$fSource},$key);
+
+ if ($typ eq 'Font')
+ { my $Font = ${$form{$fSource}}[0]->{$key}->[oNAME];
+ if (! defined $font{$Font}[foINTNAMN])
+ { $fontNr++;
+ $font{$Font}[foINTNAMN] = 'Ft' . $fontNr;
+ $font{$Font}[foREFOBJ] = $nr;
+ $objRef{'Ft' . $fontNr} = $nr;
+ }
+ }
+ if (! defined $$del2)
+ { $utrad = "$nr 0 obj " . $$del1;
+ }
+ else
+ { $utrad = "$nr 0 obj\n<<" . $$del1 . $$del2;
+ }
+ $pos += syswrite UTFIL, $utrad;
+ }
+
+ #######################################################
+ # Objekt med referenser kopieras, behandlas och skrivs
+ #######################################################
+ for my $key (@{$form{$fSource}->[fKIDS]})
+ { if ((defined $old{$key}) && ($objekt[$old{$key}])) # already processed
+ { next;
+ }
+
+ if (! defined $old{$key})
+ { $old{$key} = ++$objNr;
+ }
+ $nr = $old{$key};
+
+ $objekt[$nr] = $pos;
+
+ ($del1, $del2, $kids, $typ) = getKnown(\$form{$fSource},$key);
+
+ $$del1 =~ s/\b(\d+)\s{1,2}\d+\s{1,2}R\b/translate() . ' 0 R'/oegs;
+
+ if (defined $$del2)
+ { $utrad = "$nr 0 obj\n<<" . $$del1 . $$del2;
+ }
+ else
+ { $utrad = "$nr 0 obj " . $$del1;
+ }
+
+ if (($typ) && ($typ eq 'Font'))
+ { my $Font = $form{$fSource}[0]->{$key}->[oNAME];
+ if (! defined $font{$Font}[foINTNAMN])
+ { $fontNr++;
+ $font{$Font}[foINTNAMN] = 'Ft' . $fontNr;
+ $font{$Font}[foREFOBJ] = $nr;
+ $objRef{'Ft' . $fontNr} = $nr;
+ }
+ }
+
+ $pos += syswrite UTFIL, $utrad;
+ }
+
+ #################################
+ # Formulärobjektet behandlas
+ #################################
+
+ my $key = $form{$fSource}->[fMAIN];
+ if (! defined $key)
+ { return undef;
+ }
+
+ if (exists $old{$key}) # already processed
+ { close INFIL;
+ return $old{$key};
+ }
+
+ $nr = ++$objNr;
+
+ $objekt[$nr] = $pos;
+
+ $formRes = $form{$fSource}->[fRESOURCE];
+
+ ($del1, $del2) = getKnown(\$form{$fSource}, $key);
+
+ $nyDel1 = '<</Type/XObject/Subtype/Form/FormType 1';
+ $nyDel1 .= "/Resources $formRes" .
+ '/BBox [' .
+ $form{$fSource}->[fBBOX]->[0] . ' ' .
+ $form{$fSource}->[fBBOX]->[1] . ' ' .
+ $form{$fSource}->[fBBOX]->[2] . ' ' .
+ $form{$fSource}->[fBBOX]->[3] . ' ]' .
+ # "\]/Matrix \[ $sX 0 0 $sX $tX $tY \]" .
+ $$del1;
+ $nyDel1 =~ s/\b(\d+)\s{1,2}\d+\s{1,2}R\b/translate() . ' 0 R'/oegs;
+
+ $utrad = "$nr 0 obj" . $nyDel1 . $$del2;
+
+ $pos += syswrite UTFIL, $utrad;
+ close INFIL;
+
+ return $nr;
+}
+
+##################
+# En bild läses
+##################
+
+sub getImage
+{ my ($infil, $sidnr, $bildnr, $key) = @_;
+ if (! defined $key)
+ { errLog("Can't find image $bildnr on page $sidnr in file $infil, aborts");
+ }
+
+ @skapa = ();
+ my ($res, $corr, $nyDel1, $del1, $del2, $nr, $utrad);
+ my $fSource = $infil . '_' . $sidnr;
+ my $iSource = $fSource . '_' . $bildnr;
+
+ $behandlad{$infil}->{old} = {}
+ unless (defined $behandlad{$infil}->{old});
+ $processed{$infil}->{oldObject} = {}
+ unless (defined $processed{$infil}->{oldObject});
+ $processed{$infil}->{unZipped} = {}
+ unless (defined $processed{$infil}->{unZipped});
+
+ *old = $behandlad{$infil}->{old};
+ *oldObject = $processed{$infil}->{oldObject};
+ *unZipped = $processed{$infil}->{unZipped};
+
+ my @stati = stat($infil);
+
+ if ($form{$fSource}[fID] != $stati[9])
+ { errLog("$stati[9] ne $form{$fSource}[fID], modification time has changed, aborting");
+ }
+
+ if (exists $old{$key})
+ { return $old{$key};
+ }
+
+ open (INFIL, "<$infil") || errLog("The file $infil couldn't be opened, $!");
+ binmode INFIL;
+
+ #########################################################
+ # En bild med referenser kopieras, behandlas och skrivs
+ #########################################################
+
+ $nr = ++$objNr;
+ $old{$key} = $nr;
+
+ $objekt[$nr] = $pos;
+
+ ($del1, $del2) = getKnown(\$form{$fSource}, $key);
+
+ $$del1 =~ s/\b(\d+)\s{1,2}\d+\s{1,2}R\b/xform() . ' 0 R'/oegs;
+ if (defined $$del2)
+ { $utrad = "$nr 0 obj\n<<" . $$del1 . $$del2;
+ }
+ else
+ { $utrad = "$nr 0 obj " . $$del1;
+ }
+ $pos += syswrite UTFIL, $utrad;
+ ##################################
+ # Skriv ut underordnade objekt
+ ##################################
+ while (scalar @skapa)
+ { my @process = @skapa;
+ @skapa = ();
+ for (@process)
+ { my $gammal = $$_[0];
+ my $ny = $$_[1];
+
+ ($del1, $del2) = getKnown(\$form{$fSource}, $gammal);
+
+ $$del1 =~ s/\b(\d+)\s{1,2}\d+\s{1,2}R\b/xform() . ' 0 R'/oegs;
+ if (defined $$del2)
+ { $utrad = "$ny 0 obj\n<<" . $$del1 . $$del2;
+ }
+ else
+ { $utrad = "$ny 0 obj " . $$del1;
+ }
+ $objekt[$ny] = $pos;
+ $pos += syswrite UTFIL, $utrad;
+ }
+ }
+
+ close INFIL;
+ return $nr;
+
+}
+
+##############################################################
+# Interaktiva funktioner knutna till ett formulär återskapas
+##############################################################
+
+sub AcroFormsEtc
+{ my ($infil, $sidnr) = @_;
+
+ my ($Names, $AARoot, $AAPage, $AcroForm);
+ @skapa = ();
+
+ my ($res, $corr, $nyDel1, @objData, $del1, $del2, $utrad);
+ my $fSource = $infil . '_' . $sidnr;
+
+ $behandlad{$infil}->{old} = {}
+ unless (defined $behandlad{$infil}->{old});
+ $processed{$infil}->{oldObject} = {}
+ unless (defined $processed{$infil}->{oldObject});
+ $processed{$infil}->{unZipped} = {}
+ unless (defined $processed{$infil}->{unZipped});
+
+ *old = $behandlad{$infil}->{old};
+ *oldObject = $processed{$infil}->{oldObject};
+ *unZipped = $processed{$infil}->{unZipped};
+
+ my @stati = stat($infil);
+ if ($form{$fSource}[fID] != $stati[9])
+ { print "$stati[9] ne $form{$fSource}[fID]\n";
+ errLog("Modification time for $fSource has changed, aborting");
+ }
+
+ open (INFIL, "<$infil") || errLog("The file $infil couldn't be opened, aborting $!");
+ binmode INFIL;
+
+ my $fdSidnr = $intAct{$fSource}[iSTARTSIDA];
+ $old{$fdSidnr} = $sidObjNr;
+
+ if (($intAct{$fSource}[iNAMES]) ||(scalar @jsfiler) || (scalar @inits) || (scalar %fields))
+ { $Names = behandlaNames($intAct{$fSource}[iNAMES], $fSource);
+ }
+
+ ##################################
+ # Referenser behandlas och skrivs
+ ##################################
+
+ if (defined $intAct{$fSource}[iACROFORM])
+ { $AcroForm = $intAct{$fSource}[iACROFORM];
+ $AcroForm =~ s/\b(\d+)\s{1,2}\d+\s{1,2}R\b/xform() . ' 0 R'/oegs;
+ }
+ if (defined $intAct{$fSource}[iAAROOT])
+ { $AARoot = $intAct{$fSource}[iAAROOT];
+ $AARoot =~ s/\b(\d+)\s{1,2}\d+\s{1,2}R\b/xform() . ' 0 R'/oegs;
+ }
+
+ if (defined $intAct{$fSource}[iAAPAGE])
+ { $AAPage = $intAct{$fSource}[iAAPAGE];
+ $AAPage =~ s/\b(\d+)\s{1,2}\d+\s{1,2}R\b/xform() . ' 0 R'/oegs;
+ }
+ if (defined $intAct{$fSource}[iANNOTS])
+ { for (@{$intAct{$fSource}[iANNOTS]})
+ { push @annots, quickxform($_);
+ }
+ }
+
+ ##################################
+ # Skriv ut underordnade objekt
+ ##################################
+ while (scalar @skapa)
+ { my @process = @skapa;
+ @skapa = ();
+ for (@process)
+ { my $gammal = $$_[0];
+ my $ny = $$_[1];
+
+ my $oD = \@{$intAct{$fSource}[0]->{$gammal}};
+ @objData = @{$$oD[oNR]};
+
+ if (defined $$oD[oSTREAMP])
+ { $res = sysseek INFIL, ($objData[0] + $$oD[oPOS]), 0;
+ $corr = sysread INFIL, $del1, ($$oD[oSTREAMP] - $$oD[oPOS]) ;
+ if (defined $$oD[oKIDS])
+ { $del1 =~ s/\b(\d+)\s{1,2}\d+\s{1,2}R\b/xform() . ' 0 R'/oegs;
+ }
+ $res = sysread INFIL, $del2, ($objData[1] - $corr);
+ $utrad = "$ny 0 obj\n<<" . $del1 . $del2;
+ }
+ else
+ { $del1 = getObject($gammal);
+ $del1 = substr($del1, $$oD[oPOS]);
+ if (defined $$oD[oKIDS])
+ { $del1 =~ s/\b(\d+)\s{1,2}\d+\s{1,2}R\b/xform() . ' 0 R'/oegs;
+ }
+ $utrad = "$ny 0 obj " . $del1;
+ }
+
+ $objekt[$ny] = $pos;
+ $pos += syswrite UTFIL, $utrad;
+ }
+ }
+
+ close INFIL;
+ return ($Names, $AARoot, $AAPage, $AcroForm);
+}
+
+##############################
+# Ett namnobjekt extraheras
+##############################
+
+sub extractName
+{ my ($infil, $sidnr, $namn) = @_;
+
+ my ($res, $del1, $resType, $key, $corr, $formRes, $kids, $nr, $utrad);
+ my $del2 = '';
+ @skapa = ();
+
+ $behandlad{$infil}->{old} = {}
+ unless (defined $behandlad{$infil}->{old});
+ $processed{$infil}->{oldObject} = {}
+ unless (defined $processed{$infil}->{oldObject});
+ $processed{$infil}->{unZipped} = {}
+ unless (defined $processed{$infil}->{unZipped});
+
+ *old = $behandlad{$infil}->{old};
+ *oldObject = $processed{$infil}->{oldObject};
+ *unZipped = $processed{$infil}->{unZipped};
+
+ my $fSource = $infil . '_' . $sidnr;
+
+ my @stati = stat($infil);
+
+ if ($form{$fSource}[fID] != $stati[9])
+ { errLog("$stati[9] ne $form{$fSource}[fID] aborts");
+ }
+ if ($checkId)
+ { if ($checkId ne $stati[9])
+ { my $mess = "$checkId \<\> $stati[9] \n"
+ . "The Pdf-file $fSource has not the correct modification time. \n"
+ . "The program is aborted";
+ errLog($mess);
+ }
+ undef $checkId;
+ }
+ if ($ldir)
+ { $log .= "Cid~$stati[9]\n";
+ }
+
+ open (INFIL, "<$infil") || errLog("The file $infil couldn't be opened, aborting $!");
+ binmode INFIL;
+
+ #################################
+ # Resurserna läses
+ #################################
+
+ $formRes = $form{$fSource}->[fRESOURCE];
+
+ if ($formRes !~ m'<<.*>>'os) # If not a directory, get it
+ { if ($formRes =~ m'\b(\d+)\s{1,2}\d+\s{1,2}R'o)
+ { $key = $1;
+ $formRes = getKnown(\$form{$fSource}, $key);
+ }
+ else
+ { return undef;
+ }
+ }
+ undef $key;
+ while ($formRes =~ m'\/(\w+)\s*\<\<([^>]+)\>\>'osg)
+ { $resType = $1;
+ my $str = $2;
+ if ($str =~ m|$namn\s+(\d+)\s{1,2}\d+\s{1,2}R|s)
+ { $key = $1;
+ last;
+ }
+ }
+ if (! defined $key) # Try to expand the references
+ { my ($str, $del1, $del2);
+ while ($formRes =~ m'(\/\w+)\s+(\d+)\s{1,2}\d+\s{1,2}R'ogs)
+ { $str .= $1 . ' ';
+ ($del1, $del2) = getKnown(\$form{$fSource}, $2);
+ my $string = $$del1;
+ $str .= $string . ' ';
+ }
+ $formRes = $str;
+ while ($formRes =~ m'\/(\w+)\s*\<\<([^>]+)\>\>'osg)
+ { $resType = $1;
+ my $str = $2;
+ if ($str =~ m|$namn (\d+)\s{1,2}\d+\s{1,2}R|s)
+ { $key = $1;
+ last;
+ }
+ }
+ return undef unless $key;
+ }
+
+ ########################################
+ # Read the top object of the hierarchy
+ ########################################
+
+ ($del1, $del2) = getKnown(\$form{$fSource}, $key);
+
+ $objNr++;
+ $nr = $objNr;
+
+ if ($resType eq 'Font')
+ { my ($Font, $extNamn);
+ if ($$del1 =~ m'/BaseFont\s*/([^\s\/]+)'os)
+ { $extNamn = $1;
+ if (! exists $font{$extNamn})
+ { $fontNr++;
+ $Font = 'Ft' . $fontNr;
+ $font{$extNamn}[foINTNAMN] = $Font;
+ $font{$extNamn}[foORIGINALNR] = $nr;
+ $fontSource{$Font}[foSOURCE] = $fSource;
+ $fontSource{$Font}[foORIGINALNR] = $nr;
+ }
+ $font{$extNamn}[foREFOBJ] = $nr;
+ $Font = $font{$extNamn}[foINTNAMN];
+ $namn = $Font;
+ $objRef{$Font} = $nr;
+ }
+ else
+ { errLog("Inconsitency in $fSource, font $namn can't be found, aborting");
+ }
+ }
+ elsif ($resType eq 'ColorSpace')
+ { $colorSpace++;
+ $namn = 'Cs' . $colorSpace;
+ $objRef{$namn} = $nr;
+ }
+ elsif ($resType eq 'Pattern')
+ { $pattern++;
+ $namn = 'Pt' . $pattern;
+ $objRef{$namn} = $nr;
+ }
+ elsif ($resType eq 'Shading')
+ { $shading++;
+ $namn = 'Sh' . $shading;
+ $objRef{$namn} = $nr;
+ }
+ elsif ($resType eq 'ExtGState')
+ { $gSNr++;
+ $namn = 'Gs' . $gSNr;
+ $objRef{$namn} = $nr;
+ }
+ elsif ($resType eq 'XObject')
+ { if (defined $form{$fSource}->[0]->{$nr}->[oIMAGENR])
+ { $namn = 'Im' . $form{$fSource}->[0]->{$nr}->[oIMAGENR];
+ }
+ else
+ { $formNr++;
+ $namn = 'Fo' . $formNr;
+ }
+
+ $objRef{$namn} = $nr;
+ }
+
+ $$del1 =~ s/\b(\d+)\s{1,2}\d+\s{1,2}R\b/xform() . ' 0 R'/oegs;
+
+ if (defined $$del2)
+ { $utrad = "$nr 0 obj\n<<" . $$del1 . $$del2;
+ }
+ else
+ { $utrad = "$nr 0 obj " . $$del1;
+ }
+ $objekt[$nr] = $pos;
+ $pos += syswrite UTFIL, $utrad;
+
+ ##################################
+ # Skriv ut underordnade objekt
+ ##################################
+
+ while (scalar @skapa)
+ { my @process = @skapa;
+ @skapa = ();
+ for (@process)
+ { my $gammal = $$_[0];
+ my $ny = $$_[1];
+
+ ($del1, $del2, $kids) = getKnown(\$form{$fSource}, $gammal);
+
+ $$del1 =~ s/\b(\d+)\s{1,2}\d+\s{1,2}R\b/xform() . ' 0 R'/oegs
+ unless (! defined $kids);
+ if (defined $$del2)
+ { $utrad = "$ny 0 obj\n<<" . $$del1 . $$del2;
+ }
+ else
+ { $utrad = "$ny 0 obj " . $$del1;
+ }
+ $objekt[$ny] = $pos;
+ $pos += syswrite UTFIL, $utrad;
+ }
+ }
+ close INFIL;
+
+ return $namn;
+
+}
+
+########################
+# Ett objekt extraheras
+########################
+
+sub extractObject
+{ no warnings;
+ my ($infil, $sidnr, $key, $typ) = @_;
+
+ my ($res, $del1, $corr, $namn, $kids, $nr, $utrad);
+ my $del2 = '';
+ @skapa = ();
+
+ $behandlad{$infil}->{old} = {}
+ unless (defined $behandlad{$infil}->{old});
+ $processed{$infil}->{oldObject} = {}
+ unless (defined $processed{$infil}->{oldObject});
+ $processed{$infil}->{unZipped} = {}
+ unless (defined $processed{$infil}->{unZipped});
+
+ *old = $behandlad{$infil}->{old};
+ *oldObject = $processed{$infil}->{oldObject};
+ *unZipped = $processed{$infil}->{unZipped};
+
+ my $fSource = $infil . '_' . $sidnr;
+ my @stati = stat($infil);
+
+ if ($form{$fSource}[fID] != $stati[9])
+ { errLog("$stati[9] ne $form{$fSource}[fID] aborts");
+ }
+ if ($checkId)
+ { if ($checkId ne $stati[9])
+ { my $mess = "$checkId \<\> $stati[9] \n"
+ . "The Pdf-file $fSource has not the correct modification time. \n"
+ . "The program is aborted";
+ errLog($mess);
+ }
+ undef $checkId;
+ }
+ if ($ldir)
+ { $log .= "Cid~$stati[9]\n";
+ my $indata = prep($infil);
+ $log .= "Form~$indata~$sidnr~~load~1\n";
+ }
+
+ open (INFIL, "<$infil") || errLog("The file $infil couldn't be opened, aborting $!");
+ binmode INFIL;
+
+ ########################################
+ # Read the top object of the hierarchy
+ ########################################
+
+ ($del1, $del2, $kids) = getKnown(\$form{$fSource}, $key);
+
+ if (exists $old{$key})
+ { $nr = $old{$key}; }
+ else
+ { $old{$key} = ++$objNr;
+ $nr = $objNr;
+ }
+
+ if ($typ eq 'Font')
+ { my ($Font, $extNamn);
+ if ($$del1 =~ m'/BaseFont\s*/([^\s\/]+)'os)
+ { $extNamn = $1;
+ $fontNr++;
+ $Font = 'Ft' . $fontNr;
+ $font{$extNamn}[foINTNAMN] = $Font;
+ $font{$extNamn}[foORIGINALNR] = $key;
+ if ( ! defined $fontSource{$extNamn}[foSOURCE])
+ { $fontSource{$extNamn}[foSOURCE] = $fSource;
+ $fontSource{$extNamn}[foORIGINALNR] = $key;
+ }
+ $font{$extNamn}[foREFOBJ] = $nr;
+ $Font = $font{$extNamn}[foINTNAMN];
+ $namn = $Font;
+ $objRef{$Font} = $nr;
+ }
+ else
+ { errLog("Error in $fSource, $key is not a font, aborting");
+ }
+ }
+ elsif ($typ eq 'ColorSpace')
+ { $colorSpace++;
+ $namn = 'Cs' . $colorSpace;
+ $objRef{$namn} = $nr;
+ }
+ elsif ($typ eq 'Pattern')
+ { $pattern++;
+ $namn = 'Pt' . $pattern;
+ $objRef{$namn} = $nr;
+ }
+ elsif ($typ eq 'Shading')
+ { $shading++;
+ $namn = 'Sh' . $shading;
+ $objRef{$namn} = $nr;
+ }
+ elsif ($typ eq 'ExtGState')
+ { $gSNr++;
+ $namn = 'Gs' . $gSNr;
+ $objRef{$namn} = $nr;
+ }
+ elsif ($typ eq 'XObject')
+ { if (defined $form{$fSource}->[0]->{$nr}->[oIMAGENR])
+ { $namn = 'Im' . $form{$fSource}->[0]->{$nr}->[oIMAGENR];
+ }
+ else
+ { $formNr++;
+ $namn = 'Fo' . $formNr;
+ }
+
+ $objRef{$namn} = $nr;
+ }
+
+ $$del1 =~ s/\b(\d+)\s{1,2}\d+\s{1,2}R\b/xform() . ' 0 R'/oegs
+ unless (! defined $kids);
+ if (defined $$del2)
+ { $utrad = "$nr 0 obj\n<<" . $$del1 . $$del2;
+ }
+ else
+ { $utrad = "$nr 0 obj " . $$del1;
+ }
+
+ $objekt[$nr] = $pos;
+ $pos += syswrite UTFIL, $utrad;
+
+ ##################################
+ # Skriv ut underordnade objekt
+ ##################################
+
+ while (scalar @skapa)
+ { my @process = @skapa;
+ @skapa = ();
+ for (@process)
+ { my $gammal = $$_[0];
+ my $ny = $$_[1];
+
+ ($del1, $del2, $kids) = getKnown(\$form{$fSource}, $gammal);
+
+ $$del1 =~ s/\b(\d+)\s{1,2}\d+\s{1,2}R\b/xform() . ' 0 R'/oegs
+ unless (! defined $kids);
+
+ if (defined $$del2)
+ { $utrad = "$ny 0 obj<<" . $$del1 . $$del2;
+ }
+ else
+ { $utrad = "$ny 0 obj " . $$del1;
+ }
+
+ $objekt[$ny] = $pos;
+ $pos += syswrite UTFIL, $utrad;
+ }
+ }
+ close INFIL;
+ return $namn;
+}
+
+
+##########################################
+# En fil analyseras och sidorna kopieras
+##########################################
+
+sub analysera
+{ my $infil = shift;
+ my $from = shift || 1;
+ my $to = shift || 0;
+ my ($i, $res, @underObjekt, @sidObj, $vektor, $resources, $valid,
+ $strPos, $sidor, $filId, $Root, $del1, $del2, $utrad);
+
+ my $extraherade = 0;
+ my $sidAcc = 0;
+ @skapa = ();
+
+ $behandlad{$infil}->{old} = {}
+ unless (defined $behandlad{$infil}->{old});
+ $processed{$infil}->{oldObject} = {}
+ unless (defined $processed{$infil}->{oldObject});
+ $processed{$infil}->{unZipped} = {}
+ unless (defined $processed{$infil}->{unZipped});
+ *old = $behandlad{$infil}->{old};
+ *oldObject = $processed{$infil}->{oldObject};
+ *unZipped = $processed{$infil}->{unZipped};
+
+ $root = (exists $processed{$infil}->{root})
+ ? $processed{$infil}->{root} : 0;
+
+ my ($AcroForm, $Annots, $Names, $AARoot);
+ undef $taInterAkt;
+ undef %script;
+
+ my $checkIdOld = $checkId;
+ ($infil, $checkId) = findGet($infil, $checkIdOld);
+ if (($ldir) && ($checkId) && ($checkId ne $checkIdOld))
+ { $log .= "Cid~$checkId\n";
+ }
+ undef $checkId;
+ my @stati = stat($infil);
+ open (INFIL, "<$infil") || errLog("Couldn't open $infil,aborting. $!");
+ binmode INFIL;
+
+ if (! $root)
+ { $root = xRefs($stati[7], $infil);
+ }
+ #############
+ # Hitta root
+ #############
+
+ my $offSet;
+ my $bytes;
+ my $objektet = getObject($root);
+
+ if ((! $interActive) && ( ! $to) && ($from == 1))
+ { if ($objektet =~ m'/AcroForm(\s+\d+\s{1,2}\d+\s{1,2}R)'so)
+ { $AcroForm = $1;
+ }
+ if ($objektet =~ m'/Names\s+(\d+)\s{1,2}\d+\s{1,2}R'so)
+ { $Names = $1;
+ }
+ if ((scalar %fields) || (scalar @jsfiler) || (scalar @inits))
+ { $Names = behandlaNames($Names);
+ }
+ elsif ($Names)
+ { $Names = quickxform($Names);
+ }
+
+ #################################################
+ # Finns ett dictionary för Additional Actions ?
+ #################################################
+ if ($objektet =~ m'/AA(\s+\d+\s{1,2}\d+\s{1,2}R)'os) # Hänvisning
+ { $AARoot = $1; }
+ elsif ($objektet =~ m'/AA\s*\<\<\s*[^\>]+[^\>]+'so) # AA är ett dictionary
+ { my $k;
+ my ($dummy, $obj) = split /\/AA/, $objektet;
+ $obj =~ s/\<\</\#\<\</gs;
+ $obj =~ s/\>\>/\>\>\#/gs;
+ my @ord = split /\#/, $obj;
+ for ($i = 0; $i <= $#ord; $i++)
+ { $AARoot .= $ord[$i];
+ if ($ord[$i] =~ m'\S+'os)
+ { if ($ord[$i] =~ m'<<'os)
+ { $k++; }
+ if ($ord[$i] =~ m'>>'os)
+ { $k--; }
+ if ($k == 0)
+ { last; }
+ }
+ }
+ }
+ $taInterAkt = 1; # Flagga att ta med interaktiva funktioner
+ }
+
+ #
+ # Hitta pages
+ #
+
+ if ($objektet =~ m'/Pages\s+(\d+)\s{1,2}\d+\s{1,2}R'os)
+ { $objektet = getObject($1);
+ ($resources, $valid) = kolla($objektet);
+ if ($objektet =~ m'/Count\s+(\d+)'os)
+ { $sidor = $1; }
+ }
+ else
+ { errLog("Didn't find pages "); }
+
+ my @levels;
+ my $li = -1;
+
+ if ($objektet =~ m'/Kids\s*\[([^\]]+)'os)
+ { $vektor = $1;
+ while ($vektor =~ m'(\d+)\s{1,2}\d+\s{1,2}R'go)
+ { push @sidObj, $1;
+ }
+ $li++;
+ $levels[$li] = \@sidObj;
+ }
+
+ while (($li > -1) && ($sidAcc < $sidor))
+ { if (scalar @{$levels[$li]})
+ { my $j = shift @{$levels[$li]};
+ $objektet = getObject($j);
+ ($resources, $valid) = kolla($objektet, $resources);
+ if ($objektet =~ m'/Kids\s*\[([^\]]+)'os)
+ { $vektor = $1;
+ my @sObj;
+ while ($vektor =~ m'(\d+)\s{1,2}\d+\s{1,2}R'go)
+ { push @sObj, $1;
+ }
+ $li++;
+ $levels[$li] = \@sObj;
+ }
+ else
+ { $sidAcc++;
+ if ($sidAcc >= $from)
+ { if ($to)
+ { if ($sidAcc <= $to)
+ { sidAnalys($j, $objektet, $resources);
+ $extraherade++;
+ $sida++;
+ }
+ else
+ { $sidAcc = $sidor;
+ }
+ }
+ else
+ { sidAnalys($j, $objektet, $resources);
+ $extraherade++;
+ $sida++;
+ }
+ }
+ }
+ }
+ else
+ { $li--;
+ }
+ }
+
+ if (defined $AcroForm)
+ { $AcroForm =~ s/\b(\d+)\s{1,2}\d+\s{1,2}R\b/xform() . ' 0 R'/oegs;
+ }
+ if (defined $AARoot)
+ { $AARoot =~ s/\b(\d+)\s{1,2}\d+\s{1,2}R\b/xform() . ' 0 R'/oegs;
+ }
+
+ while (scalar @skapa)
+ { my @process = @skapa;
+ @skapa = ();
+ for (@process)
+ { my $gammal = $$_[0];
+ my $ny = $$_[1];
+ $objektet = getObject($gammal);
+
+ if ($objektet =~ m'^(\d+ \d+ obj\s*<<)(.+)(>>\s*stream)'os)
+ { $del1 = $2;
+ $strPos = length($2) + length($3) + length($1);
+ $del1 =~ s/\b(\d+)\s{1,2}\d+\s{1,2}R\b/xform() . ' 0 R'/oegs;
+ $objekt[$ny] = $pos;
+ $utrad = "$ny 0 obj<<" . "$del1" . '>>stream';
+ $del2 = substr($objektet, $strPos);
+ $utrad .= $del2;
+
+ $pos += syswrite UTFIL, $utrad;
+ }
+ else
+ { if ($objektet =~ m'^(\d+ \d+ obj)'os)
+ { my $preLength = length($1);
+ $objektet = substr($objektet, $preLength);
+ }
+ $objektet =~ s/\b(\d+)\s{1,2}\d+\s{1,2}R\b/xform() . ' 0 R'/oegs;
+ $objekt[$ny] = $pos;
+ $utrad = "$ny 0 obj$objektet";
+ $pos += syswrite UTFIL, $utrad;
+ }
+ }
+ }
+ close INFIL;
+ $processed{$infil}->{root} = $root;
+
+ return ($extraherade, $Names, $AARoot, $AcroForm);
+}
+
+sub sidAnalys
+{ my ($oNr, $obj, $resources) = @_;
+ my ($ny, $strPos, $spar, $closeProc, $del1, $del2, $utrad, $Annots);
+
+ if (! $parents[0])
+ { $objNr++;
+ $parents[0] = $objNr;
+ }
+ my $parent = $parents[0];
+ $objNr++;
+ $ny = $objNr;
+
+ $old{$oNr} = $ny;
+
+ if ($obj =~ m'/Parent\s+(\d+)\s{1,2}\d+\s{1,2}R\b'os)
+ { $old{$1} = $parent;
+ }
+
+ if ($obj =~ m'^(\d+ \d+ obj\s*<<)(.+)(>>\s*stream)'os)
+ { $del1 = $2;
+ $strPos = length($2) + length($3) + length($1);
+ $del2 = substr($obj, $strPos);
+ }
+ elsif ($obj =~ m'^\d+ \d+ obj\s*<<(.+)>>\s*endobj'os)
+ { $del1 = $1;
+ }
+ if (%links)
+ { my $tSida = $sida + 1;
+ if (defined (@{$links{'-1'}}) || (defined @{$links{$tSida}}))
+ { if ($del1 =~ m'/Annots\s*([^\/\<\>]+)'os)
+ { $Annots = $1;
+ @annots = ();
+ if ($Annots =~ m'\[([^\[\]]*)\]'os)
+ { ; }
+ else
+ { if ($Annots =~ m'\b(\d+)\s{1,2}\d+\s{1,2}R\b'os)
+ { $Annots = getObject($1);
+ }
+ }
+ while ($Annots =~ m'\b(\d+)\s{1,2}\d+\s{1,2}R\b'ogs)
+ { push @annots, xform();
+ }
+ $del1 =~ s?/Annots\s*([^\/\<\>]+)??os;
+ }
+ $Annots = '/Annots ' . mergeLinks() . ' 0 R';
+ }
+ }
+
+ if (! $taInterAkt)
+ { $del1 =~ s?\s*/AA\s*<<[^>]*>>??os;
+ }
+ if ($del1 !~ m'/Resources'o)
+ { $del1 .= "/Resources $resources";
+ }
+
+ $del1 =~ s/\b(\d+)\s{1,2}\d+\s{1,2}R\b/xform() . ' 0 R'/oegs;
+ if ($Annots)
+ { $del1 .= $Annots;
+ }
+
+ $utrad = "$ny 0 obj<<$del1>>";
+ if (defined $del2)
+ { $utrad .= "stream\n$del2";
+ }
+ else
+ { $utrad .= "endobj\n";
+ }
+
+ $objekt[$ny] = $pos;
+ $pos += syswrite UTFIL, $utrad;
+
+ push @{$kids[0]}, $ny;
+ $counts[0]++;
+ if ($counts[0] > 9)
+ { ordnaNoder(8);
+ }
+}
+
+
+sub translate
+{ if (exists $old{$1})
+ { $old{$1}; }
+ else
+ { $old{$1} = ++$objNr;
+ }
+}
+
+sub behandlaNames
+{ my ($namnObj, $iForm) = @_;
+
+ my ($low, $high, $antNod0, $entry, $nyttNr, $ny, $obj,
+ $fObjnr, $offSet, $bytes, $res, $key, $func, $corr, @objData);
+ my (@nod0, @nodUpp, @kid, @soek, %nytt);
+
+ my $objektet = '';
+ my $vektor = '';
+ my $antal = 0;
+ my $antNodUpp = 0;
+ if ($namnObj)
+ { if ($iForm) # Läsning via interntabell
+ { $objektet = getObject($namnObj, 1);
+
+ if ($objektet =~ m'<<(.+)>>'ogs)
+ { $objektet = $1; }
+ if ($objektet =~ s'/JavaScript\s+(\d+)\s{1,2}\d+\s{1,2}R''os)
+ { my $byt = $1;
+ push @kid, $1;
+ while (scalar @kid)
+ { @soek = @kid;
+ @kid = ();
+ for my $sObj (@soek)
+ { $obj = getObject($sObj, 1);
+ if ($obj =~ m'/Kids\s*\[([^]]+)'ogs)
+ { $vektor = $1;
+ }
+ while ($vektor =~ m'\b(\d+)\s{1,2}\d+\s{1,2}R\b'ogs)
+ { push @kid, $1;
+ }
+ $vektor = '';
+ if ($obj =~ m'/Names\s*\[([^]]+)'ogs)
+ { $vektor = $1;
+ }
+ while ($vektor =~ m'\(([^\)]+)\)\s*(\d+) \d R'gos)
+ { $script{$1} = $2;
+ }
+ }
+ }
+ }
+ }
+ else # Läsning av ett "doc"
+ { $objektet = getObject($namnObj);
+ if ($objektet =~ m'<<(.+)>>'ogs)
+ { $objektet = $1; }
+ if ($objektet =~ s'/JavaScript\s+(\d+)\s{1,2}\d+\s{1,2}R''os)
+ { my $byt = $1;
+ push @kid, $1;
+ while (scalar @kid)
+ { @soek = @kid;
+ @kid = ();
+ for my $sObj (@soek)
+ { $obj = getObject($sObj);
+ if ($obj =~ m'/Kids\s*\[([^]]+)'ogs)
+ { $vektor = $1;
+ }
+ while ($vektor =~ m'\b(\d+)\s{1,2}\d+\s{1,2}R\b'ogs)
+ { push @kid, $1;
+ }
+ undef $vektor;
+ if ($obj =~ m'/Names\s*\[([^]]+)'ogs)
+ { $vektor = $1;
+ }
+ while ($vektor =~ m'\(([^\)]+)\)\s*(\d+) \d R'gos)
+ { $script{$1} = $2;
+ }
+ }
+ }
+ }
+ }
+ }
+ for my $filnamn (@jsfiler)
+ { inkludera($filnamn);
+ }
+ my @nya = (keys %nyaFunk);
+ while (scalar @nya)
+ { my @behandla = @nya;
+ @nya = ();
+ for $key (@behandla)
+ { if (exists $initScript{$key})
+ { if (exists $nyaFunk{$key})
+ { $initScript{$key} = $nyaFunk{$key};
+ }
+ if (exists $script{$key}) # företräde för nya funktioner !
+ { delete $script{$key}; # gammalt script m samma namn plockas bort
+ }
+ my @fall = ($initScript{$key} =~ m'([\w\d\_\$]+)\s*\('ogs);
+ for (@fall)
+ { if (($_ ne $key) && (exists $nyaFunk{$_}))
+ { $initScript{$_} = $nyaFunk{$_};
+ push @nya, $_;
+ }
+ }
+ }
+ }
+ }
+ while (($key, $func) = each %nyaFunk)
+ { $fObjnr = skrivJS($func);
+ $script{$key} = $fObjnr;
+ $nytt{$key} = $fObjnr;
+ }
+
+ if (scalar %fields)
+ { push @inits, 'Ladda();';
+ $fObjnr = defLadda();
+ if ($duplicateInits)
+ { $script{'Ladda'} = $fObjnr;
+ $nytt{'Ladda'} = $fObjnr;
+ }
+ }
+
+ if ((scalar @inits) && ($duplicateInits))
+ { $fObjnr = defInit();
+ $script{'Init'} = $fObjnr;
+ $nytt{'Init'} = $fObjnr;
+ }
+ undef @jsfiler;
+
+ for my $key (sort (keys %script))
+ { if (! defined $low)
+ { $objNr++;
+ $ny = $objNr;
+ $objekt[$ny] = $pos;
+ $obj = "$ny 0 obj\n";
+ $low = $key;
+ $obj .= '<< /Names [';
+ }
+ $high = $key;
+ $obj .= '(' . "$key" . ')';
+ if (! exists $nytt{$key})
+ { $nyttNr = quickxform($script{$key});
+ }
+ else
+ { $nyttNr = $script{$key};
+ }
+ $obj .= "$nyttNr 0 R\n";
+ $antal++;
+ if ($antal > 9)
+ { $obj .= ' ]/Limits [(' . "$low" . ')(' . "$high" . ')] >>' . "endobj\n";
+ $pos += syswrite UTFIL, $obj;
+ push @nod0, \[$ny, $low, $high];
+ $antNod0++;
+ undef $low;
+ $antal = 0;
+ }
+ }
+ if ($antal)
+ { $obj .= ']/Limits [(' . $low . ')(' . $high . ')]>>' . "endobj\n";
+ $pos += syswrite UTFIL, $obj;
+ push @nod0, \[$ny, $low, $high];
+ $antNod0++;
+ }
+ $antal = 0;
+
+ while (scalar @nod0)
+ { for $entry (@nod0)
+ { if ($antal == 0)
+ { $objNr++;
+ $objekt[$objNr] = $pos;
+ $obj = "$objNr 0 obj\n";
+ $low = $$entry->[1];
+ $obj .= '<</Kids [';
+ }
+ $high = $$entry->[2];
+ $obj .= " $$entry->[0] 0 R";
+ $antal++;
+ if ($antal > 9)
+ { $obj .= ']/Limits [(' . $low . ')(' . $high . ')]>>' . "endobj\n";
+ $pos += syswrite UTFIL, $obj;
+ push @nodUpp, \[$objNr, $low, $high];
+ $antNodUpp++;
+ undef $low;
+ $antal = 0;
+ }
+ }
+ if ($antal > 0)
+ { if ($antNodUpp == 0) # inget i noderna över
+ { $obj .= ']>>' . "endobj\n";
+ $pos += syswrite UTFIL, $obj;
+ }
+ else
+ { $obj .= ']/Limits [(' . "$low" . ')(' . "$high" . ')]>>' . "endobj\n";
+ $pos += syswrite UTFIL, $obj;
+ push @nodUpp, \[$objNr, $low, $high];
+ $antNodUpp++;
+ undef $low;
+ $antal = 0;
+ }
+ }
+ @nod0 = @nodUpp;
+ $antNod0 = $antNodUpp;
+ undef @nodUpp;
+ $antNodUpp = 0;
+ }
+
+
+ $ny = $objNr;
+ $objektet =~ s|\s*/JavaScript\s*\d+\s{1,2}\d+\s{1,2}R||os;
+ $objektet =~ s/\b(\d+)\s{1,2}\d+\s{1,2}R\b/xform() . ' 0 R'/oegs;
+ if (scalar %script)
+ { $objektet .= "\n/JavaScript $ny 0 R\n";
+ }
+ $objNr++;
+ $ny = $objNr;
+ $objekt[$ny] = $pos;
+ $objektet = "$ny 0 obj<<" . $objektet . ">>endobj\n";
+ $pos += syswrite UTFIL, $objektet;
+ return $ny;
+}
+
+
+sub quickxform
+{ my $inNr = shift;
+ if (exists $old{$inNr})
+ { $old{$inNr}; }
+ else
+ { push @skapa, [$inNr, ++$objNr];
+ $old{$inNr} = $objNr;
+ }
+}
+
+
+sub skrivKedja
+{ my $code = ' ';
+
+ for (values %initScript)
+ { $code .= $_ . "\n";
+ }
+ $code .= "function Init()\r{\r";
+ $code .= 'if (typeof this.info.ModDate == "object")' . "\r{ return true; }\r";
+ for (@inits)
+ { $code .= $_ . "\n";
+ }
+ $code .= "}\r Init(); ";
+
+ my $spar = skrivJS($code);
+ undef @inits;
+ undef %initScript;
+ return $spar;
+}
+
+
+
+sub skrivJS
+{ my $kod = shift;
+ my $obj;
+ if (($compress) && (length($kod) > 99))
+ { $objNr++;
+ $objekt[$objNr] = $pos;
+ my $spar = $objNr;
+ $kod = compress($kod);
+ my $langd = length($kod);
+ $obj = "$objNr 0 obj<</Filter/FlateDecode"
+ . "/Length $langd>>stream\n" . $kod
+ . "\nendstream\nendobj\n";
+ $pos += syswrite UTFIL, $obj;
+ $objNr++;
+ $objekt[$objNr] = $pos;
+ $obj = "$objNr 0 obj<</S/JavaScript/JS $spar 0 R >>endobj\n";
+ }
+ else
+ { $kod =~ s'\('\\('gso;
+ $kod =~ s'\)'\\)'gso;
+ $objNr++;
+ $objekt[$objNr] = $pos;
+ $obj = "$objNr 0 obj<</S/JavaScript/JS " . '(' . $kod . ')';
+ $obj .= ">>endobj\n";
+ }
+ $pos += syswrite UTFIL, $obj;
+ return $objNr;
+}
+
+sub inkludera
+{ my $jsfil = shift;
+ my $fil;
+ if ($jsfil !~ m'\{'os)
+ { open (JSFIL, "<$jsfil") || return;
+ while (<JSFIL>)
+ { $fil .= $_;}
+
+ close JSFIL;
+ }
+ else
+ { $fil = $jsfil;
+ }
+ $fil =~ s|function\s+([\w\_\d\$]+)\s*\(|"zXyZcUt function $1 ("|sge;
+ my @funcs = split/zXyZcUt /, $fil;
+ for my $kod (@funcs)
+ { if ($kod =~ m'^function ([\w\_\d\$]+)'os)
+ { $nyaFunk{$1} = $kod;
+ }
+ }
+}
+
+
+sub defLadda
+{ my $code = "function Ladda()\r{\r";
+ for (keys %fields)
+ { my $val = $fields{$_};
+ if ($val =~ m'\s*js\s*\:(.+)'oi)
+ { $val = $1;
+ $code .= "if (this.getField('$_')) this.getField('$_').value = $val;\r";
+ }
+ else
+ { $val =~ s/([^A-Za-z0-9\-_.!* ])/sprintf("%%%02X", ord($1))/ge;
+ $code .= "if (this.getField('$_')) this.getField('$_').value = unescape('$val');\r";
+ }
+
+ }
+ $code .= " 1;}\r";
+
+
+ $initScript{'Ladda'} = $code;
+ if ($duplicateInits)
+ { my $ny = skrivJS($code);
+ return $ny;
+ }
+ else
+ { return 1;
+ }
+}
+
+sub defInit
+{ my $code = "function Init()\r{\r";
+ $code .= 'if (typeof this.info.ModDate == "object")' . "\r{ return true; }\r";
+ for (@inits)
+ { $code .= $_ . "\n";
+ }
+ $code .= '}';
+
+ my $ny = skrivJS($code);
+ return $ny;
+
+}
+
+
+
+sub errLog
+{ no strict 'refs';
+ my $mess = shift;
+ my $endMess = " $mess \n More information might be found in";
+ if ($runfil)
+ { $log .= "Log~Err: $mess\n";
+ $endMess .= "\n $runfil";
+ if (! $pos)
+ { $log .= "Log~Err: No pdf-file has been initiated\n";
+ }
+ elsif ($pos > 15000000)
+ { $log .= "Log~Err: Current pdf-file is very big: $pos bytes, will not try to finnish it\n";
+ }
+ else
+ { $log .= "Log~Err: Will try to finnish current pdf-file\n";
+ $endMess .= "\n $utfil";
+ }
+ }
+ my $errLog = 'error.log';
+ my $now = localtime();
+ my $lpos = $pos || 'undef';
+ my $lobjNr = $objNr || 'undef';
+ my $lutfil = $utfil || 'undef';
+
+ my $lrunfil = $runfil || 'undef';
+ open (ERRLOG, ">$errLog") || croak "$mess can't open an error logg, $!";
+ print ERRLOG "\n$mess\n\n";
+ print ERRLOG Carp::longmess("The error occurred when executing:\n");
+ print ERRLOG "\nSituation when the error occurred\n\n";
+ print ERRLOG " Bytes written to the current pdf-file, pos = $lpos\n";
+ print ERRLOG " Object processed, not necessarily written objNr = $lobjNr\n";
+ print ERRLOG " Current pdf-file, utfil = $lutfil\n";
+ print ERRLOG " File logging the run, runfil = $lrunfil\n";
+ print ERRLOG " Local time = $now\n";
+ print ERRLOG "\n\n";
+ close ERRLOG;
+ $endMess .= "\n $errLog";
+ if (($pos) && ($pos < 15000000))
+ { prEnd();
+ }
+ print STDERR Carp::shortmess("An error occurred \n");
+ croak "$endMess\n";
+}
diff --git a/Master/texmf-dist/scripts/xetex/perl/lib/PDF/Reuse/Util.pm b/Master/texmf-dist/scripts/xetex/perl/lib/PDF/Reuse/Util.pm
new file mode 100644
index 00000000000..ee48a6aa205
--- /dev/null
+++ b/Master/texmf-dist/scripts/xetex/perl/lib/PDF/Reuse/Util.pm
@@ -0,0 +1,326 @@
+package PDF::Reuse::Util;
+use PDF::Reuse;
+require Exporter;
+our @ISA = qw(Exporter);
+our @EXPORT = qw(hyperLink);
+
+
+use strict;
+
+our %font_widths = (
+ 'Courier' => 600,
+ 'Courier-Bold' => 600,
+ 'Courier-BoldOblique' => 600,
+ 'Courier-Oblique' => 600,
+ 'Times-Roman' =>
+ [000, 000, 000, 000, 000, 000, 000, 000,
+ 000, 000, 000, 000, 000, 000, 000, 000,
+ 000, 000, 000, 000, 000, 000, 000, 000,
+ 000, 000, 000, 000, 000, 000, 000, 000,
+ 250, 333, 408, 500, 500, 833, 778, 180,
+ 333, 333, 500, 564, 250, 333, 250, 278,
+ 500, 500, 500, 500, 500, 500, 500, 500,
+ 500, 500, 278, 278, 564, 564, 564, 444,
+ 921, 722, 667, 667, 722, 611, 556, 722,
+ 722, 333, 389, 722, 611, 889, 722, 722,
+ 556, 722, 667, 556, 611, 722, 722, 944,
+ 722, 722, 611, 333, 278, 333, 469, 500,
+ 333, 444, 500, 444, 500, 444, 333, 500,
+ 500, 278, 278, 500, 278, 778, 500, 500,
+ 500, 500, 333, 389, 278, 500, 500, 722,
+ 500, 500, 444, 480, 200, 480, 541, 350,
+ 500, 350, 333, 500, 443, 1000, 500, 500,
+ 333, 1000, 555, 333, 889, 350, 611, 350,
+ 350, 333, 333, 443, 443, 350, 500, 1000,
+ 333, 980, 388, 333, 722, 350, 444, 721,
+ 250, 333, 500, 500, 500, 500, 200, 500,
+ 333, 760, 276, 500, 564, 333, 760, 333,
+ 400, 564, 300, 300, 333, 510, 453, 250,
+ 333, 300, 310, 500, 750, 750, 750, 444,
+ 722, 722, 722, 722, 722, 722, 889, 667,
+ 611, 611, 611, 611, 333, 333, 333, 333,
+ 722, 722, 722, 722, 722, 722, 722, 564,
+ 722, 722, 722, 722, 722, 722, 556, 500,
+ 444, 444, 444, 444, 444, 444, 667, 444,
+ 444, 444, 444, 444, 278, 278, 278, 278,
+ 500, 500, 500, 500, 500, 500, 500, 564,
+ 500, 500, 500, 500, 500, 500, 500, 500],
+ 'Times-Bold' =>
+ [000, 000, 000, 000, 000, 000, 000, 000,
+ 000, 000, 000, 000, 000, 000, 000, 000,
+ 000, 000, 000, 000, 000, 000, 000, 000,
+ 000, 000, 000, 000, 000, 000, 000, 000,
+ 250, 333, 555, 500, 500, 1000, 833, 278,
+ 333, 333, 500, 570, 250, 333, 250, 278,
+ 500, 500, 500, 500, 500, 500, 500, 500,
+ 500, 500, 333, 333, 570, 570, 570, 500,
+ 930, 722, 667, 722, 722, 667, 611, 778,
+ 778, 389, 500, 778, 667, 944, 722, 778,
+ 611, 778, 722, 556, 667, 722, 722, 1000,
+ 722, 722, 667, 333, 278, 333, 581, 500,
+ 333, 500, 556, 444, 556, 444, 333, 500,
+ 556, 278, 333, 556, 278, 833, 556, 500,
+ 556, 556, 444, 389, 333, 556, 500, 722,
+ 500, 500, 444, 394, 220, 394, 520, 350,
+ 500, 350, 333, 500, 500, 1000, 500, 500,
+ 333, 1000, 556, 333, 1000, 350, 667, 350,
+ 350, 333, 333, 500, 500, 350, 500, 1000,
+ 333, 1000, 389, 333, 723, 350, 444, 722,
+ 250, 333, 500, 500, 500, 500, 220, 500,
+ 333, 747, 300, 500, 570, 333, 747, 333,
+ 400, 570, 300, 300, 333, 601, 540, 250,
+ 333, 300, 330, 500, 750, 750, 750, 500,
+ 722, 722, 722, 722, 722, 722, 1000, 722,
+ 667, 667, 667, 667, 389, 389, 389, 389,
+ 722, 722, 778, 778, 778, 778, 778, 570,
+ 778, 722, 722, 722, 722, 722, 611, 556,
+ 500, 500, 500, 500, 500, 500, 722, 444,
+ 444, 444, 444, 444, 278, 278, 278, 278,
+ 500, 556, 500, 500, 500, 500, 500, 570,
+ 500, 556, 556, 556, 556, 500, 556, 500],
+ 'Times-Italic' =>
+ [000, 000, 000, 000, 000, 000, 000, 000,
+ 000, 000, 000, 000, 000, 000, 000, 000,
+ 000, 000, 000, 000, 000, 000, 000, 000,
+ 000, 000, 000, 000, 000, 000, 000, 000,
+ 250, 333, 420, 500, 500, 833, 778, 214, #39
+ 333, 333, 500, 675, 250, 333, 250, 278, #47
+ 500, 500, 500, 500, 500, 500, 500, 500, #55
+ 500, 500, 333, 333, 675, 675, 675, 500, #63
+ 920, 611, 611, 667, 722, 611, 611, 722, #71
+ 722, 333, 444, 667, 556, 833, 667, 722, #79
+ 611, 722, 611, 500, 556, 722, 611, 833, #87
+ 611, 556, 556, 389, 278, 389, 422, 500, #95
+ 333, 500, 500, 444, 500, 444, 278, 500, #103
+ 500, 278, 278, 444, 278, 722, 500, 500, #111
+ 500, 500, 389, 389, 278, 500, 444, 667, #119
+ 444, 444, 389, 400, 275, 400, 541, 350, # 127
+ 500, 350, 333, 500, 556, 889, 500, 500, # 135
+ 333, 1000, 500, 333, 944, 350, 556, 350, # 143
+ 350, 333, 333, 556, 556, 350, 500, 890, # 151
+ 333, 980, 389, 333, 668, 350, 390, 557, # 159
+ 250, 389, 500, 500, 500, 500, 275, 500, # 167
+ 333, 760, 276, 500, 675, 333, 760, 333, # 175
+ 400, 675, 300, 300, 333, 514, 523, 250, # 183
+ 333, 300, 310, 500, 750, 750, 750, 500, # 191
+ 611, 611, 611, 611, 611, 611, 889, 667,
+ 611, 611, 611, 611, 333, 333, 333, 333,
+ 722, 667, 722, 722, 722, 722, 722, 675,
+ 722, 722, 722, 722, 722, 556, 611, 500,
+ 500, 500, 500, 500, 500, 500, 667, 444,
+ 444, 444, 444, 444, 278, 278, 278, 278,
+ 500, 500, 500, 500, 500, 500, 500, 675,
+ 500, 500, 500, 500, 500, 444, 500, 444],
+
+ 'Times-BoldItalic' =>
+ [000, 000, 000, 000, 000, 000, 000, 000,
+ 000, 000, 000, 000, 000, 000, 000, 000,
+ 000, 000, 000, 000, 000, 000, 000, 000,
+ 000, 000, 000, 000, 000, 000, 000, 000,
+ 250, 389, 555, 500, 500, 833, 778, 278,
+ 333, 333, 500, 570, 250, 333, 250, 278,
+ 500, 500, 500, 500, 500, 500, 500, 500,
+ 500, 500, 333, 333, 570, 570, 570, 500,
+ 832, 667, 667, 667, 722, 667, 667, 722,
+ 778, 389, 500, 667, 611, 889, 722, 722,
+ 611, 722, 667, 556, 611, 722, 667, 889,
+ 667, 611, 611, 333, 278, 333, 570, 500,
+ 333, 500, 500, 444, 500, 444, 333, 500,
+ 556, 278, 278, 500, 278, 778, 556, 500,
+ 500, 500, 389, 389, 278, 556, 444, 667,
+ 500, 444, 389, 348, 220, 348, 570, 350, # 127
+ 500, 350, 333, 500, 502, 1000, 500, 500, # 135
+ 333, 1000, 555, 333, 944, 350, 610, 350, # 143
+ 350, 333, 333, 500, 500, 350, 500, 1000, # 151
+ 333, 1000, 389, 333, 721, 350, 390, 610, # 159
+ 250, 389, 500, 500, 500, 500, 220, 500, #167
+ 333, 747, 266, 500, 606, 333, 747, 333, #175
+ 400, 570, 300, 300, 333, 532, 500, 250, #183
+ 333, 300, 300, 500, 750, 750, 750, 500,
+ 667, 667, 667, 667, 667, 667, 944, 667,
+ 667, 667, 667, 667, 389, 389, 389, 389,
+ 722, 722, 722, 722, 722, 722, 722, 570,
+ 722, 722, 722, 722, 722, 611, 611, 500,
+ 500, 500, 500, 500, 500, 500, 722, 444,
+ 444, 444, 444, 444, 278, 278, 278, 278,
+ 500, 556, 500, 500, 500, 500, 500, 570,
+ 500, 556, 556, 556, 556, 444, 500, 444],
+
+ 'Helvetica' =>
+ [000, 000, 000, 000, 000, 000, 000, 000,
+ 000, 000, 000, 000, 000, 000, 000, 000,
+ 000, 000, 000, 000, 000, 000, 000, 000,
+ 000, 000, 000, 000, 000, 000, 000, 000,
+ 278, 278, 355, 556, 556, 889, 667, 192,
+ 333, 333, 389, 584, 278, 333, 278, 278,
+ 556, 556, 556, 556, 556, 556, 556, 556,
+ 556, 556, 278, 278, 584, 584, 584, 556,
+ 1015, 667, 667, 722, 722, 667, 611, 778,
+ 722, 278, 500, 667, 556, 833, 722, 778,
+ 667, 778, 722, 667, 611, 722, 667, 944,
+ 667, 667, 611, 278, 278, 278, 469, 557,
+ 334, 556, 556, 500, 556, 556, 278, 556,
+ 556, 222, 222, 500, 222, 833, 556, 556,
+ 556, 556, 333, 500, 278, 556, 500, 722,
+ 500, 500, 500, 334, 260, 334, 584, 350, # 127
+ 556, 350, 222, 556, 333, 1000, 556, 556, # 135
+ 333, 1000, 667, 333, 1000, 351, 611, 350, # 143
+ 350, 223, 222, 333, 333, 351, 557, 1000, # 151
+ 333, 1000, 500, 333, 945, 350, 500, 667, # 159
+ 278, 333, 556, 556, 556, 556, 260, 556, # 167
+ 333, 737, 370, 556, 584, 333, 737, 333, # 175
+ 400, 584, 333, 333, 333, 578, 537, 278, # 183
+ 333, 333, 365, 556, 835, 835, 835, 611, # 191
+ 667, 667, 667, 667, 667, 667, 1000, 722,
+ 667, 667, 667, 667, 278, 278, 278, 278,
+ 722, 722, 778, 778, 778, 778, 778, 584,
+ 778, 722, 722, 722, 722, 667, 667, 611,
+ 556, 556, 556, 556, 556, 556, 889, 500,
+ 556, 556, 556, 556, 278, 278, 278, 278,
+ 556, 556, 556, 556, 556, 556, 556, 584,
+ 611, 556, 556, 556, 556, 500, 556, 500],
+
+ 'Helvetica-Bold' =>
+ [000, 000, 000, 000, 000, 000, 000, 000,
+ 000, 000, 000, 000, 000, 000, 000, 000,
+ 000, 000, 000, 000, 000, 000, 000, 000,
+ 000, 000, 000, 000, 000, 000, 000, 000, #31
+ 278, 333, 474, 556, 556, 889, 722, 238, #39
+ 333, 333, 389, 584, 278, 333, 278, 278, #47
+ 556, 556, 556, 556, 556, 556, 556, 556, #55
+ 556, 556, 333, 333, 584, 584, 584, 611, #63
+ 975, 722, 722, 722, 722, 667, 611, 778, #71
+ 722, 278, 556, 722, 611, 833, 722, 778, #79
+ 667, 778, 722, 667, 611, 722, 667, 944, #87
+ 667, 667, 611, 333, 278, 333, 584, 556, #95
+ 333, 556, 611, 556, 611, 556, 333, 611, #103
+ 611, 278, 278, 556, 278, 889, 611, 611, #111
+ 611, 611, 389, 556, 333, 611, 556, 778, #119
+ 556, 556, 500, 389, 280, 389, 584, 350, # 127
+ 556, 350, 278, 556, 500, 1000, 556, 556, # 135
+ 333, 1000, 667, 333, 1000, 350, 611, 350, # 143
+ 350, 278, 278, 500, 500, 350, 556, 1000, # 151
+ 333, 1000, 556, 333, 944, 350, 500, 667, # 159
+ 278, 333, 556, 556, 556, 556, 280, 556, #167
+ 333, 737, 370, 556, 584, 333, 737, 333,
+ 400, 584, 333, 333, 333, 611, 556, 278,
+ 333, 333, 365, 556, 834, 834, 834, 611,
+ 722, 722, 722, 722, 722, 722, 1000, 722,
+ 667, 667, 667, 667, 278, 278, 278, 278,
+ 722, 722, 778, 778, 778, 778, 778, 584,
+ 778, 722, 722, 722, 722, 667, 667, 611,
+ 556, 556, 556, 556, 556, 556, 889, 556,
+ 556, 556, 556, 556, 278, 278, 278, 278,
+ 611, 611, 611, 611, 611, 611, 611, 584,
+ 611, 611, 611, 611, 611, 556, 611, 556],
+
+ 'Helvetica-Oblique' =>
+ [000, 000, 000, 000, 000, 000, 000, 000,
+ 000, 000, 000, 000, 000, 000, 000, 000,
+ 000, 000, 000, 000, 000, 000, 000, 000,
+ 000, 000, 000, 000, 000, 000, 000, 000,
+ 278, 278, 355, 556, 556, 889, 667, 191,
+ 333, 333, 389, 584, 278, 333, 278, 278,
+ 556, 556, 556, 556, 556, 556, 556, 556,
+ 556, 556, 278, 278, 584, 584, 584, 556,
+ 1015, 667, 667, 722, 722, 667, 611, 778,
+ 722, 278, 500, 667, 556, 833, 722, 778,
+ 667, 778, 722, 667, 611, 722, 667, 944,
+ 667, 667, 611, 278, 278, 278, 469, 556,
+ 333, 556, 556, 500, 556, 556, 278, 556,
+ 556, 222, 222, 500, 222, 833, 556, 556,
+ 556, 556, 333, 500, 278, 556, 500, 722,
+ 500, 500, 500, 334, 260, 334, 584, 350, # 127
+ 556, 350, 222, 556, 333, 1000, 556, 556, # 135
+ 333, 1000, 667, 333, 1000, 351, 611, 350, # 143
+ 350, 223, 222, 333, 333, 351, 557, 1000, # 151
+ 333, 1000, 500, 333, 945, 350, 500, 667, # 159
+ 278, 333, 556, 556, 556, 556, 260, 556, # 167
+ 333, 737, 370, 556, 584, 333, 737, 333, # 175
+ 400, 584, 333, 333, 333, 578, 537, 278, # 183
+ 333, 333, 365, 556, 834, 834, 834, 611, # 191
+ 667, 667, 667, 667, 667, 667, 1000, 722,
+ 667, 667, 667, 667, 278, 278, 278, 278,
+ 722, 722, 778, 778, 778, 778, 778, 584,
+ 778, 722, 722, 722, 722, 667, 667, 611,
+ 556, 556, 556, 556, 556, 556, 889, 500,
+ 556, 556, 556, 556, 278, 278, 278, 278,
+ 556, 556, 556, 556, 556, 556, 556, 584,
+ 611, 556, 556, 556, 556, 500, 556, 500],
+
+ 'Helvetica-BoldOblique' =>
+ [000, 000, 000, 000, 000, 000, 000, 000,
+ 000, 000, 000, 000, 000, 000, 000, 000,
+ 000, 000, 000, 000, 000, 000, 000, 000,
+ 000, 000, 000, 000, 000, 000, 000, 000,
+ 278, 333, 474, 556, 556, 889, 722, 238, #39
+ 333, 333, 389, 584, 278, 333, 278, 278, #47
+ 556, 556, 556, 556, 556, 556, 556, 556, #55
+ 556, 556, 333, 333, 584, 584, 584, 611, #63
+ 975, 722, 722, 722, 722, 667, 611, 778, #71
+ 722, 278, 556, 722, 611, 833, 722, 778, #79
+ 667, 778, 722, 667, 611, 722, 667, 944, #87
+ 667, 667, 611, 333, 278, 333, 584, 556, #95
+ 333, 556, 611, 556, 611, 556, 333, 611, #103
+ 611, 278, 278, 556, 278, 889, 611, 611, #111
+ 611, 611, 389, 556, 333, 611, 556, 778, #119
+ 556, 556, 500, 389, 280, 389, 584, 350, # 127
+ 556, 350, 278, 556, 500, 1000, 556, 556, # 135
+ 333, 1000, 667, 333, 1000, 350, 611, 350, # 143
+ 350, 278, 278, 500, 500, 350, 556, 1000, # 151
+ 333, 1000, 556, 333, 944, 350, 500, 667, # 159
+ 278, 333, 556, 556, 556, 556, 280, 556,
+ 333, 737, 370, 556, 584, 333, 737, 333,
+ 400, 584, 333, 333, 333, 611, 556, 278,
+ 333, 333, 365, 556, 834, 834, 834, 611,
+ 722, 722, 722, 722, 722, 722, 1000, 722,
+ 667, 667, 667, 667, 278, 278, 278, 278,
+ 722, 722, 778, 778, 778, 778, 778, 584,
+ 778, 722, 722, 722, 722, 667, 667, 611,
+ 556, 556, 556, 556, 556, 556, 889, 556,
+ 556, 556, 556, 556, 278, 278, 278, 278,
+ 611, 611, 611, 611, 611, 611, 611, 584,
+ 611, 611, 611, 611, 611, 556, 611, 556]
+ );
+1;
+
+sub hyperLink
+{ my $x = shift;
+ my $y = shift;
+ my $text = shift || ' ';
+ my $URI = shift;
+ my $fontSize = shift;
+ my ($actualSize, $fontSizeBeforetheChange, $height, $x2, $y2);
+ if ((! defined $x) || (! defined $y) || (! defined $URI))
+ { return undef;
+ }
+ my ($internalName, $externalName, $oldInternalName, $oldExternalname) =
+ PDF::Reuse::prFont('HO');
+ if (! defined $fontSize)
+ { ($actualSize, $fontSizeBeforetheChange) = PDF::Reuse::prFontSize();
+ $fontSize = $fontSizeBeforetheChange;
+ PDF::Reuse::prFontSize($fontSize) if ($actualSize != $fontSizeBeforetheChange);
+ }
+ else
+ { ($actualSize, $fontSizeBeforetheChange) = PDF::Reuse::prFontSize($fontSize);
+ }
+ $height = $fontSize + 2.5;
+ my $width = PDF::Reuse::prStrWidth($text);
+ $y2 = $y - 2;
+ $x2 = $x + $width;
+ PDF::Reuse::prAdd("q\n 0.3 0.3 1 RG 0.3 0.3 1 rg\n$x $y2 m\n$x2 $y2 l\n B*\n");
+ $y2 -= 1;
+ PDF::Reuse::prText($x, $y, $text);
+ PDF::Reuse::prLink( { x => $x,
+ y => $y2,
+ width => $width,
+ height => $height,
+ URI => $URI } );
+
+ PDF::Reuse::prAdd("0 0 0 RG 0 0 0 rg\nQ\n");
+ PDF::Reuse::prFont($oldExternalname)
+ if ($oldExternalname ne $externalName);
+ PDF::Reuse::prFontSize($fontSizeBeforetheChange)
+ if ($fontSizeBeforetheChange != $fontSize);
+ return $x2;
+} \ No newline at end of file
diff --git a/Master/texmf-dist/scripts/xetex/perl/xdv2pdf_mergemarks b/Master/texmf-dist/scripts/xetex/perl/xdv2pdf_mergemarks
new file mode 100755
index 00000000000..ce36f1e8116
--- /dev/null
+++ b/Master/texmf-dist/scripts/xetex/perl/xdv2pdf_mergemarks
@@ -0,0 +1,205 @@
+#!/usr/bin/perl
+
+# /****************************************************************************\
+# Part of the XeTeX typesetting system
+# copyright (c) 1994-2005 by SIL International
+# written by Jonathan Kew
+#
+# This software is distributed under the terms of the Common Public License,
+# version 1.0.
+# For details, see <http://www.opensource.org/licenses/cpl1.0.php> or the file
+# cpl1.0.txt included with the software.
+# \****************************************************************************/
+
+BEGIN {
+ # try to locate our private Perl module directory
+ my $p = `kpsewhich -progname=xetex -format=texmfscripts Reuse.pm`;
+ chomp $p;
+ if ($p eq '') {
+ # try a known location
+ $p = '/usr/local/teTeX/share/texmf.local/scripts/xetex/perl/lib/PDF/Reuse.pm';
+ die "can't find Reuse.pm!" unless -e $p;
+ }
+ $p =~ s!/PDF/Reuse.pm!!;
+ die "perl/lib directory $p not found!" unless -d $p;
+ unshift @INC, $p;
+};
+
+use strict;
+use PDF::Reuse;
+
+die "usage: $0 <pdf-file> <mark-file>\n" unless $#ARGV == 1;
+
+my $infile = $ARGV[0];
+my $markfile = $ARGV[1];
+my $outfile = "$ARGV[0].tmp";
+
+my $newlink = undef;
+my $seenbox = 0;
+my %dest;
+my @links;
+my @bookmarks;
+
+sub toUtf16
+{
+ my $txt = shift;
+ $txt =~ s/\\([\\\(\)])/$1/g;
+ $txt = pack('n*', 0xfeff, unpack('U*', $txt));
+ $txt =~ s/\\/\\\\/g;
+ $txt =~ s/\(/\\(/g;
+ $txt =~ s/\)/\\)/g;
+ return $txt;
+}
+
+open FH, "<:utf8", "$markfile" or die "failed to read mark-file $markfile\n";
+while (<FH>) {
+ chomp;
+ my ($page, $xpos, $ypos, $txt) = split(/\t/, $_, 4);
+ if ($txt =~ /^\s*dest/o) {
+ $txt =~ /^\s*dest\s+\(([^\)]+)\)\s*(\[.+\])/o;
+ my $destname = $1;
+ $dest{$destname} = $2;
+ my $zp = $page - 1;
+ $dest{$destname} =~ s/\/View\s\[(.+)\]/$1/;
+ $dest{$destname} =~ s/\@thispage/$zp/;
+ $dest{$destname} =~ s/\@xpos/$xpos/;
+ $dest{$destname} =~ s/\@ypos/$ypos/;
+ }
+
+ elsif ($txt =~ /^\s*bann/o) {
+ if ($txt =~ m!<+\s*/Type\s*/Annot\s*/Subtype\s*/Link\s*.*/A\s*<+([^>]+)>>\s*>>!o) {
+ $newlink = { page => $page, x => $xpos, y => $ypos, action => $1 };
+ if ($txt =~ m!/Border\s*(\[[^]]+\])!o) {
+ $newlink->{border} = $1;
+ }
+ if ($txt =~ m!/C\s*(\[[^]]+\])!o) {
+ $newlink->{color} = $1;
+ }
+ }
+ $seenbox = 0;
+ }
+
+ elsif ($txt =~ /^\s*ABOX/o) {
+ if (defined $newlink) {
+ $txt =~ m/\[\s*(-?\d+(?:\.\d+)?)\s+(-?\d+(?:\.\d+)?)\s+(-?\d+(?:\.\d+)?)\s+(-?\d+(?:\.\d+)?)\s*\]/o;
+ my $boxlink = { page => $newlink->{page}, action => $newlink->{action} };
+ $boxlink->{border} = $newlink->{border} if exists $newlink->{border};
+ $boxlink->{color} = $newlink->{color} if exists $newlink->{color};
+ $boxlink->{x} = $1 < $3 ? $1 : $3;
+ $boxlink->{y} = $2 < $4 ? $2 : $4;
+ $boxlink->{width} = abs($1 - $3);
+ $boxlink->{height} = abs($2 - $4);
+ push @links, $boxlink;
+ $seenbox = 1;
+ }
+ }
+
+ elsif ($txt =~ /^\s*eann/o) {
+ if ((defined $newlink) && ($seenbox == 0)) {
+ $newlink->{width} = $xpos - $newlink->{x};
+ if ($newlink->{width} < 0) {
+ $newlink->{width} = -$newlink->{width};
+ $newlink->{x} = $xpos;
+ }
+ $newlink->{height} = $ypos - $newlink->{y};
+ if ($newlink->{height} < 0) {
+ $newlink->{height} = -$newlink->{height};
+ $newlink->{y} = $ypos;
+ }
+ push @links, $newlink;
+ undef $newlink;
+ }
+ }
+
+ elsif ($txt =~ /^\s*ann/o) {
+ $txt =~ m!width\s+(\d+(?:\.\d*)?)pt\s+height\s+(\d+(?:\.\d*)?)pt\s+.*/A\s*<+([^>]+)>>!o;
+ if (defined $1) {
+ $newlink = { page => $page, x => $xpos, y => $ypos, width => $1, height => $2, action => $3 };
+ if ($txt =~ m!/Border\s*(\[[^]]+\])!o) {
+ $newlink->{border} = $1;
+ }
+ if ($txt =~ m!/C\s*(\[[^]]+\])!o) {
+ $newlink->{color} = $1;
+ }
+ push @links, $newlink;
+ undef $newlink;
+ }
+ }
+
+ elsif ($txt =~ /^\s*outline/o) {
+ $txt =~ m!outline\s+(-?\d+)\s*<+\s*/Title\s*\(((?:[^\)]|\\\))+)\)\s*/A\s*<+([^>]+)>>\s*>>!o;
+ my ($level, $title, $action) = ($1, $2, $3);
+ my $bm = { 'text' => &toUtf16($title), 'pdfact' => $action, '_lvl' => $level };
+ if ((scalar @bookmarks == 0) || ($level <= $bookmarks[$#bookmarks]->{'_lvl'})) {
+ push @bookmarks, $bm;
+ }
+ else {
+ my $parent = $bookmarks[$#bookmarks];
+ my $plevel = $parent->{'_lvl'};
+ while ($plevel + 1 < $level) {
+ if (exists $parent->{'kids'}) {
+ $parent = $parent->{'kids'}[$#{$parent->{'kids'}}];
+ $plevel = $parent->{'_lvl'};
+ }
+ else {
+ last;
+ }
+ }
+ push @{$parent->{'kids'}}, $bm;
+ }
+ }
+
+}
+close FH;
+
+fixActions(\@bookmarks);
+
+prFile("$outfile");
+
+prBookmark(\@bookmarks);
+
+foreach (@links) {
+ my $action = $_->{action};
+ if ($action =~ m!/S\s/GoTo\s/D\s\(([^\)]+)\)!o) {
+ my $destname = $1;
+ my $explicit = $dest{$destname};
+ $action =~ s/\(.+\)/$explicit/;
+ $_->{action} = $action;
+ }
+ prLink($_);
+}
+
+prDoc($infile);
+
+prEnd();
+
+unlink($markfile);
+
+unlink($infile);
+rename($outfile, $infile);
+
+exit(0);
+
+sub fixActions
+{
+ my $bookmarks = shift;
+ foreach (@$bookmarks) {
+ $_->{'pdfact'} = fixAct($_->{'pdfact'});
+ if (exists $_->{'kids'}) {
+ fixActions($_->{'kids'});
+ }
+ }
+}
+
+sub fixAct
+{
+ my $action = shift;
+ if ($action =~ m!/S\s*/GoTo\s*/D\s*\(([^\)]+)\)!o) {
+ my $destname = $1;
+ if (exists $dest{$destname}) {
+ $action = "/Type /Action /S /GoTo /D $dest{$destname}";
+ }
+ }
+ return $action;
+}
+