summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/pax/source/src
diff options
context:
space:
mode:
Diffstat (limited to 'macros/latex/contrib/pax/source/src')
-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
6 files changed, 1200 insertions, 0 deletions
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"));
+ }
+}