package com.sun.pdfview.annotation;
import java.awt.geom.Rectangle2D;
import java.awt.geom.Rectangle2D.Float;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.List;
import com.sun.pdfview.PDFCmd;
import com.sun.pdfview.PDFObject;
import com.sun.pdfview.PDFParseException;
/*****************************************************************************
* Encapsulate a PDF annotation. This is only the super-class of PDF annotations,
* which has an "unknown" annotation type.
* Use the createAnnotation() method for getting an annotation of the correct
* type (if implemented).
*
* @author Katja Sondermann
* @since 03.07.2009
****************************************************************************/
public class PDFAnnotation{
public enum ANNOTATION_TYPE{
UNKNOWN("-", 0, PDFAnnotation.class),
LINK("Link", 1, LinkAnnotation.class),
WIDGET("Widget", 2, WidgetAnnotation.class),
STAMP("Stamp", 3, StampAnnotation.class),
FREETEXT("FreeText", 5, FreetextAnnotation.class),
// TODO 28.03.2012: add more annotation types
;
private String definition;
private int internalId;
private Class<?> className;
private ANNOTATION_TYPE(String definition, int typeId, Class<?> className) {
this.definition = definition;
this.internalId = typeId;
this.className = className;
}
/**
* @return the definition
*/
public String getDefinition() {
return definition;
}
/**
* @return the internalId
*/
public int getInternalId() {
return internalId;
}
/**
* @return the className
*/
public Class<?> getClassName() {
return className;
}
/**
* Get annotation type by it's type
* @param definition
* @return
*/
public static ANNOTATION_TYPE getByDefinition(String definition) {
for (ANNOTATION_TYPE type : values()) {
if(type.definition.equals(definition)) {
return type;
}
}
return UNKNOWN;
}
}
/** Definition of some annotation sub-types*/
public static final String GOTO = "GoTo";
public static final String GOTOE = "GoToE";
public static final String GOTOR = "GoToR";
public static final String URI = "URI";
private final PDFObject pdfObj;
private final ANNOTATION_TYPE type;
private final Float rect;
/*************************************************************************
* Constructor
* @param annotObject - the PDFObject which contains the annotation description
* @throws IOException
************************************************************************/
public PDFAnnotation(PDFObject annotObject) throws IOException{
this(annotObject, ANNOTATION_TYPE.UNKNOWN);
}
/*************************************************************************
* Constructor
* @param annotObject - the PDFObject which contains the annotation description
* @throws IOException
************************************************************************/
protected PDFAnnotation(PDFObject annotObject, ANNOTATION_TYPE type) throws IOException{
this.pdfObj = annotObject;
// in case a general "PdfAnnotation" is created the type is unknown
this.type = type;
this.rect = this.parseRect(annotObject.getDictRef("Rect"));
}
/*************************************************************************
* Create a new PDF annotation object.
*
* Currently supported annotation types:
* <li>Link annotation</li>
*
* @param parent
* @return PDFAnnotation
* @throws IOException
************************************************************************/
public static PDFAnnotation createAnnotation(PDFObject parent) throws IOException{
PDFObject subtypeValue = parent.getDictRef("Subtype");
if(subtypeValue == null) {
return null;
}
String subtypeS = subtypeValue.getStringValue();
ANNOTATION_TYPE annotationType = ANNOTATION_TYPE.getByDefinition(subtypeS);
Class<?> className = annotationType.getClassName();
Constructor<?> constructor;
try {
constructor = className.getConstructor(PDFObject.class);
return (PDFAnnotation)constructor.newInstance(parent);
} catch (Exception e) {
throw new PDFParseException("Could not parse annotation!", e);
}
}
/**
* Get a Rectangle2D.Float representation for a PDFObject that is an
* array of four Numbers.
* @param obj a PDFObject that represents an Array of exactly four
* Numbers.
*/
public Rectangle2D.Float parseRect(PDFObject obj) throws IOException {
if (obj.getType() == PDFObject.ARRAY) {
PDFObject bounds[] = obj.getArray();
if (bounds.length == 4) {
return new Rectangle2D.Float(bounds[0].getFloatValue(),
bounds[1].getFloatValue(),
bounds[2].getFloatValue() - bounds[0].getFloatValue(),
bounds[3].getFloatValue() - bounds[1].getFloatValue());
} else {
throw new PDFParseException("Rectangle definition didn't have 4 elements");
}
} else {
throw new PDFParseException("Rectangle definition not an array");
}
}
/*************************************************************************
* Get the PDF Object which contains the annotation values
* @return PDFObject
************************************************************************/
public PDFObject getPdfObj() {
return this.pdfObj;
}
/*************************************************************************
* Get the annotation type
* @return int
************************************************************************/
public ANNOTATION_TYPE getType() {
return this.type;
}
/*************************************************************************
* Get the rectangle on which the annotation should be applied to
* @return Rectangle2D.Float
************************************************************************/
public Float getRect() {
return this.rect;
}
@Override
public String toString() {
return this.pdfObj.toString();
}
/**
* Get list of pdf commands for this annotation
* @return
*/
public List<PDFCmd> getPageCommandsForAnnotation() {
return new ArrayList<PDFCmd>();
}
}