/* * Copyright (c) 2013 Allogy Interactive. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package com.sun.pdfview; import java.io.IOException; /** * Represents a destination in a PDF file. Destinations take 3 forms: * <ul> * <li> An explicit destination, which contains a reference to a page * as well as some stuff about how to fit it into the window. * <li> A named destination, which uses the PDF file's Dests entry * in the document catalog to map a name to an explicit destination * <li> A string destintation, which uses the PDF file's Dests entry. * in the name directory to map a string to an explicit destination. * </ul> * * All three of these cases are handled by the getDestination() method. */ public class PDFDestination { /** The known types of destination */ public static final int XYZ = 0; public static final int FIT = 1; public static final int FITH = 2; public static final int FITV = 3; public static final int FITR = 4; public static final int FITB = 5; public static final int FITBH = 6; public static final int FITBV = 7; /** the type of this destination (from the list above) */ private int type; /** the page we refer to */ private PDFObject pageObj; /** the left coordinate of the fit area, if applicable */ private float left; /** the right coordinate of the fit area, if applicable */ private float right; /** the top coordinate of the fit area, if applicable */ private float top; /** the bottom coordinate of the fit area, if applicable */ private float bottom; /** the zoom, if applicable */ private float zoom; /** * Creates a new instance of PDFDestination * * @param pageObj the page object this destination refers to * @param type the type of page this object refers to */ protected PDFDestination(PDFObject pageObj, int type) { this.pageObj = pageObj; this.type = type; } /** * Get a destination from either an array (explicit destination), a * name (named destination) or a string (name tree destination). * * @param obj the PDFObject representing this destination * @param root the root of the PDF object tree */ public static PDFDestination getDestination(PDFObject obj, PDFObject root) throws IOException { // resolve string and name issues if (obj.getType() == PDFObject.NAME) { obj = getDestFromName(obj, root); } else if (obj.getType() == PDFObject.STRING) { obj = getDestFromString(obj, root); } // make sure we have the right kind of object if (obj == null || obj.getType() != PDFObject.ARRAY) { throw new PDFParseException("Can't create destination from: " + obj); } // the array is in the form [page type args ... ] PDFObject[] destArray = obj.getArray(); // create the destination based on the type PDFDestination dest = null; String type = destArray[1].getStringValue(); if (type.equals("XYZ")) { dest = new PDFDestination(destArray[0], XYZ); } else if (type.equals("Fit")) { dest = new PDFDestination(destArray[0], FIT); } else if (type.equals("FitH")) { dest = new PDFDestination(destArray[0], FITH); } else if (type.equals("FitV")) { dest = new PDFDestination(destArray[0], FITV); } else if (type.equals("FitR")) { dest = new PDFDestination(destArray[0], FITR); } else if (type.equals("FitB")) { dest = new PDFDestination(destArray[0], FITB); } else if (type.equals("FitBH")) { dest = new PDFDestination(destArray[0], FITBH); } else if (type.equals("FitBV")) { dest = new PDFDestination(destArray[0], FITBV); } else { throw new PDFParseException("Unknown destination type: " + type); } // now fill in the arguments based on the type switch (dest.getType()) { case XYZ: dest.setLeft(destArray[2].getFloatValue()); dest.setTop(destArray[3].getFloatValue()); dest.setZoom(destArray[4].getFloatValue()); break; case FITH: dest.setTop(destArray[2].getFloatValue()); break; case FITV: dest.setLeft(destArray[2].getFloatValue()); break; case FITR: dest.setLeft(destArray[2].getFloatValue()); dest.setBottom(destArray[3].getFloatValue()); dest.setRight(destArray[4].getFloatValue()); dest.setTop(destArray[5].getFloatValue()); break; case FITBH: dest.setTop(destArray[2].getFloatValue()); break; case FITBV: dest.setLeft(destArray[2].getFloatValue()); break; } return dest; } /** * Get the type of this destination */ public int getType() { return type; } /** * Get the PDF Page object associated with this destination */ public PDFObject getPage() { return pageObj; } /** * Get the left coordinate value */ public float getLeft() { return left; } /** * Set the left coordinate value */ public void setLeft(float left) { this.left = left; } /** * Get the right coordinate value */ public float getRight() { return right; } /** * Set the right coordinate value */ public void setRight(float right) { this.right = right; } /** * Get the top coordinate value */ public float getTop() { return top; } /** * Set the top coordinate value */ public void setTop(float top) { this.top = top; } /** * Get the bottom coordinate value */ public float getBottom() { return bottom; } /** * Set the bottom coordinate value */ public void setBottom(float bottom) { this.bottom = bottom; } /** * Get the zoom value */ public float getZoom() { return zoom; } /** * Set the zoom value */ public void setZoom(float zoom) { this.zoom = zoom; } /** * Get a destination, given a name. This means the destination is in * the root node's dests dictionary. */ private static PDFObject getDestFromName(PDFObject name, PDFObject root) throws IOException { // find the dests object in the root node PDFObject dests = root.getDictRef("Dests"); if (dests != null) { // find this name in the dests dictionary return dests.getDictRef(name.getStringValue()); } // not found return null; } /** * Get a destination, given a string. This means the destination is in * the root node's names dictionary. */ private static PDFObject getDestFromString(PDFObject str, PDFObject root) throws IOException { // find the names object in the root node PDFObject names = root.getDictRef("Names"); if (names != null) { // find the dests entry in the names dictionary PDFObject dests = names.getDictRef("Dests"); if (dests != null) { // create a name tree object NameTree tree = new NameTree(dests); // find the value we're looking for PDFObject obj = tree.find(str.getStringValue()); // if we get back a dictionary, look for the /D value if (obj != null && obj.getType() == PDFObject.DICTIONARY) { obj = obj.getDictRef("D"); } // found it return obj; } } // not found return null; } }