You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pdfbox.apache.org by le...@apache.org on 2013/10/27 14:59:25 UTC
svn commit: r1536136 [2/2] - in
/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox: cos/ pdmodel/
pdmodel/documentinterchange/logicalstructure/ pdmodel/graphics/xobject/
pdmodel/interactive/annotation/ util/
Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/xobject/PDXObjectForm.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/xobject/PDXObjectForm.java?rev=1536136&r1=1536135&r2=1536136&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/xobject/PDXObjectForm.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/xobject/PDXObjectForm.java Sun Oct 27 13:59:24 2013
@@ -31,7 +31,7 @@ import org.apache.pdfbox.util.Matrix;
/**
* A form xobject.
- *
+ *
* @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
* @version $Revision: 1.6 $
*/
@@ -44,120 +44,118 @@ public class PDXObjectForm extends PDXOb
/**
* Standard constuctor.
- *
+ *
* @param formStream The XObject is passed as a COSStream.
*/
public PDXObjectForm(PDStream formStream)
{
- super( formStream );
- getCOSStream().setName( COSName.SUBTYPE, SUB_TYPE );
+ super(formStream);
+ getCOSStream().setName(COSName.SUBTYPE, SUB_TYPE);
}
/**
* Standard constuctor.
- *
+ *
* @param formStream The XObject is passed as a COSStream.
*/
public PDXObjectForm(COSStream formStream)
{
- super( formStream );
- getCOSStream().setName( COSName.SUBTYPE, SUB_TYPE );
+ super(formStream);
+ getCOSStream().setName(COSName.SUBTYPE, SUB_TYPE);
}
/**
* This will get the form type, currently 1 is the only form type.
- *
+ *
* @return The form type.
*/
public int getFormType()
{
- return getCOSStream().getInt( "FormType",1 );
+ return getCOSStream().getInt("FormType", 1);
}
/**
* Set the form type.
- *
+ *
* @param formType The new form type.
*/
- public void setFormType( int formType )
+ public void setFormType(int formType)
{
- getCOSStream().setInt( "FormType", formType );
+ getCOSStream().setInt("FormType", formType);
}
/**
- * This will get the resources at this page and not look up the hierarchy.
- * This attribute is inheritable, and findResources() should probably used.
- * This will return null if no resources are available at this level.
- *
+ * This will get the resources at this page and not look up the hierarchy. This attribute is inheritable, and
+ * findResources() should probably used. This will return null if no resources are available at this level.
+ *
* @return The resources at this level in the hierarchy.
*/
public PDResources getResources()
{
PDResources retval = null;
- COSDictionary resources = (COSDictionary)getCOSStream().getDictionaryObject( COSName.RESOURCES );
- if( resources != null )
+ COSDictionary resources = (COSDictionary) getCOSStream().getDictionaryObject(COSName.RESOURCES);
+ if (resources != null)
{
- retval = new PDResources( resources );
+ retval = new PDResources(resources);
}
return retval;
}
/**
* This will set the resources for this page.
- *
+ *
* @param resources The new resources for this page.
*/
- public void setResources( PDResources resources )
+ public void setResources(PDResources resources)
{
- getCOSStream().setItem( COSName.RESOURCES, resources );
+ getCOSStream().setItem(COSName.RESOURCES, resources);
}
/**
- * An array of four numbers in the form coordinate system (see
- * below), giving the coordinates of the left, bottom, right, and top edges,
- * respectively, of the form XObject's bounding box. These boundaries are used
- * to clip the form XObject and to determine its size for caching.
- *
+ * An array of four numbers in the form coordinate system (see below), giving the coordinates of the left, bottom,
+ * right, and top edges, respectively, of the form XObject's bounding box. These boundaries are used to clip the
+ * form XObject and to determine its size for caching.
+ *
* @return The BBox of the form.
*/
public PDRectangle getBBox()
{
PDRectangle retval = null;
- COSArray array = (COSArray)getCOSStream().getDictionaryObject( COSName.BBOX );
- if( array != null )
+ COSArray array = (COSArray) getCOSStream().getDictionaryObject(COSName.BBOX);
+ if (array != null)
{
- retval = new PDRectangle( array );
+ retval = new PDRectangle(array);
}
return retval;
}
/**
* This will set the BBox (bounding box) for this form.
- *
+ *
* @param bbox The new BBox for this form.
*/
public void setBBox(PDRectangle bbox)
{
- if( bbox == null )
+ if (bbox == null)
{
- getCOSStream().removeItem( COSName.BBOX );
+ getCOSStream().removeItem(COSName.BBOX);
}
else
{
- getCOSStream().setItem( COSName.BBOX, bbox.getCOSArray() );
+ getCOSStream().setItem(COSName.BBOX, bbox.getCOSArray());
}
}
/**
- * This will get the optional Matrix of an XObjectForm.
- * It maps the form space into the user space
+ * This will get the optional Matrix of an XObjectForm. It maps the form space into the user space
+ *
* @return the form matrix
*/
public Matrix getMatrix()
{
Matrix retval = null;
- COSArray array = (COSArray)getCOSStream().getDictionaryObject( COSName.MATRIX );
- if( array != null )
+ COSArray array = (COSArray) getCOSStream().getDictionaryObject(COSName.MATRIX);
+ if (array != null)
{
retval = new Matrix();
retval.setValue(0, 0, ((COSNumber) array.get(0)).floatValue());
@@ -172,6 +170,7 @@ public class PDXObjectForm extends PDXOb
/**
* Sets the optional Matrix entry for the form XObject.
+ *
* @param transform the transformation matrix
*/
public void setMatrix(AffineTransform transform)
@@ -181,9 +180,30 @@ public class PDXObjectForm extends PDXOb
transform.getMatrix(values);
for (double v : values)
{
- matrix.add(new COSFloat((float)v));
+ matrix.add(new COSFloat((float) v));
}
getCOSStream().setItem(COSName.MATRIX, matrix);
}
+ /**
+ * This will get the key of this XObjectForm in the structural parent tree. Required if the form XObject contains
+ * marked-content sequences that are structural content items.
+ *
+ * @return the integer key of the XObjectForm's entry in the structural parent tree
+ */
+ public int getStructParents()
+ {
+ return getCOSStream().getInt(COSName.STRUCT_PARENTS, 0);
+ }
+
+ /**
+ * This will set the key for this XObjectForm in the structural parent tree.
+ *
+ * @param structParent The new key for this XObjectForm.
+ */
+ public void setStructParents(int structParent)
+ {
+ getCOSStream().setInt(COSName.STRUCT_PARENTS, structParent);
+ }
+
}
Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/PDAnnotation.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/PDAnnotation.java?rev=1536136&r1=1536135&r2=1536136&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/PDAnnotation.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/PDAnnotation.java Sun Oct 27 13:59:24 2013
@@ -21,28 +21,27 @@ import java.io.IOException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.pdfbox.cos.COSArray;
+import org.apache.pdfbox.cos.COSBase;
import org.apache.pdfbox.cos.COSDictionary;
import org.apache.pdfbox.cos.COSName;
-
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.common.COSObjectable;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.graphics.color.PDGamma;
import org.apache.pdfbox.util.BitFlagHelper;
-import org.apache.pdfbox.cos.COSBase;
/**
* This class represents a PDF annotation.
- *
+ *
* @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
- * @version $Revision: 1.16 $
+ *
*/
public abstract class PDAnnotation implements COSObjectable
{
/**
* Log instance.
*/
- private static final Log log = LogFactory.getLog(PDAnnotation.class);
+ private static final Log LOG = LogFactory.getLog(PDAnnotation.class);
/**
* An annotation flag.
@@ -81,88 +80,86 @@ public abstract class PDAnnotation imple
*/
public static final int FLAG_TOGGLE_NO_VIEW = 1 << 8;
-
-
private COSDictionary dictionary;
/**
* Create the correct annotation from the base COS object.
- *
+ *
* @param base The COS object that is the annotation.
* @return The correctly typed annotation object.
* @throws IOException If there is an error while creating the annotation.
*/
- // TODO not yet implemented:
- // Movie, Screen, PrinterMark, TrapNet, Watermark, 3D, Redact
- public static PDAnnotation createAnnotation( COSBase base ) throws IOException
+ public static PDAnnotation createAnnotation(COSBase base) throws IOException
{
PDAnnotation annot = null;
- if( base instanceof COSDictionary )
+ if (base instanceof COSDictionary)
{
- COSDictionary annotDic = (COSDictionary)base;
- String subtype = annotDic.getNameAsString( COSName.SUBTYPE );
- if( PDAnnotationFileAttachment.SUB_TYPE.equals(subtype) )
+ COSDictionary annotDic = (COSDictionary) base;
+ String subtype = annotDic.getNameAsString(COSName.SUBTYPE);
+ if (PDAnnotationFileAttachment.SUB_TYPE.equals(subtype))
{
- annot = new PDAnnotationFileAttachment( annotDic );
+ annot = new PDAnnotationFileAttachment(annotDic);
}
- else if( PDAnnotationLine.SUB_TYPE.equals(subtype) )
+ else if (PDAnnotationLine.SUB_TYPE.equals(subtype))
{
- annot = new PDAnnotationLine( annotDic );
+ annot = new PDAnnotationLine(annotDic);
}
- else if( PDAnnotationLink.SUB_TYPE.equals(subtype) )
+ else if (PDAnnotationLink.SUB_TYPE.equals(subtype))
{
annot = new PDAnnotationLink(annotDic);
}
- else if( PDAnnotationPopup.SUB_TYPE.equals(subtype) )
+ else if (PDAnnotationPopup.SUB_TYPE.equals(subtype))
{
annot = new PDAnnotationPopup(annotDic);
}
- else if( PDAnnotationRubberStamp.SUB_TYPE.equals(subtype) )
+ else if (PDAnnotationRubberStamp.SUB_TYPE.equals(subtype))
{
annot = new PDAnnotationRubberStamp(annotDic);
}
- else if( PDAnnotationSquareCircle.SUB_TYPE_SQUARE.equals(subtype) ||
- PDAnnotationSquareCircle.SUB_TYPE_CIRCLE.equals(subtype) )
+ else if (PDAnnotationSquareCircle.SUB_TYPE_SQUARE.equals(subtype)
+ || PDAnnotationSquareCircle.SUB_TYPE_CIRCLE.equals(subtype))
{
- annot = new PDAnnotationSquareCircle( annotDic );
+ annot = new PDAnnotationSquareCircle(annotDic);
}
- else if( PDAnnotationText.SUB_TYPE.equals(subtype) )
+ else if (PDAnnotationText.SUB_TYPE.equals(subtype))
{
- annot = new PDAnnotationText( annotDic);
+ annot = new PDAnnotationText(annotDic);
}
- else if( PDAnnotationTextMarkup.SUB_TYPE_HIGHLIGHT.equals(subtype) ||
- PDAnnotationTextMarkup.SUB_TYPE_UNDERLINE.equals(subtype) ||
- PDAnnotationTextMarkup.SUB_TYPE_SQUIGGLY.equals(subtype) ||
- PDAnnotationTextMarkup.SUB_TYPE_STRIKEOUT.equals(subtype) )
+ else if (PDAnnotationTextMarkup.SUB_TYPE_HIGHLIGHT.equals(subtype)
+ || PDAnnotationTextMarkup.SUB_TYPE_UNDERLINE.equals(subtype)
+ || PDAnnotationTextMarkup.SUB_TYPE_SQUIGGLY.equals(subtype)
+ || PDAnnotationTextMarkup.SUB_TYPE_STRIKEOUT.equals(subtype))
{
- annot = new PDAnnotationTextMarkup( annotDic );
+ annot = new PDAnnotationTextMarkup(annotDic);
}
- else if( PDAnnotationLink.SUB_TYPE.equals(subtype) )
+ else if (PDAnnotationLink.SUB_TYPE.equals(subtype))
{
- annot = new PDAnnotationLink( annotDic );
+ annot = new PDAnnotationLink(annotDic);
}
- else if( PDAnnotationWidget.SUB_TYPE.equals(subtype) )
+ else if (PDAnnotationWidget.SUB_TYPE.equals(subtype))
{
- annot = new PDAnnotationWidget( annotDic );
+ annot = new PDAnnotationWidget(annotDic);
}
- else if( PDAnnotationMarkup.SUB_TYPE_FREETEXT.equals(subtype) ||
- PDAnnotationMarkup.SUB_TYPE_POLYGON.equals(subtype) ||
- PDAnnotationMarkup.SUB_TYPE_POLYLINE.equals(subtype) ||
- PDAnnotationMarkup.SUB_TYPE_CARET.equals(subtype) ||
- PDAnnotationMarkup.SUB_TYPE_INK.equals(subtype) ||
- PDAnnotationMarkup.SUB_TYPE_SOUND.equals(subtype) )
+ else if (PDAnnotationMarkup.SUB_TYPE_FREETEXT.equals(subtype)
+ || PDAnnotationMarkup.SUB_TYPE_POLYGON.equals(subtype)
+ || PDAnnotationMarkup.SUB_TYPE_POLYLINE.equals(subtype)
+ || PDAnnotationMarkup.SUB_TYPE_CARET.equals(subtype)
+ || PDAnnotationMarkup.SUB_TYPE_INK.equals(subtype)
+ || PDAnnotationMarkup.SUB_TYPE_SOUND.equals(subtype))
{
- annot = new PDAnnotationMarkup( annotDic );
+ annot = new PDAnnotationMarkup(annotDic);
}
else
{
- annot = new PDAnnotationUnknown( annotDic );
- log.debug("Unknown or unsupported annotation subtype "+subtype);
+ // TODO not yet implemented:
+ // Movie, Screen, PrinterMark, TrapNet, Watermark, 3D, Redact
+ annot = new PDAnnotationUnknown(annotDic);
+ LOG.debug("Unknown or unsupported annotation subtype " + subtype);
}
}
else
{
- throw new IOException( "Error: Unknown annotation type " + base );
+ throw new IOException("Error: Unknown annotation type " + base);
}
return annot;
@@ -174,21 +171,22 @@ public abstract class PDAnnotation imple
public PDAnnotation()
{
dictionary = new COSDictionary();
- dictionary.setItem( COSName.TYPE, COSName.ANNOT );
+ dictionary.setItem(COSName.TYPE, COSName.ANNOT);
}
/**
* Constructor.
- *
+ *
* @param dict The annotations dictionary.
*/
- public PDAnnotation( COSDictionary dict )
+ public PDAnnotation(COSDictionary dict)
{
dictionary = dict;
}
/**
* returns the dictionary.
+ *
* @return the dictionary
*/
public COSDictionary getDictionary()
@@ -197,57 +195,56 @@ public abstract class PDAnnotation imple
}
/**
- * The annotation rectangle, defining the location of the annotation
- * on the page in default user space units. This is usually required and should
- * not return null on valid PDF documents. But where this is a parent form field
- * with children, such as radio button collections then the rectangle will be null.
- *
+ * The annotation rectangle, defining the location of the annotation on the page in default user space units. This
+ * is usually required and should not return null on valid PDF documents. But where this is a parent form field with
+ * children, such as radio button collections then the rectangle will be null.
+ *
* @return The Rect value of this annotation.
*/
public PDRectangle getRectangle()
{
- COSArray rectArray = (COSArray)dictionary.getDictionaryObject( COSName.RECT );
+ COSArray rectArray = (COSArray) dictionary.getDictionaryObject(COSName.RECT);
PDRectangle rectangle = null;
- if( rectArray != null )
+ if (rectArray != null)
{
- rectangle = new PDRectangle( rectArray );
+ rectangle = new PDRectangle(rectArray);
}
return rectangle;
}
/**
* This will set the rectangle for this annotation.
- *
+ *
* @param rectangle The new rectangle values.
*/
- public void setRectangle( PDRectangle rectangle )
+ public void setRectangle(PDRectangle rectangle)
{
- dictionary.setItem( COSName.RECT, rectangle.getCOSArray() );
+ dictionary.setItem(COSName.RECT, rectangle.getCOSArray());
}
- /**
+ /**
* This will get the flags for this field.
- *
+ *
* @return flags The set of flags.
*/
public int getAnnotationFlags()
{
- return getDictionary().getInt( COSName.F, 0 );
+ return getDictionary().getInt(COSName.F, 0);
}
/**
* This will set the flags for this field.
- *
+ *
* @param flags The new flags.
*/
- public void setAnnotationFlags( int flags )
+ public void setAnnotationFlags(int flags)
{
- getDictionary().setInt( COSName.F, flags );
+ getDictionary().setInt(COSName.F, flags);
}
/**
* Interface method for COSObjectable.
- *
+ *
* @return This object as a standard COS object.
*/
public COSBase getCOSObject()
@@ -257,14 +254,14 @@ public abstract class PDAnnotation imple
/**
* This will get the name of the current appearance stream if any.
- *
+ *
* @return The name of the appearance stream.
*/
public String getAppearanceStream()
{
String retval = null;
- COSName name = (COSName)getDictionary().getDictionaryObject( COSName.AS );
- if( name != null )
+ COSName name = (COSName) getDictionary().getDictionaryObject(COSName.AS);
+ if (name != null)
{
retval = name.getName();
}
@@ -273,236 +270,235 @@ public abstract class PDAnnotation imple
/**
* This will set the annotations appearance stream name.
- *
+ *
* @param as The name of the appearance stream.
*/
- public void setAppearanceStream( String as )
+ public void setAppearanceStream(String as)
{
- if( as == null )
+ if (as == null)
{
- getDictionary().removeItem( COSName.AS );
+ getDictionary().removeItem(COSName.AS);
}
else
{
- getDictionary().setItem( COSName.AS, COSName.getPDFName( as ) );
+ getDictionary().setItem(COSName.AS, COSName.getPDFName(as));
}
}
/**
- * This will get the appearance dictionary associated with this annotation.
- * This may return null.
- *
+ * This will get the appearance dictionary associated with this annotation. This may return null.
+ *
* @return This annotations appearance.
*/
public PDAppearanceDictionary getAppearance()
{
PDAppearanceDictionary ap = null;
- COSDictionary apDic = (COSDictionary)dictionary.getDictionaryObject( COSName.AP );
- if( apDic != null )
+ COSDictionary apDic = (COSDictionary) dictionary.getDictionaryObject(COSName.AP);
+ if (apDic != null)
{
- ap = new PDAppearanceDictionary( apDic );
+ ap = new PDAppearanceDictionary(apDic);
}
return ap;
}
/**
* This will set the appearance associated with this annotation.
- *
+ *
* @param appearance The appearance dictionary for this annotation.
*/
- public void setAppearance( PDAppearanceDictionary appearance )
+ public void setAppearance(PDAppearanceDictionary appearance)
{
COSDictionary ap = null;
- if( appearance != null )
+ if (appearance != null)
{
ap = appearance.getDictionary();
}
- dictionary.setItem( COSName.AP, ap );
+ dictionary.setItem(COSName.AP, ap);
}
/**
* Get the invisible flag.
- *
+ *
* @return The invisible flag.
*/
public boolean isInvisible()
{
- return BitFlagHelper.getFlag( getDictionary(), COSName.F, FLAG_INVISIBLE );
+ return BitFlagHelper.getFlag(getDictionary(), COSName.F, FLAG_INVISIBLE);
}
/**
* Set the invisible flag.
- *
+ *
* @param invisible The new invisible flag.
*/
- public void setInvisible( boolean invisible )
+ public void setInvisible(boolean invisible)
{
- BitFlagHelper.setFlag( getDictionary(), COSName.F, FLAG_INVISIBLE, invisible );
+ BitFlagHelper.setFlag(getDictionary(), COSName.F, FLAG_INVISIBLE, invisible);
}
/**
* Get the hidden flag.
- *
+ *
* @return The hidden flag.
*/
public boolean isHidden()
{
- return BitFlagHelper.getFlag( getDictionary(), COSName.F, FLAG_HIDDEN );
+ return BitFlagHelper.getFlag(getDictionary(), COSName.F, FLAG_HIDDEN);
}
/**
* Set the hidden flag.
- *
+ *
* @param hidden The new hidden flag.
*/
- public void setHidden( boolean hidden )
+ public void setHidden(boolean hidden)
{
- BitFlagHelper.setFlag( getDictionary(), COSName.F, FLAG_HIDDEN, hidden );
+ BitFlagHelper.setFlag(getDictionary(), COSName.F, FLAG_HIDDEN, hidden);
}
/**
* Get the printed flag.
- *
+ *
* @return The printed flag.
*/
public boolean isPrinted()
{
- return BitFlagHelper.getFlag( getDictionary(), COSName.F, FLAG_PRINTED );
+ return BitFlagHelper.getFlag(getDictionary(), COSName.F, FLAG_PRINTED);
}
/**
* Set the printed flag.
- *
+ *
* @param printed The new printed flag.
*/
- public void setPrinted( boolean printed )
+ public void setPrinted(boolean printed)
{
- BitFlagHelper.setFlag( getDictionary(), COSName.F, FLAG_PRINTED, printed );
+ BitFlagHelper.setFlag(getDictionary(), COSName.F, FLAG_PRINTED, printed);
}
/**
* Get the noZoom flag.
- *
+ *
* @return The noZoom flag.
*/
public boolean isNoZoom()
{
- return BitFlagHelper.getFlag( getDictionary(), COSName.F, FLAG_NO_ZOOM );
+ return BitFlagHelper.getFlag(getDictionary(), COSName.F, FLAG_NO_ZOOM);
}
/**
* Set the noZoom flag.
- *
+ *
* @param noZoom The new noZoom flag.
*/
- public void setNoZoom( boolean noZoom )
+ public void setNoZoom(boolean noZoom)
{
- BitFlagHelper.setFlag( getDictionary(), COSName.F, FLAG_NO_ZOOM, noZoom );
+ BitFlagHelper.setFlag(getDictionary(), COSName.F, FLAG_NO_ZOOM, noZoom);
}
/**
* Get the noRotate flag.
- *
+ *
* @return The noRotate flag.
*/
public boolean isNoRotate()
{
- return BitFlagHelper.getFlag( getDictionary(), COSName.F, FLAG_NO_ROTATE );
+ return BitFlagHelper.getFlag(getDictionary(), COSName.F, FLAG_NO_ROTATE);
}
/**
* Set the noRotate flag.
- *
+ *
* @param noRotate The new noRotate flag.
*/
- public void setNoRotate( boolean noRotate )
+ public void setNoRotate(boolean noRotate)
{
- BitFlagHelper.setFlag( getDictionary(), COSName.F, FLAG_NO_ROTATE, noRotate );
+ BitFlagHelper.setFlag(getDictionary(), COSName.F, FLAG_NO_ROTATE, noRotate);
}
/**
* Get the noView flag.
- *
+ *
* @return The noView flag.
*/
public boolean isNoView()
{
- return BitFlagHelper.getFlag( getDictionary(), COSName.F, FLAG_NO_VIEW );
+ return BitFlagHelper.getFlag(getDictionary(), COSName.F, FLAG_NO_VIEW);
}
/**
* Set the noView flag.
- *
+ *
* @param noView The new noView flag.
*/
- public void setNoView( boolean noView )
+ public void setNoView(boolean noView)
{
- BitFlagHelper.setFlag( getDictionary(), COSName.F, FLAG_NO_VIEW, noView );
+ BitFlagHelper.setFlag(getDictionary(), COSName.F, FLAG_NO_VIEW, noView);
}
/**
* Get the readOnly flag.
- *
+ *
* @return The readOnly flag.
*/
public boolean isReadOnly()
{
- return BitFlagHelper.getFlag( getDictionary(), COSName.F, FLAG_READ_ONLY );
+ return BitFlagHelper.getFlag(getDictionary(), COSName.F, FLAG_READ_ONLY);
}
/**
* Set the readOnly flag.
- *
+ *
* @param readOnly The new readOnly flag.
*/
- public void setReadOnly( boolean readOnly )
+ public void setReadOnly(boolean readOnly)
{
- BitFlagHelper.setFlag( getDictionary(), COSName.F, FLAG_READ_ONLY, readOnly );
+ BitFlagHelper.setFlag(getDictionary(), COSName.F, FLAG_READ_ONLY, readOnly);
}
/**
* Get the locked flag.
- *
+ *
* @return The locked flag.
*/
public boolean isLocked()
{
- return BitFlagHelper.getFlag( getDictionary(), COSName.F, FLAG_LOCKED );
+ return BitFlagHelper.getFlag(getDictionary(), COSName.F, FLAG_LOCKED);
}
/**
* Set the locked flag.
- *
+ *
* @param locked The new locked flag.
*/
- public void setLocked( boolean locked )
+ public void setLocked(boolean locked)
{
- BitFlagHelper.setFlag( getDictionary(), COSName.F, FLAG_LOCKED, locked );
+ BitFlagHelper.setFlag(getDictionary(), COSName.F, FLAG_LOCKED, locked);
}
/**
* Get the toggleNoView flag.
- *
+ *
* @return The toggleNoView flag.
*/
public boolean isToggleNoView()
{
- return BitFlagHelper.getFlag( getDictionary(), COSName.F, FLAG_TOGGLE_NO_VIEW );
+ return BitFlagHelper.getFlag(getDictionary(), COSName.F, FLAG_TOGGLE_NO_VIEW);
}
/**
* Set the toggleNoView flag.
- *
+ *
* @param toggleNoView The new toggleNoView flag.
*/
- public void setToggleNoView( boolean toggleNoView )
+ public void setToggleNoView(boolean toggleNoView)
{
- BitFlagHelper.setFlag( getDictionary(), COSName.F, FLAG_TOGGLE_NO_VIEW, toggleNoView );
+ BitFlagHelper.setFlag(getDictionary(), COSName.F, FLAG_TOGGLE_NO_VIEW, toggleNoView);
}
/**
* Get the "contents" of the field.
- *
+ *
* @return the value of the contents.
*/
public String getContents()
@@ -512,93 +508,105 @@ public abstract class PDAnnotation imple
/**
* Set the "contents" of the field.
- *
+ *
* @param value the value of the contents.
*/
- public void setContents( String value)
+ public void setContents(String value)
{
dictionary.setString(COSName.CONTENTS, value);
}
/**
* This will retrieve the date and time the annotation was modified.
- *
+ *
* @return the modified date/time (often in date format, but can be an arbitary string).
*/
public String getModifiedDate()
{
- return getDictionary().getString( COSName.M );
+ return getDictionary().getString(COSName.M);
}
/**
* This will set the the date and time the annotation was modified.
- *
- * @param m
- * the date and time the annotation was created.
+ *
+ * @param m the date and time the annotation was created.
*/
- public void setModifiedDate( String m )
+ public void setModifiedDate(String m)
{
- getDictionary().setString( COSName.M, m );
+ getDictionary().setString(COSName.M, m);
}
/**
- * This will get the name, a string intended to uniquely identify each annotation
- * within a page. Not to be confused with some annotations Name entry which
- * impact the default image drawn for them.
- *
+ * This will get the name, a string intended to uniquely identify each annotation within a page. Not to be confused
+ * with some annotations Name entry which impact the default image drawn for them.
+ *
* @return The identifying name for the Annotation.
*/
public String getAnnotationName()
{
- return getDictionary().getString( COSName.NM );
+ return getDictionary().getString(COSName.NM);
}
/**
- * This will set the name, a string intended to uniquely identify each annotation
- * within a page. Not to be confused with some annotations Name entry which
- * impact the default image drawn for them.
- *
+ * This will set the name, a string intended to uniquely identify each annotation within a page. Not to be confused
+ * with some annotations Name entry which impact the default image drawn for them.
+ *
* @param nm The identifying name for the annotation.
*/
- public void setAnnotationName( String nm )
+ public void setAnnotationName(String nm)
{
- getDictionary().setString( COSName.NM, nm );
+ getDictionary().setString(COSName.NM, nm);
}
/**
- * This will set the colour used in drawing various elements.
- * As of PDF 1.6 these are : Background of icon when closed
- * Title bar of popup window
- * Border of a link annotation
- *
+ * This will get the key of this annotation in the structural parent tree.
+ *
+ * @return the integer key of the annotation's entry in the structural parent tree
+ */
+ public int getStructParent()
+ {
+ return getDictionary().getInt(COSName.STRUCT_PARENT, 0);
+ }
+
+ /**
+ * This will set the key for this annotation in the structural parent tree.
+ *
+ * @param structParent The new key for this annotation.
+ */
+ public void setStructParent(int structParent)
+ {
+ getDictionary().setInt(COSName.STRUCT_PARENT, structParent);
+ }
+
+ /**
+ * This will set the colour used in drawing various elements. As of PDF 1.6 these are : Background of icon when
+ * closed Title bar of popup window Border of a link annotation
+ *
* Colour is in DeviceRGB colourspace
- *
- * @param c
- * colour in the DeviceRGB colourspace
- *
+ *
+ * @param c colour in the DeviceRGB colourspace
+ *
*/
- public void setColour( PDGamma c )
+ public void setColour(PDGamma c)
{
- getDictionary().setItem( COSName.C, c );
+ getDictionary().setItem(COSName.C, c);
}
/**
- * This will retrieve the colour used in drawing various elements.
- * As of PDF 1.6 these are : Background of icon when closed
- * Title bar of popup window
- * Border of a link annotation
- *
+ * This will retrieve the colour used in drawing various elements. As of PDF 1.6 these are : Background of icon when
+ * closed Title bar of popup window Border of a link annotation
+ *
* Colour is in DeviceRGB colourspace
- *
+ *
* @return PDGamma object representing the colour
- *
+ *
*/
public PDGamma getColour()
{
- COSArray c = (COSArray) getDictionary().getItem(COSName.C );
+ COSArray c = (COSArray) getDictionary().getItem(COSName.C);
if (c != null)
{
- return new PDGamma( c );
+ return new PDGamma(c);
}
else
{
@@ -606,7 +614,7 @@ public abstract class PDAnnotation imple
}
}
- /**
+ /**
* This will retrieve the subtype of the annotation.
*
* @return the subtype
@@ -625,7 +633,7 @@ public abstract class PDAnnotation imple
{
this.getDictionary().setItem(COSName.P, page);
}
-
+
/**
* This will retrieve the corresponding page of this annotation.
*
Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/PDFMergerUtility.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/PDFMergerUtility.java?rev=1536136&r1=1536135&r2=1536136&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/PDFMergerUtility.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/PDFMergerUtility.java Sun Oct 27 13:59:24 2013
@@ -22,15 +22,18 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import org.apache.pdfbox.cos.COSArray;
+import org.apache.pdfbox.cos.COSBase;
import org.apache.pdfbox.cos.COSDictionary;
import org.apache.pdfbox.cos.COSInteger;
import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.cos.COSNumber;
import org.apache.pdfbox.cos.COSStream;
+import org.apache.pdfbox.cos.COSString;
import org.apache.pdfbox.exceptions.COSVisitorException;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDDocumentCatalog;
@@ -38,7 +41,11 @@ import org.apache.pdfbox.pdmodel.PDDocum
import org.apache.pdfbox.pdmodel.PDDocumentNameDictionary;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.common.COSArrayList;
+import org.apache.pdfbox.pdmodel.common.PDNumberTreeNode;
import org.apache.pdfbox.pdmodel.common.PDStream;
+import org.apache.pdfbox.pdmodel.documentinterchange.logicalstructure.PDMarkInfo;
+import org.apache.pdfbox.pdmodel.documentinterchange.logicalstructure.PDStructureTreeRoot;
+import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotation;
import org.apache.pdfbox.pdmodel.interactive.documentnavigation.outline.PDDocumentOutline;
import org.apache.pdfbox.pdmodel.interactive.documentnavigation.outline.PDOutlineItem;
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
@@ -46,14 +53,14 @@ import org.apache.pdfbox.pdmodel.interac
import org.apache.pdfbox.pdmodel.interactive.form.PDFieldFactory;
/**
- * This class will take a list of pdf documents and merge them, saving the result
- * in a new document.
- *
+ * This class will take a list of pdf documents and merge them, saving the result in a new document.
+ *
* @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
- * @version $Revision: 1.3 $
+ *
*/
public class PDFMergerUtility
{
+ private static final String STRUCTURETYPE_DOCUMENT = "Document";
private List<InputStream> sources;
private String destinationFileName;
@@ -70,6 +77,7 @@ public class PDFMergerUtility
/**
* Get the name of the destination file.
+ *
* @return Returns the destination.
*/
public String getDestinationFileName()
@@ -79,8 +87,8 @@ public class PDFMergerUtility
/**
* Set the name of the destination file.
- * @param destination
- * The destination to set.
+ *
+ * @param destination The destination to set.
*/
public void setDestinationFileName(String destination)
{
@@ -89,6 +97,7 @@ public class PDFMergerUtility
/**
* Get the destination OutputStream.
+ *
* @return Returns the destination OutputStream.
*/
public OutputStream getDestinationStream()
@@ -98,6 +107,7 @@ public class PDFMergerUtility
/**
* Set the destination OutputStream.
+ *
* @param destStream The destination to set.
*/
public void setDestinationStream(OutputStream destStream)
@@ -107,7 +117,7 @@ public class PDFMergerUtility
/**
* Add a source file to the list of files to merge.
- *
+ *
* @param source Full path and file name of source document.
*/
public void addSource(String source)
@@ -116,7 +126,7 @@ public class PDFMergerUtility
{
sources.add(new FileInputStream(new File(source)));
}
- catch(Exception e)
+ catch (Exception e)
{
throw new RuntimeException(e);
}
@@ -124,7 +134,7 @@ public class PDFMergerUtility
/**
* Add a source file to the list of files to merge.
- *
+ *
* @param source File representing source document
*/
public void addSource(File source)
@@ -133,7 +143,7 @@ public class PDFMergerUtility
{
sources.add(new FileInputStream(source));
}
- catch(Exception e)
+ catch (Exception e)
{
throw new RuntimeException(e);
}
@@ -141,7 +151,7 @@ public class PDFMergerUtility
/**
* Add a source to the list of documents to merge.
- *
+ *
* @param source InputStream representing source document
*/
public void addSource(InputStream source)
@@ -151,17 +161,17 @@ public class PDFMergerUtility
/**
* Add a list of sources to the list of documents to merge.
- *
+ *
* @param sourcesList List of InputStream objects representing source documents
*/
public void addSources(List<InputStream> sourcesList)
{
- this.sources.addAll(sourcesList);
+ sources.addAll(sourcesList);
}
/**
* Merge the list of source documents, saving the result in the destination file.
- *
+ *
* @throws IOException If there is an error saving the document.
* @throws COSVisitorException If an error occurs while saving the destination file.
*/
@@ -187,7 +197,7 @@ public class PDFMergerUtility
tobeclosed.add(source);
appendDocument(destination, source);
}
- if(destinationStream == null)
+ if (destinationStream == null)
{
destination.save(destinationFileName);
}
@@ -210,52 +220,51 @@ public class PDFMergerUtility
}
}
-
/**
* append all pages from source to destination.
- *
+ *
* @param destination the document to receive the pages
* @param source the document originating the new pages
- *
+ *
* @throws IOException If there is an error accessing data from either document.
*/
public void appendDocument(PDDocument destination, PDDocument source) throws IOException
{
- if( destination.isEncrypted() )
+ if (destination.isEncrypted())
{
- throw new IOException( "Error: destination PDF is encrypted, can't append encrypted PDF documents." );
+ throw new IOException("Error: destination PDF is encrypted, can't append encrypted PDF documents.");
}
- if( source.isEncrypted() )
+ if (source.isEncrypted())
{
- throw new IOException( "Error: source PDF is encrypted, can't append encrypted PDF documents." );
+ throw new IOException("Error: source PDF is encrypted, can't append encrypted PDF documents.");
}
PDDocumentInformation destInfo = destination.getDocumentInformation();
PDDocumentInformation srcInfo = source.getDocumentInformation();
- destInfo.getDictionary().mergeInto( srcInfo.getDictionary() );
+ destInfo.getDictionary().mergeInto(srcInfo.getDictionary());
PDDocumentCatalog destCatalog = destination.getDocumentCatalog();
PDDocumentCatalog srcCatalog = source.getDocumentCatalog();
// use the highest version number for the resulting pdf
- float destVersion = destination.getDocument().getVersion();
- float srcVersion = source.getDocument().getVersion();
+ float destVersion = destination.getDocument().getVersion();
+ float srcVersion = source.getDocument().getVersion();
if (destVersion < srcVersion)
{
destination.getDocument().setVersion(srcVersion);
}
-
- if( destCatalog.getOpenAction() == null )
+
+ if (destCatalog.getOpenAction() == null)
{
- destCatalog.setOpenAction( srcCatalog.getOpenAction() );
+ destCatalog.setOpenAction(srcCatalog.getOpenAction());
}
- // maybe there are some shared resources for all pages
- COSDictionary srcPages = (COSDictionary)srcCatalog.getCOSDictionary().getDictionaryObject( COSName.PAGES );
- COSDictionary srcResources = (COSDictionary)srcPages.getDictionaryObject( COSName.RESOURCES );
- COSDictionary destPages = (COSDictionary)destCatalog.getCOSDictionary().getDictionaryObject( COSName.PAGES );
- COSDictionary destResources = (COSDictionary)destPages.getDictionaryObject( COSName.RESOURCES );
- if (srcResources != null)
+ // maybe there are some shared resources for all pages
+ COSDictionary srcPages = (COSDictionary) srcCatalog.getCOSDictionary().getDictionaryObject(COSName.PAGES);
+ COSDictionary srcResources = (COSDictionary) srcPages.getDictionaryObject(COSName.RESOURCES);
+ COSDictionary destPages = (COSDictionary) destCatalog.getCOSDictionary().getDictionaryObject(COSName.PAGES);
+ COSDictionary destResources = (COSDictionary) destPages.getDictionaryObject(COSName.RESOURCES);
+ if (srcResources != null)
{
if (destResources != null)
{
@@ -266,56 +275,54 @@ public class PDFMergerUtility
destPages.setItem(COSName.RESOURCES, srcResources);
}
}
-
+
PDFCloneUtility cloner = new PDFCloneUtility(destination);
try
{
PDAcroForm destAcroForm = destCatalog.getAcroForm();
PDAcroForm srcAcroForm = srcCatalog.getAcroForm();
- if( destAcroForm == null )
+ if (destAcroForm == null)
{
- cloner.cloneForNewDocument( srcAcroForm );
- destCatalog.setAcroForm( srcAcroForm );
+ cloner.cloneForNewDocument(srcAcroForm);
+ destCatalog.setAcroForm(srcAcroForm);
}
else
{
- if( srcAcroForm != null )
+ if (srcAcroForm != null)
{
mergeAcroForm(cloner, destAcroForm, srcAcroForm);
}
}
}
- catch(Exception e)
+ catch (Exception e)
{
// if we are not ignoring exceptions, we'll re-throw this
- if(!ignoreAcroFormErrors)
+ if (!ignoreAcroFormErrors)
{
- throw (IOException)e;
+ throw (IOException) e;
}
}
- COSArray destThreads = (COSArray)destCatalog.getCOSDictionary().getDictionaryObject(
- COSName.THREADS);
- COSArray srcThreads = (COSArray)cloner.cloneForNewDocument(
- destCatalog.getCOSDictionary().getDictionaryObject( COSName.THREADS ));
- if( destThreads == null )
+ COSArray destThreads = (COSArray) destCatalog.getCOSDictionary().getDictionaryObject(COSName.THREADS);
+ COSArray srcThreads = (COSArray) cloner.cloneForNewDocument(destCatalog.getCOSDictionary().getDictionaryObject(
+ COSName.THREADS));
+ if (destThreads == null)
{
- destCatalog.getCOSDictionary().setItem( COSName.THREADS, srcThreads );
+ destCatalog.getCOSDictionary().setItem(COSName.THREADS, srcThreads);
}
else
{
- destThreads.addAll( srcThreads );
+ destThreads.addAll(srcThreads);
}
PDDocumentNameDictionary destNames = destCatalog.getNames();
PDDocumentNameDictionary srcNames = srcCatalog.getNames();
- if( srcNames != null )
+ if (srcNames != null)
{
- if( destNames == null )
+ if (destNames == null)
{
- destCatalog.getCOSDictionary().setItem( COSName.NAMES,
- cloner.cloneForNewDocument( srcNames ) );
+ destCatalog.getCOSDictionary().setItem(COSName.NAMES, cloner.cloneForNewDocument(srcNames));
}
else
{
@@ -326,142 +333,336 @@ public class PDFMergerUtility
PDDocumentOutline destOutline = destCatalog.getDocumentOutline();
PDDocumentOutline srcOutline = srcCatalog.getDocumentOutline();
- if( srcOutline != null )
+ if (srcOutline != null)
{
- if( destOutline == null )
+ if (destOutline == null)
{
- PDDocumentOutline cloned =
- new PDDocumentOutline( (COSDictionary)cloner.cloneForNewDocument( srcOutline ) );
- destCatalog.setDocumentOutline( cloned );
+ PDDocumentOutline cloned = new PDDocumentOutline((COSDictionary) cloner.cloneForNewDocument(srcOutline));
+ destCatalog.setDocumentOutline(cloned);
}
else
{
PDOutlineItem first = srcOutline.getFirstChild();
- if(first != null)
+ if (first != null)
{
- PDOutlineItem clonedFirst = new PDOutlineItem(
- (COSDictionary)cloner.cloneForNewDocument( first ));
- destOutline.appendChild( clonedFirst );
+ PDOutlineItem clonedFirst = new PDOutlineItem((COSDictionary) cloner.cloneForNewDocument(first));
+ destOutline.appendChild(clonedFirst);
}
}
}
String destPageMode = destCatalog.getPageMode();
String srcPageMode = srcCatalog.getPageMode();
- if( destPageMode == null )
+ if (destPageMode == null)
{
- destCatalog.setPageMode( srcPageMode );
+ destCatalog.setPageMode(srcPageMode);
}
- COSDictionary destLabels = (COSDictionary)destCatalog.getCOSDictionary().getDictionaryObject(
+ COSDictionary destLabels = (COSDictionary) destCatalog.getCOSDictionary().getDictionaryObject(
COSName.PAGE_LABELS);
- COSDictionary srcLabels = (COSDictionary)srcCatalog.getCOSDictionary().getDictionaryObject(
- COSName.PAGE_LABELS);
- if( srcLabels != null )
+ COSDictionary srcLabels = (COSDictionary) srcCatalog.getCOSDictionary()
+ .getDictionaryObject(COSName.PAGE_LABELS);
+ if (srcLabels != null)
{
int destPageCount = destination.getNumberOfPages();
COSArray destNums = null;
- if( destLabels == null )
+ if (destLabels == null)
{
destLabels = new COSDictionary();
destNums = new COSArray();
- destLabels.setItem( COSName.NUMS, destNums );
- destCatalog.getCOSDictionary().setItem( COSName.PAGE_LABELS, destLabels );
+ destLabels.setItem(COSName.NUMS, destNums);
+ destCatalog.getCOSDictionary().setItem(COSName.PAGE_LABELS, destLabels);
}
else
{
- destNums = (COSArray)destLabels.getDictionaryObject( COSName.NUMS );
+ destNums = (COSArray) destLabels.getDictionaryObject(COSName.NUMS);
}
- COSArray srcNums = (COSArray)srcLabels.getDictionaryObject( COSName.NUMS );
+ COSArray srcNums = (COSArray) srcLabels.getDictionaryObject(COSName.NUMS);
if (srcNums != null)
{
- for( int i=0; i<srcNums.size(); i+=2 )
+ for (int i = 0; i < srcNums.size(); i += 2)
{
- COSNumber labelIndex = (COSNumber)srcNums.getObject( i );
+ COSNumber labelIndex = (COSNumber) srcNums.getObject(i);
long labelIndexValue = labelIndex.intValue();
- destNums.add( COSInteger.get( labelIndexValue + destPageCount ) );
- destNums.add( cloner.cloneForNewDocument( srcNums.getObject( i+1 ) ) );
+ destNums.add(COSInteger.get(labelIndexValue + destPageCount));
+ destNums.add(cloner.cloneForNewDocument(srcNums.getObject(i + 1)));
}
}
}
- COSStream destMetadata = (COSStream)destCatalog.getCOSDictionary().getDictionaryObject( COSName.METADATA );
- COSStream srcMetadata = (COSStream)srcCatalog.getCOSDictionary().getDictionaryObject( COSName.METADATA );
- if( destMetadata == null && srcMetadata != null )
+ COSStream destMetadata = (COSStream) destCatalog.getCOSDictionary().getDictionaryObject(COSName.METADATA);
+ COSStream srcMetadata = (COSStream) srcCatalog.getCOSDictionary().getDictionaryObject(COSName.METADATA);
+ if (destMetadata == null && srcMetadata != null)
{
- PDStream newStream = new PDStream( destination, srcMetadata.getUnfilteredStream(), false );
- newStream.getStream().mergeInto( srcMetadata );
+ PDStream newStream = new PDStream(destination, srcMetadata.getUnfilteredStream(), false);
+ newStream.getStream().mergeInto(srcMetadata);
newStream.addCompression();
- destCatalog.getCOSDictionary().setItem( COSName.METADATA, newStream );
+ destCatalog.getCOSDictionary().setItem(COSName.METADATA, newStream);
+ }
+
+ // merge logical structure hierarchy if logical structure information is available in both source pdf and
+ // destination pdf
+ boolean mergeStructTree = false;
+ int destParentTreeNextKey = -1;
+ COSDictionary destParentTreeDict = null;
+ COSDictionary srcParentTreeDict = null;
+ COSArray destNumbersArray = null;
+ COSArray srcNumbersArray = null;
+ PDMarkInfo destMark = destCatalog.getMarkInfo();
+ PDStructureTreeRoot destStructTree = destCatalog.getStructureTreeRoot();
+ PDMarkInfo srcMark = srcCatalog.getMarkInfo();
+ PDStructureTreeRoot srcStructTree = srcCatalog.getStructureTreeRoot();
+ if (destStructTree != null)
+ {
+ PDNumberTreeNode destParentTree = destStructTree.getParentTree();
+ destParentTreeNextKey = destStructTree.getParentTreeNextKey();
+ if (destParentTree != null)
+ {
+ destParentTreeDict = destParentTree.getCOSDictionary();
+ destNumbersArray = (COSArray) destParentTreeDict.getDictionaryObject(COSName.NUMS);
+ if (destNumbersArray != null)
+ {
+ if (destParentTreeNextKey < 0)
+ {
+ destParentTreeNextKey = destNumbersArray.size() / 2;
+ }
+ if (destParentTreeNextKey > 0)
+ {
+ if (srcStructTree != null)
+ {
+ PDNumberTreeNode srcParentTree = srcStructTree.getParentTree();
+ if (srcParentTree != null)
+ {
+ srcParentTreeDict = srcParentTree.getCOSDictionary();
+ srcNumbersArray = (COSArray) srcParentTreeDict.getDictionaryObject(COSName.NUMS);
+ if (srcNumbersArray != null)
+ {
+ mergeStructTree = true;
+ }
+ }
+ }
+ }
+ }
+ }
+ if (destMark != null && destMark.isMarked() && !mergeStructTree)
+ {
+ destMark.setMarked(false);
+ }
+ if (!mergeStructTree)
+ {
+ destCatalog.setStructureTreeRoot(null);
+ }
}
- //finally append the pages
+ // finally append the pages
List<PDPage> pages = srcCatalog.getAllPages();
Iterator<PDPage> pageIter = pages.iterator();
- while( pageIter.hasNext() )
+ HashMap<COSDictionary, COSDictionary> objMapping = new HashMap<COSDictionary, COSDictionary>();
+ while (pageIter.hasNext())
{
PDPage page = pageIter.next();
- PDPage newPage =
- new PDPage( (COSDictionary)cloner.cloneForNewDocument( page.getCOSDictionary() ) );
- newPage.setCropBox( page.findCropBox() );
- newPage.setMediaBox( page.findMediaBox() );
- newPage.setRotation( page.findRotation() );
- destination.addPage( newPage );
+ PDPage newPage = new PDPage((COSDictionary) cloner.cloneForNewDocument(page.getCOSDictionary()));
+ newPage.setCropBox(page.findCropBox());
+ newPage.setMediaBox(page.findMediaBox());
+ newPage.setRotation(page.findRotation());
+ if (mergeStructTree)
+ {
+ updateStructParentEntries(newPage, destParentTreeNextKey);
+ objMapping.put(page.getCOSDictionary(), newPage.getCOSDictionary());
+ List<PDAnnotation> oldAnnots = page.getAnnotations();
+ List<PDAnnotation> newAnnots = newPage.getAnnotations();
+ for (int i = 0; i < oldAnnots.size(); i++)
+ {
+ objMapping.put(oldAnnots.get(i).getDictionary(), newAnnots.get(i).getDictionary());
+ }
+ // TODO update mapping for XObjects
+ }
+ destination.addPage(newPage);
}
- }
+ if (mergeStructTree)
+ {
+ updatePageReferences(srcNumbersArray, objMapping);
+ for (int i = 0; i < srcNumbersArray.size() / 2; i++)
+ {
+ destNumbersArray.add(COSInteger.get(destParentTreeNextKey + i));
+ destNumbersArray.add(srcNumbersArray.getObject(i * 2 + 1));
+ }
+ destParentTreeNextKey += srcNumbersArray.size() / 2;
+ destParentTreeDict.setItem(COSName.NUMS, destNumbersArray);
+ PDNumberTreeNode newParentTreeNode = new PDNumberTreeNode(destParentTreeDict, COSBase.class);
+ destStructTree.setParentTree(newParentTreeNode);
+ destStructTree.setParentTreeNextKey(destParentTreeNextKey);
+ COSDictionary kDictLevel0 = new COSDictionary();
+ COSArray newKArray = new COSArray();
+ COSArray destKArray = destStructTree.getKArray();
+ COSArray srcKArray = srcStructTree.getKArray();
+ if (destKArray != null && srcKArray != null)
+ {
+ updateParentEntry(destKArray, kDictLevel0);
+ newKArray.addAll(destKArray);
+ if (mergeStructTree)
+ {
+ updateParentEntry(srcKArray, kDictLevel0);
+ }
+ newKArray.addAll(srcKArray);
+ }
+ kDictLevel0.setItem(COSName.K, newKArray);
+ kDictLevel0.setItem(COSName.P, destStructTree);
+ kDictLevel0.setItem(COSName.S, new COSString(STRUCTURETYPE_DOCUMENT));
+ destStructTree.setK(kDictLevel0);
+ }
+ }
private int nextFieldNum = 1;
/**
- * Merge the contents of the source form into the destination form
- * for the destination file.
- *
+ * Merge the contents of the source form into the destination form for the destination file.
+ *
* @param cloner the object cloner for the destination document
* @param destAcroForm the destination form
* @param srcAcroForm the source form
* @throws IOException If an error occurs while adding the field.
*/
private void mergeAcroForm(PDFCloneUtility cloner, PDAcroForm destAcroForm, PDAcroForm srcAcroForm)
- throws IOException
+ throws IOException
{
List destFields = destAcroForm.getFields();
List srcFields = srcAcroForm.getFields();
- if( srcFields != null )
+ if (srcFields != null)
{
- if( destFields == null )
+ if (destFields == null)
{
destFields = new COSArrayList();
- destAcroForm.setFields( destFields );
+ destAcroForm.setFields(destFields);
}
Iterator srcFieldsIterator = srcFields.iterator();
while (srcFieldsIterator.hasNext())
{
- PDField srcField = (PDField)srcFieldsIterator.next();
- PDField destField =
- PDFieldFactory.createField(
- destAcroForm,
- (COSDictionary)cloner.cloneForNewDocument(srcField.getDictionary() ));
+ PDField srcField = (PDField) srcFieldsIterator.next();
+ PDField destField = PDFieldFactory.createField(destAcroForm,
+ (COSDictionary) cloner.cloneForNewDocument(srcField.getDictionary()));
// if the form already has a field with this name then we need to rename this field
// to prevent merge conflicts.
- if ( destAcroForm.getField(destField.getFullyQualifiedName()) != null )
+ if (destAcroForm.getField(destField.getFullyQualifiedName()) != null)
{
- destField.setPartialName("dummyFieldName"+(nextFieldNum++));
+ destField.setPartialName("dummyFieldName" + (nextFieldNum++));
}
destFields.add(destField);
}
}
}
+ /**
+ * Indicates if acroform errors are ignored or not.
+ *
+ * @return true if acroform errors are ignored
+ */
public boolean isIgnoreAcroFormErrors()
{
return ignoreAcroFormErrors;
}
- public void setIgnoreAcroFormErrors(boolean ignoreAcroFormErrors)
+ /**
+ * Set to true to ignore acroform errors.
+ *
+ * @param ignoreAcroFormErrorsValue true if acroform errors should be ignored
+ */
+ public void setIgnoreAcroFormErrors(boolean ignoreAcroFormErrorsValue)
{
- this.ignoreAcroFormErrors = ignoreAcroFormErrors;
+ ignoreAcroFormErrors = ignoreAcroFormErrorsValue;
}
+ /**
+ * Update the Pg and Obj references to the new (merged) page.
+ *
+ * @param parentTreeEntry
+ * @param objMapping mapping between old and new references
+ */
+ private void updatePageReferences(COSDictionary parentTreeEntry, HashMap<COSDictionary, COSDictionary> objMapping)
+ {
+ COSBase page = parentTreeEntry.getDictionaryObject(COSName.PG);
+ if (page instanceof COSDictionary)
+ {
+ if (objMapping.containsKey(page))
+ {
+ parentTreeEntry.setItem(COSName.PG, objMapping.get(page));
+ }
+ }
+ COSBase obj = parentTreeEntry.getDictionaryObject(COSName.OBJ);
+ if (obj instanceof COSDictionary)
+ {
+ if (objMapping.containsKey(obj))
+ {
+ parentTreeEntry.setItem(COSName.OBJ, objMapping.get(obj));
+ }
+ }
+ COSBase kSubEntry = parentTreeEntry.getDictionaryObject(COSName.K);
+ if (kSubEntry instanceof COSArray)
+ {
+ updatePageReferences((COSArray) kSubEntry, objMapping);
+ }
+ else if (kSubEntry instanceof COSDictionary)
+ {
+ updatePageReferences((COSDictionary) kSubEntry, objMapping);
+ }
+ }
+
+ private void updatePageReferences(COSArray parentTreeEntry, HashMap<COSDictionary, COSDictionary> objMapping)
+ {
+ for (int i = 0; i < parentTreeEntry.size(); i++)
+ {
+ COSBase subEntry = parentTreeEntry.getObject(i);
+ if (subEntry instanceof COSArray)
+ {
+ updatePageReferences((COSArray) subEntry, objMapping);
+ }
+ else if (subEntry instanceof COSDictionary)
+ {
+ updatePageReferences((COSDictionary) subEntry, objMapping);
+ }
+ }
+ }
+
+ /**
+ * Update the P reference to the new parent dictionary.
+ *
+ * @param kArray the kids array
+ * @param newParent the new parent
+ */
+ private void updateParentEntry(COSArray kArray, COSDictionary newParent)
+ {
+ for (int i = 0; i < kArray.size(); i++)
+ {
+ COSBase subEntry = kArray.getObject(i);
+ if (subEntry instanceof COSDictionary)
+ {
+ COSDictionary dictEntry = (COSDictionary) subEntry;
+ if (dictEntry.getDictionaryObject(COSName.P) != null)
+ {
+ dictEntry.setItem(COSName.P, newParent);
+ }
+ }
+ }
+ }
+
+ /**
+ * Update the StructParents and StructParent values in a PDPage.
+ *
+ * @param page the new page
+ * @param structParentOffset the offset which should be applied
+ */
+ private void updateStructParentEntries(PDPage page, int structParentOffset) throws IOException
+ {
+ page.setStructParents(page.getStructParents() + structParentOffset);
+ List<PDAnnotation> annots = page.getAnnotations();
+ List<PDAnnotation> newannots = new ArrayList<PDAnnotation>();
+ for (PDAnnotation annot : annots)
+ {
+ annot.setStructParent(annot.getStructParent() + structParentOffset);
+ newannots.add(annot);
+ }
+ page.setAnnotations(newannots);
+ }
}