summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/pax
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2022-06-08 03:00:49 +0000
committerNorbert Preining <norbert@preining.info>2022-06-08 03:00:49 +0000
commitb3aac3ae7b628835121d1f485fd49998308170e7 (patch)
tree79e4d65e7d316acfca2ec1adf00c35b8c6e69a4f /macros/latex/contrib/pax
parent76cfdb3c84a9a4d5d06a9f785b2bed2b44098806 (diff)
CTAN sync 202206080300
Diffstat (limited to 'macros/latex/contrib/pax')
-rw-r--r--macros/latex/contrib/pax/README6
-rwxr-xr-xmacros/latex/contrib/pax/scripts/pdfannotextractor.pl196
-rw-r--r--macros/latex/contrib/pax/source/Makefile10
-rw-r--r--macros/latex/contrib/pax/source/build.xml87
-rw-r--r--macros/latex/contrib/pax/source/license/LaTeX/lppl.txt416
-rw-r--r--macros/latex/contrib/pax/source/license/PDFAnnotExtractor/gpl.txt340
-rw-r--r--macros/latex/contrib/pax/source/src/Constants.java132
-rw-r--r--macros/latex/contrib/pax/source/src/Entry.java174
-rw-r--r--macros/latex/contrib/pax/source/src/EntryWriteException.java27
-rw-r--r--macros/latex/contrib/pax/source/src/MANIFEST.MF3
-rw-r--r--macros/latex/contrib/pax/source/src/PDFAnnotExtractor.java733
-rw-r--r--macros/latex/contrib/pax/source/src/StringVisitor.java131
-rw-r--r--macros/latex/contrib/pax/tex/pax.sty594
13 files changed, 2847 insertions, 2 deletions
diff --git a/macros/latex/contrib/pax/README b/macros/latex/contrib/pax/README
index 30ba2dba1e..2143f73fa9 100644
--- a/macros/latex/contrib/pax/README
+++ b/macros/latex/contrib/pax/README
@@ -1,5 +1,4 @@
-README for project pax (PDFAnnotExtractor), 2012/04/23 v0.1l
-
+README for project pax (PDFAnnotExtractor)
TABLE OF CONTENTS
=================
@@ -245,3 +244,6 @@ I. History
problems with incompatible `xkeyval'.
2012/04/18 v0.1l
* Option --version added to pdfannotextractor.pl.
+2022/06/07 v2022/06/07
+ * Port to recent pdfanotator
+ * New developper Bastien Roucariès <rouca !at! debian.org>
diff --git a/macros/latex/contrib/pax/scripts/pdfannotextractor.pl b/macros/latex/contrib/pax/scripts/pdfannotextractor.pl
new file mode 100755
index 0000000000..c5d5cf2a38
--- /dev/null
+++ b/macros/latex/contrib/pax/scripts/pdfannotextractor.pl
@@ -0,0 +1,196 @@
+#!/usr/bin/env perl
+use strict;
+$^W=1;
+
+# Copyright (C) 2008, 2011, 2012 Heiko Oberdiek
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301 USA
+#
+# This file is part of PDFAnnotExtractor. See README.
+
+my $name = 'PDFAnnotExtractor';
+my $program = "\L$name\E";
+my $file = "$program.pl";
+my $version = "0.1l";
+my $date = "2012/04/18";
+my $author = "Heiko Oberdiek";
+my $copyright = "Copyright (c) 2008, 2011, 2012 by $author.";
+
+# History:
+# 2008/10/01 v0.1i: First version of the wrapper script.
+# 2012/04/18 v0.1l: Option --version added.
+
+my $title = "$name $version, $date - $copyright\n";
+my $usage = <<"END_OF_USAGE";
+${title}Syntax: $program [options] <PDF files[.pdf]>
+Options:
+ --help print usage
+ --version print version number
+ --debug debug informations
+END_OF_USAGE
+
+my $help = 0;
+my $debug = 0;
+my $opt_version = 0;
+use Getopt::Long;
+GetOptions(
+ 'debug!' => \$debug,
+ 'help!' => \$help,
+ 'version!' => \$opt_version,
+) or die $usage;
+!$help or die $usage;
+if ($opt_version) {
+ print "$name $date v$version\n";
+ exit(0);
+}
+(@ARGV >= 1 or die $usage);
+
+print $title;
+
+my $error = '!!! Error:';
+my $pdfbox = 'PDFBox';
+my $prg_kpsewhich = 'kpsewhich';
+my $prg_java = 'java';
+my %prg;
+
+my $jar_pax = 'pax.jar';
+my $main_class = 'pax.PDFAnnotExtractor';
+my $jar_pdfbox = 'pdfbox.jar';
+my @jar_pdfbox = qw[
+ pdfbox.jar
+ PDFBox.jar
+ pdfbox-0.7.3.jar
+ PDFBox-0.7.3.jar
+ pdfbox-0.7.2.jar
+ PDFBox-0.7.2.jar
+];
+my @dir_jar = qw[
+ /usr/share/java
+ /usr/local/share/java
+];
+my $path_jar_pax = '';
+my $path_jar_pdfbox = '';
+my $classpath = defined $ENV{'CLASSPATH'} ? $ENV{'CLASSPATH'} : '';
+debug('CLASSPATH', $classpath);
+my $pdfbox_in_classpath = $classpath =~ /PDFBox/ ? 1 : 0;
+
+my $is_win = 0;
+$is_win = 1 if $^O =~ /^MSWin(32|64)/i
+ or $^O =~ /^dos/i
+ or $^O =~ /^os2/i;
+debug('is_win', $is_win);
+
+use File::Which;
+
+sub debug ($$) {
+ my $key = shift;
+ my $value = shift;
+ print "* $key: [$value]\n" if $debug;
+}
+
+sub check_prg ($$) {
+ my $prg = shift;
+ my $die = shift;
+ return 1 if $prg{$prg};
+ my $path = which($prg);
+ if ($path) {
+ $prg{$prg} = $path;
+ debug "Which $prg", $path;
+ return 1;
+ }
+ debug "Which $prg", '<not found>';
+ if ($die) {
+ die "$error Cannot find program `$prg'!\n";
+ }
+ return 0;
+}
+
+sub find_jar ($) {
+ my $jar_name = shift;
+
+ check_prg $prg_kpsewhich, 1;
+ my $cmd = "kpsewhich"
+ . " --progname $program"
+ . " --format texmfscripts"
+ . " $jar_name";
+ debug 'Backticks', $cmd;
+ my $path = `$cmd`;
+ if ($? == 0) {
+ chomp $path;
+ debug 'Exit code', '0/success';
+ debug $jar_name, $path;
+ return $path;
+ }
+ if ($? == -1) {
+ die "!!! Error: Cannot execute `$prg_kpsewhich' ($!)!\n";
+ }
+ if ($? & 127) {
+ die "!!! Error: `$prg_kpsewhich' died with signal " . ($? & 127)
+ . (($? & 128) ? ' with coredump' : '') . "!\n";
+ }
+ debug 'Exit code', ($? >> 8);
+ return '';
+}
+
+sub find_jar_pax () {
+ return if $path_jar_pax;
+ foreach my $dir (@dir_jar) {
+ my $path = "$dir/$jar_pax";
+ if (-f $path) {
+ $path_jar_pax = $path;
+ debug $jar_pax, $path_jar_pax;
+ return;
+ }
+ }
+ $path_jar_pax = find_jar $jar_pax;
+ if (!$path_jar_pax) {
+ die "$error Cannot find `$jar_pax'!\n";
+ }
+}
+
+
+sub launch_pax () {
+ check_prg $prg_java, 1;
+ my @cmd = ($prg_java);
+ push @cmd, '-cp';
+ push @cmd, $path_jar_pax;
+ push @cmd, 'pax.PDFAnnotExtractor';
+ push @cmd, @ARGV;
+ debug 'System', "@cmd";
+ system @cmd;
+ if ($? == 0) {
+ debug 'Result', 'ok';
+ return 0;
+ }
+ if ($? == -1) {
+ die "$error Cannot execute `$prg_java' ($!)!\n";
+ }
+ if ($? & 127) {
+ die "$error `$prg_java' died with signal " . ($? & 127)
+ . (($? & 128) ? ' with coredump' : '') . "!\n";
+ }
+ my $exit_code = $? >> 8;
+ debug 'Exit code', $exit_code;
+ return $exit_code;
+}
+
+# main program
+
+my $ret = 0;
+find_jar_pax;
+exit launch_pax;
+
+__END__
diff --git a/macros/latex/contrib/pax/source/Makefile b/macros/latex/contrib/pax/source/Makefile
new file mode 100644
index 0000000000..944ee43ded
--- /dev/null
+++ b/macros/latex/contrib/pax/source/Makefile
@@ -0,0 +1,10 @@
+distctan:
+ cd .. && mkdir pax
+ cd .. && rsync -rL `pwd`/* --exclude '.git/' --exclude 'build/' --exclude '*.zip' -L pax/
+ cd ../pax/source && ant distctan
+ rm -rf ../pax/source/build
+ rm -rf ../pax/pax
+ cd .. && zip -r pax-`date +"%Y%m%d"`.zip pax/
+
+clean:
+ cd .. && rm -rf pax
diff --git a/macros/latex/contrib/pax/source/build.xml b/macros/latex/contrib/pax/source/build.xml
new file mode 100644
index 0000000000..0a7eae3ddf
--- /dev/null
+++ b/macros/latex/contrib/pax/source/build.xml
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="us-ascii"?>
+<project name="pax" default="dist" basedir=".">
+ <description>
+ Build file for PDFAnnotExtractor
+ </description>
+
+ <property name="src" location="src"/>
+ <property name="build" location="build"/>
+ <property name="dist" location="../scripts/"/>
+ <property name="pdfbox.home" location="${basedir}"/> <!-- or somewhere else -->
+
+ <target name="init">
+ <mkdir dir="${build}"/>
+ </target>
+
+ <target name="compile"
+ depends="init"
+ description="compile the source"
+ >
+ <javac srcdir="${src}" destdir="${build}">
+ <classpath>
+ <pathelement location="${basedir}/lib/pdfbox.jar"/>
+ <pathelement location="${basedir}/lib/commons-logging.jar"/>
+ </classpath>
+ </javac>
+ </target>
+
+ <path id="build.classpath">
+ <fileset dir="${basedir}">
+ <include name="lib/*.jar"/>
+ </fileset>
+ </path>
+
+ <pathconvert property="manifest.classpath" pathsep=" ">
+ <path refid="build.classpath"/>
+ <mapper>
+ <chainedmapper>
+ <flattenmapper/>
+ <globmapper from="*.jar" to="lib/*.jar"/>
+ </chainedmapper>
+ </mapper>
+ </pathconvert>
+
+ <target name="distctan"
+ depends="compile"
+ description="generate the distribution ctan"
+ >
+ <mkdir dir="${dist}"/>
+ <jar jarfile="${dist}/${ant.project.name}.jar"
+ manifest="${src}/MANIFEST.MF"
+ basedir="${build}"
+ includes="pax/**" >
+ <zipgroupfileset dir="lib" includes="*.jar"/>
+ </jar>
+ </target>
+
+ <target name="dist"
+ depends="compile"
+ description="generate the distribution"
+ >
+ <mkdir dir="${dist}"/>
+ <mkdir dir="${dist}/lib"/>
+ <copy todir="${dist}/lib" flatten="true">
+ <fileset dir="lib">
+ <include name="*.jar" />
+ </fileset>
+ </copy>
+ <jar jarfile="${dist}/${ant.project.name}.jar"
+ manifest="${src}/MANIFEST.MF"
+ basedir="${build}"
+ includes="pax/**" >
+ <manifest>
+ <attribute name="Class-Path" value="${manifest.classpath}" />
+ </manifest>
+ </jar>
+ </target>
+
+
+ <target name="clean"
+ description="clean up"
+ >
+ <delete dir="${build}"/>
+ <delete dir="${dist}/lib"/>
+ <delete file="${dist}/pax.jar" />
+ </target>
+
+</project>
diff --git a/macros/latex/contrib/pax/source/license/LaTeX/lppl.txt b/macros/latex/contrib/pax/source/license/LaTeX/lppl.txt
new file mode 100644
index 0000000000..90e5e3ab79
--- /dev/null
+++ b/macros/latex/contrib/pax/source/license/LaTeX/lppl.txt
@@ -0,0 +1,416 @@
+The LaTeX Project Public License
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+
+LPPL Version 1.3c 2006-05-20
+
+Copyright 1999 2002-2006 LaTeX3 Project
+ Everyone is allowed to distribute verbatim copies of this
+ license document, but modification of it is not allowed.
+
+
+PREAMBLE
+========
+
+The LaTeX Project Public License (LPPL) is the primary license under
+which the the LaTeX kernel and the base LaTeX packages are distributed.
+
+You may use this license for any work of which you hold the copyright
+and which you wish to distribute. This license may be particularly
+suitable if your work is TeX-related (such as a LaTeX package), but
+it is written in such a way that you can use it even if your work is
+unrelated to TeX.
+
+The section `WHETHER AND HOW TO DISTRIBUTE WORKS UNDER THIS LICENSE',
+below, gives instructions, examples, and recommendations for authors
+who are considering distributing their works under this license.
+
+This license gives conditions under which a work may be distributed
+and modified, as well as conditions under which modified versions of
+that work may be distributed.
+
+We, the LaTeX3 Project, believe that the conditions below give you
+the freedom to make and distribute modified versions of your work
+that conform with whatever technical specifications you wish while
+maintaining the availability, integrity, and reliability of
+that work. If you do not see how to achieve your goal while
+meeting these conditions, then read the document `cfgguide.tex'
+and `modguide.tex' in the base LaTeX distribution for suggestions.
+
+
+DEFINITIONS
+===========
+
+In this license document the following terms are used:
+
+ `Work'
+ Any work being distributed under this License.
+
+ `Derived Work'
+ Any work that under any applicable law is derived from the Work.
+
+ `Modification'
+ Any procedure that produces a Derived Work under any applicable
+ law -- for example, the production of a file containing an
+ original file associated with the Work or a significant portion of
+ such a file, either verbatim or with modifications and/or
+ translated into another language.
+
+ `Modify'
+ To apply any procedure that produces a Derived Work under any
+ applicable law.
+
+ `Distribution'
+ Making copies of the Work available from one person to another, in
+ whole or in part. Distribution includes (but is not limited to)
+ making any electronic components of the Work accessible by
+ file transfer protocols such as FTP or HTTP or by shared file
+ systems such as Sun's Network File System (NFS).
+
+ `Compiled Work'
+ A version of the Work that has been processed into a form where it
+ is directly usable on a computer system. This processing may
+ include using installation facilities provided by the Work,
+ transformations of the Work, copying of components of the Work, or
+ other activities. Note that modification of any installation
+ facilities provided by the Work constitutes modification of the Work.
+
+ `Current Maintainer'
+ A person or persons nominated as such within the Work. If there is
+ no such explicit nomination then it is the `Copyright Holder' under
+ any applicable law.
+
+ `Base Interpreter'
+ A program or process that is normally needed for running or
+ interpreting a part or the whole of the Work.
+
+ A Base Interpreter may depend on external components but these
+ are not considered part of the Base Interpreter provided that each
+ external component clearly identifies itself whenever it is used
+ interactively. Unless explicitly specified when applying the
+ license to the Work, the only applicable Base Interpreter is a
+ `LaTeX-Format' or in the case of files belonging to the
+ `LaTeX-format' a program implementing the `TeX language'.
+
+
+
+CONDITIONS ON DISTRIBUTION AND MODIFICATION
+===========================================
+
+1. Activities other than distribution and/or modification of the Work
+are not covered by this license; they are outside its scope. In
+particular, the act of running the Work is not restricted and no
+requirements are made concerning any offers of support for the Work.
+
+2. You may distribute a complete, unmodified copy of the Work as you
+received it. Distribution of only part of the Work is considered
+modification of the Work, and no right to distribute such a Derived
+Work may be assumed under the terms of this clause.
+
+3. You may distribute a Compiled Work that has been generated from a
+complete, unmodified copy of the Work as distributed under Clause 2
+above, as long as that Compiled Work is distributed in such a way that
+the recipients may install the Compiled Work on their system exactly
+as it would have been installed if they generated a Compiled Work
+directly from the Work.
+
+4. If you are the Current Maintainer of the Work, you may, without
+restriction, modify the Work, thus creating a Derived Work. You may
+also distribute the Derived Work without restriction, including
+Compiled Works generated from the Derived Work. Derived Works
+distributed in this manner by the Current Maintainer are considered to
+be updated versions of the Work.
+
+5. If you are not the Current Maintainer of the Work, you may modify
+your copy of the Work, thus creating a Derived Work based on the Work,
+and compile this Derived Work, thus creating a Compiled Work based on
+the Derived Work.
+
+6. If you are not the Current Maintainer of the Work, you may
+distribute a Derived Work provided the following conditions are met
+for every component of the Work unless that component clearly states
+in the copyright notice that it is exempt from that condition. Only
+the Current Maintainer is allowed to add such statements of exemption
+to a component of the Work.
+
+ a. If a component of this Derived Work can be a direct replacement
+ for a component of the Work when that component is used with the
+ Base Interpreter, then, wherever this component of the Work
+ identifies itself to the user when used interactively with that
+ Base Interpreter, the replacement component of this Derived Work
+ clearly and unambiguously identifies itself as a modified version
+ of this component to the user when used interactively with that
+ Base Interpreter.
+
+ b. Every component of the Derived Work contains prominent notices
+ detailing the nature of the changes to that component, or a
+ prominent reference to another file that is distributed as part
+ of the Derived Work and that contains a complete and accurate log
+ of the changes.
+
+ c. No information in the Derived Work implies that any persons,
+ including (but not limited to) the authors of the original version
+ of the Work, provide any support, including (but not limited to)
+ the reporting and handling of errors, to recipients of the
+ Derived Work unless those persons have stated explicitly that
+ they do provide such support for the Derived Work.
+
+ d. You distribute at least one of the following with the Derived Work:
+
+ 1. A complete, unmodified copy of the Work;
+ if your distribution of a modified component is made by
+ offering access to copy the modified component from a
+ designated place, then offering equivalent access to copy
+ the Work from the same or some similar place meets this
+ condition, even though third parties are not compelled to
+ copy the Work along with the modified component;
+
+ 2. Information that is sufficient to obtain a complete,
+ unmodified copy of the Work.
+
+7. If you are not the Current Maintainer of the Work, you may
+distribute a Compiled Work generated from a Derived Work, as long as
+the Derived Work is distributed to all recipients of the Compiled
+Work, and as long as the conditions of Clause 6, above, are met with
+regard to the Derived Work.
+
+8. The conditions above are not intended to prohibit, and hence do not
+apply to, the modification, by any method, of any component so that it
+becomes identical to an updated version of that component of the Work as
+it is distributed by the Current Maintainer under Clause 4, above.
+
+9. Distribution of the Work or any Derived Work in an alternative
+format, where the Work or that Derived Work (in whole or in part) is
+then produced by applying some process to that format, does not relax or
+nullify any sections of this license as they pertain to the results of
+applying that process.
+
+10. a. A Derived Work may be distributed under a different license
+ provided that license itself honors the conditions listed in
+ Clause 6 above, in regard to the Work, though it does not have
+ to honor the rest of the conditions in this license.
+
+ b. If a Derived Work is distributed under a different license, that
+ Derived Work must provide sufficient documentation as part of
+ itself to allow each recipient of that Derived Work to honor the
+ restrictions in Clause 6 above, concerning changes from the Work.
+
+11. This license places no restrictions on works that are unrelated to
+the Work, nor does this license place any restrictions on aggregating
+such works with the Work by any means.
+
+12. Nothing in this license is intended to, or may be used to, prevent
+complete compliance by all parties with all applicable laws.
+
+
+NO WARRANTY
+===========
+
+There is no warranty for the Work. Except when otherwise stated in
+writing, the Copyright Holder provides the Work `as is', without
+warranty of any kind, either expressed or implied, including, but not
+limited to, the implied warranties of merchantability and fitness for a
+particular purpose. The entire risk as to the quality and performance
+of the Work is with you. Should the Work prove defective, you assume
+the cost of all necessary servicing, repair, or correction.
+
+In no event unless required by applicable law or agreed to in writing
+will The Copyright Holder, or any author named in the components of the
+Work, or any other party who may distribute and/or modify the Work as
+permitted above, be liable to you for damages, including any general,
+special, incidental or consequential damages arising out of any use of
+the Work or out of inability to use the Work (including, but not limited
+to, loss of data, data being rendered inaccurate, or losses sustained by
+anyone as a result of any failure of the Work to operate with any other
+programs), even if the Copyright Holder or said author or said other
+party has been advised of the possibility of such damages.
+
+
+MAINTENANCE OF THE WORK
+=======================
+
+The Work has the status `author-maintained' if the Copyright Holder
+explicitly and prominently states near the primary copyright notice in
+the Work that the Work can only be maintained by the Copyright Holder
+or simply that it is `author-maintained'.
+
+The Work has the status `maintained' if there is a Current Maintainer
+who has indicated in the Work that they are willing to receive error
+reports for the Work (for example, by supplying a valid e-mail
+address). It is not required for the Current Maintainer to acknowledge
+or act upon these error reports.
+
+The Work changes from status `maintained' to `unmaintained' if there
+is no Current Maintainer, or the person stated to be Current
+Maintainer of the work cannot be reached through the indicated means
+of communication for a period of six months, and there are no other
+significant signs of active maintenance.
+
+You can become the Current Maintainer of the Work by agreement with
+any existing Current Maintainer to take over this role.
+
+If the Work is unmaintained, you can become the Current Maintainer of
+the Work through the following steps:
+
+ 1. Make a reasonable attempt to trace the Current Maintainer (and
+ the Copyright Holder, if the two differ) through the means of
+ an Internet or similar search.
+
+ 2. If this search is successful, then enquire whether the Work
+ is still maintained.
+
+ a. If it is being maintained, then ask the Current Maintainer
+ to update their communication data within one month.
+
+ b. If the search is unsuccessful or no action to resume active
+ maintenance is taken by the Current Maintainer, then announce
+ within the pertinent community your intention to take over
+ maintenance. (If the Work is a LaTeX work, this could be
+ done, for example, by posting to comp.text.tex.)
+
+ 3a. If the Current Maintainer is reachable and agrees to pass
+ maintenance of the Work to you, then this takes effect
+ immediately upon announcement.
+
+ b. If the Current Maintainer is not reachable and the Copyright
+ Holder agrees that maintenance of the Work be passed to you,
+ then this takes effect immediately upon announcement.
+
+ 4. If you make an `intention announcement' as described in 2b. above
+ and after three months your intention is challenged neither by
+ the Current Maintainer nor by the Copyright Holder nor by other
+ people, then you may arrange for the Work to be changed so as
+ to name you as the (new) Current Maintainer.
+
+ 5. If the previously unreachable Current Maintainer becomes
+ reachable once more within three months of a change completed
+ under the terms of 3b) or 4), then that Current Maintainer must
+ become or remain the Current Maintainer upon request provided
+ they then update their communication data within one month.
+
+A change in the Current Maintainer does not, of itself, alter the fact
+that the Work is distributed under the LPPL license.
+
+If you become the Current Maintainer of the Work, you should
+immediately provide, within the Work, a prominent and unambiguous
+statement of your status as Current Maintainer. You should also
+announce your new status to the same pertinent community as
+in 2b) above.
+
+
+WHETHER AND HOW TO DISTRIBUTE WORKS UNDER THIS LICENSE
+======================================================
+
+This section contains important instructions, examples, and
+recommendations for authors who are considering distributing their
+works under this license. These authors are addressed as `you' in
+this section.
+
+Choosing This License or Another License
+----------------------------------------
+
+If for any part of your work you want or need to use *distribution*
+conditions that differ significantly from those in this license, then
+do not refer to this license anywhere in your work but, instead,
+distribute your work under a different license. You may use the text
+of this license as a model for your own license, but your license
+should not refer to the LPPL or otherwise give the impression that
+your work is distributed under the LPPL.
+
+The document `modguide.tex' in the base LaTeX distribution explains
+the motivation behind the conditions of this license. It explains,
+for example, why distributing LaTeX under the GNU General Public
+License (GPL) was considered inappropriate. Even if your work is
+unrelated to LaTeX, the discussion in `modguide.tex' may still be
+relevant, and authors intending to distribute their works under any
+license are encouraged to read it.
+
+A Recommendation on Modification Without Distribution
+-----------------------------------------------------
+
+It is wise never to modify a component of the Work, even for your own
+personal use, without also meeting the above conditions for
+distributing the modified component. While you might intend that such
+modifications will never be distributed, often this will happen by
+accident -- you may forget that you have modified that component; or
+it may not occur to you when allowing others to access the modified
+version that you are thus distributing it and violating the conditions
+of this license in ways that could have legal implications and, worse,
+cause problems for the community. It is therefore usually in your
+best interest to keep your copy of the Work identical with the public
+one. Many works provide ways to control the behavior of that work
+without altering any of its licensed components.
+
+How to Use This License
+-----------------------
+
+To use this license, place in each of the components of your work both
+an explicit copyright notice including your name and the year the work
+was authored and/or last substantially modified. Include also a
+statement that the distribution and/or modification of that
+component is constrained by the conditions in this license.
+
+Here is an example of such a notice and statement:
+
+ %% pig.dtx
+ %% Copyright 2005 M. Y. Name
+ %
+ % This work may be distributed and/or modified under the
+ % conditions of the LaTeX Project Public License, either version 1.3
+ % of this license or (at your option) any later version.
+ % The latest version of this license is in
+ % http://www.latex-project.org/lppl.txt
+ % and version 1.3 or later is part of all distributions of LaTeX
+ % version 2005/12/01 or later.
+ %
+ % This work has the LPPL maintenance status `maintained'.
+ %
+ % The Current Maintainer of this work is M. Y. Name.
+ %
+ % This work consists of the files pig.dtx and pig.ins
+ % and the derived file pig.sty.
+
+Given such a notice and statement in a file, the conditions
+given in this license document would apply, with the `Work' referring
+to the three files `pig.dtx', `pig.ins', and `pig.sty' (the last being
+generated from `pig.dtx' using `pig.ins'), the `Base Interpreter'
+referring to any `LaTeX-Format', and both `Copyright Holder' and
+`Current Maintainer' referring to the person `M. Y. Name'.
+
+If you do not want the Maintenance section of LPPL to apply to your
+Work, change `maintained' above into `author-maintained'.
+However, we recommend that you use `maintained', as the Maintenance
+section was added in order to ensure that your Work remains useful to
+the community even when you can no longer maintain and support it
+yourself.
+
+Derived Works That Are Not Replacements
+---------------------------------------
+
+Several clauses of the LPPL specify means to provide reliability and
+stability for the user community. They therefore concern themselves
+with the case that a Derived Work is intended to be used as a
+(compatible or incompatible) replacement of the original Work. If
+this is not the case (e.g., if a few lines of code are reused for a
+completely different task), then clauses 6b and 6d shall not apply.
+
+
+Important Recommendations
+-------------------------
+
+ Defining What Constitutes the Work
+
+ The LPPL requires that distributions of the Work contain all the
+ files of the Work. It is therefore important that you provide a
+ way for the licensee to determine which files constitute the Work.
+ This could, for example, be achieved by explicitly listing all the
+ files of the Work near the copyright notice of each file or by
+ using a line such as:
+
+ % This work consists of all files listed in manifest.txt.
+
+ in that place. In the absence of an unequivocal list it might be
+ impossible for the licensee to determine what is considered by you
+ to comprise the Work and, in such a case, the licensee would be
+ entitled to make reasonable conjectures as to which files comprise
+ the Work.
+
diff --git a/macros/latex/contrib/pax/source/license/PDFAnnotExtractor/gpl.txt b/macros/latex/contrib/pax/source/license/PDFAnnotExtractor/gpl.txt
new file mode 100644
index 0000000000..f90922eea3
--- /dev/null
+++ b/macros/latex/contrib/pax/source/license/PDFAnnotExtractor/gpl.txt
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/macros/latex/contrib/pax/source/src/Constants.java b/macros/latex/contrib/pax/source/src/Constants.java
new file mode 100644
index 0000000000..7fd8a6d0b6
--- /dev/null
+++ b/macros/latex/contrib/pax/source/src/Constants.java
@@ -0,0 +1,132 @@
+/* Constants.java
+Copyright (C) 2006-2008, 2011, 2012 Heiko Oberdiek
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+MA 02110-1301 USA
+
+This file is part of PDFAnnotExtractor. See README.
+*/
+package pax;
+
+public interface Constants {
+
+ public String PAX_VERSION = "0.1l";
+
+ public String ENTRY_BEG = "\\[";
+ public String ENTRY_END = "\\\\\n";
+ public String CMD_BEG = "{";
+ public String CMD_END = "}";
+ public String ARG_BEG = "{";
+ public String ARG_END = "}";
+ public String KVS_BEG = "{";
+ public String KVS_END = "\n}";
+ public String KVS_EMPTY = "{}";
+ public String KV_BEG = "\n ";
+ public String KV_END = ",";
+ public String KEY_BEG = "";
+ public String KEY_END = "";
+ public String VALUE_BEG = "={";
+ public String VALUE_END = "}";
+ public String HEX_STR_BEG = "\\<";
+ public String HEX_STR_END = "\\>";
+
+ public String CMD_ANNOT = "annot";
+ public String CMD_BASEURL = "baseurl";
+ public String CMD_DEST = "dest";
+ public String CMD_FILE = "file";
+ public String CMD_INFO = "info";
+ public String CMD_PAGENUM = "pagenum";
+ public String CMD_PAGE = "page";
+ public String CMD_PAX = "pax";
+
+ // cmd file
+ public String KEY_SIZE = "Size";
+ public String KEY_DATE = "Date";
+
+ // cmd info
+ public String KEY_AUTHOR = "Author";
+ public String KEY_CREATOR = "Creator";
+ public String KEY_KEYWORDS = "Keywords";
+ public String KEY_PRODUCER = "Producer";
+ public String KEY_SUBJECT = "Subject";
+ public String KEY_TITLE = "Title";
+
+ // cmd page
+ public String KEY_ROTATE = "Rotate";
+ public String KEY_MEDIA_BOX = "MediaBox";
+ public String KEY_CROP_BOX = "CropBox";
+ public String KEY_BLEED_BOX = "BleedBox";
+ public String KEY_TRIM_BOX = "TrimBox";
+ public String KEY_ART_BOX = "ArtBox";
+
+ // cmd annot attributes
+ public String KEY_C = "C";
+ public String KEY_BORDER = "Border";
+ public String KEY_BS = "BS";
+ public String KEY_H = "H";
+
+ // cmd annot/link/URI
+ public String KEY_URI = "URI";
+ public String KEY_IS_MAP = "IsMap";
+
+
+ // cmd annot/link/GoToR
+ public String KEY_FILE = "File";
+ public String KEY_DEST_NAME = "DestName";
+ public String KEY_DEST_PAGE = "DestPage";
+ public String KEY_DEST_VIEW = "DestView";
+
+ // cmd annot/link/GoTo
+ public String KEY_DEST_RECT = "Rect";
+ public String KEY_DEST_X = "DestX";
+ public String KEY_DEST_Y = "DestY";
+ public String KEY_DEST_ZOOM = "DestZoom";
+ public String KEY_DEST_LABEL = "DestLabel";
+
+ // cmd annot/link/Named
+ public String KEY_NAME = "Name";
+
+ // baseurl
+ public String PDF_URI = "URI";
+ public String PDF_BASE = "Base";
+
+ // annotations
+ public String PDF_ANNOT = "Annot";
+ public String PDF_RECT = "Rect";
+ public String PDF_LINK = "Link";
+ public String PDF_A = "A";
+ public String PDF_C = "C";
+ public String PDF_BORDER = "Border";
+ public String PDF_BS = "BS";
+ public String PDF_H = "H";
+ public String PDF_GOTO = "GoTo";
+ public String PDF_DEST = "Dest";
+
+ // destination views
+ public String PDF_XYZ = "XYZ";
+ public String PDF_FIT = "Fit";
+ public String PDF_FITH = "FitH";
+ public String PDF_FITV = "FitV";
+ public String PDF_FITR = "FitR";
+ public String PDF_FITB = "FitB";
+ public String PDF_FITBH = "FitBH";
+ public String PDF_FITBV = "FitBV";
+
+ public String PDF_NULL = "null";
+
+ public String PDF_S = "S";
+ public String PDF_NAMED = "Named";
+ public String PDF_N = "N";
+}
diff --git a/macros/latex/contrib/pax/source/src/Entry.java b/macros/latex/contrib/pax/source/src/Entry.java
new file mode 100644
index 0000000000..7140750d27
--- /dev/null
+++ b/macros/latex/contrib/pax/source/src/Entry.java
@@ -0,0 +1,174 @@
+/* Entry.java
+Copyright (C) 2006-2008, 2011, 2012 Heiko Oberdiek
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+MA 02110-1301 USA
+
+This file is part of PDFAnnotExtractor. See README.
+*/
+package pax;
+
+import java.io.*;
+import java.util.*;
+
+public class Entry implements Constants {
+
+ protected Writer out;
+
+ protected String cmd;
+ protected List args;
+ protected Map kvs;
+ protected boolean withKV;
+ protected List delayedList;
+
+ public Entry(Writer out) {
+ this.out = out;
+ cmd = null;
+ args = new Vector();
+ kvs = null;
+ withKV = false;
+ delayedList = new Vector();
+ }
+
+ public void clear() {
+ cmd = null;
+ args.clear();
+ kvs = null;
+ withKV = false;
+ }
+
+ public void setCmd(String cmd) {
+ clear();
+ this.cmd = cmd;
+ }
+
+ public String getCmd() {
+ return cmd;
+ }
+
+ public void withKV() {
+ this.withKV = true;
+ if (kvs == null) {
+ kvs = new HashMap();
+ }
+ }
+
+ public void addArg(String arg) {
+ args.add(arg);
+ }
+
+ public void putKV(String key, String value) {
+ withKV();
+ if (value == null) {
+ return;
+ }
+ kvs.put(key, value);
+ }
+
+ public boolean isEmptyKV() {
+ return !withKV || kvs.isEmpty();
+ }
+
+ public void writeDelayed() throws EntryWriteException {
+ Writer saved = out;
+ try {
+ out = new StringWriter();
+ write();
+ delayedList.add(out.toString());
+ }
+ catch (Exception e) { throw new EntryWriteException(e); }
+ finally {
+ out = saved;
+ }
+ }
+
+ public void write() throws EntryWriteException {
+ try {
+ out.write(ENTRY_BEG);
+
+ // write command
+ out.write(CMD_BEG);
+ out.write(cmd);
+ out.write(CMD_END);
+
+ // write arguments
+ Iterator it = args.iterator();
+ while (it.hasNext()) {
+ String arg = (String)it.next();
+ out.write(ARG_BEG);
+ out.write(arg);
+ out.write(ARG_END);
+ }
+
+ // write key value pairs
+ if (withKV) {
+ if (kvs.isEmpty()) {
+ out.write(KVS_EMPTY);
+ }
+ else {
+ out.write(KVS_BEG);
+ it = kvs.entrySet().iterator();
+ while (it.hasNext()) {
+ Map.Entry kv = (Map.Entry)it.next();
+ String key = (String)kv.getKey();
+ String value = (String)kv.getValue();
+ out.write(KV_BEG);
+ out.write(KEY_BEG);
+ out.write(key);
+ out.write(KEY_END);
+ if (value != null) {
+ out.write(VALUE_BEG);
+ out.write(value);
+ out.write(VALUE_END);
+ }
+ out.write(KV_END);
+ }
+ out.write(KVS_END);
+ }
+ }
+
+ out.write(ENTRY_END);
+ out.flush();
+ }
+ catch (IOException e) {
+ throw new EntryWriteException(e);
+ }
+ finally {
+ clear();
+ }
+ }
+
+ public void flushDelayed() throws EntryWriteException {
+ try {
+ Iterator it = delayedList.iterator();
+ while (it.hasNext()) {
+ out.write((String)it.next());
+ }
+ out.flush();
+ }
+ catch (IOException e) {
+ throw new EntryWriteException(e);
+ }
+ }
+
+ public void close() throws EntryWriteException {
+ try {
+ out.close();
+ }
+ catch (IOException e) {
+ throw new EntryWriteException(e);
+ }
+ }
+}
diff --git a/macros/latex/contrib/pax/source/src/EntryWriteException.java b/macros/latex/contrib/pax/source/src/EntryWriteException.java
new file mode 100644
index 0000000000..a1010ce121
--- /dev/null
+++ b/macros/latex/contrib/pax/source/src/EntryWriteException.java
@@ -0,0 +1,27 @@
+/* EntryWriteException.java
+Copyright (C) 2006-2008, 2011, 2012 Heiko Oberdiek
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+MA 02110-1301 USA
+
+This file is part of PDFAnnotExtractor. See README.
+*/
+package pax;
+
+public class EntryWriteException extends Exception {
+ public EntryWriteException(Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/macros/latex/contrib/pax/source/src/MANIFEST.MF b/macros/latex/contrib/pax/source/src/MANIFEST.MF
new file mode 100644
index 0000000000..2a141c6cfb
--- /dev/null
+++ b/macros/latex/contrib/pax/source/src/MANIFEST.MF
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+Created-By: Heiko Oberdiek
+Main-Class: pax.PDFAnnotExtractor
diff --git a/macros/latex/contrib/pax/source/src/PDFAnnotExtractor.java b/macros/latex/contrib/pax/source/src/PDFAnnotExtractor.java
new file mode 100644
index 0000000000..d135057467
--- /dev/null
+++ b/macros/latex/contrib/pax/source/src/PDFAnnotExtractor.java
@@ -0,0 +1,733 @@
+/* PDFAnnotExtractor.java
+Copyright (C) 2006-2008, 2011, 2012 Heiko Oberdiek
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+MA 02110-1301 USA
+
+This file is part of PDFAnnotExtractor. See README.
+*/
+package pax;
+
+import java.io.*;
+import java.text.*;
+import java.util.*;
+
+import org.apache.pdfbox.cos.*;
+import org.apache.pdfbox.pdfparser.*;
+import org.apache.pdfbox.pdmodel.*;
+import org.apache.pdfbox.pdmodel.common.*;
+import org.apache.pdfbox.pdmodel.interactive.action.*;
+import org.apache.pdfbox.pdmodel.interactive.action.type.*;
+import org.apache.pdfbox.pdmodel.interactive.annotation.*;
+import org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination.*;
+
+public class PDFAnnotExtractor implements Constants {
+
+ protected File inputFile;
+ protected File outputFile;
+ protected PDDocument doc;
+ protected PDDocumentCatalog catalog;
+ protected Entry entry;
+ protected int destCount;
+
+ protected static final String USAGE =
+ "Syntax: java PDFAnnotExtractor <pdffiles[.pdf]>";
+ protected static final String EXT_PDF = ".pdf";
+ protected static final String EXT_PAX = ".pax";
+
+ public static void main(String[] argv) {
+ if (argv.length < 1) {
+ System.err.println(USAGE);
+ System.exit(1);
+ }
+ for(int i = 0; i < argv.length; i++) {
+ processFile(argv[i]);
+ }
+ }
+
+ public static void processFile(String fileName) {
+ File file = new File(fileName);
+ if (file.isFile()) {
+ fileName = stripFromEnd(fileName, EXT_PDF);
+ }
+ else {
+ File testFile = new File(fileName + EXT_PDF);
+ if (testFile.isFile()) {
+ file = testFile;
+ }
+ else {
+ System.err.println(USAGE);
+ error("PDF file not found: " + fileName, null);
+ }
+ }
+ System.out.println("* Processing file `" + file.toString() + "' ...");
+ PDFAnnotExtractor p =
+ new PDFAnnotExtractor(file, new File(fileName + EXT_PAX));
+ p.parse();
+ p.close();
+ }
+
+ public PDFAnnotExtractor(File inputFile, File outputFile) {
+ this.inputFile = inputFile;
+ this.outputFile = outputFile;
+ destCount = 0;
+ try {
+ doc = PDDocument.load(inputFile);
+ catalog = doc.getDocumentCatalog();
+ }
+ catch (IOException e) {
+ error("Loading failed: " + inputFile, e);
+ }
+ try {
+ entry = new Entry(new BufferedWriter(new FileWriter(outputFile)));
+ }
+ catch (IOException e) {
+ error("Cannot open output: " + outputFile, e);
+ }
+ }
+
+ public void close() {
+ try {
+ doc.close();
+ }
+ catch (IOException e) {
+ error("Closing failed: " + inputFile, e);
+ }
+ try {
+ entry.close();
+ }
+ catch (EntryWriteException e) {
+ error("Closing failed: " + outputFile, e);
+ }
+ }
+
+ public void parse() {
+ cmd_pax();
+ cmd_file();
+ cmd_pagenum();
+ cmd_baseurl();
+ parse_pages();
+ }
+
+ public void cmd_pax() {
+ try {
+ // PAX version info
+ entry.setCmd(CMD_PAX);
+ entry.addArg(PAX_VERSION);
+ entry.write();
+ }
+ catch (Exception e) { handleCmdException(e); }
+ }
+
+ public void cmd_file() {
+ try {
+ entry.setCmd(CMD_FILE);
+ entry.addArg(formatString(inputFile.toString()));
+ long size = inputFile.length();
+ if (size > 0) {
+ entry.putKV(KEY_SIZE, "" + size);
+ }
+ long time = inputFile.lastModified();
+ if (time != 0) {
+ Date d = new Date(time);
+ DateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");
+ String date = "D:" + df.format(d);
+ df = new SimpleDateFormat("Z");
+ String zone = df.format(d);
+ if (zone.equals("+0000")) {
+ zone = "Z";
+ }
+ else {
+ // ISO format: SIGN DIGIT DIGIT DIGIT DIGIT
+ zone = zone.substring(0, 3)
+ + "'"
+ + zone.substring(3, 5)
+ + "'";
+ }
+ entry.putKV(KEY_DATE, date + zone);
+ }
+ entry.write();
+ }
+ catch (Exception e) { handleCmdException(e); }
+ }
+
+ public void cmd_pagenum() {
+ try {
+ // pagenum
+ int pagenum = doc.getNumberOfPages();
+ entry.setCmd(CMD_PAGENUM);
+ entry.addArg("" + pagenum);
+ entry.write();
+ }
+ catch (Exception e) { handleCmdException(e); }
+ }
+
+ public void cmd_info() {
+ try {
+ // info
+ entry.setCmd(CMD_INFO);
+ PDDocumentInformation info = doc.getDocumentInformation();
+ entry.putKV(KEY_AUTHOR, formatString(info.getAuthor()));
+ entry.putKV(KEY_CREATOR, formatString(info.getCreator()));
+ entry.putKV(KEY_KEYWORDS, formatString(info.getKeywords()));
+ entry.putKV(KEY_PRODUCER, formatString(info.getProducer()));
+ entry.putKV(KEY_SUBJECT, formatString(info.getSubject()));
+ entry.putKV(KEY_TITLE, formatString(info.getTitle()));
+ if (!entry.isEmptyKV()) {
+ entry.write();
+ }
+ }
+ catch (Exception e) { handleCmdException(e); }
+ }
+
+ public void cmd_baseurl() {
+ try {
+ // baseurl
+ entry.setCmd(CMD_BASEURL);
+ COSDictionary dict = catalog.getCOSDictionary();
+ dict = (COSDictionary)
+ dict.getItem(COSName.getPDFName(PDF_URI));
+ String baseurl = dict.getString(PDF_BASE);
+ if (baseurl.length() > 0) {
+ entry.addArg(formatString(baseurl));
+ entry.write();
+ }
+ }
+ catch (EntryWriteException e) { handleCmdException(e); }
+ catch (Exception e) {}
+ }
+
+ public void parse_pages() {
+ ListIterator iter = catalog.getAllPages().listIterator();
+ while (iter.hasNext()) {
+ // page
+ PDPage page = (PDPage)iter.next();
+ int num = iter.nextIndex();
+ parse_page(num, page);
+ }
+ try {
+ entry.flushDelayed();
+ }
+ catch (EntryWriteException e) {
+ System.err.println("Write error: " + outputFile);
+ System.err.println(e.getCause().toString());
+ }
+ }
+
+ public void parse_page(int num, PDPage page) {
+ cmd_page(num, page);
+ parse_annots(num, page);
+ }
+
+ public void cmd_page(int num, PDPage page) {
+ try {
+ entry.setCmd(CMD_PAGE);
+ entry.addArg("" + num);
+ entry.withKV();
+
+ // rotate entry
+ int rot = page.findRotation();
+ if (rot != 0) {
+ entry.putKV(KEY_ROTATE, "" + rot);
+ }
+
+ // box entries
+ PDRectangle mediaBox = page.findMediaBox();
+ PDRectangle cropBox = page.findCropBox();
+ PDRectangle bleedBox = page.getBleedBox();
+ PDRectangle trimBox = page.getTrimBox();
+ PDRectangle artBox = page.getArtBox();
+ entry.addArg(formatBox(mediaBox));
+ if (!equals(cropBox, mediaBox)) {
+ entry.putKV(KEY_CROP_BOX, formatBox(cropBox));
+ }
+ if (!equals(bleedBox, cropBox)) {
+ entry.putKV(KEY_BLEED_BOX, formatBox(bleedBox));
+ }
+ if (!equals(trimBox, cropBox)) {
+ entry.putKV(KEY_TRIM_BOX, formatBox(trimBox));
+ }
+ if (!equals(artBox, cropBox)) {
+ entry.putKV(KEY_ART_BOX, formatBox(artBox));
+ }
+ entry.write();
+ }
+ catch (Exception e) { handleCmdException(e); }
+ }
+
+ public void parse_annots(int num, PDPage page) {
+ // get annotations
+ COSArray annots = null;
+ try {
+ COSDictionary page_dict = page.getCOSDictionary();
+ annots = (COSArray)page_dict.getDictionaryObject(COSName.ANNOTS);
+ }
+ catch (Exception e) {}
+ if (annots == null) {
+ return;
+ }
+
+ for (int i = 0; i < annots.size(); i++) {
+ try {
+ COSDictionary annot = (COSDictionary)annots.getObject(i);
+ cmd_annot(num, annot);
+ }
+ catch (Exception e) {}
+ }
+ }
+
+ public void cmd_annot(int num, COSDictionary annot) {
+ try {
+ entry.setCmd(CMD_ANNOT);
+ entry.addArg("" + num);
+
+ // Type
+ String type = annot.getNameAsString(COSName.TYPE, PDF_ANNOT);
+ if (!type.equals(PDF_ANNOT)) {
+ throw new Exception("Wrong annotation type: " + type);
+ }
+ // Subtype
+ String subtype = annot.getNameAsString(COSName.SUBTYPE);
+ if (subtype == null) {
+ throw new Exception("Missing annotation subtype.");
+ }
+ if (!subtype.equals(PDF_LINK)) {
+ throw new Exception("Unsupported annotation subtype: "
+ + subtype);
+ }
+ entry.addArg(subtype);
+ entry.withKV();
+ // Rect
+ COSArray array = (COSArray)
+ annot.getDictionaryObject(PDF_RECT);
+ PDRectangle rect = new PDRectangle(array);
+ entry.addArg(formatBox(rect));
+ // A
+ COSDictionary a = (COSDictionary)
+ annot.getDictionaryObject(PDF_A);
+ if (a == null) {
+ COSBase cos = annot.getDictionaryObject(PDF_DEST);
+ if (cos == null) {
+ throw new Exception("Unsupported link annotation "
+ + "without action.");
+ }
+ entry.addArg(PDF_GOTO);
+ destCount++;
+ entry.putKV(KEY_DEST_LABEL, "" + destCount);
+ annot_attrs(annot);
+ entry.write();
+ add_dest(PDDestination.create(cos));
+ entry.writeDelayed();
+ return;
+ }
+ PDAction action = PDActionFactory.createAction(a);
+ if (action == null) {
+ // try named action, unsupported by PDFBox
+ if (a.getNameAsString(PDF_S).equals(PDF_NAMED)) {
+ entry.addArg(PDF_NAMED);
+ String name = a.getNameAsString(PDF_N);
+ if (name != null) {
+ entry.putKV(KEY_NAME, name);
+ annot_attrs(annot);
+ entry.write();
+ return;
+ }
+ }
+ throw new Exception("Unsupported link annotation.");
+ }
+ String actionSubtype = action.getSubType();
+ entry.addArg(actionSubtype);
+ if (action instanceof PDActionURI) {
+ PDActionURI uri = (PDActionURI)action;
+ entry.putKV(KEY_URI, formatString(uri.getURI()));
+ if (uri.shouldTrackMousePosition()) {
+ entry.putKV(KEY_IS_MAP, null);
+ }
+ }
+ else if (action instanceof PDActionGoTo) {
+ destCount++;
+ entry.putKV(KEY_DEST_LABEL, "" + destCount);
+ annot_attrs(annot);
+ entry.write();
+ add_dest(((PDActionGoTo)action).getDestination());
+ entry.writeDelayed();
+ return;
+ }
+ else if (action instanceof PDActionRemoteGoTo) {
+ PDActionRemoteGoTo gotor = (PDActionRemoteGoTo)action;
+ String file = gotor.getFile().getFile();
+ if (file == null || file.length() == 0) {
+ throw new Exception("GoToR: missing file");
+ }
+ entry.putKV(KEY_FILE, formatString(gotor.getFile().getFile()));
+
+ /*
+ PDDestination d = PDDestination.create(gotor.getD());
+ String view = "/";
+ if (d instanceof PDNamedDestination) {
+ entry.putKV(KEY_DEST_NAME,
+ ((PDNamedDestination)d)
+ .getNamedDestination());
+ }
+ else {
+ if (d instanceof PDPageFitDestination) {
+ PDPageFitDestination p =
+ (PDPageFitDestination)d;
+ view += (p.fitBoundingBox()) ? PDF_FITB : PDF_FIT;
+ }
+ else if (d instanceof PDPageFitHeightDestination) {
+ PDPageFitHeightDestination p =
+ (PDPageFitHeightDestination)d;
+ view += (p.fitBoundingBox()) ? PDF_FITBV : PDF_FITV;
+ view += " ";
+ view += (p.getLeft() == -1) ? PDF_NULL : "" + p.getLeft();
+ }
+ else if (d instanceof PDPageFitWidthDestination) {
+ PDPageFitWidthDestination p =
+ (PDPageFitWidthDestination)d;
+ view += (p.fitBoundingBox()) ? PDF_FITBH : PDF_FITH;
+ view += " ";
+ view += (p.getTop() == -1) ? PDF_NULL : "" + p.getTop();
+ }
+ else if (d instanceof PDPageXYZDestination) {
+ PDPageXYZDestination p =
+ (PDPageXYZDestination)d;
+ view += PDF_XYZ;
+ view += " ";
+ view += (p.getLeft() == -1) ? PDF_NULL : "" + p.getLeft();
+ view += " ";
+ view += (p.getTop() == -1) ? PDF_NULL : "" + p.getTop();
+ view += " ";
+ view += (p.getZoom() == -1) ? PDF_NULL : "" + p.getZoom();
+ }
+ else if (d instanceof PDPageFitRectangleDestination) {
+ PDPageFitRectangleDestination p =
+ (PDPageFitRectangleDestination)d;
+ view += PDF_FITR;
+ view += " " + p.getLeft() + " " + p.getBottom();
+ view += " " + p.getRight() + " " + p.getTop();
+ }
+ else {
+ throw new Exception("Unknown destination type");
+ }
+ entry.putKV(KEY_DEST_VIEW, view);
+ }
+ */
+
+ COSBase d = gotor.getD();
+ if (d instanceof COSString) {
+ entry.putKV(KEY_DEST_NAME,
+ formatString(((COSString)d).getString()));
+ }
+ else if (d instanceof COSName) {
+ entry.putKV(KEY_DEST_NAME,
+ formatString(((COSName)d).getName()));
+ }
+ else if (d instanceof COSArray) {
+ COSArray dest = (COSArray)d;
+ int page_num = dest.getInt(0);
+ entry.putKV(KEY_DEST_PAGE, "" + page_num);
+ String view = dest.getName(1);
+ int size = dest.size();
+ if (view.equals(PDF_FIT) || view.equals(PDF_FITB)) {
+ }
+ else if (view.equals(PDF_FITH) || view.equals(PDF_FITBH)
+ || view.equals(PDF_FITV) || view.equals(PDF_FITBV)) {
+ if (size >= 3) {
+ try {
+ String args = formatNumber(
+ ((COSNumber)dest.getObject(2)).floatValue());
+ view += " " + args;
+ }
+ catch (Exception e) {
+ size = 0;
+ }
+ }
+ if (size < 3) {
+ if (view.equals(PDF_FITH) || view.equals(PDF_FITV)) {
+ view = PDF_FIT;
+ }
+ else {
+ view = PDF_FITB;
+ }
+ }
+ }
+ else if (view.equals(PDF_XYZ)) {
+ COSBase obj;
+ view += " ";
+ if (size >= 3) {
+ obj = dest.getObject(2);
+ if (obj instanceof COSNumber) {
+ view += formatNumber(((COSNumber)obj).floatValue());
+ }
+ else {
+ view += PDF_NULL;
+ }
+ }
+ else {
+ view += PDF_NULL;
+ }
+ view += " ";
+ if (size >= 4) {
+ obj = dest.getObject(3);
+ if (obj instanceof COSNumber) {
+ view += formatNumber(((COSNumber)obj).floatValue());
+ }
+ else {
+ view += PDF_NULL;
+ }
+ }
+ else {
+ view += PDF_NULL;
+ }
+ view += " ";
+ if (size >= 5) {
+ obj = dest.getObject(4);
+ if (obj instanceof COSNumber) {
+ view += formatNumber(((COSNumber)obj).floatValue());
+ }
+ else {
+ view += PDF_NULL;
+ }
+ }
+ else {
+ view += PDF_NULL;
+ }
+ }
+ else if (view.equals(PDF_FITR)) {
+ view += " "
+ + formatNumber(((COSNumber)dest.getObject(2)).floatValue())
+ + " "
+ + formatNumber(((COSNumber)dest.getObject(3)).floatValue())
+ + " "
+ + formatNumber(((COSNumber)dest.getObject(4)).floatValue())
+ + " "
+ + formatNumber(((COSNumber)dest.getObject(5)).floatValue());
+ }
+ else {
+ throw new Exception("Unknown destination view type");
+ }
+ entry.putKV(KEY_DEST_VIEW, "/" + view);
+ }
+ else {
+ throw new Exception("GoToR: unknown dest type");
+ }
+ }
+ else {
+ throw new Exception("Unsupported link annotation type: "
+ + actionSubtype);
+ }
+ annot_attrs(annot);
+ entry.write();
+ }
+ catch (EntryWriteException e) { handleCmdException(e); }
+ catch (Exception e) {
+ System.err.println("!!! Warning: Annotation on page " + num
+ + " not recognized!");
+ System.err.println(" " + e.toString());
+ String msg = e.getMessage();
+ Throwable cause = e.getCause();
+ if (cause != null) {
+ System.err.println(" " + cause.toString());
+ }
+ if (e instanceof ClassCastException) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ private void add_dest(PDDestination dest) throws Exception {
+ entry.setCmd(CMD_DEST);
+ entry.withKV();
+ if (dest instanceof PDNamedDestination) {
+ String name = ((PDNamedDestination)dest).getNamedDestination();
+ Object obj = catalog.getNames().getDests().getValue(name);
+ if (obj instanceof PDDestination) {
+ dest = (PDDestination)obj;
+ }
+ }
+ if (dest instanceof PDPageDestination) {
+ PDPageDestination pd = (PDPageDestination)dest;
+ PDPage page = pd.getPage();
+ int pagenum = catalog.getAllPages().indexOf(page);
+ if (pagenum < 0) {
+ throw new Exception("Link to unknown page");
+ }
+ entry.addArg("" + (pagenum + 1));
+ entry.addArg("" + destCount);
+ if (pd instanceof PDPageFitDestination) {
+ PDPageFitDestination d = (PDPageFitDestination)pd;
+ entry.addArg(d.fitBoundingBox() ? PDF_FITB : PDF_FIT);
+ return;
+ }
+ if (pd instanceof PDPageFitHeightDestination) {
+ PDPageFitHeightDestination d = (PDPageFitHeightDestination)pd;
+ entry.addArg(d.fitBoundingBox() ? PDF_FITBV : PDF_FITV);
+ COSArray a = d.getCOSArray();
+ if (a.size() > 2) {
+ COSNumber n = (COSNumber)a.getObject(2);
+ if (n != null) {
+ entry.putKV(KEY_DEST_X, formatNumber(n));
+ }
+ }
+ return;
+ }
+ if (pd instanceof PDPageFitWidthDestination) {
+ PDPageFitWidthDestination d = (PDPageFitWidthDestination)pd;
+ entry.addArg(d.fitBoundingBox() ? PDF_FITBH : PDF_FITH);
+ COSArray a = d.getCOSArray();
+ if (a.size() > 2) {
+ COSNumber n = (COSNumber)a.getObject(2);
+ if (n != null) {
+ entry.putKV(KEY_DEST_Y, formatNumber(n));
+ }
+ }
+ return;
+ }
+ if (pd instanceof PDPageFitRectangleDestination) {
+ PDPageFitRectangleDestination d = (PDPageFitRectangleDestination)pd;
+ entry.addArg(PDF_FITR);
+ COSArray a = d.getCOSArray();
+ int size = a.size();
+ if (size != 6) {
+ throw new Exception("Rectangle destination without"
+ + " correct number of parameters");
+ }
+ entry.putKV(KEY_DEST_RECT,
+ formatNumber((COSNumber)a.getObject(2)) + " "
+ + formatNumber((COSNumber)a.getObject(3)) + " "
+ + formatNumber((COSNumber)a.getObject(4)) + " "
+ + formatNumber((COSNumber)a.getObject(5)));
+ return;
+ }
+ if (pd instanceof PDPageXYZDestination) {
+ PDPageXYZDestination d = (PDPageXYZDestination)pd;
+ entry.addArg(PDF_XYZ);
+ COSArray a = d.getCOSArray();
+ int size = a.size();
+ COSNumber n;
+ if (size > 2) {
+ n = (COSNumber)a.getObject(2);
+ if (n != null) {
+ entry.putKV(KEY_DEST_X, formatNumber(n));
+ }
+ }
+ if (size > 3) {
+ n = (COSNumber)a.getObject(3);
+ if (n != null) {
+ entry.putKV(KEY_DEST_Y, formatNumber(n));
+ }
+ }
+ if (size > 4) {
+ n = (COSNumber)a.getObject(4);
+ if (n != null) {
+ entry.putKV(KEY_DEST_ZOOM, formatNumber(n));
+ }
+ }
+ return;
+ }
+ }
+ throw new Exception("Unknown destination type");
+ }
+
+ protected void annot_attrs(COSDictionary annot) {
+ put_attr(annot, PDF_C, KEY_C);
+ put_attr(annot, PDF_BORDER, KEY_BORDER);
+ put_attr(annot, PDF_BS, KEY_BS);
+ put_attr(annot, PDF_H, KEY_H);
+ }
+
+ protected void put_attr(COSDictionary annot,
+ String pdfKey, String entryKey) {
+ try {
+ COSBase value = annot.getDictionaryObject(pdfKey);
+ if (value == null) {
+ return;
+ }
+ String str = value.accept(new StringVisitor()).toString();
+ if (str == null || str.length() == 0) {
+ return;
+ }
+ entry.putKV(entryKey, str);
+ }
+ catch (Exception e) {}
+ }
+
+ protected boolean equals(PDRectangle a, PDRectangle b) {
+ return a.getLowerLeftX() == b.getLowerLeftX()
+ && a.getLowerLeftY() == b.getLowerLeftY()
+ && a.getUpperRightX() == b.getUpperRightX()
+ && a.getUpperRightY() == b.getUpperRightY();
+ }
+
+ protected String formatBox(PDRectangle r) {
+ return formatNumber(r.getLowerLeftX()) + ' '
+ + formatNumber(r.getLowerLeftY()) + ' '
+ + formatNumber(r.getUpperRightX()) + ' '
+ + formatNumber(r.getUpperRightY());
+ }
+
+ protected String formatString(String s) {
+ if (s == null || s.length() == 0) {
+ return s;
+ }
+ return HEX_STR_BEG
+ + (new COSString(s)).getHexString()
+ + HEX_STR_END;
+ }
+
+ protected String formatNumber(float f) {
+ String s = "" + f;
+ return stripFromEnd(s, ".0");
+ }
+ protected String formatNumber(COSNumber obj) {
+ return formatNumber(obj.floatValue());
+ }
+
+ protected static String stripFromEnd(String str, String ext) {
+ if (str.endsWith(ext)) {
+ return str.substring(0, str.length() - ext.length());
+ }
+ return str;
+ }
+
+ protected static void error(String msg, Exception e, boolean stackTrace) {
+ System.err.println("!!! Error: " + msg);
+ if (e != null) {
+ if (stackTrace) {
+ e.printStackTrace();
+ }
+ else {
+ System.err.println(e.toString());
+ }
+ }
+ System.exit(1);
+ }
+ protected static void error(String msg, Exception e) {
+ error(msg, e, false);
+ }
+
+ protected void handleCmdException(Exception e) {
+ System.err.println("!!! Error during write of entry `"
+ + entry.getCmd() + "'!\n");
+ if (e instanceof EntryWriteException) {
+ System.err.println("Write error: " + outputFile);
+ System.err.println(((EntryWriteException)e).getCause().toString());
+ }
+ else {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/macros/latex/contrib/pax/source/src/StringVisitor.java b/macros/latex/contrib/pax/source/src/StringVisitor.java
new file mode 100644
index 0000000000..1460ade25c
--- /dev/null
+++ b/macros/latex/contrib/pax/source/src/StringVisitor.java
@@ -0,0 +1,131 @@
+/* StringVisitor.java
+Copyright (C) 2006-2008, 2011, 2012 Heiko Oberdiek
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+MA 02110-1301 USA
+
+This file is part of PDFAnnotExtractor. See README.
+*/
+package pax;
+
+import java.io.*;
+import java.util.*;
+import org.apache.pdfbox.cos.*;
+import org.apache.pdfbox.exceptions.*;
+
+public class StringVisitor implements ICOSVisitor {
+
+ protected StringBuffer buf;
+ boolean nodelim;
+
+ public StringVisitor() {
+ buf = new StringBuffer();
+ nodelim = false;
+ }
+
+ public Object visitFromNull(COSNull obj) {
+ if (nodelim) {
+ buf.append(' ');
+ }
+ buf.append("null");
+ nodelim = true;
+ return buf;
+ }
+
+ public Object visitFromBoolean(COSBoolean obj) {
+ if (nodelim) {
+ buf.append(' ');
+ }
+ buf.append(obj.getValue());
+ nodelim = true;
+ return buf;
+ }
+
+ public Object visitFromInt(COSInteger obj) {
+ if (nodelim) {
+ buf.append(' ');
+ }
+ buf.append(obj.intValue());
+ nodelim = true;
+ return buf;
+ }
+
+ public Object visitFromFloat(COSFloat obj) {
+ if (nodelim) {
+ buf.append(' ');
+ }
+ String s = "" + obj.floatValue();
+ if (s.endsWith(".0")) {
+ buf.append(s.substring(0, s.length() - ".0".length()));
+ }
+ else {
+ buf.append(s);
+ }
+ nodelim = true;
+ return buf;
+ }
+
+ public Object visitFromName(COSName obj) {
+ ByteArrayOutputStream a = new ByteArrayOutputStream();
+ try {
+ obj.writePDF(a);
+ }
+ catch (IOException e) {}
+ buf.append(a.toString());
+ nodelim = true;
+ return buf;
+ }
+
+ public Object visitFromString(COSString obj) {
+ buf.append("\\<");
+ buf.append(obj.getHexString());
+ buf.append("\\>");
+ nodelim = false;
+ return buf;
+ }
+
+ public Object visitFromArray(COSArray obj) throws COSVisitorException {
+ buf.append('[');
+ nodelim = false;
+ for (int i = 0; i < obj.size(); i++) {
+ obj.getObject(i).accept(this);
+ }
+ buf.append(']');
+ nodelim = false;
+ return buf;
+ }
+
+ public Object visitFromDictionary(COSDictionary obj) throws COSVisitorException {
+ buf.append("<<");
+ nodelim = false;
+ Iterator iter = obj.keyList().iterator();
+ while (iter.hasNext()) {
+ COSName key = (COSName)iter.next();
+ COSBase value = obj.getDictionaryObject(key);
+ key.accept(this);
+ value.accept(this);
+ }
+ buf.append(">>");
+ nodelim = false;
+ return buf;
+ }
+
+ public Object visitFromStream(COSStream obj) throws COSVisitorException {
+ throw new COSVisitorException(new Exception("Unsupported stream object"));
+ }
+ public Object visitFromDocument(COSDocument obj) throws COSVisitorException {
+ throw new COSVisitorException(new Exception("Unsupported documetn object"));
+ }
+}
diff --git a/macros/latex/contrib/pax/tex/pax.sty b/macros/latex/contrib/pax/tex/pax.sty
new file mode 100644
index 0000000000..1ea11b7fdd
--- /dev/null
+++ b/macros/latex/contrib/pax/tex/pax.sty
@@ -0,0 +1,594 @@
+%% pax.sty
+%% Copyright 2006-2008, 2011, 2012 Heiko Oberdiek
+%% Copyright 2020 Bastien Roucariès
+%
+% This work may be distributed and/or modified under the
+% conditions of the LaTeX Project Public License, either version 1.3
+% of this license or (at your option) any later version.
+% The latest version of this license is in
+% http://www.latex-project.org/lppl.txt
+% and version 1.3 or later is part of all distributions of LaTeX
+% version 2005/12/01 or later.
+%
+% This work has the LPPL maintenance status `maintained'.
+%
+% The Current Maintainer of this work is Bastien Roucariès
+%
+% This work consists of the file pax.sty.
+% See README for more details and documentation.
+%
+\NeedsTeXFormat{LaTeX2e}
+\ProvidesPackage{pax}%
+ [2020/04/06 v0.2 Annotation support for PDF graphics (HO)]%
+
+\RequirePackage{ifpdf}
+\ifpdf
+\else
+ \PackageError{pax}{Missing pdfTeX in PDF mode}{%
+ Other drivers are not supported.%
+ }%
+ \expandafter\endinput
+\fi
+
+\begingroup\expandafter\expandafter\expandafter\endgroup
+\expandafter\ifx\csname pdfstrcmp\endcsname\relax
+ \PackageError{pax}{pdfTeX is too old}{%
+ The package uses features of pdfTeX 1.30.%
+ }%
+ \expandafter\endinput
+\fi
+
+\RequirePackage{graphicx}
+\RequirePackage{ltxcmds}[2011/04/18]
+\RequirePackage{kvsetkeys}[2011/04/07]
+\RequirePackage{kvoptions}[2010/12/23]
+\RequirePackage{auxhook}[2011/03/04]
+\RequirePackage{etexcmds}[2011/02/16]
+
+% Hook into \includegraphics of graphicx with one optional
+% star, one optional argument with key value pairs and
+% the graphics name
+\let\PAX@ORG@includegraphics\includegraphics
+\def\includegraphics{%
+ \@ifstar{%
+ \@ifnextchar[{%
+ \begingroup
+ \def\x{\endgroup
+ \PAX@includegraphics[clip,%
+ }%
+ \expandafter\x\@gobble
+ }{%
+ \PAX@includegraphics[clip]%
+ }%
+ }{%
+ \@ifnextchar[{%
+ \PAX@includegraphics
+ }{%
+ \PAX@includegraphics[]%
+ }%
+ }%
+}
+\def\PAX@includegraphics[#1]#2{%
+ \begingroup
+ \sbox0{\PAX@ORG@includegraphics[{#1}]{#2}}%
+ \edef\PAX@inc@width{\the\wd0}%
+ \edef\PAX@inc@height{\the\dimexpr\dp0+\ht0}%
+ \leavevmode
+ \hbox to \wd0{%
+ \rlap{\copy0}%
+ \raise-\dp0\hbox{%
+ \PAX@AddAnnots{#1}{#2}%
+ }%
+ \hfill
+ }%
+ \endgroup
+}
+
+\SetupKeyvalOptions{family=PAX@Gin,prefix=PAX@Gin@}
+\DeclareStringOption[1]{page}
+\DeclareStringOption[0]{angle}
+\DeclareBoolOption{clip}
+\define@key{PAX@Gin}{viewport}{%
+ \ltx@LocalAppendToMacro\PAX@Gin@box@opts{%
+ \PAX@viewport#1\\%
+ }%
+}
+\define@key{PAX@Gin}{trim}{%
+ \ltx@LocalAppendToMacro\PAX@Gin@box@opts{%
+ \PAX@trim#1\\%
+ }%
+}
+\let\PAX@Gin@box@opts\@empty
+
+\def\PAX@viewport#1 #2 #3 #4\\{%
+ \PAX@defaultbp\PAX@vllx{#1}%
+ \PAX@defaultbp\PAX@vlly{#2}%
+ \PAX@defaultbp\PAX@vurx{#3}%
+ \PAX@defaultbp\PAX@vury{#4}%
+ \edef\PAX@page@llx{\dimexpr\PAX@page@llx+\PAX@vllx\relax}%
+ \edef\PAX@page@lly{\dimexpr\PAX@page@lly+\PAX@vlly\relax}%
+ \edef\PAX@page@urx{\dimexpr\PAX@page@llx+\PAX@vurx\relax}%
+ \edef\PAX@page@ury{\dimexpr\PAX@page@lly+\PAX@vury\relax}%
+}
+\def\PAX@trim#1 #2 #3 #4\\{%
+ \PAX@defaultbp\PAX@tllx{#1}%
+ \PAX@defaultbp\PAX@tlly{#2}%
+ \PAX@defaultbp\PAX@turx{#3}%
+ \PAX@defaultbp\PAX@tury{#4}%
+ \edef\PAX@page@llx{\dimexpr\PAX@page@llx+\PAX@tllx\relax}%
+ \edef\PAX@page@lly{\dimexpr\PAX@page@lly+\PAX@tlly\relax}%
+ \edef\PAX@page@urx{\dimexpr\PAX@page@urx-\PAX@turx\relax}%
+ \edef\PAX@page@ury{\dimexpr\PAX@page@ury-\PAX@tury\relax}%
+}
+
+\def\PAX@defaultbp#1#2{%
+ \afterassignment\PAX@def@bp\dimen@#2bp\relax{#1}{#2}%
+}
+\def\PAX@def@bp#1\relax#2#3{%
+ \if!#1!%
+ \edef#2{#3bp}%
+ \else
+ \edef#2{#3}%
+ \fi
+}
+
+% ignore unknown options in family `PAX@Gin'
+\kv@set@family@handler{PAX@Gin}{}
+
+\def\PAX@AddAnnots#1#2{%
+ \kvsetkeys{PAX@Gin}{#1}%
+ \Grot@setangle{\PAX@Gin@angle}%
+ % a little careful, is type of angle int or real?
+ \loop
+ \ifdim\PAX@Gin@angle\p@<360\p@
+ \else
+ \edef\PAX@Gin@angle{\the\numexpr-360+\number\PAX@Gin@angle}%
+ \repeat
+ \loop
+ \ifdim\PAX@Gin@angle\p@<\z@
+ \edef\PAX@Gin@angle{\strip@pt\dimexpr\PAX@Gin@angle\p@+360\p@}%
+ \repeat
+ \ifcase0\ifnum\PAX@Gin@angle=0 1\fi
+ \ifnum\PAX@Gin@angle=90 1\fi
+ \ifnum\PAX@Gin@angle=180 1\fi
+ \ifnum\PAX@Gin@angle=270 1\fi
+ \PackageWarning{pax}{Unsupported value for option angle}%
+ \fi
+ \filename@parse{#2}%
+ \def\PAX@file{\filename@area\filename@base.pax}%
+ \let\[\PAX@parser
+ \def\<{<}%
+ \def\>{>}%
+ \endlinechar=-1 %
+ \InputIfFileExists\PAX@file{%
+ }{%
+ \typeout{* Missing: \PAX@file}%
+ }%
+}
+\def\PAX@parser#1{\PAX@call{cmd}{#1}{}}%
+\def\PAX@call#1#2#3{%
+ \@ifundefined{PAX@#1@#2}\PAX@skip{#3\csname PAX@#1@#2\endcsname}%
+}
+\def\PAX@skip#1\\{}
+\def\PAX@stop#1\\{}
+
+\def\PAX@cmd@page#1#2{%
+ \PAX@filter@page{#1}{%
+ \PAX@getrect{page}#2\@nil
+ \PAX@Gin@box@opts
+ \ifcase0\ifnum\PAX@Gin@angle=90 1\fi
+ \ifnum\PAX@Gin@angle=270 1\fi
+ \else
+ \let\PAX@temp\PAX@inc@width
+ \let\PAX@inc@width\PAX@inc@height
+ \let\PAX@inc@height\PAX@temp
+ \fi
+ \Gscale@div\PAX@scale@x\PAX@inc@width{%
+ \dimexpr\PAX@page@urx-\PAX@page@llx\relax
+ }%
+ \Gscale@div\PAX@scale@y\PAX@inc@height{%
+ \dimexpr\PAX@page@ury-\PAX@page@lly\relax
+ }%
+ \PAX@skip
+ }%
+}
+\def\PAX@filter@page#1{%
+ \ifnum\PAX@Gin@page=#1 %
+ \expandafter\@firstofone
+ \else
+ \ifnum\PAX@Gin@page<#1 %
+ \csname fi\endcsname
+ \csname fi\endcsname
+ \expandafter\PAX@stop\@gobblefour
+ \fi
+ \expandafter\PAX@skip
+ \fi
+}
+\def\PAX@getrect#1#2 #3 #4 #5\@nil{%
+ \@namedef{PAX@#1@llx}{#2bp}%
+ \@namedef{PAX@#1@lly}{#3bp}%
+ \@namedef{PAX@#1@urx}{#4bp}%
+ \@namedef{PAX@#1@ury}{#5bp}%
+}
+
+\def\PAX@cmd@annot#1#2{%
+ \PAX@filter@page{#1}{%
+ \PAX@call{annot}{#2}{}%
+ }%
+}
+\def\PAX@annot@Link#1#2#3{%
+ \def\PAX@link@type{#2}%
+ \PAX@call{link}{#2}{%
+ \begingroup
+ \PAX@getrect{annot}#1\@nil
+ \kvsetkeys{PAX}{#3}%
+ }%
+ \PAX@skip
+}
+\newif\ifPAX@ok
+\PAX@oktrue
+
+\newif\ifPAX@GoTo
+
+\def\PAX@pdf@annot#1{%
+ \ifPAX@Gin@clip
+ \ifdim\PAX@annot@llx<\PAX@page@llx
+ \let\PAX@annot@llx\PAX@pagellx
+ \fi
+ \ifdim\PAX@annot@lly<\PAX@page@lly
+ \let\PAX@annot@lly\PAX@page@lly
+ \fi
+ \ifdim\PAX@annot@urx>\PAX@page@urx
+ \let\PAX@annot@urx\PAX@page@urx
+ \fi
+ \ifdim\PAX@annot@ury>\PAX@page@ury
+ \let\PAX@annot@ury\PAX@page@ury
+ \fi
+ \PAX@okfalse
+ \ifdim\PAX@annot@llx<\PAX@annot@urx
+ \ifdim\PAX@annot@lly<\PAX@annot@ury
+ \PAX@oktrue
+ \fi
+ \fi
+ \else
+ \PAX@oktrue
+ \fi
+ \ifPAX@ok
+ \ifcase 0\ifnum\PAX@Gin@angle=90 1\fi
+ \ifnum\PAX@Gin@angle=180 2\fi
+ \ifnum\PAX@Gin@angle=270 3\fi\space
+ % angle = 0
+ \def\PAX@raise{%
+ \PAX@scale@y\dimexpr\PAX@annot@lly-\PAX@page@lly\relax
+ }%
+ \def\PAX@right{%
+ \PAX@scale@x\dimexpr\PAX@annot@llx-\PAX@page@llx\relax
+ }%
+ \or % angle = 90
+ \def\PAX@raise{%
+ \PAX@scale@x\dimexpr\PAX@annot@llx-\PAX@page@llx\relax
+ }%
+ \def\PAX@right{%
+ \PAX@scale@y\dimexpr\PAX@page@ury-\PAX@annot@ury\relax
+ }%
+ \or % angle = 180
+ \def\PAX@raise{%
+ \PAX@scale@y\dimexpr\PAX@page@ury-\PAX@annot@ury\relax
+ }%
+ \def\PAX@right{%
+ \PAX@scale@x\dimexpr\PAX@page@urx-\PAX@annot@urx\relax
+ }%
+ \or % angle = 270
+ \def\PAX@raise{%
+ \PAX@scale@x\dimexpr\PAX@page@urx-\PAX@annot@urx\relax
+ }%
+ \def\PAX@right{%
+ \PAX@scale@y\dimexpr\PAX@annot@lly-\PAX@page@lly\relax
+ }%
+ \fi
+ \@namedef{%
+ PAX@%
+ \ifcase0\ifnum\PAX@Gin@angle=90 1\fi
+ \ifnum\PAX@Gin@angle=270 1\fi\space
+ width%
+ \else
+ height%
+ \fi
+ }{%
+ \PAX@scale@x\dimexpr\PAX@annot@urx-\PAX@annot@llx\relax
+ }%
+ \@namedef{%
+ PAX@%
+ \ifcase0\ifnum\PAX@Gin@angle=90 1\fi
+ \ifnum\PAX@Gin@angle=270 1\fi\space
+ height%
+ \else
+ width%
+ \fi
+ }{%
+ \PAX@scale@y\dimexpr\PAX@annot@ury-\PAX@annot@lly\relax
+ }%
+ \raise\PAX@raise\hb@xt@\z@{%
+ \kern\PAX@right
+ \ifPAX@GoTo
+ \pdfstartlink\@width\PAX@width\@height\PAX@height\@depth\z@
+ attr{\PAX@set@attrs}%
+ goto name{PAX@\PAX@file @\PAX@key@DestLabel}\relax
+ \pdfendlink
+ \else
+ \pdfannot\@width\PAX@width\@height\PAX@height{%
+ /Subtype/Link%
+ \PAX@set@attrs
+ /A<<%
+ /Type/Action%
+ /S/\PAX@link@type
+ #1%
+ >>%
+ }%
+ \fi
+ \hss
+ }%
+ \fi
+ \endgroup
+}
+
+\def\PAX@set@attrs{%
+ \PAX@attrs\PAX@link@type{%
+ \PAX@set@attr{C}\PAX@key@C
+ \PAX@set@attr{Border}\PAX@key@Border
+ \PAX@set@attr{BS}\PAX@key@BS
+ \PAX@set@attr{H}\PAX@key@H
+ }%
+}
+
+\def\PAX@set@attr#1#2{%
+ \ifx#2\@empty
+ \else
+ /#1 #2%
+ \fi
+}
+
+\def\PAX@attrs#1{%
+ \@ifundefined{PAX@attrs@#1}{%
+ \@ifundefined{hyperref}{%
+ \@firstofone
+ }{%
+ \Hy@setpdfborder
+ /H\@pdfhighlight
+ \@ifundefined{PAX@htype@#1}\@firstofone{%
+ \@ifundefined{@\@nameuse{PAX@htype@#1}bordercolor}\@firstofone{%
+ /C[\@nameuse{@\@nameuse{PAX@htype@#1}bordercolor}]%
+ \@gobble
+ }%
+ }{%
+ \PAX@set@attr{C}\PAX@key@C
+ }%
+ \@gobble
+ }%
+ }{%
+ \@nameuse{PAX@attrs@#1}%
+ }%
+}
+\def\PAX@htype@GoToR{file}
+\def\PAX@htype@GoTo{link}
+\def\PAX@htype@Named{link}
+\def\PAX@htype@URI{url}
+
+\def\PAX@link@URI{%
+ \PAX@pdf@annot{%
+ /URI\PAX@key@URI
+ }%
+}
+\def\PAX@link@Named{%
+ \PAX@pdf@annot{%
+ /N/\pdfescapename{\PAX@key@Name}%
+ }%
+}
+\def\PAX@link@GoToR{%
+ \PAX@pdf@annot{%
+ /F\PAX@key@File
+ /D%
+ \ifx\PAX@key@DestName\@empty
+ [\PAX@key@DestPage\space\PAX@key@DestView]%
+ \else
+ \PAX@key@DestName
+ \fi
+ }%
+}
+
+% GoTo
+
+\AddLineBeginAux{%
+ \string\providecommand{\string\PAX@DestReq}[2]{}%
+}
+\AddLineBeginAux{%
+ \string\providecommand{\string\PAX@DestProv}[2]{}%
+}
+\AtBeginDocument{%
+ \let\PAX@DestReq\@gobbletwo
+ \let\PAX@DestProv\@gobbletwo
+}
+\def\PAX@DestReq#1#2{%
+ \expandafter\gdef\csname PAX@REQ@#1@#2\endcsname{}%
+}
+\def\PAX@DestProv#1#2{%
+ \expandafter\gdef\csname PAX@PROV@#1@#2\endcsname{}%
+}
+
+\def\PAX@link@GoTo{%
+ \ifnum0<0\PAX@key@DestLabel\relax
+ \expandafter\@firstofone
+ \else
+ \endgroup
+ \expandafter\@gobble
+ \fi
+ {%
+ \if@filesw
+ \protected@write\@auxout{}{%
+ \string\PAX@DestReq{\PAX@file}{\PAX@key@DestLabel}%
+ }%
+ \fi
+ % Generate link, if destination exists
+ \@ifundefined{PAX@PROV@\PAX@file @\PAX@key@DestLabel}{%
+ \endgroup
+ }{%
+ \PAX@GoTotrue
+ \PAX@pdf@annot{}%
+ }%
+ }%
+}
+
+% Read destinations
+\def\PAX@cmd@dest#1#2#3#4{%
+ \PAX@filter@page{#1}{%
+ \if@filesw
+ \protected@write\@auxout{}{%
+ \string\PAX@DestProv{\PAX@file}{#2}%
+ }%
+ \fi
+ \@ifundefined{PAX@REQ@\PAX@file @#2}{%
+ }{%
+ \begingroup
+ \let\PAX@key@DestY\PAX@page@ury
+ \let\PAX@key@DestX\PAX@page@llx
+ \kvsetkeys{PAX}{#4}%
+ \let\PAX@dest@llx\PAX@key@DestX
+ \let\PAX@dest@urx\PAX@key@DestX
+ \let\PAX@dest@lly\PAX@key@DestY
+ \let\PAX@dest@ury\PAX@key@DestY
+ \ifx\PAX@key@DestRect\@empty
+ \else
+ \def\PAX@temp{dest}%
+ \expandafter\PAX@getrect\expandafter\PAX@temp
+ \PAX@key@DestRect\@nil
+ \fi
+ \ifPAX@Gin@clip
+ \ifx\PAX@dest@llx<\PAX@page@llx
+ \let\PAX@dest@llx\PAX@page@llx
+ \fi
+ \ifx\PAX@dest@lly<\PAX@page@lly
+ \let\PAX@dest@lly\PAX@page@lly
+ \fi
+ \ifx\PAX@dest@urx>\PAX@page@urx
+ \let\PAX@dest@urx\PAX@page@urx
+ \fi
+ \ifx\PAX@dest@ury>\PAX@page@ury
+ \let\PAX@dest@ury\PAX@page@ury
+ \fi
+ % at least prevent destinations outside the window
+ \ifx\PAX@dest@llx>\PAX@page@urx
+ \PAX@dest@llx\PAX@page@urx
+ \fi
+ \ifx\PAX@dest@lly>\PAX@page@ury
+ \PAX@dest@lly\PAX@page@ury
+ \fi
+ \ifx\PAX@dest@urx<\PAX@page@llx
+ \PAX@dest@urx\PAX@page@llx
+ \fi
+ \ifx\PAX@dest@ury<\PAX@page@lly
+ \PAX@dest@ury\PAX@page@lly
+ \fi
+ \fi
+ % I don't know, what is the best idea for rotated stuff,
+ % perhaps using the corner llx/ury
+ \ifcase 0\ifnum\PAX@Gin@angle=90 1\fi
+ \ifnum\PAX@Gin@angle=180 2\fi
+ \ifnum\PAX@Gin@angle=270 3\fi\space
+ % angle = 0
+ \def\PAX@raise{%
+ \PAX@scale@y\dimexpr\PAX@dest@lly-\PAX@page@lly\relax
+ }%
+ \def\PAX@right{%
+ \PAX@scale@x\dimexpr\PAX@dest@llx-\PAX@page@llx\relax
+ }%
+ \or % angle = 90
+ \def\PAX@raise{%
+ \PAX@scale@x\dimexpr\PAX@dest@llx-\PAX@page@llx\relax
+ }%
+ \def\PAX@right{%
+ \PAX@scale@y\dimexpr\PAX@page@ury-\PAX@dest@ury\relax
+ }%
+ \or % angle = 180
+ \def\PAX@raise{%
+ \PAX@scale@y\dimexpr\PAX@page@ury-\PAX@dest@ury\relax
+ }%
+ \def\PAX@right{%
+ \PAX@scale@x\dimexpr\PAX@page@urx-\PAX@dest@urx\relax
+ }%
+ \or % angle = 270
+ \def\PAX@raise{%
+ \PAX@scale@x\dimexpr\PAX@page@urx-\PAX@dest@urx\relax
+ }%
+ \def\PAX@right{%
+ \PAX@scale@y\dimexpr\PAX@dest@lly-\PAX@page@lly\relax
+ }%
+ \fi
+ \edef\PAX@name{name{PAX@\PAX@file @#2}}%
+ \let\PAX@type\@empty
+ \ifcase\pdfstrcmp{#3}{FITR}\relax
+ \def\PAX@type{xyz}% too lazy for now
+ \fi
+ \ifcase\pdfstrcmp{#3}{XYZ}\relax
+ \def\PAX@type{xyz}%
+ \ifx\PAX@key@DestZoom\@empty
+ \else
+ \edef\PAX@type{%
+ \PAX@type
+ zoom\numexpr1000*\number\dimexpr\PAX@key@DestZoom pt\relax
+ /\number\p@\relax
+ }%
+ \fi
+ \fi
+ \ifcase\pdfstrcmp{#3}{FIT}\relax
+ \def\PAX@type{fit}%
+ \fi
+ \ifcase\pdfstrcmp{#3}{FITB}\relax
+ \def\PAX@type{fitb}%
+ \fi
+ \ifcase\pdfstrcmp{#3}{FITH}\relax
+ \def\PAX@type{fith}%
+ \fi
+ \ifcase\pdfstrcmp{#3}{FITBH}\relax
+ \def\PAX@type{fitbh}%
+ \fi
+ \ifcase\pdfstrcmp{#3}{FITV}\relax
+ \def\PAX@type{fitv}%
+ \fi
+ \ifcase\pdfstrcmp{#3}{FITBV}\relax
+ \def\PAX@type{fitbv}%
+ \fi
+ \ifx\PAX@type\@empty
+ \def\PAX@type{xyz}%
+ \fi
+ \raise\PAX@raise\hb@xt@\z@{%
+ \kern\PAX@right
+ \pdfdest\PAX@name\PAX@type\relax
+ \hss
+ }%
+ \endgroup
+ }%
+ \PAX@skip
+ }%
+}
+
+\SetupKeyvalOptions{family=PAX,prefix=PAX@key@}
+\DeclareStringOption{URI}
+\DeclareStringOption{Name}
+\DeclareStringOption{DestName}
+\DeclareStringOption{DestPage}
+\DeclareStringOption{DestView}
+\DeclareStringOption{File}
+\DeclareStringOption{C}
+\DeclareStringOption{Border}
+\DeclareStringOption{BS}
+\DeclareStringOption{H}
+\DeclareStringOption{DestLabel}
+\DeclareStringOption{DestRect}
+\DeclareStringOption{DestZoom}
+\define@key{PAX}{DestX}{%
+ \PAX@defaultbp\PAX@key@DestX{#1}%
+}
+\define@key{PAX}{DestY}{%
+ \PAX@defaultbp\PAX@key@DestY{#1}%
+}
+\endinput