You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pdfbox.apache.org by je...@apache.org on 2010/10/22 09:21:35 UTC
svn commit: r1026228 [1/2] - in /pdfbox/trunk/pdfbox/src:
main/java/org/apache/pdfbox/cos/ main/java/org/apache/pdfbox/pdmodel/
main/java/org/apache/pdfbox/pdmodel/common/
main/java/org/apache/pdfbox/pdmodel/edit/
main/java/org/apache/pdfbox/pdmodel/gr...
Author: jeremias
Date: Fri Oct 22 07:21:34 2010
New Revision: 1026228
URL: http://svn.apache.org/viewvc?rev=1026228&view=rev
Log:
PDFBOX-865:
Added initial support for optional content groups (OCGs aka layers).
Details:
- Adds PD-layer classes to deal with optional content groups
- Made COSArray an Iterable
- COSDocument: Allow to remove an object from the document objects
- PDPageContentStream: added some functionality from marked content (incomplete)
- PDPageContentStream Bugfix: Form XObjects were always "forgotten" when a second PDPageContentStream was constructed for the same page.
- PDXObjectForm: allow to set the Matrix.
- PDDocumentCatalog: allow to set the PDF version and OCProperties
- PDResources: allow to set Properties (PDPropertyList, used for marked content lookups)
- COSObjectKey learns Comparable
- Moved object cloning functionality from PDFMergerUtility to separate class PDFCloneUtility, because it's reused by LayerUtility introduced below.
- LayerUtil allows to import pages a Form XObjects and create layers with them. These layers can later be switched on and off through the OCG PD-layer classes. The code for is largely adapted from my PDF-plug-in for Apache FOP.
Added:
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/optionalcontent/
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/optionalcontent/PDOptionalContentGroup.java (with props)
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/optionalcontent/PDOptionalContentProperties.java (with props)
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/markedcontent/
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/markedcontent/PDPropertyList.java (with props)
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/LayerUtility.java (with props)
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/PDFCloneUtility.java (with props)
pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/graphics/optionalcontent/
pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/graphics/optionalcontent/TestOptionalContentGroups.java (with props)
pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/util/TestLayerUtility.java (with props)
Modified:
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSArray.java
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSDictionary.java
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSDocument.java
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocumentCatalog.java
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDResources.java
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/COSDictionaryMap.java
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/edit/PDPageContentStream.java
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/xobject/PDXObjectForm.java
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/persistence/util/COSObjectKey.java
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/PDFMergerUtility.java
pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/TestAll.java
Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSArray.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSArray.java?rev=1026228&r1=1026227&r2=1026228&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSArray.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSArray.java Fri Oct 22 07:21:34 2010
@@ -21,8 +21,6 @@ import java.util.Collection;
import java.util.Iterator;
import java.util.List;
-
-
import org.apache.pdfbox.exceptions.COSVisitorException;
import org.apache.pdfbox.pdmodel.common.COSObjectable;
@@ -32,7 +30,7 @@ import org.apache.pdfbox.pdmodel.common.
* @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
* @version $Revision: 1.24 $
*/
-public class COSArray extends COSBase
+public class COSArray extends COSBase implements Iterable<COSBase>
{
private List<COSBase> objects = new ArrayList<COSBase>();
@@ -235,7 +233,7 @@ public class COSArray extends COSBase
public int getInt( int index, int defaultValue )
{
int retval = defaultValue;
- if ( index < size() )
+ if ( index < size() )
{
Object obj = objects.get( index );
if( obj instanceof COSNumber )
@@ -377,7 +375,7 @@ public class COSArray extends COSBase
/**
* This will remove an element from the array.
* This method will also remove a reference to the object.
- *
+ *
* @param o The object to remove.
* @return <code>true</code> if the object was removed, <code>false</code>
* otherwise
@@ -443,7 +441,7 @@ public class COSArray extends COSBase
/**
* This will return the index of the entry or -1 if it is not found.
* This method will also find references to indirect objects.
- *
+ *
* @param object The object to search for.
* @return The index of the object or -1.
*/
@@ -538,11 +536,11 @@ public class COSArray extends COSBase
add( new COSFloat( value[i] ) );
}
}
-
+
/**
* Return contents of COSArray as a Java List.
- *
- * @return the COSArray as List
+ *
+ * @return the COSArray as List
*/
public List<COSBase> toList()
{
Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSDictionary.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSDictionary.java?rev=1026228&r1=1026227&r2=1026228&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSDictionary.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSDictionary.java Fri Oct 22 07:21:34 2010
@@ -26,7 +26,6 @@ import java.util.Map;
import java.util.Set;
import org.apache.pdfbox.exceptions.COSVisitorException;
-
import org.apache.pdfbox.pdmodel.common.COSObjectable;
import org.apache.pdfbox.util.DateConverter;
@@ -570,11 +569,11 @@ public class COSDictionary extends COSBa
COSBase name = getDictionaryObject( key );
if( name != null )
{
- if ( name instanceof COSName)
+ if ( name instanceof COSName)
{
retval = ((COSName)name).getName();
}
- else if ( name instanceof COSString)
+ else if ( name instanceof COSString)
{
retval = ((COSString)name).getString();
}
@@ -1242,7 +1241,8 @@ public class COSDictionary extends COSBa
* @since Apache PDFBox 1.1.0
* @return name-value entries in this dictionary
*/
- public Set<Map.Entry<COSName, COSBase>> entrySet() {
+ public Set<Map.Entry<COSName, COSBase>> entrySet()
+ {
return items.entrySet();
}
@@ -1271,7 +1271,7 @@ public class COSDictionary extends COSBa
/**
* This will add all of the dictionarys keys/values to this dictionary.
- * Only called when adding keys to a trailer that already exists.
+ * Only called when adding keys to a trailer that already exists.
*
* @param dic The dic to get the keys from.
*/
@@ -1280,9 +1280,9 @@ public class COSDictionary extends COSBa
for( Map.Entry<COSName, COSBase> entry : dic.entrySet() )
{
/*
- * If we're at a second trailer, we have a linearized
+ * If we're at a second trailer, we have a linearized
* pdf file, meaning that the first Size entry represents
- * all of the objects so we don't need to grab the second.
+ * all of the objects so we don't need to grab the second.
*/
if(!entry.getKey().getName().equals("Size")
|| !items.containsKey(COSName.getPDFName("Size")))
@@ -1338,7 +1338,7 @@ public class COSDictionary extends COSBa
}
return retval;
}
-
+
/**
* {@inheritDoc}
*/
Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSDocument.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSDocument.java?rev=1026228&r1=1026227&r2=1026228&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSDocument.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSDocument.java Fri Oct 22 07:21:34 2010
@@ -18,7 +18,6 @@ package org.apache.pdfbox.cos;
import java.io.File;
import java.io.IOException;
-
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -29,7 +28,6 @@ import org.apache.commons.logging.LogFac
import org.apache.pdfbox.exceptions.COSVisitorException;
import org.apache.pdfbox.io.RandomAccess;
import org.apache.pdfbox.io.RandomAccessFile;
-
import org.apache.pdfbox.pdfparser.PDFObjectStreamParser;
import org.apache.pdfbox.pdfparser.PDFXrefStreamParser;
import org.apache.pdfbox.persistence.util.COSObjectKey;
@@ -524,6 +522,17 @@ public class COSDocument extends COSBase
}
/**
+ * Removes an object from the object pool.
+ * @param key the object key
+ * @return the object that was removed or null if the object was not found
+ */
+ public COSObject removeObject(COSObjectKey key)
+ {
+ COSObject obj = objectPool.remove(key);
+ return obj;
+ }
+
+ /**
* Used to populate the XRef HashMap. Will add an Xreftable entry
* that maps ObjectKeys to byte offsets in the file.
* @param objKey The objkey, with id and gen numbers
Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java?rev=1026228&r1=1026227&r2=1026228&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java Fri Oct 22 07:21:34 2010
@@ -18,10 +18,9 @@ package org.apache.pdfbox.cos;
import java.io.IOException;
import java.io.OutputStream;
-
import java.util.HashMap;
-import java.util.concurrent.ConcurrentHashMap;
import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
import org.apache.pdfbox.exceptions.COSVisitorException;
import org.apache.pdfbox.persistence.util.COSHEXTable;
@@ -129,9 +128,13 @@ public final class COSName extends COSBa
* A common COSName value.
*/
public static final COSName BASE_FONT = new COSName( "BaseFont" );
+
+ /** the COSName for "BaseState". */
+ public static final COSName BASE_STATE = new COSName( "BaseState" );
+
/**
- * A common COSName value.
- */
+ * A common COSName value.
+ */
public static final COSName BBOX = new COSName( "BBox" );
/**
* A common COSName value.
@@ -141,7 +144,7 @@ public final class COSName extends COSBa
* A common COSName value.
*/
public static final COSName BLACK_POINT = new COSName( "BlackPoint" );
-
+
/**
* A common COSName value.
*/
@@ -651,12 +654,26 @@ public final class COSName extends COSBa
* "O"
*/
public static final COSName O = new COSName("O");
-
+
/**
* "Obj"
*/
public static final COSName OBJ = new COSName("Obj");
+ /** the COSName for the content group tag. */
+ public static final COSName OC = new COSName("OC");
+ /** the COSName for an optional content group. */
+ public static final COSName OCG = new COSName("OCG");
+ /** the COSName for the optional content group list. */
+ public static final COSName OCGS = new COSName("OCGs");
+ /** the COSName for the optional content properties. */
+ public static final COSName OCPROPERTIES = new COSName("OCProperties");
+
+ /** the COSName for the "OFF" value. */
+ public static final COSName OFF = new COSName("OFF");
+ /** the COSName for the "ON" value. */
+ public static final COSName ON = new COSName("ON");
+
/**
* A common COSName value.
*/
@@ -675,6 +692,9 @@ public final class COSName extends COSBa
/** "OpenAction" */
public static final COSName OPEN_ACTION = new COSName("OpenAction");
+ /** A common COSName value. */
+ public static final COSName ORDER = new COSName( "Order" );
+
/**
* A common COSName value.
*/
@@ -730,7 +750,7 @@ public final class COSName extends COSBa
*/
public static final COSName PREV = new COSName( "Prev" );
- /** "ProcSet" */
+ /** The COSName value for "ProcSet". */
public static final COSName PROC_SET = new COSName( "ProcSet" );
/**
@@ -738,6 +758,9 @@ public final class COSName extends COSBa
*/
public static final COSName PRODUCER = new COSName( "Producer" );
+ /** The COSName value for "Properties". */
+ public static final COSName PROPERTIES = new COSName( "Properties" );
+
/**
* A common COSName value.
*/
@@ -828,7 +851,7 @@ public final class COSName extends COSBa
* A common COSName value.
*/
public static final COSName STR_F = new COSName( "StrF" );
-
+
/** "StructTreeRoot" */
public static final COSName STRUCT_TREE_ROOT = new COSName("StructTreeRoot");
@@ -848,7 +871,7 @@ public final class COSName extends COSBa
* A common COSName value.
*/
public static final COSName SUBTYPE = new COSName( "Subtype" );
-
+
/**
* "T"
*/
@@ -902,6 +925,8 @@ public final class COSName extends COSBa
* A common COSName value.
*/
public static final COSName U = new COSName( "U" );
+ /** the COSName for the "Unchanged" value. */
+ public static final COSName UNCHANGED = new COSName("Unchanged");
/** "URI" */
public static final COSName URI = new COSName("URI");
@@ -937,7 +962,7 @@ public final class COSName extends COSBa
* A common COSName value.
*/
public static final COSName WHITE_POINT = new COSName( "WhitePoint" );
-
+
/** "XObject" */
public static final COSName XOBJECT = new COSName( "XObject" );
@@ -986,7 +1011,7 @@ public final class COSName extends COSBa
* that are created.
*
* @param aName The name of the COSName object.
- * @param staticValue Indicates if the COSName object is static so that it can
+ * @param staticValue Indicates if the COSName object is static so that it can
* be stored in the HashMap without synchronizing.
*/
private COSName( String aName, boolean staticValue )
Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocumentCatalog.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocumentCatalog.java?rev=1026228&r1=1026227&r2=1026228&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocumentCatalog.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocumentCatalog.java Fri Oct 22 07:21:34 2010
@@ -25,7 +25,6 @@ import org.apache.pdfbox.cos.COSBase;
import org.apache.pdfbox.cos.COSDictionary;
import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.cos.COSStream;
-
import org.apache.pdfbox.pdmodel.common.COSArrayList;
import org.apache.pdfbox.pdmodel.common.COSObjectable;
import org.apache.pdfbox.pdmodel.common.PDDestinationOrAction;
@@ -33,13 +32,13 @@ import org.apache.pdfbox.pdmodel.common.
import org.apache.pdfbox.pdmodel.common.PDPageLabels;
import org.apache.pdfbox.pdmodel.documentinterchange.logicalstructure.PDMarkInfo;
import org.apache.pdfbox.pdmodel.documentinterchange.logicalstructure.PDStructureTreeRoot;
-import org.apache.pdfbox.pdmodel.interactive.action.type.PDURIDictionary;
+import org.apache.pdfbox.pdmodel.graphics.optionalcontent.PDOptionalContentProperties;
import org.apache.pdfbox.pdmodel.interactive.action.PDActionFactory;
import org.apache.pdfbox.pdmodel.interactive.action.PDDocumentCatalogAdditionalActions;
+import org.apache.pdfbox.pdmodel.interactive.action.type.PDURIDictionary;
import org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination.PDDestination;
import org.apache.pdfbox.pdmodel.interactive.documentnavigation.outline.PDDocumentOutline;
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
-
import org.apache.pdfbox.pdmodel.interactive.pagenavigation.PDThread;
import org.apache.pdfbox.pdmodel.interactive.viewerpreferences.PDViewerPreferences;
@@ -551,17 +550,37 @@ public class PDDocumentCatalog implement
}
/**
+ * Returns the PDF specification version this document conforms to.
+ *
+ * @return The PDF version.
+ */
+ public String getVersion()
+ {
+ return root.getNameAsString(COSName.VERSION);
+ }
+
+ /**
+ * Sets the PDF specification version this document conforms to.
+ *
+ * @param version the PDF version (ex. "1.4")
+ */
+ public void setVersion(String version)
+ {
+ root.setName(COSName.VERSION, version);
+ }
+
+ /**
* Returns the page labels descriptor of the document.
- *
+ *
* @return the page labels descriptor of the document.
- *
+ *
* @throws IOException If there is a problem retrieving the page labels.
*/
- public PDPageLabels getPageLabels() throws IOException
+ public PDPageLabels getPageLabels() throws IOException
{
PDPageLabels labels = null;
COSDictionary dict = (COSDictionary) root.getDictionaryObject(COSName.PAGE_LABELS);
- if (dict != null)
+ if (dict != null)
{
labels = new PDPageLabels(document, dict);
}
@@ -573,9 +592,39 @@ public class PDDocumentCatalog implement
*
* @param labels the new page label descriptor to set.
*/
- public void setPageLabels(PDPageLabels labels)
+ public void setPageLabels(PDPageLabels labels)
{
root.setItem(COSName.PAGE_LABELS, labels);
}
+ /**
+ * Get the optional content properties dictionary associated with this document.
+ *
+ * @return the optional properties dictionary or null if it is not present
+ * @since PDF 1.5
+ */
+ public PDOptionalContentProperties getOCProperties()
+ {
+ PDOptionalContentProperties retval = null;
+ COSDictionary dict = (COSDictionary)root.getDictionaryObject(COSName.OCPROPERTIES);
+ if (dict != null)
+ {
+ retval = new PDOptionalContentProperties(dict);
+ }
+
+ return retval;
+ }
+
+ /**
+ * Set the optional content properties dictionary.
+ *
+ * @param ocProperties the optional properties dictionary
+ * @since PDF 1.5
+ */
+ public void setOCProperties(PDOptionalContentProperties ocProperties)
+ {
+ //TODO Check for PDF 1.5 or higher
+ root.setItem(COSName.OCPROPERTIES, ocProperties);
+ }
+
}
Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDResources.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDResources.java?rev=1026228&r1=1026227&r2=1026228&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDResources.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDResources.java Fri Oct 22 07:21:34 2010
@@ -17,7 +17,6 @@
package org.apache.pdfbox.pdmodel;
import java.io.IOException;
-
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
@@ -33,6 +32,7 @@ import org.apache.pdfbox.pdmodel.graphic
import org.apache.pdfbox.pdmodel.graphics.color.PDColorSpaceFactory;
import org.apache.pdfbox.pdmodel.graphics.xobject.PDXObject;
import org.apache.pdfbox.pdmodel.graphics.xobject.PDXObjectImage;
+import org.apache.pdfbox.pdmodel.markedcontent.PDPropertyList;
/**
* This represents a set of resources available at the page/pages/stream level.
@@ -292,4 +292,31 @@ public class PDResources implements COSO
}
resources.setItem( COSName.EXT_G_STATE, dic );
}
+
+ /**
+ * Returns the dictionary mapping resource names to property list dictionaries for marked
+ * content.
+ * @return the property list
+ */
+ public PDPropertyList getProperties()
+ {
+ PDPropertyList retval = null;
+ COSDictionary props = (COSDictionary)resources.getDictionaryObject(COSName.PROPERTIES);
+
+ if (props != null)
+ {
+ retval = new PDPropertyList(props);
+ }
+ return retval;
+ }
+
+ /**
+ * Sets the dictionary mapping resource names to property list dictionaries for marked
+ * content.
+ * @param props the property list
+ */
+ public void setProperties(PDPropertyList props)
+ {
+ resources.setItem(COSName.PROPERTIES, props.getCOSObject());
+ }
}
Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/COSDictionaryMap.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/COSDictionaryMap.java?rev=1026228&r1=1026227&r2=1026228&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/COSDictionaryMap.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/COSDictionaryMap.java Fri Oct 22 07:21:34 2010
@@ -16,6 +16,14 @@
*/
package org.apache.pdfbox.pdmodel.common;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
import org.apache.pdfbox.cos.COSBase;
import org.apache.pdfbox.cos.COSBoolean;
import org.apache.pdfbox.cos.COSDictionary;
@@ -24,14 +32,6 @@ import org.apache.pdfbox.cos.COSInteger;
import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.cos.COSString;
-import java.io.IOException;
-
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
-
/**
* This is a Map that will automatically sync the contents to a COSDictionary.
*
@@ -154,7 +154,7 @@ public class COSDictionaryMap implements
*/
public Set entrySet()
{
- throw new RuntimeException( "Not yet implemented" );
+ return Collections.unmodifiableSet(actuals.entrySet());
}
/**
Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/edit/PDPageContentStream.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/edit/PDPageContentStream.java?rev=1026228&r1=1026227&r2=1026228&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/edit/PDPageContentStream.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/edit/PDPageContentStream.java Fri Oct 22 07:21:34 2010
@@ -18,26 +18,26 @@ package org.apache.pdfbox.pdmodel.edit;
import java.awt.Color;
import java.awt.color.ColorSpace;
+import java.awt.geom.AffineTransform;
import java.awt.geom.PathIterator;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
-
import java.text.NumberFormat;
-
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
-import java.util.HashMap;
+import org.apache.pdfbox.cos.COSArray;
+import org.apache.pdfbox.cos.COSDictionary;
+import org.apache.pdfbox.cos.COSName;
+import org.apache.pdfbox.cos.COSString;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDResources;
-
import org.apache.pdfbox.pdmodel.common.COSStreamArray;
import org.apache.pdfbox.pdmodel.common.PDStream;
-
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.graphics.color.PDColorSpace;
import org.apache.pdfbox.pdmodel.graphics.color.PDDeviceCMYK;
@@ -51,11 +51,6 @@ import org.apache.pdfbox.pdmodel.graphic
import org.apache.pdfbox.pdmodel.graphics.xobject.PDXObjectImage;
import org.apache.pdfbox.util.MapUtil;
-import org.apache.pdfbox.cos.COSArray;
-import org.apache.pdfbox.cos.COSDictionary;
-import org.apache.pdfbox.cos.COSName;
-import org.apache.pdfbox.cos.COSString;
-
/**
* This class will is a convenience for creating page content streams. You MUST
@@ -69,8 +64,8 @@ public class PDPageContentStream
private PDPage page;
private OutputStream output;
private boolean inTextMode = false;
- private Map<PDFont,String> fontMappings = new HashMap<PDFont,String>();
- private Map<PDXObject,String> xobjectMappings = new HashMap<PDXObject,String>();
+ private Map<PDFont,String> fontMappings;
+ private Map<PDXObject,String> xobjectMappings;
private PDResources resources;
private Map fonts;
private Map xobjects;
@@ -115,7 +110,12 @@ public class PDPageContentStream
private static final String BEZIER_312 = "c\n";
private static final String BEZIER_32 = "v\n";
private static final String BEZIER_313 = "y\n";
-
+
+ private static final String MP = "MP\n";
+ private static final String DP = "DP\n";
+ private static final String BMC = "BMC\n";
+ private static final String BDC = "BDC\n";
+ private static final String EMC = "EMC\n";
private static final String SET_STROKING_COLORSPACE = "CS\n";
private static final String SET_NON_STROKING_COLORSPACE = "cs\n";
@@ -161,8 +161,15 @@ public class PDPageContentStream
resources = new PDResources();
page.setResources( resources );
}
+
+ //Fonts including reverse lookup
fonts = resources.getFonts();
- xobjects = resources.getImages();
+ fontMappings = reverseMap(fonts, PDFont.class);
+
+ //XObjects including reverse lookup
+ xobjects = resources.getXObjects();
+ xobjectMappings = reverseMap(xobjects, PDXObject.class);
+
// If request specifies the need to append to the document
if(appendContent)
{
@@ -217,6 +224,17 @@ public class PDPageContentStream
formatDecimal.setGroupingUsed( false );
}
+ private <T> Map<T, String> reverseMap(Map map, Class<T> keyClass)
+ {
+ Map<T, String> reversed = new java.util.HashMap<T, String>();
+ for (Object o : map.entrySet())
+ {
+ Map.Entry entry = (Map.Entry)o;
+ reversed.put(keyClass.cast(entry.getValue()), (String)entry.getKey());
+ }
+ return reversed;
+ }
+
/**
* Begin some text operations.
*
@@ -300,6 +318,20 @@ public class PDPageContentStream
*/
public void drawXObject( PDXObject xobject, float x, float y, float width, float height ) throws IOException
{
+ AffineTransform transform = new AffineTransform(width, 0, 0, height, x, y);
+ drawXObject(xobject, transform);
+ }
+
+ /**
+ * Draw an xobject(form or image) using the given {@link AffineTransform} to position
+ * the xobject.
+ *
+ * @param xobject The xobject to draw.
+ * @param transform the transformation matrix
+ * @throws IOException If there is an error writing to the stream.
+ */
+ public void drawXObject( PDXObject xobject, AffineTransform transform ) throws IOException
+ {
String xObjectPrefix = null;
if( xobject instanceof PDXObjectImage )
{
@@ -318,19 +350,20 @@ public class PDPageContentStream
xobjects.put( objMapping, xobject );
}
saveGraphicsState();
- concatenate2CTM(width, 0, 0, height, x, y);
+ appendRawCommands( SPACE );
+ concatenate2CTM(transform);
appendRawCommands( SPACE );
appendRawCommands( "/" );
appendRawCommands( objMapping );
appendRawCommands( SPACE );
appendRawCommands( XOBJECT_DO );
- appendRawCommands( SPACE );
restoreGraphicsState();
}
+
/**
* The Td operator.
- * A current text matrix will be replaced with a new one (1 0 0 1 x y).
+ * A current text matrix will be replaced with a new one (1 0 0 1 x y).
* @param x The x coordinate.
* @param y The y coordinate.
* @throws IOException If there is an error writing to the stream.
@@ -350,7 +383,7 @@ public class PDPageContentStream
/**
* The Tm operator. Sets the text matrix to the given values.
- * A current text matrix will be replaced with the new one.
+ * A current text matrix will be replaced with the new one.
* @param a The a value of the matrix.
* @param b The b value of the matrix.
* @param c The c value of the matrix.
@@ -381,8 +414,20 @@ public class PDPageContentStream
}
/**
+ * The Tm operator. Sets the text matrix to the given values.
+ * A current text matrix will be replaced with the new one.
+ * @param matrix the transformation matrix
+ * @throws IOException If there is an error writing to the stream.
+ */
+ public void setTextMatrix(AffineTransform matrix) throws IOException
+ {
+ appendMatrix(matrix);
+ appendRawCommands(SET_TEXT_MATRIX);
+ }
+
+ /**
* The Tm operator. Sets the text matrix to the given scaling and translation values.
- * A current text matrix will be replaced with the new one.
+ * A current text matrix will be replaced with the new one.
* @param sx The scaling factor in x-direction.
* @param sy The scaling factor in y-direction.
* @param tx The translation value in x-direction.
@@ -396,7 +441,7 @@ public class PDPageContentStream
/**
* The Tm operator. Sets the text matrix to the given translation values.
- * A current text matrix will be replaced with the new one.
+ * A current text matrix will be replaced with the new one.
* @param tx The translation value in x-direction.
* @param ty The translation value in y-direction.
* @throws IOException If there is an error writing to the stream.
@@ -408,7 +453,7 @@ public class PDPageContentStream
/**
* The Tm operator. Sets the text matrix to the given rotation and translation values.
- * A current text matrix will be replaced with the new one.
+ * A current text matrix will be replaced with the new one.
* @param angle The angle used for the counterclockwise rotation in radians.
* @param tx The translation value in x-direction.
* @param ty The translation value in y-direction.
@@ -449,6 +494,18 @@ public class PDPageContentStream
}
/**
+ * The Cm operator. Concatenates the current transformation matrix with the given
+ * {@link AffineTransform}.
+ * @param at the transformation matrix
+ * @throws IOException If there is an error writing to the stream.
+ */
+ public void concatenate2CTM(AffineTransform at) throws IOException
+ {
+ appendMatrix(at);
+ appendRawCommands(CONCATENATE_MATRIX);
+ }
+
+ /**
* This will draw a string at the current location on the screen.
*
* @param text The text to draw.
@@ -858,7 +915,7 @@ public class PDPageContentStream
}
/**
- * Append a cubic Bézier curve to the current path. The curve extends from the current
+ * Append a cubic Bézier curve to the current path. The curve extends from the current
* point to the point (x3 , y3 ), using (x1 , y1 ) and (x2 , y2 ) as the Bézier control points
* @param x1 x coordinate of the point 1
* @param y1 y coordinate of the point 1
@@ -886,7 +943,7 @@ public class PDPageContentStream
}
/**
- * Append a cubic Bézier curve to the current path. The curve extends from the current
+ * Append a cubic Bézier curve to the current path. The curve extends from the current
* point to the point (x3 , y3 ), using the current point and (x2 , y2 ) as the Bézier control points
* @param x2 x coordinate of the point 2
* @param y2 y coordinate of the point 2
@@ -908,7 +965,7 @@ public class PDPageContentStream
}
/**
- * Append a cubic Bézier curve to the current path. The curve extends from the current
+ * Append a cubic Bézier curve to the current path. The curve extends from the current
* point to the point (x3 , y3 ), using (x1 , y1 ) and (x3 , y3 ) as the Bézier control points
* @param x1 x coordinate of the point 1
* @param y1 y coordinate of the point 1
@@ -928,10 +985,10 @@ public class PDPageContentStream
appendRawCommands( SPACE );
appendRawCommands( BEZIER_313 );
}
-
-
+
+
/**
- * Add a line to the given coordinate.
+ * Add a line to the given coordinate.
*
* @param x The x coordinate.
* @param y The y coordinate.
@@ -979,7 +1036,7 @@ public class PDPageContentStream
// lineTo
lineTo(xEnd, yEnd);
}
-
+
/**
* Draw a line on the page using the current non stroking color and the current line width.
*
@@ -995,7 +1052,7 @@ public class PDPageContentStream
// stroke
stroke();
}
-
+
/**
* Add a polygon to the current path.
* @param x x coordinate of each points
@@ -1021,7 +1078,7 @@ public class PDPageContentStream
}
closeSubPath();
}
-
+
/**
* Draw a polygon on the page using the current non stroking color.
* @param x x coordinate of each points
@@ -1045,27 +1102,27 @@ public class PDPageContentStream
addPolygon(x, y);
fill(PathIterator.WIND_NON_ZERO);
}
-
+
/**
* Stroke the path.
*/
- public void stroke() throws IOException
+ public void stroke() throws IOException
{
appendRawCommands( STROKE );
}
-
+
/**
* Close and stroke the path.
*/
- public void closeAndStroke() throws IOException
+ public void closeAndStroke() throws IOException
{
appendRawCommands( CLOSE_STROKE );
}
-
+
/**
* Fill the path.
*/
- public void fill(int windingRule) throws IOException
+ public void fill(int windingRule) throws IOException
{
if (windingRule == PathIterator.WIND_NON_ZERO)
{
@@ -1075,17 +1132,17 @@ public class PDPageContentStream
{
appendRawCommands( FILL_EVEN_ODD );
}
- else
+ else
{
throw new IOException( "Error: unknown value for winding rule" );
}
-
+
}
/**
* Close subpath.
*/
- public void closeSubPath() throws IOException
+ public void closeSubPath() throws IOException
{
appendRawCommands( CLOSE_SUBPATH );
}
@@ -1093,7 +1150,7 @@ public class PDPageContentStream
/**
* Clip path.
*/
- public void clipPath(int windingRule) throws IOException
+ public void clipPath(int windingRule) throws IOException
{
if (windingRule == PathIterator.WIND_NON_ZERO)
{
@@ -1105,7 +1162,7 @@ public class PDPageContentStream
appendRawCommands( CLIP_PATH_EVEN_ODD );
appendRawCommands( NOP );
}
- else
+ else
{
throw new IOException( "Error: unknown value for winding rule" );
}
@@ -1125,10 +1182,47 @@ public class PDPageContentStream
}
/**
+ * Begin a marked content sequence.
+ * @param tag the tag
+ * @throws IOException if an I/O error occurs
+ */
+ public void beginMarkedContentSequence(COSName tag) throws IOException
+ {
+ appendCOSName(tag);
+ appendRawCommands(SPACE);
+ appendRawCommands(BMC);
+ }
+
+ /**
+ * Begin a marked content sequence with a reference to an entry in the page resources'
+ * Properties dictionary.
+ * @param tag the tag
+ * @param propsName the properties reference
+ * @throws IOException if an I/O error occurs
+ */
+ public void beginMarkedContentSequence(COSName tag, COSName propsName) throws IOException
+ {
+ appendCOSName(tag);
+ appendRawCommands(SPACE);
+ appendCOSName(propsName);
+ appendRawCommands(SPACE);
+ appendRawCommands(BDC);
+ }
+
+ /**
+ * End a marked content sequence.
+ * @throws IOException if an I/O error occurs
+ */
+ public void endMarkedContentSequence() throws IOException
+ {
+ appendRawCommands(EMC);
+ }
+
+ /**
* q operator. Saves the current graphics state.
* @throws IOException If an error occurs while writing to the stream.
*/
- public void saveGraphicsState() throws IOException
+ public void saveGraphicsState() throws IOException
{
appendRawCommands( SAVE_GRAPHICS_STATE);
}
@@ -1137,7 +1231,7 @@ public class PDPageContentStream
* Q operator. Restores the current graphics state.
* @throws IOException If an error occurs while writing to the stream.
*/
- public void restoreGraphicsState() throws IOException
+ public void restoreGraphicsState() throws IOException
{
appendRawCommands( RESTORE_GRAPHICS_STATE );
}
@@ -1177,6 +1271,27 @@ public class PDPageContentStream
}
/**
+ * This will append a {@link COSName} to the content stream.
+ * @param name the name
+ * @throws IOException If an error occurs while writing to the stream.
+ */
+ public void appendCOSName(COSName name) throws IOException
+ {
+ name.writePDF(output);
+ }
+
+ private void appendMatrix(AffineTransform transform) throws IOException
+ {
+ double[] values = new double[6];
+ transform.getMatrix(values);
+ for (double v : values)
+ {
+ appendRawCommands(formatDecimal.format(v));
+ appendRawCommands(SPACE);
+ }
+ }
+
+ /**
* Close the content stream. This must be called when you are done with this
* object.
* @throws IOException If the underlying stream has a problem being written to.
Added: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/optionalcontent/PDOptionalContentGroup.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/optionalcontent/PDOptionalContentGroup.java?rev=1026228&view=auto
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/optionalcontent/PDOptionalContentGroup.java (added)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/optionalcontent/PDOptionalContentGroup.java Fri Oct 22 07:21:34 2010
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.pdfbox.pdmodel.graphics.optionalcontent;
+
+import org.apache.pdfbox.cos.COSBase;
+import org.apache.pdfbox.cos.COSDictionary;
+import org.apache.pdfbox.cos.COSName;
+import org.apache.pdfbox.pdmodel.common.COSObjectable;
+
+/**
+ * This class represents an optional content group (OCG).
+ *
+ * @since PDF 1.5
+ * @version $Revision$
+ */
+public class PDOptionalContentGroup implements COSObjectable
+{
+
+ private COSDictionary ocg;
+
+ /**
+ * Creates a new optional content group (OCG).
+ * @param name the name of the content group
+ */
+ public PDOptionalContentGroup(String name)
+ {
+ this.ocg = new COSDictionary();
+ this.ocg.setItem(COSName.TYPE, COSName.OCG);
+ setName(name);
+ }
+
+ /**
+ * Creates a new instance based on a given {@link COSDictionary}.
+ * @param dict the dictionary
+ */
+ public PDOptionalContentGroup(COSDictionary dict)
+ {
+ if (!dict.getItem(COSName.TYPE).equals(COSName.OCG))
+ {
+ throw new IllegalArgumentException(
+ "Provided dictionary is not of type '" + COSName.OCG + "'");
+ }
+ this.ocg = dict;
+ }
+
+ /** {@inheritDoc} */
+ public COSBase getCOSObject()
+ {
+ return this.ocg;
+ }
+
+ /**
+ * Returns the name of the optional content group.
+ * @return the name
+ */
+ public String getName()
+ {
+ return this.ocg.getString(COSName.NAME);
+ }
+
+ /**
+ * Sets the name of the optional content group.
+ * @param name the name
+ */
+ public void setName(String name)
+ {
+ this.ocg.setString(COSName.NAME, name);
+ }
+
+ //TODO Add support for "Intent" and "Usage"
+
+ /** {@inheritDoc} */
+ @Override
+ public String toString()
+ {
+ return super.toString() + " (" + getName() + ")";
+ }
+
+}
Propchange: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/optionalcontent/PDOptionalContentGroup.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/optionalcontent/PDOptionalContentGroup.java
------------------------------------------------------------------------------
svn:keywords = Id
Added: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/optionalcontent/PDOptionalContentProperties.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/optionalcontent/PDOptionalContentProperties.java?rev=1026228&view=auto
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/optionalcontent/PDOptionalContentProperties.java (added)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/optionalcontent/PDOptionalContentProperties.java Fri Oct 22 07:21:34 2010
@@ -0,0 +1,366 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.pdfbox.pdmodel.graphics.optionalcontent;
+
+import java.util.Collection;
+
+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.cos.COSObject;
+import org.apache.pdfbox.pdmodel.common.COSObjectable;
+
+/**
+ * This class represents the optional content properties dictionary.
+ *
+ * @since PDF 1.5
+ * @version $Revision$
+ */
+public class PDOptionalContentProperties implements COSObjectable
+{
+
+ /**
+ * Enumeration for the BaseState dictionary entry on the "D" dictionary.
+ */
+ public static enum BaseState
+ {
+
+ /** The "ON" value. */
+ ON(COSName.ON),
+ /** The "OFF" value. */
+ OFF(COSName.OFF),
+ /** The "Unchanged" value. */
+ UNCHANGED(COSName.UNCHANGED);
+
+ private COSName name;
+
+ private BaseState(COSName value)
+ {
+ this.name = value;
+ }
+
+ /**
+ * Returns the PDF name for the state.
+ * @return the name of the state
+ */
+ public COSName getName()
+ {
+ return this.name;
+ }
+
+ /**
+ * Returns the base state represented by the given {@link COSName}.
+ * @param state the state name
+ * @return the state enum value
+ */
+ public static BaseState valueOf(COSName state)
+ {
+ if (state == null)
+ {
+ return BaseState.ON;
+ }
+ return BaseState.valueOf(state.getName().toUpperCase());
+ }
+
+ }
+
+ private COSDictionary dict;
+
+ /**
+ * Creates a new optional content properties dictionary.
+ */
+ public PDOptionalContentProperties()
+ {
+ this.dict = new COSDictionary();
+ this.dict.setItem(COSName.OCGS, new COSArray());
+ this.dict.setItem(COSName.D, new COSDictionary());
+ }
+
+ /**
+ * Creates a new instance based on a given {@link COSDictionary}.
+ * @param props the dictionary
+ */
+ public PDOptionalContentProperties(COSDictionary props)
+ {
+ this.dict = props;
+ }
+
+ /** {@inheritDoc} */
+ public COSBase getCOSObject()
+ {
+ return this.dict;
+ }
+
+ private COSArray getOCGs()
+ {
+ COSArray ocgs = (COSArray)this.dict.getItem(COSName.OCGS);
+ if (ocgs == null)
+ {
+ ocgs = new COSArray();
+ this.dict.setItem(COSName.OCGS, ocgs); //OCGs is required
+ }
+ return ocgs;
+ }
+
+ private COSDictionary getD()
+ {
+ COSDictionary d = (COSDictionary)this.dict.getDictionaryObject(COSName.D);
+ if (d == null)
+ {
+ d = new COSDictionary();
+ this.dict.setItem(COSName.D, d); //D is required
+ }
+ return d;
+ }
+
+ /**
+ * Returns the optional content group of the given name.
+ * @param name the group name
+ * @return the optional content group or null, if there is no such group
+ */
+ public PDOptionalContentGroup getGroup(String name)
+ {
+ COSArray ocgs = getOCGs();
+ for (COSBase o : ocgs)
+ {
+ COSDictionary ocg = toDictionary(o);
+ String groupName = ocg.getString(COSName.NAME);
+ if (groupName.equals(name))
+ {
+ return new PDOptionalContentGroup(ocg);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Adds an optional content group (OCG).
+ * @param ocg the optional content group
+ */
+ public void addGroup(PDOptionalContentGroup ocg)
+ {
+ COSArray ocgs = getOCGs();
+ ocgs.add(ocg.getCOSObject());
+
+ //By default, add new group to the "Order" entry so it appears in the user interface
+ COSArray order = (COSArray)getD().getDictionaryObject(COSName.ORDER);
+ if (order == null)
+ {
+ order = new COSArray();
+ getD().setItem(COSName.ORDER, order);
+ }
+ order.add(ocg);
+ }
+
+ /**
+ * Returns the collection of all optional content groups.
+ * @return the optional content groups
+ */
+ public Collection<PDOptionalContentGroup> getOptionalContentGroups()
+ {
+ Collection<PDOptionalContentGroup> coll = new java.util.ArrayList<PDOptionalContentGroup>();
+ COSArray ocgs = getOCGs();
+ for (COSBase base : ocgs)
+ {
+ COSObject obj = (COSObject)base; //Children must be indirect references
+ coll.add(new PDOptionalContentGroup((COSDictionary)obj.getObject()));
+ }
+ return coll;
+ }
+
+ /**
+ * Returns the base state for optional content groups.
+ * @return the base state
+ */
+ public BaseState getBaseState()
+ {
+ COSDictionary d = getD();
+ COSName name = (COSName)d.getItem(COSName.BASE_STATE);
+ return BaseState.valueOf(name);
+ }
+
+ /**
+ * Sets the base state for optional content groups.
+ * @param state the base state
+ */
+ public void setBaseState(BaseState state)
+ {
+ COSDictionary d = getD();
+ d.setItem(COSName.BASE_STATE, state.getName());
+ }
+
+ /**
+ * Lists all optional content group names.
+ * @return an array of all names
+ */
+ public String[] getGroupNames()
+ {
+ COSArray ocgs = (COSArray)dict.getDictionaryObject(COSName.OCGS);
+ int size = ocgs.size();
+ String[] groups = new String[size];
+ for (int i = 0; i < size; i++)
+ {
+ COSBase obj = (COSBase)ocgs.get(i);
+ COSDictionary ocg = toDictionary(obj);
+ groups[i] = ocg.getString(COSName.NAME);
+ }
+ return groups;
+ }
+
+ /**
+ * Indicates whether a particular optional content group is found in the PDF file.
+ * @param groupName the group name
+ * @return true if the group exists, false otherwise
+ */
+ public boolean hasGroup(String groupName)
+ {
+ String[] layers = getGroupNames();
+ for (String layer : layers)
+ {
+ if (layer.equals(groupName))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Indicates whether an optional content group is enabled.
+ * @param groupName the group name
+ * @return true if the group is enabled
+ */
+ public boolean isGroupEnabled(String groupName)
+ {
+ //TODO handle Optional Content Configuration Dictionaries,
+ //i.e. OCProperties/Configs
+
+ COSDictionary d = getD();
+ COSArray on = (COSArray)d.getDictionaryObject(COSName.ON);
+ if (on != null)
+ {
+ for (COSBase o : on)
+ {
+ COSDictionary group = toDictionary(o);
+ String name = group.getString(COSName.NAME);
+ if (name.equals(groupName))
+ {
+ return true;
+ }
+ }
+ }
+
+ COSArray off = (COSArray)d.getDictionaryObject(COSName.OFF);
+ if (off != null)
+ {
+ for (COSBase o : off)
+ {
+ COSDictionary group = toDictionary(o);
+ String name = group.getString(COSName.NAME);
+ if (name.equals(groupName))
+ {
+ return false;
+ }
+ }
+ }
+
+ BaseState baseState = getBaseState();
+ boolean enabled = !baseState.equals(BaseState.OFF);
+ //TODO What to do with BaseState.Unchanged?
+ return enabled;
+ }
+
+ private COSDictionary toDictionary(COSBase o)
+ {
+ if (o instanceof COSObject)
+ {
+ return (COSDictionary)((COSObject)o).getObject();
+ }
+ else
+ {
+ return (COSDictionary)o;
+ }
+ }
+
+ /**
+ * Enables or disables an optional content group.
+ * @param groupName the group name
+ * @param enable true to enable, false to disable
+ * @return true if the group already had an on or off setting, false otherwise
+ */
+ public boolean setGroupEnabled(String groupName, boolean enable)
+ {
+ COSDictionary d = getD();
+ COSArray on = (COSArray)d.getDictionaryObject(COSName.ON);
+ if (on == null)
+ {
+ on = new COSArray();
+ d.setItem(COSName.ON, on);
+ }
+ COSArray off = (COSArray)d.getDictionaryObject(COSName.OFF);
+ if (off == null)
+ {
+ off = new COSArray();
+ d.setItem(COSName.OFF, off);
+ }
+
+ boolean found = false;
+ for (COSBase o : on)
+ {
+ COSDictionary group = toDictionary(o);
+ String name = group.getString(COSName.NAME);
+ if (!enable && name.equals(groupName))
+ {
+ //disable group
+ on.remove(group);
+ off.add(group);
+ found = true;
+ break;
+ }
+ }
+ for (COSBase o : off)
+ {
+ COSDictionary group = toDictionary(o);
+ String name = group.getString(COSName.NAME);
+ if (enable && name.equals(groupName))
+ {
+ //enable group
+ off.remove(group);
+ on.add(group);
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ {
+ PDOptionalContentGroup ocg = getGroup(groupName);
+ if (enable)
+ {
+ on.add(ocg.getCOSObject());
+ }
+ else
+ {
+ off.add(ocg.getCOSObject());
+ }
+ }
+ return found;
+ }
+
+
+}
Propchange: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/optionalcontent/PDOptionalContentProperties.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/optionalcontent/PDOptionalContentProperties.java
------------------------------------------------------------------------------
svn:keywords = Id
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=1026228&r1=1026227&r2=1026228&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 Fri Oct 22 07:21:34 2010
@@ -16,12 +16,14 @@
*/
package org.apache.pdfbox.pdmodel.graphics.xobject;
+import java.awt.geom.AffineTransform;
+
import org.apache.pdfbox.cos.COSArray;
import org.apache.pdfbox.cos.COSDictionary;
+import org.apache.pdfbox.cos.COSFloat;
import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.cos.COSNumber;
import org.apache.pdfbox.cos.COSStream;
-
import org.apache.pdfbox.pdmodel.PDResources;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.common.PDStream;
@@ -145,13 +147,13 @@ public class PDXObjectForm extends PDXOb
getCOSStream().setItem( COSName.BBOX, bbox.getCOSArray() );
}
}
-
+
/**
* 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()
+ public Matrix getMatrix()
{
Matrix retval = null;
COSArray array = (COSArray)getCOSStream().getDictionaryObject( COSName.MATRIX );
@@ -167,5 +169,21 @@ public class PDXObjectForm extends PDXOb
}
return retval;
}
-
+
+ /**
+ * Sets the optional Matrix entry for the form XObject.
+ * @param transform the transformation matrix
+ */
+ public void setMatrix(AffineTransform transform)
+ {
+ COSArray matrix = new COSArray();
+ double[] values = new double[6];
+ transform.getMatrix(values);
+ for (double v : values)
+ {
+ matrix.add(new COSFloat((float)v));
+ }
+ getCOSStream().setItem(COSName.MATRIX, matrix);
+ }
+
}
Added: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/markedcontent/PDPropertyList.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/markedcontent/PDPropertyList.java?rev=1026228&view=auto
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/markedcontent/PDPropertyList.java (added)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/markedcontent/PDPropertyList.java Fri Oct 22 07:21:34 2010
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.pdfbox.pdmodel.markedcontent;
+
+import org.apache.pdfbox.cos.COSBase;
+import org.apache.pdfbox.cos.COSDictionary;
+import org.apache.pdfbox.cos.COSName;
+import org.apache.pdfbox.pdmodel.common.COSObjectable;
+import org.apache.pdfbox.pdmodel.graphics.optionalcontent.PDOptionalContentGroup;
+
+/**
+ * This class represents a property list used for the marked content feature to map a resource name
+ * to a dictionary.
+ *
+ * @since PDF 1.2
+ * @version $Revision$
+ */
+public class PDPropertyList implements COSObjectable
+{
+
+ private COSDictionary props;
+
+ /**
+ * Creates a new property list.
+ */
+ public PDPropertyList()
+ {
+ this.props = new COSDictionary();
+ }
+
+ /**
+ * Creates a new instance based on a given {@link COSDictionary}.
+ * @param dict the dictionary
+ */
+ public PDPropertyList(COSDictionary dict)
+ {
+ this.props = dict;
+ }
+
+ /** {@inheritDoc} */
+ public COSBase getCOSObject()
+ {
+ return this.props;
+ }
+
+ /**
+ * Returns the optional content group belonging to the given resource name.
+ * @param name the resource name
+ * @return the optional content group or null if the group was not found
+ */
+ public PDOptionalContentGroup getOptionalContentGroup(COSName name)
+ {
+ COSDictionary dict = (COSDictionary)props.getDictionaryObject(name);
+ if (dict != null)
+ {
+ if (COSName.OCG.equals(dict.getItem(COSName.TYPE)))
+ {
+ return new PDOptionalContentGroup(dict);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Puts a mapping from a resource name to an optional content group.
+ * @param name the resource name
+ * @param ocg the optional content group
+ */
+ public void putMapping(COSName name, PDOptionalContentGroup ocg)
+ {
+ putMapping(name, (COSDictionary)ocg.getCOSObject());
+ }
+
+ private void putMapping(COSName name, COSDictionary dict)
+ {
+ props.setItem(name, dict);
+ }
+
+}
Propchange: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/markedcontent/PDPropertyList.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/markedcontent/PDPropertyList.java
------------------------------------------------------------------------------
svn:keywords = Id
Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/persistence/util/COSObjectKey.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/persistence/util/COSObjectKey.java?rev=1026228&r1=1026227&r2=1026228&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/persistence/util/COSObjectKey.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/persistence/util/COSObjectKey.java Fri Oct 22 07:21:34 2010
@@ -24,7 +24,7 @@ import org.apache.pdfbox.cos.COSObject;
* @author Michael Traut
* @version $Revision: 1.5 $
*/
-public class COSObjectKey
+public class COSObjectKey implements Comparable<COSObjectKey>
{
private long number;
private long generation;
@@ -113,4 +113,33 @@ public class COSObjectKey
{
return "" + getNumber() + " " + getGeneration() + " R";
}
+
+ /** {@inheritDoc} */
+ public int compareTo(COSObjectKey other)
+ {
+ if (getNumber() < other.getNumber())
+ {
+ return -1;
+ }
+ else if (getNumber() > other.getNumber())
+ {
+ return 1;
+ }
+ else
+ {
+ if (getGeneration() < other.getGeneration())
+ {
+ return -1;
+ }
+ else if (getGeneration() > other.getGeneration())
+ {
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+ }
+
}
Added: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/LayerUtility.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/LayerUtility.java?rev=1026228&view=auto
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/LayerUtility.java (added)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/LayerUtility.java Fri Oct 22 07:21:34 2010
@@ -0,0 +1,320 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.pdfbox.util;
+
+import java.awt.geom.AffineTransform;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.fontbox.util.BoundingBox;
+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.cos.COSStream;
+import org.apache.pdfbox.pdmodel.PDDocument;
+import org.apache.pdfbox.pdmodel.PDDocumentCatalog;
+import org.apache.pdfbox.pdmodel.PDPage;
+import org.apache.pdfbox.pdmodel.PDResources;
+import org.apache.pdfbox.pdmodel.common.PDRectangle;
+import org.apache.pdfbox.pdmodel.common.PDStream;
+import org.apache.pdfbox.pdmodel.edit.PDPageContentStream;
+import org.apache.pdfbox.pdmodel.graphics.optionalcontent.PDOptionalContentGroup;
+import org.apache.pdfbox.pdmodel.graphics.optionalcontent.PDOptionalContentProperties;
+import org.apache.pdfbox.pdmodel.graphics.xobject.PDXObjectForm;
+import org.apache.pdfbox.pdmodel.markedcontent.PDPropertyList;
+
+/**
+ * This class allows to import pages as Form XObjects into a PDF file and use them to create
+ * layers (optional content groups).
+ *
+ * @version $Revision$
+ */
+public class LayerUtility
+{
+ private static final boolean DEBUG = true;
+
+ private PDDocument targetDoc;
+ private PDFCloneUtility cloner;
+
+ /**
+ * Creates a new instance.
+ * @param document the PDF document to modify
+ */
+ public LayerUtility(PDDocument document)
+ {
+ this.targetDoc = document;
+ this.cloner = new PDFCloneUtility(document);
+ }
+
+ /**
+ * Returns the PDF document we work on.
+ * @return the PDF document
+ */
+ public PDDocument getDocument()
+ {
+ return this.targetDoc;
+ }
+
+ /**
+ * Some applications may not wrap their page content in a save/restore (q/Q) pair which can
+ * lead to problems with coordinate system transformations when content is appended. This
+ * method lets you add a q/Q pair around the existing page's content.
+ * @param page the page
+ * @throws IOException if an I/O error occurs
+ */
+ public void wrapInSaveRestore(PDPage page) throws IOException
+ {
+ COSDictionary saveGraphicsStateDic = new COSDictionary();
+ COSStream saveGraphicsStateStream = new COSStream(saveGraphicsStateDic,
+ getDocument().getDocument().getScratchFile());
+ OutputStream saveStream = saveGraphicsStateStream.createUnfilteredStream();
+ saveStream.write("q\n".getBytes());
+ saveStream.flush();
+
+ COSStream restoreGraphicsStateStream = new COSStream(saveGraphicsStateDic,
+ getDocument().getDocument().getScratchFile());
+ OutputStream restoreStream = restoreGraphicsStateStream.createUnfilteredStream();
+ restoreStream.write("Q\n".getBytes());
+ restoreStream.flush();
+
+ //Wrap the existing page's content in a save/restore pair (q/Q) to have a controlled
+ //environment to add additional content.
+ COSDictionary pageDictionary = page.getCOSDictionary();
+ COSBase contents = pageDictionary.getDictionaryObject(COSName.CONTENTS);
+ if (contents instanceof COSStream)
+ {
+ COSStream contentsStream = (COSStream)contents;
+
+ COSArray array = new COSArray();
+ array.add(saveGraphicsStateStream);
+ array.add(contentsStream);
+ array.add(restoreGraphicsStateStream);
+
+ pageDictionary.setItem(COSName.CONTENTS, array);
+ }
+ else if( contents instanceof COSArray )
+ {
+ COSArray contentsArray = (COSArray)contents;
+
+ contentsArray.add(0, saveGraphicsStateStream);
+ contentsArray.add(restoreGraphicsStateStream);
+ }
+ else
+ {
+ throw new IOException("Contents are unknown type: " + contents.getClass().getName());
+ }
+ }
+
+ /**
+ * Imports a page from some PDF file as a Form XObject so it can be placed on another page
+ * in the target document.
+ * @param sourceDoc the source PDF document that contains the page to be copied
+ * @param pageNumber the page number of the page to be copied
+ * @return a Form XObject containing the original page's content
+ * @throws IOException if an I/O error occurs
+ */
+ public PDXObjectForm importPageAsForm(PDDocument sourceDoc, int pageNumber) throws IOException
+ {
+ PDPage page = (PDPage)sourceDoc.getDocumentCatalog().getAllPages().get(pageNumber);
+ return importPageAsForm(sourceDoc, page);
+ }
+
+ private static final Set<String> PAGE_TO_FORM_FILTER = new java.util.HashSet<String>(
+ Arrays.asList(new String[] {"Group", "LastModified", "Metadata"}));
+
+ /**
+ * Imports a page from some PDF file as a Form XObject so it can be placed on another page
+ * in the target document.
+ * @param sourceDoc the source PDF document that contains the page to be copied
+ * @param page the page in the source PDF document to be copied
+ * @return a Form XObject containing the original page's content
+ * @throws IOException if an I/O error occurs
+ */
+ public PDXObjectForm importPageAsForm(PDDocument sourceDoc, PDPage page) throws IOException
+ {
+ COSStream pageStream = (COSStream)page.getContents().getCOSObject();
+ PDStream newStream = new PDStream(targetDoc,
+ pageStream.getUnfilteredStream(), false);
+ PDXObjectForm form = new PDXObjectForm(newStream);
+
+ //Copy resources
+ PDResources pageRes = page.findResources();
+ PDResources formRes = new PDResources();
+ cloner.cloneMerge(pageRes, formRes);
+ form.setResources(formRes);
+
+ //Transfer some values from page to form
+ transferDict(page.getCOSDictionary(), form.getCOSStream(), PAGE_TO_FORM_FILTER, true);
+
+ Matrix matrix = form.getMatrix();
+ AffineTransform at = matrix != null ? matrix.createAffineTransform() : new AffineTransform();
+ PDRectangle mediaBox = page.findMediaBox();
+ PDRectangle cropBox = page.findCropBox();
+ PDRectangle viewBox = (cropBox != null ? cropBox : mediaBox);
+
+ //Handle the /Rotation entry on the page dict
+ int rotation = getNormalizedRotation(page);
+
+ //Transform to FOP's user space
+ //at.scale(1 / viewBox.getWidth(), 1 / viewBox.getHeight());
+ at.translate(mediaBox.getLowerLeftX() - viewBox.getLowerLeftX(),
+ mediaBox.getLowerLeftY() - viewBox.getLowerLeftY());
+ switch (rotation)
+ {
+ case 90:
+ at.scale(viewBox.getWidth() / viewBox.getHeight(), viewBox.getHeight() / viewBox.getWidth());
+ at.translate(0, viewBox.getWidth());
+ at.rotate(-Math.PI / 2.0);
+ break;
+ case 180:
+ at.translate(viewBox.getWidth(), viewBox.getHeight());
+ at.rotate(-Math.PI);
+ break;
+ case 270:
+ at.scale(viewBox.getWidth() / viewBox.getHeight(), viewBox.getHeight() / viewBox.getWidth());
+ at.translate(viewBox.getHeight(), 0);
+ at.rotate(-Math.PI * 1.5);
+ default:
+ //no additional transformations necessary
+ }
+ //Compensate for Crop Boxes not starting at 0,0
+ at.translate(-viewBox.getLowerLeftX(), -viewBox.getLowerLeftY());
+ if (!at.isIdentity())
+ {
+ form.setMatrix(at);
+ }
+
+ BoundingBox bbox = new BoundingBox();
+ bbox.setLowerLeftX(viewBox.getLowerLeftX());
+ bbox.setLowerLeftY(viewBox.getLowerLeftY());
+ bbox.setUpperRightX(viewBox.getUpperRightX());
+ bbox.setUpperRightY(viewBox.getUpperRightY());
+ form.setBBox(new PDRectangle(bbox));
+
+ return form;
+ }
+
+ /**
+ * Places the given form over the existing content of the indicated page (like an overlay).
+ * The form is enveloped in a marked content section to indicate that it's part of an
+ * optional content group (OCG), here used as a layer. This optional group is returned and
+ * can be enabled and disabled through methods on {@link PDOptionalContentProperties}.
+ * @param targetPage the target page
+ * @param form the form to place
+ * @param transform the transformation matrix that controls the placement
+ * @param layerName the name for the layer/OCG to produce
+ * @return the optional content group that was generated for the form usage
+ * @throws IOException if an I/O error occurs
+ */
+ public PDOptionalContentGroup appendFormAsLayer(PDPage targetPage,
+ PDXObjectForm form, AffineTransform transform,
+ String layerName) throws IOException
+ {
+ PDDocumentCatalog catalog = targetDoc.getDocumentCatalog();
+ PDOptionalContentProperties ocprops = catalog.getOCProperties();
+ if (ocprops == null)
+ {
+ ocprops = new PDOptionalContentProperties();
+ catalog.setOCProperties(ocprops);
+ }
+ if (ocprops.hasGroup(layerName))
+ {
+ throw new IllegalArgumentException("Optional group (layer) already exists: " + layerName);
+ }
+
+ PDOptionalContentGroup layer = new PDOptionalContentGroup(layerName);
+ ocprops.addGroup(layer);
+
+ PDResources resources = targetPage.findResources();
+ PDPropertyList props = resources.getProperties();
+ if (props == null)
+ {
+ props = new PDPropertyList();
+ resources.setProperties(props);
+ }
+
+ //Find first free resource name with the pattern "MC<index>"
+ int index = 0;
+ PDOptionalContentGroup ocg;
+ COSName resourceName;
+ do
+ {
+ resourceName = COSName.getPDFName("MC" + index);
+ ocg = props.getOptionalContentGroup(resourceName);
+ index++;
+ } while (ocg != null);
+ //Put mapping for our new layer/OCG
+ props.putMapping(resourceName, layer);
+
+ PDPageContentStream contentStream = new PDPageContentStream(
+ targetDoc, targetPage, true, !DEBUG);
+ contentStream.beginMarkedContentSequence(COSName.OC, resourceName);
+ contentStream.drawXObject(form, transform);
+ contentStream.endMarkedContentSequence();
+ contentStream.close();
+
+ return layer;
+ }
+
+ private void transferDict(COSDictionary orgDict, COSDictionary targetDict,
+ Set<String> filter, boolean inclusive) throws IOException
+ {
+ for (Map.Entry<COSName, COSBase> entry : orgDict.entrySet())
+ {
+ COSName key = entry.getKey();
+ if (inclusive && !filter.contains(key.getName()))
+ {
+ continue;
+ }
+ else if (!inclusive && filter.contains(key.getName()))
+ {
+ continue;
+ }
+ targetDict.setItem(key,
+ cloner.cloneForNewDocument(entry.getValue()));
+ }
+ }
+
+ private static int getNormalizedRotation(PDPage page)
+ {
+ //Handle the /Rotation entry on the page dict
+ int rotation = page.findRotation();
+ while (rotation >= 360)
+ {
+ rotation -= 360;
+ }
+ if (rotation < 0)
+ {
+ rotation = 0;
+ }
+ switch (rotation)
+ {
+ case 90:
+ case 180:
+ case 270:
+ return rotation;
+ default:
+ return 0;
+ }
+ }
+
+
+}
Propchange: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/LayerUtility.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/LayerUtility.java
------------------------------------------------------------------------------
svn:keywords = Id
Added: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/PDFCloneUtility.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/PDFCloneUtility.java?rev=1026228&view=auto
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/PDFCloneUtility.java (added)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/PDFCloneUtility.java Fri Oct 22 07:21:34 2010
@@ -0,0 +1,244 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.pdfbox.util;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+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.cos.COSObject;
+import org.apache.pdfbox.cos.COSStream;
+import org.apache.pdfbox.pdmodel.PDDocument;
+import org.apache.pdfbox.pdmodel.common.COSObjectable;
+import org.apache.pdfbox.pdmodel.common.PDStream;
+
+/**
+ * Utility class used to clone PDF objects. It keeps track of objects it has already cloned.
+ *
+ * @version $Revision$
+ */
+public class PDFCloneUtility
+{
+
+ private PDDocument destination;
+ private Map<Object,COSBase> clonedVersion = new HashMap<Object,COSBase>();
+
+ /**
+ * Creates a new instance for the given target document.
+ * @param dest the destination PDF document that will receive the clones
+ */
+ public PDFCloneUtility(PDDocument dest)
+ {
+ this.destination = dest;
+ }
+
+ /**
+ * Returns the destination PDF document this cloner instance is set up for.
+ * @return the destination PDF document
+ */
+ public PDDocument getDestination()
+ {
+ return this.destination;
+ }
+
+ /**
+ * Deep-clones the given object for inclusion into a different PDF document identified by
+ * the destination parameter.
+ * @param base the initial object as the root of the deep-clone operation
+ * @return the cloned instance of the base object
+ * @throws IOException if an I/O error occurs
+ */
+ public COSBase cloneForNewDocument( Object base ) throws IOException
+ {
+ if( base == null )
+ {
+ return null;
+ }
+ COSBase retval = (COSBase)clonedVersion.get( base );
+ if( retval != null )
+ {
+ //we are done, it has already been converted.
+ }
+ else if( base instanceof List )
+ {
+ COSArray array = new COSArray();
+ List list = (List)base;
+ for( int i=0; i<list.size(); i++ )
+ {
+ array.add( cloneForNewDocument( list.get( i ) ) );
+ }
+ retval = array;
+ }
+ else if( base instanceof COSObjectable && !(base instanceof COSBase) )
+ {
+ retval = cloneForNewDocument( ((COSObjectable)base).getCOSObject() );
+ clonedVersion.put( base, retval );
+ }
+ else if( base instanceof COSObject )
+ {
+ COSObject object = (COSObject)base;
+ retval = cloneForNewDocument( object.getObject() );
+ clonedVersion.put( base, retval );
+ }
+ else if( base instanceof COSArray )
+ {
+ COSArray newArray = new COSArray();
+ COSArray array = (COSArray)base;
+ for( int i=0; i<array.size(); i++ )
+ {
+ newArray.add( cloneForNewDocument( array.get( i ) ) );
+ }
+ retval = newArray;
+ clonedVersion.put( base, retval );
+ }
+ else if( base instanceof COSStream )
+ {
+ COSStream originalStream = (COSStream)base;
+ PDStream stream = new PDStream( destination, originalStream.getFilteredStream(), true );
+ clonedVersion.put( base, stream.getStream() );
+ for( Map.Entry<COSName, COSBase> entry : originalStream.entrySet() )
+ {
+ stream.getStream().setItem(
+ entry.getKey(),
+ cloneForNewDocument(entry.getValue()));
+ }
+ retval = stream.getStream();
+ }
+ else if( base instanceof COSDictionary )
+ {
+ COSDictionary dic = (COSDictionary)base;
+ retval = new COSDictionary();
+ clonedVersion.put( base, retval );
+ for( Map.Entry<COSName, COSBase> entry : dic.entrySet() )
+ {
+ ((COSDictionary)retval).setItem(
+ entry.getKey(),
+ cloneForNewDocument(entry.getValue()));
+ }
+ }
+ else
+ {
+ retval = (COSBase)base;
+ }
+ clonedVersion.put( base, retval );
+ return retval;
+ }
+
+
+ /**
+ * Merges two objects of the same type by deep-cloning its members.
+ * <br/>
+ * Base and target must be instances of the same class.
+ * @param base the base object to be cloned
+ * @param target the merge target
+ * @throws IOException if an I/O error occurs
+ */
+ public void cloneMerge( COSObjectable base, COSObjectable target) throws IOException
+ {
+ if( base == null )
+ {
+ return;
+ }
+ COSBase retval = (COSBase)clonedVersion.get( base );
+ if( retval != null )
+ {
+ return;
+ //we are done, it has already been converted. // ### Is that correct for cloneMerge???
+ }
+ else if( base instanceof List )
+ {
+ COSArray array = new COSArray();
+ List list = (List)base;
+ for( int i = 0; i < list.size(); i++ )
+ {
+ array.add( cloneForNewDocument( list.get( i ) ) );
+ }
+ ((List)target).add(array);
+ }
+ else if( base instanceof COSObjectable && !(base instanceof COSBase) )
+ {
+ cloneMerge(((COSObjectable)base).getCOSObject(), ((COSObjectable)target).getCOSObject() );
+ clonedVersion.put( base, retval );
+ }
+ else if( base instanceof COSObject )
+ {
+ if(target instanceof COSObject)
+ {
+ cloneMerge(((COSObject) base).getObject(),((COSObject) target).getObject() );
+ }
+ else if(target instanceof COSDictionary)
+ {
+ cloneMerge(((COSObject)base).getObject(), ((COSDictionary)target));
+ }
+ clonedVersion.put( base, retval );
+ }
+ else if( base instanceof COSArray )
+ {
+ COSArray array = (COSArray)base;
+ for( int i=0; i<array.size(); i++ )
+ {
+ ((COSArray)target).add( cloneForNewDocument( array.get( i ) ) );
+ }
+ clonedVersion.put( base, retval );
+ }
+ else if( base instanceof COSStream )
+ {
+ // does that make sense???
+ COSStream originalStream = (COSStream)base;
+ PDStream stream = new PDStream( destination, originalStream.getFilteredStream(), true );
+ clonedVersion.put( base, stream.getStream() );
+ for( Map.Entry<COSName, COSBase> entry : originalStream.entrySet() )
+ {
+ stream.getStream().setItem(
+ entry.getKey(),
+ cloneForNewDocument(entry.getValue()));
+ }
+ retval = stream.getStream();
+ target = retval;
+ }
+ else if( base instanceof COSDictionary )
+ {
+ COSDictionary dic = (COSDictionary)base;
+ clonedVersion.put( base, retval );
+ for( Map.Entry<COSName, COSBase> entry : dic.entrySet() )
+ {
+ COSName key = entry.getKey();
+ COSBase value = entry.getValue();
+ if (((COSDictionary)target).getItem(key) != null)
+ {
+ cloneMerge(value, ((COSDictionary)target).getItem(key));
+ }
+ else
+ {
+ ((COSDictionary)target).setItem( key, cloneForNewDocument(value));
+ }
+ }
+ }
+ else
+ {
+ retval = (COSBase)base;
+ }
+ clonedVersion.put( base, retval );
+
+ }
+
+}
Propchange: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/PDFCloneUtility.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/PDFCloneUtility.java
------------------------------------------------------------------------------
svn:keywords = Id