aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/org/pdfbox/pdmodel
diff options
context:
space:
mode:
authortknall <tknall@7b5415b0-85f9-ee4d-85bd-d5d0c3b42d1c>2006-12-01 12:20:24 +0000
committertknall <tknall@7b5415b0-85f9-ee4d-85bd-d5d0c3b42d1c>2006-12-01 12:20:24 +0000
commit6025b6016517c6d898d8957d1d7e03ba71431912 (patch)
treeb15bd6fa5ffe9588a9bca3f2b8a7e358f83b6eba /src/main/java/org/pdfbox/pdmodel
parentd2c77e820ab4aba8235d71275755021347b3ad10 (diff)
downloadpdf-as-3-6025b6016517c6d898d8957d1d7e03ba71431912.tar.gz
pdf-as-3-6025b6016517c6d898d8957d1d7e03ba71431912.tar.bz2
pdf-as-3-6025b6016517c6d898d8957d1d7e03ba71431912.zip
Initial import of release 2.2.REL-2.2@923
git-svn-id: https://joinup.ec.europa.eu/svn/pdf-as/trunk@4 7b5415b0-85f9-ee4d-85bd-d5d0c3b42d1c
Diffstat (limited to 'src/main/java/org/pdfbox/pdmodel')
-rw-r--r--src/main/java/org/pdfbox/pdmodel/PDDestinationNameTreeNode.java90
-rw-r--r--src/main/java/org/pdfbox/pdmodel/PDDocument.java725
-rw-r--r--src/main/java/org/pdfbox/pdmodel/PDDocumentCatalog.java378
-rw-r--r--src/main/java/org/pdfbox/pdmodel/PDDocumentInformation.java297
-rw-r--r--src/main/java/org/pdfbox/pdmodel/PDDocumentNameDictionary.java164
-rw-r--r--src/main/java/org/pdfbox/pdmodel/PDEmbeddedFilesNameTreeNode.java89
-rw-r--r--src/main/java/org/pdfbox/pdmodel/PDPage.java776
-rw-r--r--src/main/java/org/pdfbox/pdmodel/PDPageNode.java459
-rw-r--r--src/main/java/org/pdfbox/pdmodel/PDResources.java313
-rw-r--r--src/main/java/org/pdfbox/pdmodel/common/COSArrayList.java643
-rw-r--r--src/main/java/org/pdfbox/pdmodel/common/COSDictionaryMap.java278
-rw-r--r--src/main/java/org/pdfbox/pdmodel/common/COSObjectable.java49
-rw-r--r--src/main/java/org/pdfbox/pdmodel/common/COSStreamArray.java304
-rw-r--r--src/main/java/org/pdfbox/pdmodel/common/DualCOSObjectable.java56
-rw-r--r--src/main/java/org/pdfbox/pdmodel/common/PDMatrix.java120
-rw-r--r--src/main/java/org/pdfbox/pdmodel/common/PDMemoryStream.java284
-rw-r--r--src/main/java/org/pdfbox/pdmodel/common/PDMetadata.java87
-rw-r--r--src/main/java/org/pdfbox/pdmodel/common/PDNameTreeNode.java337
-rw-r--r--src/main/java/org/pdfbox/pdmodel/common/PDNamedTextStream.java137
-rw-r--r--src/main/java/org/pdfbox/pdmodel/common/PDObjectStream.java151
-rw-r--r--src/main/java/org/pdfbox/pdmodel/common/PDRange.java146
-rw-r--r--src/main/java/org/pdfbox/pdmodel/common/PDRectangle.java295
-rw-r--r--src/main/java/org/pdfbox/pdmodel/common/PDStream.java538
-rw-r--r--src/main/java/org/pdfbox/pdmodel/common/PDTextStream.java180
-rw-r--r--src/main/java/org/pdfbox/pdmodel/common/filespecification/PDComplexFileSpecification.java326
-rw-r--r--src/main/java/org/pdfbox/pdmodel/common/filespecification/PDEmbeddedFile.java298
-rw-r--r--src/main/java/org/pdfbox/pdmodel/common/filespecification/PDFileSpecification.java83
-rw-r--r--src/main/java/org/pdfbox/pdmodel/common/filespecification/PDSimpleFileSpecification.java95
-rw-r--r--src/main/java/org/pdfbox/pdmodel/common/filespecification/package.html9
-rw-r--r--src/main/java/org/pdfbox/pdmodel/common/package.html9
-rw-r--r--src/main/java/org/pdfbox/pdmodel/documentinterchange/logicalstructure/PDMarkInfo.java149
-rw-r--r--src/main/java/org/pdfbox/pdmodel/documentinterchange/logicalstructure/PDStructureElement.java76
-rw-r--r--src/main/java/org/pdfbox/pdmodel/documentinterchange/logicalstructure/package.html10
-rw-r--r--src/main/java/org/pdfbox/pdmodel/documentinterchange/prepress/PDBoxStyle.java222
-rw-r--r--src/main/java/org/pdfbox/pdmodel/documentinterchange/prepress/package.html9
-rw-r--r--src/main/java/org/pdfbox/pdmodel/edit/PDPageContentStream.java648
-rw-r--r--src/main/java/org/pdfbox/pdmodel/edit/package.html9
-rw-r--r--src/main/java/org/pdfbox/pdmodel/encryption/PDEncryptionDictionary.java193
-rw-r--r--src/main/java/org/pdfbox/pdmodel/encryption/PDEncryptionManager.java131
-rw-r--r--src/main/java/org/pdfbox/pdmodel/encryption/PDStandardEncryption.java416
-rw-r--r--src/main/java/org/pdfbox/pdmodel/encryption/package.html9
-rw-r--r--src/main/java/org/pdfbox/pdmodel/fdf/FDFAnnotation.java114
-rw-r--r--src/main/java/org/pdfbox/pdmodel/fdf/FDFCatalog.java195
-rw-r--r--src/main/java/org/pdfbox/pdmodel/fdf/FDFDictionary.java465
-rw-r--r--src/main/java/org/pdfbox/pdmodel/fdf/FDFDocument.java377
-rw-r--r--src/main/java/org/pdfbox/pdmodel/fdf/FDFField.java763
-rw-r--r--src/main/java/org/pdfbox/pdmodel/fdf/FDFIconFit.java227
-rw-r--r--src/main/java/org/pdfbox/pdmodel/fdf/FDFJavaScript.java172
-rw-r--r--src/main/java/org/pdfbox/pdmodel/fdf/FDFNamedPageReference.java128
-rw-r--r--src/main/java/org/pdfbox/pdmodel/fdf/FDFOptionElement.java129
-rw-r--r--src/main/java/org/pdfbox/pdmodel/fdf/FDFPage.java148
-rw-r--r--src/main/java/org/pdfbox/pdmodel/fdf/FDFPageInfo.java85
-rw-r--r--src/main/java/org/pdfbox/pdmodel/fdf/FDFTemplate.java167
-rw-r--r--src/main/java/org/pdfbox/pdmodel/fdf/package.html9
-rw-r--r--src/main/java/org/pdfbox/pdmodel/font/PDCIDFont.java248
-rw-r--r--src/main/java/org/pdfbox/pdmodel/font/PDCIDFontType0Font.java66
-rw-r--r--src/main/java/org/pdfbox/pdmodel/font/PDCIDFontType2Font.java66
-rw-r--r--src/main/java/org/pdfbox/pdmodel/font/PDFont.java863
-rw-r--r--src/main/java/org/pdfbox/pdmodel/font/PDFontDescriptor.java530
-rw-r--r--src/main/java/org/pdfbox/pdmodel/font/PDFontDescriptorAFM.java446
-rw-r--r--src/main/java/org/pdfbox/pdmodel/font/PDFontDescriptorDictionary.java580
-rw-r--r--src/main/java/org/pdfbox/pdmodel/font/PDFontFactory.java108
-rw-r--r--src/main/java/org/pdfbox/pdmodel/font/PDMMType1Font.java62
-rw-r--r--src/main/java/org/pdfbox/pdmodel/font/PDSimpleFont.java239
-rw-r--r--src/main/java/org/pdfbox/pdmodel/font/PDTrueTypeFont.java437
-rw-r--r--src/main/java/org/pdfbox/pdmodel/font/PDType0Font.java129
-rw-r--r--src/main/java/org/pdfbox/pdmodel/font/PDType1AfmPfbFont.java206
-rw-r--r--src/main/java/org/pdfbox/pdmodel/font/PDType1Font.java267
-rw-r--r--src/main/java/org/pdfbox/pdmodel/font/PDType3Font.java152
-rw-r--r--src/main/java/org/pdfbox/pdmodel/font/Type3StreamParser.java607
-rw-r--r--src/main/java/org/pdfbox/pdmodel/font/package.html9
-rw-r--r--src/main/java/org/pdfbox/pdmodel/graphics/PDExtendedGraphicsState.java724
-rw-r--r--src/main/java/org/pdfbox/pdmodel/graphics/PDFontSetting.java133
-rw-r--r--src/main/java/org/pdfbox/pdmodel/graphics/PDGraphicsState.java438
-rw-r--r--src/main/java/org/pdfbox/pdmodel/graphics/PDLineDashPattern.java135
-rw-r--r--src/main/java/org/pdfbox/pdmodel/graphics/color/PDCalGray.java240
-rw-r--r--src/main/java/org/pdfbox/pdmodel/graphics/color/PDCalRGB.java289
-rw-r--r--src/main/java/org/pdfbox/pdmodel/graphics/color/PDColorSpace.java97
-rw-r--r--src/main/java/org/pdfbox/pdmodel/graphics/color/PDColorSpaceFactory.java218
-rw-r--r--src/main/java/org/pdfbox/pdmodel/graphics/color/PDColorSpaceInstance.java130
-rw-r--r--src/main/java/org/pdfbox/pdmodel/graphics/color/PDDeviceCMYK.java137
-rw-r--r--src/main/java/org/pdfbox/pdmodel/graphics/color/PDDeviceGray.java112
-rw-r--r--src/main/java/org/pdfbox/pdmodel/graphics/color/PDDeviceN.java244
-rw-r--r--src/main/java/org/pdfbox/pdmodel/graphics/color/PDDeviceNAttributes.java126
-rw-r--r--src/main/java/org/pdfbox/pdmodel/graphics/color/PDDeviceRGB.java130
-rw-r--r--src/main/java/org/pdfbox/pdmodel/graphics/color/PDGamma.java151
-rw-r--r--src/main/java/org/pdfbox/pdmodel/graphics/color/PDICCBased.java343
-rw-r--r--src/main/java/org/pdfbox/pdmodel/graphics/color/PDIndexed.java271
-rw-r--r--src/main/java/org/pdfbox/pdmodel/graphics/color/PDLab.java300
-rw-r--r--src/main/java/org/pdfbox/pdmodel/graphics/color/PDPattern.java122
-rw-r--r--src/main/java/org/pdfbox/pdmodel/graphics/color/PDSeparation.java198
-rw-r--r--src/main/java/org/pdfbox/pdmodel/graphics/color/PDTristimulus.java155
-rw-r--r--src/main/java/org/pdfbox/pdmodel/graphics/color/package.html9
-rw-r--r--src/main/java/org/pdfbox/pdmodel/graphics/package.html9
-rw-r--r--src/main/java/org/pdfbox/pdmodel/graphics/predictor/Average.java81
-rw-r--r--src/main/java/org/pdfbox/pdmodel/graphics/predictor/None.java104
-rw-r--r--src/main/java/org/pdfbox/pdmodel/graphics/predictor/Paeth.java121
-rw-r--r--src/main/java/org/pdfbox/pdmodel/graphics/predictor/PredictorAlgorithm.java336
-rw-r--r--src/main/java/org/pdfbox/pdmodel/graphics/predictor/Sub.java86
-rw-r--r--src/main/java/org/pdfbox/pdmodel/graphics/predictor/Up.java100
-rw-r--r--src/main/java/org/pdfbox/pdmodel/graphics/predictor/Uptimum.java153
-rw-r--r--src/main/java/org/pdfbox/pdmodel/graphics/predictor/package.html10
-rw-r--r--src/main/java/org/pdfbox/pdmodel/graphics/xobject/PDCcitt.java598
-rw-r--r--src/main/java/org/pdfbox/pdmodel/graphics/xobject/PDInlinedImage.java201
-rw-r--r--src/main/java/org/pdfbox/pdmodel/graphics/xobject/PDJpeg.java156
-rw-r--r--src/main/java/org/pdfbox/pdmodel/graphics/xobject/PDPixelMap.java236
-rw-r--r--src/main/java/org/pdfbox/pdmodel/graphics/xobject/PDXObject.java207
-rw-r--r--src/main/java/org/pdfbox/pdmodel/graphics/xobject/PDXObjectForm.java120
-rw-r--r--src/main/java/org/pdfbox/pdmodel/graphics/xobject/PDXObjectImage.java244
-rw-r--r--src/main/java/org/pdfbox/pdmodel/graphics/xobject/package.html9
-rw-r--r--src/main/java/org/pdfbox/pdmodel/interactive/action/PDActionFactory.java96
-rw-r--r--src/main/java/org/pdfbox/pdmodel/interactive/action/PDAdditionalActions.java106
-rw-r--r--src/main/java/org/pdfbox/pdmodel/interactive/action/PDAnnotationAdditionalActions.java380
-rw-r--r--src/main/java/org/pdfbox/pdmodel/interactive/action/PDDocumentCatalogAdditionalActions.java238
-rw-r--r--src/main/java/org/pdfbox/pdmodel/interactive/action/PDFormFieldAdditionalActions.java216
-rw-r--r--src/main/java/org/pdfbox/pdmodel/interactive/action/PDPageAdditionalActions.java150
-rw-r--r--src/main/java/org/pdfbox/pdmodel/interactive/action/package.html9
-rw-r--r--src/main/java/org/pdfbox/pdmodel/interactive/action/type/PDAction.java187
-rw-r--r--src/main/java/org/pdfbox/pdmodel/interactive/action/type/PDActionGoTo.java92
-rw-r--r--src/main/java/org/pdfbox/pdmodel/interactive/action/type/PDActionJavaScript.java102
-rw-r--r--src/main/java/org/pdfbox/pdmodel/interactive/action/type/PDActionLaunch.java244
-rw-r--r--src/main/java/org/pdfbox/pdmodel/interactive/action/type/PDActionRemoteGoTo.java187
-rw-r--r--src/main/java/org/pdfbox/pdmodel/interactive/action/type/PDActionURI.java183
-rw-r--r--src/main/java/org/pdfbox/pdmodel/interactive/action/type/PDWindowsLaunchParams.java180
-rw-r--r--src/main/java/org/pdfbox/pdmodel/interactive/action/type/package.html9
-rw-r--r--src/main/java/org/pdfbox/pdmodel/interactive/annotation/PDAnnotation.java503
-rw-r--r--src/main/java/org/pdfbox/pdmodel/interactive/annotation/PDAnnotationRubberStamp.java153
-rw-r--r--src/main/java/org/pdfbox/pdmodel/interactive/annotation/PDAnnotationUnknown.java54
-rw-r--r--src/main/java/org/pdfbox/pdmodel/interactive/annotation/PDAnnotationWidget.java65
-rw-r--r--src/main/java/org/pdfbox/pdmodel/interactive/annotation/PDAppearanceDictionary.java245
-rw-r--r--src/main/java/org/pdfbox/pdmodel/interactive/annotation/PDAppearanceStream.java146
-rw-r--r--src/main/java/org/pdfbox/pdmodel/interactive/annotation/package.html9
-rw-r--r--src/main/java/org/pdfbox/pdmodel/interactive/digitalsignature/PDSignature.java85
-rw-r--r--src/main/java/org/pdfbox/pdmodel/interactive/digitalsignature/package.html9
-rw-r--r--src/main/java/org/pdfbox/pdmodel/interactive/documentnavigation/destination/PDDestination.java125
-rw-r--r--src/main/java/org/pdfbox/pdmodel/interactive/documentnavigation/destination/PDNamedDestination.java142
-rw-r--r--src/main/java/org/pdfbox/pdmodel/interactive/documentnavigation/destination/PDPageDestination.java155
-rw-r--r--src/main/java/org/pdfbox/pdmodel/interactive/documentnavigation/destination/PDPageFitDestination.java102
-rw-r--r--src/main/java/org/pdfbox/pdmodel/interactive/documentnavigation/destination/PDPageFitHeightDestination.java132
-rw-r--r--src/main/java/org/pdfbox/pdmodel/interactive/documentnavigation/destination/PDPageFitRectangleDestination.java188
-rw-r--r--src/main/java/org/pdfbox/pdmodel/interactive/documentnavigation/destination/PDPageFitWidthDestination.java134
-rw-r--r--src/main/java/org/pdfbox/pdmodel/interactive/documentnavigation/destination/PDPageXYZDestination.java159
-rw-r--r--src/main/java/org/pdfbox/pdmodel/interactive/documentnavigation/destination/package.html9
-rw-r--r--src/main/java/org/pdfbox/pdmodel/interactive/documentnavigation/outline/PDDocumentOutline.java62
-rw-r--r--src/main/java/org/pdfbox/pdmodel/interactive/documentnavigation/outline/PDOutlineItem.java425
-rw-r--r--src/main/java/org/pdfbox/pdmodel/interactive/documentnavigation/outline/PDOutlineNode.java320
-rw-r--r--src/main/java/org/pdfbox/pdmodel/interactive/documentnavigation/outline/package.html9
-rw-r--r--src/main/java/org/pdfbox/pdmodel/interactive/documentnavigation/package.html9
-rw-r--r--src/main/java/org/pdfbox/pdmodel/interactive/form/PDAcroForm.java328
-rw-r--r--src/main/java/org/pdfbox/pdmodel/interactive/form/PDAppearance.java645
-rw-r--r--src/main/java/org/pdfbox/pdmodel/interactive/form/PDCheckbox.java187
-rw-r--r--src/main/java/org/pdfbox/pdmodel/interactive/form/PDChoiceButton.java95
-rw-r--r--src/main/java/org/pdfbox/pdmodel/interactive/form/PDChoiceField.java127
-rw-r--r--src/main/java/org/pdfbox/pdmodel/interactive/form/PDField.java610
-rw-r--r--src/main/java/org/pdfbox/pdmodel/interactive/form/PDFieldFactory.java218
-rw-r--r--src/main/java/org/pdfbox/pdmodel/interactive/form/PDPushButton.java84
-rw-r--r--src/main/java/org/pdfbox/pdmodel/interactive/form/PDRadioCollection.java170
-rw-r--r--src/main/java/org/pdfbox/pdmodel/interactive/form/PDSignature.java90
-rw-r--r--src/main/java/org/pdfbox/pdmodel/interactive/form/PDTextbox.java64
-rw-r--r--src/main/java/org/pdfbox/pdmodel/interactive/form/PDUnknownField.java72
-rw-r--r--src/main/java/org/pdfbox/pdmodel/interactive/form/PDVariableText.java324
-rw-r--r--src/main/java/org/pdfbox/pdmodel/interactive/form/package.html9
-rw-r--r--src/main/java/org/pdfbox/pdmodel/interactive/pagenavigation/PDThread.java152
-rw-r--r--src/main/java/org/pdfbox/pdmodel/interactive/pagenavigation/PDThreadBead.java234
-rw-r--r--src/main/java/org/pdfbox/pdmodel/interactive/pagenavigation/package.html9
-rw-r--r--src/main/java/org/pdfbox/pdmodel/interactive/viewerpreferences/PDViewerPreferences.java365
-rw-r--r--src/main/java/org/pdfbox/pdmodel/interactive/viewerpreferences/package.html9
-rw-r--r--src/main/java/org/pdfbox/pdmodel/package.html9
-rw-r--r--src/main/java/org/pdfbox/pdmodel/text/PDTextState.java286
-rw-r--r--src/main/java/org/pdfbox/pdmodel/text/package.html9
170 files changed, 34770 insertions, 0 deletions
diff --git a/src/main/java/org/pdfbox/pdmodel/PDDestinationNameTreeNode.java b/src/main/java/org/pdfbox/pdmodel/PDDestinationNameTreeNode.java
new file mode 100644
index 0000000..6c8956c
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/PDDestinationNameTreeNode.java
@@ -0,0 +1,90 @@
+/**
+ * Copyright (c) 2005, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel;
+
+import java.io.IOException;
+
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.pdmodel.common.PDNameTreeNode;
+import org.pdfbox.pdmodel.interactive.documentnavigation.destination.PDDestination;
+import org.pdfbox.pdmodel.interactive.documentnavigation.destination.PDPageDestination;
+
+/**
+ * This class holds all of the name trees that are available at the document level.
+ *
+ * @author Ben Litchfield (ben@benlitchfield.com)
+ * @version $Revision: 1.1 $
+ */
+public class PDDestinationNameTreeNode extends PDNameTreeNode
+{
+ /**
+ * Constructor.
+ */
+ public PDDestinationNameTreeNode()
+ {
+ super( PDPageDestination.class );
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param dic The COS dictionary.
+ */
+ public PDDestinationNameTreeNode( COSDictionary dic )
+ {
+ super( dic, PDPageDestination.class );
+ }
+
+ /**
+ * @see PDNameTreeNode#convertCOSToPD( COSBase )
+ */
+ protected Object convertCOSToPD( COSBase base ) throws IOException
+ {
+ COSBase destination = base;
+ if( base instanceof COSDictionary )
+ {
+ //the destination is sometimes stored in the D dictionary
+ //entry instead of being directly an array, so just dereference
+ //it for now
+ destination = ((COSDictionary)base).getDictionaryObject( "D" );
+ }
+ return PDDestination.create( destination );
+ }
+
+ /**
+ * @see PDNameTreeNode#createChildNode( COSDictionary )
+ */
+ protected PDNameTreeNode createChildNode( COSDictionary dic )
+ {
+ return new PDDestinationNameTreeNode(dic);
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/PDDocument.java b/src/main/java/org/pdfbox/pdmodel/PDDocument.java
new file mode 100644
index 0000000..94150fb
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/PDDocument.java
@@ -0,0 +1,725 @@
+/**
+ * Copyright (c) 2003-2005, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel;
+
+import java.awt.print.PageFormat;
+import java.awt.print.Pageable;
+import java.awt.print.Paper;
+import java.awt.print.Printable;
+import java.awt.print.PrinterException;
+import java.awt.print.PrinterIOException;
+import java.awt.print.PrinterJob;
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.List;
+
+import org.pdfbox.cos.COSArray;
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSDocument;
+import org.pdfbox.cos.COSInteger;
+import org.pdfbox.cos.COSName;
+import org.pdfbox.cos.COSStream;
+import org.pdfbox.cos.COSString;
+
+import org.pdfbox.encryption.PDFEncryption;
+import org.pdfbox.encryption.DocumentEncryption;
+
+import org.pdfbox.exceptions.COSVisitorException;
+import org.pdfbox.exceptions.CryptographyException;
+import org.pdfbox.exceptions.InvalidPasswordException;
+
+import org.pdfbox.pdfparser.PDFParser;
+
+import org.pdfbox.pdfwriter.COSWriter;
+
+import org.pdfbox.pdmodel.common.PDRectangle;
+import org.pdfbox.pdmodel.common.PDStream;
+
+import org.pdfbox.pdmodel.encryption.PDEncryptionDictionary;
+import org.pdfbox.pdmodel.encryption.PDEncryptionManager;
+import org.pdfbox.pdmodel.encryption.PDStandardEncryption;
+
+/**
+ * This is the in-memory representation of the PDF document. You need to call
+ * close() on this object when you are done using it!!
+ *
+ * @author Ben Litchfield (ben@benlitchfield.com)
+ * @version $Revision: 1.35 $
+ */
+public class PDDocument implements Pageable
+{
+ private COSDocument document;
+ private boolean encryptOnSave = false;
+ private String encryptUserPassword = null;
+ private String encryptOwnerPassword = null;
+
+ //cached values
+ private PDDocumentInformation documentInformation;
+ private PDDocumentCatalog documentCatalog;
+
+ //The encParameters will be cached here. When the document is decrypted then
+ //the COSDocument will not have an "Encrypt" dictionary anymore and this object
+ //must be used.
+ private PDEncryptionDictionary encParameters = null;
+ /**
+ * This will tell if the document was decrypted with the master password.
+ */
+ private boolean decryptedWithOwnerPassword = false;
+
+ /**
+ * Constructor, creates a new PDF Document with no pages. You need to add
+ * at least one page for the document to be valid.
+ *
+ * @throws IOException If there is an error creating this document.
+ */
+ public PDDocument() throws IOException
+ {
+ document = new COSDocument();
+
+ //First we need a trailer
+ COSDictionary trailer = new COSDictionary();
+ document.setTrailer( trailer );
+
+ //Next we need the root dictionary.
+ COSDictionary rootDictionary = new COSDictionary();
+ trailer.setItem( COSName.ROOT, rootDictionary );
+ rootDictionary.setItem( COSName.TYPE, COSName.CATALOG );
+ rootDictionary.setItem( COSName.VERSION, COSName.getPDFName( "1.4" ) );
+
+ //next we need the pages tree structure
+ COSDictionary pages = new COSDictionary();
+ rootDictionary.setItem( COSName.PAGES, pages );
+ pages.setItem( COSName.TYPE, COSName.PAGES );
+ COSArray kidsArray = new COSArray();
+ pages.setItem( COSName.KIDS, kidsArray );
+ pages.setItem( COSName.COUNT, new COSInteger( 0 ) );
+ }
+
+ /**
+ * This will add a page to the document. This is a convenience method, that
+ * will add the page to the root of the hierarchy and set the parent of the
+ * page to the root.
+ *
+ * @param page The page to add to the document.
+ */
+ public void addPage( PDPage page )
+ {
+ PDPageNode rootPages = getDocumentCatalog().getPages();
+ rootPages.getKids().add( page );
+ page.setParent( rootPages );
+ rootPages.updateCount();
+ }
+
+ /**
+ * Remove the page from the document.
+ *
+ * @param page The page to remove from the document.
+ *
+ * @return true if the page was found false otherwise.
+ */
+ public boolean removePage( PDPage page )
+ {
+ PDPageNode parent = page.getParent();
+ boolean retval = parent.getKids().remove( page );
+ if( retval )
+ {
+ //do a recursive updateCount starting at the root
+ //of the document
+ getDocumentCatalog().getPages().updateCount();
+ }
+ return retval;
+ }
+
+ /**
+ * Remove the page from the document.
+ *
+ * @param pageNumber 0 based index to page number.
+ * @return true if the page was found false otherwise.
+ */
+ public boolean removePage( int pageNumber )
+ {
+ boolean removed = false;
+ List allPages = getDocumentCatalog().getAllPages();
+ if( allPages.size() > pageNumber)
+ {
+ PDPage page = (PDPage)allPages.get( pageNumber );
+ removed = removePage( page );
+ }
+ return removed;
+ }
+
+ /**
+ * This will import and copy the contents from another location. Currently
+ * the content stream is stored in a scratch file. The scratch file is
+ * associated with the document. If you are adding a page to this document
+ * from another document and want to copy the contents to this document's
+ * scratch file then use this method otherwise just use the addPage method.
+ *
+ * @param page The page to import.
+ * @return The page that was imported.
+ *
+ * @throws IOException If there is an error copying the page.
+ */
+ public PDPage importPage( PDPage page ) throws IOException
+ {
+ PDPage importedPage = new PDPage( new COSDictionary( page.getCOSDictionary() ) );
+ InputStream is = null;
+ OutputStream os = null;
+ try
+ {
+ PDStream src = page.getContents();
+ PDStream dest = new PDStream( new COSStream( src.getStream(), document.getScratchFile() ) );
+ importedPage.setContents( dest );
+ os = dest.createOutputStream();
+
+ byte[] buf = new byte[10240];
+ int amountRead = 0;
+ is = src.createInputStream();
+ while((amountRead = is.read(buf,0,10240)) > -1)
+ {
+ os.write(buf, 0, amountRead);
+ }
+ addPage( importedPage );
+ }
+ finally
+ {
+ if( is != null )
+ {
+ is.close();
+ }
+ if( os != null )
+ {
+ os.close();
+ }
+ }
+ return importedPage;
+
+ }
+
+ /**
+ * Constructor that uses an existing document. The COSDocument that
+ * is passed in must be valid.
+ *
+ * @param doc The COSDocument that this document wraps.
+ */
+ public PDDocument( COSDocument doc )
+ {
+ document = doc;
+ }
+
+ /**
+ * This will get the low level document.
+ *
+ * @return The document that this layer sits on top of.
+ */
+ public COSDocument getDocument()
+ {
+ return document;
+ }
+
+ /**
+ * This will get the document info dictionary. This is guaranteed to not return null.
+ *
+ * @return The documents /Info dictionary
+ */
+ public PDDocumentInformation getDocumentInformation()
+ {
+ if( documentInformation == null )
+ {
+ COSDictionary trailer = document.getTrailer();
+ COSDictionary infoDic = (COSDictionary)trailer.getDictionaryObject( COSName.INFO );
+ if( infoDic == null )
+ {
+ infoDic = new COSDictionary();
+ trailer.setItem( COSName.INFO, infoDic );
+ }
+ documentInformation = new PDDocumentInformation( infoDic );
+ }
+ return documentInformation;
+ }
+
+ /**
+ * This will set the document information for this document.
+ *
+ * @param info The updated document information.
+ */
+ public void setDocumentInformation( PDDocumentInformation info )
+ {
+ documentInformation = info;
+ document.getTrailer().setItem( COSName.INFO, info.getDictionary() );
+ }
+
+ /**
+ * This will get the document CATALOG. This is guaranteed to not return null.
+ *
+ * @return The documents /Root dictionary
+ */
+ public PDDocumentCatalog getDocumentCatalog()
+ {
+ if( documentCatalog == null )
+ {
+ COSDictionary trailer = document.getTrailer();
+ COSDictionary infoDic = (COSDictionary)trailer.getDictionaryObject( COSName.ROOT );
+ if( infoDic == null )
+ {
+ documentCatalog = new PDDocumentCatalog( this );
+ }
+ else
+ {
+ documentCatalog = new PDDocumentCatalog( this, infoDic );
+ }
+
+ }
+ return documentCatalog;
+ }
+
+ /**
+ * This will tell if this document is encrypted or not.
+ *
+ * @return true If this document is encrypted.
+ */
+ public boolean isEncrypted()
+ {
+ return document.isEncrypted();
+ }
+
+ /**
+ * This will get the encryption dictionary for this document. This will still
+ * return the parameters if the document was decrypted. If the document was
+ * never encrypted then this will return null. As the encryption architecture
+ * in PDF documents is plugable this returns an abstract class, but the only
+ * supported subclass at this time is a PDStandardEncryption object.
+ *
+ * @return The encryption dictionary(most likely a PDStandardEncryption object)
+ *
+ * @throws IOException If there is an error determining which security handler to use.
+ */
+ public PDEncryptionDictionary getEncryptionDictionary() throws IOException
+ {
+ if( encParameters == null )
+ {
+ encParameters = PDEncryptionManager.getEncryptionDictionary( document.getEncryptionDictionary() );
+ }
+ return encParameters;
+ }
+
+ /**
+ * This will set the encryption dictionary for this document.
+ *
+ * @param encDictionary The encryption dictionary(most likely a PDStandardEncryption object)
+ *
+ * @throws IOException If there is an error determining which security handler to use.
+ */
+ public void setEncryptionDictionary( PDEncryptionDictionary encDictionary ) throws IOException
+ {
+ encParameters = encDictionary;
+ }
+
+ /**
+ * This will determine if this is the user password. This only applies when
+ * the document is encrypted and uses standard encryption.
+ *
+ * @param password The plain text user password.
+ *
+ * @return true If the password passed in matches the user password used to encrypt the document.
+ *
+ * @throws IOException If there is an error determining if it is the user password.
+ * @throws CryptographyException If there is an error in the encryption algorithms.
+ */
+ public boolean isUserPassword( String password ) throws IOException, CryptographyException
+ {
+ boolean retval = false;
+ if( password == null )
+ {
+ password = "";
+ }
+ PDFEncryption encryptor = new PDFEncryption();
+ PDEncryptionDictionary encryptionDictionary = getEncryptionDictionary();
+ if( encryptionDictionary == null )
+ {
+ throw new IOException( "Error: Document is not encrypted" );
+ }
+ else
+ {
+ if( encryptionDictionary instanceof PDStandardEncryption )
+ {
+ COSString documentID = (COSString)document.getDocumentID().get(0);
+ PDStandardEncryption standard = (PDStandardEncryption)encryptionDictionary;
+ retval = encryptor.isUserPassword(
+ password.getBytes(),
+ standard.getUserKey(),
+ standard.getOwnerKey(),
+ standard.getPermissions(),
+ documentID.getBytes(),
+ standard.getRevision(),
+ standard.getLength()/8 );
+ }
+ else
+ {
+ throw new IOException( "Error: Encyption dictionary is not 'Standard'" +
+ encryptionDictionary.getClass().getName() );
+ }
+ }
+ return retval;
+ }
+
+ /**
+ * This will determine if this is the owner password. This only applies when
+ * the document is encrypted and uses standard encryption.
+ *
+ * @param password The plain text owner password.
+ *
+ * @return true If the password passed in matches the owner password used to encrypt the document.
+ *
+ * @throws IOException If there is an error determining if it is the user password.
+ * @throws CryptographyException If there is an error in the encryption algorithms.
+ */
+ public boolean isOwnerPassword( String password ) throws IOException, CryptographyException
+ {
+ boolean retval = false;
+ if( password == null )
+ {
+ password = "";
+ }
+ PDFEncryption encryptor = new PDFEncryption();
+ PDEncryptionDictionary encryptionDictionary = getEncryptionDictionary();
+ if( encryptionDictionary == null )
+ {
+ throw new IOException( "Error: Document is not encrypted" );
+ }
+ else
+ {
+ if( encryptionDictionary instanceof PDStandardEncryption )
+ {
+ COSString documentID = (COSString)document.getDocumentID().get( 0 );
+ PDStandardEncryption standard = (PDStandardEncryption)encryptionDictionary;
+ retval = encryptor.isOwnerPassword(
+ password.getBytes(),
+ standard.getUserKey(),
+ standard.getOwnerKey(),
+ standard.getPermissions(),
+ documentID.getBytes(),
+ standard.getRevision(),
+ standard.getLength()/8 );
+ }
+ else
+ {
+ throw new IOException( "Error: Encyption dictionary is not 'Standard'" +
+ encryptionDictionary.getClass().getName() );
+ }
+ }
+ return retval;
+ }
+
+ /**
+ * This will decrypt a document.
+ *
+ * @param password Either the user or owner password.
+ *
+ * @throws CryptographyException If there is an error decrypting the document.
+ * @throws IOException If there is an error getting the stream data.
+ * @throws InvalidPasswordException If the password is not a user or owner password.
+ */
+ public void decrypt( String password ) throws CryptographyException, IOException, InvalidPasswordException
+ {
+ decryptedWithOwnerPassword = isOwnerPassword( password );
+ DocumentEncryption decryptor = new DocumentEncryption( this );
+ decryptor.decryptDocument( password );
+ document.dereferenceObjectStreams();
+ }
+
+ /**
+ * This will tell if the document was decrypted with the master password. This
+ * entry is invalid if the PDF was not decrypted.
+ *
+ * @return true if the pdf was decrypted with the master password.
+ */
+ public boolean wasDecryptedWithOwnerPassword()
+ {
+ return decryptedWithOwnerPassword;
+ }
+
+ /**
+ * This will <b>mark</b> a document to be encrypted. The actual encryption
+ * will occur when the document is saved.
+ *
+ * @param ownerPassword The owner password to encrypt the document.
+ * @param userPassword The user password to encrypt the document.
+ *
+ * @throws CryptographyException If an error occurs during encryption.
+ * @throws IOException If there is an error accessing the data.
+ */
+ public void encrypt( String ownerPassword, String userPassword )
+ throws CryptographyException, IOException
+ {
+ encryptOnSave = true;
+ encryptOwnerPassword = ownerPassword;
+ encryptUserPassword = userPassword;
+ }
+
+
+ /**
+ * The owner password that was passed into the encrypt method. You should
+ * never use this method. This will not longer be valid once encryption
+ * has occured.
+ *
+ * @return The owner password passed to the encrypt method.
+ */
+ public String getOwnerPasswordForEncryption()
+ {
+ return encryptOwnerPassword;
+ }
+
+ /**
+ * The user password that was passed into the encrypt method. You should
+ * never use this method. This will not longer be valid once encryption
+ * has occured.
+ *
+ * @return The user password passed to the encrypt method.
+ */
+ public String getUserPasswordForEncryption()
+ {
+ return encryptUserPassword;
+ }
+
+ /**
+ * Internal method do determine if the document will be encrypted when it is saved.
+ *
+ * @return True if encrypt has been called and the document
+ * has not been saved yet.
+ */
+ public boolean willEncryptWhenSaving()
+ {
+ return encryptOnSave;
+ }
+
+ /**
+ * This shoule only be called by the COSWriter after encryption has completed.
+ *
+ */
+ public void clearWillEncryptWhenSaving()
+ {
+ encryptOnSave = false;
+ }
+
+ /**
+ * This will load a document from a file.
+ *
+ * @param filename The name of the file to load.
+ *
+ * @return The document that was loaded.
+ *
+ * @throws IOException If there is an error reading from the stream.
+ */
+ public static PDDocument load( String filename ) throws IOException
+ {
+ return load( new BufferedInputStream( new FileInputStream( filename ) ) );
+ }
+
+ /**
+ * This will load a document from a file.
+ *
+ * @param file The name of the file to load.
+ *
+ * @return The document that was loaded.
+ *
+ * @throws IOException If there is an error reading from the stream.
+ */
+ public static PDDocument load( File file ) throws IOException
+ {
+ return load( new BufferedInputStream( new FileInputStream( file ) ) );
+ }
+
+ /**
+ * This will load a document from an input stream.
+ *
+ * @param input The stream that contains the document.
+ *
+ * @return The document that was loaded.
+ *
+ * @throws IOException If there is an error reading from the stream.
+ */
+ public static PDDocument load( InputStream input ) throws IOException
+ {
+ PDFParser parser = new PDFParser( input );
+ parser.parse();
+ return parser.getPDDocument();
+ }
+
+ /**
+ * This will save this document to the filesystem.
+ *
+ * @param fileName The file to save as.
+ *
+ * @throws IOException If there is an error saving the document.
+ * @throws COSVisitorException If an error occurs while generating the data.
+ */
+ public void save( String fileName ) throws IOException, COSVisitorException
+ {
+ save( new FileOutputStream( fileName ) );
+ }
+
+ /**
+ * This will save the document to an output stream.
+ *
+ * @param output The stream to write to.
+ *
+ * @throws IOException If there is an error writing the document.
+ * @throws COSVisitorException If an error occurs while generating the data.
+ */
+ public void save( OutputStream output ) throws IOException, COSVisitorException
+ {
+ //update the count in case any pages have been added behind the scenes.
+ getDocumentCatalog().getPages().updateCount();
+ COSWriter writer = null;
+ try
+ {
+ writer = new COSWriter( output );
+ writer.write( this );
+ writer.close();
+ }
+ finally
+ {
+ if( writer != null )
+ {
+ writer.close();
+ }
+ }
+
+ }
+
+ /**
+ * This will return the total page count of the PDF document. Note: This method
+ * is deprecated in favor of the getNumberOfPages method. The getNumberOfPages is
+ * a required interface method of the Pageable interface. This method will
+ * be removed in a future version of PDFBox!!
+ *
+ * @return The total number of pages in the PDF document.
+ * @deprecated Use the getNumberOfPages method instead!
+ */
+ public int getPageCount()
+ {
+ return getNumberOfPages();
+ }
+
+ /**
+ * @see Pageable#getNumberOfPages()
+ */
+ public int getNumberOfPages()
+ {
+ PDDocumentCatalog cat = getDocumentCatalog();
+ return (int)cat.getPages().getCount();
+ }
+
+ /**
+ * @see Pageable#getPageFormat(int)
+ */
+ public PageFormat getPageFormat(int pageIndex)
+ {
+ PDPage page = (PDPage)getDocumentCatalog().getAllPages().get( pageIndex );
+ PDRectangle mediaBox = page.findMediaBox();
+ PageFormat format = new PageFormat();
+ Paper paper = new Paper();
+ //hmm the imageable area might need to be the CropBox instead
+ //of the media box???
+ paper.setImageableArea( 0,0,mediaBox.getWidth(),mediaBox.getHeight());
+ paper.setSize( mediaBox.getWidth(), mediaBox.getHeight() );
+ format.setPaper( paper );
+ return format;
+ }
+
+ /**
+ * @see Pageable#getPrintable(int)
+ */
+ public Printable getPrintable(int pageIndex)
+ {
+ return (Printable)getDocumentCatalog().getAllPages().get( pageIndex );
+ }
+
+ /**
+ * This will send the PDF document to a printer. The printing functionality
+ * depends on the org.pdfbox.pdfviewer.PageDrawer functionality. The PageDrawer
+ * is a work in progress and some PDFs will print correctly and some will
+ * not. This is a convenience method to create the java.awt.print.PrinterJob.
+ * The PDDocument implements the java.awt.print.Pageable interface and
+ * PDPage implementes the java.awt.print.Printable interface, so advanced printing
+ * capabilities can be done by using those interfaces instead of this method.
+ *
+ * @throws PrinterException If there is an error while sending the PDF to
+ * the printer, or you do not have permissions to print this document.
+ */
+ public void print() throws PrinterException
+ {
+ PDEncryptionDictionary encDictionary = null;
+ try
+ {
+ encDictionary = getEncryptionDictionary();
+ }
+ catch( IOException io )
+ {
+ throw new PrinterIOException( io );
+ }
+
+ //only care about standard encryption and if it was decrypted with the
+ //user password
+ if( encDictionary instanceof PDStandardEncryption &&
+ !wasDecryptedWithOwnerPassword() )
+ {
+ PDStandardEncryption stdEncryption = (PDStandardEncryption)encDictionary;
+ if( !stdEncryption.canPrint() )
+ {
+ throw new PrinterException( "You do not have permission to print this document." );
+ }
+ }
+
+ PrinterJob printJob = PrinterJob.getPrinterJob();
+ printJob.setPageable(this);
+ if( printJob.printDialog() )
+ {
+ printJob.print();
+ }
+ }
+
+ /**
+ * This will close the underlying COSDocument object.
+ *
+ * @throws IOException If there is an error releasing resources.
+ */
+ public void close() throws IOException
+ {
+ document.close();
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/PDDocumentCatalog.java b/src/main/java/org/pdfbox/pdmodel/PDDocumentCatalog.java
new file mode 100644
index 0000000..552d404
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/PDDocumentCatalog.java
@@ -0,0 +1,378 @@
+/**
+ * Copyright (c) 2003-2005, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.pdfbox.cos.COSArray;
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSName;
+import org.pdfbox.cos.COSStream;
+import org.pdfbox.cos.COSString;
+
+import org.pdfbox.pdmodel.common.COSArrayList;
+import org.pdfbox.pdmodel.common.COSObjectable;
+import org.pdfbox.pdmodel.common.PDMetadata;
+import org.pdfbox.pdmodel.documentinterchange.logicalstructure.PDMarkInfo;
+import org.pdfbox.pdmodel.interactive.action.type.PDAction;
+import org.pdfbox.pdmodel.interactive.action.PDActionFactory;
+import org.pdfbox.pdmodel.interactive.action.PDDocumentCatalogAdditionalActions;
+import org.pdfbox.pdmodel.interactive.documentnavigation.outline.PDDocumentOutline;
+import org.pdfbox.pdmodel.interactive.form.PDAcroForm;
+
+import org.pdfbox.pdmodel.interactive.pagenavigation.PDThread;
+import org.pdfbox.pdmodel.interactive.viewerpreferences.PDViewerPreferences;
+
+/**
+ * This class represents the acroform of a PDF document.
+ *
+ * @author Ben Litchfield (ben@benlitchfield.com)
+ * @version $Revision: 1.16 $
+ */
+public class PDDocumentCatalog implements COSObjectable
+{
+ private COSDictionary root;
+ private PDDocument document;
+
+ private PDAcroForm acroForm = null;
+
+ /**
+ * Constructor.
+ *
+ * @param doc The document that this catalog is part of.
+ */
+ public PDDocumentCatalog( PDDocument doc )
+ {
+ document = doc;
+ root = new COSDictionary();
+ root.setItem( COSName.TYPE, new COSString( "Catalog" ) );
+ document.getDocument().getTrailer().setItem( COSName.ROOT, root );
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param doc The document that this catalog is part of.
+ * @param rootDictionary The root dictionary that this object wraps.
+ */
+ public PDDocumentCatalog( PDDocument doc, COSDictionary rootDictionary )
+ {
+ document = doc;
+ root = rootDictionary;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSBase getCOSObject()
+ {
+ return root;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSDictionary getCOSDictionary()
+ {
+ return root;
+ }
+
+ /**
+ * This will get the documents acroform. This will return null if
+ * no acroform is part of the document.
+ *
+ * @return The documents acroform.
+ */
+ public PDAcroForm getAcroForm()
+ {
+ if( acroForm == null )
+ {
+ COSDictionary acroFormDic =
+ (COSDictionary)root.getDictionaryObject( COSName.ACRO_FORM );
+ if( acroFormDic == null )
+ {
+ acroForm = new PDAcroForm( document );
+ root.setItem( COSName.ACRO_FORM, acroForm.getDictionary() );
+ }
+ else
+ {
+ acroForm = new PDAcroForm( document, acroFormDic );
+ }
+ }
+ return acroForm;
+ }
+
+ /**
+ * This will get the root node for the pages.
+ *
+ * @return The parent page node.
+ */
+ public PDPageNode getPages()
+ {
+ return new PDPageNode( (COSDictionary)root.getDictionaryObject( COSName.PAGES ) );
+ }
+
+ /**
+ * The PDF document contains a hierarchical structure of PDPageNode and PDPages, which
+ * is mostly just a way to store this information. This method will return a flat list
+ * of all PDPage objects in this document.
+ *
+ * @return A list of PDPage objects.
+ */
+ public List getAllPages()
+ {
+ List retval = new ArrayList();
+ PDPageNode rootNode = getPages();
+ //old (slower):
+ //getPageObjects( rootNode, retval );
+ rootNode.getAllKids(retval);
+ return retval;
+ }
+
+ /**
+ * Get the viewer preferences associated with this document or null if they
+ * do not exist.
+ *
+ * @return The document's viewer preferences.
+ */
+ public PDViewerPreferences getViewerPreferences()
+ {
+ PDViewerPreferences retval = null;
+ COSDictionary dict = (COSDictionary)root.getDictionaryObject( "ViewerPreferences" );
+ if( dict != null )
+ {
+ retval = new PDViewerPreferences( dict );
+ }
+
+ return retval;
+ }
+
+ /**
+ * Set the viewer preferences.
+ *
+ * @param prefs The new viewer preferences.
+ */
+ public void setViewerPreferences( PDViewerPreferences prefs )
+ {
+ root.setItem( "ViewerPreferences", prefs );
+ }
+
+ /**
+ * Get the outline associated with this document or null if it
+ * does not exist.
+ *
+ * @return The document's outline.
+ */
+ public PDDocumentOutline getDocumentOutline()
+ {
+ PDDocumentOutline retval = null;
+ COSDictionary dict = (COSDictionary)root.getDictionaryObject( "Outlines" );
+ if( dict != null )
+ {
+ retval = new PDDocumentOutline( dict );
+ }
+
+ return retval;
+ }
+
+ /**
+ * Set the document outlines.
+ *
+ * @param outlines The new document outlines.
+ */
+ public void setDocumentOutline( PDDocumentOutline outlines )
+ {
+ root.setItem( "Outlines", outlines );
+ }
+
+ /**
+ * Get the list threads for this pdf document.
+ *
+ * @return A list of PDThread objects.
+ */
+ public List getThreads()
+ {
+ COSArray array = (COSArray)root.getDictionaryObject( "Threads" );
+ if( array == null )
+ {
+ array = new COSArray();
+ root.setItem( "Threads", array );
+ }
+ List pdObjects = new ArrayList();
+ for( int i=0; i<array.size(); i++ )
+ {
+ pdObjects.add( new PDThread( (COSDictionary)array.getObject( i ) ) );
+ }
+ return new COSArrayList( pdObjects, array );
+ }
+
+ /**
+ * Set the list of threads for this pdf document.
+ *
+ * @param threads The list of threads, or null to clear it.
+ */
+ public void setThreads( List threads )
+ {
+ root.setItem( "Threads", COSArrayList.converterToCOSArray( threads ) );
+ }
+
+ /**
+ * Get the metadata that is part of the document catalog. This will
+ * return null if there is no meta data for this object.
+ *
+ * @return The metadata for this object.
+ */
+ public PDMetadata getMetadata()
+ {
+ PDMetadata retval = null;
+ COSStream stream = (COSStream)root.getDictionaryObject( "Metadata" );
+ if( stream != null )
+ {
+ retval = new PDMetadata( stream );
+ }
+ return retval;
+ }
+
+ /**
+ * Set the metadata for this object. This can be null.
+ *
+ * @param meta The meta data for this object.
+ */
+ public void setMetadata( PDMetadata meta )
+ {
+ root.setItem( "Metadata", meta );
+ }
+
+ /**
+ * Set the Document Open Action for this object.
+ *
+ * @param action The action you want to perform.
+ */
+ public void setOpenAction( PDAction action )
+ {
+ root.setItem( COSName.getPDFName("OpenAction"), action );
+ }
+
+ /**
+ * Get the Document Open Action for this object.
+ *
+ * @return The action to perform when the document is opened.
+ */
+ public PDAction getOpenAction()
+ {
+ PDAction action = null;
+ COSDictionary actionDic = (COSDictionary) root.getDictionaryObject("OpenAction");
+
+ action = PDActionFactory.createAction(actionDic);
+
+ return action;
+ }
+ /**
+ * @return The Additional Actions for this Document
+ */
+ public PDDocumentCatalogAdditionalActions getActions()
+ {
+ COSDictionary addAct = (COSDictionary) root.getDictionaryObject("AA");
+ if (addAct == null)
+ {
+ addAct = new COSDictionary();
+ root.setItem("AA", addAct);
+ }
+ return new PDDocumentCatalogAdditionalActions(addAct);
+ }
+
+ /**
+ * Set the additional actions for the document.
+ *
+ * @param actions The actions that are associated with this document.
+ */
+ public void setActions( PDDocumentCatalogAdditionalActions actions )
+ {
+ root.setItem("AA", actions );
+ }
+
+ /**
+ * @return The names dictionary for this document or null if none exist.
+ */
+ public PDDocumentNameDictionary getNames()
+ {
+ PDDocumentNameDictionary nameDic = null;
+ COSDictionary names = (COSDictionary) root.getDictionaryObject("Names");
+ if(names != null)
+ {
+ nameDic = new PDDocumentNameDictionary(this,names);
+ }
+ return nameDic;
+ }
+
+ /**
+ * Set the names dictionary for the document.
+ *
+ * @param names The names dictionary that is associated with this document.
+ */
+ public void setNames( PDDocumentNameDictionary names )
+ {
+ root.setItem("Names", names );
+ }
+
+ /**
+ * Get info about doc's usage of tagged features. This will return
+ * null if there is no information.
+ *
+ * @return The new mark info.
+ */
+ public PDMarkInfo getMarkInfo()
+ {
+ PDMarkInfo retval = null;
+ COSDictionary dic = (COSDictionary)root.getDictionaryObject( "MarkInfo" );
+ if( dic != null )
+ {
+ retval = new PDMarkInfo( dic );
+ }
+ return retval;
+ }
+
+ /**
+ * Set information about the doc's usage of tagged features.
+ *
+ * @param markInfo The new MarkInfo data.
+ */
+ public void setMarkInfo( PDMarkInfo markInfo )
+ {
+ root.setItem( "MarkInfo", markInfo );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/PDDocumentInformation.java b/src/main/java/org/pdfbox/pdmodel/PDDocumentInformation.java
new file mode 100644
index 0000000..a30e90c
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/PDDocumentInformation.java
@@ -0,0 +1,297 @@
+/**
+ * Copyright (c) 2003-2005, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel;
+
+import java.io.IOException;
+
+import java.util.Calendar;
+
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSName;
+
+import org.pdfbox.pdmodel.common.COSObjectable;
+
+/**
+ * This is the document metadata. Each getXXX method will return the entry if
+ * it exists or null if it does not exist. If you pass in null for the setXXX
+ * method then it will clear the value.
+ *
+ * @author Ben Litchfield (ben@benlitchfield.com)
+ * @version $Revision: 1.10 $
+ */
+public class PDDocumentInformation implements COSObjectable
+{
+ private static final COSName TITLE = COSName.getPDFName( "Title" );
+ private static final COSName AUTHOR = COSName.getPDFName( "Author" );
+ private static final COSName SUBJECT = COSName.getPDFName( "Subject" );
+ private static final COSName KEYWORDS = COSName.getPDFName( "Keywords" );
+ private static final COSName CREATOR = COSName.getPDFName( "Creator" );
+ private static final COSName PRODUCER = COSName.getPDFName( "Producer" );
+ private static final COSName CREATION_DATE = COSName.getPDFName( "CreationDate" );
+ private static final COSName MODIFICATION_DATE = COSName.getPDFName( "ModDate" );
+ private static final COSName TRAPPED = COSName.getPDFName( "Trapped" );
+ private COSDictionary info;
+
+
+ /**
+ * Default Constructor.
+ */
+ public PDDocumentInformation()
+ {
+ info = new COSDictionary();
+ }
+
+ /**
+ * Constructor that is used for a preexisting dictionary.
+ *
+ * @param dic The underlying dictionary.
+ */
+ public PDDocumentInformation( COSDictionary dic )
+ {
+ info = dic;
+ }
+
+ /**
+ * This will get the underlying dictionary that this object wraps.
+ *
+ * @return The underlying info dictionary.
+ */
+ public COSDictionary getDictionary()
+ {
+ return info;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSBase getCOSObject()
+ {
+ return info;
+ }
+
+ /**
+ * This will get the title of the document. This will return null if no title exists.
+ *
+ * @return The title of the document.
+ */
+ public String getTitle()
+ {
+ return info.getString( TITLE );
+ }
+
+ /**
+ * This will set the title of the document.
+ *
+ * @param title The new title for the document.
+ */
+ public void setTitle( String title )
+ {
+ info.setString( TITLE, title );
+ }
+
+ /**
+ * This will get the author of the document. This will return null if no author exists.
+ *
+ * @return The author of the document.
+ */
+ public String getAuthor()
+ {
+ return info.getString( AUTHOR );
+ }
+
+ /**
+ * This will set the author of the document.
+ *
+ * @param author The new author for the document.
+ */
+ public void setAuthor( String author )
+ {
+ info.setString( AUTHOR, author );
+ }
+
+ /**
+ * This will get the subject of the document. This will return null if no subject exists.
+ *
+ * @return The subject of the document.
+ */
+ public String getSubject()
+ {
+ return info.getString( SUBJECT );
+ }
+
+ /**
+ * This will set the subject of the document.
+ *
+ * @param subject The new subject for the document.
+ */
+ public void setSubject( String subject )
+ {
+ info.setString( SUBJECT, subject );
+ }
+
+ /**
+ * This will get the keywords of the document. This will return null if no keywords exists.
+ *
+ * @return The keywords of the document.
+ */
+ public String getKeywords()
+ {
+ return info.getString( KEYWORDS );
+ }
+
+ /**
+ * This will set the keywords of the document.
+ *
+ * @param keywords The new keywords for the document.
+ */
+ public void setKeywords( String keywords )
+ {
+ info.setString( KEYWORDS, keywords );
+ }
+
+ /**
+ * This will get the creator of the document. This will return null if no creator exists.
+ *
+ * @return The creator of the document.
+ */
+ public String getCreator()
+ {
+ return info.getString( CREATOR );
+ }
+
+ /**
+ * This will set the creator of the document.
+ *
+ * @param creator The new creator for the document.
+ */
+ public void setCreator( String creator )
+ {
+ info.setString( CREATOR, creator );
+ }
+
+ /**
+ * This will get the producer of the document. This will return null if no producer exists.
+ *
+ * @return The producer of the document.
+ */
+ public String getProducer()
+ {
+ return info.getString( PRODUCER );
+ }
+
+ /**
+ * This will set the producer of the document.
+ *
+ * @param producer The new producer for the document.
+ */
+ public void setProducer( String producer )
+ {
+ info.setString( PRODUCER, producer );
+ }
+
+ /**
+ * This will get the creation date of the document. This will return null if no creation date exists.
+ *
+ * @return The creation date of the document.
+ *
+ * @throws IOException If there is an error creating the date.
+ */
+ public Calendar getCreationDate() throws IOException
+ {
+ return info.getDate( CREATION_DATE );
+ }
+
+ /**
+ * This will set the creation date of the document.
+ *
+ * @param date The new creation date for the document.
+ */
+ public void setCreationDate( Calendar date )
+ {
+ info.setDate( CREATION_DATE, date );
+ }
+
+ /**
+ * This will get the modification date of the document. This will return null if no modification date exists.
+ *
+ * @return The modification date of the document.
+ *
+ * @throws IOException If there is an error creating the date.
+ */
+ public Calendar getModificationDate() throws IOException
+ {
+ return info.getDate( MODIFICATION_DATE );
+ }
+
+ /**
+ * This will set the modification date of the document.
+ *
+ * @param date The new modification date for the document.
+ */
+ public void setModificationDate( Calendar date )
+ {
+ info.setDate( MODIFICATION_DATE, date );
+ }
+
+ /**
+ * This will get the trapped value for the document.
+ * This will return null if one is not found.
+ *
+ * @return The trapped value for the document.
+ */
+ public String getTrapped()
+ {
+ return info.getNameAsString( TRAPPED );
+ }
+
+ /**
+ * This will set the trapped of the document. This will be
+ * 'True', 'False', or 'Unknown'.
+ *
+ * @param value The new trapped value for the document.
+ */
+ public void setTrapped( String value )
+ {
+ if( value != null &&
+ !value.equals( "True" ) &&
+ !value.equals( "False" ) &&
+ !value.equals( "Unknown" ) )
+ {
+ throw new RuntimeException( "Valid values for trapped are " +
+ "'True', 'False', or 'Unknown'" );
+ }
+
+ info.setName( TRAPPED, value );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/PDDocumentNameDictionary.java b/src/main/java/org/pdfbox/pdmodel/PDDocumentNameDictionary.java
new file mode 100644
index 0000000..f343d7a
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/PDDocumentNameDictionary.java
@@ -0,0 +1,164 @@
+/**
+ * Copyright (c) 2005, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel;
+
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.pdmodel.common.COSObjectable;
+
+/**
+ * This class holds all of the name trees that are available at the document level.
+ *
+ * @author Ben Litchfield (ben@benlitchfield.com)
+ * @version $Revision: 1.2 $
+ */
+public class PDDocumentNameDictionary implements COSObjectable
+{
+ private COSDictionary nameDictionary;
+ private PDDocumentCatalog catalog;
+
+ /**
+ * Constructor.
+ *
+ * @param cat The document catalog that this dictionary is part of.
+ */
+ public PDDocumentNameDictionary( PDDocumentCatalog cat )
+ {
+ nameDictionary = new COSDictionary();
+ catalog = cat;
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param cat The document that this dictionary is part of.
+ * @param names The names dictionary.
+ */
+ public PDDocumentNameDictionary( PDDocumentCatalog cat, COSDictionary names )
+ {
+ catalog = cat;
+ nameDictionary = names;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSBase getCOSObject()
+ {
+ return nameDictionary;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos dictionary for this object.
+ */
+ public COSDictionary getCOSDictionary()
+ {
+ return nameDictionary;
+ }
+
+ /**
+ * Get the destination named tree node. The value in this name tree will be PDDestination
+ * objects.
+ *
+ * @return The destination name tree node.
+ */
+ public PDDestinationNameTreeNode getDests()
+ {
+ PDDestinationNameTreeNode dests = null;
+
+ COSDictionary dic = (COSDictionary)nameDictionary.getDictionaryObject( "Dests" );
+
+ //The document catalog also contains the Dests entry sometimes
+ //so check there as well.
+ if( dic == null )
+ {
+ dic = (COSDictionary)catalog.getCOSDictionary().getDictionaryObject( "Dests" );
+ }
+
+ if( dic != null )
+ {
+ dests = new PDDestinationNameTreeNode( dic );
+ }
+
+
+ return dests;
+ }
+
+ /**
+ * Set the named destinations that are associated with this document.
+ *
+ * @param dests The destination names.
+ */
+ public void setDests( PDDestinationNameTreeNode dests )
+ {
+ nameDictionary.setItem( "Dests", dests );
+ //The dests can either be in the document catalog or in the
+ //names dictionary, PDFBox will just maintain the one in the
+ //names dictionary for now unless there is a reason to do
+ //something else.
+ //clear the potentially out of date Dests reference.
+ catalog.getCOSDictionary().setItem( "Dests", (COSObjectable)null);
+ }
+
+ /**
+ * Get the embedded files named tree node. The value in this name tree will be PDComplexFileSpecification
+ * objects.
+ *
+ * @return The embedded files name tree node.
+ */
+ public PDEmbeddedFilesNameTreeNode getEmbeddedFiles()
+ {
+ PDEmbeddedFilesNameTreeNode retval = null;
+
+ COSDictionary dic = (COSDictionary)nameDictionary.getDictionaryObject( "EmbeddedFiles" );
+
+ if( dic != null )
+ {
+ retval = new PDEmbeddedFilesNameTreeNode( dic );
+ }
+
+ return retval;
+ }
+
+ /**
+ * Set the named embedded files that are associated with this document.
+ *
+ * @param ef The new embedded files
+ */
+ public void setEmbeddedFiles( PDEmbeddedFilesNameTreeNode ef )
+ {
+ nameDictionary.setItem( "EmbeddedFiles", ef );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/PDEmbeddedFilesNameTreeNode.java b/src/main/java/org/pdfbox/pdmodel/PDEmbeddedFilesNameTreeNode.java
new file mode 100644
index 0000000..11c1103
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/PDEmbeddedFilesNameTreeNode.java
@@ -0,0 +1,89 @@
+/**
+ * Copyright (c) 2005, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel;
+
+import java.io.IOException;
+
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.pdmodel.common.PDNameTreeNode;
+import org.pdfbox.pdmodel.common.filespecification.PDComplexFileSpecification;
+
+/**
+ * This class holds all of the name trees that are available at the document level.
+ *
+ * @author Ben Litchfield (ben@benlitchfield.com)
+ * @version $Revision: 1.1 $
+ */
+public class PDEmbeddedFilesNameTreeNode extends PDNameTreeNode
+{
+ /**
+ * Constructor.
+ */
+ public PDEmbeddedFilesNameTreeNode()
+ {
+ super( PDComplexFileSpecification.class );
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param dic The COS dictionary.
+ */
+ public PDEmbeddedFilesNameTreeNode( COSDictionary dic )
+ {
+ super( dic, PDComplexFileSpecification.class );
+ }
+
+ /**
+ * @see PDNameTreeNode#convertCOSToPD( COSBase )
+ */
+ protected Object convertCOSToPD( COSBase base ) throws IOException
+ {
+ COSBase destination = base;
+ if( base instanceof COSDictionary )
+ {
+ //the destination is sometimes stored in the D dictionary
+ //entry instead of being directly an array, so just dereference
+ //it for now
+ destination = ((COSDictionary)base).getDictionaryObject( "D" );
+ }
+ return new PDComplexFileSpecification( (COSDictionary)destination );
+ }
+
+ /**
+ * @see PDNameTreeNode#createChildNode( COSDictionary )
+ */
+ protected PDNameTreeNode createChildNode( COSDictionary dic )
+ {
+ return new PDEmbeddedFilesNameTreeNode(dic);
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/PDPage.java b/src/main/java/org/pdfbox/pdmodel/PDPage.java
new file mode 100644
index 0000000..3739a5a
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/PDPage.java
@@ -0,0 +1,776 @@
+/**
+ * Copyright (c) 2003-2005, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel;
+
+import org.pdfbox.cos.COSArray;
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSInteger;
+import org.pdfbox.cos.COSName;
+import org.pdfbox.cos.COSNumber;
+import org.pdfbox.cos.COSStream;
+
+import org.pdfbox.pdfviewer.PageDrawer;
+import org.pdfbox.pdmodel.common.COSArrayList;
+import org.pdfbox.pdmodel.common.COSObjectable;
+import org.pdfbox.pdmodel.common.PDMetadata;
+import org.pdfbox.pdmodel.common.PDRectangle;
+import org.pdfbox.pdmodel.common.PDStream;
+import org.pdfbox.pdmodel.interactive.action.PDPageAdditionalActions;
+import org.pdfbox.pdmodel.interactive.annotation.PDAnnotation;
+import org.pdfbox.pdmodel.interactive.pagenavigation.PDThreadBead;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.image.BufferedImage;
+import java.awt.print.PageFormat;
+import java.awt.print.Paper;
+import java.awt.print.Printable;
+import java.awt.print.PrinterException;
+import java.awt.print.PrinterIOException;
+import java.io.IOException;
+
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+import java.util.List;
+
+/**
+ * This represents a single page in a PDF document.
+ *
+ * @author Ben Litchfield (ben@benlitchfield.com)
+ * @version $Revision: 1.24 $
+ */
+public class PDPage implements COSObjectable, Printable
+{
+ private COSDictionary page;
+
+ /**
+ * A page size of LETTER or 8.5x11.
+ */
+ public static final PDRectangle PAGE_SIZE_LETTER = new PDRectangle( 612, 792 );
+
+
+ /**
+ * Creates a new instance of PDPage with a size of 8.5x11.
+ */
+ public PDPage()
+ {
+ page = new COSDictionary();
+ page.setItem( COSName.TYPE, COSName.PAGE );
+ setMediaBox( PAGE_SIZE_LETTER );
+ }
+
+ /**
+ * Creates a new instance of PDPage.
+ *
+ * @param pageDic The existing page dictionary.
+ */
+ public PDPage( COSDictionary pageDic )
+ {
+ page = pageDic;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSBase getCOSObject()
+ {
+ return page;
+ }
+
+ /**
+ * This will get the underlying dictionary that this class acts on.
+ *
+ * @return The underlying dictionary for this class.
+ */
+ public COSDictionary getCOSDictionary()
+ {
+ return page;
+ }
+
+
+ /**
+ * This is the parent page node. The parent is a required element of the
+ * page. This will be null until this page is added to the document.
+ *
+ * @return The parent to this page.
+ */
+ public PDPageNode getParent()
+ {
+ PDPageNode parent = null;
+ COSDictionary parentDic = (COSDictionary)page.getDictionaryObject( COSName.PARENT );
+ if( parentDic != null )
+ {
+ parent = new PDPageNode( parentDic );
+ }
+ return parent;
+ }
+
+ /**
+ * This will set the parent of this page.
+ *
+ * @param parent The parent to this page node.
+ */
+ public void setParent( PDPageNode parent )
+ {
+ page.setItem( COSName.PARENT, parent.getDictionary() );
+ }
+
+ /**
+ * This will update the last modified time for the page object.
+ */
+ public void updateLastModified()
+ {
+ page.setDate( "LastModified", new GregorianCalendar() );
+ }
+
+ /**
+ * This will get the date that the content stream was last modified. This
+ * may return null.
+ *
+ * @return The date the content stream was last modified.
+ *
+ * @throws IOException If there is an error accessing the date information.
+ */
+ public Calendar getLastModified() throws IOException
+ {
+ return page.getDate( "LastModified" );
+ }
+
+ /**
+ * 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)page.getDictionaryObject( COSName.RESOURCES );
+ if( resources != null )
+ {
+ retval = new PDResources( resources );
+ }
+ return retval;
+ }
+
+ /**
+ * This will find the resources for this page by looking up the hierarchy until
+ * it finds them.
+ *
+ * @return The resources at this level in the hierarchy.
+ */
+ public PDResources findResources()
+ {
+ PDResources retval = getResources();
+ PDPageNode parent = getParent();
+ if( retval == null && parent != null )
+ {
+ retval = parent.findResources();
+ }
+ return retval;
+ }
+
+ /**
+ * This will set the resources for this page.
+ *
+ * @param resources The new resources for this page.
+ */
+ public void setResources( PDResources resources )
+ {
+ page.setItem( COSName.RESOURCES, resources );
+ }
+
+ /**
+ * A rectangle, expressed
+ * in default user space units, defining the boundaries of the physical
+ * medium on which the page is intended to be displayed or printed
+ *
+ * This will get the MediaBox at this page and not look up the hierarchy.
+ * This attribute is inheritable, and findMediaBox() should probably used.
+ * This will return null if no MediaBox are available at this level.
+ *
+ * @return The MediaBox at this level in the hierarchy.
+ */
+ public PDRectangle getMediaBox()
+ {
+ PDRectangle retval = null;
+ COSArray array = (COSArray)page.getDictionaryObject( COSName.MEDIA_BOX );
+ if( array != null )
+ {
+ retval = new PDRectangle( array );
+ }
+ return retval;
+ }
+
+ /**
+ * This will find the MediaBox for this page by looking up the hierarchy until
+ * it finds them.
+ *
+ * @return The MediaBox at this level in the hierarchy.
+ */
+ public PDRectangle findMediaBox()
+ {
+ PDRectangle retval = getMediaBox();
+ PDPageNode parent = getParent();
+ if( retval == null && parent != null )
+ {
+ retval = parent.findMediaBox();
+ }
+ return retval;
+ }
+
+ /**
+ * This will set the mediaBox for this page.
+ *
+ * @param mediaBox The new mediaBox for this page.
+ */
+ public void setMediaBox( PDRectangle mediaBox )
+ {
+ if( mediaBox == null )
+ {
+ page.removeItem( COSName.MEDIA_BOX );
+ }
+ else
+ {
+ page.setItem( COSName.MEDIA_BOX, mediaBox.getCOSArray() );
+ }
+ }
+
+ /**
+ * A rectangle, expressed in default user space units,
+ * defining the visible region of default user space. When the page is displayed
+ * or printed, its contents are to be clipped (cropped) to this rectangle
+ * and then imposed on the output medium in some implementationdefined
+ * manner
+ *
+ * This will get the CropBox at this page and not look up the hierarchy.
+ * This attribute is inheritable, and findCropBox() should probably used.
+ * This will return null if no CropBox is available at this level.
+ *
+ * @return The CropBox at this level in the hierarchy.
+ */
+ public PDRectangle getCropBox()
+ {
+ PDRectangle retval = null;
+ COSArray array = (COSArray)page.getDictionaryObject( COSName.CROP_BOX);
+ if( array != null )
+ {
+ retval = new PDRectangle( array );
+ }
+ return retval;
+ }
+
+ /**
+ * This will find the CropBox for this page by looking up the hierarchy until
+ * it finds them.
+ *
+ * @return The CropBox at this level in the hierarchy.
+ */
+ public PDRectangle findCropBox()
+ {
+ PDRectangle retval = getCropBox();
+ PDPageNode parent = getParent();
+ if( retval == null && parent != null )
+ {
+ retval = findParentCropBox( parent );
+ }
+
+ //default value for cropbox is the media box
+ if( retval == null )
+ {
+ retval = findMediaBox();
+ }
+ return retval;
+ }
+
+ /**
+ * This will search for a crop box in the parent and return null if it is not
+ * found. It will NOT default to the media box if it cannot be found.
+ *
+ * @param node The node
+ */
+ private PDRectangle findParentCropBox( PDPageNode node )
+ {
+ PDRectangle rect = node.getCropBox();
+ PDPageNode parent = node.getParent();
+ if( rect == null && parent != null )
+ {
+ rect = findParentCropBox( parent );
+ }
+ return rect;
+ }
+
+ /**
+ * This will set the CropBox for this page.
+ *
+ * @param cropBox The new CropBox for this page.
+ */
+ public void setCropBox( PDRectangle cropBox )
+ {
+ if( cropBox == null )
+ {
+ page.removeItem( COSName.CROP_BOX );
+ }
+ else
+ {
+ page.setItem( COSName.CROP_BOX, cropBox.getCOSArray() );
+ }
+ }
+
+ /**
+ * A rectangle, expressed in default user space units, defining
+ * the region to which the contents of the page should be clipped
+ * when output in a production environment. The default is the CropBox.
+ *
+ * @return The BleedBox attribute.
+ */
+ public PDRectangle getBleedBox()
+ {
+ PDRectangle retval = null;
+ COSArray array = (COSArray)page.getDictionaryObject( COSName.BLEED_BOX );
+ if( array != null )
+ {
+ retval = new PDRectangle( array );
+ }
+ else
+ {
+ retval = findCropBox();
+ }
+ return retval;
+ }
+
+ /**
+ * This will set the BleedBox for this page.
+ *
+ * @param bleedBox The new BleedBox for this page.
+ */
+ public void setBleedBox( PDRectangle bleedBox )
+ {
+ if( bleedBox == null )
+ {
+ page.removeItem( COSName.BLEED_BOX );
+ }
+ else
+ {
+ page.setItem( COSName.BLEED_BOX, bleedBox.getCOSArray() );
+ }
+ }
+
+ /**
+ * A rectangle, expressed in default user space units, defining
+ * the intended dimensions of the finished page after trimming.
+ * The default is the CropBox.
+ *
+ * @return The TrimBox attribute.
+ */
+ public PDRectangle getTrimBox()
+ {
+ PDRectangle retval = null;
+ COSArray array = (COSArray)page.getDictionaryObject( COSName.TRIM_BOX );
+ if( array != null )
+ {
+ retval = new PDRectangle( array );
+ }
+ else
+ {
+ retval = findCropBox();
+ }
+ return retval;
+ }
+
+ /**
+ * This will set the TrimBox for this page.
+ *
+ * @param trimBox The new TrimBox for this page.
+ */
+ public void setTrimBox( PDRectangle trimBox )
+ {
+ if( trimBox == null )
+ {
+ page.removeItem( COSName.TRIM_BOX );
+ }
+ else
+ {
+ page.setItem( COSName.TRIM_BOX, trimBox.getCOSArray() );
+ }
+ }
+
+ /**
+ * A rectangle, expressed in default user space units, defining
+ * the extent of the page's meaningful content (including potential
+ * white space) as intended by the page's creator The default isthe CropBox.
+ *
+ * @return The ArtBox attribute.
+ */
+ public PDRectangle getArtBox()
+ {
+ PDRectangle retval = null;
+ COSArray array = (COSArray)page.getDictionaryObject( COSName.ART_BOX );
+ if( array != null )
+ {
+ retval = new PDRectangle( array );
+ }
+ else
+ {
+ retval = findCropBox();
+ }
+ return retval;
+ }
+
+ /**
+ * This will set the ArtBox for this page.
+ *
+ * @param artBox The new ArtBox for this page.
+ */
+ public void setArtBox( PDRectangle artBox )
+ {
+ if( artBox == null )
+ {
+ page.removeItem( COSName.ART_BOX );
+ }
+ else
+ {
+ page.setItem( COSName.ART_BOX, artBox.getCOSArray() );
+ }
+ }
+
+
+ //todo BoxColorInfo
+ //todo Contents
+
+ /**
+ * A value representing the rotation. This will be null if not set at this level
+ * The number of degrees by which the page should
+ * be rotated clockwise when displayed or printed. The value must be a multiple
+ * of 90.
+ *
+ * This will get the rotation at this page and not look up the hierarchy.
+ * This attribute is inheritable, and findRotation() should probably used.
+ * This will return null if no rotation is available at this level.
+ *
+ * @return The rotation at this level in the hierarchy.
+ */
+ public Integer getRotation()
+ {
+ Integer retval = null;
+ COSNumber value = (COSNumber)page.getDictionaryObject( COSName.ROTATE );
+ if( value != null )
+ {
+ retval = new Integer( value.intValue() );
+ }
+ return retval;
+ }
+
+ /**
+ * This will find the rotation for this page by looking up the hierarchy until
+ * it finds them.
+ *
+ * @return The rotation at this level in the hierarchy.
+ */
+ public int findRotation()
+ {
+ int retval = 0;
+ Integer rotation = getRotation();
+ if( rotation != null )
+ {
+ retval = rotation.intValue();
+ }
+ else
+ {
+ PDPageNode parent = getParent();
+ if( parent != null )
+ {
+ retval = parent.findRotation();
+ }
+ }
+
+ return retval;
+ }
+
+ /**
+ * This will set the rotation for this page.
+ *
+ * @param rotation The new rotation for this page.
+ */
+ public void setRotation( int rotation )
+ {
+ page.setItem( COSName.ROTATE, new COSInteger( rotation ) );
+ }
+
+ /**
+ * This will get the contents of the PDF Page, in the case that the contents
+ * of the page is an array then then the entire array of streams will be
+ * be wrapped and appear as a single stream.
+ *
+ * @return The page content stream.
+ *
+ * @throws IOException If there is an error obtaining the stream.
+ */
+ public PDStream getContents() throws IOException
+ {
+ return PDStream.createFromCOS( page.getDictionaryObject( COSName.CONTENTS ) );
+ }
+
+ /**
+ * This will set the contents of this page.
+ *
+ * @param contents The new contents of the page.
+ */
+ public void setContents( PDStream contents )
+ {
+ page.setItem( COSName.CONTENTS, contents );
+ }
+
+ /**
+ * This will get a list of PDThreadBead objects, which are article threads in the
+ * document. This will return an empty list of there are no thread beads.
+ *
+ * @return A list of article threads on this page.
+ */
+ public List getThreadBeads()
+ {
+ COSArray beads = (COSArray)page.getDictionaryObject( COSName.B );
+ if( beads == null )
+ {
+ beads = new COSArray();
+ }
+ List pdObjects = new ArrayList();
+ for( int i=0; i<beads.size(); i++)
+ {
+ COSDictionary beadDic = (COSDictionary)beads.getObject( i );
+ PDThreadBead bead = null;
+ //in some cases the bead is null
+ if( beadDic != null )
+ {
+ bead = new PDThreadBead( beadDic );
+ }
+ pdObjects.add( bead );
+ }
+ return new COSArrayList(pdObjects, beads);
+
+ }
+
+ /**
+ * This will set the list of thread beads.
+ *
+ * @param beads A list of PDThreadBead objects or null.
+ */
+ public void setThreadBeads( List beads )
+ {
+ page.setItem( COSName.B, COSArrayList.converterToCOSArray( beads ) );
+ }
+
+ /**
+ * Get the metadata that is part of the document catalog. This will
+ * return null if there is no meta data for this object.
+ *
+ * @return The metadata for this object.
+ */
+ public PDMetadata getMetadata()
+ {
+ PDMetadata retval = null;
+ COSStream stream = (COSStream)page.getDictionaryObject( COSName.METADATA );
+ if( stream != null )
+ {
+ retval = new PDMetadata( stream );
+ }
+ return retval;
+ }
+
+ /**
+ * Set the metadata for this object. This can be null.
+ *
+ * @param meta The meta data for this object.
+ */
+ public void setMetadata( PDMetadata meta )
+ {
+ page.setItem( COSName.METADATA, meta );
+ }
+
+ /**
+ * Convert this page to an output image.
+ *
+ * @return A graphical representation of this page.
+ *
+ * @throws IOException If there is an error drawing to the image.
+ */
+ public BufferedImage convertToImage() throws IOException
+ {
+ int scaling = 2;
+ int rotation = findRotation();
+ PDRectangle mBox = findMediaBox();
+ int width = (int)(mBox.getWidth());//*2);
+ int height = (int)(mBox.getHeight());//*2);
+ if( rotation == 90 || rotation == 270 )
+ {
+ int tmp = width;
+ width = height;
+ height = tmp;
+ }
+ Dimension pageDimension = new Dimension( width, height );
+
+ //note we are doing twice as many pixels because
+ //the default size is not really good resolution,
+ //so create an image that is twice the size
+ //and let the client scale it down.
+ BufferedImage retval =
+ new BufferedImage( width*scaling, height*scaling, BufferedImage.TYPE_BYTE_INDEXED );
+ Graphics2D graphics = (Graphics2D)retval.getGraphics();
+ graphics.setColor( Color.WHITE );
+ graphics.fillRect(0,0,width*scaling, height*scaling);
+ graphics.scale( scaling, scaling );
+ PageDrawer drawer = new PageDrawer();
+ drawer.drawPage( graphics, this, pageDimension );
+
+
+ return retval;
+ }
+
+ /**
+ * Get the page actions.
+ *
+ * @return The Actions for this Page
+ */
+ public PDPageAdditionalActions getActions()
+ {
+ COSDictionary addAct = (COSDictionary) page.getDictionaryObject(COSName.AA);
+ if (addAct == null)
+ {
+ addAct = new COSDictionary();
+ page.setItem(COSName.AA, addAct);
+ }
+ return new PDPageAdditionalActions(addAct);
+ }
+
+ /**
+ * Set the page actions.
+ *
+ * @param actions The actions for the page.
+ */
+ public void setActions( PDPageAdditionalActions actions )
+ {
+ page.setItem( COSName.AA, actions );
+ }
+
+ /**
+ * This will return a list of the Annotations for this page.
+ *
+ * @return List of the PDAnnotation objects.
+ *
+ * @throws IOException If there is an error while creating the annotations.
+ */
+ public List getAnnotations() throws IOException
+ {
+ COSArrayList retval = null;
+ COSArray annots = (COSArray)page.getDictionaryObject(COSName.ANNOTS);
+ if (annots == null)
+ {
+ annots = new COSArray();
+ page.setItem(COSName.ANNOTS, annots);
+ retval = new COSArrayList(new ArrayList(), annots);
+ }
+ else
+ {
+ List actuals = new ArrayList();
+
+ for (int i=0; i < annots.size(); i++)
+ {
+ COSBase item = annots.getObject(i);
+ actuals.add( PDAnnotation.createAnnotation( item ) );
+ }
+ retval = new COSArrayList(actuals, annots);
+ }
+ return retval;
+ }
+
+ /**
+ * This will set the list of annotations.
+ *
+ * @param annots The new list of annotations.
+ */
+ public void setAnnotations( List annots )
+ {
+ page.setItem( COSName.ANNOTS, COSArrayList.converterToCOSArray( annots ) );
+ }
+
+ /**
+ * @see Printable#print(java.awt.Graphics, java.awt.print.PageFormat, int)
+ */
+ public int print(Graphics graphics, PageFormat pageFormat, int pageIndex)
+ throws PrinterException
+ {
+ int retval = Printable.NO_SUCH_PAGE;
+ if( pageIndex == 0 )
+ {
+ try
+ {
+ retval = Printable.PAGE_EXISTS;
+ PageDrawer drawer = new PageDrawer();
+ PDRectangle pageSize = findMediaBox();
+ Paper paper = new Paper();
+
+ paper.setImageableArea( 0, 0, pageSize.getWidth(), pageSize.getHeight());
+ pageFormat.setPaper( paper );
+ drawer.drawPage( graphics, this, pageSize.createDimension() );
+
+ }
+ catch( IOException io )
+ {
+ throw new PrinterIOException( io );
+ }
+
+ }
+ return retval;
+ }
+
+ /**
+ * @see Object#equals( Object )
+ */
+ public boolean equals( Object other )
+ {
+ return other instanceof PDPage && ((PDPage)other).getCOSObject() == this.getCOSObject();
+ }
+
+ /**
+ * @see Object#hashCode()
+ */
+ public int hashCode()
+ {
+ return this.getCOSDictionary().hashCode();
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/PDPageNode.java b/src/main/java/org/pdfbox/pdmodel/PDPageNode.java
new file mode 100644
index 0000000..9567d39
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/PDPageNode.java
@@ -0,0 +1,459 @@
+/**
+ * Copyright (c) 2003, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel;
+
+import org.pdfbox.cos.COSArray;
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSName;
+import org.pdfbox.cos.COSNumber;
+import org.pdfbox.cos.COSInteger;
+
+import org.pdfbox.pdmodel.common.COSArrayList;
+import org.pdfbox.pdmodel.common.COSObjectable;
+import org.pdfbox.pdmodel.common.PDRectangle;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * This represents a page node in a pdf document.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.6 $
+ */
+public class PDPageNode implements COSObjectable
+{
+ private COSDictionary page;
+
+ /**
+ * Creates a new instance of PDPage.
+ */
+ public PDPageNode()
+ {
+ page = new COSDictionary();
+ page.setItem( COSName.TYPE, COSName.PAGES );
+ page.setItem( COSName.KIDS, new COSArray() );
+ page.setItem( COSName.COUNT, new COSInteger( 0 ) );
+ }
+
+ /**
+ * Creates a new instance of PDPage.
+ *
+ * @param pages The dictionary pages.
+ */
+ public PDPageNode( COSDictionary pages )
+ {
+ page = pages;
+ }
+
+ /**
+ * This will update the count attribute of the page node. This only needs to
+ * be called if you add or remove pages. The PDDocument will call this for you
+ * when you use the PDDocumnet persistence methods. So, basically most clients
+ * will never need to call this.
+ *
+ * @return The update count for this node.
+ */
+ public long updateCount()
+ {
+ long totalCount = 0;
+ List kids = getKids();
+ Iterator kidIter = kids.iterator();
+ while( kidIter.hasNext() )
+ {
+ Object next = kidIter.next();
+ if( next instanceof PDPage )
+ {
+ totalCount++;
+ }
+ else
+ {
+ PDPageNode node = (PDPageNode)next;
+ totalCount += node.updateCount();
+ }
+ }
+ page.setItem( COSName.COUNT, new COSInteger( totalCount ) );
+ return totalCount;
+ }
+
+ /**
+ * This will get the count of descendent page objects.
+ *
+ * @return The total number of descendent page objects.
+ */
+ public long getCount()
+ {
+ return ((COSNumber)page.getDictionaryObject( COSName.COUNT )).intValue();
+ }
+
+ /**
+ * This will get the underlying dictionary that this class acts on.
+ *
+ * @return The underlying dictionary for this class.
+ */
+ public COSDictionary getDictionary()
+ {
+ return page;
+ }
+
+ /**
+ * This is the parent page node.
+ *
+ * @return The parent to this page.
+ */
+ public PDPageNode getParent()
+ {
+ PDPageNode parent = null;
+ COSDictionary parentDic = (COSDictionary)page.getDictionaryObject( COSName.PARENT );
+ if( parentDic != null )
+ {
+ parent = new PDPageNode( parentDic );
+ }
+ return parent;
+ }
+
+ /**
+ * This will set the parent of this page.
+ *
+ * @param parent The parent to this page node.
+ */
+ public void setParent( PDPageNode parent )
+ {
+ page.setItem( COSName.PARENT, parent.getDictionary() );
+ }
+
+ /**
+ * @see COSObjectable#getCOSObject()
+ */
+ public COSBase getCOSObject()
+ {
+ return page;
+ }
+
+ /**
+ * This will return all kids of this node, either PDPageNode or PDPage.
+ *
+ * @return All direct descendents of this node.
+ */
+ public List getKids()
+ {
+ List actuals = new ArrayList();
+ COSArray kids = getAllKids(actuals, page, false);
+ return new COSArrayList( actuals, kids );
+ }
+
+ /**
+ * This will return all kids of this node as PDPage.
+ *
+ * @param result All direct and indirect descendents of this node are added to this list.
+ */
+ public void getAllKids(List result)
+ {
+ getAllKids(result, page, true);
+ }
+
+ /**
+ * This will return all kids of the given page node as PDPage.
+ *
+ * @param result All direct and optionally indirect descendents of this node are added to this list.
+ * @param page Page dictionary of a page node.
+ * @param recurse if true indirect descendents are processed recursively
+ */
+ private static COSArray getAllKids(List result, COSDictionary page, boolean recurse)
+ {
+ COSArray kids = (COSArray)page.getDictionaryObject( COSName.KIDS );
+
+ for( int i=0; i<kids.size(); i++ )
+ {
+ COSBase obj = kids.getObject( i );
+ if (obj instanceof COSDictionary)
+ {
+ COSDictionary kid = (COSDictionary)obj;
+ if( COSName.PAGE.equals( kid.getDictionaryObject( COSName.TYPE ) ) )
+ {
+ result.add( new PDPage( kid ) );
+ }
+ else
+ {
+ if (recurse)
+ {
+ getAllKids(result, kid, recurse);
+ }
+ else
+ {
+ result.add( new PDPageNode( kid ) );
+ }
+ }
+ }
+ }
+ return kids;
+ }
+
+ /**
+ * This will get the resources at this page node 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)page.getDictionaryObject( COSName.RESOURCES );
+ if( resources != null )
+ {
+ retval = new PDResources( resources );
+ }
+ return retval;
+ }
+
+ /**
+ * This will find the resources for this page by looking up the hierarchy until
+ * it finds them.
+ *
+ * @return The resources at this level in the hierarchy.
+ */
+ public PDResources findResources()
+ {
+ PDResources retval = getResources();
+ PDPageNode parent = getParent();
+ if( retval == null && parent != null )
+ {
+ retval = parent.findResources();
+ }
+ return retval;
+ }
+
+ /**
+ * This will set the resources for this page.
+ *
+ * @param resources The new resources for this page.
+ */
+ public void setResources( PDResources resources )
+ {
+ if( resources == null )
+ {
+ page.removeItem( COSName.RESOURCES );
+ }
+ else
+ {
+ page.setItem( COSName.RESOURCES, resources.getCOSDictionary() );
+ }
+ }
+
+ /**
+ * This will get the MediaBox at this page and not look up the hierarchy.
+ * This attribute is inheritable, and findMediaBox() should probably used.
+ * This will return null if no MediaBox are available at this level.
+ *
+ * @return The MediaBox at this level in the hierarchy.
+ */
+ public PDRectangle getMediaBox()
+ {
+ PDRectangle retval = null;
+ COSArray array = (COSArray)page.getDictionaryObject( COSName.MEDIA_BOX );
+ if( array != null )
+ {
+ retval = new PDRectangle( array );
+ }
+ return retval;
+ }
+
+ /**
+ * This will find the MediaBox for this page by looking up the hierarchy until
+ * it finds them.
+ *
+ * @return The MediaBox at this level in the hierarchy.
+ */
+ public PDRectangle findMediaBox()
+ {
+ PDRectangle retval = getMediaBox();
+ PDPageNode parent = getParent();
+ if( retval == null && parent != null )
+ {
+ retval = parent.findMediaBox();
+ }
+ return retval;
+ }
+
+ /**
+ * This will set the mediaBox for this page.
+ *
+ * @param mediaBox The new mediaBox for this page.
+ */
+ public void setMediaBox( PDRectangle mediaBox )
+ {
+ if( mediaBox == null )
+ {
+ page.removeItem( COSName.MEDIA_BOX );
+ }
+ else
+ {
+ page.setItem( COSName.MEDIA_BOX , mediaBox.getCOSArray() );
+ }
+ }
+
+/**
+ * This will get the CropBox at this page and not look up the hierarchy.
+ * This attribute is inheritable, and findCropBox() should probably used.
+ * This will return null if no CropBox is available at this level.
+ *
+ * @return The CropBox at this level in the hierarchy.
+ */
+ public PDRectangle getCropBox()
+ {
+ PDRectangle retval = null;
+ COSArray array = (COSArray)page.getDictionaryObject( COSName.CROP_BOX );
+ if( array != null )
+ {
+ retval = new PDRectangle( array );
+ }
+ return retval;
+ }
+
+ /**
+ * This will find the CropBox for this page by looking up the hierarchy until
+ * it finds them.
+ *
+ * @return The CropBox at this level in the hierarchy.
+ */
+ public PDRectangle findCropBox()
+ {
+ PDRectangle retval = getCropBox();
+ PDPageNode parent = getParent();
+ if( retval == null && parent != null )
+ {
+ retval = findParentCropBox( parent );
+ }
+
+ //default value for cropbox is the media box
+ if( retval == null )
+ {
+ retval = findMediaBox();
+ }
+ return retval;
+ }
+
+ /**
+ * This will search for a crop box in the parent and return null if it is not
+ * found. It will NOT default to the media box if it cannot be found.
+ *
+ * @param node The node
+ */
+ private PDRectangle findParentCropBox( PDPageNode node )
+ {
+ PDRectangle rect = node.getCropBox();
+ PDPageNode parent = node.getParent();
+ if( rect == null && parent != null )
+ {
+ rect = findParentCropBox( node );
+ }
+ return rect;
+ }
+
+ /**
+ * This will set the CropBox for this page.
+ *
+ * @param cropBox The new CropBox for this page.
+ */
+ public void setCropBox( PDRectangle cropBox )
+ {
+ if( cropBox == null )
+ {
+ page.removeItem( COSName.CROP_BOX );
+ }
+ else
+ {
+ page.setItem( COSName.CROP_BOX, cropBox.getCOSArray() );
+ }
+ }
+
+ /**
+ * A value representing the rotation. This will be null if not set at this level
+ * The number of degrees by which the page should
+ * be rotated clockwise when displayed or printed. The value must be a multiple
+ * of 90.
+ *
+ * This will get the rotation at this page and not look up the hierarchy.
+ * This attribute is inheritable, and findRotation() should probably used.
+ * This will return null if no rotation is available at this level.
+ *
+ * @return The rotation at this level in the hierarchy.
+ */
+ public Integer getRotation()
+ {
+ Integer retval = null;
+ COSNumber value = (COSNumber)page.getDictionaryObject( COSName.ROTATE );
+ if( value != null )
+ {
+ retval = new Integer( (int)value.intValue() );
+ }
+ return retval;
+ }
+
+ /**
+ * This will find the rotation for this page by looking up the hierarchy until
+ * it finds them.
+ *
+ * @return The rotation at this level in the hierarchy.
+ */
+ public int findRotation()
+ {
+ int retval = 0;
+ Integer rotation = getRotation();
+ if( rotation != null )
+ {
+ retval = rotation.intValue();
+ }
+ else
+ {
+ PDPageNode parent = getParent();
+ if( parent != null )
+ {
+ retval = parent.findRotation();
+ }
+ }
+
+ return retval;
+ }
+
+ /**
+ * This will set the rotation for this page.
+ *
+ * @param rotation The new rotation for this page.
+ */
+ public void setRotation( int rotation )
+ {
+ page.setItem( COSName.ROTATE, new COSInteger( rotation ) );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/PDResources.java b/src/main/java/org/pdfbox/pdmodel/PDResources.java
new file mode 100644
index 0000000..9494b69
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/PDResources.java
@@ -0,0 +1,313 @@
+/**
+ * Copyright (c) 2003-2005, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel;
+
+import java.io.IOException;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSName;
+import org.pdfbox.cos.COSStream;
+
+import org.pdfbox.pdmodel.common.COSDictionaryMap;
+import org.pdfbox.pdmodel.common.COSObjectable;
+
+import org.pdfbox.pdmodel.font.PDFontFactory;
+
+import org.pdfbox.pdmodel.graphics.PDExtendedGraphicsState;
+
+import org.pdfbox.pdmodel.graphics.color.PDColorSpaceFactory;
+
+import org.pdfbox.pdmodel.graphics.xobject.PDXObject;
+import org.pdfbox.pdmodel.graphics.xobject.PDXObjectImage;
+
+/**
+ * This represents a set of resources available at the page/pages/stream level.
+ *
+ * @author Ben Litchfield (ben@benlitchfield.com)
+ * @version $Revision: 1.13 $
+ */
+public class PDResources implements COSObjectable
+{
+ private COSDictionary resources;
+
+ /**
+ * Default constructor.
+ */
+ public PDResources()
+ {
+ resources = new COSDictionary();
+ }
+
+ /**
+ * Prepopulated resources.
+ *
+ * @param resourceDictionary The cos dictionary for this resource.
+ */
+ public PDResources( COSDictionary resourceDictionary )
+ {
+ resources = resourceDictionary;
+ }
+
+ /**
+ * This will get the underlying dictionary.
+ *
+ * @return The dictionary for these resources.
+ */
+ public COSDictionary getCOSDictionary()
+ {
+ return resources;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSBase getCOSObject()
+ {
+ return resources;
+ }
+
+ /**
+ * This will get the map of fonts. This will never return null. The keys are string
+ * and the values are PDFont objects.
+ *
+ * @return The map of fonts.
+ *
+ * @throws IOException If there is an error getting the fonts.
+ */
+ public Map getFonts() throws IOException
+ {
+ Map retval = null;
+ COSDictionary fonts = (COSDictionary)resources.getDictionaryObject( COSName.FONT );
+
+ if( fonts == null )
+ {
+ fonts = new COSDictionary();
+ resources.setItem( COSName.FONT, fonts );
+ }
+
+ Map actuals = new HashMap();
+ retval = new COSDictionaryMap( actuals, fonts );
+ Iterator fontNames = fonts.keyList().iterator();
+ while( fontNames.hasNext() )
+ {
+ COSName fontName = (COSName)fontNames.next();
+ COSBase font = fonts.getDictionaryObject( fontName );
+ //data-000174.pdf contains a font that is a COSArray, looks to be an error in the
+ //PDF, we will just ignore entries that are not dictionaries.
+ if( font instanceof COSDictionary )
+ {
+ COSDictionary fontDictionary = (COSDictionary)font;
+ actuals.put( fontName.getName(), PDFontFactory.createFont( fontDictionary ) );
+ }
+ }
+ return retval;
+ }
+
+ /**
+ * This will get the map of PDXObjects that are in the resource dictionary.
+ *
+ * @return The map of xobjects.
+ *
+ * @throws IOException If there is an error creating the xobjects.
+ */
+ public Map getXObjects() throws IOException
+ {
+ Map retval = null;
+ COSDictionary xobjects = (COSDictionary)resources.getDictionaryObject( "XObject" );
+
+ if( xobjects == null )
+ {
+ xobjects = new COSDictionary();
+ resources.setItem( "XObject", xobjects );
+ }
+
+ Map actuals = new HashMap();
+ retval = new COSDictionaryMap( actuals, xobjects );
+ Iterator imageNames = xobjects.keyList().iterator();
+ while( imageNames.hasNext() )
+ {
+ COSName objName = (COSName)imageNames.next();
+ COSBase cosObject = xobjects.getDictionaryObject(objName);
+ PDXObject xobject = PDXObject.createXObject( cosObject );
+ if( xobject !=null )
+ {
+ actuals.put( objName.getName(), xobject);
+ }
+ }
+ return retval;
+ }
+
+ /**
+ * This will get the map of images. An empty map will be returned if there
+ * are no underlying images.
+ * So far the keys are COSName of the image
+ * and the value is the corresponding PDXObjectImage.
+ *
+ * @author By BM
+ * @return The map of images.
+ * @throws IOException If there is an error writing the picture.
+ */
+ public Map getImages() throws IOException
+ {
+ Map retval = null;
+ COSDictionary images = (COSDictionary)resources.getDictionaryObject( "XObject" );
+
+ if( images == null )
+ {
+ images = new COSDictionary();
+ resources.setItem( "XObject", images );
+ }
+
+ if( images != null )
+ {
+ Map actuals = new HashMap();
+ retval = new COSDictionaryMap( actuals, images );
+ Iterator imageNames = images.keyList().iterator();
+ while( imageNames.hasNext() )
+ {
+ COSName imageName = (COSName)imageNames.next();
+ COSStream image = (COSStream)(images.getDictionaryObject(imageName));
+
+ COSName subType =(COSName)image.getDictionaryObject(COSName.SUBTYPE);
+ if( subType.equals(COSName.IMAGE) )
+ {
+ PDXObjectImage ximage = (PDXObjectImage)PDXObject.createXObject( image );
+ if( ximage !=null )
+ {
+ actuals.put( imageName.getName(), ximage);
+ }
+ }
+ }
+ }
+ return retval;
+ }
+
+ /**
+ * This will set the map of fonts.
+ *
+ * @param fonts The new map of fonts.
+ */
+ public void setFonts( Map fonts )
+ {
+ resources.setItem( COSName.FONT, COSDictionaryMap.convert( fonts ) );
+ }
+
+ /**
+ * This will get the map of colorspaces. This will return null if the underlying
+ * resources dictionary does not have a colorspace dictionary. The keys are string
+ * and the values are PDColorSpace objects.
+ *
+ * @return The map of colorspaces.
+ *
+ * @throws IOException If there is an error getting the colorspaces.
+ */
+ public Map getColorSpaces() throws IOException
+ {
+ Map retval = null;
+ COSDictionary colorspaces = (COSDictionary)resources.getDictionaryObject( COSName.getPDFName( "ColorSpace" ) );
+
+ if( colorspaces != null )
+ {
+ Map actuals = new HashMap();
+ retval = new COSDictionaryMap( actuals, colorspaces );
+ Iterator csNames = colorspaces.keyList().iterator();
+ while( csNames.hasNext() )
+ {
+ COSName csName = (COSName)csNames.next();
+ COSBase cs = colorspaces.getDictionaryObject( csName );
+ actuals.put( csName.getName(), PDColorSpaceFactory.createColorSpace( cs ) );
+ }
+ }
+ return retval;
+ }
+
+ /**
+ * This will set the map of colorspaces.
+ *
+ * @param colorspaces The new map of colorspaces.
+ */
+ public void setColorSpaces( Map colorspaces )
+ {
+ resources.setItem( COSName.getPDFName( "ColorSpace" ), COSDictionaryMap.convert( colorspaces ) );
+ }
+
+ /**
+ * This will get the map of graphic states. This will return null if the underlying
+ * resources dictionary does not have a graphics dictionary. The keys are the graphic state
+ * name as a String and the values are PDExtendedGraphicsState objects.
+ *
+ * @return The map of extended graphic state objects.
+ */
+ public Map getGraphicsStates()
+ {
+ Map retval = null;
+ COSDictionary states = (COSDictionary)resources.getDictionaryObject( COSName.getPDFName( "ExtGState" ) );
+
+ if( states != null )
+ {
+ Map actuals = new HashMap();
+ retval = new COSDictionaryMap( actuals, states );
+ Iterator names = states.keyList().iterator();
+ while( names.hasNext() )
+ {
+ COSName name = (COSName)names.next();
+ COSDictionary dictionary = (COSDictionary)states.getDictionaryObject( name );
+ actuals.put( name.getName(), new PDExtendedGraphicsState( dictionary ) );
+ }
+ }
+ return retval;
+ }
+
+ /**
+ * This will set the map of graphics states.
+ *
+ * @param states The new map of states.
+ */
+ public void setGraphicsStates( Map states )
+ {
+ Iterator iter = states.keySet().iterator();
+ COSDictionary dic = new COSDictionary();
+ while( iter.hasNext() )
+ {
+ String name = (String)iter.next();
+ PDExtendedGraphicsState state = (PDExtendedGraphicsState)states.get( name );
+ dic.setItem( COSName.getPDFName( name ), state.getCOSObject() );
+ }
+ resources.setItem( COSName.getPDFName( "ExtGState" ), dic );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/common/COSArrayList.java b/src/main/java/org/pdfbox/pdmodel/common/COSArrayList.java
new file mode 100644
index 0000000..bb3648a
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/common/COSArrayList.java
@@ -0,0 +1,643 @@
+/**
+ * Copyright (c) 2003-2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.common;
+
+import org.pdfbox.cos.COSArray;
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSInteger;
+import org.pdfbox.cos.COSFloat;
+import org.pdfbox.cos.COSString;
+import org.pdfbox.cos.COSName;
+import org.pdfbox.cos.COSNull;
+import org.pdfbox.cos.COSNumber;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+
+/**
+ * This is an implementation of a List that will sync its contents to a COSArray.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.12 $
+ */
+public class COSArrayList implements List
+{
+ private COSArray array;
+ private List actual;
+
+ private COSDictionary parentDict;
+ private String dictKey;
+
+ /**
+ * Constructor.
+ *
+ * @param actualList The list of standard java objects
+ * @param cosArray The COS array object to sync to.
+ */
+ public COSArrayList( List actualList, COSArray cosArray )
+ {
+ actual = actualList;
+ array = cosArray;
+ }
+
+ /**
+ * This is a really special constructor. Sometimes the PDF spec says
+ * that a dictionary entry can either be a single item or an array of those
+ * items. But in the PDModel interface we really just want to always return
+ * a java.util.List. In the case were we get the list and never modify it
+ * we don't want to convert to COSArray and put one element, unless we append
+ * to the list. So here we are going to create this object with a single
+ * item instead of a list, but allow more items to be added and then converted
+ * to an array.
+ *
+ * @param actualObject The PDModel object.
+ * @param item The COS Model object.
+ * @param dictionary The dictionary that holds the item, and will hold the array if an item is added.
+ * @param dictionaryKey The key into the dictionary to set the item.
+ */
+ public COSArrayList( Object actualObject, COSBase item, COSDictionary dictionary, String dictionaryKey )
+ {
+ array = new COSArray();
+ array.add( item );
+ actual = new ArrayList();
+ actual.add( actualObject );
+
+ parentDict = dictionary;
+ dictKey = dictionaryKey;
+ }
+
+ /**
+ * @see List#size()
+ */
+ public int size()
+ {
+ return actual.size();
+ }
+
+ /**
+ * @see List#isEmpty()
+ */
+ public boolean isEmpty()
+ {
+ return actual.isEmpty();
+ }
+
+ /**
+ * @see List#contains( Object )
+ */
+ public boolean contains(Object o)
+ {
+ return actual.contains(o);
+ }
+
+ /**
+ * @see List#iterator()
+ */
+ public Iterator iterator()
+ {
+ return actual.iterator();
+ }
+
+ /**
+ * @see List#toArray()
+ */
+ public Object[] toArray()
+ {
+ return actual.toArray();
+ }
+
+ /**
+ * @see List#toArray( Object[] )
+ */
+ public Object[] toArray(Object[] a)
+ {
+ return actual.toArray(a);
+
+ }
+
+ /**
+ * @see List#add( Object )
+ */
+ public boolean add(Object o)
+ {
+ //when adding if there is a parentDict then change the item
+ //in the dictionary from a single item to an array.
+ if( parentDict != null )
+ {
+ parentDict.setItem( dictKey, array );
+ //clear the parent dict so it doesn't happen again, there might be
+ //a usecase for keeping the parentDict around but not now.
+ parentDict = null;
+ }
+ //string is a special case because we can't subclass to be COSObjectable
+ if( o instanceof String )
+ {
+ array.add( new COSString( (String)o ) );
+ }
+ else if( o instanceof DualCOSObjectable )
+ {
+ DualCOSObjectable dual = (DualCOSObjectable)o;
+ array.add( dual.getFirstCOSObject() );
+ array.add( dual.getSecondCOSObject() );
+ }
+ else
+ {
+ array.add( ((COSObjectable)o).getCOSObject() );
+ }
+ return actual.add(o);
+ }
+
+ /**
+ * @see List#remove( Object )
+ */
+ public boolean remove(Object o)
+ {
+ boolean retval = true;
+ int index = actual.indexOf( o );
+ if( index >= 0 )
+ {
+ actual.remove( index );
+ array.remove( index );
+ }
+ else
+ {
+ retval = false;
+ }
+ return retval;
+ }
+
+ /**
+ * @see List#containsAll( Collection )
+ */
+ public boolean containsAll(Collection c)
+ {
+ return actual.containsAll( c );
+ }
+
+ /**
+ * @see List#addAll( Collection )
+ */
+ public boolean addAll(Collection c)
+ {
+ //when adding if there is a parentDict then change the item
+ //in the dictionary from a single item to an array.
+ if( parentDict != null && c.size() > 0)
+ {
+ parentDict.setItem( dictKey, array );
+ //clear the parent dict so it doesn't happen again, there might be
+ //a usecase for keeping the parentDict around but not now.
+ parentDict = null;
+ }
+ array.addAll( toCOSObjectList( c ) );
+ return actual.addAll( c );
+ }
+
+ /**
+ * @see List#addAll( int, Collection )
+ */
+ public boolean addAll(int index, Collection c)
+ {
+ //when adding if there is a parentDict then change the item
+ //in the dictionary from a single item to an array.
+ if( parentDict != null && c.size() > 0)
+ {
+ parentDict.setItem( dictKey, array );
+ //clear the parent dict so it doesn't happen again, there might be
+ //a usecase for keeping the parentDict around but not now.
+ parentDict = null;
+ }
+
+ if( c.size() >0 && c.toArray()[0] instanceof DualCOSObjectable )
+ {
+ array.addAll( index*2, toCOSObjectList( c ) );
+ }
+ else
+ {
+ array.addAll( index, toCOSObjectList( c ) );
+ }
+ return actual.addAll( index, c );
+ }
+
+ /**
+ * This will take an array of COSNumbers and return a COSArrayList of
+ * java.lang.Integer values.
+ *
+ * @param intArray The existing integer Array.
+ *
+ * @return A list that is part of the core Java collections.
+ */
+ public static List convertIntegerCOSArrayToList( COSArray intArray )
+ {
+ List numbers = new ArrayList();
+ for( int i=0; i<intArray.size(); i++ )
+ {
+ numbers.add( new Integer( ((COSNumber)intArray.get( i )).intValue() ) );
+ }
+ return new COSArrayList( numbers, intArray );
+ }
+
+ /**
+ * This will take an array of COSNumbers and return a COSArrayList of
+ * java.lang.Float values.
+ *
+ * @param floatArray The existing float Array.
+ *
+ * @return The list of Float objects.
+ */
+ public static List convertFloatCOSArrayToList( COSArray floatArray )
+ {
+ List retval = null;
+ if( floatArray != null )
+ {
+ List numbers = new ArrayList();
+ for( int i=0; i<floatArray.size(); i++ )
+ {
+ numbers.add( new Float( ((COSNumber)floatArray.get( i )).floatValue() ) );
+ }
+ retval = new COSArrayList( numbers, floatArray );
+ }
+ return retval;
+ }
+
+ /**
+ * This will take an array of COSName and return a COSArrayList of
+ * java.lang.String values.
+ *
+ * @param nameArray The existing name Array.
+ *
+ * @return The list of String objects.
+ */
+ public static List convertCOSNameCOSArrayToList( COSArray nameArray )
+ {
+ List retval = null;
+ if( nameArray != null )
+ {
+ List names = new ArrayList();
+ for( int i=0; i<nameArray.size(); i++ )
+ {
+ names.add( ((COSName)nameArray.getObject( i )).getName() );
+ }
+ retval = new COSArrayList( names, nameArray );
+ }
+ return retval;
+ }
+
+ /**
+ * This will take an array of COSString and return a COSArrayList of
+ * java.lang.String values.
+ *
+ * @param stringArray The existing name Array.
+ *
+ * @return The list of String objects.
+ */
+ public static List convertCOSStringCOSArrayToList( COSArray stringArray )
+ {
+ List retval = null;
+ if( stringArray != null )
+ {
+ List string = new ArrayList();
+ for( int i=0; i<stringArray.size(); i++ )
+ {
+ string.add( ((COSString)stringArray.getObject( i )).getString() );
+ }
+ retval = new COSArrayList( string, stringArray );
+ }
+ return retval;
+ }
+
+ /**
+ * This will take an list of string objects and return a COSArray of COSName
+ * objects.
+ *
+ * @param strings A list of strings
+ *
+ * @return An array of COSName objects
+ */
+ public static COSArray convertStringListToCOSNameCOSArray( List strings )
+ {
+ COSArray retval = new COSArray();
+ for( int i=0; i<strings.size(); i++ )
+ {
+ Object next = strings.get( i );
+ if( next instanceof COSName )
+ {
+ retval.add( (COSName)next );
+ }
+ else
+ {
+ retval.add( COSName.getPDFName( (String)next ) );
+ }
+ }
+ return retval;
+ }
+
+ /**
+ * This will take an list of string objects and return a COSArray of COSName
+ * objects.
+ *
+ * @param strings A list of strings
+ *
+ * @return An array of COSName objects
+ */
+ public static COSArray convertStringListToCOSStringCOSArray( List strings )
+ {
+ COSArray retval = new COSArray();
+ for( int i=0; i<strings.size(); i++ )
+ {
+ retval.add( new COSString( (String)strings.get( i ) ) );
+ }
+ return retval;
+ }
+
+ /**
+ * This will convert a list of COSObjectables to an
+ * array list of COSBase objects.
+ *
+ * @param cosObjectableList A list of COSObjectable.
+ *
+ * @return A list of COSBase.
+ */
+ public static COSArray converterToCOSArray( List cosObjectableList )
+ {
+ COSArray array = null;
+ if( cosObjectableList != null )
+ {
+ array = new COSArray();
+ Iterator iter = cosObjectableList.iterator();
+ while( iter.hasNext() )
+ {
+ Object next = iter.next();
+ if( next instanceof String )
+ {
+ array.add( new COSString( (String)next ) );
+ }
+ else if( next instanceof Integer || next instanceof Long )
+ {
+ array.add( new COSInteger( ((Number)next).longValue() ) );
+ }
+ else if( next instanceof Float || next instanceof Double )
+ {
+ array.add( new COSFloat( ((Number)next).floatValue() ) );
+ }
+ else if( next instanceof COSObjectable )
+ {
+ COSObjectable object = (COSObjectable)next;
+ array.add( object.getCOSObject() );
+ }
+ else if( next instanceof DualCOSObjectable )
+ {
+ DualCOSObjectable object = (DualCOSObjectable)next;
+ array.add( object.getFirstCOSObject() );
+ array.add( object.getSecondCOSObject() );
+ }
+ else if( next == null )
+ {
+ array.add( COSNull.NULL );
+ }
+ else
+ {
+ throw new RuntimeException( "Error: Don't know how to convert type to COSBase '" +
+ next.getClass().getName() + "'" );
+ }
+ }
+ }
+ return array;
+ }
+
+ private List toCOSObjectList( Collection list )
+ {
+ List cosObjects = new ArrayList();
+ Iterator iter = list.iterator();
+ while( iter.hasNext() )
+ {
+ Object next = iter.next();
+ if( next instanceof String )
+ {
+ cosObjects.add( new COSString( (String)next ) );
+ }
+ else if( next instanceof DualCOSObjectable )
+ {
+ DualCOSObjectable object = (DualCOSObjectable)next;
+ array.add( object.getFirstCOSObject() );
+ array.add( object.getSecondCOSObject() );
+ }
+ else
+ {
+ COSObjectable cos = (COSObjectable)next;
+ cosObjects.add( cos.getCOSObject() );
+ }
+ }
+ return cosObjects;
+ }
+
+ /**
+ * @see List#removeAll( Collection )
+ */
+ public boolean removeAll(Collection c)
+ {
+ array.removeAll( toCOSObjectList( c ) );
+ return actual.removeAll( c );
+ }
+
+ /**
+ * @see List#retainAll( Collection )
+ */
+ public boolean retainAll(Collection c)
+ {
+ array.retainAll( toCOSObjectList( c ) );
+ return actual.retainAll( c );
+ }
+
+ /**
+ * @see List#clear()
+ */
+ public void clear()
+ {
+ //when adding if there is a parentDict then change the item
+ //in the dictionary from a single item to an array.
+ if( parentDict != null )
+ {
+ parentDict.setItem( dictKey, (COSBase)null );
+ }
+ actual.clear();
+ array.clear();
+ }
+
+ /**
+ * @see List#equals( Object )
+ */
+ public boolean equals(Object o)
+ {
+ return actual.equals( o );
+ }
+
+ /**
+ * @see List#hashCode()
+ */
+ public int hashCode()
+ {
+ return actual.hashCode();
+ }
+
+ /**
+ * @see List#get( int )
+ */
+ public Object get(int index)
+ {
+ return actual.get( index );
+
+ }
+
+ /**
+ * @see List#set( int, Object )
+ */
+ public Object set(int index, Object element)
+ {
+ if( element instanceof String )
+ {
+ COSString item = new COSString( (String)element );
+ if( parentDict != null && index == 0 )
+ {
+ parentDict.setItem( dictKey, item );
+ }
+ array.set( index, item );
+ }
+ else if( element instanceof DualCOSObjectable )
+ {
+ DualCOSObjectable dual = (DualCOSObjectable)element;
+ array.set( index*2, dual.getFirstCOSObject() );
+ array.set( index*2+1, dual.getSecondCOSObject() );
+ }
+ else
+ {
+ if( parentDict != null && index == 0 )
+ {
+ parentDict.setItem( dictKey, ((COSObjectable)element).getCOSObject() );
+ }
+ array.set( index, ((COSObjectable)element).getCOSObject() );
+ }
+ return actual.set( index, element );
+ }
+
+ /**
+ * @see List#add( int, Object )
+ */
+ public void add(int index, Object element)
+ {
+ //when adding if there is a parentDict then change the item
+ //in the dictionary from a single item to an array.
+ if( parentDict != null )
+ {
+ parentDict.setItem( dictKey, array );
+ //clear the parent dict so it doesn't happen again, there might be
+ //a usecase for keeping the parentDict around but not now.
+ parentDict = null;
+ }
+ actual.add( index, element );
+ if( element instanceof String )
+ {
+ array.add( index, new COSString( (String)element ) );
+ }
+ else if( element instanceof DualCOSObjectable )
+ {
+ DualCOSObjectable dual = (DualCOSObjectable)element;
+ array.add( index*2, dual.getFirstCOSObject() );
+ array.add( index*2+1, dual.getSecondCOSObject() );
+ }
+ else
+ {
+ array.add( index, ((COSObjectable)element).getCOSObject() );
+ }
+ }
+
+ /**
+ * @see List#remove( int )
+ */
+ public Object remove(int index)
+ {
+ if( array.size() > index && array.get( index ) instanceof DualCOSObjectable )
+ {
+ //remove both objects
+ array.remove( index );
+ array.remove( index );
+ }
+ else
+ {
+ array.remove( index );
+ }
+ return actual.remove( index );
+ }
+
+ /**
+ * @see List#indexOf( Object )
+ */
+ public int indexOf(Object o)
+ {
+ return actual.indexOf( o );
+ }
+
+ /**
+ * @see List#lastIndexOf( Object )
+ */
+ public int lastIndexOf(Object o)
+ {
+ return actual.indexOf( o );
+
+ }
+
+ /**
+ * @see List#listIterator()
+ */
+ public ListIterator listIterator()
+ {
+ return actual.listIterator();
+ }
+
+ /**
+ * @see List#listIterator( int )
+ */
+ public ListIterator listIterator(int index)
+ {
+ return actual.listIterator( index );
+ }
+
+ /**
+ * @see List#subList( int, int )
+ */
+ public List subList(int fromIndex, int toIndex)
+ {
+ return actual.subList( fromIndex, toIndex );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/common/COSDictionaryMap.java b/src/main/java/org/pdfbox/pdmodel/common/COSDictionaryMap.java
new file mode 100644
index 0000000..ca3821d
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/common/COSDictionaryMap.java
@@ -0,0 +1,278 @@
+/**
+ * Copyright (c) 2003-2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.common;
+
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSBoolean;
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSFloat;
+import org.pdfbox.cos.COSInteger;
+import org.pdfbox.cos.COSName;
+import org.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.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.9 $
+ */
+public class COSDictionaryMap implements Map
+{
+ private COSDictionary map;
+ private Map actuals;
+
+ /**
+ * Constructor for this map.
+ *
+ * @param actualsMap The map with standard java objects as values.
+ * @param dicMap The map with COSBase objects as values.
+ */
+ public COSDictionaryMap( Map actualsMap, COSDictionary dicMap )
+ {
+ actuals = actualsMap;
+ map = dicMap;
+ }
+
+
+ /**
+ * @see java.util.Map#size()
+ */
+ public int size()
+ {
+ return map.size();
+ }
+
+ /**
+ * @see java.util.Map#isEmpty()
+ */
+ public boolean isEmpty()
+ {
+ return size() == 0;
+ }
+
+ /**
+ * @see java.util.Map#containsKey()
+ */
+ public boolean containsKey(Object key)
+ {
+ return map.keyList().contains( key );
+ }
+
+ /**
+ * @see java.util.Map#containsValue()
+ */
+ public boolean containsValue(Object value)
+ {
+ return actuals.containsValue( value );
+ }
+
+ /**
+ * @see java.util.Map#get()
+ */
+ public Object get(Object key)
+ {
+ return actuals.get( key );
+ }
+
+ /**
+ * @see java.util.Map#put()
+ */
+ public Object put(Object key, Object value)
+ {
+ COSObjectable object = (COSObjectable)value;
+
+ map.setItem( COSName.getPDFName( (String)key ), object.getCOSObject() );
+ return actuals.put( key, value );
+ }
+
+ /**
+ * @see java.util.Map#remove()
+ */
+ public Object remove(Object key)
+ {
+ map.removeItem( COSName.getPDFName( (String)key ) );
+ return actuals.remove( key );
+ }
+
+ /**
+ * @see java.util.Map#putAll()
+ */
+ public void putAll(Map t)
+ {
+ throw new RuntimeException( "Not yet implemented" );
+ }
+
+ /**
+ * @see java.util.Map#clear()
+ */
+ public void clear()
+ {
+ map.clear();
+ actuals.clear();
+ }
+
+ /**
+ * @see java.util.Map#keySet()
+ */
+ public Set keySet()
+ {
+ return actuals.keySet();
+ }
+
+ /**
+ * @see java.util.Map#values()
+ */
+ public Collection values()
+ {
+ return actuals.values();
+ }
+
+ /**
+ * @see java.util.Map#entrySet()
+ */
+ public Set entrySet()
+ {
+ throw new RuntimeException( "Not yet implemented" );
+ }
+
+ /**
+ * @see java.util.Map#equals()
+ */
+ public boolean equals(Object o)
+ {
+ boolean retval = false;
+ if( o instanceof COSDictionaryMap )
+ {
+ COSDictionaryMap other = (COSDictionaryMap)o;
+ retval = other.map.equals( this.map );
+ }
+ return retval;
+ }
+
+ /**
+ * This will get a string representation of this map.
+ *
+ * @return A human readable form of this map.
+ */
+ public String toString()
+ {
+ return actuals.toString();
+ }
+
+ /**
+ * @see java.util.Map#hashCode()
+ */
+ public int hashCode()
+ {
+ return map.hashCode();
+ }
+
+ /**
+ * This will take a map&lt;java.lang.String,org.pdfbox.pdmodel.COSObjectable&gt;
+ * and convert it into a COSDictionary&lt;COSName,COSBase&gt;.
+ *
+ * @param someMap A map containing COSObjectables
+ *
+ * @return A proper COSDictionary
+ */
+ public static COSDictionary convert( Map someMap )
+ {
+ Iterator iter = someMap.keySet().iterator();
+ COSDictionary dic = new COSDictionary();
+ while( iter.hasNext() )
+ {
+ String name = (String)iter.next();
+ COSObjectable object = (COSObjectable)someMap.get( name );
+ dic.setItem( COSName.getPDFName( name ), object.getCOSObject() );
+ }
+ return dic;
+ }
+
+ /**
+ * This will take a COS dictionary and convert it into COSDictionaryMap. All cos
+ * objects will be converted to their primitive form.
+ *
+ * @param map The COS mappings.
+ * @return A standard java map.
+ * @throws IOException If there is an error during the conversion.
+ */
+ public static COSDictionaryMap convertBasicTypesToMap( COSDictionary map ) throws IOException
+ {
+ COSDictionaryMap retval = null;
+ if( map != null )
+ {
+ Map actualMap = new HashMap();
+ Iterator keyIter = map.keyList().iterator();
+ while( keyIter.hasNext() )
+ {
+ COSName key = (COSName)keyIter.next();
+ COSBase cosObj = map.getDictionaryObject( key );
+ Object actualObject = null;
+ if( cosObj instanceof COSString )
+ {
+ actualObject = ((COSString)cosObj).getString();
+ }
+ else if( cosObj instanceof COSInteger )
+ {
+ actualObject = new Integer( ((COSInteger)cosObj).intValue() );
+ }
+ else if( cosObj instanceof COSName )
+ {
+ actualObject = ((COSName)cosObj).getName();
+ }
+ else if( cosObj instanceof COSFloat )
+ {
+ actualObject = new Float( ((COSInteger)cosObj).floatValue() );
+ }
+ else if( cosObj instanceof COSBoolean )
+ {
+ actualObject = ((COSBoolean)cosObj).getValue() ? Boolean.TRUE : Boolean.FALSE;
+ }
+ else
+ {
+ throw new IOException( "Error:unknown type of object to convert:" + cosObj );
+ }
+ actualMap.put( key.getName(), actualObject );
+ }
+ retval = new COSDictionaryMap( actualMap, map );
+ }
+
+ return retval;
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/common/COSObjectable.java b/src/main/java/org/pdfbox/pdmodel/common/COSObjectable.java
new file mode 100644
index 0000000..5bf7bfc
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/common/COSObjectable.java
@@ -0,0 +1,49 @@
+/**
+ * Copyright (c) 2003, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.common;
+
+import org.pdfbox.cos.COSBase;
+
+/**
+ * This is an interface used to get/create the underlying COSObject.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.2 $
+ */
+public interface COSObjectable
+{
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSBase getCOSObject();
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/common/COSStreamArray.java b/src/main/java/org/pdfbox/pdmodel/common/COSStreamArray.java
new file mode 100644
index 0000000..87dbb6a
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/common/COSStreamArray.java
@@ -0,0 +1,304 @@
+/**
+ * Copyright (c) 2003-2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.common;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.RandomAccessFile;
+import java.io.SequenceInputStream;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Vector;
+
+import org.pdfbox.cos.COSArray;
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSName;
+import org.pdfbox.cos.COSStream;
+import org.pdfbox.cos.ICOSVisitor;
+
+import org.pdfbox.exceptions.COSVisitorException;
+
+import org.pdfbox.pdfparser.PDFStreamParser;
+
+/**
+ * This will take an array of streams and sequence them together.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.7 $
+ */
+public class COSStreamArray extends COSStream
+{
+ private COSArray streams;
+
+ /**
+ * The first stream will be used to delegate some of the methods for this
+ * class.
+ */
+ private COSStream firstStream;
+
+ /**
+ * Constructor.
+ *
+ * @param array The array of COSStreams to concatenate together.
+ */
+ public COSStreamArray( COSArray array )
+ {
+ super( new COSDictionary(), null );
+ streams = array;
+ if( array.size() > 0 )
+ {
+ firstStream = (COSStream)array.getObject( 0 );
+ }
+ }
+ /**
+ * This will get the scratch file associated with this stream.
+ *
+ * @return The scratch file where this stream is being stored.
+ */
+ public RandomAccessFile getScratchFile()
+ {
+ return firstStream.getScratchFile();
+ }
+
+ /**
+ * This will get an object from this streams dictionary.
+ *
+ * @param key The key to the object.
+ *
+ * @return The dictionary object with the key or null if one does not exist.
+ */
+ public COSBase getItem( COSName key )
+ {
+ return firstStream.getItem( key );
+ }
+
+ /**
+ * This will get an object from this streams dictionary and dereference it
+ * if necessary.
+ *
+ * @param key The key to the object.
+ *
+ * @return The dictionary object with the key or null if one does not exist.
+ */
+ public COSBase getDictionaryObject( COSName key )
+ {
+ return firstStream.getDictionaryObject( key );
+ }
+
+ /**
+ * @see Object#toString()
+ */
+ public String toString()
+ {
+ String result = "COSStream{}";
+ return result;
+ }
+
+ /**
+ * This will get all the tokens in the stream.
+ *
+ * @return All of the tokens in the stream.
+ *
+ * @throws IOException If there is an error parsing the stream.
+ */
+ public List getStreamTokens() throws IOException
+ {
+ List retval = null;
+ if( streams.size() > 0 )
+ {
+ PDFStreamParser parser = new PDFStreamParser( this );
+ parser.parse();
+ retval = parser.getTokens();
+ }
+ else
+ {
+ retval = new ArrayList();
+ }
+ return retval;
+ }
+
+ /**
+ * This will get the dictionary that is associated with this stream.
+ *
+ * @return the object that is associated with this stream.
+ */
+ public COSDictionary getDictionary()
+ {
+ return firstStream;
+ }
+
+ /**
+ * This will get the stream with all of the filters applied.
+ *
+ * @return the bytes of the physical (endoced) stream
+ *
+ * @throws IOException when encoding/decoding causes an exception
+ */
+ public InputStream getFilteredStream() throws IOException
+ {
+ throw new IOException( "Error: Not allowed to get filtered stream from array of streams." );
+ /**
+ Vector inputStreams = new Vector();
+ byte[] inbetweenStreamBytes = "\n".getBytes();
+
+ for( int i=0;i<streams.size(); i++ )
+ {
+ COSStream stream = (COSStream)streams.getObject( i );
+ }
+
+ return new SequenceInputStream( inputStreams.elements() );
+ **/
+ }
+
+ /**
+ * This will get the logical content stream with none of the filters.
+ *
+ * @return the bytes of the logical (decoded) stream
+ *
+ * @throws IOException when encoding/decoding causes an exception
+ */
+ public InputStream getUnfilteredStream() throws IOException
+ {
+ Vector inputStreams = new Vector();
+ byte[] inbetweenStreamBytes = "\n".getBytes();
+
+ for( int i=0;i<streams.size(); i++ )
+ {
+ COSStream stream = (COSStream)streams.getObject( i );
+ inputStreams.add( stream.getUnfilteredStream() );
+ //handle the case where there is no whitespace in the
+ //between streams in the contents array, without this
+ //it is possible that two operators will get concatenated
+ //together
+ inputStreams.add( new ByteArrayInputStream( inbetweenStreamBytes ) );
+ }
+
+ return new SequenceInputStream( inputStreams.elements() );
+ }
+
+ /**
+ * visitor pattern double dispatch method.
+ *
+ * @param visitor The object to notify when visiting this object.
+ * @return any object, depending on the visitor implementation, or null
+ * @throws COSVisitorException If an error occurs while visiting this object.
+ */
+ public Object accept(ICOSVisitor visitor) throws COSVisitorException
+ {
+ return streams.accept( visitor );
+ }
+
+
+ /**
+ * This will return the filters to apply to the byte stream
+ * the method will return.
+ * - null if no filters are to be applied
+ * - a COSName if one filter is to be applied
+ * - a COSArray containing COSNames if multiple filters are to be applied
+ *
+ * @return the COSBase object representing the filters
+ */
+ public COSBase getFilters()
+ {
+ return firstStream.getFilters();
+ }
+
+ /**
+ * This will create a new stream for which filtered byte should be
+ * written to. You probably don't want this but want to use the
+ * createUnfilteredStream, which is used to write raw bytes to.
+ *
+ * @return A stream that can be written to.
+ *
+ * @throws IOException If there is an error creating the stream.
+ */
+ public OutputStream createFilteredStream() throws IOException
+ {
+ return firstStream.createFilteredStream();
+ }
+
+ /**
+ * This will create a new stream for which filtered byte should be
+ * written to. You probably don't want this but want to use the
+ * createUnfilteredStream, which is used to write raw bytes to.
+ *
+ * @param expectedLength An entry where a length is expected.
+ *
+ * @return A stream that can be written to.
+ *
+ * @throws IOException If there is an error creating the stream.
+ */
+ public OutputStream createFilteredStream( COSBase expectedLength ) throws IOException
+ {
+ return firstStream.createFilteredStream( expectedLength );
+ }
+
+ /**
+ * set the filters to be applied to the stream.
+ *
+ * @param filters The filters to set on this stream.
+ *
+ * @throws IOException If there is an error clearing the old filters.
+ */
+ public void setFilters(COSBase filters) throws IOException
+ {
+ //should this be allowed? Should this
+ //propagate to all streams in the array?
+ firstStream.setFilters( filters );
+ }
+
+ /**
+ * This will create an output stream that can be written to.
+ *
+ * @return An output stream which raw data bytes should be written to.
+ *
+ * @throws IOException If there is an error creating the stream.
+ */
+ public OutputStream createUnfilteredStream() throws IOException
+ {
+ return firstStream.createUnfilteredStream();
+ }
+
+ /**
+ * Appends a new stream to the array that represents this object's stream.
+ *
+ * @param streamToAppend The stream to append.
+ */
+ public void appendStream(COSStream streamToAppend)
+ {
+ streams.add(streamToAppend);
+ }
+
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/common/DualCOSObjectable.java b/src/main/java/org/pdfbox/pdmodel/common/DualCOSObjectable.java
new file mode 100644
index 0000000..9c70d15
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/common/DualCOSObjectable.java
@@ -0,0 +1,56 @@
+/**
+ * Copyright (c) 2003, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.common;
+
+import org.pdfbox.cos.COSBase;
+
+/**
+ * This is an interface to represent a PDModel object that holds two COS objects.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.1 $
+ */
+public interface DualCOSObjectable
+{
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSBase getFirstCOSObject();
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSBase getSecondCOSObject();
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/common/PDMatrix.java b/src/main/java/org/pdfbox/pdmodel/common/PDMatrix.java
new file mode 100644
index 0000000..ffee9e8
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/common/PDMatrix.java
@@ -0,0 +1,120 @@
+/**
+ * Copyright (c) 2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.common;
+
+import org.pdfbox.cos.COSArray;
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSFloat;
+import org.pdfbox.cos.COSNumber;
+
+/**
+ * This class will be used for matrix manipulation.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.2 $
+ */
+public class PDMatrix implements Cloneable, COSObjectable
+{
+ private COSArray matrix;
+
+ /**
+ * Constructor.
+ */
+ public PDMatrix()
+ {
+ matrix = new COSArray();
+ matrix.add( new COSFloat( 1.0f ) );
+ matrix.add( new COSFloat( 0.0f ) );
+ matrix.add( new COSFloat( 0.0f ) );
+ matrix.add( new COSFloat( 0.0f ) );
+ matrix.add( new COSFloat( 1.0f ) );
+ matrix.add( new COSFloat( 0.0f ) );
+ matrix.add( new COSFloat( 0.0f ) );
+ matrix.add( new COSFloat( 0.0f ) );
+ matrix.add( new COSFloat( 1.0f ) );
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param array The array that describes the matrix.
+ */
+ public PDMatrix( COSArray array )
+ {
+ matrix = array;
+ }
+
+ /**
+ * This will get the underlying array value.
+ *
+ * @return The cos object that this object wraps.
+ */
+ public COSArray getCOSArray()
+ {
+ return matrix;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSBase getCOSObject()
+ {
+ return matrix;
+ }
+
+
+ /**
+ * This will get a matrix value at some point.
+ *
+ * @param row The row to get the value from.
+ * @param column The column to get the value from.
+ *
+ * @return The value at the row/column position.
+ */
+ public float getValue( int row, int column )
+ {
+ return ((COSNumber)matrix.get( row*3 + column )).floatValue();
+ }
+
+ /**
+ * This will set a value at a position.
+ *
+ * @param row The row to set the value at.
+ * @param column the column to set the value at.
+ * @param value The value to set at the position.
+ */
+ public void setValue( int row, int column, float value )
+ {
+ matrix.set( row*3+column, new COSFloat( value ) );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/common/PDMemoryStream.java b/src/main/java/org/pdfbox/pdmodel/common/PDMemoryStream.java
new file mode 100644
index 0000000..61cbfbf
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/common/PDMemoryStream.java
@@ -0,0 +1,284 @@
+/**
+ * Copyright (c) 2005, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.common;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import java.util.List;
+
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSStream;
+
+import org.pdfbox.pdmodel.common.filespecification.PDFileSpecification;
+
+/**
+ * A PDStream represents a stream in a PDF document. Streams are tied to a single
+ * PDF document.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.1 $
+ */
+public class PDMemoryStream extends PDStream
+{
+ private byte[] data;
+
+ /**
+ * This will create a new PDStream object.
+ *
+ * @param buffer The data for this in memory stream.
+ */
+ public PDMemoryStream( byte[] buffer )
+ {
+ data = buffer;
+ }
+
+
+
+ /**
+ * If there are not compression filters on the current stream then this
+ * will add a compression filter, flate compression for example.
+ */
+ public void addCompression()
+ {
+ //no compression to add
+ }
+
+
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSBase getCOSObject()
+ {
+ throw new UnsupportedOperationException( "not supported for memory stream" );
+ }
+
+ /**
+ * This will get a stream that can be written to.
+ *
+ * @return An output stream to write data to.
+ *
+ * @throws IOException If an IO error occurs during writing.
+ */
+ public OutputStream createOutputStream() throws IOException
+ {
+ throw new UnsupportedOperationException( "not supported for memory stream" );
+ }
+
+ /**
+ * This will get a stream that can be read from.
+ *
+ * @return An input stream that can be read from.
+ *
+ * @throws IOException If an IO error occurs during reading.
+ */
+ public InputStream createInputStream() throws IOException
+ {
+ return new ByteArrayInputStream( data );
+ }
+
+ /**
+ * This will get a stream with some filters applied but not others. This is useful
+ * when doing images, ie filters = [flate,dct], we want to remove flate but leave dct
+ *
+ * @param stopFilters A list of filters to stop decoding at.
+ * @return A stream with decoded data.
+ * @throws IOException If there is an error processing the stream.
+ */
+ public InputStream getPartiallyFilteredStream( List stopFilters ) throws IOException
+ {
+ return createInputStream();
+ }
+
+ /**
+ * Get the cos stream associated with this object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSStream getStream()
+ {
+ throw new UnsupportedOperationException( "not supported for memory stream" );
+ }
+
+ /**
+ * This will get the length of the filtered/compressed stream. This is readonly in the
+ * PD Model and will be managed by this class.
+ *
+ * @return The length of the filtered stream.
+ */
+ public int getLength()
+ {
+ return data.length;
+ }
+
+ /**
+ * This will get the list of filters that are associated with this stream. Or
+ * null if there are none.
+ * @return A list of all encoding filters to apply to this stream.
+ */
+ public List getFilters()
+ {
+ return null;
+ }
+
+ /**
+ * This will set the filters that are part of this stream.
+ *
+ * @param filters The filters that are part of this stream.
+ */
+ public void setFilters( List filters )
+ {
+ throw new UnsupportedOperationException( "not supported for memory stream" );
+ }
+
+ /**
+ * Get the list of decode parameters. Each entry in the list will refer to
+ * an entry in the filters list.
+ *
+ * @return The list of decode parameters.
+ *
+ * @throws IOException if there is an error retrieving the parameters.
+ */
+ public List getDecodeParams() throws IOException
+ {
+ return null;
+ }
+
+ /**
+ * This will set the list of decode params.
+ *
+ * @param decodeParams The list of decode params.
+ */
+ public void setDecodeParams( List decodeParams )
+ {
+ //do nothing
+ }
+
+ /**
+ * This will get the file specification for this stream. This is only
+ * required for external files.
+ *
+ * @return The file specification.
+ */
+ public PDFileSpecification getFile()
+ {
+ return null;
+ }
+
+ /**
+ * Set the file specification.
+ * @param f The file specification.
+ */
+ public void setFile( PDFileSpecification f )
+ {
+ //do nothing.
+ }
+
+ /**
+ * This will get the list of filters that are associated with this stream. Or
+ * null if there are none.
+ * @return A list of all encoding filters to apply to this stream.
+ */
+ public List getFileFilters()
+ {
+ return null;
+ }
+
+ /**
+ * This will set the filters that are part of this stream.
+ *
+ * @param filters The filters that are part of this stream.
+ */
+ public void setFileFilters( List filters )
+ {
+ //do nothing.
+ }
+
+ /**
+ * Get the list of decode parameters. Each entry in the list will refer to
+ * an entry in the filters list.
+ *
+ * @return The list of decode parameters.
+ *
+ * @throws IOException if there is an error retrieving the parameters.
+ */
+ public List getFileDecodeParams() throws IOException
+ {
+ return null;
+ }
+
+ /**
+ * This will set the list of decode params.
+ *
+ * @param decodeParams The list of decode params.
+ */
+ public void setFileDecodeParams( List decodeParams )
+ {
+ //do nothing
+ }
+
+ /**
+ * This will copy the stream into a byte array.
+ *
+ * @return The byte array of the filteredStream
+ * @throws IOException When getFilteredStream did not work
+ */
+ public byte[] getByteArray() throws IOException
+ {
+ return data;
+ }
+
+ /**
+ * Get the metadata that is part of the document catalog. This will
+ * return null if there is no meta data for this object.
+ *
+ * @return The metadata for this object.
+ */
+ public PDMetadata getMetadata()
+ {
+ return null;
+ }
+
+ /**
+ * Set the metadata for this object. This can be null.
+ *
+ * @param meta The meta data for this object.
+ */
+ public void setMetadata( PDMetadata meta )
+ {
+ //do nothing
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/common/PDMetadata.java b/src/main/java/org/pdfbox/pdmodel/common/PDMetadata.java
new file mode 100644
index 0000000..77be580
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/common/PDMetadata.java
@@ -0,0 +1,87 @@
+/**
+ * Copyright (c) 2005, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.common;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.pdfbox.cos.COSStream;
+
+import org.pdfbox.pdmodel.PDDocument;
+
+/**
+ * This class represents metadata for various objects in a PDF document.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.1 $
+ */
+public class PDMetadata extends PDStream
+{
+
+ /**
+ * This will create a new PDMetadata object.
+ *
+ * @param document The document that the stream will be part of.
+ */
+ public PDMetadata( PDDocument document )
+ {
+ super( document );
+ getStream().setName( "Type", "Metadata" );
+ getStream().setName( "Subtype", "XML" );
+ }
+
+ /**
+ * Constructor. Reads all data from the input stream and embeds it into the
+ * document, this will close the InputStream.
+ *
+ * @param doc The document that will hold the stream.
+ * @param str The stream parameter.
+ * @param filtered True if the stream already has a filter applied.
+ * @throws IOException If there is an error creating the stream in the document.
+ */
+ public PDMetadata( PDDocument doc, InputStream str, boolean filtered ) throws IOException
+ {
+ super( doc, str, filtered );
+ getStream().setName( "Type", "Metadata" );
+ getStream().setName( "Subtype", "XML" );
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param str The stream parameter.
+ */
+ public PDMetadata( COSStream str )
+ {
+ super( str );
+ }
+
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/common/PDNameTreeNode.java b/src/main/java/org/pdfbox/pdmodel/common/PDNameTreeNode.java
new file mode 100644
index 0000000..4a79d10
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/common/PDNameTreeNode.java
@@ -0,0 +1,337 @@
+/**
+ * Copyright (c) 2004-2005, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.common;
+
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.pdfbox.cos.COSArray;
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSString;
+
+/**
+ * This class represends a PDF Name tree. See the PDF Reference 1.5 section 3.8.5
+ * for more details.
+ *
+ * @author Ben Litchfield (ben@benlitchfield.com)
+ * @version $Revision: 1.3 $
+ */
+public class PDNameTreeNode implements COSObjectable
+{
+ private COSDictionary node;
+ private Class valueType = null;
+
+ /**
+ * Constructor.
+ *
+ * @param valueClass The PD Model type of object that is the value.
+ */
+ public PDNameTreeNode( Class valueClass )
+ {
+ node = new COSDictionary();
+ valueType = valueClass;
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param dict The dictionary that holds the name information.
+ * @param valueClass The PD Model type of object that is the value.
+ */
+ public PDNameTreeNode( COSDictionary dict, Class valueClass )
+ {
+ node = dict;
+ valueType = valueClass;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSBase getCOSObject()
+ {
+ return node;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSDictionary getCOSDictionary()
+ {
+ return node;
+ }
+
+ /**
+ * Return the children of this node. This list will contain PDNameTreeNode objects.
+ *
+ * @return The list of children or null if there are no children.
+ */
+ public List getKids()
+ {
+
+ List retval = null;
+ COSArray kids = (COSArray)node.getDictionaryObject( "Kids" );
+ if( kids != null )
+ {
+ List pdObjects = new ArrayList();
+ for( int i=0; i<kids.size(); i++ )
+ {
+ pdObjects.add( createChildNode( (COSDictionary)kids.getObject(i) ) );
+ }
+ retval = new COSArrayList(pdObjects,kids);
+ }
+
+ return retval;
+ }
+
+ /**
+ * Set the children of this named tree.
+ *
+ * @param kids The children of this named tree.
+ */
+ public void setKids( List kids )
+ {
+ node.setItem( "Kids", COSArrayList.converterToCOSArray( kids ) );
+ }
+
+ /**
+ * The name to retrieve.
+ *
+ * @param name The name in the tree.
+ *
+ * @return The value of the name in the tree.
+ *
+ * @throws IOException If an there is a problem creating the destinations.
+ */
+ public Object getValue( String name ) throws IOException
+ {
+ Object retval = null;
+ Map names = getNames();
+ if( names != null )
+ {
+ retval = names.get( name );
+ }
+ else
+ {
+ List kids = getKids();
+ for( int i=0; i<kids.size() && retval == null; i++ )
+ {
+ PDNameTreeNode childNode = (PDNameTreeNode)kids.get( i );
+ if( childNode.getLowerLimit().compareTo( name ) <= 0 &&
+ childNode.getUpperLimit().compareTo( name ) >= 0 )
+ {
+ retval = childNode.getValue( name );
+ }
+ }
+ }
+ return retval;
+ }
+
+
+ /**
+ * This will return a map of names. The key will be a java.lang.String the value will
+ * depend on where this class is being used.
+ *
+ * @return A map of cos objects.
+ *
+ * @throws IOException If there is an error while creating the sub types.
+ */
+ public Map getNames() throws IOException
+ {
+ Map names = null;
+ COSArray namesArray = (COSArray)node.getDictionaryObject( "Names" );
+ if( namesArray != null )
+ {
+ names = new HashMap();
+ for( int i=0; i<namesArray.size(); i+=2 )
+ {
+ COSString key = (COSString)namesArray.getObject(i);
+ COSBase cosValue = namesArray.getObject( i+1 );
+ Object pdValue = convertCOSToPD( cosValue );
+
+ names.put( key.getString(), pdValue );
+ }
+ names = Collections.unmodifiableMap(names);
+ }
+
+ return names;
+ }
+
+ /**
+ * Method to convert the COS value in the name tree to the PD Model object. The
+ * default implementation will simply use reflection to create the correct object
+ * type. Subclasses can do whatever they want.
+ *
+ * @param base The COS object to convert.
+ * @return The converted PD Model object.
+ * @throws IOException If there is an error during creation.
+ */
+ protected Object convertCOSToPD( COSBase base ) throws IOException
+ {
+ Object retval = null;
+ try
+ {
+ Constructor ctor = valueType.getConstructor( new Class[] { base.getClass() } );
+ retval = ctor.newInstance( new Object[] { base } );
+ }
+ catch( Throwable t )
+ {
+ throw new IOException( "Error while trying to create value in named tree:" + t.getMessage());
+
+ }
+ return retval;
+ }
+
+ /**
+ * Create a child node object.
+ *
+ * @param dic The dictionary for the child node object to refer to.
+ * @return The new child node object.
+ */
+ protected PDNameTreeNode createChildNode( COSDictionary dic )
+ {
+ return new PDNameTreeNode(dic,valueType);
+ }
+
+ /**
+ * Set the names of for this node. The keys should be java.lang.String and the
+ * values must be a COSObjectable. This method will set the appropriate upper and lower
+ * limits based on the keys in the map.
+ *
+ * @param names The map of names to objects.
+ */
+ public void setNames( Map names )
+ {
+ if( names == null )
+ {
+ node.setItem( "Names", (COSObjectable)null );
+ node.setItem( "Limits", (COSObjectable)null);
+ }
+ else
+ {
+ List keys = new ArrayList( names.keySet() );
+ Collections.sort( keys );
+ COSArray array = new COSArray();
+ for( int i=0; i<keys.size(); i++ )
+ {
+ String key = (String)keys.get(i);
+ array.add( new COSString( key ) );
+ COSObjectable obj = (COSObjectable)names.get( key );
+ array.add( obj );
+ }
+ String lower = null;
+ String upper = null;
+ if( keys.size() > 0 )
+ {
+ lower = (String)keys.get( 0 );
+ upper = (String)keys.get( keys.size()-1 );
+ }
+ setUpperLimit( upper );
+ setLowerLimit( lower );
+ node.setItem( "Names", array );
+ }
+ }
+
+ /**
+ * Get the highest value for a key in the name map.
+ *
+ * @return The highest value for a key in the map.
+ */
+ public String getUpperLimit()
+ {
+ String retval = null;
+ COSArray arr = (COSArray)node.getDictionaryObject( "Limits" );
+ if( arr != null )
+ {
+ retval = arr.getString( 1 );
+ }
+ return retval;
+ }
+
+ /**
+ * Set the highest value for the key in the map.
+ *
+ * @param upper The new highest value for a key in the map.
+ */
+ private void setUpperLimit( String upper )
+ {
+ COSArray arr = (COSArray)node.getDictionaryObject( "Limits" );
+ if( arr == null )
+ {
+ arr = new COSArray();
+ arr.add( null );
+ arr.add( null );
+ }
+ arr.setString( 1, upper );
+ }
+
+ /**
+ * Get the lowest value for a key in the name map.
+ *
+ * @return The lowest value for a key in the map.
+ */
+ public String getLowerLimit()
+ {
+ String retval = null;
+ COSArray arr = (COSArray)node.getDictionaryObject( "Limits" );
+ if( arr != null )
+ {
+ retval = arr.getString( 0 );
+ }
+ return retval;
+ }
+
+ /**
+ * Set the lowest value for the key in the map.
+ *
+ * @param lower The new lowest value for a key in the map.
+ */
+ private void setLowerLimit( String lower )
+ {
+ COSArray arr = (COSArray)node.getDictionaryObject( "Limits" );
+ if( arr == null )
+ {
+ arr = new COSArray();
+ arr.add( null );
+ arr.add( null );
+ }
+ arr.setString( 0, lower );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/common/PDNamedTextStream.java b/src/main/java/org/pdfbox/pdmodel/common/PDNamedTextStream.java
new file mode 100644
index 0000000..2321683
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/common/PDNamedTextStream.java
@@ -0,0 +1,137 @@
+/**
+ * Copyright (c) 2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.common;
+
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSName;
+
+/**
+ * A named text stream is a combination of a name and a PDTextStream object. This
+ * is used in name trees.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.2 $
+ */
+public class PDNamedTextStream implements DualCOSObjectable
+{
+ private COSName streamName;
+ private PDTextStream stream;
+
+ /**
+ * Constructor.
+ */
+ public PDNamedTextStream()
+ {
+ //default constructor
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param name The name of the stream.
+ * @param str The stream.
+ */
+ public PDNamedTextStream( COSName name, COSBase str )
+ {
+ streamName = name;
+ stream = PDTextStream.createTextStream( str );
+ }
+
+ /**
+ * The name of the named text stream.
+ *
+ * @return The stream name.
+ */
+ public String getName()
+ {
+ String name = null;
+ if( streamName != null )
+ {
+ name = streamName.getName();
+ }
+ return name;
+ }
+
+ /**
+ * This will set the name of the named text stream.
+ *
+ * @param name The name of the named text stream.
+ */
+ public void setName( String name )
+ {
+ streamName = COSName.getPDFName( name );
+ }
+
+ /**
+ * This will get the stream.
+ *
+ * @return The stream associated with this name.
+ */
+ public PDTextStream getStream()
+ {
+ return stream;
+ }
+
+ /**
+ * This will set the stream.
+ *
+ * @param str The stream associated with this name.
+ */
+ public void setStream( PDTextStream str )
+ {
+ stream = str;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSBase getFirstCOSObject()
+ {
+ return streamName;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSBase getSecondCOSObject()
+ {
+ COSBase retval = null;
+ if( stream != null )
+ {
+ retval = stream.getCOSObject();
+ }
+ return retval;
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/common/PDObjectStream.java b/src/main/java/org/pdfbox/pdmodel/common/PDObjectStream.java
new file mode 100644
index 0000000..3d31c1a
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/common/PDObjectStream.java
@@ -0,0 +1,151 @@
+/**
+ * Copyright (c) 2004-2005, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.common;
+
+import org.pdfbox.cos.COSStream;
+
+import org.pdfbox.pdmodel.PDDocument;
+
+
+
+/**
+ * A PDStream represents a stream in a PDF document. Streams are tied to a single
+ * PDF document.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.2 $
+ */
+public class PDObjectStream extends PDStream
+{
+
+ /**
+ * Constructor.
+ *
+ * @param str The stream parameter.
+ */
+ public PDObjectStream( COSStream str )
+ {
+ super( str );
+ }
+
+ /**
+ * This will create a new PDStream object.
+ *
+ * @param document The document that the stream will be part of.
+ * @return A new stream object.
+ */
+ public static PDObjectStream createStream( PDDocument document )
+ {
+ COSStream cosStream = new COSStream( document.getDocument().getScratchFile() );
+ PDObjectStream strm = new PDObjectStream( cosStream );
+ strm.getStream().setName( "Type", "ObjStm" );
+ return strm;
+ }
+
+ /**
+ * Get the type of this object, should always return "ObjStm".
+ *
+ * @return The type of this object.
+ */
+ public String getType()
+ {
+ return getStream().getNameAsString( "Type" );
+ }
+
+ /**
+ * Get the number of compressed object.
+ *
+ * @return The number of compressed objects.
+ */
+ public int getNumberOfObjects()
+ {
+ return getStream().getInt( "N", 0 );
+ }
+
+ /**
+ * Set the number of objects.
+ *
+ * @param n The new number of objects.
+ */
+ public void setNumberOfObjects( int n )
+ {
+ getStream().setInt( "N", n );
+ }
+
+ /**
+ * The byte offset (in the decoded stream) of the first compressed object.
+ *
+ * @return The byte offset to the first object.
+ */
+ public int getFirstByteOffset()
+ {
+ return getStream().getInt( "First", 0 );
+ }
+
+ /**
+ * The byte offset (in the decoded stream) of the first compressed object.
+ *
+ * @param n The byte offset to the first object.
+ */
+ public void setFirstByteOffset( int n )
+ {
+ getStream().setInt( "First", n );
+ }
+
+ /**
+ * A reference to an object stream, of which the current object stream is
+ * considered an extension.
+ *
+ * @return The object that this stream is an extension.
+ */
+ public PDObjectStream getExtends()
+ {
+ PDObjectStream retval = null;
+ COSStream stream = (COSStream)getStream().getDictionaryObject( "Extends" );
+ if( stream != null )
+ {
+ retval = new PDObjectStream( stream );
+ }
+ return retval;
+
+ }
+
+ /**
+ * A reference to an object stream, of which the current object stream is
+ * considered an extension.
+ *
+ * @param stream The object stream extension.
+ */
+ public void setExtends( PDObjectStream stream )
+ {
+ getStream().setItem( "Extends", stream );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/common/PDRange.java b/src/main/java/org/pdfbox/pdmodel/common/PDRange.java
new file mode 100644
index 0000000..2493d87
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/common/PDRange.java
@@ -0,0 +1,146 @@
+/**
+ * Copyright (c) 2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.common;
+
+import org.pdfbox.cos.COSArray;
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSFloat;
+import org.pdfbox.cos.COSNumber;
+
+/**
+ * This class will be used to signify a range. a(min) <= a* <= a(max)
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.2 $
+ */
+public class PDRange implements COSObjectable
+{
+ private COSArray rangeArray;
+ private int startingIndex;
+
+ /**
+ * Constructor with an initial range of 0..1.
+ */
+ public PDRange()
+ {
+ rangeArray = new COSArray();
+ rangeArray.add( new COSFloat( 0.0f ) );
+ rangeArray.add( new COSFloat( 1.0f ) );
+ startingIndex = 0;
+ }
+
+ /**
+ * Constructor assumes a starting index of 0.
+ *
+ * @param range The array that describes the range.
+ */
+ public PDRange( COSArray range )
+ {
+ rangeArray = range;
+ }
+
+ /**
+ * Constructor with an index into an array. Because some arrays specify
+ * multiple ranges ie [ 0,1, 0,2, 2,3 ] It is convenient for this
+ * class to take an index into an array. So if you want this range to
+ * represent 0,2 in the above example then you would say <code>new PDRange( array, 2 )</code>.
+ *
+ * @param range The array that describes the index
+ * @param index The index into the array for the start of the range.
+ */
+ public PDRange( COSArray range, int index )
+ {
+ rangeArray = range;
+ startingIndex = index;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSBase getCOSObject()
+ {
+ return rangeArray;
+ }
+
+ /**
+ * This will get the underlying array value.
+ *
+ * @return The cos object that this object wraps.
+ */
+ public COSArray getCOSArray()
+ {
+ return rangeArray;
+ }
+
+ /**
+ * This will get the minimum value of the range.
+ *
+ * @return The min value.
+ */
+ public float getMin()
+ {
+ COSNumber min = (COSNumber)rangeArray.getObject( startingIndex );
+ return min.floatValue();
+ }
+
+ /**
+ * This will set the minimum value for the range.
+ *
+ * @param min The new minimum for the range.
+ */
+ public void setMin( float min )
+ {
+ rangeArray.set( startingIndex, new COSFloat( min ) );
+ }
+
+ /**
+ * This will get the maximum value of the range.
+ *
+ * @return The max value.
+ */
+ public float getMax()
+ {
+ COSNumber max = (COSNumber)rangeArray.getObject( startingIndex+1 );
+ return max.floatValue();
+ }
+
+ /**
+ * This will set the maximum value for the range.
+ *
+ * @param max The new maximum for the range.
+ */
+ public void setMax( float max )
+ {
+ rangeArray.set( startingIndex+1, new COSFloat( max ) );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/common/PDRectangle.java b/src/main/java/org/pdfbox/pdmodel/common/PDRectangle.java
new file mode 100644
index 0000000..b9f3267
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/common/PDRectangle.java
@@ -0,0 +1,295 @@
+/**
+ * Copyright (c) 2003-2005, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.common;
+
+import org.pdfbox.cos.COSArray;
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSFloat;
+import org.pdfbox.cos.COSNumber;
+
+import org.pdfbox.util.BoundingBox;
+
+import java.awt.Dimension;
+
+/**
+ * This represents a rectangle in a PDF document.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.10 $
+ */
+public class PDRectangle implements COSObjectable
+{
+ private COSArray rectArray;
+
+ /**
+ * Constructor.
+ *
+ * Initializes to 0,0,0,0
+ */
+ public PDRectangle()
+ {
+ rectArray = new COSArray();
+ rectArray.add( new COSFloat( 0.0f ) );
+ rectArray.add( new COSFloat( 0.0f ) );
+ rectArray.add( new COSFloat( 0.0f ) );
+ rectArray.add( new COSFloat( 0.0f ) );
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param width The width of the rectangle.
+ * @param height The height of the rectangle.
+ */
+ public PDRectangle( float width, float height )
+ {
+ rectArray = new COSArray();
+ rectArray.add( new COSFloat( 0.0f ) );
+ rectArray.add( new COSFloat( 0.0f ) );
+ rectArray.add( new COSFloat( width ) );
+ rectArray.add( new COSFloat( height ) );
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param box The non PD bouding box.
+ */
+ public PDRectangle( BoundingBox box )
+ {
+ rectArray = new COSArray();
+ rectArray.add( new COSFloat( box.getLowerLeftX() ) );
+ rectArray.add( new COSFloat( box.getLowerLeftY() ) );
+ rectArray.add( new COSFloat( box.getUpperRightX() ) );
+ rectArray.add( new COSFloat( box.getUpperRightY() ) );
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param array An array of numbers as specified in the PDF Reference for a rectangle type.
+ */
+ public PDRectangle( COSArray array )
+ {
+ rectArray = array;
+ }
+
+ /**
+ * Method to determine if the x/y point is inside this rectangle.
+ * @param x The x-coordinate to test.
+ * @param y The y-coordinate to test.
+ * @return True if the point is inside this rectangle.
+ */
+ public boolean contains( float x, float y )
+ {
+ float llx = getLowerLeftX();
+ float urx = getUpperRightX();
+ float lly = getLowerLeftY();
+ float ury = getUpperRightY();
+ return x >= llx && x <= urx &&
+ y >= lly && y <= ury;
+ }
+
+ /**
+ * This will create a translated rectangle based off of this rectangle, such
+ * that the new rectangle retains the same dimensions(height/width), but the
+ * lower left x,y values are zero. <br />
+ * 100, 100, 400, 400 (llx, lly, urx, ury ) <br />
+ * will be translated to 0,0,300,300
+ *
+ * @return A new rectangle that has been translated back to the origin.
+ */
+ public PDRectangle createRetranslatedRectangle()
+ {
+ PDRectangle retval = new PDRectangle();
+ retval.setUpperRightX( getWidth() );
+ retval.setUpperRightY( getHeight() );
+ return retval;
+ }
+
+ /**
+ * This will get the underlying array for this rectangle.
+ *
+ * @return The cos array.
+ */
+ public COSArray getCOSArray()
+ {
+ return rectArray;
+ }
+
+ /**
+ * This will get the lower left x coordinate.
+ *
+ * @return The lower left x.
+ */
+ public float getLowerLeftX()
+ {
+ return ((COSNumber)rectArray.get(0)).floatValue();
+ }
+
+ /**
+ * This will set the lower left x coordinate.
+ *
+ * @param value The lower left x.
+ */
+ public void setLowerLeftX(float value)
+ {
+ rectArray.set(0, new COSFloat( value ) );
+ }
+
+ /**
+ * This will get the lower left y coordinate.
+ *
+ * @return The lower left y.
+ */
+ public float getLowerLeftY()
+ {
+ return ((COSNumber)rectArray.get(1)).floatValue();
+ }
+
+ /**
+ * This will set the lower left y coordinate.
+ *
+ * @param value The lower left y.
+ */
+ public void setLowerLeftY(float value)
+ {
+ rectArray.set(1, new COSFloat( value ) );
+ }
+
+ /**
+ * This will get the upper right x coordinate.
+ *
+ * @return The upper right x .
+ */
+ public float getUpperRightX()
+ {
+ return ((COSNumber)rectArray.get(2)).floatValue();
+ }
+
+ /**
+ * This will set the upper right x coordinate.
+ *
+ * @param value The upper right x .
+ */
+ public void setUpperRightX(float value)
+ {
+ rectArray.set(2, new COSFloat( value ) );
+ }
+
+ /**
+ * This will get the upper right y coordinate.
+ *
+ * @return The upper right y.
+ */
+ public float getUpperRightY()
+ {
+ return ((COSNumber)rectArray.get(3)).floatValue();
+ }
+
+ /**
+ * This will set the upper right y coordinate.
+ *
+ * @param value The upper right y.
+ */
+ public void setUpperRightY(float value)
+ {
+ rectArray.set(3, new COSFloat( value ) );
+ }
+
+ /**
+ * This will get the width of this rectangle as calculated by
+ * upperRightX - lowerLeftX.
+ *
+ * @return The width of this rectangle.
+ */
+ public float getWidth()
+ {
+ return getUpperRightX() - getLowerLeftX();
+ }
+
+ /**
+ * This will get the height of this rectangle as calculated by
+ * upperRightY - lowerLeftY.
+ *
+ * @return The height of this rectangle.
+ */
+ public float getHeight()
+ {
+ return getUpperRightY() - getLowerLeftY();
+ }
+
+ /**
+ * A convenience method to create a dimension object for AWT operations.
+ *
+ * @return A dimension that matches the width and height of this rectangle.
+ */
+ public Dimension createDimension()
+ {
+ return new Dimension( (int)getWidth(), (int)getHeight() );
+ }
+
+ /**
+ * This will move the rectangle the given relative amount.
+ *
+ * @param horizontalAmount positive values will move rectangle to the right, negative's to the left.
+ * @param verticalAmount positive values will move the rectangle up, negative's down.
+ */
+ public void move(float horizontalAmount, float verticalAmount)
+ {
+ setUpperRightX(getUpperRightX() + horizontalAmount);
+ setLowerLeftX(getLowerLeftX() + horizontalAmount);
+ setUpperRightY(getUpperRightY() + verticalAmount);
+ setLowerLeftY(getLowerLeftY() + verticalAmount);
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSBase getCOSObject()
+ {
+ return rectArray;
+ }
+
+
+ /**
+ * This will return a string representation of this rectangle.
+ *
+ * @return This object as a string.
+ */
+ public String toString()
+ {
+ return "[" + getLowerLeftX() + "," + getLowerLeftY() + "," +
+ getUpperRightX() + "," + getUpperRightY() +"]";
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/common/PDStream.java b/src/main/java/org/pdfbox/pdmodel/common/PDStream.java
new file mode 100644
index 0000000..74398b2
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/common/PDStream.java
@@ -0,0 +1,538 @@
+/**
+ * Copyright (c) 2004-2005, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.common;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.pdfbox.cos.COSArray;
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSName;
+import org.pdfbox.cos.COSStream;
+
+import org.pdfbox.filter.Filter;
+import org.pdfbox.filter.FilterManager;
+
+import org.pdfbox.pdmodel.PDDocument;
+
+import org.pdfbox.pdmodel.common.filespecification.PDFileSpecification;
+
+/**
+ * A PDStream represents a stream in a PDF document. Streams are tied to a single
+ * PDF document.
+ *
+ * @author Ben Litchfield (ben@benlitchfield.com)
+ * @version $Revision: 1.14 $
+ */
+public class PDStream implements COSObjectable
+{
+ private COSStream stream;
+
+ /**
+ * This will create a new PDStream object.
+ */
+ protected PDStream()
+ {
+ //should only be called by PDMemoryStream
+ }
+
+ /**
+ * This will create a new PDStream object.
+ *
+ * @param document The document that the stream will be part of.
+ */
+ public PDStream( PDDocument document )
+ {
+ stream = new COSStream( document.getDocument().getScratchFile() );
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param str The stream parameter.
+ */
+ public PDStream( COSStream str )
+ {
+ stream = str;
+ }
+
+ /**
+ * Constructor. Reads all data from the input stream and embeds it into the
+ * document, this will close the InputStream.
+ *
+ * @param doc The document that will hold the stream.
+ * @param str The stream parameter.
+ * @throws IOException If there is an error creating the stream in the document.
+ */
+ public PDStream( PDDocument doc, InputStream str ) throws IOException
+ {
+ this( doc, str, false );
+ }
+
+ /**
+ * Constructor. Reads all data from the input stream and embeds it into the
+ * document, this will close the InputStream.
+ *
+ * @param doc The document that will hold the stream.
+ * @param str The stream parameter.
+ * @param filtered True if the stream already has a filter applied.
+ * @throws IOException If there is an error creating the stream in the document.
+ */
+ public PDStream( PDDocument doc, InputStream str, boolean filtered ) throws IOException
+ {
+ OutputStream output = null;
+ try
+ {
+ stream = new COSStream( doc.getDocument().getScratchFile() );
+ if( filtered )
+ {
+ output = stream.createFilteredStream();
+ }
+ else
+ {
+ output = stream.createUnfilteredStream();
+ }
+ byte[] buffer = new byte[ 1024 ];
+ int amountRead = -1;
+ while( (amountRead = str.read(buffer)) != -1 )
+ {
+ output.write( buffer, 0, amountRead );
+ }
+ }
+ finally
+ {
+ if( output != null )
+ {
+ output.close();
+ }
+ if( str != null )
+ {
+ str.close();
+ }
+ }
+ }
+
+ /**
+ * If there are not compression filters on the current stream then this
+ * will add a compression filter, flate compression for example.
+ */
+ public void addCompression()
+ {
+ List filters = getFilters();
+ if( filters == null )
+ {
+ filters = new ArrayList();
+ filters.add( COSName.FLATE_DECODE );
+ setFilters( filters );
+ }
+ }
+
+ /**
+ * Create a pd stream from either a regular COSStream on a COSArray of cos streams.
+ * @param base Either a COSStream or COSArray.
+ * @return A PDStream or null if base is null.
+ * @throws IOException If there is an error creating the PDStream.
+ */
+ public static PDStream createFromCOS( COSBase base ) throws IOException
+ {
+ PDStream retval = null;
+ if( base instanceof COSStream )
+ {
+ retval = new PDStream( (COSStream)base );
+ }
+ else if( base instanceof COSArray )
+ {
+ retval = new PDStream( new COSStreamArray( (COSArray)base ) );
+ }
+ else
+ {
+ if( base != null )
+ {
+ throw new IOException( "Contents are unknown type:" + base.getClass().getName() );
+ }
+ }
+ return retval;
+ }
+
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSBase getCOSObject()
+ {
+ return stream;
+ }
+
+ /**
+ * This will get a stream that can be written to.
+ *
+ * @return An output stream to write data to.
+ *
+ * @throws IOException If an IO error occurs during writing.
+ */
+ public OutputStream createOutputStream() throws IOException
+ {
+ return stream.createUnfilteredStream();
+ }
+
+ /**
+ * This will get a stream that can be read from.
+ *
+ * @return An input stream that can be read from.
+ *
+ * @throws IOException If an IO error occurs during reading.
+ */
+ public InputStream createInputStream() throws IOException
+ {
+ return stream.getUnfilteredStream();
+ }
+
+ /**
+ * This will get a stream with some filters applied but not others. This is useful
+ * when doing images, ie filters = [flate,dct], we want to remove flate but leave dct
+ *
+ * @param stopFilters A list of filters to stop decoding at.
+ * @return A stream with decoded data.
+ * @throws IOException If there is an error processing the stream.
+ */
+ public InputStream getPartiallyFilteredStream( List stopFilters ) throws IOException
+ {
+ FilterManager manager = stream.getFilterManager();
+ InputStream is = stream.getFilteredStream();
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+ List filters = getFilters();
+ Iterator iter = filters.iterator();
+ String nextFilter = null;
+ boolean done = false;
+ while( iter.hasNext() && !done )
+ {
+ os.reset();
+ nextFilter = (String)iter.next();
+ if( stopFilters.contains( nextFilter ) )
+ {
+ done = true;
+ }
+ else
+ {
+ Filter filter = manager.getFilter( COSName.getPDFName(nextFilter) );
+ filter.decode( is, os, stream );
+ is = new ByteArrayInputStream( os.toByteArray() );
+ }
+ }
+ return is;
+ }
+
+ /**
+ * Get the cos stream associated with this object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSStream getStream()
+ {
+ return stream;
+ }
+
+ /**
+ * This will get the length of the filtered/compressed stream. This is readonly in the
+ * PD Model and will be managed by this class.
+ *
+ * @return The length of the filtered stream.
+ */
+ public int getLength()
+ {
+ return stream.getInt( "Length", 0 );
+ }
+
+ /**
+ * This will get the list of filters that are associated with this stream. Or
+ * null if there are none.
+ * @return A list of all encoding filters to apply to this stream.
+ */
+ public List getFilters()
+ {
+ List retval = null;
+ COSBase filters = stream.getFilters();
+ if( filters instanceof COSName )
+ {
+ COSName name = (COSName)filters;
+ retval = new COSArrayList( name.getName(), name, stream, "Filter" );
+ }
+ else if( filters instanceof COSArray )
+ {
+ retval = COSArrayList.convertCOSNameCOSArrayToList( (COSArray)filters );
+ }
+ return retval;
+ }
+
+ /**
+ * This will set the filters that are part of this stream.
+ *
+ * @param filters The filters that are part of this stream.
+ */
+ public void setFilters( List filters )
+ {
+ COSBase obj = COSArrayList.convertStringListToCOSNameCOSArray( filters );
+ stream.setItem( "Filter", obj );
+ }
+
+ /**
+ * Get the list of decode parameters. Each entry in the list will refer to
+ * an entry in the filters list.
+ *
+ * @return The list of decode parameters.
+ *
+ * @throws IOException if there is an error retrieving the parameters.
+ */
+ public List getDecodeParams() throws IOException
+ {
+ List retval = null;
+
+ COSBase dp = stream.getDictionaryObject( "DecodeParms" );
+ if( dp == null )
+ {
+ //See PDF Ref 1.5 implementation note 7, the DP is sometimes used instead.
+ dp = stream.getDictionaryObject( "DP" );
+ }
+ if( dp instanceof COSDictionary )
+ {
+ Map map = COSDictionaryMap.convertBasicTypesToMap( (COSDictionary)dp );
+ retval = new COSArrayList(map, dp, stream, "DecodeParams" );
+ }
+ else if( dp instanceof COSArray )
+ {
+ COSArray array = (COSArray)dp;
+ List actuals = new ArrayList();
+ for( int i=0; i<array.size(); i++ )
+ {
+ actuals.add(
+ COSDictionaryMap.convertBasicTypesToMap(
+ (COSDictionary)array.getObject( i ) ) );
+ }
+ retval = new COSArrayList(actuals, array);
+ }
+
+ return retval;
+ }
+
+ /**
+ * This will set the list of decode params.
+ *
+ * @param decodeParams The list of decode params.
+ */
+ public void setDecodeParams( List decodeParams )
+ {
+ stream.setItem(
+ "DecodeParams", COSArrayList.converterToCOSArray( decodeParams ) );
+ }
+
+ /**
+ * This will get the file specification for this stream. This is only
+ * required for external files.
+ *
+ * @return The file specification.
+ */
+ public PDFileSpecification getFile()
+ {
+ COSBase f = stream.getDictionaryObject( "F" );
+ PDFileSpecification retval = PDFileSpecification.createFS( f );
+ return retval;
+ }
+
+ /**
+ * Set the file specification.
+ * @param f The file specification.
+ */
+ public void setFile( PDFileSpecification f )
+ {
+ stream.setItem( "F", f );
+ }
+
+ /**
+ * This will get the list of filters that are associated with this stream. Or
+ * null if there are none.
+ * @return A list of all encoding filters to apply to this stream.
+ */
+ public List getFileFilters()
+ {
+ List retval = null;
+ COSBase filters = stream.getDictionaryObject( "FFilter" );
+ if( filters instanceof COSName )
+ {
+ COSName name = (COSName)filters;
+ retval = new COSArrayList( name.getName(), name, stream, "FFilter" );
+ }
+ else if( filters instanceof COSArray )
+ {
+ retval = COSArrayList.convertCOSNameCOSArrayToList( (COSArray)filters );
+ }
+ return retval;
+ }
+
+ /**
+ * This will set the filters that are part of this stream.
+ *
+ * @param filters The filters that are part of this stream.
+ */
+ public void setFileFilters( List filters )
+ {
+ COSBase obj = COSArrayList.convertStringListToCOSNameCOSArray( filters );
+ stream.setItem( "FFilter", obj );
+ }
+
+ /**
+ * Get the list of decode parameters. Each entry in the list will refer to
+ * an entry in the filters list.
+ *
+ * @return The list of decode parameters.
+ *
+ * @throws IOException if there is an error retrieving the parameters.
+ */
+ public List getFileDecodeParams() throws IOException
+ {
+ List retval = null;
+
+ COSBase dp = stream.getDictionaryObject( "FDecodeParms" );
+ if( dp instanceof COSDictionary )
+ {
+ Map map = COSDictionaryMap.convertBasicTypesToMap( (COSDictionary)dp );
+ retval = new COSArrayList(map, dp, stream, "FDecodeParams" );
+ }
+ else if( dp instanceof COSArray )
+ {
+ COSArray array = (COSArray)dp;
+ List actuals = new ArrayList();
+ for( int i=0; i<array.size(); i++ )
+ {
+ actuals.add(
+ COSDictionaryMap.convertBasicTypesToMap(
+ (COSDictionary)array.getObject( i ) ) );
+ }
+ retval = new COSArrayList(actuals, array);
+ }
+
+ return retval;
+ }
+
+ /**
+ * This will set the list of decode params.
+ *
+ * @param decodeParams The list of decode params.
+ */
+ public void setFileDecodeParams( List decodeParams )
+ {
+ stream.setItem(
+ "FDecodeParams", COSArrayList.converterToCOSArray( decodeParams ) );
+ }
+
+ /**
+ * This will copy the stream into a byte array.
+ *
+ * @return The byte array of the filteredStream
+ * @throws IOException When getFilteredStream did not work
+ */
+ public byte[] getByteArray() throws IOException
+ {
+ ByteArrayOutputStream output = new ByteArrayOutputStream();
+ byte[] buf = new byte[1024];
+ InputStream is = null;
+ try
+ {
+ is = createInputStream();
+ int amountRead = -1;
+ while( (amountRead = is.read( buf )) != -1)
+ {
+ output.write( buf, 0, amountRead );
+ }
+ }
+ finally
+ {
+ if( is != null )
+ {
+ is.close();
+ }
+ }
+ return output.toByteArray();
+ }
+
+ /**
+ * A convenience method to get this stream as a string. Uses
+ * the default system encoding.
+ *
+ * @return a String representation of this (input) stream, with the
+ * platform default encoding.
+ *
+ * @throws IOException if there is an error while converting the stream
+ * to a string.
+ */
+ public String getInputStreamAsString() throws IOException
+ {
+ byte[] bStream = getByteArray();
+ return new String(bStream);
+ }
+
+ /**
+ * Get the metadata that is part of the document catalog. This will
+ * return null if there is no meta data for this object.
+ *
+ * @return The metadata for this object.
+ */
+ public PDMetadata getMetadata()
+ {
+ PDMetadata retval = null;
+ COSStream mdStream = (COSStream)stream.getDictionaryObject( "Metadata" );
+ if( mdStream != null )
+ {
+ retval = new PDMetadata( mdStream );
+ }
+ return retval;
+ }
+
+ /**
+ * Set the metadata for this object. This can be null.
+ *
+ * @param meta The meta data for this object.
+ */
+ public void setMetadata( PDMetadata meta )
+ {
+ stream.setItem( "Metadata", meta );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/common/PDTextStream.java b/src/main/java/org/pdfbox/pdmodel/common/PDTextStream.java
new file mode 100644
index 0000000..c7c5ca1
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/common/PDTextStream.java
@@ -0,0 +1,180 @@
+/**
+ * Copyright (c) 2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.common;
+
+import java.io.ByteArrayOutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.io.IOException;
+
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSStream;
+import org.pdfbox.cos.COSString;
+
+/**
+ * A PDTextStream class is used when the PDF specification supports either
+ * a string or a stream for the value of an object. This is usually when
+ * a value could be large or small, for example a JavaScript method. This
+ * class will help abstract that and give a single unified interface to
+ * those types of fields.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.2 $
+ */
+public class PDTextStream implements COSObjectable
+{
+ private COSString string;
+ private COSStream stream;
+
+ /**
+ * Constructor.
+ *
+ * @param str The string parameter.
+ */
+ public PDTextStream( COSString str )
+ {
+ string = str;
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param str The string parameter.
+ */
+ public PDTextStream( String str )
+ {
+ string = new COSString( str );
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param str The stream parameter.
+ */
+ public PDTextStream( COSStream str )
+ {
+ stream = str;
+ }
+
+ /**
+ * This will create the text stream object. base must either be a string
+ * or a stream.
+ *
+ * @param base The COS text stream object.
+ *
+ * @return A PDTextStream that wraps the base object.
+ */
+ public static PDTextStream createTextStream( COSBase base )
+ {
+ PDTextStream retval = null;
+ if( base instanceof COSString )
+ {
+ retval = new PDTextStream( (COSString) base );
+ }
+ else if( base instanceof COSStream )
+ {
+ retval = new PDTextStream( (COSStream)base );
+ }
+ return retval;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSBase getCOSObject()
+ {
+ COSBase retval = null;
+ if( string == null )
+ {
+ retval = stream;
+ }
+ else
+ {
+ retval = string;
+ }
+ return retval;
+ }
+
+ /**
+ * This will get this value as a string. If this is a stream then it
+ * will load the entire stream into memory, so you should only do this when
+ * the stream is a manageable size.
+ *
+ * @return This value as a string.
+ *
+ * @throws IOException If an IO error occurs while accessing the stream.
+ */
+ public String getAsString() throws IOException
+ {
+ String retval = null;
+ if( string != null )
+ {
+ retval = string.getString();
+ }
+ else
+ {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ byte[] buffer = new byte[ 1024 ];
+ int amountRead = -1;
+ InputStream is = stream.getUnfilteredStream();
+ while( (amountRead = is.read( buffer ) ) != -1 )
+ {
+ out.write( buffer, 0, amountRead );
+ }
+ retval = new String( out.toByteArray() );
+ }
+ return retval;
+ }
+
+ /**
+ * This is the preferred way of getting data with this class as it uses
+ * a stream object.
+ *
+ * @return The stream object.
+ *
+ * @throws IOException If an IO error occurs while accessing the stream.
+ */
+ public InputStream getAsStream() throws IOException
+ {
+ InputStream retval = null;
+ if( string != null )
+ {
+ retval = new ByteArrayInputStream( string.getBytes() );
+ }
+ else
+ {
+ retval = stream.getUnfilteredStream();
+ }
+ return retval;
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/common/filespecification/PDComplexFileSpecification.java b/src/main/java/org/pdfbox/pdmodel/common/filespecification/PDComplexFileSpecification.java
new file mode 100644
index 0000000..12618f1
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/common/filespecification/PDComplexFileSpecification.java
@@ -0,0 +1,326 @@
+/**
+ * Copyright (c) 2004-2005, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.common.filespecification;
+
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSStream;
+
+/**
+ * This represents a file specification.
+ *
+ * @author Ben Litchfield (ben@benlitchfield.com)
+ * @version $Revision: 1.3 $
+ */
+public class PDComplexFileSpecification extends PDFileSpecification
+{
+ private COSDictionary fs;
+
+ /**
+ * Default Constructor.
+ */
+ public PDComplexFileSpecification()
+ {
+ fs = new COSDictionary();
+ fs.setName( "Type", "Filespec" );
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param dict The dictionary that fulfils this file specification.
+ */
+ public PDComplexFileSpecification( COSDictionary dict )
+ {
+ fs = dict;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSBase getCOSObject()
+ {
+ return fs;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSDictionary getCOSDictionary()
+ {
+ return fs;
+ }
+
+ /**
+ * This will get the file name.
+ *
+ * @return The file name.
+ */
+ public String getFile()
+ {
+ return fs.getString( "F" );
+ }
+
+ /**
+ * This will set the file name.
+ *
+ * @param file The name of the file.
+ */
+ public void setFile( String file )
+ {
+ fs.setString( "F", file );
+ }
+
+ /**
+ * This will get the name representing a Dos file.
+ *
+ * @return The file name.
+ */
+ public String getFileDos()
+ {
+ return fs.getString( "DOS" );
+ }
+
+ /**
+ * This will set name representing a dos file.
+ *
+ * @param file The name of the file.
+ */
+ public void setFileDos( String file )
+ {
+ fs.setString( "DOS", file );
+ }
+
+ /**
+ * This will get the name representing a Mac file.
+ *
+ * @return The file name.
+ */
+ public String getFileMac()
+ {
+ return fs.getString( "Mac" );
+ }
+
+ /**
+ * This will set name representing a Mac file.
+ *
+ * @param file The name of the file.
+ */
+ public void setFileMac( String file )
+ {
+ fs.setString( "Mac", file );
+ }
+
+ /**
+ * This will get the name representing a Unix file.
+ *
+ * @return The file name.
+ */
+ public String getFileUnix()
+ {
+ return fs.getString( "Unix" );
+ }
+
+ /**
+ * This will set name representing a Unix file.
+ *
+ * @param file The name of the file.
+ */
+ public void setFileUnix( String file )
+ {
+ fs.setString( "Unix", file );
+ }
+
+ /**
+ * Tell if the underlying file is volatile and should not be cached by the
+ * reader application. Default: false
+ *
+ * @param fileIsVolatile The new value for the volatility of the file.
+ */
+ public void setVolatile( boolean fileIsVolatile )
+ {
+ fs.setBoolean( "V", fileIsVolatile );
+ }
+
+ /**
+ * Get if the file is volatile. Default: false
+ *
+ * @return True if the file is volatile attribute is set.
+ */
+ public boolean isVolatile()
+ {
+ return fs.getBoolean( "V", false );
+ }
+
+ /**
+ * Get the embedded file.
+ *
+ * @return The embedded file for this file spec.
+ */
+ public PDEmbeddedFile getEmbeddedFile()
+ {
+ PDEmbeddedFile file = null;
+ COSStream stream = (COSStream)fs.getObjectFromPath( "EF/F" );
+ if( stream != null )
+ {
+ file = new PDEmbeddedFile( stream );
+ }
+ return file;
+ }
+
+ /**
+ * Set the embedded file for this spec.
+ *
+ * @param file The file to be embedded.
+ */
+ public void setEmbeddedFile( PDEmbeddedFile file )
+ {
+ COSDictionary ef = (COSDictionary)fs.getDictionaryObject( "EF" );
+ if( ef == null && file != null )
+ {
+ ef = new COSDictionary();
+ fs.setItem( "EF", ef );
+ }
+ if( ef != null )
+ {
+ ef.setItem( "F", file );
+ }
+ }
+
+ /**
+ * Get the embedded dos file.
+ *
+ * @return The embedded file for this file spec.
+ */
+ public PDEmbeddedFile getEmbeddedFileDos()
+ {
+ PDEmbeddedFile file = null;
+ COSStream stream = (COSStream)fs.getObjectFromPath( "EF/DOS" );
+ if( stream != null )
+ {
+ file = new PDEmbeddedFile( stream );
+ }
+ return file;
+ }
+
+ /**
+ * Set the embedded dos file for this spec.
+ *
+ * @param file The dos file to be embedded.
+ */
+ public void setEmbeddedFileDos( PDEmbeddedFile file )
+ {
+ COSDictionary ef = (COSDictionary)fs.getDictionaryObject( "DOS" );
+ if( ef == null && file != null )
+ {
+ ef = new COSDictionary();
+ fs.setItem( "EF", ef );
+ }
+ if( ef != null )
+ {
+ ef.setItem( "DOS", file );
+ }
+ }
+
+ /**
+ * Get the embedded Mac file.
+ *
+ * @return The embedded file for this file spec.
+ */
+ public PDEmbeddedFile getEmbeddedFileMac()
+ {
+ PDEmbeddedFile file = null;
+ COSStream stream = (COSStream)fs.getObjectFromPath( "EF/Mac" );
+ if( stream != null )
+ {
+ file = new PDEmbeddedFile( stream );
+ }
+ return file;
+ }
+
+ /**
+ * Set the embedded Mac file for this spec.
+ *
+ * @param file The Mac file to be embedded.
+ */
+ public void setEmbeddedFileMac( PDEmbeddedFile file )
+ {
+ COSDictionary ef = (COSDictionary)fs.getDictionaryObject( "Mac" );
+ if( ef == null && file != null )
+ {
+ ef = new COSDictionary();
+ fs.setItem( "EF", ef );
+ }
+ if( ef != null )
+ {
+ ef.setItem( "Mac", file );
+ }
+ }
+
+ /**
+ * Get the embedded Unix file.
+ *
+ * @return The embedded file for this file spec.
+ */
+ public PDEmbeddedFile getEmbeddedFileUnix()
+ {
+ PDEmbeddedFile file = null;
+ COSStream stream = (COSStream)fs.getObjectFromPath( "EF/Unix" );
+ if( stream != null )
+ {
+ file = new PDEmbeddedFile( stream );
+ }
+ return file;
+ }
+
+ /**
+ * Set the embedded Unix file for this spec.
+ *
+ * @param file The Unix file to be embedded.
+ */
+ public void setEmbeddedFileUnix( PDEmbeddedFile file )
+ {
+ COSDictionary ef = (COSDictionary)fs.getDictionaryObject( "Unix" );
+ if( ef == null && file != null )
+ {
+ ef = new COSDictionary();
+ fs.setItem( "EF", ef );
+ }
+ if( ef != null )
+ {
+ ef.setItem( "Unix", file );
+ }
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/common/filespecification/PDEmbeddedFile.java b/src/main/java/org/pdfbox/pdmodel/common/filespecification/PDEmbeddedFile.java
new file mode 100644
index 0000000..1f4a288
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/common/filespecification/PDEmbeddedFile.java
@@ -0,0 +1,298 @@
+/**
+ * Copyright (c) 2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.common.filespecification;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Calendar;
+
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSStream;
+import org.pdfbox.pdmodel.PDDocument;
+import org.pdfbox.pdmodel.common.PDStream;
+
+/**
+ * This represents an embedded file in a file specification.
+ *
+ * @author Ben Litchfield (ben@benlitchfield.com)
+ * @version $Revision: 1.1 $
+ */
+public class PDEmbeddedFile extends PDStream
+{
+
+ /**
+ * @see PDStream#PDStream(PDDocument)
+ */
+ public PDEmbeddedFile( PDDocument document )
+ {
+ super( document );
+ getStream().setName( "Type", "EmbeddedFile" );
+
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param str The stream parameter.
+ */
+ public PDEmbeddedFile( COSStream str )
+ {
+ super( str );
+ }
+
+ /**
+ * @see PDStream#PDStream(PDDocument, InputStream )
+ */
+ public PDEmbeddedFile( PDDocument doc, InputStream str ) throws IOException
+ {
+ super( doc, str );
+ getStream().setName( "Type", "EmbeddedFile" );
+ }
+
+ /**
+ * @see PDStream#PDStream(PDDocument, InputStream, boolean)
+ */
+ public PDEmbeddedFile( PDDocument doc, InputStream str, boolean filtered ) throws IOException
+ {
+ super( doc, str, filtered );
+ getStream().setName( "Type", "EmbeddedFile" );
+ }
+
+ /**
+ * Set the subtype for this embedded file. This should be a mime type value. Optional.
+ *
+ * @param mimeType The mimeType for the file.
+ */
+ public void setSubtype( String mimeType )
+ {
+ getStream().setName( "Subtype", mimeType );
+ }
+
+ /**
+ * Get the subtype(mimetype) for the embedded file.
+ *
+ * @return The type of embedded file.
+ */
+ public String getSubtype()
+ {
+ return getStream().getNameAsString( "Subtype" );
+ }
+
+ /**
+ * Get the size of the embedded file.
+ *
+ * @return The size of the embedded file.
+ */
+ public int getSize()
+ {
+ return getStream().getEmbeddedInt( "Params", "Size" );
+ }
+
+ /**
+ * Set the size of the embedded file.
+ *
+ * @param size The size of the embedded file.
+ */
+ public void setSize( int size )
+ {
+ getStream().setEmbeddedInt( "Params", "Size", size );
+ }
+
+ /**
+ * Get the creation date of the embedded file.
+ *
+ * @return The Creation date.
+ * @throws IOException If there is an error while constructing the date.
+ */
+ public Calendar getCreationDate() throws IOException
+ {
+ return getStream().getEmbeddedDate( "Params", "CreationDate" );
+ }
+
+ /**
+ * Set the creation date.
+ *
+ * @param creation The new creation date.
+ */
+ public void setCreationDate( Calendar creation )
+ {
+ getStream().setEmbeddedDate( "Params", "CreationDate", creation );
+ }
+
+ /**
+ * Get the mod date of the embedded file.
+ *
+ * @return The mod date.
+ * @throws IOException If there is an error while constructing the date.
+ */
+ public Calendar getModDate() throws IOException
+ {
+ return getStream().getEmbeddedDate( "Params", "ModDate" );
+ }
+
+ /**
+ * Set the mod date.
+ *
+ * @param mod The new creation mod.
+ */
+ public void setModDate( Calendar mod )
+ {
+ getStream().setEmbeddedDate( "Params", "ModDate", mod );
+ }
+
+ /**
+ * Get the check sum of the embedded file.
+ *
+ * @return The check sum of the file.
+ */
+ public String getCheckSum()
+ {
+ return getStream().getEmbeddedString( "Params", "CheckSum" );
+ }
+
+ /**
+ * Set the check sum.
+ *
+ * @param checksum The checksum of the file.
+ */
+ public void setCheckSum( String checksum )
+ {
+ getStream().setEmbeddedString( "Params", "CheckSum", checksum );
+ }
+
+ /**
+ * Get the mac subtype.
+ *
+ * @return The mac subtype.
+ */
+ public String getMacSubtype()
+ {
+ String retval = null;
+ COSDictionary params = (COSDictionary)getStream().getDictionaryObject( "Params" );
+ if( params != null )
+ {
+ retval = params.getEmbeddedString( "Mac", "Subtype" );
+ }
+ return retval;
+ }
+
+ /**
+ * Set the mac subtype.
+ *
+ * @param macSubtype The mac subtype.
+ */
+ public void setMacSubtype( String macSubtype )
+ {
+ COSDictionary params = (COSDictionary)getStream().getDictionaryObject( "Params" );
+ if( params == null && macSubtype != null )
+ {
+ params = new COSDictionary();
+ getStream().setItem( "Params", params );
+ }
+ if( params != null )
+ {
+ params.setEmbeddedString( "Mac", "Subtype", macSubtype );
+ }
+ }
+
+ /**
+ * Get the mac Creator.
+ *
+ * @return The mac Creator.
+ */
+ public String getMacCreator()
+ {
+ String retval = null;
+ COSDictionary params = (COSDictionary)getStream().getDictionaryObject( "Params" );
+ if( params != null )
+ {
+ retval = params.getEmbeddedString( "Mac", "Creator" );
+ }
+ return retval;
+ }
+
+ /**
+ * Set the mac Creator.
+ *
+ * @param macCreator The mac Creator.
+ */
+ public void setMacCreator( String macCreator )
+ {
+ COSDictionary params = (COSDictionary)getStream().getDictionaryObject( "Params" );
+ if( params == null && macCreator != null )
+ {
+ params = new COSDictionary();
+ getStream().setItem( "Params", params );
+ }
+ if( params != null )
+ {
+ params.setEmbeddedString( "Mac", "Creator", macCreator );
+ }
+ }
+
+ /**
+ * Get the mac ResFork.
+ *
+ * @return The mac ResFork.
+ */
+ public String getMacResFork()
+ {
+ String retval = null;
+ COSDictionary params = (COSDictionary)getStream().getDictionaryObject( "Params" );
+ if( params != null )
+ {
+ retval = params.getEmbeddedString( "Mac", "ResFork" );
+ }
+ return retval;
+ }
+
+ /**
+ * Set the mac ResFork.
+ *
+ * @param macResFork The mac ResFork.
+ */
+ public void setMacResFork( String macResFork )
+ {
+ COSDictionary params = (COSDictionary)getStream().getDictionaryObject( "Params" );
+ if( params == null && macResFork != null )
+ {
+ params = new COSDictionary();
+ getStream().setItem( "Params", params );
+ }
+ if( params != null )
+ {
+ params.setEmbeddedString( "Mac", "ResFork", macResFork);
+ }
+ }
+
+
+
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/common/filespecification/PDFileSpecification.java b/src/main/java/org/pdfbox/pdmodel/common/filespecification/PDFileSpecification.java
new file mode 100644
index 0000000..2028247
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/common/filespecification/PDFileSpecification.java
@@ -0,0 +1,83 @@
+/**
+ * Copyright (c) 2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.common.filespecification;
+
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSString;
+
+import org.pdfbox.pdmodel.common.COSObjectable;
+
+/**
+ * This represents a file specification.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.2 $
+ */
+public abstract class PDFileSpecification implements COSObjectable
+{
+
+ /**
+ * A file specfication can either be a COSString or a COSDictionary. This
+ * will create the file specification either way.
+ *
+ * @param base The cos object that describes the fs.
+ *
+ * @return The file specification for the COSBase object.
+ */
+ public static PDFileSpecification createFS( COSBase base )
+ {
+ PDFileSpecification retval = null;
+ if( base instanceof COSString )
+ {
+ retval = new PDSimpleFileSpecification( (COSString)base );
+ }
+ else if( base instanceof COSDictionary )
+ {
+ retval = new PDComplexFileSpecification( (COSDictionary)base );
+ }
+ return retval;
+ }
+
+ /**
+ * This will get the file name.
+ *
+ * @return The file name.
+ */
+ public abstract String getFile();
+
+ /**
+ * This will set the file name.
+ *
+ * @param file The name of the file.
+ */
+ public abstract void setFile( String file );
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/common/filespecification/PDSimpleFileSpecification.java b/src/main/java/org/pdfbox/pdmodel/common/filespecification/PDSimpleFileSpecification.java
new file mode 100644
index 0000000..b885a78
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/common/filespecification/PDSimpleFileSpecification.java
@@ -0,0 +1,95 @@
+/**
+ * Copyright (c) 2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.common.filespecification;
+
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSString;
+
+/**
+ * A file specification that is just a string.
+ *
+ * @author blitchfield
+ * @version $Revision: 1.1 $
+ */
+public class PDSimpleFileSpecification extends PDFileSpecification
+{
+ private COSString file;
+
+ /**
+ * Constructor.
+ *
+ */
+ public PDSimpleFileSpecification()
+ {
+ file = new COSString( "" );
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param fileName The file that this spec represents.
+ */
+ public PDSimpleFileSpecification( COSString fileName )
+ {
+ file = fileName;
+ }
+
+ /**
+ * This will get the file name.
+ *
+ * @return The file name.
+ */
+ public String getFile()
+ {
+ return file.getString();
+ }
+
+ /**
+ * This will set the file name.
+ *
+ * @param fileName The name of the file.
+ */
+ public void setFile( String fileName )
+ {
+ file = new COSString( fileName );
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSBase getCOSObject()
+ {
+ return file;
+ }
+
+}
diff --git a/src/main/java/org/pdfbox/pdmodel/common/filespecification/package.html b/src/main/java/org/pdfbox/pdmodel/common/filespecification/package.html
new file mode 100644
index 0000000..ca87d22
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/common/filespecification/package.html
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+
+</head>
+<body>
+The file specification package defines classes that are used for the PDF File Specification logic.
+</body>
+</html>
diff --git a/src/main/java/org/pdfbox/pdmodel/common/package.html b/src/main/java/org/pdfbox/pdmodel/common/package.html
new file mode 100644
index 0000000..9d81599
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/common/package.html
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+
+</head>
+<body>
+High level PD classes that are used throughout several packages are placed in the PDModel common package.
+</body>
+</html>
diff --git a/src/main/java/org/pdfbox/pdmodel/documentinterchange/logicalstructure/PDMarkInfo.java b/src/main/java/org/pdfbox/pdmodel/documentinterchange/logicalstructure/PDMarkInfo.java
new file mode 100644
index 0000000..47a8ff3
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/documentinterchange/logicalstructure/PDMarkInfo.java
@@ -0,0 +1,149 @@
+/**
+ * Copyright (c) 2005, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.documentinterchange.logicalstructure;
+
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.pdmodel.common.COSObjectable;
+
+/**
+ * The MarkInfo provides additional information relevant to specialized
+ * uses of structured documents.
+ *
+ * @author Ben Litchfield (ben@benlitchfield.com)
+ * @version $Revision: 1.3 $
+ */
+public class PDMarkInfo implements COSObjectable
+{
+ private COSDictionary dictionary;
+
+ /**
+ * Default Constructor.
+ *
+ */
+ public PDMarkInfo()
+ {
+ dictionary = new COSDictionary();
+ }
+
+ /**
+ * Constructor for an existing MarkInfo element.
+ *
+ * @param dic The existing dictionary.
+ */
+ public PDMarkInfo( COSDictionary dic )
+ {
+ dictionary = dic;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSBase getCOSObject()
+ {
+ return dictionary;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSDictionary getDictionary()
+ {
+ return dictionary;
+ }
+
+ /**
+ * Tells if this is a tagged PDF.
+ *
+ * @return true If this is a tagged PDF.
+ */
+ public boolean isMarked()
+ {
+ return dictionary.getBoolean( "Marked", false );
+ }
+
+ /**
+ * Set if this is a tagged PDF.
+ *
+ * @param value The new marked value.
+ */
+ public void setMarked( boolean value )
+ {
+ dictionary.setBoolean( "Marked", value );
+ }
+
+ /**
+ * Tells if structure elements use user properties.
+ *
+ * @return A boolean telling if the structure elements use user properties.
+ */
+ public boolean usesUserProperties()
+ {
+ return dictionary.getBoolean( "UserProperties", false );
+ }
+
+ /**
+ * Set if the structure elements contain user properties.
+ *
+ * @param userProps The new value for this property.
+ */
+ public void setUserProperties( boolean userProps )
+ {
+ dictionary.setBoolean( "UserProperties", userProps );
+ }
+
+ /**
+ * Tells if this PDF contain 'suspect' tags. See PDF Reference 1.6
+ * section 10.6 "Logical Structure" for more information about this property.
+ *
+ * @return true if the suspect flag has been set.
+ */
+ public boolean isSuspect()
+ {
+ return dictionary.getBoolean( "Suspects", false );
+ }
+
+ /**
+ * Set the value of the suspects property. See PDF Reference 1.6
+ * section 10.6 "Logical Structure" for more information about this
+ * property.
+ *
+ * @param suspect The new "Suspects" value.
+ */
+ public void setSuspect( boolean suspect )
+ {
+ dictionary.setBoolean( "Suspects", false );
+ }
+}
diff --git a/src/main/java/org/pdfbox/pdmodel/documentinterchange/logicalstructure/PDStructureElement.java b/src/main/java/org/pdfbox/pdmodel/documentinterchange/logicalstructure/PDStructureElement.java
new file mode 100644
index 0000000..9760b1b
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/documentinterchange/logicalstructure/PDStructureElement.java
@@ -0,0 +1,76 @@
+/**
+ * Copyright (c) 2003-2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.documentinterchange.logicalstructure;
+
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.pdmodel.common.COSObjectable;
+
+/**
+ * A structure element.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.1 $
+ */
+public class PDStructureElement implements COSObjectable
+{
+ private COSDictionary dictionary;
+
+ /**
+ * Default Constructor.
+ *
+ */
+ public PDStructureElement()
+ {
+ dictionary = new COSDictionary();
+ }
+
+ /**
+ * Constructor for an existing structure element.
+ *
+ * @param dic The existing dictionary.
+ */
+ public PDStructureElement( COSDictionary dic )
+ {
+ dictionary = dic;
+ }
+
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSBase getCOSObject()
+ {
+ return dictionary;
+ }
+}
diff --git a/src/main/java/org/pdfbox/pdmodel/documentinterchange/logicalstructure/package.html b/src/main/java/org/pdfbox/pdmodel/documentinterchange/logicalstructure/package.html
new file mode 100644
index 0000000..7039586
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/documentinterchange/logicalstructure/package.html
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+
+</head>
+<body>
+The logical structure package provides a mechanism for incorporating
+structural information about a document's content into a PDF file.
+</body>
+</html>
diff --git a/src/main/java/org/pdfbox/pdmodel/documentinterchange/prepress/PDBoxStyle.java b/src/main/java/org/pdfbox/pdmodel/documentinterchange/prepress/PDBoxStyle.java
new file mode 100644
index 0000000..4f092ef
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/documentinterchange/prepress/PDBoxStyle.java
@@ -0,0 +1,222 @@
+/**
+ * Copyright (c) 2005, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.documentinterchange.prepress;
+
+import org.pdfbox.cos.COSArray;
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSInteger;
+import org.pdfbox.pdmodel.common.COSObjectable;
+import org.pdfbox.pdmodel.graphics.PDLineDashPattern;
+import org.pdfbox.pdmodel.graphics.color.PDColorSpaceInstance;
+import org.pdfbox.pdmodel.graphics.color.PDDeviceRGB;
+
+/**
+ * The Box Style specifies visual characteristics for displaying box areas.
+ *
+ * @author Ben Litchfield (ben@benlitchfield.com)
+ * @version $Revision: 1.2 $
+ */
+public class PDBoxStyle implements COSObjectable
+{
+ /**
+ * Style for guideline.
+ */
+ public static final String GUIDELINE_STYLE_SOLID = "S";
+ /**
+ * Style for guideline.
+ */
+ public static final String GUIDELINE_STYLE_DASHED = "D";
+
+ private COSDictionary dictionary;
+
+ /**
+ * Default Constructor.
+ *
+ */
+ public PDBoxStyle()
+ {
+ dictionary = new COSDictionary();
+ }
+
+ /**
+ * Constructor for an existing BoxStyle element.
+ *
+ * @param dic The existing dictionary.
+ */
+ public PDBoxStyle( COSDictionary dic )
+ {
+ dictionary = dic;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSBase getCOSObject()
+ {
+ return dictionary;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSDictionary getDictionary()
+ {
+ return dictionary;
+ }
+
+ /**
+ * Get the color to be used for the guidelines. This is guaranteed to
+ * not return null. The color space will always be DeviceRGB and the
+ * default color is [0,0,0].
+ *
+ *@return The guideline color.
+ */
+ public PDColorSpaceInstance getGuidelineColor()
+ {
+ COSArray colorValues = (COSArray)dictionary.getDictionaryObject( "C" );
+ if( colorValues == null )
+ {
+ colorValues = new COSArray();
+ colorValues.add( COSInteger.ZERO );
+ colorValues.add( COSInteger.ZERO );
+ colorValues.add( COSInteger.ZERO );
+ dictionary.setItem( "C", colorValues );
+ }
+ PDColorSpaceInstance instance = new PDColorSpaceInstance( colorValues );
+ instance.setColorSpace( PDDeviceRGB.INSTANCE );
+ return instance;
+ }
+
+ /**
+ * Set the color space instance for this box style. This must be a
+ * PDDeviceRGB!
+ *
+ * @param color The new colorspace value.
+ */
+ public void setGuideLineColor( PDColorSpaceInstance color )
+ {
+ COSArray values = null;
+ if( color != null )
+ {
+ values = color.getCOSColorSpaceValue();
+ }
+ dictionary.setItem( "C", values );
+ }
+
+ /**
+ * Get the width of the of the guideline in default user space units.
+ * The default is 1.
+ *
+ * @return The width of the guideline.
+ */
+ public float getGuidelineWidth()
+ {
+ return dictionary.getFloat( "W", 1 );
+ }
+
+ /**
+ * Set the guideline width.
+ *
+ * @param width The width in default user space units.
+ */
+ public void setGuidelineWidth( float width )
+ {
+ dictionary.setFloat( "W", width );
+ }
+
+ /**
+ * Get the style for the guideline. The default is "S" for solid.
+ *
+ * @return The guideline style.
+ * @see PDBoxStyle#GUIDELINE_STYLE_DASHED
+ * @see PDBoxStyle#GUIDELINE_STYLE_SOLID
+ */
+ public String getGuidelineStyle()
+ {
+ return dictionary.getNameAsString( "S", GUIDELINE_STYLE_SOLID );
+ }
+
+ /**
+ * Set the style for the box.
+ *
+ * @param style The style for the box line.
+ * @see PDBoxStyle#GUIDELINE_STYLE_DASHED
+ * @see PDBoxStyle#GUIDELINE_STYLE_SOLID
+ */
+ public void setGuidelineStyle( String style )
+ {
+ dictionary.setName( "S", style );
+ }
+
+ /**
+ * Get the line dash pattern for this box style. This is guaranteed to not
+ * return null. The default is [3],0.
+ *
+ * @return The line dash pattern.
+ */
+ public PDLineDashPattern getLineDashPattern()
+ {
+ PDLineDashPattern pattern = null;
+ COSArray d = (COSArray)dictionary.getDictionaryObject( "D" );
+ if( d == null )
+ {
+ d = new COSArray();
+ d.add( new COSInteger(3) );
+ dictionary.setItem( "D", d );
+ }
+ COSArray lineArray = new COSArray();
+ lineArray.add( d );
+ //dash phase is not specified and assumed to be zero.
+ lineArray.add( new COSInteger( 0 ) );
+ pattern = new PDLineDashPattern( lineArray );
+ return pattern;
+ }
+
+ /**
+ * Set the line dash pattern associated with this box style.
+ *
+ * @param pattern The patter for this box style.
+ */
+ public void setLineDashPattern( PDLineDashPattern pattern )
+ {
+ COSArray array = null;
+ if( pattern != null )
+ {
+ array = pattern.getCOSDashPattern();
+ }
+ dictionary.setItem( "D", array );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/documentinterchange/prepress/package.html b/src/main/java/org/pdfbox/pdmodel/documentinterchange/prepress/package.html
new file mode 100644
index 0000000..8285a3f
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/documentinterchange/prepress/package.html
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+
+</head>
+<body>
+This package contains classes for prepress support in PDFBox.
+</body>
+</html>
diff --git a/src/main/java/org/pdfbox/pdmodel/edit/PDPageContentStream.java b/src/main/java/org/pdfbox/pdmodel/edit/PDPageContentStream.java
new file mode 100644
index 0000000..1e3b25f
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/edit/PDPageContentStream.java
@@ -0,0 +1,648 @@
+/**
+ * Copyright (c) 2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.edit;
+
+import java.awt.Color;
+import java.awt.color.ColorSpace;
+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.pdfbox.pdmodel.PDDocument;
+import org.pdfbox.pdmodel.PDPage;
+import org.pdfbox.pdmodel.PDResources;
+
+import org.pdfbox.pdmodel.common.COSStreamArray;
+import org.pdfbox.pdmodel.common.PDStream;
+
+import org.pdfbox.pdmodel.font.PDFont;
+import org.pdfbox.pdmodel.graphics.xobject.PDXObjectImage;
+
+import org.pdfbox.cos.COSArray;
+import org.pdfbox.cos.COSName;
+import org.pdfbox.cos.COSString;
+
+
+/**
+ * This class will is a convenience for creating page content streams. You MUST
+ * call close() when you are finished with this object.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.14 $
+ */
+public class PDPageContentStream
+{
+ private PDPage page;
+ private OutputStream output;
+ private boolean inTextMode = false;
+ private Map fontMappings = new HashMap();
+ private Map imageMappings = new HashMap();
+ private int fontNumber = 1;
+ private int imageNumber = 1;
+ private PDResources resources;
+
+ //cached storage component for getting color values
+ private float[] colorComponents = new float[4];
+
+ private NumberFormat formatDecimal = NumberFormat.getNumberInstance( Locale.US );
+
+ private static final String BEGIN_TEXT = "BT\n";
+ private static final String END_TEXT = "ET\n";
+ private static final String SET_FONT = "Tf\n";
+ private static final String MOVE_TEXT_POSITION = "Td\n";
+ private static final String SHOW_TEXT = "Tj\n";
+
+ private static final String SAVE_GRAPHICS_STATE = "q\n";
+ private static final String RESTORE_GRAPHICS_STATE = "Q\n";
+ private static final String CONCATENATE_MATRIX = "cm\n";
+ private static final String XOBJECT_DO = "Do\n";
+ private static final String RG_STROKING = "RG\n";
+ private static final String RG_NON_STROKING = "rg\n";
+ private static final String K_STROKING = "K\n";
+ private static final String K_NON_STROKING = "k\n";
+ private static final String G_STROKING = "G\n";
+ private static final String G_NON_STROKING = "g\n";
+ private static final String APPEND_RECTANGLE = "re\n";
+ private static final String FILL = "f\n";
+
+
+ private static final int SPACE = 32;
+
+
+ /**
+ * Create a new PDPage content stream.
+ *
+ * @param document The document the page is part of.
+ * @param sourcePage The page to write the contents to.
+ * @throws IOException If there is an error writing to the page contents.
+ */
+ public PDPageContentStream( PDDocument document, PDPage sourcePage ) throws IOException
+ {
+ this(document,sourcePage,false,true);
+ }
+
+ /**
+ * Create a new PDPage content stream.
+ *
+ * @param document The document the page is part of.
+ * @param sourcePage The page to write the contents to.
+ * @param appendContent Indicates whether content will be overwritten. If false all previous content is deleted.
+ * @param compress Tell if the content stream should compress the page contents.
+ * @throws IOException If there is an error writing to the page contents.
+ */
+ public PDPageContentStream( PDDocument document, PDPage sourcePage, boolean appendContent, boolean compress )
+ throws IOException
+ {
+ page = sourcePage;
+ resources = page.getResources();
+ if( resources == null )
+ {
+ resources = new PDResources();
+ page.setResources( resources );
+ }
+ // If request specifies the need to append to the document
+ if(appendContent)
+ {
+ // Get the pdstream from the source page instead of creating a new one
+ PDStream contents = sourcePage.getContents();
+
+ // Create a pdstream to append new content
+ PDStream contentsToAppend = new PDStream( document );
+
+ // This will be the resulting COSStreamArray after existing and new streams are merged
+ COSStreamArray compoundStream = null;
+
+ // If contents is already an array, a new stream is simply appended to it
+ if(contents.getStream() instanceof COSStreamArray)
+ {
+ compoundStream = (COSStreamArray)contents.getStream();
+ compoundStream.appendStream( contentsToAppend.getStream());
+ }
+ else
+ {
+ // Creates the COSStreamArray and adds the current stream plus a new one to it
+ COSArray newArray = new COSArray();
+ newArray.add(contents.getCOSObject());
+ newArray.add(contentsToAppend.getCOSObject());
+ compoundStream = new COSStreamArray(newArray);
+ }
+
+ if( compress )
+ {
+ List filters = new ArrayList();
+ filters.add( COSName.FLATE_DECODE );
+ contentsToAppend.setFilters( filters );
+ }
+
+ // Sets the compoundStream as page contents
+ sourcePage.setContents( new PDStream(compoundStream) );
+ output = contentsToAppend.createOutputStream();
+ }
+ else
+ {
+ PDStream contents = new PDStream( document );
+ if( compress )
+ {
+ List filters = new ArrayList();
+ filters.add( COSName.FLATE_DECODE );
+ contents.setFilters( filters );
+ }
+ sourcePage.setContents( contents );
+ output = contents.createOutputStream();
+ }
+ formatDecimal.setMaximumFractionDigits( 10 );
+ formatDecimal.setGroupingUsed( false );
+ }
+
+ /**
+ * Begin some text operations.
+ *
+ * @throws IOException If there is an error writing to the stream or if you attempt to
+ * nest beginText calls.
+ */
+ public void beginText() throws IOException
+ {
+ if( inTextMode )
+ {
+ throw new IOException( "Error: Nested beginText() calls are not allowed." );
+ }
+ appendRawCommands( BEGIN_TEXT );
+ inTextMode = true;
+ }
+
+ /**
+ * End some text operations.
+ *
+ * @throws IOException If there is an error writing to the stream or if you attempt to
+ * nest endText calls.
+ */
+ public void endText() throws IOException
+ {
+ if( !inTextMode )
+ {
+ throw new IOException( "Error: You must call beginText() before calling endText." );
+ }
+ appendRawCommands( END_TEXT );
+ inTextMode = false;
+ }
+
+ /**
+ * Set the font to draw text with.
+ *
+ * @param font The font to use.
+ * @param fontSize The font size to draw the text.
+ * @throws IOException If there is an error writing the font information.
+ */
+ public void setFont( PDFont font, float fontSize ) throws IOException
+ {
+ String fontMapping = (String)fontMappings.get( font );
+ if( fontMapping == null )
+ {
+ fontMapping = "F" + fontNumber++;
+ fontMappings.put( font, fontMapping );
+ resources.getFonts().put( fontMapping, font );
+ }
+ appendRawCommands( "/");
+ appendRawCommands( fontMapping );
+ appendRawCommands( SPACE );
+ appendRawCommands( formatDecimal.format( fontSize ) );
+ appendRawCommands( SPACE );
+ appendRawCommands( SET_FONT );
+ }
+
+ /**
+ * Draw an image at the x,y coordinates, with the default size of the image.
+ *
+ * @param image The image to draw.
+ * @param x The x-coordinate to draw the image.
+ * @param y The y-coordinate to draw the image.
+ *
+ * @throws IOException If there is an error writing to the stream.
+ */
+ public void drawImage( PDXObjectImage image, int x, int y ) throws IOException
+ {
+ drawImage( image, x, y, image.getWidth(), image.getHeight() );
+ }
+
+ /**
+ * Draw an image at the x,y coordinates and a certain width and height.
+ *
+ * @param image The image to draw.
+ * @param x The x-coordinate to draw the image.
+ * @param y The y-coordinate to draw the image.
+ * @param width The width of the image to draw.
+ * @param height The height of the image to draw.
+ *
+ * @throws IOException If there is an error writing to the stream.
+ */
+ public void drawImage( PDXObjectImage image, int x, int y, int width, int height ) throws IOException
+ {
+ String imageMapping = (String)imageMappings.get( image );
+ if( imageMapping == null )
+ {
+ imageMapping = "Im" + imageNumber++;
+ imageMappings.put( image, imageMapping );
+ resources.getImages().put( imageMapping, image );
+ }
+ appendRawCommands( SAVE_GRAPHICS_STATE );
+ appendRawCommands( formatDecimal.format( width ) );
+ appendRawCommands( SPACE );
+ appendRawCommands( formatDecimal.format( 0 ) );
+ appendRawCommands( SPACE );
+ appendRawCommands( formatDecimal.format( 0 ) );
+ appendRawCommands( SPACE );
+ appendRawCommands( formatDecimal.format( height ) );
+ appendRawCommands( SPACE );
+ appendRawCommands( formatDecimal.format( x ) );
+ appendRawCommands( SPACE );
+ appendRawCommands( formatDecimal.format( y ) );
+ appendRawCommands( SPACE );
+ appendRawCommands( CONCATENATE_MATRIX );
+ appendRawCommands( SPACE );
+ appendRawCommands( "/" );
+ appendRawCommands( imageMapping );
+ appendRawCommands( SPACE );
+ appendRawCommands( XOBJECT_DO );
+ appendRawCommands( SPACE );
+ appendRawCommands( RESTORE_GRAPHICS_STATE );
+ }
+
+ /**
+ * The Td operator.
+ * @param x The x coordinate.
+ * @param y The y coordinate.
+ * @throws IOException If there is an error writing to the stream.
+ */
+ public void moveTextPositionByAmount( float x, float y ) throws IOException
+ {
+ if( !inTextMode )
+ {
+ throw new IOException( "Error: must call beginText() before moveTextPositionByAmount");
+ }
+ appendRawCommands( formatDecimal.format( x ) );
+ appendRawCommands( SPACE );
+ appendRawCommands( formatDecimal.format( y ) );
+ appendRawCommands( SPACE );
+ appendRawCommands( MOVE_TEXT_POSITION );
+ }
+
+ /**
+ * This will draw a string at the current location on the screen.
+ *
+ * @param text The text to draw.
+ * @throws IOException If an io exception occurs.
+ */
+ public void drawString( String text ) throws IOException
+ {
+ if( !inTextMode )
+ {
+ throw new IOException( "Error: must call beginText() before drawString");
+ }
+ COSString string = new COSString( text );
+ ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+ string.writePDF( buffer );
+ appendRawCommands( new String( buffer.toByteArray(), "ISO-8859-1"));
+ appendRawCommands( SPACE );
+ appendRawCommands( SHOW_TEXT );
+ }
+
+ /**
+ * Set the stroking color, specified as RGB.
+ *
+ * @param color The color to set.
+ * @throws IOException If an IO error occurs while writing to the stream.
+ */
+ public void setStrokingColor( Color color ) throws IOException
+ {
+ ColorSpace colorSpace = color.getColorSpace();
+ if( colorSpace.getType() == ColorSpace.TYPE_RGB )
+ {
+ setStrokingColor( color.getRed(), color.getGreen(), color.getBlue() );
+ }
+ else if( colorSpace.getType() == ColorSpace.TYPE_GRAY )
+ {
+ color.getColorComponents( colorComponents );
+ setStrokingColor( colorComponents[0] );
+ }
+ else if( colorSpace.getType() == ColorSpace.TYPE_CMYK )
+ {
+ color.getColorComponents( colorComponents );
+ setStrokingColor( colorComponents[0], colorComponents[2], colorComponents[2], colorComponents[3] );
+ }
+ else
+ {
+ throw new IOException( "Error: unknown colorspace:" + colorSpace );
+ }
+ }
+
+ /**
+ * Set the non stroking color, specified as RGB.
+ *
+ * @param color The color to set.
+ * @throws IOException If an IO error occurs while writing to the stream.
+ */
+ public void setNonStrokingColor( Color color ) throws IOException
+ {
+ ColorSpace colorSpace = color.getColorSpace();
+ if( colorSpace.getType() == ColorSpace.TYPE_RGB )
+ {
+ setNonStrokingColor( color.getRed(), color.getGreen(), color.getBlue() );
+ }
+ else if( colorSpace.getType() == ColorSpace.TYPE_GRAY )
+ {
+ color.getColorComponents( colorComponents );
+ setNonStrokingColor( colorComponents[0] );
+ }
+ else if( colorSpace.getType() == ColorSpace.TYPE_CMYK )
+ {
+ color.getColorComponents( colorComponents );
+ setNonStrokingColor( colorComponents[0], colorComponents[2], colorComponents[2], colorComponents[3] );
+ }
+ else
+ {
+ throw new IOException( "Error: unknown colorspace:" + colorSpace );
+ }
+ }
+
+ /**
+ * Set the stroking color, specified as RGB, 0-255.
+ *
+ * @param r The red value.
+ * @param g The green value.
+ * @param b The blue value.
+ * @throws IOException If an IO error occurs while writing to the stream.
+ */
+ public void setStrokingColor( int r, int g, int b ) throws IOException
+ {
+ appendRawCommands( formatDecimal.format( r/255d ) );
+ appendRawCommands( SPACE );
+ appendRawCommands( formatDecimal.format( g/255d ) );
+ appendRawCommands( SPACE );
+ appendRawCommands( formatDecimal.format( b/255d ) );
+ appendRawCommands( SPACE );
+ appendRawCommands( RG_STROKING );
+ }
+
+ /**
+ * Set the stroking color, specified as CMYK, 0-255.
+ *
+ * @param c The cyan value.
+ * @param m The magenta value.
+ * @param y The yellow value.
+ * @param k The black value.
+ * @throws IOException If an IO error occurs while writing to the stream.
+ */
+ public void setStrokingColor( int c, int m, int y, int k) throws IOException
+ {
+ appendRawCommands( formatDecimal.format( c/255d ) );
+ appendRawCommands( SPACE );
+ appendRawCommands( formatDecimal.format( m/255d ) );
+ appendRawCommands( SPACE );
+ appendRawCommands( formatDecimal.format( y/255d ) );
+ appendRawCommands( SPACE );
+ appendRawCommands( formatDecimal.format( k/255d ) );
+ appendRawCommands( SPACE );
+ appendRawCommands( K_STROKING );
+ }
+
+ /**
+ * Set the stroking color, specified as CMYK, 0.0-1.0.
+ *
+ * @param c The cyan value.
+ * @param m The magenta value.
+ * @param y The yellow value.
+ * @param k The black value.
+ * @throws IOException If an IO error occurs while writing to the stream.
+ */
+ public void setStrokingColor( double c, double m, double y, double k) throws IOException
+ {
+ appendRawCommands( formatDecimal.format( c ) );
+ appendRawCommands( SPACE );
+ appendRawCommands( formatDecimal.format( m ) );
+ appendRawCommands( SPACE );
+ appendRawCommands( formatDecimal.format( y ) );
+ appendRawCommands( SPACE );
+ appendRawCommands( formatDecimal.format( k ) );
+ appendRawCommands( SPACE );
+ appendRawCommands( K_STROKING );
+ }
+
+ /**
+ * Set the stroking color, specified as grayscale, 0-255.
+ *
+ * @param g The gray value.
+ * @throws IOException If an IO error occurs while writing to the stream.
+ */
+ public void setStrokingColor( int g ) throws IOException
+ {
+ appendRawCommands( formatDecimal.format( g/255d ) );
+ appendRawCommands( SPACE );
+ appendRawCommands( G_STROKING );
+ }
+
+ /**
+ * Set the stroking color, specified as Grayscale 0.0-1.0.
+ *
+ * @param g The gray value.
+ * @throws IOException If an IO error occurs while writing to the stream.
+ */
+ public void setStrokingColor( double g ) throws IOException
+ {
+ appendRawCommands( formatDecimal.format( g ) );
+ appendRawCommands( SPACE );
+ appendRawCommands( G_STROKING );
+ }
+
+ /**
+ * Set the non stroking color, specified as RGB, 0-255.
+ *
+ * @param r The red value.
+ * @param g The green value.
+ * @param b The blue value.
+ * @throws IOException If an IO error occurs while writing to the stream.
+ */
+ public void setNonStrokingColor( int r, int g, int b ) throws IOException
+ {
+ appendRawCommands( formatDecimal.format( r/255d ) );
+ appendRawCommands( SPACE );
+ appendRawCommands( formatDecimal.format( g/255d ) );
+ appendRawCommands( SPACE );
+ appendRawCommands( formatDecimal.format( b/255d ) );
+ appendRawCommands( SPACE );
+ appendRawCommands( RG_NON_STROKING );
+ }
+
+ /**
+ * Set the non stroking color, specified as CMYK, 0-255.
+ *
+ * @param c The cyan value.
+ * @param m The magenta value.
+ * @param y The yellow value.
+ * @param k The black value.
+ * @throws IOException If an IO error occurs while writing to the stream.
+ */
+ public void setNonStrokingColor( int c, int m, int y, int k) throws IOException
+ {
+ appendRawCommands( formatDecimal.format( c/255d ) );
+ appendRawCommands( SPACE );
+ appendRawCommands( formatDecimal.format( m/255d ) );
+ appendRawCommands( SPACE );
+ appendRawCommands( formatDecimal.format( y/255d ) );
+ appendRawCommands( SPACE );
+ appendRawCommands( formatDecimal.format( k/255d ) );
+ appendRawCommands( SPACE );
+ appendRawCommands( K_NON_STROKING );
+ }
+
+ /**
+ * Set the non stroking color, specified as CMYK, 0.0-1.0.
+ *
+ * @param c The cyan value.
+ * @param m The magenta value.
+ * @param y The yellow value.
+ * @param k The black value.
+ * @throws IOException If an IO error occurs while writing to the stream.
+ */
+ public void setNonStrokingColor( double c, double m, double y, double k) throws IOException
+ {
+ appendRawCommands( formatDecimal.format( c ) );
+ appendRawCommands( SPACE );
+ appendRawCommands( formatDecimal.format( m ) );
+ appendRawCommands( SPACE );
+ appendRawCommands( formatDecimal.format( y ) );
+ appendRawCommands( SPACE );
+ appendRawCommands( formatDecimal.format( k ) );
+ appendRawCommands( SPACE );
+ appendRawCommands( K_NON_STROKING );
+ }
+
+ /**
+ * Set the non stroking color, specified as grayscale, 0-255.
+ *
+ * @param g The gray value.
+ * @throws IOException If an IO error occurs while writing to the stream.
+ */
+ public void setNonStrokingColor( int g ) throws IOException
+ {
+ appendRawCommands( formatDecimal.format( g/255d ) );
+ appendRawCommands( SPACE );
+ appendRawCommands( G_NON_STROKING );
+ }
+
+ /**
+ * Set the non stroking color, specified as Grayscale 0.0-1.0.
+ *
+ * @param g The gray value.
+ * @throws IOException If an IO error occurs while writing to the stream.
+ */
+ public void setNonStrokingColor( double g ) throws IOException
+ {
+ appendRawCommands( formatDecimal.format( g ) );
+ appendRawCommands( SPACE );
+ appendRawCommands( G_NON_STROKING );
+ }
+
+ /**
+ * Draw a rectangle on the page using the current non stroking color.
+ *
+ * @param x The lower left x coordinate.
+ * @param y The lower left y coordinate.
+ * @param width The width of the rectangle.
+ * @param height The height of the rectangle.
+ * @throws IOException If there is an error while drawing on the screen.
+ */
+ public void fillRect( float x, float y, float width, float height ) throws IOException
+ {
+ appendRawCommands( formatDecimal.format( x ) );
+ appendRawCommands( SPACE );
+ appendRawCommands( formatDecimal.format( y ) );
+ appendRawCommands( SPACE );
+ appendRawCommands( formatDecimal.format( width ) );
+ appendRawCommands( SPACE );
+ appendRawCommands( formatDecimal.format( height ) );
+ appendRawCommands( SPACE );
+ appendRawCommands( APPEND_RECTANGLE );
+ appendRawCommands( FILL );
+ }
+
+
+ /**
+ * This will append raw commands to the content stream.
+ *
+ * @param commands The commands to append to the stream.
+ * @throws IOException If an error occurs while writing to the stream.
+ */
+ public void appendRawCommands( String commands ) throws IOException
+ {
+ appendRawCommands( commands.getBytes( "ISO-8859-1" ) );
+ }
+
+ /**
+ * This will append raw commands to the content stream.
+ *
+ * @param commands The commands to append to the stream.
+ * @throws IOException If an error occurs while writing to the stream.
+ */
+ public void appendRawCommands( byte[] commands ) throws IOException
+ {
+ output.write( commands );
+ }
+
+ /**
+ * This will append raw commands to the content stream.
+ *
+ * @param data Append a raw byte to the stream.
+ *
+ * @throws IOException If an error occurs while writing to the stream.
+ */
+ public void appendRawCommands( int data ) throws IOException
+ {
+ output.write( data );
+ }
+
+ /**
+ * 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.
+ */
+ public void close() throws IOException
+ {
+ output.close();
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/edit/package.html b/src/main/java/org/pdfbox/pdmodel/edit/package.html
new file mode 100644
index 0000000..f6b0ffd
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/edit/package.html
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+
+</head>
+<body>
+The PDModel edit package will be used to store classes for creating page content.
+</body>
+</html>
diff --git a/src/main/java/org/pdfbox/pdmodel/encryption/PDEncryptionDictionary.java b/src/main/java/org/pdfbox/pdmodel/encryption/PDEncryptionDictionary.java
new file mode 100644
index 0000000..08f18fb
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/encryption/PDEncryptionDictionary.java
@@ -0,0 +1,193 @@
+/**
+ * Copyright (c) 2003, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.encryption;
+
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSInteger;
+import org.pdfbox.cos.COSName;
+import org.pdfbox.cos.COSNumber;
+
+/**
+ * This represents the base class for encryption dictionaries. All PDF implementations
+ * are expected to implement the Standard encryption algorithm, but others can be plugged in.
+ *
+ * See PDF Reference 1.4 section "3.5 Encryption"
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.5 $
+ */
+public abstract class PDEncryptionDictionary
+{
+ /**
+ * See PDF Reference 1.4 Table 3.13.
+ */
+ public static final int VERSION0_UNDOCUMENTED_UNSUPPORTED = 0;
+ /**
+ * See PDF Reference 1.4 Table 3.13.
+ */
+ public static final int VERSION1_40_BIT_ALGORITHM = 1;
+ /**
+ * See PDF Reference 1.4 Table 3.13.
+ */
+ public static final int VERSION2_VARIABLE_LENGTH_ALGORITHM = 2;
+ /**
+ * See PDF Reference 1.4 Table 3.13.
+ */
+ public static final int VERSION3_UNPUBLISHED_ALGORITHM = 3;
+ /**
+ * See PDF Reference 1.4 Table 3.13.
+ */
+ public static final int VERSION4_SECURITY_HANDLER = 4;
+
+ /**
+ * The default security handler.
+ */
+ public static final String DEFAULT_NAME = "Standard";
+
+ /**
+ * The default length for the encryption key.
+ */
+ public static final int DEFAULT_LENGTH = 40;
+
+ /**
+ * The default version, according to the PDF Reference.
+ */
+ public static final int DEFAULT_VERSION = VERSION0_UNDOCUMENTED_UNSUPPORTED;
+
+ /**
+ * The cos model wrapped object.
+ */
+ protected COSDictionary encryptionDictionary = null;
+
+ /**
+ * Constructor.
+ *
+ * @param dictionary The pre-existing encryption dictionary.
+ */
+ protected PDEncryptionDictionary( COSDictionary dictionary )
+ {
+ encryptionDictionary = dictionary;
+ }
+
+ /**
+ * Constructor, sub classes need to fill out the required fields.
+ */
+ protected PDEncryptionDictionary()
+ {
+ encryptionDictionary = new COSDictionary();
+ setLength( DEFAULT_LENGTH );
+ setVersion( DEFAULT_VERSION );
+ }
+
+ /**
+ * This will get the dictionary associated with this encryption dictionary.
+ *
+ * @return The COS dictionary that this object wraps.
+ */
+ public COSDictionary getCOSDictionary()
+ {
+ return encryptionDictionary;
+ }
+
+ /**
+ * Read-only field of the encryption filter name. The default value is
+ * "Standard" for the built in security handler.
+ *
+ * @return The name of the encryption handler.
+ */
+ public String getFilter()
+ {
+ String filter = DEFAULT_NAME;
+ COSName cosFilter = (COSName)encryptionDictionary.getDictionaryObject( COSName.FILTER );
+ if( cosFilter != null )
+ {
+ filter = cosFilter.getName();
+ }
+ return filter;
+ }
+
+ /**
+ * This will return the V entry of the encryption dictionary.<br /><br />
+ * See PDF Reference 1.4 Table 3.13.
+ *
+ * @return The encryption version to use.
+ */
+ public int getVersion()
+ {
+ int version = DEFAULT_VERSION;
+ COSNumber cosVersion = (COSNumber)encryptionDictionary.getDictionaryObject( COSName.getPDFName( "V" ) );
+ if( cosVersion != null )
+ {
+ version = cosVersion.intValue();
+ }
+ return version;
+ }
+
+ /**
+ * This will set the V entry of the encryption dictionary.<br /><br />
+ * See PDF Reference 1.4 Table 3.13. <br /><br/>
+ * <b>Note: This value is used to decrypt the pdf document. If you change this when
+ * the document is encrypted then decryption will fail!.</b>
+ *
+ * @param version The new encryption version.
+ */
+ public void setVersion( int version )
+ {
+ encryptionDictionary.setItem( COSName.getPDFName( "V" ), new COSInteger( version ) );
+ }
+
+ /**
+ * This will return the Length entry of the encryption dictionary.<br /><br />
+ * The length in <b>bits</b> for the encryption algorithm. This will return a multiple of 8.
+ *
+ * @return The length in bits for the encryption algorithm
+ */
+ public int getLength()
+ {
+ int length = DEFAULT_LENGTH;
+ COSNumber cosLength = (COSNumber)encryptionDictionary.getDictionaryObject( COSName.LENGTH );
+ if( cosLength != null )
+ {
+ length = cosLength.intValue();
+ }
+ return length;
+ }
+
+ /**
+ * This will set the number of bits to use for the encryption algorithm.
+ *
+ * @param length The new key length.
+ */
+ public void setLength( int length )
+ {
+ encryptionDictionary.setItem( COSName.LENGTH, new COSInteger( length ) );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/encryption/PDEncryptionManager.java b/src/main/java/org/pdfbox/pdmodel/encryption/PDEncryptionManager.java
new file mode 100644
index 0000000..9dfc36e
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/encryption/PDEncryptionManager.java
@@ -0,0 +1,131 @@
+/**
+ * Copyright (c) 2003-2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.encryption;
+
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSName;
+import java.io.IOException;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * This class will handle loading of the different security handlers.
+ *
+ * See PDF Reference 1.4 section "3.5 Encryption"
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.5 $
+ */
+public class PDEncryptionManager
+{
+ private static Map handlerMap = Collections.synchronizedMap( new HashMap() );
+
+ static
+ {
+ registerSecurityHandler( PDStandardEncryption.FILTER_NAME, PDStandardEncryption.class );
+ }
+
+ private PDEncryptionManager()
+ {
+ }
+
+ /**
+ * This will allow the user to register new security handlers when unencrypting a
+ * document.
+ *
+ * @param filterName As described in the encryption dictionary.
+ * @param handlerClass A subclass of PDEncryptionDictionary that has a constructor that takes
+ * a COSDictionary.
+ */
+ public static void registerSecurityHandler( String filterName, Class handlerClass )
+ {
+ handlerMap.put( COSName.getPDFName( filterName ), handlerClass );
+ }
+
+ /**
+ * This will get the correct security handler for the encryption dictionary.
+ *
+ * @param dictionary The encryption dictionary.
+ *
+ * @return An implementation of PDEncryptionDictionary(PDStandardEncryption for most cases).
+ *
+ * @throws IOException If a security handler could not be found.
+ */
+ public static PDEncryptionDictionary getEncryptionDictionary( COSDictionary dictionary )
+ throws IOException
+ {
+ Object retval = null;
+ if( dictionary != null )
+ {
+ COSName filter = (COSName)dictionary.getDictionaryObject( COSName.FILTER );
+ Class handlerClass = (Class)handlerMap.get( filter );
+ if( handlerClass == null )
+ {
+ throw new IOException( "No handler for security handler '" + filter.getName() + "'" );
+ }
+ else
+ {
+ try
+ {
+ Constructor ctor = handlerClass.getConstructor( new Class[] {
+ COSDictionary.class
+ } );
+ retval = ctor.newInstance( new Object[] {
+ dictionary
+ } );
+ }
+ catch( NoSuchMethodException e )
+ {
+ throw new IOException( e.getMessage() );
+ }
+ catch( InstantiationException e )
+ {
+ throw new IOException( e.getMessage() );
+ }
+ catch( IllegalAccessException e )
+ {
+ throw new IOException( e.getMessage() );
+ }
+ catch( InvocationTargetException e )
+ {
+ throw new IOException( e.getMessage() );
+ }
+ }
+ }
+ return (PDEncryptionDictionary)retval;
+
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/encryption/PDStandardEncryption.java b/src/main/java/org/pdfbox/pdmodel/encryption/PDStandardEncryption.java
new file mode 100644
index 0000000..5b3be3b
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/encryption/PDStandardEncryption.java
@@ -0,0 +1,416 @@
+/**
+ * Copyright (c) 2003, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.encryption;
+
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSInteger;
+import org.pdfbox.cos.COSName;
+import org.pdfbox.cos.COSNumber;
+import org.pdfbox.cos.COSString;
+
+import java.io.IOException;
+
+/**
+ * This class holds information that is related to the standard PDF encryption.
+ *
+ * See PDF Reference 1.4 section "3.5 Encryption"
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.5 $
+ */
+public class PDStandardEncryption extends PDEncryptionDictionary
+{
+ /**
+ * The 'Filter' name for this security handler.
+ */
+ public static final String FILTER_NAME = "Standard";
+
+ /**
+ * The default revision of one is not specified.
+ */
+ public static final int DEFAULT_REVISION = 3;
+
+ /**
+ * Encryption revision 2.
+ */
+ public static final int REVISION2 = 2;
+ /**
+ * Encryption revision 3.
+ */
+ public static final int REVISION3 = 3;
+ /**
+ * Encryption revision 4.
+ */
+ public static final int REVISION4 = 4;
+
+ /**
+ * The default set of permissions which is to allow all.
+ */
+ public static final int DEFAULT_PERMISSIONS = 0xFFFFFFFF ^ 3;//bits 0 & 1 need to be zero
+
+ private static final int PRINT_BIT = 3;
+ private static final int MODIFICATION_BIT = 4;
+ private static final int EXTRACT_BIT = 5;
+ private static final int MODIFY_ANNOTATIONS_BIT = 6;
+ private static final int FILL_IN_FORM_BIT = 9;
+ private static final int EXTRACT_FOR_ACCESSIBILITY_BIT = 10;
+ private static final int ASSEMBLE_DOCUMENT_BIT = 11;
+ private static final int DEGRADED_PRINT_BIT = 12;
+
+ /**
+ * Default constructor that uses Version 2, Revision 3, 40 bit encryption,
+ * all permissions allowed.
+ */
+ public PDStandardEncryption()
+ {
+ super();
+ encryptionDictionary.setItem( COSName.FILTER, COSName.getPDFName( FILTER_NAME ) );
+ setVersion( PDEncryptionDictionary.VERSION1_40_BIT_ALGORITHM );
+ setRevision( PDStandardEncryption.REVISION2 );
+ setPermissions( DEFAULT_PERMISSIONS );
+ }
+
+ /**
+ * Constructor from existing dictionary.
+ *
+ * @param dict The existing encryption dictionary.
+ */
+ public PDStandardEncryption( COSDictionary dict )
+ {
+ super( dict );
+ }
+
+ /**
+ * This will return the R entry of the encryption dictionary.<br /><br />
+ * See PDF Reference 1.4 Table 3.14.
+ *
+ * @return The encryption revision to use.
+ */
+ public int getRevision()
+ {
+ int revision = DEFAULT_VERSION;
+ COSNumber cosRevision = (COSNumber)encryptionDictionary.getDictionaryObject( COSName.getPDFName( "R" ) );
+ if( cosRevision != null )
+ {
+ revision = cosRevision.intValue();
+ }
+ return revision;
+ }
+
+ /**
+ * This will set the R entry of the encryption dictionary.<br /><br />
+ * See PDF Reference 1.4 Table 3.14. <br /><br/>
+ *
+ * <b>Note: This value is used to decrypt the pdf document. If you change this when
+ * the document is encrypted then decryption will fail!.</b>
+ *
+ * @param revision The new encryption version.
+ */
+ public void setRevision( int revision )
+ {
+ encryptionDictionary.setItem( COSName.getPDFName( "R" ), new COSInteger( revision ) );
+ }
+
+ /**
+ * This will get the O entry in the standard encryption dictionary.
+ *
+ * @return A 32 byte array or null if there is no owner key.
+ */
+ public byte[] getOwnerKey()
+ {
+ byte[] o = null;
+ COSString owner = (COSString)encryptionDictionary.getDictionaryObject( COSName.getPDFName( "O" ) );
+ if( owner != null )
+ {
+ o = owner.getBytes();
+ }
+ return o;
+ }
+
+ /**
+ * This will set the O entry in the standard encryption dictionary.
+ *
+ * @param o A 32 byte array or null if there is no owner key.
+ *
+ * @throws IOException If there is an error setting the data.
+ */
+ public void setOwnerKey( byte[] o ) throws IOException
+ {
+ COSString owner = new COSString();
+ owner.append( o );
+ encryptionDictionary.setItem( COSName.getPDFName( "O" ), owner );
+ }
+
+ /**
+ * This will get the U entry in the standard encryption dictionary.
+ *
+ * @return A 32 byte array or null if there is no user key.
+ */
+ public byte[] getUserKey()
+ {
+ byte[] u = null;
+ COSString user = (COSString)encryptionDictionary.getDictionaryObject( COSName.getPDFName( "U" ) );
+ if( user != null )
+ {
+ u = user.getBytes();
+ }
+ return u;
+ }
+
+ /**
+ * This will set the U entry in the standard encryption dictionary.
+ *
+ * @param u A 32 byte array.
+ *
+ * @throws IOException If there is an error setting the data.
+ */
+ public void setUserKey( byte[] u ) throws IOException
+ {
+ COSString user = new COSString();
+ user.append( u );
+ encryptionDictionary.setItem( COSName.getPDFName( "U" ), user );
+ }
+
+ /**
+ * This will get the permissions bit mask.
+ *
+ * @return The permissions bit mask.
+ */
+ public int getPermissions()
+ {
+ int permissions = 0;
+ COSInteger p = (COSInteger)encryptionDictionary.getDictionaryObject( COSName.getPDFName( "P" ) );
+ if( p != null )
+ {
+ permissions = p.intValue();
+ }
+ return permissions;
+ }
+
+ /**
+ * This will set the permissions bit mask.
+ *
+ * @param p The new permissions bit mask
+ */
+ public void setPermissions( int p )
+ {
+ encryptionDictionary.setItem( COSName.getPDFName( "P" ), new COSInteger( p ) );
+ }
+
+ private boolean isPermissionBitOn( int bit )
+ {
+ return (getPermissions() & (1 << (bit-1))) != 0;
+ }
+
+ private boolean setPermissionBit( int bit, boolean value )
+ {
+ int permissions = getPermissions();
+ if( value )
+ {
+ permissions = permissions | (1 << (bit-1));
+ }
+ else
+ {
+ permissions = permissions & (0xFFFFFFFF ^ (1 << (bit-1)));
+ }
+ setPermissions( permissions );
+
+ return (getPermissions() & (1 << (bit-1))) != 0;
+ }
+
+ /**
+ * This will tell if the user can print.
+ *
+ * @return true If supplied with the user password they are allowed to print.
+ */
+ public boolean canPrint()
+ {
+ return isPermissionBitOn( PRINT_BIT );
+ }
+
+ /**
+ * Set if the user can print.
+ *
+ * @param allowPrinting A boolean determining if the user can print.
+ */
+ public void setCanPrint( boolean allowPrinting )
+ {
+ setPermissionBit( PRINT_BIT, allowPrinting );
+ }
+
+ /**
+ * This will tell if the user can modify contents of the document.
+ *
+ * @return true If supplied with the user password they are allowed to modify the document
+ */
+ public boolean canModify()
+ {
+ return isPermissionBitOn( MODIFICATION_BIT );
+ }
+
+ /**
+ * Set if the user can modify the document.
+ *
+ * @param allowModifications A boolean determining if the user can modify the document.
+ */
+ public void setCanModify( boolean allowModifications )
+ {
+ setPermissionBit( MODIFICATION_BIT, allowModifications );
+ }
+
+ /**
+ * This will tell if the user can extract text and images from the PDF document.
+ *
+ * @return true If supplied with the user password they are allowed to extract content
+ * from the PDF document
+ */
+ public boolean canExtractContent()
+ {
+ return isPermissionBitOn( EXTRACT_BIT );
+ }
+
+ /**
+ * Set if the user can extract content from the document.
+ *
+ * @param allowExtraction A boolean determining if the user can extract content
+ * from the document.
+ */
+ public void setCanExtractContent( boolean allowExtraction )
+ {
+ setPermissionBit( EXTRACT_BIT, allowExtraction );
+ }
+
+ /**
+ * This will tell if the user can add/modify text annotations, fill in interactive forms fields.
+ *
+ * @return true If supplied with the user password they are allowed to modify annotations.
+ */
+ public boolean canModifyAnnotations()
+ {
+ return isPermissionBitOn( MODIFY_ANNOTATIONS_BIT );
+ }
+
+ /**
+ * Set if the user can modify annotations.
+ *
+ * @param allowAnnotationModification A boolean determining if the user can modify annotations.
+ */
+ public void setCanModifyAnnotations( boolean allowAnnotationModification )
+ {
+ setPermissionBit( MODIFY_ANNOTATIONS_BIT, allowAnnotationModification );
+ }
+
+ /**
+ * This will tell if the user can fill in interactive forms.
+ *
+ * @return true If supplied with the user password they are allowed to fill in form fields.
+ */
+ public boolean canFillInForm()
+ {
+ return isPermissionBitOn( FILL_IN_FORM_BIT );
+ }
+
+ /**
+ * Set if the user can fill in interactive forms.
+ *
+ * @param allowFillingInForm A boolean determining if the user can fill in interactive forms.
+ */
+ public void setCanFillInForm( boolean allowFillingInForm )
+ {
+ setPermissionBit( FILL_IN_FORM_BIT, allowFillingInForm );
+ }
+
+ /**
+ * This will tell if the user can extract text and images from the PDF document
+ * for accessibility purposes.
+ *
+ * @return true If supplied with the user password they are allowed to extract content
+ * from the PDF document
+ */
+ public boolean canExtractForAccessibility()
+ {
+ return isPermissionBitOn( EXTRACT_FOR_ACCESSIBILITY_BIT );
+ }
+
+ /**
+ * Set if the user can extract content from the document for accessibility purposes.
+ *
+ * @param allowExtraction A boolean determining if the user can extract content
+ * from the document.
+ */
+ public void setCanExtractForAccessibility( boolean allowExtraction )
+ {
+ setPermissionBit( EXTRACT_FOR_ACCESSIBILITY_BIT, allowExtraction );
+ }
+
+ /**
+ * This will tell if the user can insert/rotate/delete pages.
+ *
+ * @return true If supplied with the user password they are allowed to extract content
+ * from the PDF document
+ */
+ public boolean canAssembleDocument()
+ {
+ return isPermissionBitOn( ASSEMBLE_DOCUMENT_BIT );
+ }
+
+ /**
+ * Set if the user can insert/rotate/delete pages.
+ *
+ * @param allowAssembly A boolean determining if the user can assemble the document.
+ */
+ public void setCanAssembleDocument( boolean allowAssembly )
+ {
+ setPermissionBit( ASSEMBLE_DOCUMENT_BIT, allowAssembly );
+ }
+
+ /**
+ * This will tell if the user can print the document in a degraded format.
+ *
+ * @return true If supplied with the user password they are allowed to print the
+ * document in a degraded format.
+ */
+ public boolean canPrintDegraded()
+ {
+ return isPermissionBitOn( DEGRADED_PRINT_BIT );
+ }
+
+ /**
+ * Set if the user can print the document in a degraded format.
+ *
+ * @param allowAssembly A boolean determining if the user can print the
+ * document in a degraded format.
+ */
+ public void setCanPrintDegraded( boolean allowAssembly )
+ {
+ setPermissionBit( DEGRADED_PRINT_BIT, allowAssembly );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/encryption/package.html b/src/main/java/org/pdfbox/pdmodel/encryption/package.html
new file mode 100644
index 0000000..a458817
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/encryption/package.html
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+
+</head>
+<body>
+The encryption package will handle the PDF document security handlers and the functionality of pluggable security handlers.
+</body>
+</html>
diff --git a/src/main/java/org/pdfbox/pdmodel/fdf/FDFAnnotation.java b/src/main/java/org/pdfbox/pdmodel/fdf/FDFAnnotation.java
new file mode 100644
index 0000000..3d121e7
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/fdf/FDFAnnotation.java
@@ -0,0 +1,114 @@
+/**
+ * Copyright (c) 2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.fdf;
+
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSInteger;
+import org.pdfbox.cos.COSNumber;
+
+import org.pdfbox.pdmodel.common.COSObjectable;
+
+/**
+ * This represents an FDF annotation that is part of the FDF document.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.2 $
+ */
+public class FDFAnnotation implements COSObjectable
+{
+ private COSDictionary annot;
+
+ /**
+ * Default constructor.
+ */
+ public FDFAnnotation()
+ {
+ annot = new COSDictionary();
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param a The FDF annotation.
+ */
+ public FDFAnnotation( COSDictionary a )
+ {
+ annot = a;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSBase getCOSObject()
+ {
+ return annot;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSDictionary getCOSDictionary()
+ {
+ return annot;
+ }
+
+ /**
+ * This will get the page number or null if it does not exist.
+ *
+ * @return The page number.
+ */
+ public Integer getPage()
+ {
+ Integer retval = null;
+ COSNumber page = (COSNumber)annot.getDictionaryObject( "Page" );
+ if( page != null )
+ {
+ retval = new Integer( page.intValue() );
+ }
+ return retval;
+ }
+
+ /**
+ * This will set the page.
+ *
+ * @param page The page number.
+ */
+ public void setPage( int page )
+ {
+ annot.setItem( "Page", new COSInteger( page ) );
+ }
+
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/fdf/FDFCatalog.java b/src/main/java/org/pdfbox/pdmodel/fdf/FDFCatalog.java
new file mode 100644
index 0000000..f6959ee
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/fdf/FDFCatalog.java
@@ -0,0 +1,195 @@
+/**
+ * Copyright (c) 2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.fdf;
+
+import java.io.IOException;
+import java.io.Writer;
+
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSDictionary;
+
+import org.pdfbox.pdmodel.common.COSObjectable;
+
+import org.pdfbox.pdmodel.interactive.digitalsignature.PDSignature;
+
+import org.w3c.dom.Element;
+
+/**
+ * This represents an FDF catalog that is part of the FDF document.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.2 $
+ */
+public class FDFCatalog implements COSObjectable
+{
+ private COSDictionary catalog;
+
+ /**
+ * Default constructor.
+ */
+ public FDFCatalog()
+ {
+ catalog = new COSDictionary();
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param cat The FDF documents catalog.
+ */
+ public FDFCatalog( COSDictionary cat )
+ {
+ catalog = cat;
+ }
+
+ /**
+ * This will create an FDF catalog from an XFDF XML document.
+ *
+ * @param element The XML document that contains the XFDF data.
+ * @throws IOException If there is an error reading from the dom.
+ */
+ public FDFCatalog( Element element ) throws IOException
+ {
+ this();
+ FDFDictionary fdfDict = new FDFDictionary( element );
+ setFDF( fdfDict );
+ }
+
+ /**
+ * This will write this element as an XML document.
+ *
+ * @param output The stream to write the xml to.
+ *
+ * @throws IOException If there is an error writing the XML.
+ */
+ public void writeXML( Writer output ) throws IOException
+ {
+ FDFDictionary fdf = getFDF();
+ fdf.writeXML( output );
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSBase getCOSObject()
+ {
+ return catalog;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSDictionary getCOSDictionary()
+ {
+ return catalog;
+ }
+
+ /**
+ * This will get the version that was specified in the catalog dictionary.
+ *
+ * @return The FDF version.
+ */
+ public String getVersion()
+ {
+ return catalog.getNameAsString( "Version" );
+ }
+
+ /**
+ * This will set the version of the FDF document.
+ *
+ * @param version The new version for the FDF document.
+ */
+ public void setVersion( String version )
+ {
+ catalog.setName( "Version", version );
+ }
+
+ /**
+ * This will get the FDF dictionary.
+ *
+ * @return The FDF dictionary.
+ */
+ public FDFDictionary getFDF()
+ {
+ COSDictionary fdf = (COSDictionary)catalog.getDictionaryObject( "FDF" );
+ FDFDictionary retval = null;
+ if( fdf != null )
+ {
+ retval = new FDFDictionary( fdf );
+ }
+ else
+ {
+ retval = new FDFDictionary();
+ setFDF( retval );
+ }
+ return retval;
+ }
+
+ /**
+ * This will set the FDF document.
+ *
+ * @param fdf The new FDF dictionary.
+ */
+ public void setFDF( FDFDictionary fdf )
+ {
+ catalog.setItem( "FDF", fdf );
+ }
+
+ /**
+ * This will get the signature or null if there is none.
+ *
+ * @return The signature.
+ */
+ public PDSignature getSignature()
+ {
+ PDSignature signature = null;
+ COSDictionary sig = (COSDictionary)catalog.getDictionaryObject( "Sig" );
+ if( sig != null )
+ {
+ signature = new PDSignature( sig );
+ }
+ return signature;
+ }
+
+ /**
+ * This will set the signature that is associated with this catalog.
+ *
+ * @param sig The new signature.
+ */
+ public void setSignature( PDSignature sig )
+ {
+ catalog.setItem( "Sig", sig );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/fdf/FDFDictionary.java b/src/main/java/org/pdfbox/pdmodel/fdf/FDFDictionary.java
new file mode 100644
index 0000000..ab25bc7
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/fdf/FDFDictionary.java
@@ -0,0 +1,465 @@
+/**
+ * Copyright (c) 2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.fdf;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.pdfbox.cos.COSArray;
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSStream;
+import org.pdfbox.cos.COSString;
+
+import org.pdfbox.pdmodel.common.COSObjectable;
+import org.pdfbox.pdmodel.common.COSArrayList;
+import org.pdfbox.pdmodel.common.filespecification.PDFileSpecification;
+import org.pdfbox.pdmodel.common.filespecification.PDSimpleFileSpecification;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+/**
+ * This represents an FDF dictionary that is part of the FDF document.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.6 $
+ */
+public class FDFDictionary implements COSObjectable
+{
+ private COSDictionary fdf;
+
+ /**
+ * Default constructor.
+ */
+ public FDFDictionary()
+ {
+ fdf = new COSDictionary();
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param fdfDictionary The FDF documents catalog.
+ */
+ public FDFDictionary( COSDictionary fdfDictionary )
+ {
+ fdf = fdfDictionary;
+ }
+
+ /**
+ * This will create an FDF dictionary from an XFDF XML document.
+ *
+ * @param fdfXML The XML document that contains the XFDF data.
+ * @throws IOException If there is an error reading from the dom.
+ */
+ public FDFDictionary( Element fdfXML ) throws IOException
+ {
+ this();
+ NodeList nodeList = fdfXML.getChildNodes();
+ for( int i=0; i<nodeList.getLength(); i++ )
+ {
+ Node node = nodeList.item( i );
+ if( node instanceof Element )
+ {
+ Element child = (Element)node;
+ if( child.getTagName().equals( "f" ) )
+ {
+ PDSimpleFileSpecification fs = new PDSimpleFileSpecification();
+ fs.setFile( child.getAttribute( "href" ) );
+
+ }
+ else if( child.getTagName().equals( "ids" ) )
+ {
+ COSArray ids = new COSArray();
+ String original = child.getAttribute( "original" );
+ String modified = child.getAttribute( "modified" );
+ ids.add( COSString.createFromHexString( original ) );
+ ids.add( COSString.createFromHexString( modified ) );
+ setID( ids );
+ }
+ else if( child.getTagName().equals( "fields" ) )
+ {
+ NodeList fields = child.getElementsByTagName( "field" );
+ List fieldList = new ArrayList();
+ for( int f=0; f<fields.getLength(); f++ )
+ {
+ fieldList.add( new FDFField( (Element)fields.item( f ) ) );
+ }
+ setFields( fieldList );
+ }
+ }
+ }
+ }
+
+ /**
+ * This will write this element as an XML document.
+ *
+ * @param output The stream to write the xml to.
+ *
+ * @throws IOException If there is an error writing the XML.
+ */
+ public void writeXML( Writer output ) throws IOException
+ {
+ PDFileSpecification fs = this.getFile();
+ if( fs != null )
+ {
+ output.write( "<f href=\"" + fs.getFile() + "\" />\n" );
+ }
+ COSArray ids = this.getID();
+ if( ids != null )
+ {
+ COSString original = (COSString)ids.getObject( 0 );
+ COSString modified = (COSString)ids.getObject( 1 );
+ output.write( "<ids original=\"" + original.getHexString() + "\" " );
+ output.write( "modified=\"" + modified.getHexString() + "\" />\n");
+ }
+ List fields = getFields();
+ if( fields != null && fields.size() > 0 )
+ {
+ output.write( "<fields>\n" );
+ for( int i=0; i<fields.size(); i++ )
+ {
+ ((FDFField)fields.get( i )).writeXML( output );
+ }
+ output.write( "</fields>\n" );
+ }
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSBase getCOSObject()
+ {
+ return fdf;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSDictionary getCOSDictionary()
+ {
+ return fdf;
+ }
+
+ /**
+ * The source file or target file: the PDF document file that
+ * this FDF file was exported from or is intended to be imported into.
+ *
+ * @return The F entry of the FDF dictionary.
+ */
+ public PDFileSpecification getFile()
+ {
+ return PDFileSpecification.createFS( fdf.getDictionaryObject( "F" ) );
+ }
+
+ /**
+ * This will set the file specification.
+ *
+ * @param fs The file specification.
+ */
+ public void setFile( PDFileSpecification fs )
+ {
+ fdf.setItem( "F", fs );
+ }
+
+ /**
+ * This is the FDF id.
+ *
+ * @return The FDF ID.
+ */
+ public COSArray getID()
+ {
+ return (COSArray)fdf.getDictionaryObject( "ID" );
+ }
+
+ /**
+ * This will set the FDF id.
+ *
+ * @param id The new id for the FDF.
+ */
+ public void setID( COSArray id )
+ {
+ fdf.setItem( "ID", id );
+ }
+
+ /**
+ * This will get the list of FDF Fields. This will return a list of FDFField
+ * objects.
+ *
+ * @return A list of FDF fields.
+ */
+ public List getFields()
+ {
+ List retval = null;
+ COSArray fieldArray = (COSArray)fdf.getDictionaryObject( "Fields" );
+ if( fieldArray != null )
+ {
+ List fields = new ArrayList();
+ for( int i=0; i<fieldArray.size(); i++ )
+ {
+ fields.add( new FDFField( (COSDictionary)fieldArray.getObject( i ) ) );
+ }
+ retval = new COSArrayList( fields, fieldArray );
+ }
+ return retval;
+ }
+
+ /**
+ * This will set the list of fields. This should be a list of FDFField objects.
+ *
+ * @param fields The list of fields.
+ */
+ public void setFields( List fields )
+ {
+ fdf.setItem( "Fields", COSArrayList.converterToCOSArray( fields ) );
+ }
+
+ /**
+ * This will get the status string to be displayed as the result of an
+ * action.
+ *
+ * @return The status.
+ */
+ public String getStatus()
+ {
+ return fdf.getString( "Status" );
+ }
+
+ /**
+ * This will set the status string.
+ *
+ * @param status The new status string.
+ */
+ public void setStatus( String status )
+ {
+ fdf.setString( "Status", status );
+ }
+
+ /**
+ * This will get the list of FDF Pages. This will return a list of FDFPage objects.
+ *
+ * @return A list of FDF pages.
+ */
+ public List getPages()
+ {
+ List retval = null;
+ COSArray pageArray = (COSArray)fdf.getDictionaryObject( "Pages" );
+ if( pageArray != null )
+ {
+ List pages = new ArrayList();
+ for( int i=0; i<pageArray.size(); i++ )
+ {
+ pages.add( new FDFPage( (COSDictionary)pageArray.get( i ) ) );
+ }
+ retval = new COSArrayList( pages, pageArray );
+ }
+ return retval;
+ }
+
+ /**
+ * This will set the list of pages. This should be a list of FDFPage objects.
+ *
+ *
+ * @param pages The list of pages.
+ */
+ public void setPages( List pages )
+ {
+ fdf.setItem( "Pages", COSArrayList.converterToCOSArray( pages ) );
+ }
+
+ /**
+ * The encoding to be used for a FDF field. The default is PDFDocEncoding
+ * and this method will never return null.
+ *
+ * @return The encoding value.
+ */
+ public String getEncoding()
+ {
+ String encoding = fdf.getNameAsString( "Encoding" );
+ if( encoding == null )
+ {
+ encoding = "PDFDocEncoding";
+ }
+ return encoding;
+
+ }
+
+ /**
+ * This will set the encoding.
+ *
+ * @param encoding The new encoding.
+ */
+ public void setEncoding( String encoding )
+ {
+ fdf.setName( "Encoding", encoding );
+ }
+
+ /**
+ * This will get the list of FDF Annotations. This will return a list of FDFAnnotation objects
+ * or null if the entry is not set.
+ *
+ * @return A list of FDF annotations.
+ */
+ public List getAnnotations()
+ {
+ List retval = null;
+ COSArray annotArray = (COSArray)fdf.getDictionaryObject( "Annots" );
+ if( annotArray != null )
+ {
+ List annots = new ArrayList();
+ for( int i=0; i<annotArray.size(); i++ )
+ {
+ annots.add( new FDFAnnotation( (COSDictionary)annotArray.getObject( i ) ) );
+ }
+ retval = new COSArrayList( annots, annotArray );
+ }
+ return retval;
+ }
+
+ /**
+ * This will set the list of annotations. This should be a list of FDFAnnotation objects.
+ *
+ *
+ * @param annots The list of annotations.
+ */
+ public void setAnnotations( List annots )
+ {
+ fdf.setItem( "Annots", COSArrayList.converterToCOSArray( annots ) );
+ }
+
+ /**
+ * This will get the incremental updates since the PDF was last opened.
+ *
+ * @return The differences entry of the FDF dictionary.
+ */
+ public COSStream getDifferences()
+ {
+ return (COSStream)fdf.getDictionaryObject( "Differences" );
+ }
+
+ /**
+ * This will set the differences stream.
+ *
+ * @param diff The new differences stream.
+ */
+ public void setDifferences( COSStream diff )
+ {
+ fdf.setItem( "Differences", diff );
+ }
+
+ /**
+ * This will get the target frame in the browser to open this document.
+ *
+ * @return The target frame.
+ */
+ public String getTarget()
+ {
+ return fdf.getString( "Target" );
+ }
+
+ /**
+ * This will set the target frame in the browser to open this document.
+ *
+ * @param target The new target frame.
+ */
+ public void setTarget( String target )
+ {
+ fdf.setString( "Target", target );
+ }
+
+ /**
+ * This will get the list of embedded FDF entries, or null if the entry is null.
+ * This will return a list of PDFileSpecification objects.
+ *
+ * @return A list of embedded FDF files.
+ */
+ public List getEmbeddedFDFs()
+ {
+ List retval = null;
+ COSArray embeddedArray = (COSArray)fdf.getDictionaryObject( "EmbeddedFDFs" );
+ if( embeddedArray != null )
+ {
+ List embedded = new ArrayList();
+ for( int i=0; i<embeddedArray.size(); i++ )
+ {
+ embedded.add( PDFileSpecification.createFS( embeddedArray.get( i ) ) );
+ }
+ retval = new COSArrayList( embedded, embeddedArray );
+ }
+ return retval;
+ }
+
+ /**
+ * This will set the list of embedded FDFs. This should be a list of
+ * PDFileSpecification objects.
+ *
+ *
+ * @param embedded The list of embedded FDFs.
+ */
+ public void setEmbeddedFDFs( List embedded )
+ {
+ fdf.setItem( "EmbeddedFDFs", COSArrayList.converterToCOSArray( embedded ) );
+ }
+
+ /**
+ * This will get the java script entry.
+ *
+ * @return The java script entry describing javascript commands.
+ */
+ public FDFJavaScript getJavaScript()
+ {
+ FDFJavaScript fs = null;
+ COSDictionary dic = (COSDictionary)fdf.getDictionaryObject( "JavaScript" );
+ if( dic != null )
+ {
+ fs = new FDFJavaScript( dic );
+ }
+ return fs;
+ }
+
+ /**
+ * This will set the JavaScript entry.
+ *
+ * @param js The javascript entries.
+ */
+ public void setJavaScript( FDFJavaScript js )
+ {
+ fdf.setItem( "JavaScript", js );
+ }
+
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/fdf/FDFDocument.java b/src/main/java/org/pdfbox/pdmodel/fdf/FDFDocument.java
new file mode 100644
index 0000000..8350314
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/fdf/FDFDocument.java
@@ -0,0 +1,377 @@
+/**
+ * Copyright (c) 2004-2005, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.fdf;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FileWriter;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.Writer;
+
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSDocument;
+import org.pdfbox.cos.COSName;
+
+import org.pdfbox.exceptions.COSVisitorException;
+
+import org.pdfbox.pdfparser.PDFParser;
+
+import org.pdfbox.pdfwriter.COSWriter;
+
+import org.pdfbox.util.XMLUtil;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+/**
+ * This is the in-memory representation of the FDF document. You need to call
+ * close() on this object when you are done using it!!
+ *
+ * @author Ben Litchfield (ben@benlitchfield.com)
+ * @version $Revision: 1.5 $
+ */
+public class FDFDocument
+{
+ private COSDocument document;
+
+ /**
+ * Constructor, creates a new FDF document.
+ *
+ * @throws IOException If there is an error creating this document.
+ */
+ public FDFDocument() throws IOException
+ {
+ document = new COSDocument();
+ document.setHeaderString( "%FDF-1.2" );
+
+ //First we need a trailer
+ document.setTrailer( new COSDictionary() );
+
+ //Next we need the root dictionary.
+ FDFCatalog catalog = new FDFCatalog();
+ setCatalog( catalog );
+ }
+
+ /**
+ * Constructor that uses an existing document. The COSDocument that
+ * is passed in must be valid.
+ *
+ * @param doc The COSDocument that this document wraps.
+ */
+ public FDFDocument( COSDocument doc )
+ {
+ document = doc;
+ }
+
+ /**
+ * This will create an FDF document from an XFDF XML document.
+ *
+ * @param doc The XML document that contains the XFDF data.
+ * @throws IOException If there is an error reading from the dom.
+ */
+ public FDFDocument( Document doc ) throws IOException
+ {
+ this();
+ Element xfdf = doc.getDocumentElement();
+ if( !xfdf.getNodeName().equals( "xfdf" ) )
+ {
+ throw new IOException( "Error while importing xfdf document, " +
+ "root should be 'xfdf' and not '" + xfdf.getNodeName() + "'" );
+ }
+ FDFCatalog cat = new FDFCatalog( xfdf );
+ setCatalog( cat );
+ }
+
+ /**
+ * This will write this element as an XML document.
+ *
+ * @param output The stream to write the xml to.
+ *
+ * @throws IOException If there is an error writing the XML.
+ */
+ public void writeXML( Writer output ) throws IOException
+ {
+ output.write( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" );
+ output.write( "<xfdf xmlns=\"http://ns.adobe.com/xfdf/\" xml:space=\"preserve\">\n" );
+
+ getCatalog().writeXML( output );
+
+ output.write( "</xfdf>\n" );
+ }
+
+
+
+ /**
+ * This will get the low level document.
+ *
+ * @return The document that this layer sits on top of.
+ */
+ public COSDocument getDocument()
+ {
+ return document;
+ }
+
+ /**
+ * This will get the FDF Catalog. This is guaranteed to not return null.
+ *
+ * @return The documents /Root dictionary
+ */
+ public FDFCatalog getCatalog()
+ {
+ FDFCatalog retval = null;
+ COSDictionary trailer = document.getTrailer();
+ COSDictionary root = (COSDictionary)trailer.getDictionaryObject( COSName.ROOT );
+ if( root == null )
+ {
+ retval = new FDFCatalog();
+ setCatalog( retval );
+ }
+ else
+ {
+ retval = new FDFCatalog( root );
+ }
+ return retval;
+ }
+
+ /**
+ * This will set the FDF catalog for this FDF document.
+ *
+ * @param cat The FDF catalog.
+ */
+ public void setCatalog( FDFCatalog cat )
+ {
+ COSDictionary trailer = document.getTrailer();
+ trailer.setItem( COSName.ROOT, cat );
+ }
+
+ /**
+ * This will load a document from a file.
+ *
+ * @param filename The name of the file to load.
+ *
+ * @return The document that was loaded.
+ *
+ * @throws IOException If there is an error reading from the stream.
+ */
+ public static FDFDocument load( String filename ) throws IOException
+ {
+ return load( new BufferedInputStream( new FileInputStream( filename ) ) );
+ }
+
+ /**
+ * This will load a document from a file.
+ *
+ * @param file The name of the file to load.
+ *
+ * @return The document that was loaded.
+ *
+ * @throws IOException If there is an error reading from the stream.
+ */
+ public static FDFDocument load( File file ) throws IOException
+ {
+ return load( new BufferedInputStream( new FileInputStream( file ) ) );
+ }
+
+ /**
+ * This will load a document from an input stream.
+ *
+ * @param input The stream that contains the document.
+ *
+ * @return The document that was loaded.
+ *
+ * @throws IOException If there is an error reading from the stream.
+ */
+ public static FDFDocument load( InputStream input ) throws IOException
+ {
+ PDFParser parser = new PDFParser( input );
+ parser.parse();
+ return parser.getFDFDocument();
+ }
+
+ /**
+ * This will load a document from a file.
+ *
+ * @param filename The name of the file to load.
+ *
+ * @return The document that was loaded.
+ *
+ * @throws IOException If there is an error reading from the stream.
+ */
+ public static FDFDocument loadXFDF( String filename ) throws IOException
+ {
+ return loadXFDF( new BufferedInputStream( new FileInputStream( filename ) ) );
+ }
+
+ /**
+ * This will load a document from a file.
+ *
+ * @param file The name of the file to load.
+ *
+ * @return The document that was loaded.
+ *
+ * @throws IOException If there is an error reading from the stream.
+ */
+ public static FDFDocument loadXFDF( File file ) throws IOException
+ {
+ return loadXFDF( new BufferedInputStream( new FileInputStream( file ) ) );
+ }
+
+ /**
+ * This will load a document from an input stream.
+ *
+ * @param input The stream that contains the document.
+ *
+ * @return The document that was loaded.
+ *
+ * @throws IOException If there is an error reading from the stream.
+ */
+ public static FDFDocument loadXFDF( InputStream input ) throws IOException
+ {
+ Document doc = XMLUtil.parse( input );
+ return new FDFDocument( doc );
+ }
+
+ /**
+ * This will save this document to the filesystem.
+ *
+ * @param fileName The file to save as.
+ *
+ * @throws IOException If there is an error saving the document.
+ * @throws COSVisitorException If an error occurs while generating the data.
+ */
+ public void save( File fileName ) throws IOException, COSVisitorException
+ {
+ save( new FileOutputStream( fileName ) );
+ }
+
+ /**
+ * This will save this document to the filesystem.
+ *
+ * @param fileName The file to save as.
+ *
+ * @throws IOException If there is an error saving the document.
+ * @throws COSVisitorException If an error occurs while generating the data.
+ */
+ public void save( String fileName ) throws IOException, COSVisitorException
+ {
+ save( new FileOutputStream( fileName ) );
+ }
+
+ /**
+ * This will save the document to an output stream.
+ *
+ * @param output The stream to write to.
+ *
+ * @throws IOException If there is an error writing the document.
+ * @throws COSVisitorException If an error occurs while generating the data.
+ */
+ public void save( OutputStream output ) throws IOException, COSVisitorException
+ {
+ COSWriter writer = null;
+ try
+ {
+ writer = new COSWriter( output );
+ writer.write( document );
+ writer.close();
+ }
+ finally
+ {
+ if( writer != null )
+ {
+ writer.close();
+ }
+ }
+ }
+
+ /**
+ * This will save this document to the filesystem.
+ *
+ * @param fileName The file to save as.
+ *
+ * @throws IOException If there is an error saving the document.
+ * @throws COSVisitorException If an error occurs while generating the data.
+ */
+ public void saveXFDF( File fileName ) throws IOException, COSVisitorException
+ {
+ saveXFDF( new BufferedWriter( new FileWriter( fileName ) ) );
+ }
+
+ /**
+ * This will save this document to the filesystem.
+ *
+ * @param fileName The file to save as.
+ *
+ * @throws IOException If there is an error saving the document.
+ * @throws COSVisitorException If an error occurs while generating the data.
+ */
+ public void saveXFDF( String fileName ) throws IOException, COSVisitorException
+ {
+ saveXFDF( new BufferedWriter( new FileWriter( fileName ) ) );
+ }
+
+ /**
+ * This will save the document to an output stream and close the stream.
+ *
+ * @param output The stream to write to.
+ *
+ * @throws IOException If there is an error writing the document.
+ * @throws COSVisitorException If an error occurs while generating the data.
+ */
+ public void saveXFDF( Writer output ) throws IOException, COSVisitorException
+ {
+ try
+ {
+ writeXML( output );
+ }
+ finally
+ {
+ if( output != null )
+ {
+ output.close();
+ }
+ }
+ }
+
+ /**
+ * This will close the underlying COSDocument object.
+ *
+ * @throws IOException If there is an error releasing resources.
+ */
+ public void close() throws IOException
+ {
+ document.close();
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/fdf/FDFField.java b/src/main/java/org/pdfbox/pdmodel/fdf/FDFField.java
new file mode 100644
index 0000000..35b90ed
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/fdf/FDFField.java
@@ -0,0 +1,763 @@
+/**
+ * Copyright (c) 2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.fdf;
+
+import java.io.IOException;
+import java.io.Writer;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.pdfbox.cos.COSArray;
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSInteger;
+import org.pdfbox.cos.COSName;
+import org.pdfbox.cos.COSNumber;
+import org.pdfbox.cos.COSStream;
+import org.pdfbox.cos.COSString;
+
+import org.pdfbox.pdmodel.common.COSObjectable;
+import org.pdfbox.pdmodel.common.COSArrayList;
+import org.pdfbox.pdmodel.common.PDTextStream;
+
+import org.pdfbox.pdmodel.interactive.action.PDActionFactory;
+import org.pdfbox.pdmodel.interactive.action.PDAdditionalActions;
+import org.pdfbox.pdmodel.interactive.action.type.PDAction;
+
+import org.pdfbox.pdmodel.interactive.annotation.PDAppearanceDictionary;
+
+import org.pdfbox.util.XMLUtil;
+
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+/**
+ * This represents an FDF field that is part of the FDF document.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.4 $
+ */
+public class FDFField implements COSObjectable
+{
+ private COSDictionary field;
+
+ /**
+ * Default constructor.
+ */
+ public FDFField()
+ {
+ field = new COSDictionary();
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param f The FDF field.
+ */
+ public FDFField( COSDictionary f )
+ {
+ field = f;
+ }
+
+ /**
+ * This will create an FDF field from an XFDF XML document.
+ *
+ * @param fieldXML The XML document that contains the XFDF data.
+ * @throws IOException If there is an error reading from the dom.
+ */
+ public FDFField( Element fieldXML ) throws IOException
+ {
+ this();
+ this.setPartialFieldName( fieldXML.getAttribute( "name" ) );
+ NodeList nodeList = fieldXML.getChildNodes();
+ List kids = new ArrayList();
+ for( int i=0; i<nodeList.getLength(); i++ )
+ {
+ Node node = nodeList.item( i );
+ if( node instanceof Element )
+ {
+ Element child = (Element)node;
+ if( child.getTagName().equals( "value" ) )
+ {
+ setValue( XMLUtil.getNodeValue( child ) );
+ }
+ else if( child.getTagName().equals( "value-richtext" ) )
+ {
+ setRichText( new PDTextStream( XMLUtil.getNodeValue( child ) ) );
+ }
+ else if( child.getTagName().equals( "field" ) )
+ {
+ kids.add( new FDFField( child ) );
+ }
+ }
+ }
+ if( kids.size() > 0 )
+ {
+ setKids( kids );
+ }
+
+ }
+
+ /**
+ * This will write this element as an XML document.
+ *
+ * @param output The stream to write the xml to.
+ *
+ * @throws IOException If there is an error writing the XML.
+ */
+ public void writeXML( Writer output ) throws IOException
+ {
+ output.write( "<field name=\"" + getPartialFieldName() + "\">\n");
+ Object value = getValue();
+ if( value != null )
+ {
+ output.write( "<value>" + value + "</value>\n" );
+ }
+ PDTextStream rt = getRichText();
+ if( rt != null )
+ {
+ output.write( "<value-richtext>" + rt.getAsString() + "</value-richtext>\n" );
+ }
+ List kids = getKids();
+ if( kids != null )
+ {
+ for( int i=0; i<kids.size(); i++ )
+ {
+ ((FDFField)kids.get( i ) ).writeXML( output );
+ }
+ }
+ output.write( "</field>\n");
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSBase getCOSObject()
+ {
+ return field;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSDictionary getCOSDictionary()
+ {
+ return field;
+ }
+
+ /**
+ * This will get the list of kids. This will return a list of FDFField objects.
+ * This will return null if the underlying list is null.
+ *
+ * @return The list of kids.
+ */
+ public List getKids()
+ {
+ COSArray kids = (COSArray)field.getDictionaryObject( "Kids" );
+ List retval = null;
+ if( kids != null )
+ {
+ List actuals = new ArrayList();
+ for( int i=0; i<kids.size(); i++ )
+ {
+ actuals.add( new FDFField( (COSDictionary)kids.getObject( i ) ) );
+ }
+ retval = new COSArrayList( actuals, kids );
+ }
+ return retval;
+ }
+
+ /**
+ * This will set the list of kids.
+ *
+ * @param kids A list of FDFField objects.
+ */
+ public void setKids( List kids )
+ {
+ field.setItem( "Kids", COSArrayList.converterToCOSArray( kids ) );
+ }
+
+ /**
+ * This will get the "T" entry in the field dictionary. A partial field
+ * name. Where the fully qualified field name is a concatenation of
+ * the parent's fully qualified field name and "." as a separator. For example<br/>
+ * Address.State<br />
+ * Address.City<br />
+ *
+ * @return The partial field name.
+ */
+ public String getPartialFieldName()
+ {
+ return field.getString( "T" );
+ }
+
+ /**
+ * This will set the partial field name.
+ *
+ * @param partial The partial field name.
+ */
+ public void setPartialFieldName( String partial )
+ {
+ field.setString( "T", partial );
+ }
+
+ /**
+ * This will set the value for the field. This will return type will either be <br />
+ * String : Checkboxes, Radio Button <br />
+ * java.util.List of strings: Choice Field
+ * PDTextStream: Textfields
+ *
+ * @return The value of the field.
+ *
+ * @throws IOException If there is an error getting the value.
+ */
+ public Object getValue() throws IOException
+ {
+ Object retval = null;
+ COSBase value = field.getDictionaryObject( "V" );
+ if( value instanceof COSName )
+ {
+ retval = ((COSName)value).getName();
+ }
+ else if( value instanceof COSArray )
+ {
+ retval = COSArrayList.convertCOSStringCOSArrayToList( (COSArray)value );
+ }
+ else if( value instanceof COSString || value instanceof COSStream )
+ {
+ retval = PDTextStream.createTextStream( value );
+ }
+ else if( value == null )
+ {
+ //Ok, value is null so do nothing
+ }
+ else
+ {
+ throw new IOException( "Error:Unknown type for field import" + value );
+ }
+ return retval;
+ }
+
+ /**
+ * You should pass in a string, or a java.util.List of strings to set the
+ * value.
+ *
+ * @param value The value that should populate when imported.
+ *
+ * @throws IOException If there is an error setting the value.
+ */
+ public void setValue( Object value ) throws IOException
+ {
+ COSBase cos = null;
+ if( value instanceof List )
+ {
+ cos = COSArrayList.convertStringListToCOSStringCOSArray( (List)value );
+ }
+ else if( value instanceof String )
+ {
+ cos = COSName.getPDFName( (String)value );
+ }
+ else if( value instanceof COSObjectable )
+ {
+ cos = ((COSObjectable)value).getCOSObject();
+ }
+ else if( value == null )
+ {
+ //do nothing and let cos remain null as well.
+ }
+ else
+ {
+ throw new IOException( "Error:Unknown type for field import" + value );
+ }
+ field.setItem( "V", cos );
+ }
+
+ /**
+ * This will get the Ff entry of the cos dictionary. If it it not present then
+ * this method will return null.
+ *
+ * @return The field flags.
+ */
+ public Integer getFieldFlags()
+ {
+ Integer retval = null;
+ COSNumber ff = (COSNumber)field.getDictionaryObject( "Ff" );
+ if( ff != null )
+ {
+ retval = new Integer( ff.intValue() );
+ }
+ return retval;
+ }
+
+ /**
+ * This will get the field flags that are associated with this field. The Ff entry
+ * in the FDF field dictionary.
+ *
+ * @param ff The new value for the field flags.
+ */
+ public void setFieldFlags( Integer ff )
+ {
+ COSInteger value = null;
+ if( ff != null )
+ {
+ value = new COSInteger( ff.intValue() );
+ }
+ field.setItem( "Ff", value );
+ }
+
+ /**
+ * This will get the field flags that are associated with this field. The Ff entry
+ * in the FDF field dictionary.
+ *
+ * @param ff The new value for the field flags.
+ */
+ public void setFieldFlags( int ff )
+ {
+ field.setItem( "Ff", new COSInteger( ff ) );
+ }
+
+ /**
+ * This will get the SetFf entry of the cos dictionary. If it it not present then
+ * this method will return null.
+ *
+ * @return The field flags.
+ */
+ public Integer getSetFieldFlags()
+ {
+ Integer retval = null;
+ COSNumber ff = (COSNumber)field.getDictionaryObject( "SetFf" );
+ if( ff != null )
+ {
+ retval = new Integer( ff.intValue() );
+ }
+ return retval;
+ }
+
+ /**
+ * This will get the field flags that are associated with this field. The SetFf entry
+ * in the FDF field dictionary.
+ *
+ * @param ff The new value for the "set field flags".
+ */
+ public void setSetFieldFlags( Integer ff )
+ {
+ COSInteger value = null;
+ if( ff != null )
+ {
+ value = new COSInteger( ff.intValue() );
+ }
+ field.setItem( "SetFf", value );
+ }
+
+ /**
+ * This will get the field flags that are associated with this field. The SetFf entry
+ * in the FDF field dictionary.
+ *
+ * @param ff The new value for the "set field flags".
+ */
+ public void setSetFieldFlags( int ff )
+ {
+ field.setItem( "SetFf", new COSInteger( ff ) );
+ }
+
+ /**
+ * This will get the ClrFf entry of the cos dictionary. If it it not present then
+ * this method will return null.
+ *
+ * @return The field flags.
+ */
+ public Integer getClearFieldFlags()
+ {
+ Integer retval = null;
+ COSNumber ff = (COSNumber)field.getDictionaryObject( "ClrFf" );
+ if( ff != null )
+ {
+ retval = new Integer( ff.intValue() );
+ }
+ return retval;
+ }
+
+ /**
+ * This will get the field flags that are associated with this field. The ClrFf entry
+ * in the FDF field dictionary.
+ *
+ * @param ff The new value for the "clear field flags".
+ */
+ public void setClearFieldFlags( Integer ff )
+ {
+ COSInteger value = null;
+ if( ff != null )
+ {
+ value = new COSInteger( ff.intValue() );
+ }
+ field.setItem( "ClrFf", value );
+ }
+
+ /**
+ * This will get the field flags that are associated with this field. The ClrFf entry
+ * in the FDF field dictionary.
+ *
+ * @param ff The new value for the "clear field flags".
+ */
+ public void setClearFieldFlags( int ff )
+ {
+ field.setItem( "ClrFf", new COSInteger( ff ) );
+ }
+
+ /**
+ * This will get the F entry of the cos dictionary. If it it not present then
+ * this method will return null.
+ *
+ * @return The widget field flags.
+ */
+ public Integer getWidgetFieldFlags()
+ {
+ Integer retval = null;
+ COSNumber f = (COSNumber)field.getDictionaryObject( "F" );
+ if( f != null )
+ {
+ retval = new Integer( f.intValue() );
+ }
+ return retval;
+ }
+
+ /**
+ * This will get the widget field flags that are associated with this field. The F entry
+ * in the FDF field dictionary.
+ *
+ * @param f The new value for the field flags.
+ */
+ public void setWidgetFieldFlags( Integer f )
+ {
+ COSInteger value = null;
+ if( f != null )
+ {
+ value = new COSInteger( f.intValue() );
+ }
+ field.setItem( "F", value );
+ }
+
+ /**
+ * This will get the field flags that are associated with this field. The F entry
+ * in the FDF field dictionary.
+ *
+ * @param f The new value for the field flags.
+ */
+ public void setWidgetFieldFlags( int f )
+ {
+ field.setItem( "F", new COSInteger( f ) );
+ }
+
+ /**
+ * This will get the SetF entry of the cos dictionary. If it it not present then
+ * this method will return null.
+ *
+ * @return The field flags.
+ */
+ public Integer getSetWidgetFieldFlags()
+ {
+ Integer retval = null;
+ COSNumber ff = (COSNumber)field.getDictionaryObject( "SetF" );
+ if( ff != null )
+ {
+ retval = new Integer( ff.intValue() );
+ }
+ return retval;
+ }
+
+ /**
+ * This will get the widget field flags that are associated with this field. The SetF entry
+ * in the FDF field dictionary.
+ *
+ * @param ff The new value for the "set widget field flags".
+ */
+ public void setSetWidgetFieldFlags( Integer ff )
+ {
+ COSInteger value = null;
+ if( ff != null )
+ {
+ value = new COSInteger( ff.intValue() );
+ }
+ field.setItem( "SetF", value );
+ }
+
+ /**
+ * This will get the widget field flags that are associated with this field. The SetF entry
+ * in the FDF field dictionary.
+ *
+ * @param ff The new value for the "set widget field flags".
+ */
+ public void setSetWidgetFieldFlags( int ff )
+ {
+ field.setItem( "SetF", new COSInteger( ff ) );
+ }
+
+ /**
+ * This will get the ClrF entry of the cos dictionary. If it it not present then
+ * this method will return null.
+ *
+ * @return The widget field flags.
+ */
+ public Integer getClearWidgetFieldFlags()
+ {
+ Integer retval = null;
+ COSNumber ff = (COSNumber)field.getDictionaryObject( "ClrF" );
+ if( ff != null )
+ {
+ retval = new Integer( ff.intValue() );
+ }
+ return retval;
+ }
+
+ /**
+ * This will get the field flags that are associated with this field. The ClrF entry
+ * in the FDF field dictionary.
+ *
+ * @param ff The new value for the "clear widget field flags".
+ */
+ public void setClearWidgetFieldFlags( Integer ff )
+ {
+ COSInteger value = null;
+ if( ff != null )
+ {
+ value = new COSInteger( ff.intValue() );
+ }
+ field.setItem( "ClrF", value );
+ }
+
+ /**
+ * This will get the field flags that are associated with this field. The ClrF entry
+ * in the FDF field dictionary.
+ *
+ * @param ff The new value for the "clear field flags".
+ */
+ public void setClearWidgetFieldFlags( int ff )
+ {
+ field.setItem( "ClrF", new COSInteger( ff ) );
+ }
+
+ /**
+ * This will get the appearance dictionary that specifies the appearance of
+ * a pushbutton field.
+ *
+ * @return The AP entry of this dictionary.
+ */
+ public PDAppearanceDictionary getAppearanceDictionary()
+ {
+ PDAppearanceDictionary retval = null;
+ COSDictionary dict = (COSDictionary)field.getDictionaryObject( "AP" );
+ if( dict != null )
+ {
+ retval = new PDAppearanceDictionary( dict );
+ }
+ return retval;
+ }
+
+ /**
+ * This will set the appearance dictionary.
+ *
+ * @param ap The apperance dictionary.
+ */
+ public void setAppearanceDictionary( PDAppearanceDictionary ap )
+ {
+ field.setItem( "AP", ap );
+ }
+
+ /**
+ * This will get named page references..
+ *
+ * @return The named page references.
+ */
+ public FDFNamedPageReference getAppearanceStreamReference()
+ {
+ FDFNamedPageReference retval = null;
+ COSDictionary ref = (COSDictionary)field.getDictionaryObject( "APRef" );
+ if( ref != null )
+ {
+ retval = new FDFNamedPageReference( ref );
+ }
+ return retval;
+ }
+
+ /**
+ * This will set the named page references.
+ *
+ * @param ref The named page references.
+ */
+ public void setAppearanceStreamReference( FDFNamedPageReference ref )
+ {
+ field.setItem( "APRef", ref );
+ }
+
+ /**
+ * This will get the icon fit that is associated with this field.
+ *
+ * @return The IF entry.
+ */
+ public FDFIconFit getIconFit()
+ {
+ FDFIconFit retval = null;
+ COSDictionary dic = (COSDictionary)field.getDictionaryObject( "IF" );
+ if( dic != null )
+ {
+ retval = new FDFIconFit( dic );
+ }
+ return retval;
+ }
+
+ /**
+ * This will set the icon fit entry.
+ *
+ * @param fit The icon fit object.
+ */
+ public void setIconFit( FDFIconFit fit )
+ {
+ field.setItem( "IF", fit );
+ }
+
+ /**
+ * This will return a list of options for a choice field. The value in the
+ * list will be 1 of 2 types. java.lang.String or FDFOptionElement.
+ *
+ * @return A list of all options.
+ */
+ public List getOptions()
+ {
+ List retval = null;
+ COSArray array = (COSArray)field.getDictionaryObject( "Opt" );
+ if( array != null )
+ {
+ List objects = new ArrayList();
+ for( int i=0; i<array.size(); i++ )
+ {
+ COSBase next = array.getObject( i );
+ if( next instanceof COSString )
+ {
+ objects.add( ((COSString)next).getString() );
+ }
+ else
+ {
+ COSArray value = (COSArray)next;
+ objects.add( new FDFOptionElement( value ) );
+ }
+ }
+ retval = new COSArrayList( objects, array );
+ }
+ return retval;
+ }
+
+ /**
+ * This will set the options for the choice field. The objects in the list
+ * should either be java.lang.String or FDFOptionElement.
+ *
+ * @param options The options to set.
+ */
+ public void setOptions( List options )
+ {
+ COSArray value = COSArrayList.converterToCOSArray( options );
+ field.setItem( "Opt", value );
+ }
+
+ /**
+ * This will get the action that is associated with this field.
+ *
+ * @return The A entry in the field dictionary.
+ */
+ public PDAction getAction()
+ {
+ return PDActionFactory.createAction( (COSDictionary)field.getDictionaryObject( "A" ) );
+ }
+
+ /**
+ * This will set the action that is associated with this field.
+ *
+ * @param a The new action.
+ */
+ public void setAction( PDAction a )
+ {
+ field.setItem( "A", a );
+ }
+
+ /**
+ * This will get a list of additional actions that will get executed based
+ * on events.
+ *
+ * @return The AA entry in this field dictionary.
+ */
+ public PDAdditionalActions getAdditionalActions()
+ {
+ PDAdditionalActions retval = null;
+ COSDictionary dict = (COSDictionary)field.getDictionaryObject( "AA" );
+ if( dict != null )
+ {
+ retval = new PDAdditionalActions( dict );
+ }
+
+ return retval;
+ }
+
+ /**
+ * This will set the additional actions that are associated with this field.
+ *
+ * @param aa The additional actions.
+ */
+ public void setAdditionalActions( PDAdditionalActions aa )
+ {
+ field.setItem( "AA", aa );
+ }
+
+ /**
+ * This will set the rich text that is associated with this field.
+ *
+ * @return The rich text XHTML stream.
+ */
+ public PDTextStream getRichText()
+ {
+ COSBase rv = field.getDictionaryObject( "RV" );
+ return PDTextStream.createTextStream( rv );
+ }
+
+ /**
+ * This will set the rich text value.
+ *
+ * @param rv The rich text value for the stream.
+ */
+ public void setRichText( PDTextStream rv )
+ {
+ field.setItem( "RV", rv );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/fdf/FDFIconFit.java b/src/main/java/org/pdfbox/pdmodel/fdf/FDFIconFit.java
new file mode 100644
index 0000000..c765bfc
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/fdf/FDFIconFit.java
@@ -0,0 +1,227 @@
+/**
+ * Copyright (c) 2004-2005, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.fdf;
+
+import org.pdfbox.cos.COSArray;
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSDictionary;
+
+import org.pdfbox.pdmodel.common.COSObjectable;
+import org.pdfbox.pdmodel.common.PDRange;
+
+/**
+ * This represents an Icon fit dictionary for an FDF field.
+ *
+ * @author Ben Litchfield (ben@benlitchfield.com)
+ * @version $Revision: 1.2 $
+ */
+public class FDFIconFit implements COSObjectable
+{
+ private COSDictionary fit;
+
+ /**
+ * A scale option.
+ */
+ public static final String SCALE_OPTION_ALWAYS = "A";
+ /**
+ * A scale option.
+ */
+ public static final String SCALE_OPTION_ONLY_WHEN_ICON_IS_BIGGER = "B";
+ /**
+ * A scale option.
+ */
+ public static final String SCALE_OPTION_ONLY_WHEN_ICON_IS_SMALLER = "S";
+ /**
+ * A scale option.
+ */
+ public static final String SCALE_OPTION_NEVER = "N";
+
+ /**
+ * Scale to fill with of annotation, disregarding aspect ratio.
+ */
+ public static final String SCALE_TYPE_ANAMORPHIC = "A";
+ /**
+ * Scale to fit width or height, smaller of two, while retaining aspect ration.
+ */
+ public static final String SCALE_TYPE_PROPORTIONAL = "P";
+
+
+
+ /**
+ * Default constructor.
+ */
+ public FDFIconFit()
+ {
+ fit = new COSDictionary();
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param f The icon fit dictionary.
+ */
+ public FDFIconFit( COSDictionary f )
+ {
+ fit = f;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSBase getCOSObject()
+ {
+ return fit;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSDictionary getCOSDictionary()
+ {
+ return fit;
+ }
+
+ /**
+ * This will get the scale option. See the SCALE_OPTION_XXX constants. This
+ * is guaranteed to never return null. Default: Always
+ *
+ * @return The scale option.
+ */
+ public String getScaleOption()
+ {
+ String retval = fit.getNameAsString( "SW" );
+ if( retval == null )
+ {
+ retval = SCALE_OPTION_ALWAYS;
+ }
+ return retval;
+ }
+
+ /**
+ * This will set the scale option for the icon. Set the SCALE_OPTION_XXX constants.
+ *
+ * @param option The scale option.
+ */
+ public void setScaleOption( String option )
+ {
+ fit.setName( "SW", option );
+ }
+
+ /**
+ * This will get the scale type. See the SCALE_TYPE_XXX constants. This is
+ * guaranteed to never return null. Default: Proportional
+ *
+ * @return The scale type.
+ */
+ public String getScaleType()
+ {
+ String retval = fit.getNameAsString( "S" );
+ if( retval == null )
+ {
+ retval = SCALE_TYPE_PROPORTIONAL;
+ }
+ return retval;
+ }
+
+ /**
+ * This will set the scale type. See the SCALE_TYPE_XXX constants.
+ *
+ * @param scale The scale type.
+ */
+ public void setScaleType( String scale )
+ {
+ fit.setName( "S", scale );
+ }
+
+ /**
+ * This is guaranteed to never return null.<br />
+ *
+ * To quote the PDF Spec
+ * "An array of two numbers between 0.0 and 1.0 indicating the fraction of leftover
+ * space to allocate at the left and bottom of the icon. A value of [0.0 0.0] positions the
+ * icon at the bottom-left corner of the annotation rectangle; a value of [0.5 0.5] centers it
+ * within the rectangle. This entry is used only if the icon is scaled proportionally. Default
+ * value: [0.5 0.5]."
+ *
+ * @return The fractional space to allocate.
+ */
+ public PDRange getFractionalSpaceToAllocate()
+ {
+ PDRange retval = null;
+ COSArray array = (COSArray)fit.getDictionaryObject( "A" );
+ if( array == null )
+ {
+ retval = new PDRange();
+ retval.setMin( .5f );
+ retval.setMax( .5f );
+ setFractionalSpaceToAllocate( retval );
+ }
+ else
+ {
+ retval = new PDRange( array );
+ }
+ return retval;
+ }
+
+ /**
+ * This will set frational space to allocate.
+ *
+ * @param space The space to allocate.
+ */
+ public void setFractionalSpaceToAllocate( PDRange space )
+ {
+ fit.setItem( "A", space );
+ }
+
+ /**
+ * This will tell if the icon should scale to fit the annotation bounds. Default: false
+ *
+ * @return A flag telling if the icon should scale.
+ */
+ public boolean shouldScaleToFitAnnotation()
+ {
+ return fit.getBoolean( "FB", false );
+ }
+
+ /**
+ * This will tell the icon to scale.
+ *
+ * @param value The flag value.
+ */
+ public void setScaleToFitAnnotation( boolean value )
+ {
+ fit.setBoolean( "FB", value );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/fdf/FDFJavaScript.java b/src/main/java/org/pdfbox/pdmodel/fdf/FDFJavaScript.java
new file mode 100644
index 0000000..dfa6b0f
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/fdf/FDFJavaScript.java
@@ -0,0 +1,172 @@
+/**
+ * Copyright (c) 2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.fdf;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.pdfbox.cos.COSArray;
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSName;
+
+import org.pdfbox.pdmodel.common.COSObjectable;
+import org.pdfbox.pdmodel.common.COSArrayList;
+import org.pdfbox.pdmodel.common.PDTextStream;
+import org.pdfbox.pdmodel.common.PDNamedTextStream;
+
+/**
+ * This represents an FDF JavaScript dictionary that is part of the FDF document.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.2 $
+ */
+public class FDFJavaScript implements COSObjectable
+{
+ private COSDictionary js;
+
+ /**
+ * Default constructor.
+ */
+ public FDFJavaScript()
+ {
+ js = new COSDictionary();
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param javaScript The FDF java script.
+ */
+ public FDFJavaScript( COSDictionary javaScript )
+ {
+ js = javaScript;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSBase getCOSObject()
+ {
+ return js;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSDictionary getCOSDictionary()
+ {
+ return js;
+ }
+
+ /**
+ * This will get the javascript that is executed before the import.
+ *
+ * @return Some javascript code.
+ */
+ public PDTextStream getBefore()
+ {
+ return PDTextStream.createTextStream( js.getDictionaryObject( "Before" ) );
+ }
+
+ /**
+ * This will set the javascript code the will get execute before the import.
+ *
+ * @param before A reference to some javascript code.
+ */
+ public void setBefore( PDTextStream before )
+ {
+ js.setItem( "Before", before );
+ }
+
+ /**
+ * This will get the javascript that is executed after the import.
+ *
+ * @return Some javascript code.
+ */
+ public PDTextStream getAfter()
+ {
+ return PDTextStream.createTextStream( js.getDictionaryObject( "After" ) );
+ }
+
+ /**
+ * This will set the javascript code the will get execute after the import.
+ *
+ * @param after A reference to some javascript code.
+ */
+ public void setAfter( PDTextStream after )
+ {
+ js.setItem( "After", after );
+ }
+
+ /**
+ * This will return a list of PDNamedTextStream objects. This is the "Doc"
+ * entry of the pdf document. These will be added to the PDF documents
+ * javascript name tree. This will not return null.
+ *
+ * @return A list of all named javascript entries.
+ */
+ public List getNamedJavaScripts()
+ {
+ List retval = null;
+ COSArray array = (COSArray)js.getDictionaryObject( "Doc" );
+ List namedStreams = new ArrayList();
+ if( array == null )
+ {
+ array = new COSArray();
+ js.setItem( "Doc", array );
+ }
+ for( int i=0; i<array.size(); i++ )
+ {
+ COSName name = (COSName)array.get( i );
+ i++;
+ COSBase stream = array.get( i );
+ PDNamedTextStream namedStream = new PDNamedTextStream( name, stream );
+ namedStreams.add( namedStream );
+ }
+ return new COSArrayList( namedStreams, array );
+ }
+
+ /**
+ * This should be a list of PDNamedTextStream objects.
+ *
+ * @param namedStreams The named streams.
+ */
+ public void setNamedJavaScripts( List namedStreams )
+ {
+ COSArray array = COSArrayList.converterToCOSArray( namedStreams );
+ js.setItem( "Doc", array );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/fdf/FDFNamedPageReference.java b/src/main/java/org/pdfbox/pdmodel/fdf/FDFNamedPageReference.java
new file mode 100644
index 0000000..c03689b
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/fdf/FDFNamedPageReference.java
@@ -0,0 +1,128 @@
+/**
+ * Copyright (c) 2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.fdf;
+
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSDictionary;
+
+import org.pdfbox.pdmodel.common.COSObjectable;
+
+import org.pdfbox.pdmodel.common.filespecification.PDFileSpecification;;
+
+/**
+ * This represents an FDF named page reference that is part of the FDF field.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.1 $
+ */
+public class FDFNamedPageReference implements COSObjectable
+{
+ private COSDictionary ref;
+
+ /**
+ * Default constructor.
+ */
+ public FDFNamedPageReference()
+ {
+ ref = new COSDictionary();
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param r The FDF named page reference dictionary.
+ */
+ public FDFNamedPageReference( COSDictionary r )
+ {
+ ref = r;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSBase getCOSObject()
+ {
+ return ref;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSDictionary getCOSDictionary()
+ {
+ return ref;
+ }
+
+ /**
+ * This will get the name of the referenced page. A required parameter.
+ *
+ * @return The name of the referenced page.
+ */
+ public String getName()
+ {
+ return ref.getString( "Name" );
+ }
+
+ /**
+ * This will set the name of the referenced page.
+ *
+ * @param name The referenced page name.
+ */
+ public void setName( String name )
+ {
+ ref.setString( "Name", name );
+ }
+
+ /**
+ * This will get the file specification of this reference. An optional parameter.
+ *
+ * @return The F entry for this dictionary.
+ */
+ public PDFileSpecification getFileSpecification()
+ {
+ COSBase fs = ref.getDictionaryObject( "F" );
+ return PDFileSpecification.createFS( fs );
+ }
+
+ /**
+ * This will set the file specification for this named page reference.
+ *
+ * @param fs The file specification to set.
+ */
+ public void setFileSpecification( PDFileSpecification fs )
+ {
+ ref.setItem( "F", fs );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/fdf/FDFOptionElement.java b/src/main/java/org/pdfbox/pdmodel/fdf/FDFOptionElement.java
new file mode 100644
index 0000000..d82a715
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/fdf/FDFOptionElement.java
@@ -0,0 +1,129 @@
+/**
+ * Copyright (c) 2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.fdf;
+
+import org.pdfbox.cos.COSArray;
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSString;
+
+import org.pdfbox.pdmodel.common.COSObjectable;
+
+/**
+ * This represents an object that can be used in a Field's Opt entry to represent
+ * an available option and a default appearance string.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.1 $
+ */
+public class FDFOptionElement implements COSObjectable
+{
+ private COSArray option;
+
+ /**
+ * Default constructor.
+ */
+ public FDFOptionElement()
+ {
+ option = new COSArray();
+ option.add( new COSString( "" ) );
+ option.add( new COSString( "" ) );
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param o The option element.
+ */
+ public FDFOptionElement( COSArray o )
+ {
+ option = o;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSBase getCOSObject()
+ {
+ return option;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSArray getCOSArray()
+ {
+ return option;
+ }
+
+ /**
+ * This will get the string of one of the available options. A required element.
+ *
+ * @return An available option.
+ */
+ public String getOption()
+ {
+ return ((COSString)option.getObject( 0 ) ).getString();
+ }
+
+ /**
+ * This will set the string for an available option.
+ *
+ * @param opt One of the available options.
+ */
+ public void setOption( String opt )
+ {
+ option.set( 0, new COSString( opt ) );
+ }
+
+ /**
+ * This will get the string of default appearance string. A required element.
+ *
+ * @return A default appearance string.
+ */
+ public String getDefaultAppearanceString()
+ {
+ return ((COSString)option.getObject( 1 ) ).getString();
+ }
+
+ /**
+ * This will set the default appearance string.
+ *
+ * @param da The default appearance string.
+ */
+ public void setDefaultAppearanceString( String da )
+ {
+ option.set( 1, new COSString( da ) );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/fdf/FDFPage.java b/src/main/java/org/pdfbox/pdmodel/fdf/FDFPage.java
new file mode 100644
index 0000000..1f5e0b9
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/fdf/FDFPage.java
@@ -0,0 +1,148 @@
+/**
+ * Copyright (c) 2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.fdf;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.pdfbox.cos.COSArray;
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSDictionary;
+
+import org.pdfbox.pdmodel.common.COSArrayList;
+import org.pdfbox.pdmodel.common.COSObjectable;
+
+/**
+ * This represents an FDF page that is part of the FDF document.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.2 $
+ */
+public class FDFPage implements COSObjectable
+{
+ private COSDictionary page;
+
+ /**
+ * Default constructor.
+ */
+ public FDFPage()
+ {
+ page = new COSDictionary();
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param p The FDF page.
+ */
+ public FDFPage( COSDictionary p )
+ {
+ page = p;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSBase getCOSObject()
+ {
+ return page;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSDictionary getCOSDictionary()
+ {
+ return page;
+ }
+
+ /**
+ * This will get a list of FDFTemplage objects that describe the named pages
+ * that serve as templates.
+ *
+ * @return A list of templates.
+ */
+ public List getTemplates()
+ {
+ List retval = null;
+ COSArray array = (COSArray)page.getDictionaryObject( "Templates" );
+ if( array != null )
+ {
+ List objects = new ArrayList();
+ for( int i=0; i<array.size(); i++ )
+ {
+ objects.add( new FDFTemplate( (COSDictionary)array.getObject( i ) ) );
+ }
+ retval = new COSArrayList( objects, array );
+ }
+ return retval;
+ }
+
+ /**
+ * A list of FDFTemplate objects.
+ *
+ * @param templates A list of templates for this Page.
+ */
+ public void setTemplates( List templates )
+ {
+ page.setItem( "Templates", COSArrayList.converterToCOSArray( templates ) );
+ }
+
+ /**
+ * This will get the FDF page info object.
+ *
+ * @return The Page info.
+ */
+ public FDFPageInfo getPageInfo()
+ {
+ FDFPageInfo retval = null;
+ COSDictionary dict = (COSDictionary)page.getDictionaryObject( "Info" );
+ if( dict != null )
+ {
+ retval = new FDFPageInfo( dict );
+ }
+ return retval;
+ }
+
+ /**
+ * This will set the page info.
+ *
+ * @param info The new page info dictionary.
+ */
+ public void setPageInfo( FDFPageInfo info )
+ {
+ page.setItem( "Info", info );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/fdf/FDFPageInfo.java b/src/main/java/org/pdfbox/pdmodel/fdf/FDFPageInfo.java
new file mode 100644
index 0000000..e30441e
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/fdf/FDFPageInfo.java
@@ -0,0 +1,85 @@
+/**
+ * Copyright (c) 2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.fdf;
+
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSDictionary;
+
+import org.pdfbox.pdmodel.common.COSObjectable;
+
+/**
+ * This represents an FDF page info that is part of the FDF page.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.1 $
+ */
+public class FDFPageInfo implements COSObjectable
+{
+ private COSDictionary pageInfo;
+
+ /**
+ * Default constructor.
+ */
+ public FDFPageInfo()
+ {
+ pageInfo = new COSDictionary();
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param p The FDF page.
+ */
+ public FDFPageInfo( COSDictionary p )
+ {
+ pageInfo = p;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSBase getCOSObject()
+ {
+ return pageInfo;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSDictionary getCOSDictionary()
+ {
+ return pageInfo;
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/fdf/FDFTemplate.java b/src/main/java/org/pdfbox/pdmodel/fdf/FDFTemplate.java
new file mode 100644
index 0000000..217ca30
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/fdf/FDFTemplate.java
@@ -0,0 +1,167 @@
+/**
+ * Copyright (c) 2004-2005, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.fdf;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.pdfbox.cos.COSArray;
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSDictionary;
+
+import org.pdfbox.pdmodel.common.COSArrayList;
+import org.pdfbox.pdmodel.common.COSObjectable;
+
+/**
+ * This represents an FDF template that is part of the FDF page.
+ *
+ * @author Ben Litchfield (ben@benlitchfield.com)
+ * @version $Revision: 1.2 $
+ */
+public class FDFTemplate implements COSObjectable
+{
+ private COSDictionary template;
+
+ /**
+ * Default constructor.
+ */
+ public FDFTemplate()
+ {
+ template = new COSDictionary();
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param t The FDF page template.
+ */
+ public FDFTemplate( COSDictionary t )
+ {
+ template = t;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSBase getCOSObject()
+ {
+ return template;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSDictionary getCOSDictionary()
+ {
+ return template;
+ }
+
+ /**
+ * This is the template reference.
+ *
+ * @return The template reference.
+ */
+ public FDFNamedPageReference getTemplateReference()
+ {
+ FDFNamedPageReference retval = null;
+ COSDictionary dict = (COSDictionary)template.getDictionaryObject( "TRef" );
+ if( dict != null )
+ {
+ retval = new FDFNamedPageReference( dict );
+ }
+ return retval;
+ }
+
+ /**
+ * This will set the template reference.
+ *
+ * @param tRef The template reference.
+ */
+ public void setTemplateReference( FDFNamedPageReference tRef )
+ {
+ template.setItem( "TRef", tRef );
+ }
+
+ /**
+ * This will get a list of fields that are part of this template.
+ *
+ * @return A list of fields.
+ */
+ public List getFields()
+ {
+ List retval = null;
+ COSArray array = (COSArray)template.getDictionaryObject( "Fields" );
+ if( array != null )
+ {
+ List fields = new ArrayList();
+ for( int i=0; i<array.size(); i++ )
+ {
+ fields.add( new FDFField( (COSDictionary)array.getObject( i ) ) );
+ }
+ retval = new COSArrayList( fields, array );
+ }
+ return retval;
+ }
+
+ /**
+ * This will set a list of fields for this template.
+ *
+ * @param fields The list of fields to set for this template.
+ */
+ public void setFields( List fields )
+ {
+ template.setItem( "Fields", COSArrayList.converterToCOSArray( fields ) );
+ }
+
+ /**
+ * A flag telling if the fields imported from the template may be renamed if there are conflicts.
+ *
+ * @return A flag telling if the fields can be renamed.
+ */
+ public boolean shouldRename()
+ {
+ return template.getBoolean( "Rename", false );
+ }
+
+ /**
+ * This will set if the fields can be renamed.
+ *
+ * @param value The flag value.
+ */
+ public void setRename( boolean value )
+ {
+ template.setBoolean( "Rename", value );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/fdf/package.html b/src/main/java/org/pdfbox/pdmodel/fdf/package.html
new file mode 100644
index 0000000..e2b6fea
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/fdf/package.html
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+
+</head>
+<body>
+The fdf package will handle all of the logic used for FDF objects inside of the PDF/FDF document.
+</body>
+</html>
diff --git a/src/main/java/org/pdfbox/pdmodel/font/PDCIDFont.java b/src/main/java/org/pdfbox/pdmodel/font/PDCIDFont.java
new file mode 100644
index 0000000..e13b821
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/font/PDCIDFont.java
@@ -0,0 +1,248 @@
+/**
+ * Copyright (c) 2003-2005, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.font;
+
+import java.awt.Graphics;
+
+import java.io.IOException;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.pdfbox.cos.COSArray;
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSInteger;
+import org.pdfbox.cos.COSName;
+import org.pdfbox.cos.COSNumber;
+import org.pdfbox.pdmodel.common.PDRectangle;
+
+import org.apache.log4j.Logger;
+
+/**
+ * This is implementation for the CIDFontType0/CIDFontType2 Fonts.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.7 $
+ */
+public abstract class PDCIDFont extends PDFont
+{
+ private static Logger log = Logger.getLogger(PDCIDFont.class);
+
+
+ private Map widthCache = new HashMap();
+
+ /**
+ * Constructor.
+ */
+ public PDCIDFont()
+ {
+ super();
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param fontDictionary The font dictionary according to the PDF specification.
+ */
+ public PDCIDFont( COSDictionary fontDictionary )
+ {
+ super( fontDictionary );
+ }
+
+ /**
+ * @see PDFont#drawString( String, Graphics, float, float, float, float, float )
+ */
+ public void drawString( String string, Graphics g, float fontSize,
+ float xScale, float yScale, float x, float y )
+ {
+ throw new RuntimeException( "Not yet implemented" );
+ }
+
+ /**
+ * This will get the fonts bouding box.
+ *
+ * @return The fonts bouding box.
+ *
+ * @throws IOException If there is an error getting the font bounding box.
+ */
+ public PDRectangle getFontBoundingBox() throws IOException
+ {
+ throw new RuntimeException( "Not yet implemented" );
+ }
+
+ /**
+ * This will get the default width. The default value for the default width is 1000.
+ *
+ * @return The default width for the glyphs in this font.
+ */
+ public long getDefaultWidth()
+ {
+ long dw = 1000;
+ COSNumber number = (COSNumber)font.getDictionaryObject( COSName.getPDFName( "DW" ) );
+ if( number != null )
+ {
+ dw = number.intValue();
+ }
+ return dw;
+ }
+
+ /**
+ * This will set the default width for the glyphs of this font.
+ *
+ * @param dw The default width.
+ */
+ public void setDefaultWidth( long dw )
+ {
+ font.setItem( COSName.getPDFName( "DW" ), new COSInteger( dw ) );
+ }
+
+ /**
+ * This will get the font width for a character.
+ *
+ * @param c The character code to get the width for.
+ * @param offset The offset into the array.
+ * @param length The length of the data.
+ *
+ * @return The width is in 1000 unit of text space, ie 333 or 777
+ *
+ * @throws IOException If an error occurs while parsing.
+ */
+ public float getFontWidth( byte[] c, int offset, int length ) throws IOException
+ {
+
+ float retval = 0.0f;
+ int code = getCodeFromArray( c, offset, length );
+
+ Float widthFloat = (Float)widthCache.get( new Integer( code ) );
+ if( widthFloat == null )
+ {
+ COSArray widths = (COSArray)font.getDictionaryObject( COSName.getPDFName( "W" ) );
+
+ if( widths != null )
+ {
+ boolean foundWidth = false;
+ for( int i=0; !foundWidth && i<widths.size(); i++ )
+ {
+ COSNumber firstCode = (COSNumber)widths.getObject( i++ );
+ COSBase next = widths.getObject( i );
+ if( next instanceof COSArray )
+ {
+ COSArray array = (COSArray)next;
+ if( code >= firstCode.intValue() &&
+ code < firstCode.intValue() + array.size() )
+ {
+ COSNumber rangeWidth =
+ (COSNumber)array.get( code - firstCode.intValue() );
+ retval = rangeWidth.floatValue();
+ foundWidth = true;
+ }
+ }
+ else
+ {
+ COSNumber secondCode = (COSNumber)next;
+ i++;
+ COSNumber rangeWidth = (COSNumber)widths.getObject( i );
+ if( code >= firstCode.intValue() &&
+ code <= secondCode.intValue() )
+ {
+ retval = rangeWidth.floatValue();
+ foundWidth = true;
+ }
+ }
+ }
+ widthCache.put( new Integer( code ), new Float( retval ) );
+ }
+ }
+ else
+ {
+ retval = widthFloat.floatValue();
+ }
+
+ if(log.isDebugEnabled() )
+ {
+ log.debug( "PDCIDFontType0Font.getFontWidth( code=" + code +" ) retval=" +retval );
+ }
+ return retval;
+ }
+
+ /**
+ * This will get the average font width for all characters.
+ *
+ * @return The width is in 1000 unit of text space, ie 333 or 777
+ *
+ * @throws IOException If an error occurs while parsing.
+ */
+ public float getAverageFontWidth() throws IOException
+ {
+ float totalWidths = 0.0f;
+ float characterCount = 0.0f;
+ float defaultWidth = getDefaultWidth();
+ COSArray widths = (COSArray)font.getDictionaryObject( COSName.getPDFName( "W" ) );
+
+ if( widths != null )
+ {
+ for( int i=0; i<widths.size(); i++ )
+ {
+ COSNumber firstCode = (COSNumber)widths.getObject( i++ );
+ COSBase next = widths.getObject( i );
+ float nextWidth=0.0f;
+ if( next instanceof COSArray )
+ {
+ COSArray array = (COSArray)next;
+ for( int j=0; j<array.size(); j++ )
+ {
+ COSNumber width = (COSNumber)array.get( j );
+ totalWidths+=width.floatValue();
+ characterCount += 1;
+ }
+ }
+ else
+ {
+ COSNumber secondCode = (COSNumber)next;
+ i++;
+ COSNumber rangeWidth = (COSNumber)widths.getObject( i );
+ if( rangeWidth.floatValue() > 0 )
+ {
+ totalWidths += rangeWidth.floatValue();
+ characterCount += 1;
+ }
+ }
+ }
+ }
+ float average = totalWidths / characterCount;
+ if( average <= 0 )
+ {
+ average = defaultWidth;
+ }
+ return average;
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/font/PDCIDFontType0Font.java b/src/main/java/org/pdfbox/pdmodel/font/PDCIDFontType0Font.java
new file mode 100644
index 0000000..4c6589c
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/font/PDCIDFontType0Font.java
@@ -0,0 +1,66 @@
+/**
+ * Copyright (c) 2003, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.font;
+
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSName;
+
+import org.apache.log4j.Logger;
+
+/**
+ * This is implementation of the CIDFontType0 Font.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.4 $
+ */
+public class PDCIDFontType0Font extends PDCIDFont
+{
+ private static Logger log = Logger.getLogger(PDCIDFontType0Font.class);
+
+ /**
+ * Constructor.
+ */
+ public PDCIDFontType0Font()
+ {
+ super();
+ font.setItem( COSName.SUBTYPE, COSName.getPDFName( "CIDFontType0" ) );
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param fontDictionary The font dictionary according to the PDF specification.
+ */
+ public PDCIDFontType0Font( COSDictionary fontDictionary )
+ {
+ super( fontDictionary );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/font/PDCIDFontType2Font.java b/src/main/java/org/pdfbox/pdmodel/font/PDCIDFontType2Font.java
new file mode 100644
index 0000000..bda6c4a
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/font/PDCIDFontType2Font.java
@@ -0,0 +1,66 @@
+/**
+ * Copyright (c) 2003, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.font;
+
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSName;
+
+import org.apache.log4j.Logger;
+
+/**
+ * This is implementation of the CIDFontType2 Font.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.3 $
+ */
+public class PDCIDFontType2Font extends PDCIDFont
+{
+ private static Logger log = Logger.getLogger(PDCIDFontType2Font.class);
+
+ /**
+ * Constructor.
+ */
+ public PDCIDFontType2Font()
+ {
+ super();
+ font.setItem( COSName.SUBTYPE, COSName.getPDFName( "CIDFontType2" ) );
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param fontDictionary The font dictionary according to the PDF specification.
+ */
+ public PDCIDFontType2Font( COSDictionary fontDictionary )
+ {
+ super( fontDictionary );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/font/PDFont.java b/src/main/java/org/pdfbox/pdmodel/font/PDFont.java
new file mode 100644
index 0000000..593c8b0
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/font/PDFont.java
@@ -0,0 +1,863 @@
+/**
+ * Copyright (c) 2003-2005, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.font;
+
+import org.pdfbox.afmparser.AFMParser;
+
+import org.pdfbox.afmtypes.FontMetric;
+
+import org.pdfbox.cmapparser.CMapParser;
+
+import org.pdfbox.cmaptypes.CMap;
+
+import org.pdfbox.encoding.AFMEncoding;
+import org.pdfbox.encoding.DictionaryEncoding;
+import org.pdfbox.encoding.Encoding;
+import org.pdfbox.encoding.EncodingManager;
+
+import org.pdfbox.cos.COSArray;
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSFloat;
+import org.pdfbox.cos.COSName;
+import org.pdfbox.cos.COSNumber;
+import org.pdfbox.cos.COSStream;
+
+import org.pdfbox.pdmodel.common.COSArrayList;
+import org.pdfbox.pdmodel.common.COSObjectable;
+import org.pdfbox.pdmodel.common.PDMatrix;
+import org.pdfbox.pdmodel.common.PDRectangle;
+
+import org.pdfbox.util.ResourceLoader;
+
+import org.apache.log4j.Logger;
+
+import java.awt.Graphics;
+
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.IOException;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.StringTokenizer;
+
+/**
+ * This is the base class for all PDF fonts.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.32 $
+ */
+public abstract class PDFont implements COSObjectable
+{
+ private static Logger log = Logger.getLogger(PDFont.class);
+
+ /**
+ * The cos dictionary for this font.
+ */
+ protected COSDictionary font;
+
+ /**
+ * This is only used if this is a font object and it has an encoding.
+ */
+ private Encoding fontEncoding = null;
+ /**
+ * This is only used if this is a font object and it has an encoding and it is
+ * a type0 font with a cmap.
+ */
+ private CMap cmap = null;
+
+ private static Map afmResources = null;
+ private static Map cmapObjects = null;
+ private static Map afmObjects = null;
+ private static Map cmapSubstitutions = null;
+
+ static
+ {
+ //these are read-only once they are created
+ afmResources = new HashMap();
+ cmapSubstitutions = new HashMap();
+
+ //these are read-write
+ cmapObjects = Collections.synchronizedMap( new HashMap() );
+ afmObjects = Collections.synchronizedMap( new HashMap() );
+
+
+ afmResources.put( COSName.getPDFName( "Courier-Bold" ), "Resources/afm/Courier-Bold.afm" );
+ afmResources.put( COSName.getPDFName( "Courier-BoldOblique" ), "Resources/afm/Courier-BoldOblique.afm" );
+ afmResources.put( COSName.getPDFName( "Courier" ), "Resources/afm/Courier.afm" );
+ afmResources.put( COSName.getPDFName( "Courier-Oblique" ), "Resources/afm/Courier-Oblique.afm" );
+ afmResources.put( COSName.getPDFName( "Helvetica" ), "Resources/afm/Helvetica.afm" );
+ afmResources.put( COSName.getPDFName( "Helvetica-Bold" ), "Resources/afm/Helvetica-Bold.afm" );
+ afmResources.put( COSName.getPDFName( "Helvetica-BoldOblique" ), "Resources/afm/Helvetica-BoldOblique.afm" );
+ afmResources.put( COSName.getPDFName( "Helvetica-Oblique" ), "Resources/afm/Helvetica-Oblique.afm" );
+ afmResources.put( COSName.getPDFName( "Symbol" ), "Resources/afm/Symbol.afm" );
+ afmResources.put( COSName.getPDFName( "Times-Bold" ), "Resources/afm/Times-Bold.afm" );
+ afmResources.put( COSName.getPDFName( "Times-BoldItalic" ), "Resources/afm/Times-BoldItalic.afm" );
+ afmResources.put( COSName.getPDFName( "Times-Italic" ), "Resources/afm/Times-Italic.afm" );
+ afmResources.put( COSName.getPDFName( "Times-Roman" ), "Resources/afm/Times-Roman.afm" );
+ afmResources.put( COSName.getPDFName( "ZapfDingbats" ), "Resources/afm/ZapfDingbats.afm" );
+
+ cmapSubstitutions.put( "ETenms-B5-H", "ETen-B5-H" );
+ cmapSubstitutions.put( "ETenms-B5-V", "ETen-B5-V" );
+ }
+
+ /**
+ * This will clear AFM resources that are stored statically.
+ * This is usually not a problem unless you want to reclaim
+ * resources for a long running process.
+ *
+ * SPECIAL NOTE: The font calculations are currently in COSObject, which
+ * is where they will reside until PDFont is mature enough to take them over.
+ * PDFont is the appropriate place for them and not in COSObject but we need font
+ * calculations for text extractaion. THIS METHOD WILL BE MOVED OR REMOVED
+ * TO ANOTHER LOCATION IN A FUTURE VERSION OF PDFBOX.
+ */
+ public static void clearResources()
+ {
+ afmObjects.clear();
+ cmapObjects.clear();
+ }
+
+ /**
+ * Constructor.
+ */
+ public PDFont()
+ {
+ font = new COSDictionary();
+ font.setItem( COSName.TYPE, COSName.FONT );
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param fontDictionary The font dictionary according to the PDF specification.
+ */
+ public PDFont( COSDictionary fontDictionary )
+ {
+ font = fontDictionary;
+ }
+
+ /**
+ * @see COSObjectable#getCOSObject()
+ */
+ public COSBase getCOSObject()
+ {
+ return font;
+ }
+
+ /**
+ * This will get the font width for a character.
+ *
+ * @param c The character code to get the width for.
+ * @param offset The offset into the array.
+ * @param length The length of the data.
+ *
+ * @return The width is in 1000 unit of text space, ie 333 or 777
+ *
+ * @throws IOException If an error occurs while parsing.
+ */
+ public abstract float getFontWidth( byte[] c, int offset, int length ) throws IOException;
+
+ /**
+ * This will get the width of this string for this font.
+ *
+ * @param string The string to get the width of.
+ *
+ * @return The width of the string in 1000 units of text space, ie 333 567...
+ *
+ * @throws IOException If there is an error getting the width information.
+ */
+ public float getStringWidth( String string ) throws IOException
+ {
+ byte[] data = string.getBytes();
+ float totalWidth = 0;
+ for( int i=0; i<data.length; i++ )
+ {
+ totalWidth+=getFontWidth( data, i, 1 );
+ }
+ return totalWidth;
+ }
+
+ /**
+ * This will get the average font width for all characters.
+ *
+ * @return The width is in 1000 unit of text space, ie 333 or 777
+ *
+ * @throws IOException If an error occurs while parsing.
+ */
+ public abstract float getAverageFontWidth() throws IOException;
+
+ /**
+ * This will draw a string on a canvas using the font.
+ *
+ * @param string The string to draw.
+ * @param g The graphics to draw onto.
+ * @param fontSize The size of the font to draw.
+ * @param xScale The x scaling percent.
+ * @param yScale The y scaling percent.
+ * @param x The x coordinate to draw at.
+ * @param y The y coordinate to draw at.
+ *
+ * @throws IOException If there is an error drawing the specific string.
+ */
+ public abstract void drawString( String string, Graphics g, float fontSize,
+ float xScale, float yScale, float x, float y ) throws IOException;
+
+ /**
+ * Used for multibyte encodings.
+ *
+ * @param data The array of data.
+ * @param offset The offset into the array.
+ * @param length The number of bytes to use.
+ *
+ * @return The int value of data from the array.
+ */
+ protected int getCodeFromArray( byte[] data, int offset, int length )
+ {
+ int code = 0;
+ for( int i=0; i<length; i++ )
+ {
+ code <<= 8;
+ code = (data[offset+i]+256)%256;
+ }
+ return code;
+ }
+
+ /**
+ * This will attempt to get the font width from an AFM file.
+ *
+ * @param code The character code we are trying to get.
+ *
+ * @return The font width from the AFM file.
+ *
+ * @throws IOException if we cannot find the width.
+ */
+ protected float getFontWidthFromAFMFile( int code ) throws IOException
+ {
+ float retval = 0;
+ FontMetric metric = getAFM();
+ if( metric != null )
+ {
+ Encoding encoding = getEncoding();
+ COSName characterName = encoding.getName( code );
+ retval = metric.getCharacterWidth( characterName.getName() );
+ }
+ return retval;
+ }
+
+ /**
+ * This will attempt to get the average font width from an AFM file.
+ *
+ * @return The average font width from the AFM file.
+ *
+ * @throws IOException if we cannot find the width.
+ */
+ protected float getAverageFontWidthFromAFMFile() throws IOException
+ {
+ float retval = 0;
+ FontMetric metric = getAFM();
+ if( metric != null )
+ {
+ retval = metric.getAverageCharacterWidth();
+ }
+ return retval;
+ }
+
+ /**
+ * This will get an AFM object if one exists.
+ *
+ * @return The afm object from the name.
+ *
+ * @throws IOException If there is an error getting the AFM object.
+ */
+ protected FontMetric getAFM() throws IOException
+ {
+ COSName name = (COSName)font.getDictionaryObject( COSName.BASE_FONT );
+ FontMetric result = null;
+ if( name != null )
+ {
+ result = (FontMetric)afmObjects.get( name );
+ if( result == null )
+ {
+ String resource = (String)afmResources.get( name );
+ if( log.isDebugEnabled() )
+ {
+ log.debug("resource: " + resource + ", name: " + name.getName());
+ }
+ if( resource == null )
+ {
+ if( log.isDebugEnabled() )
+ {
+ log.debug( "resource is null" );
+ }
+ //ok for now
+ //throw new IOException( "Unknown AFM font '" + name.getName() + "'" );
+ }
+ else
+ {
+ InputStream afmStream = ResourceLoader.loadResource( resource );
+ if( afmStream == null )
+ {
+ throw new IOException( "Can't handle font width:" + resource );
+ }
+ AFMParser parser = new AFMParser( afmStream );
+ parser.parse();
+ result = parser.getResult();
+ afmObjects.put( name, result );
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * This will perform the encoding of a character if needed.
+ *
+ * @param c The character to encode.
+ * @param offset The offset into the array to get the data
+ * @param length The number of bytes to read.
+ *
+ * @return The value of the encoded character.
+ *
+ * @throws IOException If there is an error during the encoding.
+ */
+ public String encode( byte[] c, int offset, int length ) throws IOException
+ {
+ String retval = null;
+ COSName fontSubtype = (COSName)font.getDictionaryObject( COSName.SUBTYPE );
+ String fontSubtypeName = fontSubtype.getName();
+ if( fontSubtypeName.equals( "Type0" ) ||
+ fontSubtypeName.equals( "Type1" ) ||
+ fontSubtypeName.equals( "TrueType" ))
+ {
+ if( cmap == null )
+ {
+ if( font.getDictionaryObject( COSName.TO_UNICODE ) != null )
+ {
+ COSStream toUnicode = (COSStream)font.getDictionaryObject( COSName.TO_UNICODE );
+ if( toUnicode != null )
+ {
+ parseCmap( toUnicode.getUnfilteredStream(), null );
+ if( log.isDebugEnabled() )
+ {
+ log.debug( "Getting embedded CMAP Stream from ToUnicode" );
+ }
+ }
+ }
+ else
+ {
+ COSBase encoding = font.getDictionaryObject( COSName.ENCODING );
+ if( encoding instanceof COSStream )
+ {
+ COSStream encodingStream = (COSStream)encoding;
+ parseCmap( encodingStream.getUnfilteredStream(), null );
+ if( log.isDebugEnabled() )
+ {
+ log.debug( "Getting embedded CMAP Stream from encoding" );
+ }
+ }
+ else if( fontSubtypeName.equals( "Type0" ) &&
+ encoding instanceof COSName )
+ {
+ COSName encodingName = (COSName)encoding;
+ cmap = (CMap)cmapObjects.get( encodingName );
+ if( cmap != null )
+ {
+ cmap = (CMap)cmapObjects.get( encodingName );
+ }
+ else
+ {
+ if( log.isDebugEnabled() )
+ {
+ log.debug( "Getting CMAP Stream from resource" );
+ }
+ String cmapName = encodingName.getName();
+ cmapName = performCMAPSubstitution( cmapName );
+ String resourceName = "Resources/cmap/" + cmapName;
+ parseCmap( ResourceLoader.loadResource( resourceName ), encodingName );
+ if( cmap == null && !encodingName.getName().equals( COSName.IDENTITY_H.getName() ) )
+ {
+ throw new IOException( "Error: Could not find predefined " +
+ "CMAP file for '" + encodingName.getName() + "'" );
+ }
+ }
+ }
+ else if( encoding instanceof COSName ||
+ encoding instanceof COSDictionary )
+ {
+ Encoding currentFontEncoding = getEncoding();
+ if( currentFontEncoding != null )
+ {
+ retval = currentFontEncoding.getCharacter( getCodeFromArray( c, offset, length ) );
+ }
+ }
+ else
+ {
+ COSDictionary fontDescriptor =
+ (COSDictionary)font.getDictionaryObject( COSName.FONT_DESC );
+ if( fontSubtypeName.equals( "TrueType" ) &&
+ fontDescriptor != null &&
+ (fontDescriptor.getDictionaryObject( COSName.FONT_FILE )!= null ||
+ fontDescriptor.getDictionaryObject( COSName.FONT_FILE2 ) != null ||
+ fontDescriptor.getDictionaryObject( COSName.FONT_FILE3 ) != null ) )
+ {
+ //If we are using an embedded font then there is not much we can do besides
+ //return the same character codes.
+ //retval = new String( c,offset, length );
+ retval = getStringFromArray( c, offset, length );
+ }
+ else
+ {
+ //this case will be handled below after checking the cmap
+ }
+ }
+ }
+
+
+ }
+ }
+ if( log.isDebugEnabled() )
+ {
+ log.debug( "retval=" + retval + " cmap=" + cmap);
+ }
+ if( retval == null && cmap != null )
+ {
+
+ retval = cmap.lookup( c, offset, length );
+ if( log.isDebugEnabled() )
+ {
+ log.debug( "cmap.lookup(" +c + ")='" +retval + "'" );
+ }
+ }
+ //if we havn't found a value yet and
+ //we are still on the first byte and
+ //there is no cmap or the cmap does not have 2 byte mappings then try to encode
+ //using fallback methods.
+ if( retval == null &&
+ length == 1 &&
+ (cmap == null || !cmap.hasTwoByteMappings()))
+ {
+ if( log.isDebugEnabled() )
+ {
+ log.debug( "No CMAP: Using fallback method");
+ }
+ Encoding encoding = getEncoding();
+ if( encoding != null )
+ {
+ retval = encoding.getCharacter( getCodeFromArray( c, offset, length ) );
+ }
+ if( retval == null )
+ {
+ retval = getStringFromArray( c, offset, length );
+ }
+ }
+ return retval;
+ }
+
+ private static final String[] SINGLE_CHAR_STRING = new String[256];
+ private static final String[][] DOUBLE_CHAR_STRING = new String[256][256];
+ static
+ {
+ for( int i=0; i<256; i++ )
+ {
+ SINGLE_CHAR_STRING[i] = new String( new byte[] {(byte)i} );
+ for( int j=0; j<256; j++ )
+ {
+ DOUBLE_CHAR_STRING[i][j] = new String( new byte[] {(byte)i, (byte)j} );
+ }
+ }
+ }
+
+ private static String getStringFromArray( byte[] c, int offset, int length ) throws IOException
+ {
+ String retval = null;
+ if( length == 1 )
+ {
+ retval = SINGLE_CHAR_STRING[(c[offset]+256)%256];
+ }
+ else if( length == 2 )
+ {
+ retval = DOUBLE_CHAR_STRING[(c[offset]+256)%256][(c[offset+1]+256)%256];
+ }
+ else
+ {
+ throw new IOException( "Error:Unknown character length:" + length );
+ }
+ return retval;
+ }
+
+ /**
+ * Some cmap names are synonyms for other CMAPs. If that is the case
+ * then this method will perform that substitution.
+ *
+ * @param cmapName The name of the cmap to attempt to look up.
+ *
+ * @return Either the original name or the substituted name.
+ */
+ private String performCMAPSubstitution( String cmapName )
+ {
+ String retval = (String)cmapSubstitutions.get( cmapName );
+ if( retval == null )
+ {
+ //if there is no substitution then just return the same value.
+ retval = cmapName;
+ }
+ return retval;
+ }
+
+ private void parseCmap( InputStream cmapStream, COSName encodingName ) throws IOException
+ {
+ if( log.isDebugEnabled() )
+ {
+ log.debug( "Parsing a new CMAP for font:" + font );
+ }
+ if( cmapStream != null )
+ {
+ CMapParser parser = new CMapParser( cmapStream, null );
+ parser.parse();
+ cmap = parser.getResult();
+ if( encodingName != null )
+ {
+ cmapObjects.put( encodingName, cmap );
+ }
+ }
+ }
+
+ /**
+ * The will set the encoding for this font.
+ *
+ * @param enc The font encoding.
+ */
+ public void setEncoding( Encoding enc )
+ {
+ font.setItem( COSName.ENCODING, enc );
+ fontEncoding = enc;
+ }
+
+ /**
+ * This will get or create the encoder.
+ *
+ * modified by Christophe Huault : DGBS Strasbourg huault@free.fr october 2004
+ *
+ * @return The encoding to use.
+ *
+ * @throws IOException If there is an error getting the encoding.
+ */
+ public Encoding getEncoding() throws IOException
+ {
+ EncodingManager manager = new EncodingManager();
+ if( fontEncoding == null )
+ {
+ COSBase encoding = font.getDictionaryObject( COSName.ENCODING );
+ if( encoding == null )
+ {
+ FontMetric metric = getAFM();
+ if( metric != null )
+ {
+ fontEncoding = new AFMEncoding( metric );
+ }
+ if( fontEncoding == null )
+ {
+ fontEncoding = manager.getStandardEncoding();
+ }
+ }
+ /**
+ * Si la clé /Encoding existe dans le dictionnaire fonte il y a deux possibilités :
+ * 1er cas : elle est associé à une reference contenant un dictionnaire de type encoding.
+ * Ce dictionnaire PDF est représenté par un DictionaryEncoding.
+ * If the /Encoding Key does exist in the font dictionary, there are two cases :
+ * case one : The value associated with /Encoding is a reference to a dictionary.
+ * This dictionary is represented by an instance of DictionaryEncoding class
+ */
+ else if( encoding instanceof COSDictionary )
+ {
+ COSDictionary encodingDic = (COSDictionary)encoding;
+ //Let's see if the encoding dictionary has a base encoding
+ //If it does not then we will attempt to get it from the font
+ //file
+ COSName baseEncodingName = (COSName) encodingDic.getDictionaryObject(
+ COSName.BASE_ENCODING);
+ //on ajoute une entrée /BaseEncoding dans /Encoding uniquement si elle en est absente
+ //if not find in Encoding dictinary target, we try to find it from else where
+ if( baseEncodingName == null)
+ {
+ COSName fontEncodingFromFile = getEncodingFromFont();
+ encodingDic.setItem(
+ COSName.BASE_ENCODING,
+ fontEncodingFromFile );
+ }
+ fontEncoding = new DictionaryEncoding( encodingDic );
+ }
+ else if( encoding instanceof COSName )
+ {
+ if( !encoding.equals( COSName.IDENTITY_H ) )
+ {
+ fontEncoding = manager.getEncoding( (COSName)encoding );
+ }
+ }
+ else
+ {
+ throw new IOException( "Unexpected encoding type:" + encoding.getClass().getName() );
+ }
+ }
+ return fontEncoding;
+ }
+
+ /**
+ * This will always return "Font" for fonts.
+ *
+ * @return The type of object that this is.
+ */
+ public String getType()
+ {
+ return font.getNameAsString( COSName.TYPE );
+ }
+
+ /**
+ * This will get the subtype of font, Type1, Type3, ...
+ *
+ * @return The type of font that this is.
+ */
+ public String getSubType()
+ {
+ return font.getNameAsString( COSName.SUBTYPE );
+ }
+
+ /**
+ * The PostScript name of the font.
+ *
+ * @return The postscript name of the font.
+ */
+ public String getBaseFont()
+ {
+ return font.getNameAsString( COSName.BASE_FONT );
+ }
+
+ /**
+ * Set the PostScript name of the font.
+ *
+ * @param baseFont The postscript name for the font.
+ */
+ public void setBaseFont( String baseFont )
+ {
+ font.setName( COSName.BASE_FONT, baseFont );
+ }
+
+ /**
+ * The code for the first char or -1 if there is none.
+ *
+ * @return The code for the first character.
+ */
+ public int getFirstChar()
+ {
+ return font.getInt( COSName.FIRST_CHAR, -1 );
+ }
+
+ /**
+ * Set the first character this font supports.
+ *
+ * @param firstChar The first character.
+ */
+ public void setFirstChar( int firstChar )
+ {
+ font.setInt( COSName.FIRST_CHAR, firstChar );
+ }
+
+ /**
+ * The code for the last char or -1 if there is none.
+ *
+ * @return The code for the last character.
+ */
+ public int getLastChar()
+ {
+ return font.getInt( COSName.LAST_CHAR, -1 );
+ }
+
+ /**
+ * Set the last character this font supports.
+ *
+ * @param lastChar The last character.
+ */
+ public void setLastChar( int lastChar )
+ {
+ font.setInt( COSName.LAST_CHAR, lastChar );
+ }
+
+ /**
+ * The widths of the characters. This will be null for the standard 14 fonts.
+ *
+ * @return The widths of the characters.
+ */
+ public List getWidths()
+ {
+ COSArray array = (COSArray)font.getDictionaryObject( COSName.WIDTHS );
+ return COSArrayList.convertFloatCOSArrayToList( array );
+ }
+
+ /**
+ * Set the widths of the characters code.
+ *
+ * @param widths The widths of the character codes.
+ */
+ public void setWidths( List widths )
+ {
+ font.setItem( COSName.WIDTHS, COSArrayList.converterToCOSArray( widths ) );
+ }
+
+ /**
+ * This will get the matrix that is used to transform glyph space to
+ * text space. By default there are 1000 glyph units to 1 text space
+ * unit, but type3 fonts can use any value.
+ *
+ * Note:If this is a type3 font then it can be modified via the PDType3Font.setFontMatrix, otherwise this
+ * is a read-only property.
+ *
+ * @return The matrix to transform from glyph space to text space.
+ */
+ public PDMatrix getFontMatrix()
+ {
+ PDMatrix matrix = null;
+ COSArray array = (COSArray)font.getDictionaryObject( COSName.FONT_MATRIX );
+ if( array == null )
+ {
+ array = new COSArray();
+ array.add( new COSFloat( 0.001f ) );
+ array.add( COSNumber.ZERO );
+ array.add( COSNumber.ZERO );
+ array.add( new COSFloat( 0.001f ) );
+ array.add( COSNumber.ZERO );
+ array.add( COSNumber.ZERO );
+ }
+ matrix = new PDMatrix(array);
+
+ return matrix;
+ }
+
+ /**
+ * Try to get the encoding for the font and add it to the target
+ * the target must be an an Encoding Dictionary.
+ *
+ * added by Christophe Huault : DGBS Strasbourg huault@free.fr october 2004
+ *
+ * @return The encoding from the font.
+ *
+ * @throws IOException If there is an error reading the file.
+ */
+ private COSName getEncodingFromFont() throws IOException
+ {
+ //This whole section of code needs to be replaced with an actual
+ //type1 font parser!!
+
+
+ COSName retvalue = null;
+ //recuperer le programme de fonte dans son stream qui doit se trouver
+ //dans le flux référencé par à la clé FileFont lui même situé dans
+ //le dictionnaire associé à /FontDescriptor du dictionnaire de type /Font courrant
+ //get the font program in the stream which should be located in
+ //the /FileFont Stream object himself in the /FontDescriptior of the current
+ //font dictionary
+ COSDictionary fontDescriptor = (COSDictionary) font.getDictionaryObject(
+ COSName.FONT_DESC);
+ if( fontDescriptor != null )
+ {
+ COSStream fontFile = (COSStream) fontDescriptor.getDictionaryObject(
+ COSName.FONT_FILE);
+ if( fontFile != null )
+ {
+ BufferedReader in =
+ new BufferedReader(new InputStreamReader(fontFile.getUnfilteredStream()));
+ /**
+ * this section parse the FileProgram stream searching for a /Encoding entry
+ * the research stop if the entry "currentdict end" is reach or after 100 lignes
+ */
+ StringTokenizer st = null;
+ boolean found = false;
+ String line = "";
+ String key = null;
+ for( int i = 0; null!=( line = in.readLine() ) &&
+ i < 40 &&
+ !line.equals("currentdict end")
+ && !found; i++)
+ {
+ st = new StringTokenizer(line);
+ if( st.hasMoreTokens() )
+ {
+ key = st.nextToken();
+ if(key.equals("/Encoding") && st.hasMoreTokens() )
+ {
+ COSName value = COSName.getPDFName( st.nextToken() );
+ found = true;
+ if( value.equals( COSName.MAC_ROMAN_ENCODING ) ||
+ value.equals( COSName.PDF_DOC_ENCODING ) ||
+ value.equals( COSName.STANDARD_ENCODING ) ||
+ value.equals( COSName.WIN_ANSI_ENCODING ) )
+ {
+ //value is expected to be one of the encodings
+ //ie. StandardEncoding,WinAnsiEncoding,MacRomanEncoding,PDFDocEncoding
+ retvalue = value;
+ }
+ }
+ }
+ }
+ }
+ }
+ return retvalue;
+ }
+
+ /**
+ * This will get the fonts bouding box.
+ *
+ * @return The fonts bouding box.
+ *
+ * @throws IOException If there is an error getting the bounding box.
+ */
+ public abstract PDRectangle getFontBoundingBox() throws IOException;
+
+ /**
+ * @see Object#equals( Object )
+ */
+ public boolean equals( Object other )
+ {
+ return other instanceof PDFont && ((PDFont)other).getCOSObject() == this.getCOSObject();
+ }
+
+ /**
+ * @see Object#hashCode()
+ */
+ public int hashCode()
+ {
+ return this.getCOSObject().hashCode();
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/font/PDFontDescriptor.java b/src/main/java/org/pdfbox/pdmodel/font/PDFontDescriptor.java
new file mode 100644
index 0000000..59668ce
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/font/PDFontDescriptor.java
@@ -0,0 +1,530 @@
+/**
+ * Copyright (c) 2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.font;
+
+import java.io.IOException;
+
+import org.pdfbox.pdmodel.common.PDRectangle;
+
+/**
+ * This class represents an interface to the font description. This will depend
+ * on the font type for the actual implementation. If it is a AFM/cmap/or embedded font.
+ *
+ * @author Ben Litchfield
+ * @version $Revision: 1.1 $
+ */
+public abstract class PDFontDescriptor
+{
+ /**
+ * A font descriptor flag. See PDF Reference for description.
+ */
+ private static final int FLAG_FIXED_PITCH = 1;
+ /**
+ * A font descriptor flag. See PDF Reference for description.
+ */
+ private static final int FLAG_SERIF = 2;
+ /**
+ * A font descriptor flag. See PDF Reference for description.
+ */
+ private static final int FLAG_SYMBOLIC = 3;
+ /**
+ * A font descriptor flag. See PDF Reference for description.
+ */
+ private static final int FLAG_SCRIPT = 4;
+ /**
+ * A font descriptor flag. See PDF Reference for description.
+ */
+ private static final int FLAG_NON_SYMBOLIC = 6;
+ /**
+ * A font descriptor flag. See PDF Reference for description.
+ */
+ private static final int FLAG_ITALIC = 7;
+ /**
+ * A font descriptor flag. See PDF Reference for description.
+ */
+ private static final int FLAG_ALL_CAP = 17;
+ /**
+ * A font descriptor flag. See PDF Reference for description.
+ */
+ private static final int FLAG_SMALL_CAP = 18;
+ /**
+ * A font descriptor flag. See PDF Reference for description.
+ */
+ private static final int FLAG_FORCE_BOLD = 19;
+
+
+ /**
+ * Get the font name.
+ *
+ * @return The name of the font.
+ */
+ public abstract String getFontName();
+
+ /**
+ * This will set the font name.
+ *
+ * @param fontName The new name for the font.
+ */
+ public abstract void setFontName( String fontName );
+
+ /**
+ * A string representing the preferred font family.
+ *
+ * @return The font family.
+ */
+ public abstract String getFontFamily();
+
+ /**
+ * This will set the font family.
+ *
+ * @param fontFamily The font family.
+ */
+ public abstract void setFontFamily( String fontFamily );
+
+ /**
+ * A string representing the preferred font stretch.
+ * According to the PDF Spec:
+ * The font stretch value; it must be one of the following (ordered from
+ * narrowest to widest): UltraCondensed, ExtraCondensed, Condensed, SemiCondensed,
+ * Normal, SemiExpanded, Expanded, ExtraExpanded or UltraExpanded.
+ *
+ * @return The font stretch.
+ */
+ public abstract String getFontStretch();
+
+ /**
+ * This will set the font stretch.
+ *
+ * @param fontStretch The font stretch
+ */
+ public abstract void setFontStretch( String fontStretch );
+
+ /**
+ * The weight of the font. According to the PDF spec "possible values are
+ * 100, 200, 300, 400, 500, 600, 700, 800 or 900" Where a higher number is
+ * more weight and appears to be more bold.
+ *
+ * @return The font weight.
+ */
+ public abstract float getFontWeight();
+
+ /**
+ * Set the weight of the font.
+ *
+ * @param fontWeight The new weight of the font.
+ */
+ public abstract void setFontWeight( float fontWeight );
+
+ /**
+ * This will get the font flags.
+ *
+ * @return The font flags.
+ */
+ public abstract int getFlags();
+
+ /**
+ * This will set the font flags.
+ *
+ * @param flags The new font flags.
+ */
+ public abstract void setFlags( int flags );
+
+ /**
+ * A convenience method that checks the flag bit.
+ *
+ * @return The flag value.
+ */
+ public boolean isFixedPitch()
+ {
+ return isFlagBitOn( FLAG_FIXED_PITCH );
+ }
+
+ /**
+ * A convenience method that sets the flag bit.
+ *
+ * @param flag The flag value.
+ */
+ public void setFixedPitch( boolean flag )
+ {
+ setFlagBit( FLAG_FIXED_PITCH, flag );
+ }
+
+ /**
+ * A convenience method that checks the flag bit.
+ *
+ * @return The flag value.
+ */
+ public boolean isSerif()
+ {
+ return isFlagBitOn( FLAG_SERIF );
+ }
+
+ /**
+ * A convenience method that sets the flag bit.
+ *
+ * @param flag The flag value.
+ */
+ public void setSerif( boolean flag )
+ {
+ setFlagBit( FLAG_SERIF, flag );
+ }
+
+ /**
+ * A convenience method that checks the flag bit.
+ *
+ * @return The flag value.
+ */
+ public boolean isSymbolic()
+ {
+ return isFlagBitOn( FLAG_SYMBOLIC );
+ }
+
+ /**
+ * A convenience method that sets the flag bit.
+ *
+ * @param flag The flag value.
+ */
+ public void setSymbolic( boolean flag )
+ {
+ setFlagBit( FLAG_SYMBOLIC, flag );
+ }
+
+ /**
+ * A convenience method that checks the flag bit.
+ *
+ * @return The flag value.
+ */
+ public boolean isScript()
+ {
+ return isFlagBitOn( FLAG_SCRIPT );
+ }
+
+ /**
+ * A convenience method that sets the flag bit.
+ *
+ * @param flag The flag value.
+ */
+ public void setScript( boolean flag )
+ {
+ setFlagBit( FLAG_SCRIPT, flag );
+ }
+
+ /**
+ * A convenience method that checks the flag bit.
+ *
+ * @return The flag value.
+ */
+ public boolean isNonSymbolic()
+ {
+ return isFlagBitOn( FLAG_NON_SYMBOLIC );
+ }
+
+ /**
+ * A convenience method that sets the flag bit.
+ *
+ * @param flag The flag value.
+ */
+ public void setNonSymbolic( boolean flag )
+ {
+ setFlagBit( FLAG_NON_SYMBOLIC, flag );
+ }
+
+ /**
+ * A convenience method that checks the flag bit.
+ *
+ * @return The flag value.
+ */
+ public boolean isItalic()
+ {
+ return isFlagBitOn( FLAG_ITALIC );
+ }
+
+ /**
+ * A convenience method that sets the flag bit.
+ *
+ * @param flag The flag value.
+ */
+ public void setItalic( boolean flag )
+ {
+ setFlagBit( FLAG_ITALIC, flag );
+ }
+
+ /**
+ * A convenience method that checks the flag bit.
+ *
+ * @return The flag value.
+ */
+ public boolean isAllCap()
+ {
+ return isFlagBitOn( FLAG_ALL_CAP);
+ }
+
+ /**
+ * A convenience method that sets the flag bit.
+ *
+ * @param flag The flag value.
+ */
+ public void setAllCap( boolean flag )
+ {
+ setFlagBit( FLAG_ALL_CAP, flag );
+ }
+
+ /**
+ * A convenience method that checks the flag bit.
+ *
+ * @return The flag value.
+ */
+ public boolean isSmallCap()
+ {
+ return isFlagBitOn( FLAG_SMALL_CAP );
+ }
+
+ /**
+ * A convenience method that sets the flag bit.
+ *
+ * @param flag The flag value.
+ */
+ public void setSmallCap( boolean flag )
+ {
+ setFlagBit( FLAG_SMALL_CAP, flag );
+ }
+
+ /**
+ * A convenience method that checks the flag bit.
+ *
+ * @return The flag value.
+ */
+ public boolean isForceBold()
+ {
+ return isFlagBitOn( FLAG_FORCE_BOLD );
+ }
+
+ /**
+ * A convenience method that sets the flag bit.
+ *
+ * @param flag The flag value.
+ */
+ public void setForceBold( boolean flag )
+ {
+ setFlagBit( FLAG_FORCE_BOLD, flag );
+ }
+
+ private boolean isFlagBitOn( int bit )
+ {
+ return (getFlags() & (1 << (bit-1))) != 0;
+ }
+
+ private void setFlagBit( int bit, boolean value )
+ {
+ int flags = getFlags();
+ if( value )
+ {
+ flags = flags| (1 << (bit-1));
+ }
+ else
+ {
+ flags = flags & (0xFFFFFFFF ^ (1 << (bit-1)));
+ }
+ setFlags( flags );
+ }
+
+ /**
+ * This will get the fonts bouding box.
+ *
+ * @return The fonts bouding box.
+ */
+ public abstract PDRectangle getFontBoundingBox();
+
+ /**
+ * Set the fonts bounding box.
+ *
+ * @param rect The new bouding box.
+ */
+ public abstract void setFontBoundingBox( PDRectangle rect );
+
+ /**
+ * This will get the italic angle for the font.
+ *
+ * @return The italic angle.
+ */
+ public abstract float getItalicAngle();
+
+ /**
+ * This will set the italic angle for the font.
+ *
+ * @param angle The new italic angle for the font.
+ */
+ public abstract void setItalicAngle( float angle );
+
+ /**
+ * This will get the ascent for the font.
+ *
+ * @return The ascent.
+ */
+ public abstract float getAscent();
+
+ /**
+ * This will set the ascent for the font.
+ *
+ * @param ascent The new ascent for the font.
+ */
+ public abstract void setAscent( float ascent );
+
+ /**
+ * This will get the descent for the font.
+ *
+ * @return The descent.
+ */
+ public abstract float getDescent();
+
+ /**
+ * This will set the descent for the font.
+ *
+ * @param descent The new descent for the font.
+ */
+ public abstract void setDescent( float descent );
+
+ /**
+ * This will get the leading for the font.
+ *
+ * @return The leading.
+ */
+ public abstract float getLeading();
+
+ /**
+ * This will set the leading for the font.
+ *
+ * @param leading The new leading for the font.
+ */
+ public abstract void setLeading( float leading );
+
+ /**
+ * This will get the CapHeight for the font.
+ *
+ * @return The cap height.
+ */
+ public abstract float getCapHeight();
+
+ /**
+ * This will set the cap height for the font.
+ *
+ * @param capHeight The new cap height for the font.
+ */
+ public abstract void setCapHeight( float capHeight );
+
+ /**
+ * This will get the x height for the font.
+ *
+ * @return The x height.
+ */
+ public abstract float getXHeight();
+
+ /**
+ * This will set the x height for the font.
+ *
+ * @param xHeight The new x height for the font.
+ */
+ public abstract void setXHeight( float xHeight );
+
+ /**
+ * This will get the stemV for the font.
+ *
+ * @return The stem v value.
+ */
+ public abstract float getStemV();
+
+ /**
+ * This will set the stem V for the font.
+ *
+ * @param stemV The new stem v for the font.
+ */
+ public abstract void setStemV( float stemV );
+
+ /**
+ * This will get the stemH for the font.
+ *
+ * @return The stem h value.
+ */
+ public abstract float getStemH();
+
+ /**
+ * This will set the stem H for the font.
+ *
+ * @param stemH The new stem h for the font.
+ */
+ public abstract void setStemH( float stemH );
+
+ /**
+ * This will get the average width for the font. This is part of the
+ * definition in the font description. If it is not present then PDFBox
+ * will make an attempt to calculate it.
+ *
+ * @return The average width value.
+ *
+ * @throws IOException If there is an error calculating the average width.
+ */
+ public abstract float getAverageWidth() throws IOException;
+
+ /**
+ * This will set the average width for the font.
+ *
+ * @param averageWidth The new average width for the font.
+ */
+ public abstract void setAverageWidth( float averageWidth );
+
+ /**
+ * This will get the max width for the font.
+ *
+ * @return The max width value.
+ */
+ public abstract float getMaxWidth();
+
+ /**
+ * This will set the max width for the font.
+ *
+ * @param maxWidth The new max width for the font.
+ */
+ public abstract void setMaxWidth( float maxWidth );
+
+ /**
+ * This will get the character set for the font.
+ *
+ * @return The character set value.
+ */
+ public abstract String getCharSet();
+
+ /**
+ * This will set the character set for the font.
+ *
+ * @param charSet The new character set for the font.
+ */
+ public abstract void setCharacterSet( String charSet );
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/font/PDFontDescriptorAFM.java b/src/main/java/org/pdfbox/pdmodel/font/PDFontDescriptorAFM.java
new file mode 100644
index 0000000..3326b74
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/font/PDFontDescriptorAFM.java
@@ -0,0 +1,446 @@
+/**
+ * Copyright (c) 2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.font;
+
+import java.io.IOException;
+
+import org.pdfbox.afmtypes.FontMetric;
+
+import org.pdfbox.pdmodel.common.PDRectangle;
+
+import org.pdfbox.util.BoundingBox;
+
+/**
+ * This class represents the font descriptor when the font information
+ * is coming from an AFM file.
+ *
+ * @author Ben Litchfield
+ * @version $Revision: 1.1 $
+ */
+public class PDFontDescriptorAFM extends PDFontDescriptor
+{
+ private FontMetric afm;
+
+ /**
+ * Constructor.
+ *
+ * @param afmFile The AFM file.
+ */
+ public PDFontDescriptorAFM( FontMetric afmFile )
+ {
+ afm = afmFile;
+ }
+
+ /**
+ * Get the font name.
+ *
+ * @return The name of the font.
+ */
+ public String getFontName()
+ {
+ return afm.getFontName();
+ }
+
+ /**
+ * This will set the font name.
+ *
+ * @param fontName The new name for the font.
+ */
+ public void setFontName( String fontName )
+ {
+ throw new UnsupportedOperationException( "The AFM Font descriptor is immutable" );
+ }
+
+ /**
+ * A string representing the preferred font family.
+ *
+ * @return The font family.
+ */
+ public String getFontFamily()
+ {
+ return afm.getFamilyName();
+ }
+
+ /**
+ * This will set the font family.
+ *
+ * @param fontFamily The font family.
+ */
+ public void setFontFamily( String fontFamily )
+ {
+ throw new UnsupportedOperationException( "The AFM Font descriptor is immutable" );
+ }
+
+ /**
+ * The weight of the font. According to the PDF spec "possible values are
+ * 100, 200, 300, 400, 500, 600, 700, 800 or 900" Where a higher number is
+ * more weight and appears to be more bold.
+ *
+ * @return The font weight.
+ */
+ public float getFontWeight()
+ {
+ String weight = afm.getWeight();
+ float retval = 500;
+ if( weight != null && weight.equalsIgnoreCase( "bold" ) )
+ {
+ retval = 900;
+ }
+ else if( weight != null && weight.equalsIgnoreCase( "light" ) )
+ {
+ retval = 100;
+ }
+ return retval;
+ }
+
+ /**
+ * Set the weight of the font.
+ *
+ * @param fontWeight The new weight of the font.
+ */
+ public void setFontWeight( float fontWeight )
+ {
+ throw new UnsupportedOperationException( "The AFM Font descriptor is immutable" );
+ }
+
+ /**
+ * A string representing the preferred font stretch.
+ *
+ * @return The font stretch.
+ */
+ public String getFontStretch()
+ {
+ return null;
+ }
+
+ /**
+ * This will set the font stretch.
+ *
+ * @param fontStretch The font stretch
+ */
+ public void setFontStretch( String fontStretch )
+ {
+ throw new UnsupportedOperationException( "The AFM Font descriptor is immutable" );
+ }
+
+ /**
+ * This will get the font flags.
+ *
+ * @return The font flags.
+ */
+ public int getFlags()
+ {
+ //I believe that the only flag that AFM supports is the is fixed pitch
+ return afm.isFixedPitch() ? 1 : 0;
+ }
+
+ /**
+ * This will set the font flags.
+ *
+ * @param flags The new font flags.
+ */
+ public void setFlags( int flags )
+ {
+ throw new UnsupportedOperationException( "The AFM Font descriptor is immutable" );
+ }
+
+ /**
+ * This will get the fonts bouding box.
+ *
+ * @return The fonts bouding box.
+ */
+ public PDRectangle getFontBoundingBox()
+ {
+ BoundingBox box = afm.getFontBBox();
+ PDRectangle retval = null;
+ if( box != null )
+ {
+ retval = new PDRectangle( box );
+ }
+ return retval;
+ }
+
+ /**
+ * Set the fonts bounding box.
+ *
+ * @param rect The new bouding box.
+ */
+ public void setFontBoundingBox( PDRectangle rect )
+ {
+ throw new UnsupportedOperationException( "The AFM Font descriptor is immutable" );
+ }
+
+ /**
+ * This will get the italic angle for the font.
+ *
+ * @return The italic angle.
+ */
+ public float getItalicAngle()
+ {
+ return afm.getItalicAngle();
+ }
+
+ /**
+ * This will set the italic angle for the font.
+ *
+ * @param angle The new italic angle for the font.
+ */
+ public void setItalicAngle( float angle )
+ {
+ throw new UnsupportedOperationException( "The AFM Font descriptor is immutable" );
+ }
+
+ /**
+ * This will get the ascent for the font.
+ *
+ * @return The ascent.
+ */
+ public float getAscent()
+ {
+ return afm.getAscender();
+ }
+
+ /**
+ * This will set the ascent for the font.
+ *
+ * @param ascent The new ascent for the font.
+ */
+ public void setAscent( float ascent )
+ {
+ throw new UnsupportedOperationException( "The AFM Font descriptor is immutable" );
+ }
+
+ /**
+ * This will get the descent for the font.
+ *
+ * @return The descent.
+ */
+ public float getDescent()
+ {
+ return afm.getDescender();
+ }
+
+ /**
+ * This will set the descent for the font.
+ *
+ * @param descent The new descent for the font.
+ */
+ public void setDescent( float descent )
+ {
+ throw new UnsupportedOperationException( "The AFM Font descriptor is immutable" );
+ }
+
+ /**
+ * This will get the leading for the font.
+ *
+ * @return The leading.
+ */
+ public float getLeading()
+ {
+ //AFM does not support setting the leading so we will just ignore it.
+ return 0f;
+ }
+
+ /**
+ * This will set the leading for the font.
+ *
+ * @param leading The new leading for the font.
+ */
+ public void setLeading( float leading )
+ {
+ throw new UnsupportedOperationException( "The AFM Font descriptor is immutable" );
+ }
+
+ /**
+ * This will get the CapHeight for the font.
+ *
+ * @return The cap height.
+ */
+ public float getCapHeight()
+ {
+ return afm.getCapHeight();
+ }
+
+ /**
+ * This will set the cap height for the font.
+ *
+ * @param capHeight The new cap height for the font.
+ */
+ public void setCapHeight( float capHeight )
+ {
+ throw new UnsupportedOperationException( "The AFM Font descriptor is immutable" );
+ }
+
+ /**
+ * This will get the x height for the font.
+ *
+ * @return The x height.
+ */
+ public float getXHeight()
+ {
+ return afm.getXHeight();
+ }
+
+ /**
+ * This will set the x height for the font.
+ *
+ * @param xHeight The new x height for the font.
+ */
+ public void setXHeight( float xHeight )
+ {
+ throw new UnsupportedOperationException( "The AFM Font descriptor is immutable" );
+ }
+
+ /**
+ * This will get the stemV for the font.
+ *
+ * @return The stem v value.
+ */
+ public float getStemV()
+ {
+ //afm does not have a stem v
+ return 0;
+ }
+
+ /**
+ * This will set the stem V for the font.
+ *
+ * @param stemV The new stem v for the font.
+ */
+ public void setStemV( float stemV )
+ {
+ throw new UnsupportedOperationException( "The AFM Font descriptor is immutable" );
+ }
+
+ /**
+ * This will get the stemH for the font.
+ *
+ * @return The stem h value.
+ */
+ public float getStemH()
+ {
+ //afm does not have a stem h
+ return 0;
+ }
+
+ /**
+ * This will set the stem H for the font.
+ *
+ * @param stemH The new stem h for the font.
+ */
+ public void setStemH( float stemH )
+ {
+ throw new UnsupportedOperationException( "The AFM Font descriptor is immutable" );
+ }
+
+ /**
+ * This will get the average width for the font.
+ *
+ * @return The average width value.
+ *
+ * @throws IOException If there is an error calculating the average width.
+ */
+ public float getAverageWidth() throws IOException
+ {
+ return afm.getAverageCharacterWidth();
+ }
+
+ /**
+ * This will set the average width for the font.
+ *
+ * @param averageWidth The new average width for the font.
+ */
+ public void setAverageWidth( float averageWidth )
+ {
+ throw new UnsupportedOperationException( "The AFM Font descriptor is immutable" );
+ }
+
+ /**
+ * This will get the max width for the font.
+ *
+ * @return The max width value.
+ */
+ public float getMaxWidth()
+ {
+ //afm does not support max width;
+ return 0;
+ }
+
+ /**
+ * This will set the max width for the font.
+ *
+ * @param maxWidth The new max width for the font.
+ */
+ public void setMaxWidth( float maxWidth )
+ {
+ throw new UnsupportedOperationException( "The AFM Font descriptor is immutable" );
+ }
+
+ /**
+ * This will get the missing width for the font.
+ *
+ * @return The missing width value.
+ */
+ public float getMissingWidth()
+ {
+ return 0;
+ }
+
+ /**
+ * This will set the missing width for the font.
+ *
+ * @param missingWidth The new missing width for the font.
+ */
+ public void setMissingWidth( float missingWidth )
+ {
+ throw new UnsupportedOperationException( "The AFM Font descriptor is immutable" );
+ }
+
+ /**
+ * This will get the character set for the font.
+ *
+ * @return The character set value.
+ */
+ public String getCharSet()
+ {
+ return afm.getCharacterSet();
+ }
+
+ /**
+ * This will set the character set for the font.
+ *
+ * @param charSet The new character set for the font.
+ */
+ public void setCharacterSet( String charSet )
+ {
+ throw new UnsupportedOperationException( "The AFM Font descriptor is immutable" );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/font/PDFontDescriptorDictionary.java b/src/main/java/org/pdfbox/pdmodel/font/PDFontDescriptorDictionary.java
new file mode 100644
index 0000000..f3bf61e
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/font/PDFontDescriptorDictionary.java
@@ -0,0 +1,580 @@
+/**
+ * Copyright (c) 2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.font;
+
+import org.pdfbox.cos.COSArray;
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSName;
+import org.pdfbox.cos.COSString;
+import org.pdfbox.cos.COSStream;
+
+import org.pdfbox.pdmodel.common.PDRectangle;
+import org.pdfbox.pdmodel.common.PDStream;
+
+/**
+ * This class represents an implementation to the font descriptor that gets its
+ * information from a COS Dictionary.
+ *
+ * @author Ben Litchfield
+ * @version $Revision: 1.2 $
+ */
+public class PDFontDescriptorDictionary extends PDFontDescriptor
+{
+ private COSDictionary dic;
+
+ /**
+ * Constructor.
+ */
+ public PDFontDescriptorDictionary()
+ {
+ dic = new COSDictionary();
+ dic.setName( "Type", "FontDescriptor" );
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param desc The wrapped COS Dictionary.
+ */
+ public PDFontDescriptorDictionary( COSDictionary desc )
+ {
+ dic = desc;
+ }
+
+ /**
+ * This will get the dictionary for this object.
+ *
+ * @return The COS dictionary.
+ */
+ public COSDictionary getCOSDictionary()
+ {
+ return dic;
+ }
+
+ /**
+ * Get the font name.
+ *
+ * @return The name of the font.
+ */
+ public String getFontName()
+ {
+ String retval = null;
+ COSName name = (COSName)dic.getDictionaryObject( COSName.getPDFName( "FontName" ) );
+ if( name != null )
+ {
+ retval = name.getName();
+ }
+ return retval;
+ }
+
+ /**
+ * This will set the font name.
+ *
+ * @param fontName The new name for the font.
+ */
+ public void setFontName( String fontName )
+ {
+ COSName name = null;
+ if( fontName != null )
+ {
+ name = COSName.getPDFName( fontName );
+ }
+ dic.setItem( COSName.getPDFName( "FontName" ), name );
+ }
+
+ /**
+ * A string representing the preferred font family.
+ *
+ * @return The font family.
+ */
+ public String getFontFamily()
+ {
+ String retval = null;
+ COSString name = (COSString)dic.getDictionaryObject( COSName.getPDFName( "FontFamily" ) );
+ if( name != null )
+ {
+ retval = name.getString();
+ }
+ return retval;
+ }
+
+ /**
+ * This will set the font family.
+ *
+ * @param fontFamily The font family.
+ */
+ public void setFontFamily( String fontFamily )
+ {
+ COSString name = null;
+ if( fontFamily != null )
+ {
+ name = new COSString( fontFamily );
+ }
+ dic.setItem( COSName.getPDFName( "FontFamily" ), name );
+ }
+
+ /**
+ * The weight of the font. According to the PDF spec "possible values are
+ * 100, 200, 300, 400, 500, 600, 700, 800 or 900" Where a higher number is
+ * more weight and appears to be more bold.
+ *
+ * @return The font weight.
+ */
+ public float getFontWeight()
+ {
+ return dic.getFloat( "FontWeight",0 );
+ }
+
+ /**
+ * Set the weight of the font.
+ *
+ * @param fontWeight The new weight of the font.
+ */
+ public void setFontWeight( float fontWeight )
+ {
+ dic.setFloat( "FontWeight", fontWeight );
+ }
+
+ /**
+ * A string representing the preferred font stretch.
+ * According to the PDF Spec:
+ * The font stretch value; it must be one of the following (ordered from
+ * narrowest to widest): UltraCondensed, ExtraCondensed, Condensed, SemiCondensed,
+ * Normal, SemiExpanded, Expanded, ExtraExpanded or UltraExpanded.
+ *
+ * @return The stretch of the font.
+ */
+ public String getFontStretch()
+ {
+ String retval = null;
+ COSName name = (COSName)dic.getDictionaryObject( COSName.getPDFName( "FontStretch" ) );
+ if( name != null )
+ {
+ retval = name.getName();
+ }
+ return retval;
+ }
+
+ /**
+ * This will set the font stretch.
+ *
+ * @param fontStretch The new stretch for the font.
+ */
+ public void setFontStretch( String fontStretch )
+ {
+ COSName name = null;
+ if( fontStretch != null )
+ {
+ name = COSName.getPDFName( fontStretch );
+ }
+ dic.setItem( COSName.getPDFName( "FontStretch" ), name );
+ }
+
+ /**
+ * This will get the font flags.
+ *
+ * @return The font flags.
+ */
+ public int getFlags()
+ {
+ return dic.getInt( "Flags", 0 );
+ }
+
+ /**
+ * This will set the font flags.
+ *
+ * @param flags The new font flags.
+ */
+ public void setFlags( int flags )
+ {
+ dic.setInt( "Flags", flags );
+ }
+
+ /**
+ * This will get the fonts bouding box.
+ *
+ * @return The fonts bouding box.
+ */
+ public PDRectangle getFontBoundingBox()
+ {
+ COSArray rect = (COSArray)dic.getDictionaryObject( COSName.getPDFName( "FontBBox" ) );
+ PDRectangle retval = null;
+ if( rect != null )
+ {
+ retval = new PDRectangle( rect );
+ }
+ return retval;
+ }
+
+ /**
+ * Set the fonts bounding box.
+ *
+ * @param rect The new bouding box.
+ */
+ public void setFontBoundingBox( PDRectangle rect )
+ {
+ COSArray array = null;
+ if( rect != null )
+ {
+ array = rect.getCOSArray();
+ }
+ dic.setItem( COSName.getPDFName( "FontBBox" ), array );
+ }
+
+ /**
+ * This will get the italic angle for the font.
+ *
+ * @return The italic angle.
+ */
+ public float getItalicAngle()
+ {
+ return dic.getFloat( "ItalicAngle", 0 );
+ }
+
+ /**
+ * This will set the italic angle for the font.
+ *
+ * @param angle The new italic angle for the font.
+ */
+ public void setItalicAngle( float angle )
+ {
+ dic.setFloat( "ItalicAngle", angle );
+ }
+
+ /**
+ * This will get the ascent for the font.
+ *
+ * @return The ascent.
+ */
+ public float getAscent()
+ {
+ return dic.getFloat( "Ascent", 0 );
+ }
+
+ /**
+ * This will set the ascent for the font.
+ *
+ * @param ascent The new ascent for the font.
+ */
+ public void setAscent( float ascent )
+ {
+ dic.setFloat( "Ascent", ascent );
+ }
+
+ /**
+ * This will get the descent for the font.
+ *
+ * @return The descent.
+ */
+ public float getDescent()
+ {
+ return dic.getFloat( "Descent", 0 );
+ }
+
+ /**
+ * This will set the descent for the font.
+ *
+ * @param descent The new descent for the font.
+ */
+ public void setDescent( float descent )
+ {
+ dic.setFloat( "Descent", descent );
+ }
+
+ /**
+ * This will get the leading for the font.
+ *
+ * @return The leading.
+ */
+ public float getLeading()
+ {
+ return dic.getFloat( "Leading", 0 );
+ }
+
+ /**
+ * This will set the leading for the font.
+ *
+ * @param leading The new leading for the font.
+ */
+ public void setLeading( float leading )
+ {
+ dic.setFloat( "Leading", leading );
+ }
+
+ /**
+ * This will get the CapHeight for the font.
+ *
+ * @return The cap height.
+ */
+ public float getCapHeight()
+ {
+ return dic.getFloat( "CapHeight", 0 );
+ }
+
+ /**
+ * This will set the cap height for the font.
+ *
+ * @param capHeight The new cap height for the font.
+ */
+ public void setCapHeight( float capHeight )
+ {
+ dic.setFloat( "CapHeight", capHeight );
+ }
+
+ /**
+ * This will get the x height for the font.
+ *
+ * @return The x height.
+ */
+ public float getXHeight()
+ {
+ return dic.getFloat( "XHeight", 0 );
+ }
+
+ /**
+ * This will set the x height for the font.
+ *
+ * @param xHeight The new x height for the font.
+ */
+ public void setXHeight( float xHeight )
+ {
+ dic.setFloat( "XHeight", xHeight );
+ }
+
+ /**
+ * This will get the stemV for the font.
+ *
+ * @return The stem v value.
+ */
+ public float getStemV()
+ {
+ return dic.getFloat( "StemV", 0 );
+ }
+
+ /**
+ * This will set the stem V for the font.
+ *
+ * @param stemV The new stem v for the font.
+ */
+ public void setStemV( float stemV )
+ {
+ dic.setFloat( "StemV", stemV );
+ }
+
+ /**
+ * This will get the stemH for the font.
+ *
+ * @return The stem h value.
+ */
+ public float getStemH()
+ {
+ return dic.getFloat( "StemH", 0 );
+ }
+
+ /**
+ * This will set the stem H for the font.
+ *
+ * @param stemH The new stem h for the font.
+ */
+ public void setStemH( float stemH )
+ {
+ dic.setFloat( "StemH", stemH );
+ }
+
+ /**
+ * This will get the average width for the font.
+ *
+ * @return The average width value.
+ */
+ public float getAverageWidth()
+ {
+ return dic.getFloat( "AvgWidth", 0 );
+ }
+
+ /**
+ * This will set the average width for the font.
+ *
+ * @param averageWidth The new average width for the font.
+ */
+ public void setAverageWidth( float averageWidth )
+ {
+ dic.setFloat( "AvgWidth", averageWidth );
+ }
+
+ /**
+ * This will get the max width for the font.
+ *
+ * @return The max width value.
+ */
+ public float getMaxWidth()
+ {
+ return dic.getFloat( "MaxWidth", 0 );
+ }
+
+ /**
+ * This will set the max width for the font.
+ *
+ * @param maxWidth The new max width for the font.
+ */
+ public void setMaxWidth( float maxWidth )
+ {
+ dic.setFloat( "MaxWidth", maxWidth );
+ }
+
+ /**
+ * This will get the missing width for the font.
+ *
+ * @return The missing width value.
+ */
+ public float getMissingWidth()
+ {
+ return dic.getFloat( "MissingWidth", 0 );
+ }
+
+ /**
+ * This will set the missing width for the font.
+ *
+ * @param missingWidth The new missing width for the font.
+ */
+ public void setMissingWidth( float missingWidth )
+ {
+ dic.setFloat( "MissingWidth", missingWidth );
+ }
+
+ /**
+ * This will get the character set for the font.
+ *
+ * @return The character set value.
+ */
+ public String getCharSet()
+ {
+ String retval = null;
+ COSString name = (COSString)dic.getDictionaryObject( COSName.getPDFName( "CharSet" ) );
+ if( name != null )
+ {
+ retval = name.getString();
+ }
+ return retval;
+ }
+
+ /**
+ * This will set the character set for the font.
+ *
+ * @param charSet The new character set for the font.
+ */
+ public void setCharacterSet( String charSet )
+ {
+ COSString name = null;
+ if( charSet != null )
+ {
+ name = new COSString( charSet );
+ }
+ dic.setItem( COSName.getPDFName( "CharSet" ), name );
+ }
+
+ /**
+ * A stream containing a Type 1 font program.
+ *
+ * @return A stream containing a Type 1 font program.
+ */
+ public PDStream getFontFile()
+ {
+ PDStream retval = null;
+ COSStream stream = (COSStream)dic.getDictionaryObject( "FontFile" );
+ if( stream != null )
+ {
+ retval = new PDStream( stream );
+ }
+ return retval;
+ }
+
+ /**
+ * Set the type 1 font program.
+ *
+ * @param type1Stream The type 1 stream.
+ */
+ public void setFontFile( PDStream type1Stream )
+ {
+ dic.setItem( "FontFile", type1Stream );
+ }
+
+ /**
+ * A stream containing a true type font program.
+ *
+ * @return A stream containing a true type font program.
+ */
+ public PDStream getFontFile2()
+ {
+ PDStream retval = null;
+ COSStream stream = (COSStream)dic.getDictionaryObject( "FontFile2" );
+ if( stream != null )
+ {
+ retval = new PDStream( stream );
+ }
+ return retval;
+ }
+
+ /**
+ * Set the true type font program.
+ *
+ * @param ttfStream The true type stream.
+ */
+ public void setFontFile2( PDStream ttfStream )
+ {
+ dic.setItem( "FontFile2", ttfStream );
+ }
+
+ /**
+ * A stream containing a font program that is not true type or type 1.
+ *
+ * @return A stream containing a font program.
+ */
+ public PDStream getFontFile3()
+ {
+ PDStream retval = null;
+ COSStream stream = (COSStream)dic.getDictionaryObject( "FontFile3" );
+ if( stream != null )
+ {
+ retval = new PDStream( stream );
+ }
+ return retval;
+ }
+
+ /**
+ * Set a stream containing a font program that is not true type or type 1.
+ *
+ * @param stream The font program stream.
+ */
+ public void setFontFile3( PDStream stream )
+ {
+ dic.setItem( "FontFile3", stream );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/font/PDFontFactory.java b/src/main/java/org/pdfbox/pdmodel/font/PDFontFactory.java
new file mode 100644
index 0000000..329a8bf
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/font/PDFontFactory.java
@@ -0,0 +1,108 @@
+/**
+ * Copyright (c) 2003, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.font;
+
+import java.io.IOException;
+
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSName;
+
+/**
+ * This will create the correct type of font based on information in the dictionary.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.4 $
+ */
+public class PDFontFactory
+{
+ /**
+ * private constructor, should only use static methods in this class.
+ */
+ private PDFontFactory()
+ {
+ }
+
+ /**
+ * This will create the correct font based on information in the dictionary.
+ *
+ * @param dic The populated dictionary.
+ *
+ * @return The corrent implementation for the font.
+ *
+ * @throws IOException If the dictionary is not valid.
+ */
+ public static PDFont createFont( COSDictionary dic ) throws IOException
+ {
+ PDFont retval = null;
+
+ COSName type = (COSName)dic.getDictionaryObject( COSName.TYPE );
+ if( !type.equals( COSName.FONT ) )
+ {
+ throw new IOException( "Cannot create font if /Type is not /Font. Actual=" +type );
+ }
+
+ COSName subType = (COSName)dic.getDictionaryObject( COSName.SUBTYPE );
+ if( subType.equals( COSName.getPDFName( "Type1" ) ) )
+ {
+ retval = new PDType1Font( dic );
+ }
+ else if( subType.equals( COSName.getPDFName( "MMType1" ) ) )
+ {
+ retval = new PDMMType1Font( dic );
+ }
+ else if( subType.equals( COSName.getPDFName( "TrueType" ) ) )
+ {
+ retval = new PDTrueTypeFont( dic );
+ }
+ else if( subType.equals( COSName.getPDFName( "Type3" ) ) )
+ {
+ retval = new PDType3Font( dic );
+ }
+ else if( subType.equals( COSName.getPDFName( "Type0" ) ) )
+ {
+ retval = new PDType0Font( dic );
+ }
+ else if( subType.equals( COSName.getPDFName( "CIDFontType0" ) ) )
+ {
+ retval = new PDCIDFontType0Font( dic );
+ }
+ else if( subType.equals( COSName.getPDFName( "CIDFontType2" ) ) )
+ {
+ retval = new PDCIDFontType2Font( dic );
+ }
+ else
+ {
+ throw new IOException( "Unknown font subtype=" + subType );
+ }
+
+ return retval;
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/font/PDMMType1Font.java b/src/main/java/org/pdfbox/pdmodel/font/PDMMType1Font.java
new file mode 100644
index 0000000..a0dffba
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/font/PDMMType1Font.java
@@ -0,0 +1,62 @@
+/**
+ * Copyright (c) 2003, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.font;
+
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSName;
+
+/**
+ * This is implementation of the Multiple Master Type1 Font.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.3 $
+ */
+public class PDMMType1Font extends PDSimpleFont
+{
+ /**
+ * Constructor.
+ */
+ public PDMMType1Font()
+ {
+ super();
+ font.setItem( COSName.SUBTYPE, COSName.getPDFName( "MMType1" ) );
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param fontDictionary The font dictionary according to the PDF specification.
+ */
+ public PDMMType1Font( COSDictionary fontDictionary )
+ {
+ super( fontDictionary );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/font/PDSimpleFont.java b/src/main/java/org/pdfbox/pdmodel/font/PDSimpleFont.java
new file mode 100644
index 0000000..a1356ba
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/font/PDSimpleFont.java
@@ -0,0 +1,239 @@
+/**
+ * Copyright (c) 2003-2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.font;
+
+import java.awt.Graphics;
+
+import java.io.IOException;
+
+import org.apache.log4j.Logger;
+import org.pdfbox.afmtypes.FontMetric;
+
+import org.pdfbox.cos.COSArray;
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSName;
+import org.pdfbox.cos.COSNumber;
+import org.pdfbox.cos.COSInteger;
+
+import org.pdfbox.pdmodel.common.PDRectangle;
+import org.pdfbox.pdmodel.common.PDStream;
+
+/**
+ * This class contains implementation details of the simple pdf fonts.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.11 $
+ */
+public abstract class PDSimpleFont extends PDFont
+{
+ private static Logger log = Logger.getLogger( PDSimpleFont.class );
+ /**
+ * Constructor.
+ */
+ public PDSimpleFont()
+ {
+ super();
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param fontDictionary The font dictionary according to the PDF specification.
+ */
+ public PDSimpleFont( COSDictionary fontDictionary )
+ {
+ super( fontDictionary );
+ }
+
+ /**
+ * @see PDFont#drawString( String, Graphics, float, float, float, float, float )
+ */
+ public void drawString( String string, Graphics g, float fontSize,
+ float xScale, float yScale, float x, float y ) throws IOException
+ {
+ log.warn( "Not yet implemented:" + getClass().getName() );
+ }
+
+ /**
+ * This will get the font width for a character.
+ *
+ * @param c The character code to get the width for.
+ * @param offset The offset into the array.
+ * @param length The length of the data.
+ *
+ * @return The width is in 1000 unit of text space, ie 333 or 777
+ *
+ * @throws IOException If an error occurs while parsing.
+ */
+ public float getFontWidth( byte[] c, int offset, int length ) throws IOException
+ {
+ float fontWidth = 0;
+ int code = getCodeFromArray( c, offset, length );
+
+ //hmm should this be in a subclass??
+ COSInteger firstChar = (COSInteger)font.getDictionaryObject( COSName.FIRST_CHAR );
+ COSInteger lastChar = (COSInteger)font.getDictionaryObject( COSName.LAST_CHAR );
+ if( firstChar != null && lastChar != null )
+ {
+ long first = firstChar.intValue();
+ long last = lastChar.intValue();
+ if( code >= first && code <= last && font.getDictionaryObject( COSName.WIDTHS ) != null )
+ {
+ COSArray widthArray = (COSArray)font.getDictionaryObject( COSName.WIDTHS );
+ COSNumber fontWidthObject = (COSNumber)widthArray.get( (int)(code - first) );
+ fontWidth = fontWidthObject.floatValue();
+ }
+ else
+ {
+ fontWidth = getFontWidthFromAFMFile( code );
+ }
+ }
+ else
+ {
+ fontWidth = getFontWidthFromAFMFile( code );
+ }
+ return fontWidth;
+ }
+
+ /**
+ * This will get the average font width for all characters.
+ *
+ * @return The width is in 1000 unit of text space, ie 333 or 777
+ *
+ * @throws IOException If an error occurs while parsing.
+ */
+ public float getAverageFontWidth() throws IOException
+ {
+ float average = 0.0f;
+ float totalWidth = 0.0f;
+ float characterCount = 0.0f;
+ COSArray widths = (COSArray)font.getDictionaryObject( COSName.WIDTHS );
+ if( widths != null )
+ {
+ for( int i=0; i<widths.size(); i++ )
+ {
+ COSNumber fontWidth = (COSNumber)widths.getObject( i );
+ if( fontWidth.floatValue() > 0 )
+ {
+ totalWidth += fontWidth.floatValue();
+ characterCount += 1;
+ }
+ }
+ }
+
+ if( totalWidth > 0 )
+ {
+ average = totalWidth / characterCount;
+ }
+ else
+ {
+ average = getAverageFontWidthFromAFMFile();
+ }
+ return average;
+ }
+
+ /**
+ * This will get the font descriptor for this font.
+ *
+ * @return The font descriptor for this font.
+ *
+ * @throws IOException If there is an error parsing an AFM file, or unable to
+ * create a PDFontDescriptor object.
+ */
+ public PDFontDescriptor getFontDescriptor() throws IOException
+ {
+ PDFontDescriptor retval = null;
+ COSDictionary fd = (COSDictionary)font.getDictionaryObject( COSName.getPDFName( "FontDescriptor" ) );
+ if( fd == null )
+ {
+ FontMetric afm = getAFM();
+ if( afm == null )
+ {
+ throw new IOException( "Error: Can't create font descriptor file" );
+ }
+ retval = new PDFontDescriptorAFM( afm );
+ }
+ else
+ {
+ retval = new PDFontDescriptorDictionary( fd );
+ }
+
+ return retval;
+ }
+
+ /**
+ * This will set the font descriptor.
+ *
+ * @param fontDescriptor The font descriptor.
+ */
+ public void setFontDescriptor( PDFontDescriptorDictionary fontDescriptor )
+ {
+ COSDictionary dic = null;
+ if( fontDescriptor != null )
+ {
+ dic = fontDescriptor.getCOSDictionary();
+ }
+ font.setItem( COSName.getPDFName( "FontDescriptor" ), dic );
+ }
+
+ /**
+ * This will get the ToUnicode stream.
+ *
+ * @return The ToUnicode stream.
+ * @throws IOException If there is an error getting the stream.
+ */
+ public PDStream getToUnicode() throws IOException
+ {
+ return PDStream.createFromCOS( font.getDictionaryObject( "ToUnicode" ) );
+ }
+
+ /**
+ * This will set the ToUnicode stream.
+ *
+ * @param unicode The unicode stream.
+ */
+ public void setToUnicode( PDStream unicode )
+ {
+ font.setItem( "ToUnicode", unicode );
+ }
+
+ /**
+ * This will get the fonts bounding box.
+ *
+ * @return The fonts bouding box.
+ *
+ * @throws IOException If there is an error getting the bounding box.
+ */
+ public PDRectangle getFontBoundingBox() throws IOException
+ {
+ return getFontDescriptor().getFontBoundingBox();
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/font/PDTrueTypeFont.java b/src/main/java/org/pdfbox/pdmodel/font/PDTrueTypeFont.java
new file mode 100644
index 0000000..d462255
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/font/PDTrueTypeFont.java
@@ -0,0 +1,437 @@
+/**
+ * Copyright (c) 2003-2005, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.font;
+
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSName;
+
+import org.pdfbox.pdmodel.PDDocument;
+
+import org.pdfbox.pdmodel.common.PDRectangle;
+import org.pdfbox.pdmodel.common.PDStream;
+
+import org.pdfbox.encoding.WinAnsiEncoding;
+
+import org.pdfbox.ttf.CMAPEncodingEntry;
+import org.pdfbox.ttf.CMAPTable;
+import org.pdfbox.ttf.GlyphData;
+import org.pdfbox.ttf.GlyphTable;
+import org.pdfbox.ttf.HeaderTable;
+import org.pdfbox.ttf.HorizontalHeaderTable;
+import org.pdfbox.ttf.HorizontalMetricsTable;
+import org.pdfbox.ttf.MemoryTTFDataStream;
+import org.pdfbox.ttf.NamingTable;
+import org.pdfbox.ttf.NameRecord;
+import org.pdfbox.ttf.OS2WindowsMetricsTable;
+import org.pdfbox.ttf.PostScriptTable;
+import org.pdfbox.ttf.TTFParser;
+import org.pdfbox.ttf.TrueTypeFont;
+import org.pdfbox.util.ResourceLoader;
+
+import java.awt.Font;
+import java.awt.FontFormatException;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.RenderingHints;
+import java.awt.geom.AffineTransform;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * This is the TrueType implementation of fonts.
+ *
+ * @author Ben Litchfield (ben@benlitchfield.com)
+ * @version $Revision: 1.14 $
+ */
+public class PDTrueTypeFont extends PDSimpleFont
+{
+ /**
+ * This is the key to a property in the Resources/PDFBox_External_Fonts.properties file
+ * to load a Font when a mapping does not exist for the current font.
+ */
+ public static final String UNKNOWN_FONT = "UNKNOWN_FONT";
+
+ private Font awtFont = null;
+
+ private static Properties externalFonts = new Properties();
+ private static Map loadedExternalFonts = new HashMap();
+
+ static
+ {
+ try
+ {
+ ResourceLoader.loadProperties( "Resources/PDFBox_External_Fonts.properties", externalFonts );
+ }
+ catch( IOException io )
+ {
+ io.printStackTrace();
+ throw new RuntimeException( "Error loading font resources" );
+ }
+ }
+
+
+ /**
+ * Constructor.
+ */
+ public PDTrueTypeFont()
+ {
+ super();
+ font.setItem( COSName.SUBTYPE, COSName.TRUE_TYPE );
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param fontDictionary The font dictionary according to the PDF specification.
+ */
+ public PDTrueTypeFont( COSDictionary fontDictionary )
+ {
+ super( fontDictionary );
+ }
+
+ /**
+ * This will load a TTF font from a font file.
+ *
+ * @param doc The PDF document that will hold the embedded font.
+ * @param file The file on the filesystem that holds the font file.
+ * @return A true type font.
+ * @throws IOException If there is an error loading the file data.
+ */
+ public static PDTrueTypeFont loadTTF( PDDocument doc, String file ) throws IOException
+ {
+ return loadTTF( doc, new File( file ) );
+ }
+
+ /**
+ * This will load a TTF to be embedding into a document.
+ *
+ * @param doc The PDF document that will hold the embedded font.
+ * @param file A TTF file stream.
+ * @return A PDF TTF.
+ * @throws IOException If there is an error loading the data.
+ */
+ public static PDTrueTypeFont loadTTF( PDDocument doc, File file ) throws IOException
+ {
+ PDTrueTypeFont retval = new PDTrueTypeFont();
+ PDFontDescriptorDictionary fd = new PDFontDescriptorDictionary();
+ PDStream fontStream = new PDStream(doc, new FileInputStream( file ), false );
+ fontStream.getStream().setInt( COSName.LENGTH1, (int)file.length() );
+ fontStream.addCompression();
+ fd.setFontFile2( fontStream );
+ retval.setFontDescriptor( fd );
+ //only support winansi encoding right now, should really
+ //just use Identity-H with unicode mapping
+ retval.setEncoding( new WinAnsiEncoding() );
+ TrueTypeFont ttf = null;
+ try
+ {
+ TTFParser parser = new TTFParser();
+ ttf = parser.parseTTF( file );
+ NamingTable naming = ttf.getNaming();
+ List records = naming.getNameRecords();
+ for( int i=0; i<records.size(); i++ )
+ {
+ NameRecord nr = (NameRecord)records.get( i );
+ if( nr.getNameId() == NameRecord.NAME_POSTSCRIPT_NAME )
+ {
+ retval.setBaseFont( nr.getString() );
+ fd.setFontName( nr.getString() );
+ }
+ else if( nr.getNameId() == NameRecord.NAME_FONT_FAMILY_NAME )
+ {
+ fd.setFontFamily( nr.getString() );
+ }
+ }
+
+ OS2WindowsMetricsTable os2 = ttf.getOS2Windows();
+ fd.setNonSymbolic( true );
+ switch( os2.getFamilyClass() )
+ {
+ case OS2WindowsMetricsTable.FAMILY_CLASS_SYMBOLIC:
+ fd.setSymbolic( true );
+ fd.setNonSymbolic( false );
+ break;
+ case OS2WindowsMetricsTable.FAMILY_CLASS_SCRIPTS:
+ fd.setScript( true );
+ break;
+ case OS2WindowsMetricsTable.FAMILY_CLASS_CLAREDON_SERIFS:
+ case OS2WindowsMetricsTable.FAMILY_CLASS_FREEFORM_SERIFS:
+ case OS2WindowsMetricsTable.FAMILY_CLASS_MODERN_SERIFS:
+ case OS2WindowsMetricsTable.FAMILY_CLASS_OLDSTYLE_SERIFS:
+ case OS2WindowsMetricsTable.FAMILY_CLASS_SLAB_SERIFS:
+ fd.setSerif( true );
+ break;
+ default:
+ //do nothing
+ }
+ switch( os2.getWidthClass() )
+ {
+ case OS2WindowsMetricsTable.WIDTH_CLASS_ULTRA_CONDENSED:
+ fd.setFontStretch( "UltraCondensed" );
+ break;
+ case OS2WindowsMetricsTable.WIDTH_CLASS_EXTRA_CONDENSED:
+ fd.setFontStretch( "ExtraCondensed" );
+ break;
+ case OS2WindowsMetricsTable.WIDTH_CLASS_CONDENSED:
+ fd.setFontStretch( "Condensed" );
+ break;
+ case OS2WindowsMetricsTable.WIDTH_CLASS_SEMI_CONDENSED:
+ fd.setFontStretch( "SemiCondensed" );
+ break;
+ case OS2WindowsMetricsTable.WIDTH_CLASS_MEDIUM:
+ fd.setFontStretch( "Normal" );
+ break;
+ case OS2WindowsMetricsTable.WIDTH_CLASS_SEMI_EXPANDED:
+ fd.setFontStretch( "SemiExpanded" );
+ break;
+ case OS2WindowsMetricsTable.WIDTH_CLASS_EXPANDED:
+ fd.setFontStretch( "Expanded" );
+ break;
+ case OS2WindowsMetricsTable.WIDTH_CLASS_EXTRA_EXPANDED:
+ fd.setFontStretch( "ExtraExpanded" );
+ break;
+ case OS2WindowsMetricsTable.WIDTH_CLASS_ULTRA_EXPANDED:
+ fd.setFontStretch( "UltraExpanded" );
+ break;
+ default:
+ //do nothing
+ }
+ fd.setFontWeight( os2.getWeightClass() );
+
+ //todo retval.setFixedPitch
+ //todo retval.setNonSymbolic
+ //todo retval.setItalic
+ //todo retval.setAllCap
+ //todo retval.setSmallCap
+ //todo retval.setForceBold
+
+ HeaderTable header = ttf.getHeader();
+ PDRectangle rect = new PDRectangle();
+ rect.setLowerLeftX( header.getXMin() * 1000f/header.getUnitsPerEm() );
+ rect.setLowerLeftY( header.getYMin() * 1000f/header.getUnitsPerEm() );
+ rect.setUpperRightX( header.getXMax() * 1000f/header.getUnitsPerEm() );
+ rect.setUpperRightY( header.getYMax() * 1000f/header.getUnitsPerEm() );
+ fd.setFontBoundingBox( rect );
+
+ HorizontalHeaderTable hHeader = ttf.getHorizontalHeader();
+ fd.setAscent( hHeader.getAscender() * 1000f/header.getUnitsPerEm() );
+ fd.setDescent( hHeader.getDescender() * 1000f/header.getUnitsPerEm() );
+
+ GlyphTable glyphTable = ttf.getGlyph();
+ GlyphData[] glyphs = glyphTable.getGlyphs();
+
+ PostScriptTable ps = ttf.getPostScript();
+ fd.setFixedPitch( ps.getIsFixedPitch() > 0 );
+ fd.setItalicAngle( ps.getItalicAngle() );
+
+ String[] names = ps.getGlyphNames();
+ if( names != null )
+ {
+ for( int i=0; i<names.length; i++ )
+ {
+ //if we have a capital H then use that, otherwise use the
+ //tallest letter
+ if( names[i].equals( "H" ) )
+ {
+ fd.setCapHeight( (glyphs[i].getBoundingBox().getUpperRightY()* 1000f)/
+ header.getUnitsPerEm() );
+ }
+ if( names[i].equals( "x" ) )
+ {
+ fd.setXHeight( (glyphs[i].getBoundingBox().getUpperRightY()* 1000f)/header.getUnitsPerEm() );
+ }
+ }
+ }
+
+ //hmm there does not seem to be a clear definition for StemV,
+ //this is close enough and I am told it doesn't usually get used.
+ fd.setStemV( (fd.getFontBoundingBox().getWidth() * .13f) );
+
+
+ CMAPTable cmapTable = ttf.getCMAP();
+ CMAPEncodingEntry[] cmaps = cmapTable.getCmaps();
+ int[] glyphToCCode = null;
+ for( int i=0; i<cmaps.length; i++ )
+ {
+ if( cmaps[i].getPlatformId() == CMAPTable.PLATFORM_WINDOWS &&
+ cmaps[i].getPlatformEncodingId() == CMAPTable.ENCODING_UNICODE )
+ {
+ glyphToCCode = cmaps[i].getGlyphIdToCharacterCode();
+ }
+ }
+ int firstChar = 0;
+ /**
+ for( int i=0; i<glyphToCCode.length; i++ )
+ {
+ if( glyphToCCode[i] != 0 )
+ {
+ firstChar = Math.min( glyphToCCode[i], firstChar );
+ }
+ }*/
+
+ int maxWidths=256;
+ HorizontalMetricsTable hMet = ttf.getHorizontalMetrics();
+ int[] widthValues = hMet.getAdvanceWidth();
+ List widths = new ArrayList( widthValues.length );
+ Integer zero = new Integer( 250 );
+ for( int i=0; i<widthValues.length && i<maxWidths; i++ )
+ {
+ widths.add( zero );
+ }
+ for( int i=0; i<widthValues.length; i++ )
+ {
+ if(glyphToCCode[i]-firstChar < widths.size() &&
+ glyphToCCode[i]-firstChar >= 0 &&
+ widths.get( glyphToCCode[i]-firstChar) == zero )
+ {
+ widths.set( glyphToCCode[i]-firstChar,
+ new Integer( (int)(widthValues[i]* 1000f)/header.getUnitsPerEm() ) );
+ }
+ }
+ retval.setWidths( widths );
+
+ retval.setFirstChar( firstChar );
+ retval.setLastChar( firstChar + widths.size()-1 );
+
+ }
+ finally
+ {
+ if( ttf != null )
+ {
+ ttf.close();
+ }
+ }
+
+ return retval;
+ }
+
+ /**
+ * @see PDFont#drawString( String, Graphics, float, float, float, float, float )
+ */
+ public void drawString( String string, Graphics g, float fontSize,
+ float xScale, float yScale, float x, float y ) throws IOException
+ {
+ PDFontDescriptorDictionary fd = (PDFontDescriptorDictionary)getFontDescriptor();
+ if( awtFont == null )
+ {
+ PDStream ttfStream = fd.getFontFile2();
+ String fontName = fd.getFontName();
+ awtFont = Font.getFont( fontName, null );
+ if( ttfStream == null )
+ {
+ //throw new IOException( "Error:TTF Stream is null");
+ // Embedded true type programs are optional,
+ // if there is no stream, we must use an external
+ // file.
+ ttfStream = getExternalFontFile2( fd );
+ }
+ if( ttfStream == null )
+ {
+ //if we can't find a font then just fake it.
+ awtFont = new Font("Arial", Font.PLAIN, 1 );
+ }
+ else
+ {
+ try
+ {
+ awtFont = Font.createFont( Font.TRUETYPE_FONT, ttfStream.createInputStream() );
+ }
+ catch( FontFormatException e )
+ {
+ throw new IOException( e.getMessage() );
+ }
+ }
+ }
+ AffineTransform at = new AffineTransform();
+ at.scale( xScale, yScale );
+ Graphics2D g2d = (Graphics2D)g;
+ g2d.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON );
+ g2d.setFont( awtFont.deriveFont( at ).deriveFont( fontSize ) );
+ g2d.drawString( string, (int)x, (int)y );
+ }
+
+ /**
+ * Permit to load an external TTF Font program file
+ *
+ * Created by Pascal Allain
+ * Vertical7 Inc.
+ *
+ * @param fd The font descriptor currently used
+ *
+ * @return A PDStream with the Font File program, null if fd is null
+ *
+ * @throws IOException If the font is not found
+ */
+ private PDStream getExternalFontFile2(PDFontDescriptorDictionary fd)
+ throws IOException
+ {
+ PDStream retval = null;
+
+ if ( fd != null )
+ {
+ String baseFont = getBaseFont();
+ String fontResource = externalFonts.getProperty( UNKNOWN_FONT );
+ if( (baseFont != null) &&
+ (externalFonts.containsKey(baseFont)) )
+ {
+ fontResource = externalFonts.getProperty(baseFont);
+ }
+ if( fontResource != null )
+ {
+ TrueTypeFont extTTF = (TrueTypeFont)loadedExternalFonts.get( baseFont );
+ if( extTTF == null )
+ {
+ TTFParser ttfParser = new TTFParser();
+ InputStream is = ResourceLoader.loadResource( fontResource );
+ if( is == null )
+ {
+ throw new IOException( "Error missing font resource '" + externalFonts.get(baseFont) + "'" );
+ }
+ MemoryTTFDataStream stream = new MemoryTTFDataStream( is );
+ extTTF = ttfParser.parseTTF( stream );
+ loadedExternalFonts.put( baseFont, extTTF );
+ }
+ retval = extTTF.getPDStream();
+ }
+ }
+
+ return retval;
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/font/PDType0Font.java b/src/main/java/org/pdfbox/pdmodel/font/PDType0Font.java
new file mode 100644
index 0000000..010df33
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/font/PDType0Font.java
@@ -0,0 +1,129 @@
+/**
+ * Copyright (c) 2003-2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.font;
+
+import java.awt.Graphics;
+
+import org.pdfbox.cos.COSArray;
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSName;
+import org.pdfbox.pdmodel.common.PDRectangle;
+
+import java.io.IOException;
+
+/**
+ * This is implementation of the Type0 Font.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.7 $
+ */
+public class PDType0Font extends PDFont
+{
+ /**
+ * Constructor.
+ */
+ public PDType0Font()
+ {
+ super();
+ font.setItem( COSName.SUBTYPE, COSName.getPDFName( "Type0" ) );
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param fontDictionary The font dictionary according to the PDF specification.
+ */
+ public PDType0Font( COSDictionary fontDictionary )
+ {
+ super( fontDictionary );
+ }
+
+ /**
+ * @see PDFont#drawString( String, Graphics, float, float, float, float, float )
+ */
+ public void drawString( String string, Graphics g, float fontSize,
+ float xScale, float yScale, float x, float y )
+ {
+ throw new RuntimeException( "Not yet implemented" );
+ }
+
+ /**
+ * This will get the fonts bouding box.
+ *
+ * @return The fonts bouding box.
+ *
+ * @throws IOException If there is an error getting the bounding box.
+ */
+ public PDRectangle getFontBoundingBox() throws IOException
+ {
+ throw new RuntimeException( "Not yet implemented" );
+ }
+
+ /**
+ * This will get the font width for a character.
+ *
+ * @param c The character code to get the width for.
+ * @param offset The offset into the array.
+ * @param length The length of the data.
+ *
+ * @return The width is in 1000 unit of text space, ie 333 or 777
+ *
+ * @throws IOException If an error occurs while parsing.
+ */
+ public float getFontWidth( byte[] c, int offset, int length ) throws IOException
+ {
+ COSArray descendantFontArray =
+ (COSArray)font.getDictionaryObject( COSName.getPDFName( "DescendantFonts" ) );
+
+ COSDictionary descendantFontDictionary = (COSDictionary)descendantFontArray.getObject( 0 );
+ PDFont descendentFont = PDFontFactory.createFont( descendantFontDictionary );
+
+ return descendentFont.getFontWidth( c, offset, length );
+ }
+
+ /**
+ * This will get the average font width for all characters.
+ *
+ * @return The width is in 1000 unit of text space, ie 333 or 777
+ *
+ * @throws IOException If an error occurs while parsing.
+ */
+ public float getAverageFontWidth() throws IOException
+ {
+ COSArray descendantFontArray =
+ (COSArray)font.getDictionaryObject( COSName.getPDFName( "DescendantFonts" ) );
+
+ COSDictionary descendantFontDictionary = (COSDictionary)descendantFontArray.getObject( 0 );
+ PDFont descendentFont = PDFontFactory.createFont( descendantFontDictionary );
+
+ return descendentFont.getAverageFontWidth();
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/font/PDType1AfmPfbFont.java b/src/main/java/org/pdfbox/pdmodel/font/PDType1AfmPfbFont.java
new file mode 100644
index 0000000..89fdc5e
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/font/PDType1AfmPfbFont.java
@@ -0,0 +1,206 @@
+/**
+ * Copyright (c) 2004-2005, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+
+package org.pdfbox.pdmodel.font;
+
+import java.io.BufferedInputStream;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.pdfbox.afmparser.AFMParser;
+import org.pdfbox.afmtypes.CharMetric;
+import org.pdfbox.afmtypes.FontMetric;
+import org.pdfbox.encoding.AFMEncoding;
+import org.pdfbox.pdmodel.PDDocument;
+import org.pdfbox.pdmodel.common.PDRectangle;
+import org.pdfbox.pdmodel.common.PDStream;
+import org.pdfbox.pfb.PfbParser;
+
+/**
+ * This is implementation of the Type1 Font
+ * with a afm and a pfb file.
+ *
+ * @author <a href="mailto:m.g.n@gmx.de">Michael Niedermair</a>
+ * @version $Revision: 1.3 $
+ */
+public class PDType1AfmPfbFont extends PDType1Font
+{
+ /**
+ * the buffersize.
+ */
+ private static final int BUFFERSIZE = 0xffff;
+
+ /**
+ * The font descriptor.
+ */
+ private PDFontDescriptorDictionary fd;
+
+ /**
+ * the font metric.
+ */
+ private FontMetric metric;
+
+ /**
+ * Create a new object.
+ * @param doc The PDF document that will hold the embedded font.
+ * @param afmname The font filename.
+ * @throws IOException If there is an error loading the data.
+ */
+ public PDType1AfmPfbFont(final PDDocument doc, final String afmname)
+ throws IOException
+ {
+
+ super();
+
+ InputStream afmin = new BufferedInputStream(
+ new FileInputStream(afmname), BUFFERSIZE);
+ String pfbname = afmname.replaceAll(".AFM", "").replaceAll(".afm", "")
+ + ".pfb";
+ InputStream pfbin = new BufferedInputStream(
+ new FileInputStream(pfbname), BUFFERSIZE);
+
+ load(doc, afmin, pfbin);
+ }
+
+ /**
+ * Create a new object.
+ * @param doc The PDF document that will hold the embedded font.
+ * @param afm The afm input.
+ * @param pfb The pfb input.
+ * @throws IOException If there is an error loading the data.
+ */
+ public PDType1AfmPfbFont(final PDDocument doc, final InputStream afm, final InputStream pfb)
+ throws IOException
+ {
+ super();
+
+ load(doc, afm, pfb);
+ }
+
+ /**
+ * This will load a afm and pfb to be embedding into a document.
+ *
+ * @param doc The PDF document that will hold the embedded font.
+ * @param afm The afm input.
+ * @param pfb The pfb input.
+ * @throws IOException If there is an error loading the data.
+ */
+ private void load(final PDDocument doc, final InputStream afm,
+ final InputStream pfb) throws IOException
+ {
+
+ fd = new PDFontDescriptorDictionary();
+ setFontDescriptor(fd);
+
+ // read the pfb
+ PfbParser pfbparser = new PfbParser(pfb);
+ pfb.close();
+
+ PDStream fontStream = new PDStream(doc, pfbparser.getInputStream(),
+ false);
+ fontStream.getStream().setInt("Length", pfbparser.size());
+ for (int i = 0; i < pfbparser.getLengths().length; i++)
+ {
+ fontStream.getStream().setInt("Length" + (i + 1),
+ pfbparser.getLengths()[i]);
+ }
+ fontStream.addCompression();
+ fd.setFontFile(fontStream);
+
+ // read the afm
+ AFMParser parser = new AFMParser(afm);
+ parser.parse();
+ metric = parser.getResult();
+ setEncoding(new AFMEncoding(metric));
+
+ // set the values
+ setBaseFont(metric.getFontName());
+ fd.setFontName(metric.getFontName());
+ fd.setFontFamily(metric.getFamilyName());
+ fd.setNonSymbolic(true);
+ fd.setFontBoundingBox(new PDRectangle(metric.getFontBBox()));
+ fd.setItalicAngle(metric.getItalicAngle());
+ fd.setAscent(metric.getAscender());
+ fd.setDescent(metric.getDescender());
+ fd.setCapHeight(metric.getCapHeight());
+ fd.setXHeight(metric.getXHeight());
+ fd.setAverageWidth(metric.getAverageCharacterWidth());
+ fd.setCharacterSet(metric.getCharacterSet());
+
+ // get firstchar, lastchar
+ int firstchar = 255;
+ int lastchar = 0;
+
+ // widths
+ List listmetric = metric.getCharMetrics();
+
+ int maxWidths = 256;
+ List widths = new ArrayList(maxWidths);
+ Integer zero = new Integer(0);
+ Iterator iter = listmetric.iterator();
+ while (iter.hasNext())
+ {
+ CharMetric m = (CharMetric) iter.next();
+ int n = m.getCharacterCode();
+ if (n > 0)
+ {
+ firstchar = Math.min(firstchar, n);
+ lastchar = Math.max(lastchar, n);
+ if (m.getWx() > 0)
+ {
+ float width = m.getWx();
+ widths.add(new Float(width));
+ }
+ else
+ {
+ widths.add(zero);
+ }
+ }
+ }
+ setFirstChar(firstchar);
+ setLastChar(lastchar);
+ setWidths(widths);
+
+ }
+
+ /**
+ * @see org.pdfbox.pdmodel.font.PDSimpleFont#getFontDescriptor()
+ */
+ public PDFontDescriptor getFontDescriptor() throws IOException
+ {
+ return fd;
+ }
+
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/font/PDType1Font.java b/src/main/java/org/pdfbox/pdmodel/font/PDType1Font.java
new file mode 100644
index 0000000..891f7c9
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/font/PDType1Font.java
@@ -0,0 +1,267 @@
+/**
+ * Copyright (c) 2004-2005, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.font;
+
+import java.awt.Font;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.RenderingHints;
+import java.awt.geom.AffineTransform;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSName;
+
+/**
+ * This is implementation of the Type1 Font.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.10 $
+ */
+public class PDType1Font extends PDSimpleFont
+{
+ /**
+ * Standard Base 14 Font.
+ */
+ public static final PDType1Font TIMES_ROMAN = new PDType1Font( "Times-Roman" );
+ /**
+ * Standard Base 14 Font.
+ */
+ public static final PDType1Font TIMES_BOLD = new PDType1Font( "Times-Bold" );
+ /**
+ * Standard Base 14 Font.
+ */
+ public static final PDType1Font TIMES_ITALIC = new PDType1Font( "Times-Italic" );
+ /**
+ * Standard Base 14 Font.
+ */
+ public static final PDType1Font TIMES_BOLD_ITALIC = new PDType1Font( "Times-BoldItalic" );
+ /**
+ * Standard Base 14 Font.
+ */
+ public static final PDType1Font HELVETICA = new PDType1Font( "Helvetica" );
+ /**
+ * Standard Base 14 Font.
+ */
+ public static final PDType1Font HELVETICA_BOLD = new PDType1Font( "Helvetica-Bold" );
+ /**
+ * Standard Base 14 Font.
+ */
+ public static final PDType1Font HELVETICA_OBLIQUE = new PDType1Font( "Helvetica-Oblique" );
+ /**
+ * Standard Base 14 Font.
+ */
+ public static final PDType1Font HELVETICA_BOLD_OBLIQUE = new PDType1Font( "Helvetica-BoldOblique" );
+ /**
+ * Standard Base 14 Font.
+ */
+ public static final PDType1Font COURIER = new PDType1Font( "Courier" );
+ /**
+ * Standard Base 14 Font.
+ */
+ public static final PDType1Font COURIER_BOLD = new PDType1Font( "Courier-Bold" );
+ /**
+ * Standard Base 14 Font.
+ */
+ public static final PDType1Font COURIER_OBLIQUE = new PDType1Font( "Courier-Oblique" );
+ /**
+ * Standard Base 14 Font.
+ */
+ public static final PDType1Font COURIER_BOLD_OBLIQUE = new PDType1Font( "Courier-BoldOblique" );
+ /**
+ * Standard Base 14 Font.
+ */
+ public static final PDType1Font SYMBOL = new PDType1Font( "Symbol" );
+ /**
+ * Standard Base 14 Font.
+ */
+ public static final PDType1Font ZAPF_DINGBATS = new PDType1Font( "ZapfDingbats" );
+
+
+ private static final Map STANDARD_14 = new HashMap();
+ static
+ {
+ STANDARD_14.put( TIMES_ROMAN.getBaseFont(), TIMES_ROMAN );
+ STANDARD_14.put( TIMES_BOLD.getBaseFont(), TIMES_BOLD );
+ STANDARD_14.put( TIMES_ITALIC.getBaseFont(), TIMES_ITALIC );
+ STANDARD_14.put( TIMES_BOLD_ITALIC.getBaseFont(), TIMES_BOLD_ITALIC );
+ STANDARD_14.put( HELVETICA.getBaseFont(), HELVETICA );
+ STANDARD_14.put( HELVETICA_BOLD.getBaseFont(), HELVETICA_BOLD );
+ STANDARD_14.put( HELVETICA_OBLIQUE.getBaseFont(), HELVETICA_OBLIQUE );
+ STANDARD_14.put( HELVETICA_BOLD_OBLIQUE.getBaseFont(), HELVETICA_BOLD_OBLIQUE );
+ STANDARD_14.put( COURIER.getBaseFont(), COURIER );
+ STANDARD_14.put( COURIER_BOLD.getBaseFont(), COURIER_BOLD );
+ STANDARD_14.put( COURIER_OBLIQUE.getBaseFont(), COURIER_OBLIQUE );
+ STANDARD_14.put( COURIER_BOLD_OBLIQUE.getBaseFont(), COURIER_BOLD_OBLIQUE );
+ STANDARD_14.put( SYMBOL.getBaseFont(), SYMBOL );
+ STANDARD_14.put( ZAPF_DINGBATS.getBaseFont(), ZAPF_DINGBATS );
+ }
+
+ private Font awtFont = null;
+
+ /**
+ * Constructor.
+ */
+ public PDType1Font()
+ {
+ super();
+ font.setItem( COSName.SUBTYPE, COSName.getPDFName( "Type1" ) );
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param fontDictionary The font dictionary according to the PDF specification.
+ */
+ public PDType1Font( COSDictionary fontDictionary )
+ {
+ super( fontDictionary );
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param baseFont The base font for this font.
+ */
+ public PDType1Font( String baseFont )
+ {
+ this();
+ setBaseFont( baseFont );
+ }
+
+ /**
+ * A convenience method to get one of the standard 14 font from name.
+ *
+ * @param name The name of the font to get.
+ *
+ * @return The font that matches the name or null if it does not exist.
+ */
+ public static PDType1Font getStandardFont( String name )
+ {
+ return (PDType1Font)STANDARD_14.get( name );
+ }
+
+ /**
+ * This will get the names of the standard 14 fonts.
+ *
+ * @return An array of the names of the standard 14 fonts.
+ */
+ public static String[] getStandard14Names()
+ {
+ return (String[])STANDARD_14.keySet().toArray( new String[14] );
+ }
+
+ /**
+ * @see PDFont#drawString( String, Graphics, float, float, float, float, float )
+ */
+ public void drawString( String string, Graphics g, float fontSize,
+ float xScale, float yScale, float x, float y ) throws IOException
+ {
+ if( awtFont == null )
+ {
+ String baseFont = this.getBaseFont();
+ if( baseFont.equals( TIMES_ROMAN.getBaseFont() ) )
+ {
+ awtFont = new Font( "Times New Roman", Font.PLAIN, 1 );
+ }
+ else if( baseFont.equals( TIMES_ITALIC.getBaseFont() ) )
+ {
+ awtFont = new Font( "Times New Roman", Font.ITALIC, 1 );
+ }
+ else if( baseFont.equals( TIMES_BOLD.getBaseFont() ) )
+ {
+ awtFont = new Font( "Times New Roman", Font.BOLD, 1 );
+ }
+ else if( baseFont.equals( TIMES_BOLD_ITALIC.getBaseFont() ) )
+ {
+ awtFont = new Font( "Times New Roman", Font.BOLD | Font.ITALIC, 1 );
+ }
+ else if( baseFont.equals( HELVETICA.getBaseFont() ) )
+ {
+ awtFont = new Font( "Helvetica", Font.PLAIN, 1 );
+ }
+ else if( baseFont.equals( HELVETICA_BOLD.getBaseFont() ) )
+ {
+ awtFont = new Font( "Helvetica", Font.BOLD, 1 );
+ }
+ else if( baseFont.equals( HELVETICA_BOLD_OBLIQUE.getBaseFont() ) )
+ {
+ awtFont = new Font( "Helvetica", Font.BOLD | Font.ITALIC, 1 );
+ }
+ else if( baseFont.equals( HELVETICA_OBLIQUE.getBaseFont() ) )
+ {
+ awtFont = new Font( "Helvetica", Font.ITALIC, 1 );
+ }
+ else if( baseFont.equals( COURIER.getBaseFont() ) )
+ {
+ awtFont = new Font( "Courier", Font.PLAIN, 1 );
+ }
+ else if( baseFont.equals( COURIER_BOLD.getBaseFont() ) )
+ {
+ awtFont = new Font( "Courier", Font.BOLD, 1 );
+ }
+ else if( baseFont.equals( COURIER_BOLD_OBLIQUE.getBaseFont() ) )
+ {
+ awtFont = new Font( "Courier", Font.BOLD | Font.ITALIC, 1 );
+ }
+ else if( baseFont.equals( COURIER_OBLIQUE.getBaseFont() ) )
+ {
+ awtFont = new Font( "Courier", Font.ITALIC, 1 );
+ }
+ else if( baseFont.equals( SYMBOL.getBaseFont() ) )
+ {
+ awtFont = new Font( "Symbol", Font.PLAIN, 1 );
+ }
+ else if( baseFont.equals( ZAPF_DINGBATS.getBaseFont() ) )
+ {
+ awtFont = new Font( "ZapfDingbats", Font.PLAIN, 1 );
+ }
+ else
+ {
+ awtFont = new Font( "Arial", Font.PLAIN, 1 );
+ //throw new IOException( "Not yet implemented:" + getClass().getName() + " " +
+ //this.getBaseFont() +
+ //" " + this + " " + TIMES_ROMAN );
+ }
+ }
+ AffineTransform at = new AffineTransform();
+ at.scale( xScale, yScale );
+
+ Graphics2D g2d = (Graphics2D)g;
+ g2d.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON );
+ g2d.setFont( awtFont.deriveFont( at ).deriveFont( fontSize ) );
+ //g2d.getFontRenderContext().getTransform().scale( xScale, yScale );
+
+ g2d.drawString( string, (int)x, (int)y );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/font/PDType3Font.java b/src/main/java/org/pdfbox/pdmodel/font/PDType3Font.java
new file mode 100644
index 0000000..5f9c363
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/font/PDType3Font.java
@@ -0,0 +1,152 @@
+/**
+ * Copyright (c) 2003-2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.font;
+
+import org.apache.log4j.Logger;
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSName;
+import org.pdfbox.cos.COSStream;
+import org.pdfbox.pdmodel.common.PDMatrix;
+
+import java.awt.Graphics;
+import java.awt.Image;
+
+import java.io.IOException;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * This is implementation of the Type3 Font.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.6 $
+ */
+public class PDType3Font extends PDSimpleFont
+{
+ private static Logger log = Logger.getLogger( PDType3Font.class );
+
+ //A map of character code to java.awt.Image for the glyph
+ private Map images = new HashMap();
+
+ /**
+ * Constructor.
+ */
+ public PDType3Font()
+ {
+ super();
+ font.setItem( COSName.SUBTYPE, COSName.getPDFName( "Type3" ) );
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param fontDictionary The font dictionary according to the PDF specification.
+ */
+ public PDType3Font( COSDictionary fontDictionary )
+ {
+ super( fontDictionary );
+ }
+
+ /**
+ * Type3 fonts have their glyphs defined as a content stream. This
+ * will create the image that represents that character
+ *
+ * @throws IOException If there is an error creating the image.
+ */
+ private Image createImageIfNecessary( char character ) throws IOException
+ {
+ Character c = new Character( character );
+ Image retval = (Image)images.get( c );
+ if( retval == null )
+ {
+ COSDictionary charProcs = (COSDictionary)font.getDictionaryObject( COSName.getPDFName( "CharProcs" ) );
+ COSStream stream = (COSStream)charProcs.getDictionaryObject( COSName.getPDFName( "" + character ) );
+ if( stream != null )
+ {
+ Type3StreamParser parser = new Type3StreamParser();
+ retval = parser.createImage( stream );
+ images.put( c, retval );
+ }
+ else
+ {
+ log.warn( "Error font type 3 image stream is null" );
+ }
+ }
+ return retval;
+
+ }
+
+ /**
+ * This will draw a string on a canvas using the font.
+ *
+ * @param string The string to draw.
+ * @param g The graphics to draw onto.
+ * @param fontSize The size of the font to draw.
+ * @param x The x coordinate to draw at.
+ * @param y The y coordinate to draw at.
+ *
+ * @throws IOException If there is an error drawing the image on the screen.
+ */
+ public void drawString( String string, Graphics g, float fontSize, float x, float y ) throws IOException
+ {
+ //if( string.equals( "V" )|| string.equals( "o" ) )
+ {
+ for(int i=0; i<string.length(); i++)
+ {
+ //todo need to use image observers and such
+ char c = string.charAt( i );
+ Image image = createImageIfNecessary( c );
+ if( image != null )
+ {
+ int newWidth = (int)(.12*image.getWidth(null));
+ int newHeight = (int)(.12*image.getHeight(null));
+ if( newWidth > 0 && newHeight > 0 )
+ {
+ image = image.getScaledInstance( newWidth, newHeight, Image.SCALE_SMOOTH );
+ g.drawImage( image, (int)x, (int)y, null );
+ x+=newWidth;
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Set the font matrix for this type3 font.
+ *
+ * @param matrix The font matrix for this type3 font.
+ */
+ public void setFontMatrix( PDMatrix matrix )
+ {
+ font.setItem( "FontMatrix", matrix );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/font/Type3StreamParser.java b/src/main/java/org/pdfbox/pdmodel/font/Type3StreamParser.java
new file mode 100644
index 0000000..a2adc1f
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/font/Type3StreamParser.java
@@ -0,0 +1,607 @@
+/**
+ * Copyright (c) 2003-2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.font;
+
+import java.awt.Image;
+
+import java.io.IOException;
+
+import java.util.List;
+
+import org.pdfbox.cos.COSNumber;
+import org.pdfbox.cos.COSStream;
+
+import org.pdfbox.pdmodel.graphics.xobject.PDInlinedImage;
+
+import org.pdfbox.util.BoundingBox;
+import org.pdfbox.util.ImageParameters;
+import org.pdfbox.util.PDFOperator;
+import org.pdfbox.util.PDFStreamEngine;
+
+/**
+ * This class will handle creating an image for a type 3 glyph.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.8 $
+ */
+public class Type3StreamParser extends PDFStreamEngine
+{
+ private PDInlinedImage image = null;
+ private BoundingBox box = null;
+
+
+ /**
+ * This will parse a type3 stream and create an image from it.
+ *
+ * @param type3Stream The stream containing the operators to draw the image.
+ *
+ * @return The image that was created.
+ *
+ * @throws IOException If there is an error processing the stream.
+ */
+ public Image createImage( COSStream type3Stream ) throws IOException
+ {
+ processStream( null, null, type3Stream );
+ return image.createImage();
+ }
+
+ /**
+ * This is used to handle an operation.
+ *
+ * @param operator The operation to perform.
+ * @param arguments The list of arguments.
+ *
+ * @throws IOException If there is an error processing the operation.
+ */
+ protected void processOperator( PDFOperator operator, List arguments ) throws IOException
+ {
+ super.processOperator( operator, arguments );
+ String operation = operator.getOperation();
+ /**
+ if( operation.equals( "b" ) )
+ {
+ //Close, fill, and stroke path using nonzero winding number rule
+ }
+ else if( operation.equals( "B" ) )
+ {
+ //Fill and stroke path using nonzero winding number rule
+ }
+ else if( operation.equals( "b*" ) )
+ {
+ //Close, fill, and stroke path using even-odd rule
+ }
+ else if( operation.equals( "B*" ) )
+ {
+ //Fill and stroke path using even-odd rule
+ }
+ else if( operation.equals( "BDC" ) )
+ {
+ //(PDF 1.2) Begin marked-content sequence with property list
+ }
+ else **/if( operation.equals( "BI" ) )
+ {
+ ImageParameters params = operator.getImageParameters();
+ image = new PDInlinedImage();
+ image.setImageParameters( params );
+ image.setImageData( operator.getImageData() );
+ //begin inline image object
+ }/**
+ else if( operation.equals( "BMC" ) )
+ {
+ //(PDF 1.2) Begin marked-content sequence
+ }
+ else if( operation.equals( "BT" ) )
+ {
+ log.debug( "<BT>" );
+ textMatrix = new Matrix();
+ textLineMatrix = new Matrix();
+ }
+ else if( operation.equals( "BX" ) )
+ {
+ //(PDF 1.1) Begin compatibility section
+ }
+ else if( operation.equals( "c" ) )
+ {
+ //Append curved segment to path (three control points)
+ }
+ else if( operation.equals( "cm" ) )
+ {
+ }
+ else if( operation.equals( "cs" ) )
+ {
+ }
+ else if( operation.equals( "CS" ) )
+ {
+ }
+ else if( operation.equals( "d" ) )
+ {
+ //Set the line dash pattern in the graphics state
+ }
+ else */if( operation.equals( "d0" ) )
+ {
+ //set glyph with for a type3 font
+ //COSNumber horizontalWidth = (COSNumber)arguments.get( 0 );
+ //COSNumber verticalWidth = (COSNumber)arguments.get( 1 );
+ //width = horizontalWidth.intValue();
+ //height = verticalWidth.intValue();
+ }
+ else if( operation.equals( "d1" ) )
+ {
+ //set glyph with and bounding box for type 3 font
+ //COSNumber horizontalWidth = (COSNumber)arguments.get( 0 );
+ //COSNumber verticalWidth = (COSNumber)arguments.get( 1 );
+ COSNumber llx = (COSNumber)arguments.get( 2 );
+ COSNumber lly = (COSNumber)arguments.get( 3 );
+ COSNumber urx = (COSNumber)arguments.get( 4 );
+ COSNumber ury = (COSNumber)arguments.get( 5 );
+
+ //width = horizontalWidth.intValue();
+ //height = verticalWidth.intValue();
+ box = new BoundingBox();
+ box.setLowerLeftX( llx.floatValue() );
+ box.setLowerLeftY( lly.floatValue() );
+ box.setUpperRightX( urx.floatValue() );
+ box.setUpperRightY( ury.floatValue() );
+ }/*
+ else if( operation.equals( "Do" ) )
+ {
+ //invoke named object.
+ }
+ else if( operation.equals( "DP" ) )
+ {
+ //(PDF 1.2) De.ne marked-content point with property list
+ }
+ else if( operation.equals( "EI" ) )
+ {
+ //end inline image object
+ }
+ else if( operation.equals( "EMC" ) )
+ {
+ //End inline image object
+ }
+ else if( operation.equals( "ET" ) )
+ {
+ log.debug( "<ET>" );
+ textMatrix = null;
+ textLineMatrix = null;
+ }
+ else if( operation.equals( "EX" ) )
+ {
+ //(PDF 1.1) End compatibility section
+ }
+ else if( operation.equals( "f" ) )
+ {
+ //Fill the path, using the nonzero winding number rule to determine the region to .ll
+ }
+ else if( operation.equals( "F" ) )
+ {
+ }
+ else if( operation.equals( "f*" ) )
+ {
+ //Fill path using even-odd rule
+ }
+ else if( operation.equals( "g" ) )
+ {
+ }
+ else if( operation.equals( "G" ) )
+ {
+ }
+ else if( operation.equals( "gs" ) )
+ {
+ }
+ else if( operation.equals( "h" ) )
+ {
+ //close subpath
+ }
+ else if( operation.equals( "i" ) )
+ {
+ //set flatness tolerance, not sure what this does
+ }
+ else if( operation.equals( "ID" ) )
+ {
+ //begin inline image data
+ }
+ else if( operation.equals( "j" ) )
+ {
+ //Set the line join style in the graphics state
+ //System.out.println( "<j>" );
+ }
+ else if( operation.equals( "J" ) )
+ {
+ //Set the line cap style in the graphics state
+ //System.out.println( "<J>" );
+ }
+ else if( operation.equals( "k" ) )
+ {
+ //Set CMYK color for nonstroking operations
+ }
+ else if( operation.equals( "K" ) )
+ {
+ //Set CMYK color for stroking operations
+ }
+ else if( operation.equals( "l" ) )
+ {
+ //append straight line segment from the current point to the point.
+ COSNumber x = (COSNumber)arguments.get( 0 );
+ COSNumber y = (COSNumber)arguments.get( 1 );
+ linePath.lineTo( x.floatValue(), pageSize.getHeight()-y.floatValue() );
+ }
+ else if( operation.equals( "m" ) )
+ {
+ COSNumber x = (COSNumber)arguments.get( 0 );
+ COSNumber y = (COSNumber)arguments.get( 1 );
+ linePath.reset();
+ linePath.moveTo( x.floatValue(), pageSize.getHeight()-y.floatValue() );
+ //System.out.println( "<m x=\"" + x.getValue() + "\" y=\"" + y.getValue() + "\" >" );
+ }
+ else if( operation.equals( "M" ) )
+ {
+ //System.out.println( "<M>" );
+ }
+ else if( operation.equals( "MP" ) )
+ {
+ //(PDF 1.2) Define marked-content point
+ }
+ else if( operation.equals( "n" ) )
+ {
+ //End path without .lling or stroking
+ //System.out.println( "<n>" );
+ }
+ else if( operation.equals( "q" ) )
+ {
+ //save graphics state
+ if( log.isDebugEnabled() )
+ {
+ log.debug( "<" + operation + "> - save state" );
+ }
+ graphicsStack.push(graphicsState.clone());
+ }
+ else if( operation.equals( "Q" ) )
+ {
+ //restore graphics state
+ if( log.isDebugEnabled() )
+ {
+ log.debug( "<" + operation + "> - restore state" );
+ }
+ graphicsState = (PDGraphicsState)graphicsStack.pop();
+ }
+ else if( operation.equals( "re" ) )
+ {
+ }
+ else if( operation.equals( "rg" ) )
+ {
+ //Set RGB color for nonstroking operations
+ }
+ else if( operation.equals( "RG" ) )
+ {
+ //Set RGB color for stroking operations
+ }
+ else if( operation.equals( "ri" ) )
+ {
+ //Set color rendering intent
+ }
+ else if( operation.equals( "s" ) )
+ {
+ //Close and stroke path
+ }
+ else if( operation.equals( "S" ) )
+ {
+ graphics.draw( linePath );
+ }
+ else if( operation.equals( "sc" ) )
+ {
+ //set color for nonstroking operations
+ //System.out.println( "<sc>" );
+ }
+ else if( operation.equals( "SC" ) )
+ {
+ //set color for stroking operations
+ //System.out.println( "<SC>" );
+ }
+ else if( operation.equals( "scn" ) )
+ {
+ //set color for nonstroking operations special
+ }
+ else if( operation.equals( "SCN" ) )
+ {
+ //set color for stroking operations special
+ }
+ else if( operation.equals( "sh" ) )
+ {
+ //(PDF 1.3) Paint area de.ned by shading pattern
+ }
+ else if( operation.equals( "T*" ) )
+ {
+ if (log.isDebugEnabled())
+ {
+ log.debug("<T* graphicsState.getTextState().getLeading()=\"" +
+ graphicsState.getTextState().getLeading() + "\">");
+ }
+ //move to start of next text line
+ if( graphicsState.getTextState().getLeading() == 0 )
+ {
+ graphicsState.getTextState().setLeading( -.01f );
+ }
+ Matrix td = new Matrix();
+ td.setValue( 2, 1, -1 * graphicsState.getTextState().getLeading() * textMatrix.getValue(1,1));
+ textLineMatrix = textLineMatrix.multiply( td );
+ textMatrix = textLineMatrix.copy();
+ }
+ else if( operation.equals( "Tc" ) )
+ {
+ //set character spacing
+ COSNumber characterSpacing = (COSNumber)arguments.get( 0 );
+ if (log.isDebugEnabled())
+ {
+ log.debug("<Tc characterSpacing=\"" + characterSpacing.floatValue() + "\" />");
+ }
+ graphicsState.getTextState().setCharacterSpacing( characterSpacing.floatValue() );
+ }
+ else if( operation.equals( "Td" ) )
+ {
+ COSNumber x = (COSNumber)arguments.get( 0 );
+ COSNumber y = (COSNumber)arguments.get( 1 );
+ if (log.isDebugEnabled())
+ {
+ log.debug("<Td x=\"" + x.floatValue() + "\" y=\"" + y.floatValue() + "\">");
+ }
+ Matrix td = new Matrix();
+ td.setValue( 2, 0, x.floatValue() * textMatrix.getValue(0,0) );
+ td.setValue( 2, 1, y.floatValue() * textMatrix.getValue(1,1) );
+ //log.debug( "textLineMatrix before " + textLineMatrix );
+ textLineMatrix = textLineMatrix.multiply( td );
+ //log.debug( "textLineMatrix after " + textLineMatrix );
+ textMatrix = textLineMatrix.copy();
+ }
+ else if( operation.equals( "TD" ) )
+ {
+ //move text position and set leading
+ COSNumber x = (COSNumber)arguments.get( 0 );
+ COSNumber y = (COSNumber)arguments.get( 1 );
+ if (log.isDebugEnabled())
+ {
+ log.debug("<TD x=\"" + x.floatValue() + "\" y=\"" + y.floatValue() + "\">");
+ }
+ graphicsState.getTextState().setLeading( -1 * y.floatValue() );
+ Matrix td = new Matrix();
+ td.setValue( 2, 0, x.floatValue() * textMatrix.getValue(0,0) );
+ td.setValue( 2, 1, y.floatValue() * textMatrix.getValue(1,1) );
+ //log.debug( "textLineMatrix before " + textLineMatrix );
+ textLineMatrix = textLineMatrix.multiply( td );
+ //log.debug( "textLineMatrix after " + textLineMatrix );
+ textMatrix = textLineMatrix.copy();
+ }
+ else if( operation.equals( "Tf" ) )
+ {
+ //set font and size
+ COSName fontName = (COSName)arguments.get( 0 );
+ graphicsState.getTextState().setFontSize( ((COSNumber)arguments.get( 1 ) ).floatValue() );
+
+ if (log.isDebugEnabled())
+ {
+ log.debug("<Tf font=\"" + fontName.getName() + "\" size=\"" +
+ graphicsState.getTextState().getFontSize() + "\">");
+ }
+
+ //old way
+ //graphicsState.getTextState().getFont() = (COSObject)stream.getDictionaryObject( fontName );
+ //if( graphicsState.getTextState().getFont() == null )
+ //{
+ // graphicsState.getTextState().getFont() = (COSObject)graphicsState.getTextState().getFont()
+ // Dictionary.getItem( fontName );
+ //}
+ graphicsState.getTextState().setFont( (PDFont)fonts.get( fontName.getName() ) );
+ if( graphicsState.getTextState().getFont() == null )
+ {
+ throw new IOException( "Error: Could not find font(" + fontName + ") in map=" + fonts );
+ }
+ //log.debug( "Font Resource=" + fontResource );
+ //log.debug( "Current Font=" + graphicsState.getTextState().getFont() );
+ //log.debug( "graphicsState.getTextState().getFontSize()=" + graphicsState.getTextState().getFontSize() );
+ }
+ else if( operation.equals( "Tj" ) )
+ {
+ COSString string = (COSString)arguments.get( 0 );
+ TextPosition pos = showString( string.getBytes() );
+ if (log.isDebugEnabled())
+ {
+ log.debug("<Tj string=\"" + string.getString() + "\">");
+ }
+ }
+ else if( operation.equals( "TJ" ) )
+ {
+ Matrix td = new Matrix();
+
+ COSArray array = (COSArray)arguments.get( 0 );
+ for( int i=0; i<array.size(); i++ )
+ {
+ COSBase next = array.get( i );
+ if( next instanceof COSNumber )
+ {
+ float value = -1*
+ (((COSNumber)next).floatValue()/1000) *
+ graphicsState.getTextState().getFontSize() *
+ textMatrix.getValue(1,1);
+
+ if (log.isDebugEnabled())
+ {
+ log.debug( "<TJ(" + i + ") value=\"" + value +
+ "\", param=\"" + ((COSNumber)next).floatValue() +
+ "\", fontsize=\"" + graphicsState.getTextState().getFontSize() + "\">" );
+ }
+ td.setValue( 2, 0, value );
+ textMatrix = textMatrix.multiply( td );
+ }
+ else if( next instanceof COSString )
+ {
+ TextPosition pos = showString( ((COSString)next).getBytes() );
+ if (log.isDebugEnabled())
+ {
+ log.debug("<TJ(" + i + ") string=\"" + pos.getString() + "\">");
+ }
+ }
+ else
+ {
+ throw new IOException( "Unknown type in array for TJ operation:" + next );
+ }
+ }
+ }
+ else if( operation.equals( "TL" ) )
+ {
+ COSNumber leading = (COSNumber)arguments.get( 0 );
+ graphicsState.getTextState().setLeading( leading.floatValue() );
+ if (log.isDebugEnabled())
+ {
+ log.debug("<TL leading=\"" + leading.floatValue() + "\" >");
+ }
+ }
+ else if( operation.equals( "Tm" ) )
+ {
+ //Set text matrix and text line matrix
+ COSNumber a = (COSNumber)arguments.get( 0 );
+ COSNumber b = (COSNumber)arguments.get( 1 );
+ COSNumber c = (COSNumber)arguments.get( 2 );
+ COSNumber d = (COSNumber)arguments.get( 3 );
+ COSNumber e = (COSNumber)arguments.get( 4 );
+ COSNumber f = (COSNumber)arguments.get( 5 );
+
+ if (log.isDebugEnabled())
+ {
+ log.debug("<Tm " +
+ "a=\"" + a.floatValue() + "\" " +
+ "b=\"" + b.floatValue() + "\" " +
+ "c=\"" + c.floatValue() + "\" " +
+ "d=\"" + d.floatValue() + "\" " +
+ "e=\"" + e.floatValue() + "\" " +
+ "f=\"" + f.floatValue() + "\" >");
+ }
+
+ textMatrix = new Matrix();
+ textMatrix.setValue( 0, 0, a.floatValue() );
+ textMatrix.setValue( 0, 1, b.floatValue() );
+ textMatrix.setValue( 1, 0, c.floatValue() );
+ textMatrix.setValue( 1, 1, d.floatValue() );
+ textMatrix.setValue( 2, 0, e.floatValue() );
+ textMatrix.setValue( 2, 1, f.floatValue() );
+ textLineMatrix = textMatrix.copy();
+ }
+ else if( operation.equals( "Tr" ) )
+ {
+ //Set text rendering mode
+ //System.out.println( "<Tr>" );
+ }
+ else if( operation.equals( "Ts" ) )
+ {
+ //Set text rise
+ //System.out.println( "<Ts>" );
+ }
+ else if( operation.equals( "Tw" ) )
+ {
+ //set word spacing
+ COSNumber wordSpacing = (COSNumber)arguments.get( 0 );
+ if (log.isDebugEnabled())
+ {
+ log.debug("<Tw wordSpacing=\"" + wordSpacing.floatValue() + "\" />");
+ }
+ graphicsState.getTextState().setWordSpacing( wordSpacing.floatValue() );
+ }
+ else if( operation.equals( "Tz" ) )
+ {
+ //Set horizontal text scaling
+ }
+ else if( operation.equals( "v" ) )
+ {
+ //Append curved segment to path (initial point replicated)
+ }
+ else if( operation.equals( "w" ) )
+ {
+ //Set the line width in the graphics state
+ //System.out.println( "<w>" );
+ }
+ else if( operation.equals( "W" ) )
+ {
+ //Set clipping path using nonzero winding number rule
+ //System.out.println( "<W>" );
+ }
+ else if( operation.equals( "W*" ) )
+ {
+ //Set clipping path using even-odd rule
+ }
+ else if( operation.equals( "y" ) )
+ {
+ //Append curved segment to path (final point replicated)
+ }
+ else if( operation.equals( "'" ) )
+ {
+ // Move to start of next text line, and show text
+ //
+ COSString string = (COSString)arguments.get( 0 );
+ if (log.isDebugEnabled())
+ {
+ log.debug("<' string=\"" + string.getString() + "\">");
+ }
+
+ Matrix td = new Matrix();
+ td.setValue( 2, 1, -1 * graphicsState.getTextState().getLeading() * textMatrix.getValue(1,1));
+ textLineMatrix = textLineMatrix.multiply( td );
+ textMatrix = textLineMatrix.copy();
+
+ showString( string.getBytes() );
+ }
+ else if( operation.equals( "\"" ) )
+ {
+ //Set word and character spacing, move to next line, and show text
+ //
+ COSNumber wordSpacing = (COSNumber)arguments.get( 0 );
+ COSNumber characterSpacing = (COSNumber)arguments.get( 1 );
+ COSString string = (COSString)arguments.get( 2 );
+
+ if (log.isDebugEnabled())
+ {
+ log.debug("<\" wordSpacing=\"" + wordSpacing +
+ "\", characterSpacing=\"" + characterSpacing +
+ "\", string=\"" + string.getString() + "\">");
+ }
+
+ graphicsState.getTextState().setCharacterSpacing( characterSpacing.floatValue() );
+ graphicsState.getTextState().setWordSpacing( wordSpacing.floatValue() );
+
+ Matrix td = new Matrix();
+ td.setValue( 2, 1, -1 * graphicsState.getTextState().getLeading() * textMatrix.getValue(1,1));
+ textLineMatrix = textLineMatrix.multiply( td );
+ textMatrix = textLineMatrix.copy();
+
+ showString( string.getBytes() );
+ }*/
+ }
+
+
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/font/package.html b/src/main/java/org/pdfbox/pdmodel/font/package.html
new file mode 100644
index 0000000..4e8d27e
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/font/package.html
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+
+</head>
+<body>
+Classes to deal with font functionality in a PDF Document.
+</body>
+</html>
diff --git a/src/main/java/org/pdfbox/pdmodel/graphics/PDExtendedGraphicsState.java b/src/main/java/org/pdfbox/pdmodel/graphics/PDExtendedGraphicsState.java
new file mode 100644
index 0000000..3fe9c40
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/graphics/PDExtendedGraphicsState.java
@@ -0,0 +1,724 @@
+/**
+ * Copyright (c) 2003, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.graphics;
+
+import org.pdfbox.cos.COSArray;
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSBoolean;
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSFloat;
+import org.pdfbox.cos.COSInteger;
+import org.pdfbox.cos.COSName;
+import org.pdfbox.cos.COSNumber;
+
+import org.pdfbox.pdmodel.common.COSObjectable;
+
+import java.io.IOException;
+
+import java.util.Iterator;
+
+/**
+ * This class represents the graphics state dictionary that is stored in the PDF document.
+ * The PDGraphicsStateValue holds the current runtime values as a stream is being executed.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.4 $
+ */
+public class PDExtendedGraphicsState implements COSObjectable
+{
+ private static final COSName LW = COSName.getPDFName( "LW" );
+ private static final COSName LC = COSName.getPDFName( "LC" );
+ private static final COSName LJ = COSName.getPDFName( "LJ" );
+ private static final COSName ML = COSName.getPDFName( "ML" );
+ private static final COSName D = COSName.getPDFName( "D" );
+ private static final COSName RI = COSName.getPDFName( "RI" );
+ private static final COSName OP = COSName.getPDFName( "OP" );
+ private static final COSName OP_NS = COSName.getPDFName( "op" );
+ private static final COSName OPM = COSName.getPDFName( "OPM" );
+ private static final COSName FONT = COSName.getPDFName( "Font" );
+ private static final COSName FL = COSName.getPDFName( "FL" );
+ private static final COSName SM = COSName.getPDFName( "SM" );
+ private static final COSName SA = COSName.getPDFName( "SA" );
+ private static final COSName CA = COSName.getPDFName( "CA" );
+ private static final COSName CA_NS = COSName.getPDFName( "ca" );
+ private static final COSName AIS = COSName.getPDFName( "AIS" );
+ private static final COSName TK = COSName.getPDFName( "TK" );
+
+ /**
+ * Rendering intent constants, see PDF Reference 1.5 Section 4.5.4 Rendering Intents.
+ */
+ public static final String RENDERING_INTENT_ABSOLUTE_COLORIMETRIC = "AbsoluteColorimetric";
+ /**
+ * Rendering intent constants, see PDF Reference 1.5 Section 4.5.4 Rendering Intents.
+ */
+ public static final String RENDERING_INTENT_RELATIVE_COLORIMETRIC = "RelativeColorimetric";
+ /**
+ * Rendering intent constants, see PDF Reference 1.5 Section 4.5.4 Rendering Intents.
+ */
+ public static final String RENDERING_INTENT_SATURATION = "Saturation";
+ /**
+ * Rendering intent constants, see PDF Reference 1.5 Section 4.5.4 Rendering Intents.
+ */
+ public static final String RENDERING_INTENT_PERCEPTUAL = "Perceptual";
+
+
+ private COSDictionary graphicsState;
+
+ /**
+ * Default constructor, creates blank graphics state.
+ */
+ public PDExtendedGraphicsState()
+ {
+ graphicsState = new COSDictionary();
+ graphicsState.setItem( COSName.TYPE, COSName.getPDFName( "ExtGState" ) );
+ }
+
+ /**
+ * Create a graphics state from an existing dictionary.
+ *
+ * @param dictionary The existing graphics state.
+ */
+ public PDExtendedGraphicsState( COSDictionary dictionary )
+ {
+ graphicsState = dictionary;
+ }
+
+ /**
+ * This will implement the gs operator.
+ *
+ * @param gs The state to copy this dictionaries values into.
+ *
+ * @throws IOException If there is an error copying font information.
+ */
+ public void copyIntoGraphicsState( PDGraphicsState gs ) throws IOException
+ {
+ Iterator keys = graphicsState.keyList().iterator();
+ while( keys.hasNext() )
+ {
+ COSName key = (COSName)keys.next();
+ if( key.equals( LW ) )
+ {
+ gs.setLineWidth( getLineWidth().doubleValue() );
+ }
+ else if( key.equals( LC ) )
+ {
+ gs.setLineCap( getLineCapStyle().intValue() );
+ }
+ else if( key.equals( LJ ) )
+ {
+ gs.setLineJoin( getLineJoinStyle().intValue() );
+ }
+ else if( key.equals( ML ) )
+ {
+ gs.setMiterLimit( getMiterLimit().doubleValue() );
+ }
+ else if( key.equals( D ) )
+ {
+ gs.setLineDashPattern( getLineDashPattern() );
+ }
+ else if( key.equals( RI ) )
+ {
+ gs.setRenderingIntent( getRenderingIntent() );
+ }
+ else if( key.equals( OPM ) )
+ {
+ gs.setOverprintMode( getOverprintMode().doubleValue() );
+ }
+ else if( key.equals( FONT ) )
+ {
+ PDFontSetting setting = getFontSetting();
+ gs.getTextState().setFont( setting.getFont() );
+ gs.getTextState().setFontSize( setting.getFontSize() );
+ }
+ else if( key.equals( FL ) )
+ {
+ gs.setFlatness( getFlatnessTolerance().floatValue() );
+ }
+ else if( key.equals( SM ) )
+ {
+ gs.setSmoothness( getSmoothnessTolerance().floatValue() );
+ }
+ else if( key.equals( SA ) )
+ {
+ gs.setStrokeAdjustment( getAutomaticStrokeAdjustment().booleanValue() );
+ }
+ else if( key.equals( CA ) )
+ {
+ gs.setAlphaConstants( getStrokingAlpaConstant().floatValue() );
+ }/**
+ else if( key.equals( CA_NS ) )
+ {
+ }**/
+ else if( key.equals( AIS ) )
+ {
+ gs.setAlphaSource( getAlpaSourceFlag().booleanValue() );
+ }
+ else if( key.equals( TK ) )
+ {
+ gs.getTextState().setKnockoutFlag( getTextKnockoutFlag().booleanValue() );
+ }
+ }
+ }
+
+ /**
+ * This will get the underlying dictionary that this class acts on.
+ *
+ * @return The underlying dictionary for this class.
+ */
+ public COSDictionary getCOSDictionary()
+ {
+ return graphicsState;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSBase getCOSObject()
+ {
+ return graphicsState;
+ }
+
+ /**
+ * This will get the line width. This will return null if there is no line width
+ *
+ * @return null or the LW value of the dictionary.
+ */
+ public Float getLineWidth()
+ {
+ return getFloatItem( LW );
+ }
+
+ /**
+ * This will set the line width.
+ *
+ * @param width The line width for the object.
+ */
+ public void setLineWidth( Float width )
+ {
+ setFloatItem( LW, width );
+ }
+
+ /**
+ * This will get the line cap style.
+ *
+ * @return null or the LC value of the dictionary.
+ */
+ public Long getLineCapStyle()
+ {
+ return getLongItem( LC );
+ }
+
+ /**
+ * This will set the line cap style for the graphics state.
+ *
+ * @param style The new line cap style to set.
+ */
+ public void setLineCapStyle( Long style )
+ {
+ setLongItem( LC, style );
+ }
+
+ /**
+ * This will get the line join style.
+ *
+ * @return null or the LJ value in the dictionary.
+ */
+ public Long getLineJoinStyle()
+ {
+ return getLongItem( LJ );
+ }
+
+ /**
+ * This will set the line join style.
+ *
+ * @param style The new line join style.
+ */
+ public void setLineJoinStyle( Long style )
+ {
+ setLongItem( LJ, style );
+ }
+
+
+ /**
+ * This will get the miter limit.
+ *
+ * @return null or the ML value in the dictionary.
+ */
+ public Float getMiterLimit()
+ {
+ return getFloatItem( ML );
+ }
+
+ /**
+ * This will set the miter limit for the graphics state.
+ *
+ * @param miterLimit The new miter limit value
+ */
+ public void setMiterLimit( Float miterLimit )
+ {
+ setFloatItem( ML, miterLimit );
+ }
+
+ /**
+ * This will get the dash pattern.
+ *
+ * @return null or the D value in the dictionary.
+ */
+ public PDLineDashPattern getLineDashPattern()
+ {
+ PDLineDashPattern retval = null;
+ COSArray dp = (COSArray)graphicsState.getDictionaryObject( D );
+ if( dp != null )
+ {
+ retval = new PDLineDashPattern( dp );
+ }
+ return retval;
+ }
+
+ /**
+ * This will set the dash pattern for the graphics state.
+ *
+ * @param dashPattern The dash pattern
+ */
+ public void setLineDashPattern( PDLineDashPattern dashPattern )
+ {
+ graphicsState.setItem( D, dashPattern.getCOSObject() );
+ }
+
+ /**
+ * This will get the rendering intent.
+ *
+ * @return null or the RI value in the dictionary.
+ */
+ public String getRenderingIntent()
+ {
+ String retval = null;
+ COSName ri = (COSName)graphicsState.getDictionaryObject( RI );
+ if( ri != null )
+ {
+ retval = ((COSName)ri).getName();
+ }
+ return retval;
+ }
+
+ /**
+ * This will set the rendering intent for the graphics state.
+ *
+ * @param ri The new rendering intent
+ */
+ public void setRenderingIntent( String ri )
+ {
+ COSName intent = null;
+ if( ri != null )
+ {
+ intent = COSName.getPDFName( ri );
+ }
+ graphicsState.setItem( RI, intent );
+ }
+
+ /**
+ * This will get the overprint control.
+ *
+ * @return The overprint control or null if one has not been set.
+ */
+ public Boolean getStrokingOverprintControl()
+ {
+ return getBooleanItem( OP );
+ }
+
+ /**
+ * This will get the overprint control(OP).
+ *
+ * @param op The overprint control.
+ */
+ public void setStrokingOverprintControl( Boolean op )
+ {
+ setBooleanItem( OP, op );
+ }
+
+ /**
+ * This will get the overprint control for non stroking operations. If this
+ * value is null then the regular overprint control value will be returned.
+ *
+ * @return The overprint control or null if one has not been set.
+ */
+ public Boolean getNonStrokingOverprintControl()
+ {
+ Boolean retval = getBooleanItem( OP_NS );
+ if( retval == null )
+ {
+ retval = getStrokingOverprintControl();
+ }
+ return retval;
+ }
+
+ /**
+ * This will get the overprint control(OP).
+ *
+ * @param op The overprint control.
+ */
+ public void setNonStrokingOverprintControl( Boolean op )
+ {
+ setBooleanItem( OP_NS, op );
+ }
+
+ /**
+ * This will get the overprint control mode.
+ *
+ * @return The overprint control mode or null if one has not been set.
+ */
+ public Float getOverprintMode()
+ {
+ return getFloatItem( OPM );
+ }
+
+ /**
+ * This will get the overprint mode(OPM).
+ *
+ * @param overprintMode The overprint mode
+ */
+ public void setOverprintMode( Float overprintMode )
+ {
+ setFloatItem( OPM, overprintMode );
+ }
+
+ /**
+ * This will get the font setting of the graphics state.
+ *
+ * @return The font setting.
+ */
+ public PDFontSetting getFontSetting()
+ {
+ PDFontSetting setting = null;
+ COSArray font = (COSArray)graphicsState.getDictionaryObject( FONT );
+ if( font != null )
+ {
+ setting = new PDFontSetting( font );
+ }
+ return setting;
+ }
+
+ /**
+ * This will set the font setting for this graphics state.
+ *
+ * @param fs The new font setting.
+ */
+ public void setFontSetting( PDFontSetting fs )
+ {
+ graphicsState.setItem( FONT, fs );
+ }
+
+ /**
+ * This will get the flatness tolerance.
+ *
+ * @return The flatness tolerance or null if one has not been set.
+ */
+ public Float getFlatnessTolerance()
+ {
+ return getFloatItem( FL );
+ }
+
+ /**
+ * This will get the flatness tolerance.
+ *
+ * @param flatness The new flatness tolerance
+ */
+ public void setFlatnessTolerance( Float flatness )
+ {
+ setFloatItem( FL, flatness );
+ }
+
+ /**
+ * This will get the smothness tolerance.
+ *
+ * @return The smothness tolerance or null if one has not been set.
+ */
+ public Float getSmoothnessTolerance()
+ {
+ return getFloatItem( SM );
+ }
+
+ /**
+ * This will get the smoothness tolerance.
+ *
+ * @param smoothness The new smoothness tolerance
+ */
+ public void setSmoothnessTolerance( Float smoothness )
+ {
+ setFloatItem( SM, smoothness );
+ }
+
+ /**
+ * This will get the automatic stroke adjustment flag.
+ *
+ * @return The automatic stroke adjustment flag or null if one has not been set.
+ */
+ public Boolean getAutomaticStrokeAdjustment()
+ {
+ return getBooleanItem( SA );
+ }
+
+ /**
+ * This will get the automatic stroke adjustment flag.
+ *
+ * @param sa The new automatic stroke adjustment flag.
+ */
+ public void setAutomaticStrokeAdjustment( Boolean sa )
+ {
+ setBooleanItem( SA, sa );
+ }
+
+ /**
+ * This will get the stroking alpha constant.
+ *
+ * @return The stroking alpha constant or null if one has not been set.
+ */
+ public Float getStrokingAlpaConstant()
+ {
+ return getFloatItem( CA );
+ }
+
+ /**
+ * This will get the stroking alpha constant.
+ *
+ * @param alpha The new stroking alpha constant.
+ */
+ public void setStrokingAlphaConstant( Float alpha )
+ {
+ setFloatItem( CA, alpha );
+ }
+
+ /**
+ * This will get the non stroking alpha constant.
+ *
+ * @return The non stroking alpha constant or null if one has not been set.
+ */
+ public Float getNonStrokingAlpaConstant()
+ {
+ return getFloatItem( CA_NS );
+ }
+
+ /**
+ * This will get the non stroking alpha constant.
+ *
+ * @param alpha The new non stroking alpha constant.
+ */
+ public void setNonStrokingAlphaConstant( Float alpha )
+ {
+ setFloatItem( CA_NS, alpha );
+ }
+
+ /**
+ * This will get the alpha source flag.
+ *
+ * @return The alpha source flag.
+ */
+ public Boolean getAlpaSourceFlag()
+ {
+ return getBooleanItem( AIS );
+ }
+
+ /**
+ * This will get the alpha source flag.
+ *
+ * @param alpha The alpha source flag.
+ */
+ public void setAlphaSourceFlag( Boolean alpha )
+ {
+ setBooleanItem( AIS, alpha );
+ }
+
+ /**
+ * This will get the text knockout flag.
+ *
+ * @return The text knockout flag.
+ */
+ public Boolean getTextKnockoutFlag()
+ {
+ return getBooleanItem( TK );
+ }
+
+ /**
+ * This will get the text knockout flag.
+ *
+ * @param tk The text knockout flag.
+ */
+ public void setTextKnockoutFlag( Boolean tk )
+ {
+ setBooleanItem( TK, tk );
+ }
+
+ /**
+ * This will get a float item from the dictionary.
+ *
+ * @param key The key to the item.
+ *
+ * @return The value for that item.
+ */
+ private Float getFloatItem( COSName key )
+ {
+ Float retval = null;
+ COSNumber value = (COSNumber)graphicsState.getDictionaryObject( key );
+ if( value != null )
+ {
+ retval = new Float( value.floatValue() );
+ }
+ return retval;
+ }
+
+ /**
+ * This will set a float object.
+ *
+ * @param key The key to the data that we are setting.
+ * @param value The value that we are setting.
+ */
+ private void setFloatItem( COSName key, Float value )
+ {
+ if( value == null )
+ {
+ graphicsState.removeItem( key );
+ }
+ else
+ {
+ graphicsState.setItem( key, new COSFloat( value.floatValue() ) );
+ }
+ }
+
+ /**
+ * This will get a integer item from the dictionary.
+ *
+ * @param key The key to the item.
+ *
+ * @return The value for that item.
+ */
+ private Integer getIntegerItem( COSName key )
+ {
+ Integer retval = null;
+ COSNumber value = (COSNumber)graphicsState.getDictionaryObject( key );
+ if( value != null )
+ {
+ retval = new Integer( value.intValue() );
+ }
+ return retval;
+ }
+
+ /**
+ * This will set a integer object.
+ *
+ * @param key The key to the data that we are setting.
+ * @param value The value that we are setting.
+ */
+ private void setIntegerItem( COSName key, Integer value )
+ {
+ if( value == null )
+ {
+ graphicsState.removeItem( key );
+ }
+ else
+ {
+ graphicsState.setItem( key, new COSInteger( value.intValue() ) );
+ }
+ }
+
+ /**
+ * This will get an int item from the dictionary.
+ *
+ * @param key The key to the item.
+ *
+ * @return The value for that item.
+ */
+ private Long getLongItem( COSName key )
+ {
+ Long retval = null;
+ COSNumber value = (COSNumber)graphicsState.getDictionaryObject( key );
+ if( value != null )
+ {
+ retval = new Long( value.intValue() );
+ }
+ return retval;
+ }
+
+ /**
+ * This will set an integer object.
+ *
+ * @param key The key to the data that we are setting.
+ * @param value The value that we are setting.
+ */
+ private void setLongItem( COSName key, Long value )
+ {
+ if( value == null )
+ {
+ graphicsState.removeItem( key );
+ }
+ else
+ {
+ graphicsState.setItem( key, new COSInteger( value.longValue() ) );
+ }
+ }
+
+ /**
+ * This will get a boolean item from the dictionary.
+ *
+ * @param key The key to the item.
+ *
+ * @return The value for that item.
+ */
+ private Boolean getBooleanItem( COSName key )
+ {
+ Boolean retval = null;
+ COSBoolean value = (COSBoolean)graphicsState.getDictionaryObject( key );
+ if( value != null )
+ {
+ retval = value.getValueAsObject();
+ }
+ return retval;
+ }
+
+ /**
+ * This will set an boolean object.
+ *
+ * @param key The key to the data that we are setting.
+ * @param value The value that we are setting.
+ */
+ private void setBooleanItem( COSName key, Boolean value )
+ {
+ if( value == null )
+ {
+ graphicsState.removeItem( key );
+ }
+ else
+ {
+ graphicsState.setItem( key, COSBoolean.getBoolean( value ) );
+ }
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/graphics/PDFontSetting.java b/src/main/java/org/pdfbox/pdmodel/graphics/PDFontSetting.java
new file mode 100644
index 0000000..039609f
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/graphics/PDFontSetting.java
@@ -0,0 +1,133 @@
+/**
+ * Copyright (c) 2003, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.graphics;
+
+import org.pdfbox.cos.COSArray;
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSFloat;
+import org.pdfbox.cos.COSNumber;
+
+import org.pdfbox.pdmodel.common.COSObjectable;
+
+import org.pdfbox.pdmodel.font.PDFont;
+import org.pdfbox.pdmodel.font.PDFontFactory;
+
+import java.io.IOException;
+
+/**
+ * This class represents a font setting used for the graphics state. A font setting is a font and a
+ * font size. Maybe there is a better name for this?
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.3 $
+ */
+public class PDFontSetting implements COSObjectable
+{
+ private COSArray fontSetting = null;
+
+ /**
+ * Creates a blank font setting, font will be null, size will be 1.
+ */
+ public PDFontSetting()
+ {
+ fontSetting = new COSArray();
+ fontSetting.add( null );
+ fontSetting.add( new COSFloat( 1 ) );
+ }
+
+ /**
+ * Constructs a font setting from an existing array.
+ *
+ * @param fs The new font setting value.
+ */
+ public PDFontSetting( COSArray fs )
+ {
+ fontSetting = fs;
+ }
+
+ /**
+ * @see COSObjectable#getCOSObject()
+ */
+ public COSBase getCOSObject()
+ {
+ return fontSetting;
+ }
+
+ /**
+ * This will get the font for this font setting.
+ *
+ * @return The font for this setting of null if one was not found.
+ *
+ * @throws IOException If there is an error getting the font.
+ */
+ public PDFont getFont() throws IOException
+ {
+ PDFont retval = null;
+ COSBase font = fontSetting.get( 0 );
+ if( font instanceof COSDictionary )
+ {
+ retval = PDFontFactory.createFont( (COSDictionary)font );
+ }
+ return retval;
+ }
+
+ /**
+ * This will set the font for this font setting.
+ *
+ * @param font The new font.
+ */
+ public void setFont( PDFont font )
+ {
+ fontSetting.set( 0, font );
+ }
+
+ /**
+ * This will get the size of the font.
+ *
+ * @return The size of the font.
+ */
+ public float getFontSize()
+ {
+ COSNumber size = (COSNumber)fontSetting.get( 1 );
+ return size.floatValue();
+ }
+
+ /**
+ * This will set the size of the font.
+ *
+ * @param size The new size of the font.
+ */
+ public void setFontSize( float size )
+ {
+ fontSetting.set( 1, new COSFloat( size ) );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/graphics/PDGraphicsState.java b/src/main/java/org/pdfbox/pdmodel/graphics/PDGraphicsState.java
new file mode 100644
index 0000000..4115198
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/graphics/PDGraphicsState.java
@@ -0,0 +1,438 @@
+/**
+ * Copyright (c) 2003, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.graphics;
+
+import org.pdfbox.util.Matrix;
+
+import org.pdfbox.pdmodel.text.PDTextState;
+
+import org.pdfbox.pdmodel.graphics.color.PDColorSpaceInstance;
+
+/**
+ * This class will hold the current state of the graphics parameters when executing a
+ * content stream.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.3 $
+ */
+public class PDGraphicsState implements Cloneable
+{
+ private Matrix currentTransformationMatrix = new Matrix();
+
+ //Here are some attributes of the Graphics state, but have not been created yet.
+ //
+ //clippingPath
+ private PDColorSpaceInstance strokingColorSpace = new PDColorSpaceInstance();
+ private PDColorSpaceInstance nonStrokingColorSpace = new PDColorSpaceInstance();
+ private PDTextState textState = new PDTextState();
+ private double lineWidth = 0;
+ private int lineCap = 0;
+ private int lineJoin = 0;
+ private double miterLimit = 0;
+ private PDLineDashPattern lineDashPattern;
+ private String renderingIntent;
+ private boolean strokeAdjustment = false;
+ //blend mode
+ //soft mask
+ private double alphaConstants = 0;
+ private boolean alphaSource = false;
+
+ //DEVICE DEPENDENT parameters
+ private boolean overprint = false;
+ private double overprintMode = 0;
+ //black generation
+ //undercolor removal
+ //transfer
+ //halftone
+ private double flatness = 1.0;
+ private double smoothness = 0;
+
+ /**
+ * Get the value of the CTM.
+ *
+ * @return The current transformation matrix.
+ */
+ public Matrix getCurrentTransformationMatrix()
+ {
+ return currentTransformationMatrix;
+ }
+
+ /**
+ * Set the value of the CTM.
+ *
+ * @param value The current transformation matrix.
+ */
+ public void setCurrentTransformationMatrix(Matrix value)
+ {
+ currentTransformationMatrix = value;
+ }
+
+ /**
+ * Get the value of the line width.
+ *
+ * @return The current line width.
+ */
+ public double getLineWidth()
+ {
+ return lineWidth;
+ }
+
+ /**
+ * set the value of the line width.
+ *
+ * @param value The current line width.
+ */
+ public void setLineWidth(double value)
+ {
+ lineWidth = value;
+ }
+
+ /**
+ * Get the value of the line cap.
+ *
+ * @return The current line cap.
+ */
+ public int getLineCap()
+ {
+ return lineCap;
+ }
+
+ /**
+ * set the value of the line cap.
+ *
+ * @param value The current line cap.
+ */
+ public void setLineCap(int value)
+ {
+ lineCap = value;
+ }
+
+ /**
+ * Get the value of the line join.
+ *
+ * @return The current line join value.
+ */
+ public int getLineJoin()
+ {
+ return lineJoin;
+ }
+
+ /**
+ * Get the value of the line join.
+ *
+ * @param value The current line join
+ */
+ public void setLineJoin(int value)
+ {
+ lineJoin = value;
+ }
+
+ /**
+ * Get the value of the miter limit.
+ *
+ * @return The current miter limit.
+ */
+ public double getMiterLimit()
+ {
+ return miterLimit;
+ }
+
+ /**
+ * set the value of the miter limit.
+ *
+ * @param value The current miter limit.
+ */
+ public void setMiterLimit(double value)
+ {
+ miterLimit = value;
+ }
+
+ /**
+ * Get the value of the stroke adjustment parameter.
+ *
+ * @return The current stroke adjustment.
+ */
+ public boolean isStrokeAdjustment()
+ {
+ return strokeAdjustment;
+ }
+
+ /**
+ * set the value of the stroke adjustment.
+ *
+ * @param value The value of the stroke adjustment parameter.
+ */
+ public void setStrokeAdjustment(boolean value)
+ {
+ strokeAdjustment = value;
+ }
+
+ /**
+ * Get the value of the alpha constants property.
+ *
+ * @return The value of the alpha constants parameter.
+ */
+ public double getAlphaConstants()
+ {
+ return alphaConstants;
+ }
+
+ /**
+ * set the value of the alpha constants property.
+ *
+ * @param value The value of the alpha constants parameter.
+ */
+ public void setAlphaConstants(double value)
+ {
+ alphaConstants = value;
+ }
+
+ /**
+ * get the value of the alpha source property.
+ *
+ * @return The value of the alpha source parameter.
+ */
+ public boolean isAlphaSource()
+ {
+ return alphaSource;
+ }
+
+ /**
+ * set the value of the alpha source property.
+ *
+ * @param value The value of the alpha source parameter.
+ */
+ public void setAlphaSource(boolean value)
+ {
+ alphaSource = value;
+ }
+
+ /**
+ * get the value of the overprint property.
+ *
+ * @return The value of the overprint parameter.
+ */
+ public boolean isOverprint()
+ {
+ return overprint;
+ }
+
+ /**
+ * set the value of the overprint property.
+ *
+ * @param value The value of the overprint parameter.
+ */
+ public void setOverprint(boolean value)
+ {
+ overprint = value;
+ }
+
+ /**
+ * get the value of the overprint mode property.
+ *
+ * @return The value of the overprint mode parameter.
+ */
+ public double getOverprintMode()
+ {
+ return overprintMode;
+ }
+
+ /**
+ * set the value of the overprint mode property.
+ *
+ * @param value The value of the overprint mode parameter.
+ */
+ public void setOverprintMode(double value)
+ {
+ overprintMode = value;
+ }
+
+ /**
+ * get the value of the flatness property.
+ *
+ * @return The value of the flatness parameter.
+ */
+ public double getFlatness()
+ {
+ return flatness;
+ }
+
+ /**
+ * set the value of the flatness property.
+ *
+ * @param value The value of the flatness parameter.
+ */
+ public void setFlatness(double value)
+ {
+ flatness = value;
+ }
+
+ /**
+ * get the value of the smoothness property.
+ *
+ * @return The value of the smoothness parameter.
+ */
+ public double getSmoothness()
+ {
+ return smoothness;
+ }
+
+ /**
+ * set the value of the smoothness property.
+ *
+ * @param value The value of the smoothness parameter.
+ */
+ public void setSmoothness(double value)
+ {
+ smoothness = value;
+ }
+
+ /**
+ * This will get the graphics text state.
+ *
+ * @return The graphics text state.
+ */
+ public PDTextState getTextState()
+ {
+ return textState;
+ }
+
+ /**
+ * This will set the graphics text state.
+ *
+ * @param value The graphics text state.
+ */
+ public void setTextState(PDTextState value)
+ {
+ textState = value;
+ }
+
+ /**
+ * This will get the current line dash pattern.
+ *
+ * @return The line dash pattern.
+ */
+ public PDLineDashPattern getLineDashPattern()
+ {
+ return lineDashPattern;
+ }
+
+ /**
+ * This will set the current line dash pattern.
+ *
+ * @param value The new line dash pattern.
+ */
+ public void setLineDashPattern(PDLineDashPattern value)
+ {
+ lineDashPattern = value;
+ }
+
+ /**
+ * This will get the rendering intent.
+ *
+ * @see PDExtendedGraphicsState
+ *
+ * @return The rendering intent
+ */
+ public String getRenderingIntent()
+ {
+ return renderingIntent;
+ }
+
+ /**
+ * This will set the rendering intent.
+ *
+ * @param value The new rendering intent.
+ */
+ public void setRenderingIntent(String value)
+ {
+ renderingIntent = value;
+ }
+
+ /**
+ * @see Object#clone()
+ */
+ public Object clone()
+ {
+ PDGraphicsState clone = null;
+ try
+ {
+ clone = (PDGraphicsState)super.clone();
+ clone.setTextState( (PDTextState)textState.clone() );
+ clone.setCurrentTransformationMatrix( currentTransformationMatrix.copy() );
+ }
+ catch( CloneNotSupportedException e )
+ {
+ e.printStackTrace();
+ }
+ return clone;
+ }
+
+ /**
+ * This will get the current stroking colorspace.
+ *
+ * @return The current stroking colorspace.
+ */
+ public PDColorSpaceInstance getStrokingColorSpace()
+ {
+ return strokingColorSpace;
+ }
+
+ /**
+ * This will set the current stroking colorspace.
+ *
+ * @param value The new stroking colorspace instance.
+ */
+ public void setStrokingColorSpace(PDColorSpaceInstance value)
+ {
+ strokingColorSpace = value;
+ }
+
+ /**
+ * This will get the nonstroking color space instance.
+ *
+ * @return The colorspace instance.
+ */
+ public PDColorSpaceInstance getNonStrokingColorSpace()
+ {
+ return nonStrokingColorSpace;
+ }
+
+ /**
+ * This will set the non-stroking colorspace instance.
+ *
+ * @param value The non-stroking colorspace instance.
+ */
+ public void setNonStrokingColorSpace(PDColorSpaceInstance value)
+ {
+ nonStrokingColorSpace = value;
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/graphics/PDLineDashPattern.java b/src/main/java/org/pdfbox/pdmodel/graphics/PDLineDashPattern.java
new file mode 100644
index 0000000..a67d5e4
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/graphics/PDLineDashPattern.java
@@ -0,0 +1,135 @@
+/**
+ * Copyright (c) 2003-2005, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.graphics;
+
+import org.pdfbox.cos.COSArray;
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSInteger;
+import org.pdfbox.cos.COSNumber;
+
+import org.pdfbox.pdmodel.common.COSArrayList;
+import org.pdfbox.pdmodel.common.COSObjectable;
+
+import java.util.List;
+
+/**
+ * This class represents the line dash pattern for a graphics state. See PDF
+ * Reference 1.5 section 4.3.2
+ *
+ * @author Ben Litchfield (ben@benlitchfield.com)
+ * @version $Revision: 1.4 $
+ */
+public class PDLineDashPattern implements COSObjectable
+{
+ private COSArray lineDashPattern = null;
+
+ /**
+ * Creates a blank line dash pattern. With no dashes and a phase of 0.
+ */
+ public PDLineDashPattern()
+ {
+ lineDashPattern = new COSArray();
+ lineDashPattern.add( new COSArray() );
+ lineDashPattern.add( new COSInteger( 0 ) );
+ }
+
+ /**
+ * Constructs a line dash pattern from an existing array.
+ *
+ * @param ldp The existing line dash pattern.
+ */
+ public PDLineDashPattern( COSArray ldp )
+ {
+ lineDashPattern = ldp;
+ }
+
+ /**
+ * @see COSObjectable#getCOSObject()
+ */
+ public COSBase getCOSObject()
+ {
+ return lineDashPattern;
+ }
+
+ /**
+ * This will get the line dash pattern phase. The dash phase specifies the
+ * distance into the dash pattern at which to start the dash.
+ *
+ * @return The line dash pattern phase.
+ */
+ public int getPhaseStart()
+ {
+ COSNumber phase = (COSNumber)lineDashPattern.get( 1 );
+ return phase.intValue();
+ }
+
+ /**
+ * This will set the line dash pattern phase.
+ *
+ * @param phase The new line dash patter phase.
+ */
+ public void setPhaseStart( int phase )
+ {
+ lineDashPattern.set( 1, new COSInteger( phase ) );
+ }
+
+ /**
+ * This will return a list of java.lang.Integer objects that represent the line
+ * dash pattern appearance.
+ *
+ * @return The line dash pattern.
+ */
+ public List getDashPattern()
+ {
+ COSArray dashPatterns = (COSArray)lineDashPattern.get( 0 );
+ return COSArrayList.convertIntegerCOSArrayToList( dashPatterns );
+ }
+
+ /**
+ * Get the line dash pattern as a COS object.
+ *
+ * @return The cos array line dash pattern.
+ */
+ public COSArray getCOSDashPattern()
+ {
+ return (COSArray)lineDashPattern.get( 0 );
+ }
+
+ /**
+ * This will replace the existing line dash pattern.
+ *
+ * @param dashPattern A list of java.lang.Integer objects.
+ */
+ public void setDashPattern( List dashPattern )
+ {
+ lineDashPattern.set( 0, COSArrayList.converterToCOSArray( dashPattern ) );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/graphics/color/PDCalGray.java b/src/main/java/org/pdfbox/pdmodel/graphics/color/PDCalGray.java
new file mode 100644
index 0000000..fc6f84e
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/graphics/color/PDCalGray.java
@@ -0,0 +1,240 @@
+/**
+ * Copyright (c) 2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.graphics.color;
+
+import org.pdfbox.cos.COSArray;
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSFloat;
+import org.pdfbox.cos.COSName;
+import org.pdfbox.cos.COSNumber;
+
+import java.awt.color.ColorSpace;
+import java.awt.image.ColorModel;
+
+import java.io.IOException;
+
+/**
+ * This class represents a Cal Gray color space.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.4 $
+ */
+public class PDCalGray extends PDColorSpace
+{
+ /**
+ * The name of this color space.
+ */
+ public static final String NAME = "CalGray";
+
+ private COSArray array;
+ private COSDictionary dictionary;
+
+ /**
+ * Constructor.
+ */
+ public PDCalGray()
+ {
+ array = new COSArray();
+ dictionary = new COSDictionary();
+ array.add( COSName.getPDFName( NAME ) );
+ array.add( dictionary );
+ }
+
+ /**
+ * Constructor with array.
+ *
+ * @param gray The underlying color space.
+ */
+ public PDCalGray( COSArray gray )
+ {
+ array = gray;
+ dictionary = (COSDictionary)array.getObject( 1 );
+ }
+
+ /**
+ * This will get the number of components that this color space is made up of.
+ *
+ * @return The number of components in this color space.
+ *
+ * @throws IOException If there is an error getting the number of color components.
+ */
+ public int getNumberOfComponents() throws IOException
+ {
+ return 1;
+ }
+
+ /**
+ * This will return the name of the color space.
+ *
+ * @return The name of the color space.
+ */
+ public String getName()
+ {
+ return NAME;
+ }
+
+ /**
+ * Create a Java colorspace for this colorspace.
+ *
+ * @return A color space that can be used for Java AWT operations.
+ *
+ * @throws IOException If there is an error creating the color space.
+ */
+ public ColorSpace createColorSpace() throws IOException
+ {
+ throw new IOException( "Not implemented" );
+ }
+
+ /**
+ * Create a Java color model for this colorspace.
+ *
+ * @param bpc The number of bits per component.
+ *
+ * @return A color model that can be used for Java AWT operations.
+ *
+ * @throws IOException If there is an error creating the color model.
+ */
+ public ColorModel createColorModel( int bpc ) throws IOException
+ {
+ throw new IOException( "Not implemented" );
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSBase getCOSObject()
+ {
+ return array;
+ }
+
+ /**
+ * This will get the gamma value. If none is present then the default of 1
+ * will be returned.
+ *
+ * @return The gamma value.
+ */
+ public float getGamma()
+ {
+ float retval = 1.0f;
+ COSNumber gamma = (COSNumber)dictionary.getDictionaryObject( COSName.getPDFName( "Gamma" ) );
+ if( gamma != null )
+ {
+ retval = gamma.floatValue();
+ }
+ return retval;
+ }
+
+ /**
+ * Set the gamma value.
+ *
+ * @param value The new gamma value.
+ */
+ public void setGamma( float value )
+ {
+ dictionary.setItem( COSName.getPDFName( "Gamma" ), new COSFloat( value ) );
+ }
+
+ /**
+ * This will return the whitepoint tristimulus. As this is a required field
+ * this will never return null. A default of 1,1,1 will be returned if the
+ * pdf does not have any values yet.
+ *
+ * @return The whitepoint tristimulus.
+ */
+ public PDTristimulus getWhitepoint()
+ {
+ PDTristimulus retval = null;
+ COSArray wp = (COSArray)dictionary.getDictionaryObject( COSName.getPDFName( "WhitePoint" ) );
+ if( wp == null )
+ {
+ wp.add( new COSFloat( 1.0f ) );
+ wp.add( new COSFloat( 1.0f ) );
+ wp.add( new COSFloat( 1.0f ) );
+ dictionary.setItem( COSName.getPDFName( "WhitePoint" ), wp );
+ }
+ return new PDTristimulus( wp );
+ }
+
+ /**
+ * This will set the whitepoint tristimulus. As this is a required field
+ * this null should not be passed into this function.
+ *
+ * @param wp The whitepoint tristimulus.
+ */
+ public void setWhitepoint( PDTristimulus wp )
+ {
+ COSBase wpArray = wp.getCOSObject();
+ if( wpArray != null )
+ {
+ dictionary.setItem( COSName.getPDFName( "WhitePoint" ), wpArray );
+ }
+ }
+
+ /**
+ * This will return the BlackPoint tristimulus. This is an optional field but
+ * has defaults so this will never return null.
+ * A default of 0,0,0 will be returned if the pdf does not have any values yet.
+ *
+ * @return The blackpoint tristimulus.
+ */
+ public PDTristimulus getBlackPoint()
+ {
+ PDTristimulus retval = null;
+ COSArray bp = (COSArray)dictionary.getDictionaryObject( COSName.getPDFName( "BlackPoint" ) );
+ if( bp == null )
+ {
+ bp.add( new COSFloat( 0.0f ) );
+ bp.add( new COSFloat( 0.0f ) );
+ bp.add( new COSFloat( 0.0f ) );
+ dictionary.setItem( COSName.getPDFName( "BlackPoint" ), bp );
+ }
+ return new PDTristimulus( bp );
+ }
+
+ /**
+ * This will set the BlackPoint tristimulus. As this is a required field
+ * this null should not be passed into this function.
+ *
+ * @param bp The BlackPoint tristimulus.
+ */
+ public void setBlackPoint( PDTristimulus bp )
+ {
+ COSBase bpArray = null;
+ if( bp != null )
+ {
+ bpArray = bp.getCOSObject();
+ }
+ dictionary.setItem( COSName.getPDFName( "BlackPoint" ), bpArray );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/graphics/color/PDCalRGB.java b/src/main/java/org/pdfbox/pdmodel/graphics/color/PDCalRGB.java
new file mode 100644
index 0000000..6aa4eb1
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/graphics/color/PDCalRGB.java
@@ -0,0 +1,289 @@
+/**
+ * Copyright (c) 2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.graphics.color;
+
+import org.pdfbox.cos.COSArray;
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSFloat;
+import org.pdfbox.cos.COSName;
+
+import org.pdfbox.pdmodel.common.PDMatrix;
+
+import java.awt.color.ColorSpace;
+import java.awt.image.ColorModel;
+
+import java.io.IOException;
+
+/**
+ * This class represents a Cal RGB color space.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.2 $
+ */
+public class PDCalRGB extends PDColorSpace
+{
+ /**
+ * The name of this color space.
+ */
+ public static final String NAME = "CalRGB";
+
+ private COSArray array;
+ private COSDictionary dictionary;
+
+ /**
+ * Constructor.
+ */
+ public PDCalRGB()
+ {
+ array = new COSArray();
+ dictionary = new COSDictionary();
+ array.add( COSName.getPDFName( NAME ) );
+ array.add( dictionary );
+ }
+
+ /**
+ * Constructor with array.
+ *
+ * @param rgb The underlying color space.
+ */
+ public PDCalRGB( COSArray rgb )
+ {
+ array = rgb;
+ dictionary = (COSDictionary)array.getObject( 1 );
+ }
+
+ /**
+ * This will get the number of components that this color space is made up of.
+ *
+ * @return The number of components in this color space.
+ *
+ * @throws IOException If there is an error getting the number of color components.
+ */
+ public int getNumberOfComponents() throws IOException
+ {
+ return 3;
+ }
+
+ /**
+ * This will return the name of the color space.
+ *
+ * @return The name of the color space.
+ */
+ public String getName()
+ {
+ return NAME;
+ }
+
+ /**
+ * Create a Java colorspace for this colorspace.
+ *
+ * @return A color space that can be used for Java AWT operations.
+ *
+ * @throws IOException If there is an error creating the color space.
+ */
+ public ColorSpace createColorSpace() throws IOException
+ {
+ throw new IOException( "Not implemented" );
+ }
+
+ /**
+ * Create a Java color model for this colorspace.
+ *
+ * @param bpc The number of bits per component.
+ *
+ * @return A color model that can be used for Java AWT operations.
+ *
+ * @throws IOException If there is an error creating the color model.
+ */
+ public ColorModel createColorModel( int bpc ) throws IOException
+ {
+ throw new IOException( "Not implemented" );
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSBase getCOSObject()
+ {
+ return array;
+ }
+
+ /**
+ * This will return the whitepoint tristimulus. As this is a required field
+ * this will never return null. A default of 1,1,1 will be returned if the
+ * pdf does not have any values yet.
+ *
+ * @return The whitepoint tristimulus.
+ */
+ public PDTristimulus getWhitepoint()
+ {
+ PDTristimulus retval = null;
+ COSArray wp = (COSArray)dictionary.getDictionaryObject( COSName.getPDFName( "WhitePoint" ) );
+ if( wp == null )
+ {
+ wp.add( new COSFloat( 1.0f ) );
+ wp.add( new COSFloat( 1.0f ) );
+ wp.add( new COSFloat( 1.0f ) );
+ dictionary.setItem( COSName.getPDFName( "WhitePoint" ), wp );
+ }
+ return new PDTristimulus( wp );
+ }
+
+ /**
+ * This will set the whitepoint tristimulus. As this is a required field
+ * this null should not be passed into this function.
+ *
+ * @param wp The whitepoint tristimulus.
+ */
+ public void setWhitepoint( PDTristimulus wp )
+ {
+ COSBase wpArray = wp.getCOSObject();
+ if( wpArray != null )
+ {
+ dictionary.setItem( COSName.getPDFName( "WhitePoint" ), wpArray );
+ }
+ }
+
+ /**
+ * This will return the BlackPoint tristimulus. This is an optional field but
+ * has defaults so this will never return null.
+ * A default of 0,0,0 will be returned if the pdf does not have any values yet.
+ *
+ * @return The blackpoint tristimulus.
+ */
+ public PDTristimulus getBlackPoint()
+ {
+ PDTristimulus retval = null;
+ COSArray bp = (COSArray)dictionary.getDictionaryObject( COSName.getPDFName( "BlackPoint" ) );
+ if( bp == null )
+ {
+ bp.add( new COSFloat( 0.0f ) );
+ bp.add( new COSFloat( 0.0f ) );
+ bp.add( new COSFloat( 0.0f ) );
+ dictionary.setItem( COSName.getPDFName( "BlackPoint" ), bp );
+ }
+ return new PDTristimulus( bp );
+ }
+
+ /**
+ * This will set the BlackPoint tristimulus. As this is a required field
+ * this null should not be passed into this function.
+ *
+ * @param bp The BlackPoint tristimulus.
+ */
+ public void setBlackPoint( PDTristimulus bp )
+ {
+
+ COSBase bpArray = null;
+ if( bp != null )
+ {
+ bpArray = bp.getCOSObject();
+ }
+ dictionary.setItem( COSName.getPDFName( "BlackPoint" ), bpArray );
+ }
+
+ /**
+ * This will get the gamma value. If none is present then the default of 1,1,1
+ * will be returned.
+ *
+ * @return The gamma value.
+ */
+ public PDGamma getGamma()
+ {
+ COSArray gamma = (COSArray)dictionary.getDictionaryObject( COSName.getPDFName( "Gamma" ) );
+ if( gamma == null )
+ {
+ gamma = new COSArray();
+ gamma.add( new COSFloat( 1.0f ) );
+ gamma.add( new COSFloat( 1.0f ) );
+ gamma.add( new COSFloat( 1.0f ) );
+ dictionary.setItem( COSName.getPDFName( "Gamma" ), gamma );
+ }
+ return new PDGamma( gamma );
+ }
+
+ /**
+ * Set the gamma value.
+ *
+ * @param value The new gamma value.
+ */
+ public void setGamma( PDGamma value )
+ {
+ COSArray gamma = null;
+ if( value != null )
+ {
+ gamma = (COSArray)value.getCOSArray();
+ }
+ dictionary.setItem( COSName.getPDFName( "Gamma" ), gamma );
+ }
+
+ /**
+ * This will get the linear interpretation array. This is guaranteed to not
+ * return null. If the underlying dictionary contains null then the identity
+ * matrix will be returned.
+ *
+ * @return The linear interpretation matrix.
+ */
+ public PDMatrix getLinearInterpretation()
+ {
+ PDMatrix retval = null;
+ COSArray matrix = (COSArray)dictionary.getDictionaryObject( COSName.getPDFName( "Matrix" ) );
+ if( matrix == null )
+ {
+ retval = new PDMatrix();
+ setLinearInterpretation( retval );
+ }
+ else
+ {
+ retval = new PDMatrix( matrix );
+ }
+ return retval;
+ }
+
+ /**
+ * This will set the linear interpretation matrix. Passing in null will
+ * clear the matrix.
+ *
+ * @param matrix The new linear interpretation matrix.
+ */
+ public void setLinearInterpretation( PDMatrix matrix )
+ {
+ COSArray matrixArray = null;
+ if( matrix != null )
+ {
+ matrixArray = matrix.getCOSArray();
+ }
+ dictionary.setItem( COSName.getPDFName( "Matrix" ), matrixArray );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/graphics/color/PDColorSpace.java b/src/main/java/org/pdfbox/pdmodel/graphics/color/PDColorSpace.java
new file mode 100644
index 0000000..33ac0a1
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/graphics/color/PDColorSpace.java
@@ -0,0 +1,97 @@
+/**
+ * Copyright (c) 2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.graphics.color;
+
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSName;
+
+import org.pdfbox.pdmodel.common.COSObjectable;
+
+import java.io.IOException;
+
+import java.awt.color.ColorSpace;
+import java.awt.image.ColorModel;
+
+
+/**
+ * This class represents a color space in a pdf document.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.4 $
+ */
+public abstract class PDColorSpace implements COSObjectable
+{
+ /**
+ * This will return the name of the color space.
+ *
+ * @return The name of the color space.
+ */
+ public abstract String getName();
+
+ /**
+ * This will get the number of components that this color space is made up of.
+ *
+ * @return The number of components in this color space.
+ *
+ * @throws IOException If there is an error getting the number of color components.
+ */
+ public abstract int getNumberOfComponents() throws IOException;
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSBase getCOSObject()
+ {
+ return COSName.getPDFName( getName() );
+ }
+
+ /**
+ * Create a Java colorspace for this colorspace.
+ *
+ * @return A color space that can be used for Java AWT operations.
+ *
+ * @throws IOException If there is an error creating the color space.
+ */
+ public abstract ColorSpace createColorSpace() throws IOException;
+
+ /**
+ * Create a Java color model for this colorspace.
+ *
+ * @param bpc The number of bits per component.
+ *
+ * @return A color model that can be used for Java AWT operations.
+ *
+ * @throws IOException If there is an error creating the color model.
+ */
+ public abstract ColorModel createColorModel( int bpc ) throws IOException;
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/graphics/color/PDColorSpaceFactory.java b/src/main/java/org/pdfbox/pdmodel/graphics/color/PDColorSpaceFactory.java
new file mode 100644
index 0000000..8c9aad5
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/graphics/color/PDColorSpaceFactory.java
@@ -0,0 +1,218 @@
+/**
+ * Copyright (c) 2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.graphics.color;
+
+import java.awt.color.ColorSpace;
+import java.awt.color.ICC_ColorSpace;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.pdfbox.cos.COSArray;
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSFloat;
+import org.pdfbox.cos.COSName;
+import org.pdfbox.pdmodel.PDDocument;
+import org.pdfbox.pdmodel.common.PDStream;
+
+/**
+ * This class represents a color space in a pdf document.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.10 $
+ */
+public final class PDColorSpaceFactory
+{
+ /**
+ * Private constructor for utility classes.
+ */
+ private PDColorSpaceFactory()
+ {
+ //utility class should not be implemented
+ }
+
+ /**
+ * This will create the correct color space given the name.
+ *
+ * @param colorSpace The color space object.
+ *
+ * @return The color space.
+ *
+ * @throws IOException If the color space name is unknown.
+ */
+ public static PDColorSpace createColorSpace( COSBase colorSpace ) throws IOException
+ {
+ PDColorSpace retval = null;
+ if( colorSpace instanceof COSName )
+ {
+ retval = createColorSpace( ((COSName)colorSpace).getName() );
+ }
+ else if( colorSpace instanceof COSArray )
+ {
+ COSArray array = (COSArray)colorSpace;
+ COSName type = (COSName)array.getObject( 0 );
+ if( type.getName().equals( PDCalGray.NAME ) )
+ {
+ retval = new PDCalGray( array );
+ }
+ else if( type.getName().equals( PDCalRGB.NAME ) )
+ {
+ retval = new PDCalRGB( array );
+ }
+ else if( type.getName().equals( PDDeviceN.NAME ) )
+ {
+ retval = new PDDeviceN( array );
+ }
+ else if( type.getName().equals( PDIndexed.NAME ) ||
+ type.getName().equals( PDIndexed.ABBREVIATED_NAME ))
+ {
+ retval = new PDIndexed( array );
+ }
+ else if( type.getName().equals( PDLab.NAME ) )
+ {
+ retval = new PDLab( array );
+ }
+ else if( type.getName().equals( PDSeparation.NAME ) )
+ {
+ retval = new PDSeparation( array );
+ }
+ else if( type.getName().equals( PDICCBased.NAME ) )
+ {
+ retval = new PDICCBased( array );
+ }
+ else if( type.getName().equals( PDPattern.NAME ) )
+ {
+ retval = new PDPattern( array );
+ }
+ else
+ {
+ throw new IOException( "Unknown colorspace array type:" + type );
+ }
+ }
+ else
+ {
+ throw new IOException( "Unknown colorspace type:" + colorSpace );
+ }
+ return retval;
+ }
+
+ /**
+ * This will create the correct color space given the name.
+ *
+ * @param colorSpaceName The name of the colorspace.
+ *
+ * @return The color space.
+ *
+ * @throws IOException If the color space name is unknown.
+ */
+ public static PDColorSpace createColorSpace( String colorSpaceName ) throws IOException
+ {
+ PDColorSpace cs = null;
+ if( colorSpaceName.equals( PDDeviceCMYK.NAME ) ||
+ colorSpaceName.equals( PDDeviceCMYK.ABBREVIATED_NAME ) )
+ {
+ cs = PDDeviceCMYK.INSTANCE;
+ }
+ else if( colorSpaceName.equals( PDDeviceRGB.NAME ) ||
+ colorSpaceName.equals( PDDeviceRGB.ABBREVIATED_NAME ) )
+ {
+ cs = PDDeviceRGB.INSTANCE;
+ }
+ else if( colorSpaceName.equals( PDDeviceGray.NAME ) ||
+ colorSpaceName.equals( PDDeviceGray.ABBREVIATED_NAME ))
+ {
+ cs = new PDDeviceGray();
+ }
+ else if( colorSpaceName.equals( PDLab.NAME ) )
+ {
+ cs = new PDLab();
+ }
+ else if( colorSpaceName.equals( PDPattern.NAME ) )
+ {
+ cs = new PDPattern();
+ }
+ else
+ {
+ throw new IOException( "Error: Unknown colorspace '" + colorSpaceName + "'" );
+ }
+ return cs;
+ }
+
+ /**
+ * This will create the correct color space from a java colorspace.
+ *
+ * @param doc The doc to potentiall write information to.
+ * @param cs The awt colorspace.
+ *
+ * @return The color space.
+ *
+ * @throws IOException If the color space name is unknown.
+ */
+ public static PDColorSpace createColorSpace( PDDocument doc, ColorSpace cs ) throws IOException
+ {
+ PDColorSpace retval = null;
+ if( cs.isCS_sRGB() )
+ {
+ retval = PDDeviceRGB.INSTANCE;
+ }
+ else if( cs instanceof ICC_ColorSpace )
+ {
+ ICC_ColorSpace ics = (ICC_ColorSpace)cs;
+ PDICCBased pdCS = new PDICCBased( doc );
+ retval = pdCS;
+ COSArray ranges = new COSArray();
+ for( int i=0; i<cs.getNumComponents(); i++ )
+ {
+ ranges.add( new COSFloat( ics.getMinValue( i ) ) );
+ ranges.add( new COSFloat( ics.getMaxValue( i ) ) );
+ }
+ PDStream iccData = pdCS.getPDStream();
+ OutputStream output = null;
+ try
+ {
+ output = iccData.createOutputStream();
+ output.write( ics.getProfile().getData() );
+ }
+ finally
+ {
+ if( output != null )
+ {
+ output.close();
+ }
+ }
+ pdCS.setNumberOfComponents( cs.getNumComponents() );
+ }
+ else
+ {
+ throw new IOException( "Not yet implemented:" + cs );
+ }
+ return retval;
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/graphics/color/PDColorSpaceInstance.java b/src/main/java/org/pdfbox/pdmodel/graphics/color/PDColorSpaceInstance.java
new file mode 100644
index 0000000..23693df
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/graphics/color/PDColorSpaceInstance.java
@@ -0,0 +1,130 @@
+/**
+ * Copyright (c) 2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.graphics.color;
+
+import java.awt.Color;
+import java.io.IOException;
+
+import org.pdfbox.cos.COSArray;
+
+/**
+ * This class represents a color space and the color value for that colorspace.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.3 $
+ */
+public class PDColorSpaceInstance
+{
+ private PDColorSpace colorSpace = new PDDeviceGray();
+ private COSArray colorSpaceValue = new COSArray();
+
+ /**
+ * Default constructor.
+ *
+ */
+ public PDColorSpaceInstance()
+ {
+ //do nothing
+ }
+
+ /**
+ * Create the current color from the colorspace and values.
+ * @return The current awt color.
+ * @throws IOException If there is an error creating the color.
+ */
+ public Color createColor() throws IOException
+ {
+ float[] components = colorSpaceValue.toFloatArray();
+ Color color = new Color( colorSpace.createColorSpace(), components, 1f );
+ return color;
+ }
+
+ /**
+ * Constructor with an existing color set. Default colorspace is PDDeviceGray.
+ *
+ * @param csValues The color space values.
+ */
+ public PDColorSpaceInstance( COSArray csValues )
+ {
+ colorSpaceValue = csValues;
+ }
+
+
+ /**
+ * This will get the current colorspace.
+ *
+ * @return The current colorspace.
+ */
+ public PDColorSpace getColorSpace()
+ {
+ return colorSpace;
+ }
+
+ /**
+ * This will set the current colorspace.
+ *
+ * @param value The new colorspace.
+ */
+ public void setColorSpace(PDColorSpace value)
+ {
+ colorSpace = value;
+ }
+
+ /**
+ * This will get the color space values. Either 1 for gray or 3 for RGB.
+ *
+ * @return The colorspace values.
+ */
+ public float[] getColorSpaceValue()
+ {
+ return colorSpaceValue.toFloatArray();
+ }
+
+ /**
+ * This will get the color space values. Either 1 for gray or 3 for RGB.
+ *
+ * @return The colorspace values.
+ */
+ public COSArray getCOSColorSpaceValue()
+ {
+ return colorSpaceValue;
+ }
+
+ /**
+ * This will update the colorspace values.
+ *
+ * @param value The new colorspace values.
+ */
+ public void setColorSpaceValue(float[] value)
+ {
+ colorSpaceValue.setFloatArray( value );
+ }
+}
diff --git a/src/main/java/org/pdfbox/pdmodel/graphics/color/PDDeviceCMYK.java b/src/main/java/org/pdfbox/pdmodel/graphics/color/PDDeviceCMYK.java
new file mode 100644
index 0000000..dfbdfe5
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/graphics/color/PDDeviceCMYK.java
@@ -0,0 +1,137 @@
+/**
+ * Copyright (c) 2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.graphics.color;
+
+import java.awt.color.ColorSpace;
+import java.awt.color.ICC_ColorSpace;
+import java.awt.color.ICC_Profile;
+import java.awt.image.ColorModel;
+
+import java.io.InputStream;
+import java.io.IOException;
+
+import org.pdfbox.util.ResourceLoader;
+
+/**
+ * This class represents a CMYK color space.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.5 $
+ */
+public class PDDeviceCMYK extends PDColorSpace
+{
+ /**
+ * The single instance of this class.
+ */
+ public static final PDDeviceCMYK INSTANCE = new PDDeviceCMYK();
+
+ /**
+ * The name of this color space.
+ */
+ public static final String NAME = "DeviceCMYK";
+
+ /**
+ * The abbreviated name of this color space.
+ */
+ public static final String ABBREVIATED_NAME = "CMYK";
+
+ private ColorSpace cSpace = null;
+
+ private PDDeviceCMYK()
+ {
+
+ }
+
+ /**
+ * This will return the name of the color space.
+ *
+ * @return The name of the color space.
+ */
+ public String getName()
+ {
+ return NAME;
+ }
+
+ /**
+ * This will get the number of components that this color space is made up of.
+ *
+ * @return The number of components in this color space.
+ *
+ * @throws IOException If there is an error getting the number of color components.
+ */
+ public int getNumberOfComponents() throws IOException
+ {
+ return 4;
+ }
+
+ /**
+ * Create a Java colorspace for this colorspace.
+ *
+ * @return A color space that can be used for Java AWT operations.
+ *
+ * @throws IOException If there is an error creating the color space.
+ */
+ public ColorSpace createColorSpace() throws IOException
+ {
+ if( cSpace == null )
+ {
+ InputStream profile = null;
+ try
+ {
+ profile = ResourceLoader.loadResource( "Resources/colorspace-profiles/CMYK.pf" );
+ ICC_Profile iccProfile = ICC_Profile.getInstance( profile );
+ cSpace = new ICC_ColorSpace( iccProfile );
+ }
+ finally
+ {
+ if( profile != null )
+ {
+ profile.close();
+ }
+ }
+ }
+ return cSpace;
+ }
+
+ /**
+ * Create a Java color model for this colorspace.
+ *
+ * @param bpc The number of bits per component.
+ *
+ * @return A color model that can be used for Java AWT operations.
+ *
+ * @throws IOException If there is an error creating the color model.
+ */
+ public ColorModel createColorModel( int bpc ) throws IOException
+ {
+ throw new IOException( "Not implemented" );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/graphics/color/PDDeviceGray.java b/src/main/java/org/pdfbox/pdmodel/graphics/color/PDDeviceGray.java
new file mode 100644
index 0000000..a9afddb
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/graphics/color/PDDeviceGray.java
@@ -0,0 +1,112 @@
+/**
+ * Copyright (c) 2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.graphics.color;
+
+import java.awt.color.ColorSpace;
+
+import java.awt.image.ColorModel;
+import java.awt.image.ComponentColorModel;
+import java.awt.image.DataBuffer;
+import java.awt.Transparency;
+
+import java.io.IOException;
+
+/**
+ * This class represents a Gray color space.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.5 $
+ */
+public class PDDeviceGray extends PDColorSpace
+{
+ /**
+ * The name of this color space.
+ */
+ public static final String NAME = "DeviceGray";
+
+ /**
+ * The abbreviated name of this color space.
+ */
+ public static final String ABBREVIATED_NAME = "G";
+
+ /**
+ * This will return the name of the color space.
+ *
+ * @return The name of the color space.
+ */
+ public String getName()
+ {
+ return NAME;
+ }
+
+ /**
+ * This will get the number of components that this color space is made up of.
+ *
+ * @return The number of components in this color space.
+ *
+ * @throws IOException If there is an error getting the number of color components.
+ */
+ public int getNumberOfComponents() throws IOException
+ {
+ return 1;
+ }
+
+ /**
+ * Create a Java colorspace for this colorspace.
+ *
+ * @return A color space that can be used for Java AWT operations.
+ *
+ * @throws IOException If there is an error creating the color space.
+ */
+ public ColorSpace createColorSpace() throws IOException
+ {
+ return ColorSpace.getInstance( ColorSpace.CS_GRAY );
+ }
+
+ /**
+ * Create a Java color model for this colorspace.
+ *
+ * @param bpc The number of bits per component.
+ *
+ * @return A color model that can be used for Java AWT operations.
+ *
+ * @throws IOException If there is an error creating the color model.
+ */
+ public ColorModel createColorModel( int bpc ) throws IOException
+ {
+ ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_GRAY);
+ int[] nBits = {bpc};
+ ColorModel colorModel = new ComponentColorModel(cs, nBits, false,false,
+ Transparency.OPAQUE,DataBuffer.TYPE_BYTE);
+ return colorModel;
+
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/graphics/color/PDDeviceN.java b/src/main/java/org/pdfbox/pdmodel/graphics/color/PDDeviceN.java
new file mode 100644
index 0000000..92561e7
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/graphics/color/PDDeviceN.java
@@ -0,0 +1,244 @@
+/**
+ * Copyright (c) 2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.graphics.color;
+
+import java.awt.color.ColorSpace;
+import java.awt.image.ColorModel;
+
+import java.io.IOException;
+
+import java.util.List;
+
+import org.pdfbox.cos.COSArray;
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSName;
+import org.pdfbox.cos.COSNull;
+
+import org.pdfbox.pdmodel.common.COSArrayList;
+
+/**
+ * This class represents a DeviceN color space.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.2 $
+ */
+public class PDDeviceN extends PDColorSpace
+{
+ /**
+ * The name of this color space.
+ */
+ public static final String NAME = "DeviceN";
+
+ private COSArray array;
+
+ /**
+ * Constructor.
+ */
+ public PDDeviceN()
+ {
+ array = new COSArray();
+ array.add( COSName.getPDFName( NAME ) );
+ array.add( COSName.getPDFName( "" ) );
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param separation The array containing all separation information.
+ */
+ public PDDeviceN( COSArray separation )
+ {
+ array = separation;
+ }
+
+ /**
+ * This will return the name of the color space. For a PDSeparation object
+ * this will always return "Separation"
+ *
+ * @return The name of the color space.
+ */
+ public String getName()
+ {
+ return NAME;
+ }
+
+ /**
+ * This will get the number of components that this color space is made up of.
+ *
+ * @return The number of components in this color space.
+ *
+ * @throws IOException If there is an error getting the number of color components.
+ */
+ public int getNumberOfComponents() throws IOException
+ {
+ return getColorantNames().size();
+ }
+
+ /**
+ * Create a Java colorspace for this colorspace.
+ *
+ * @return A color space that can be used for Java AWT operations.
+ *
+ * @throws IOException If there is an error creating the color space.
+ */
+ public ColorSpace createColorSpace() throws IOException
+ {
+ throw new IOException( "Not implemented" );
+ }
+
+ /**
+ * Create a Java color model for this colorspace.
+ *
+ * @param bpc The number of bits per component.
+ *
+ * @return A color model that can be used for Java AWT operations.
+ *
+ * @throws IOException If there is an error creating the color model.
+ */
+ public ColorModel createColorModel( int bpc ) throws IOException
+ {
+ throw new IOException( "Not implemented" );
+ }
+
+ /**
+ * This will get the colorant names. A list of string objects.
+ *
+ * @return A list of colorants
+ */
+ public List getColorantNames()
+ {
+ COSArray names = (COSArray)array.getObject( 1 );
+ return COSArrayList.convertCOSNameCOSArrayToList( names );
+ }
+
+ /**
+ * This will set the list of colorants.
+ *
+ * @param names The list of colorant names.
+ */
+ public void setColorantNames( List names )
+ {
+ COSArray namesArray = COSArrayList.convertStringListToCOSNameCOSArray( names );
+ array.set( 1, namesArray );
+ }
+
+ /**
+ * This will get the alternate color space for this separation.
+ *
+ * @return The alternate color space.
+ *
+ * @throws IOException If there is an error getting the alternate color space.
+ */
+ public PDColorSpace getAlternateColorSpace() throws IOException
+ {
+ COSBase alternate = array.getObject( 2 );
+ return PDColorSpaceFactory.createColorSpace( alternate );
+ }
+
+ /**
+ * This will set the alternate color space.
+ *
+ * @param cs The alternate color space.
+ */
+ public void setAlternateColorSpace( PDColorSpace cs )
+ {
+ COSBase space = null;
+ if( cs != null )
+ {
+ space = cs.getCOSObject();
+ }
+ array.set( 2, space );
+ }
+
+ /**
+ * This will get the tint transform function. At this time the PDModel
+ * does not support functions so we will just return the COSBase object. This
+ * method will change in the future to be a PDModel object.
+ *
+ * @return The tint transform function.
+ */
+ public COSBase getTintTransform()
+ {
+ return array.get( 3 );
+ }
+
+ /**
+ * This will set the tint transform function. At this time the PDModel
+ * does not support functions so we will just return the COSBase object. This
+ * method will change in the future to be a PDModel object.
+ *
+ * @param tint The tint transform function.
+ */
+ public void setTintTransform( COSBase tint )
+ {
+ array.set( 3, tint );
+ }
+
+ /**
+ * This will get the attributes that are associated with the deviceN
+ * color space.
+ *
+ * @return The DeviceN attributes.
+ */
+ public PDDeviceNAttributes getAttributes()
+ {
+ PDDeviceNAttributes retval = null;
+ if( array.size() <5)
+ {
+ retval = new PDDeviceNAttributes();
+ setAttributes( retval );
+ }
+ return retval;
+ }
+
+ /**
+ * This will set the color space attributes. If null is passed in then
+ * all attribute will be removed.
+ *
+ * @param attributes The color space attributes.
+ */
+ public void setAttributes( PDDeviceNAttributes attributes )
+ {
+ if( attributes == null )
+ {
+ array.remove( 4 );
+ }
+ else
+ {
+ //make sure array is large enough
+ while( array.size() < 5 )
+ {
+ array.add( COSNull.NULL );
+ }
+ array.set( 4, attributes.getCOSDictionary() );
+ }
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/graphics/color/PDDeviceNAttributes.java b/src/main/java/org/pdfbox/pdmodel/graphics/color/PDDeviceNAttributes.java
new file mode 100644
index 0000000..00366df
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/graphics/color/PDDeviceNAttributes.java
@@ -0,0 +1,126 @@
+/**
+ * Copyright (c) 2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.graphics.color;
+
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSName;
+
+import org.pdfbox.pdmodel.common.COSDictionaryMap;
+
+import java.io.IOException;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * This class represents attributes for a DeviceN color space.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.1 $
+ */
+public class PDDeviceNAttributes
+{
+ private COSDictionary dictionary;
+
+ /**
+ * Constructor.
+ */
+ public PDDeviceNAttributes()
+ {
+ dictionary = new COSDictionary();
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param attributes A dictionary that has all of the attributes.
+ */
+ public PDDeviceNAttributes( COSDictionary attributes )
+ {
+ dictionary = attributes;
+ }
+
+ /**
+ * This will get the underlying cos dictionary.
+ *
+ * @return The dictionary that this object wraps.
+ */
+ public COSDictionary getCOSDictionary()
+ {
+ return dictionary;
+ }
+
+ /**
+ * This will get a map of colorants. See the PDF Reference for more details about
+ * this attribute. The map will contain a java.lang.String as the key, a colorant name,
+ * and a PDColorSpace as the value.
+ *
+ * @return The colorant map.
+ *
+ * @throws IOException If there is an error getting the colorspaces.
+ */
+ public Map getColorants() throws IOException
+ {
+ Map actuals = new HashMap();
+ COSDictionary colorants = (COSDictionary)dictionary.getDictionaryObject( COSName.getPDFName( "Colorants" ) );
+ if( colorants == null )
+ {
+ colorants = new COSDictionary();
+ dictionary.setItem( COSName.getPDFName( "Colorants" ), colorants );
+ }
+ Iterator iter = colorants.keyList().iterator();
+ while( iter.hasNext() )
+ {
+ COSName name = (COSName)iter.next();
+ COSBase value = colorants.getDictionaryObject( name );
+ actuals.put( name.getName(), PDColorSpaceFactory.createColorSpace( value ) );
+ }
+ return new COSDictionaryMap( actuals, colorants );
+ }
+
+ /**
+ * This will replace the existing colorant attribute. The key should be strings
+ * and the values should be PDColorSpaces.
+ *
+ * @param colorants The map of colorants.
+ */
+ public void setColorants( Map colorants )
+ {
+ COSDictionary colorantDict = null;
+ if( colorants != null )
+ {
+ colorantDict = COSDictionaryMap.convert( colorants );
+ }
+ dictionary.setItem( COSName.getPDFName( "Colorants" ), colorantDict );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/graphics/color/PDDeviceRGB.java b/src/main/java/org/pdfbox/pdmodel/graphics/color/PDDeviceRGB.java
new file mode 100644
index 0000000..14c0dc3
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/graphics/color/PDDeviceRGB.java
@@ -0,0 +1,130 @@
+/**
+ * Copyright (c) 2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.graphics.color;
+
+import java.awt.Transparency;
+
+import java.awt.color.ColorSpace;
+
+import java.awt.image.ColorModel;
+import java.awt.image.ComponentColorModel;
+import java.awt.image.DataBuffer;
+
+import java.io.IOException;
+
+/**
+ * This class represents an RGB color space.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.7 $
+ */
+public class PDDeviceRGB extends PDColorSpace
+{
+ /**
+ * The name of this color space.
+ */
+ public static final String NAME = "DeviceRGB";
+
+ /**
+ * The abbreviated name of this color space.
+ */
+ public static final String ABBREVIATED_NAME = "RGB";
+
+ /**
+ * This is the single instance of this class.
+ */
+ public static final PDDeviceRGB INSTANCE = new PDDeviceRGB();
+
+ /**
+ * This class is immutable.
+ */
+ private PDDeviceRGB()
+ {
+ //only here to make immutable.
+ }
+
+ /**
+ * This will return the name of the color space.
+ *
+ * @return The name of the color space.
+ */
+ public String getName()
+ {
+ return NAME;
+ }
+
+ /**
+ * This will get the number of components that this color space is made up of.
+ *
+ * @return The number of components in this color space.
+ *
+ * @throws IOException If there is an error getting the number of color components.
+ */
+ public int getNumberOfComponents() throws IOException
+ {
+ return 3;
+ }
+
+ /**
+ * Create a Java colorspace for this colorspace.
+ *
+ * @return A color space that can be used for Java AWT operations.
+ *
+ * @throws IOException If there is an error creating the color space.
+ */
+ public ColorSpace createColorSpace() throws IOException
+ {
+ return ColorSpace.getInstance( ColorSpace.CS_sRGB );
+ }
+
+ /**
+ * Create a Java color model for this colorspace.
+ *
+ * @param bpc The number of bits per component.
+ *
+ * @return A color model that can be used for Java AWT operations.
+ *
+ * @throws IOException If there is an error creating the color model.
+ */
+ public ColorModel createColorModel( int bpc ) throws IOException
+ {
+ int[] nbBits = { bpc, bpc, bpc };
+ ComponentColorModel componentColorModel =
+ new ComponentColorModel( createColorSpace(),
+ nbBits,
+ false,
+ false,
+ Transparency.OPAQUE,
+ DataBuffer.TYPE_BYTE );
+
+ return (ColorModel)componentColorModel;
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/graphics/color/PDGamma.java b/src/main/java/org/pdfbox/pdmodel/graphics/color/PDGamma.java
new file mode 100644
index 0000000..31fa82e
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/graphics/color/PDGamma.java
@@ -0,0 +1,151 @@
+/**
+ * Copyright (c) 2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.graphics.color;
+
+import org.pdfbox.cos.COSArray;
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSFloat;
+import org.pdfbox.cos.COSNumber;
+
+import org.pdfbox.pdmodel.common.COSObjectable;
+
+/**
+ * A gamma array, or collection of three floating point parameters used for
+ * color operations.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.1 $
+ */
+public class PDGamma implements COSObjectable
+{
+ private COSArray values = null;
+
+ /**
+ * Constructor. Defaults all values to 0, 0, 0.
+ */
+ public PDGamma()
+ {
+ values = new COSArray();
+ values.add( new COSFloat( 0.0f ) );
+ values.add( new COSFloat( 0.0f ) );
+ values.add( new COSFloat( 0.0f ) );
+ }
+
+ /**
+ * Constructor from COS object.
+ *
+ * @param array The array containing the XYZ values.
+ */
+ public PDGamma( COSArray array )
+ {
+ values = array;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSBase getCOSObject()
+ {
+ return values;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSArray getCOSArray()
+ {
+ return values;
+ }
+
+ /**
+ * This will get the r value of the tristimulus.
+ *
+ * @return The R value.
+ */
+ public float getR()
+ {
+ return ((COSNumber)values.get( 0 )).floatValue();
+ }
+
+ /**
+ * This will set the r value of the tristimulus.
+ *
+ * @param r The r value for the tristimulus.
+ */
+ public void setR( float r )
+ {
+ values.set( 0, new COSFloat( r ) );
+ }
+
+ /**
+ * This will get the g value of the tristimulus.
+ *
+ * @return The g value.
+ */
+ public float getG()
+ {
+ return ((COSNumber)values.get( 1 )).floatValue();
+ }
+
+ /**
+ * This will set the g value of the tristimulus.
+ *
+ * @param g The g value for the tristimulus.
+ */
+ public void setG( float g )
+ {
+ values.set( 1, new COSFloat( g ) );
+ }
+
+ /**
+ * This will get the b value of the tristimulus.
+ *
+ * @return The B value.
+ */
+ public float getB()
+ {
+ return ((COSNumber)values.get( 2 )).floatValue();
+ }
+
+ /**
+ * This will set the b value of the tristimulus.
+ *
+ * @param b The b value for the tristimulus.
+ */
+ public void setB( float b )
+ {
+ values.set( 2, new COSFloat( b ) );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/graphics/color/PDICCBased.java b/src/main/java/org/pdfbox/pdmodel/graphics/color/PDICCBased.java
new file mode 100644
index 0000000..d8189d0
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/graphics/color/PDICCBased.java
@@ -0,0 +1,343 @@
+/**
+ * Copyright (c) 2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.graphics.color;
+
+import org.pdfbox.cos.COSArray;
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSInteger;
+import org.pdfbox.cos.COSFloat;
+import org.pdfbox.cos.COSName;
+import org.pdfbox.cos.COSNumber;
+import org.pdfbox.cos.COSStream;
+
+import org.pdfbox.pdmodel.PDDocument;
+import org.pdfbox.pdmodel.common.COSArrayList;
+import org.pdfbox.pdmodel.common.PDRange;
+import org.pdfbox.pdmodel.common.PDStream;
+
+import java.awt.Transparency;
+import java.awt.color.ColorSpace;
+import java.awt.color.ICC_ColorSpace;
+import java.awt.color.ICC_Profile;
+import java.awt.image.ColorModel;
+import java.awt.image.ComponentColorModel;
+import java.awt.image.DataBuffer;
+
+import java.io.InputStream;
+import java.io.IOException;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class represents a ICC profile color space.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.5 $
+ */
+public class PDICCBased extends PDColorSpace
+{
+ /**
+ * The name of this color space.
+ */
+ public static final String NAME = "ICCBased";
+
+ private COSArray array;
+ private PDStream stream;
+
+ /**
+ * Default constructor, creates empty stream.
+ *
+ * @param doc The document to store the icc data.
+ */
+ public PDICCBased( PDDocument doc )
+ {
+ array = new COSArray();
+ array.add( COSName.getPDFName( NAME ) );
+ array.add( new PDStream( doc ) );
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param iccArray The ICC stream object.
+ */
+ public PDICCBased( COSArray iccArray )
+ {
+ array = iccArray;
+ stream = new PDStream( (COSStream)iccArray.getObject( 1 ) );
+ }
+
+ /**
+ * This will return the name of the color space.
+ *
+ * @return The name of the color space.
+ */
+ public String getName()
+ {
+ return NAME;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSBase getCOSObject()
+ {
+ return array;
+ }
+
+ /**
+ * Get the pd stream for this icc color space.
+ *
+ * @return Get the stream for this icc based color space.
+ */
+ public PDStream getPDStream()
+ {
+ return stream;
+ }
+
+ /**
+ * Create a Java colorspace for this colorspace.
+ *
+ * @return A color space that can be used for Java AWT operations.
+ *
+ * @throws IOException If there is an error creating the color space.
+ */
+ public ColorSpace createColorSpace() throws IOException
+ {
+ InputStream profile = null;
+ ColorSpace cSpace = null;
+ try
+ {
+ profile = stream.createInputStream();
+ ICC_Profile iccProfile = ICC_Profile.getInstance( profile );
+ cSpace = new ICC_ColorSpace( iccProfile );
+ }
+ finally
+ {
+ if( profile != null )
+ {
+ profile.close();
+ }
+ }
+ return cSpace;
+ }
+
+ /**
+ * Create a Java color model for this colorspace.
+ *
+ * @param bpc The number of bits per component.
+ *
+ * @return A color model that can be used for Java AWT operations.
+ *
+ * @throws IOException If there is an error creating the color model.
+ */
+ public ColorModel createColorModel( int bpc ) throws IOException
+ {
+ int[] nbBits = { bpc, bpc, bpc };
+ ComponentColorModel componentColorModel =
+ new ComponentColorModel( createColorSpace(),
+ nbBits,
+ false,
+ false,
+ Transparency.OPAQUE,
+ DataBuffer.TYPE_BYTE );
+
+ return componentColorModel;
+ }
+
+ /**
+ * This will return the number of color components. As of PDF 1.4 this will
+ * be 1,3,4.
+ *
+ * @return The number of components in this color space.
+ *
+ * @throws IOException If there is an error getting the number of color components.
+ */
+ public int getNumberOfComponents() throws IOException
+ {
+ COSNumber n = (COSNumber)stream.getStream().getDictionaryObject( COSName.getPDFName( "N" ) );
+ return n.intValue();
+ }
+
+ /**
+ * This will set the number of color components.
+ *
+ * @param n The number of color components.
+ */
+ public void setNumberOfComponents( int n )
+ {
+ stream.getStream().setItem( COSName.getPDFName( "N" ), new COSInteger( n ) );
+ }
+
+ /**
+ * This will return a list of alternate color spaces(PDColorSpace) if the display application
+ * does not support this icc stream.
+ *
+ * @return A list of alternate color spaces.
+ *
+ * @throws IOException If there is an error getting the alternate color spaces.
+ */
+ public List getAlternateColorSpaces() throws IOException
+ {
+ COSBase alternate = stream.getStream().getDictionaryObject( COSName.getPDFName( "Alternate" ) );
+ COSArray alternateArray = null;
+ if( alternate == null )
+ {
+ alternateArray = new COSArray();
+ int numComponents = getNumberOfComponents();
+ String csName = null;
+ if( numComponents == 1 )
+ {
+ csName = PDDeviceGray.NAME;
+ }
+ else if( numComponents == 3 )
+ {
+ csName = PDDeviceRGB.NAME;
+ }
+ else if( numComponents == 4 )
+ {
+ csName = PDDeviceCMYK.NAME;
+ }
+ else
+ {
+ throw new IOException( "Unknown colorspace number of components:" + numComponents );
+ }
+ alternateArray.add( COSName.getPDFName( csName ) );
+ }
+ else
+ {
+ if( alternate instanceof COSArray )
+ {
+ alternateArray = (COSArray)alternate;
+ }
+ else if( alternate instanceof COSName )
+ {
+ alternateArray = new COSArray();
+ alternateArray.add( alternate );
+ }
+ else
+ {
+ throw new IOException( "Error: expected COSArray or COSName and not " +
+ alternate.getClass().getName() );
+ }
+ }
+ List retval = new ArrayList();
+ for( int i=0; i<alternateArray.size(); i++ )
+ {
+ retval.add( PDColorSpaceFactory.createColorSpace( alternateArray.get( i ) ) );
+ }
+ return new COSArrayList( retval, alternateArray );
+ }
+
+ /**
+ * This will set the list of alternate color spaces. This should be a list
+ * of PDColorSpace objects.
+ *
+ * @param list The list of colorspace objects.
+ */
+ public void setAlternateColorSpaces( List list )
+ {
+ COSArray altArray = null;
+ if( list != null )
+ {
+ altArray = COSArrayList.converterToCOSArray( list );
+ }
+ stream.getStream().setItem( COSName.getPDFName( "Alternate" ), altArray );
+ }
+
+ private COSArray getRangeArray( int n )
+ {
+ COSArray rangeArray = (COSArray)stream.getStream().getDictionaryObject( COSName.getPDFName( "Range" ) );
+ if( rangeArray == null )
+ {
+ rangeArray = new COSArray();
+ stream.getStream().setItem( COSName.getPDFName( "Range" ), rangeArray );
+ while( rangeArray.size() < n*2 )
+ {
+ rangeArray.add( new COSFloat( -100 ) );
+ rangeArray.add( new COSFloat( 100 ) );
+ }
+ }
+ return rangeArray;
+ }
+
+ /**
+ * This will get the range for a certain component number. This is will never
+ * return null. If it is not present then the range -100 to 100 will
+ * be returned.
+ *
+ * @param n The component number to get the range for.
+ *
+ * @return The range for this component.
+ */
+ public PDRange getRangeForComponent( int n )
+ {
+ COSArray rangeArray = getRangeArray( n );
+ return new PDRange( rangeArray, n );
+ }
+
+ /**
+ * This will set the a range for this color space.
+ *
+ * @param range The new range for the a component.
+ * @param n The component to set the range for.
+ */
+ public void setRangeForComponent( PDRange range, int n )
+ {
+ COSArray rangeArray = getRangeArray( n );
+ rangeArray.set( n*2, new COSFloat( range.getMin() ) );
+ rangeArray.set( n*2+1, new COSFloat( range.getMax() ) );
+ }
+
+ /**
+ * This will get the metadata stream for this object. Null if there is no
+ * metadata stream.
+ *
+ * @return The metadata stream, if it exists.
+ */
+ public COSStream getMetadata()
+ {
+ return (COSStream)stream.getStream().getDictionaryObject( COSName.getPDFName( "Metadata" ) );
+ }
+
+ /**
+ * This will set the metadata stream that is associated with this color space.
+ *
+ * @param metadata The new metadata stream.
+ */
+ public void setMetadata( COSStream metadata )
+ {
+ stream.getStream().setItem( COSName.getPDFName( "Metadata" ), metadata );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/graphics/color/PDIndexed.java b/src/main/java/org/pdfbox/pdmodel/graphics/color/PDIndexed.java
new file mode 100644
index 0000000..cd1d9e7
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/graphics/color/PDIndexed.java
@@ -0,0 +1,271 @@
+/**
+ * Copyright (c) 2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.graphics.color;
+
+import org.pdfbox.cos.COSArray;
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSInteger;
+import org.pdfbox.cos.COSName;
+import org.pdfbox.cos.COSNumber;
+import org.pdfbox.cos.COSStream;
+import org.pdfbox.cos.COSString;
+
+import java.awt.color.ColorSpace;
+import java.awt.image.ColorModel;
+import java.awt.image.IndexColorModel;
+
+import java.io.InputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+/**
+ * This class represents an Indexed color space.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.3 $
+ */
+public class PDIndexed extends PDColorSpace
+{
+
+ /**
+ * The name of this color space.
+ */
+ public static final String NAME = "Indexed";
+
+ /**
+ * The abbreviated name of this color space.
+ */
+ public static final String ABBREVIATED_NAME = "I";
+
+ private COSArray array;
+
+ /**
+ * Constructor, default DeviceRGB, hival 255.
+ */
+ public PDIndexed()
+ {
+ array = new COSArray();
+ array.add( COSName.getPDFName( NAME ) );
+ array.add( COSName.getPDFName( PDDeviceRGB.NAME ) );
+ array.add( new COSInteger( 255 ) );
+ array.add( org.pdfbox.cos.COSNull.NULL );
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param indexedArray The array containing the indexed parameters
+ */
+ public PDIndexed( COSArray indexedArray )
+ {
+ array = indexedArray;
+ }
+
+ /**
+ * This will return the number of color components. This will return the
+ * number of color components in the base color.
+ *
+ * @return The number of components in this color space.
+ *
+ * @throws IOException If there is an error getting the number of color components.
+ */
+ public int getNumberOfComponents() throws IOException
+ {
+ return getBaseColorSpace().getNumberOfComponents();
+ }
+
+ /**
+ * This will return the name of the color space.
+ *
+ * @return The name of the color space.
+ */
+ public String getName()
+ {
+ return NAME;
+ }
+
+ /**
+ * Create a Java colorspace for this colorspace.
+ *
+ * @return A color space that can be used for Java AWT operations.
+ *
+ * @throws IOException If there is an error creating the color space.
+ */
+ public ColorSpace createColorSpace() throws IOException
+ {
+ throw new IOException( "Not implemented" );
+ }
+
+ /**
+ * Create a Java color model for this colorspace.
+ *
+ * @param bpc The number of bits per component.
+ *
+ * @return A color model that can be used for Java AWT operations.
+ *
+ * @throws IOException If there is an error creating the color model.
+ */
+ public ColorModel createColorModel( int bpc ) throws IOException
+ {
+ int size = getHighValue();
+ byte[] index = getLookupData();
+ //for (int i=0;i<index.length;i++) System.out.print(index[i]+" ");
+
+ ColorModel cm = new IndexColorModel(bpc, size+1, index,0,false);
+ return cm;
+ }
+
+ /**
+ * This will get the color space that acts as the index for this color space.
+ *
+ * @return The base color space.
+ *
+ * @throws IOException If there is error creating the base color space.
+ */
+ public PDColorSpace getBaseColorSpace() throws IOException
+ {
+ PDColorSpace retval = null;
+ COSBase base = array.getObject( 1 );
+ if( base instanceof COSName )
+ {
+ retval = PDColorSpaceFactory.createColorSpace( (COSName)base );
+ }
+ else
+ {
+ throw new IOException( "Error:unknown base colorspace" );
+ }
+
+ return retval;
+ }
+
+ /**
+ * This will set the base color space.
+ *
+ * @param base The base color space to use as the index.
+ */
+ public void setBaseColorSpace( PDColorSpace base )
+ {
+ array.set( 1, base.getCOSObject() );
+ }
+
+ /**
+ * Get the highest value for the lookup.
+ *
+ * @return The hival entry.
+ */
+ public int getHighValue()
+ {
+ return ((COSNumber)array.getObject( 2 )).intValue();
+ }
+
+ /**
+ * This will set the highest value that is allowed. This cannot be higher
+ * than 255.
+ *
+ * @param high The highest value for the lookup table.
+ */
+ public void setHighValue( int high )
+ {
+ array.set( 2, new COSInteger( high ) );
+ }
+
+ /**
+ * This will perform a lookup into the color lookup table.
+ *
+ * @param componentNumber The component number, probably 1,2,3,3.
+ * @param lookupIndex The zero-based index into the table, should not exceed the high value.
+ *
+ * @return The value that was from the lookup table.
+ *
+ * @throws IOException If there is an error looking up the color.
+ */
+ public int lookupColor( int componentNumber, int lookupIndex ) throws IOException
+ {
+ COSBase lookupTable = array.getObject( 3 );
+ PDColorSpace baseColor = getBaseColorSpace();
+ byte[] data = getLookupData();
+ int numberOfComponents = baseColor.getNumberOfComponents();
+ return (data[componentNumber*numberOfComponents + lookupIndex]+256)%256;
+ }
+
+ private byte[] getLookupData() throws IOException
+ {
+ COSBase lookupTable = array.getObject( 3 );
+ byte[] data = null;
+ if( lookupTable instanceof COSString )
+ {
+ data = ((COSString)lookupTable).getBytes();
+ }
+ else if( lookupTable instanceof COSStream )
+ {
+ //Data will be small so just load the whole thing into memory for
+ //easier processing
+ COSStream lookupStream = (COSStream)lookupTable;
+ InputStream input = lookupStream.getUnfilteredStream();
+ ByteArrayOutputStream output = new ByteArrayOutputStream(1024);
+ byte[] buffer = new byte[ 1024 ];
+ int amountRead;
+ while( (amountRead = input.read(buffer, 0, buffer.length)) != -1 )
+ {
+ output.write( buffer, 0, amountRead );
+ }
+ data = output.toByteArray();
+ }
+ else if( lookupTable == null )
+ {
+ data = new byte[0];
+ }
+ else
+ {
+ throw new IOException( "Error: Unknown type for lookup table " + lookupTable );
+ }
+ return data;
+ }
+
+ /**
+ * This will set a color in the color lookup table.
+ *
+ * @param componentNumber The component number, probably 1,2,3,3.
+ * @param lookupIndex The zero-based index into the table, should not exceed the high value.
+ * @param color The color that will go into the table.
+ *
+ * @throws IOException If there is an error looking up the color.
+ */
+ public void setLookupColor( int componentNumber, int lookupIndex, int color ) throws IOException
+ {
+ PDColorSpace baseColor = getBaseColorSpace();
+ int numberOfComponents = baseColor.getNumberOfComponents();
+ byte[] data = getLookupData();
+ data[componentNumber*numberOfComponents + lookupIndex] = (byte)color;
+ COSString string = new COSString( data );
+ array.set( 3, string );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/graphics/color/PDLab.java b/src/main/java/org/pdfbox/pdmodel/graphics/color/PDLab.java
new file mode 100644
index 0000000..9bd3220
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/graphics/color/PDLab.java
@@ -0,0 +1,300 @@
+/**
+ * Copyright (c) 2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.graphics.color;
+
+import org.pdfbox.cos.COSArray;
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSFloat;
+import org.pdfbox.cos.COSName;
+
+import org.pdfbox.pdmodel.common.PDRange;
+
+import java.awt.color.ColorSpace;
+import java.awt.image.ColorModel;
+
+import java.io.IOException;
+
+/**
+ * This class represents a Lab color space.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.2 $
+ */
+public class PDLab extends PDColorSpace
+{
+ /**
+ * The name of this color space.
+ */
+ public static final String NAME = "Lab";
+
+ private COSArray array;
+ private COSDictionary dictionary;
+
+ /**
+ * Constructor.
+ */
+ public PDLab()
+ {
+ array = new COSArray();
+ dictionary = new COSDictionary();
+ array.add( COSName.getPDFName( NAME ) );
+ array.add( dictionary );
+ }
+
+ /**
+ * Constructor with array.
+ *
+ * @param lab The underlying color space.
+ */
+ public PDLab( COSArray lab )
+ {
+ array = lab;
+ dictionary = (COSDictionary)array.getObject( 1 );
+ }
+
+ /**
+ * This will return the name of the color space.
+ *
+ * @return The name of the color space.
+ */
+ public String getName()
+ {
+ return NAME;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSBase getCOSObject()
+ {
+ return array;
+ }
+
+ /**
+ * Create a Java colorspace for this colorspace.
+ *
+ * @return A color space that can be used for Java AWT operations.
+ *
+ * @throws IOException If there is an error creating the color space.
+ */
+ public ColorSpace createColorSpace() throws IOException
+ {
+ throw new IOException( "Not implemented" );
+ }
+
+ /**
+ * Create a Java color model for this colorspace.
+ *
+ * @param bpc The number of bits per component.
+ *
+ * @return A color model that can be used for Java AWT operations.
+ *
+ * @throws IOException If there is an error creating the color model.
+ */
+ public ColorModel createColorModel( int bpc ) throws IOException
+ {
+ throw new IOException( "Not implemented" );
+ }
+
+ /**
+ * This will get the number of components that this color space is made up of.
+ *
+ * @return The number of components in this color space.
+ *
+ * @throws IOException If there is an error getting the number of color components.
+ */
+ public int getNumberOfComponents() throws IOException
+ {
+ //BJL
+ //hmm is this correct, I am not 100% sure.
+ return 3;
+ }
+
+ /**
+ * This will return the whitepoint tristimulus. As this is a required field
+ * this will never return null. A default of 1,1,1 will be returned if the
+ * pdf does not have any values yet.
+ *
+ * @return The whitepoint tristimulus.
+ */
+ public PDTristimulus getWhitepoint()
+ {
+ PDTristimulus retval = null;
+ COSArray wp = (COSArray)dictionary.getDictionaryObject( COSName.getPDFName( "WhitePoint" ) );
+ if( wp == null )
+ {
+ wp.add( new COSFloat( 1.0f ) );
+ wp.add( new COSFloat( 1.0f ) );
+ wp.add( new COSFloat( 1.0f ) );
+ dictionary.setItem( COSName.getPDFName( "WhitePoint" ), wp );
+ }
+ return new PDTristimulus( wp );
+ }
+
+ /**
+ * This will set the whitepoint tristimulus. As this is a required field
+ * this null should not be passed into this function.
+ *
+ * @param wp The whitepoint tristimulus.
+ */
+ public void setWhitepoint( PDTristimulus wp )
+ {
+ COSBase wpArray = wp.getCOSObject();
+ if( wpArray != null )
+ {
+ dictionary.setItem( COSName.getPDFName( "WhitePoint" ), wpArray );
+ }
+ }
+
+ /**
+ * This will return the BlackPoint tristimulus. This is an optional field but
+ * has defaults so this will never return null.
+ * A default of 0,0,0 will be returned if the pdf does not have any values yet.
+ *
+ * @return The blackpoint tristimulus.
+ */
+ public PDTristimulus getBlackPoint()
+ {
+ PDTristimulus retval = null;
+ COSArray bp = (COSArray)dictionary.getDictionaryObject( COSName.getPDFName( "BlackPoint" ) );
+ if( bp == null )
+ {
+ bp.add( new COSFloat( 0.0f ) );
+ bp.add( new COSFloat( 0.0f ) );
+ bp.add( new COSFloat( 0.0f ) );
+ dictionary.setItem( COSName.getPDFName( "BlackPoint" ), bp );
+ }
+ return new PDTristimulus( bp );
+ }
+
+ /**
+ * This will set the BlackPoint tristimulus. As this is a required field
+ * this null should not be passed into this function.
+ *
+ * @param bp The BlackPoint tristimulus.
+ */
+ public void setBlackPoint( PDTristimulus bp )
+ {
+
+ COSBase bpArray = null;
+ if( bp != null )
+ {
+ bpArray = bp.getCOSObject();
+ }
+ dictionary.setItem( COSName.getPDFName( "BlackPoint" ), bpArray );
+ }
+
+ private COSArray getRangeArray()
+ {
+ COSArray range = (COSArray)dictionary.getDictionaryObject( COSName.getPDFName( "Range" ) );
+ if( range == null )
+ {
+ range = new COSArray();
+ dictionary.setItem( COSName.getPDFName( "Range" ), array );
+ range.add( new COSFloat( -100 ) );
+ range.add( new COSFloat( 100 ) );
+ range.add( new COSFloat( -100 ) );
+ range.add( new COSFloat( 100 ) );
+ }
+ return range;
+ }
+
+ /**
+ * This will get the valid range for the a component. If none is found
+ * then the default will be returned, which is -100 to 100.
+ *
+ * @return The a range.
+ */
+ public PDRange getARange()
+ {
+ COSArray range = getRangeArray();
+ return new PDRange( range, 0 );
+ }
+
+ /**
+ * This will set the a range for this color space.
+ *
+ * @param range The new range for the a component.
+ */
+ public void setARange( PDRange range )
+ {
+ COSArray rangeArray = null;
+ //if null then reset to defaults
+ if( range == null )
+ {
+ rangeArray = getRangeArray();
+ rangeArray.set( 0, new COSFloat( -100 ) );
+ rangeArray.set( 1, new COSFloat( 100 ) );
+ }
+ else
+ {
+ rangeArray = range.getCOSArray();
+ }
+ dictionary.setItem( COSName.getPDFName( "Range" ), rangeArray );
+ }
+
+ /**
+ * This will get the valid range for the b component. If none is found
+ * then the default will be returned, which is -100 to 100.
+ *
+ * @return The b range.
+ */
+ public PDRange getBRange()
+ {
+ COSArray range = getRangeArray();
+ return new PDRange( range, 2 );
+ }
+
+ /**
+ * This will set the b range for this color space.
+ *
+ * @param range The new range for the b component.
+ */
+ public void setBRange( PDRange range )
+ {
+ COSArray rangeArray = null;
+ //if null then reset to defaults
+ if( range == null )
+ {
+ rangeArray = getRangeArray();
+ rangeArray.set( 2, new COSFloat( -100 ) );
+ rangeArray.set( 3, new COSFloat( 100 ) );
+ }
+ else
+ {
+ rangeArray = range.getCOSArray();
+ }
+ dictionary.setItem( COSName.getPDFName( "Range" ), rangeArray );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/graphics/color/PDPattern.java b/src/main/java/org/pdfbox/pdmodel/graphics/color/PDPattern.java
new file mode 100644
index 0000000..4c43914
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/graphics/color/PDPattern.java
@@ -0,0 +1,122 @@
+/**
+ * Copyright (c) 2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.graphics.color;
+
+import org.pdfbox.cos.COSArray;
+import org.pdfbox.cos.COSName;
+
+import java.awt.color.ColorSpace;
+import java.awt.image.ColorModel;
+
+import java.io.IOException;
+
+/**
+ * This class represents a Pattern color space.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.3 $
+ */
+public class PDPattern extends PDColorSpace
+{
+ private COSArray array;
+
+ /**
+ * The name of this color space.
+ */
+ public static final String NAME = "Pattern";
+
+ /**
+ * Default constructor.
+ */
+ public PDPattern()
+ {
+ array = new COSArray();
+ array.add( COSName.getPDFName( NAME ) );
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param pattern The pattern array.
+ */
+ public PDPattern( COSArray pattern)
+ {
+ array = pattern;
+ }
+
+ /**
+ * This will return the name of the color space.
+ *
+ * @return The name of the color space.
+ */
+ public String getName()
+ {
+ return NAME;
+ }
+
+ /**
+ * This will get the number of components that this color space is made up of.
+ *
+ * @return The number of components in this color space.
+ *
+ * @throws IOException If there is an error getting the number of color components.
+ */
+ public int getNumberOfComponents() throws IOException
+ {
+ return -1;
+ }
+
+ /**
+ * Create a Java colorspace for this colorspace.
+ *
+ * @return A color space that can be used for Java AWT operations.
+ *
+ * @throws IOException If there is an error creating the color space.
+ */
+ public ColorSpace createColorSpace() throws IOException
+ {
+ throw new IOException( "Not implemented" );
+ }
+
+ /**
+ * Create a Java color model for this colorspace.
+ *
+ * @param bpc The number of bits per component.
+ *
+ * @return A color model that can be used for Java AWT operations.
+ *
+ * @throws IOException If there is an error creating the color model.
+ */
+ public ColorModel createColorModel( int bpc ) throws IOException
+ {
+ throw new IOException( "Not implemented" );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/graphics/color/PDSeparation.java b/src/main/java/org/pdfbox/pdmodel/graphics/color/PDSeparation.java
new file mode 100644
index 0000000..cc92f6f
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/graphics/color/PDSeparation.java
@@ -0,0 +1,198 @@
+/**
+ * Copyright (c) 2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.graphics.color;
+
+import java.awt.color.ColorSpace;
+import java.awt.image.ColorModel;
+
+import java.io.IOException;
+
+import org.pdfbox.cos.COSArray;
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSName;
+
+/**
+ * This class represents a Separation color space.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.2 $
+ */
+public class PDSeparation extends PDColorSpace
+{
+ /**
+ * The name of this color space.
+ */
+ public static final String NAME = "Separation";
+
+ private COSArray array;
+
+ /**
+ * Constructor.
+ */
+ public PDSeparation()
+ {
+ array = new COSArray();
+ array.add( COSName.getPDFName( NAME ) );
+ array.add( COSName.getPDFName( "" ) );
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param separation The array containing all separation information.
+ */
+ public PDSeparation( COSArray separation )
+ {
+ array = separation;
+ }
+
+ /**
+ * This will return the name of the color space. For a PDSeparation object
+ * this will always return "Separation"
+ *
+ * @return The name of the color space.
+ */
+ public String getName()
+ {
+ return NAME;
+ }
+
+ /**
+ * This will get the number of components that this color space is made up of.
+ *
+ * @return The number of components in this color space.
+ *
+ * @throws IOException If there is an error getting the number of color components.
+ */
+ public int getNumberOfComponents() throws IOException
+ {
+ return 1;
+ }
+
+ /**
+ * Create a Java colorspace for this colorspace.
+ *
+ * @return A color space that can be used for Java AWT operations.
+ *
+ * @throws IOException If there is an error creating the color space.
+ */
+ public ColorSpace createColorSpace() throws IOException
+ {
+ throw new IOException( "Not implemented" );
+ }
+
+ /**
+ * Create a Java color model for this colorspace.
+ *
+ * @param bpc The number of bits per component.
+ *
+ * @return A color model that can be used for Java AWT operations.
+ *
+ * @throws IOException If there is an error creating the color model.
+ */
+ public ColorModel createColorModel( int bpc ) throws IOException
+ {
+ throw new IOException( "Not implemented" );
+ }
+
+ /**
+ * This will get the separation name.
+ *
+ * @return The name in the separation.
+ */
+ public String getColorantName()
+ {
+ COSName name = (COSName)array.getObject( 1 );
+ return name.getName();
+ }
+
+ /**
+ * This will set the separation name.
+ *
+ * @param name The separation name.
+ */
+ public void setColorantName( String name )
+ {
+ array.set( 1, COSName.getPDFName( name ) );
+ }
+
+ /**
+ * This will get the alternate color space for this separation.
+ *
+ * @return The alternate color space.
+ *
+ * @throws IOException If there is an error getting the alternate color space.
+ */
+ public PDColorSpace getAlternateColorSpace() throws IOException
+ {
+ COSBase alternate = array.getObject( 2 );
+ return PDColorSpaceFactory.createColorSpace( alternate );
+ }
+
+ /**
+ * This will set the alternate color space.
+ *
+ * @param cs The alternate color space.
+ */
+ public void setAlternateColorSpace( PDColorSpace cs )
+ {
+ COSBase space = null;
+ if( cs != null )
+ {
+ space = cs.getCOSObject();
+ }
+ array.set( 2, space );
+ }
+
+ /**
+ * This will get the tint transform function. At this time the PDModel
+ * does not support functions so we will just return the COSBase object. This
+ * method will change in the future to be a PDModel object.
+ *
+ * @return The tint transform function.
+ */
+ public COSBase getTintTransform()
+ {
+ return array.get( 3 );
+ }
+
+ /**
+ * This will set the tint transform function. At this time the PDModel
+ * does not support functions so we will just return the COSBase object. This
+ * method will change in the future to be a PDModel object.
+ *
+ * @param tint The tint transform function.
+ */
+ public void setTintTransform( COSBase tint )
+ {
+ array.set( 3, tint );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/graphics/color/PDTristimulus.java b/src/main/java/org/pdfbox/pdmodel/graphics/color/PDTristimulus.java
new file mode 100644
index 0000000..296b147
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/graphics/color/PDTristimulus.java
@@ -0,0 +1,155 @@
+/**
+ * Copyright (c) 2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.graphics.color;
+
+import org.pdfbox.cos.COSArray;
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSFloat;
+import org.pdfbox.cos.COSNumber;
+
+import org.pdfbox.pdmodel.common.COSObjectable;
+
+/**
+ * A tristimulus, or collection of three floating point parameters used for
+ * color operations.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.1 $
+ */
+public class PDTristimulus implements COSObjectable
+{
+ private COSArray values = null;
+
+ /**
+ * Constructor. Defaults all values to 0, 0, 0.
+ */
+ public PDTristimulus()
+ {
+ values = new COSArray();
+ values.add( new COSFloat( 0.0f ) );
+ values.add( new COSFloat( 0.0f ) );
+ values.add( new COSFloat( 0.0f ) );
+ }
+
+ /**
+ * Constructor from COS object.
+ *
+ * @param array The array containing the XYZ values.
+ */
+ public PDTristimulus( COSArray array )
+ {
+ values = array;
+ }
+
+ /**
+ * Constructor from COS object.
+ *
+ * @param array The array containing the XYZ values.
+ */
+ public PDTristimulus( float[] array )
+ {
+ values = new COSArray();
+ for( int i=0; i<array.length && i<3; i++ )
+ {
+ values.add( new COSFloat( array[i] ) );
+ }
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSBase getCOSObject()
+ {
+ return values;
+ }
+
+ /**
+ * This will get the x value of the tristimulus.
+ *
+ * @return The X value.
+ */
+ public float getX()
+ {
+ return ((COSNumber)values.get( 0 )).floatValue();
+ }
+
+ /**
+ * This will set the x value of the tristimulus.
+ *
+ * @param x The x value for the tristimulus.
+ */
+ public void setX( float x )
+ {
+ values.set( 0, new COSFloat( x ) );
+ }
+
+ /**
+ * This will get the y value of the tristimulus.
+ *
+ * @return The Y value.
+ */
+ public float getY()
+ {
+ return ((COSNumber)values.get( 1 )).floatValue();
+ }
+
+ /**
+ * This will set the y value of the tristimulus.
+ *
+ * @param y The y value for the tristimulus.
+ */
+ public void setY( float y )
+ {
+ values.set( 1, new COSFloat( y ) );
+ }
+
+ /**
+ * This will get the z value of the tristimulus.
+ *
+ * @return The Z value.
+ */
+ public float getZ()
+ {
+ return ((COSNumber)values.get( 2 )).floatValue();
+ }
+
+ /**
+ * This will set the z value of the tristimulus.
+ *
+ * @param z The z value for the tristimulus.
+ */
+ public void setZ( float z )
+ {
+ values.set( 2, new COSFloat( z ) );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/graphics/color/package.html b/src/main/java/org/pdfbox/pdmodel/graphics/color/package.html
new file mode 100644
index 0000000..733efff
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/graphics/color/package.html
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+
+</head>
+<body>
+This package deals with colors that are stored in a PDF document.
+</body>
+</html> \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/graphics/package.html b/src/main/java/org/pdfbox/pdmodel/graphics/package.html
new file mode 100644
index 0000000..3c1f7ca
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/graphics/package.html
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+
+</head>
+<body>
+The PDModel graphics package deals with graphics states, operations, and parameters within the PDF document.
+</body>
+</html>
diff --git a/src/main/java/org/pdfbox/pdmodel/graphics/predictor/Average.java b/src/main/java/org/pdfbox/pdmodel/graphics/predictor/Average.java
new file mode 100644
index 0000000..46e65dc
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/graphics/predictor/Average.java
@@ -0,0 +1,81 @@
+/**
+ * Copyright (c) 2005, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.graphics.predictor;
+
+/**
+ * We can use raw on the right hand side of
+ * the decoding formula because it is already decoded.
+ *
+ * <code>average(i,j) = raw(i,j) + (raw(i-1,j)+raw(i,j-1)/2</code>
+ *
+ * decoding
+ *
+ * <code>raw(i,j) = avarage(i,j) - (raw(i-1,j)+raw(i,j-1)/2</code>
+ *
+ * @author xylifyx@yahoo.co.uk
+ * @version $Revision: 1.2 $
+ */
+public class Average extends PredictorAlgorithm
+{
+ /**
+ * Not an optimal version, but close to the def.
+ *
+ * @see org.pdfbox.pdmodel.graphics.predictor.PredictorAlgorithm#encodeLine(byte[], byte[],
+ * int, int, int, int)
+ */
+ public void encodeLine(byte[] src, byte[] dest, int srcDy, int srcOffset,
+ int destDy, int destOffset)
+ {
+ int bpl = getWidth() * getBpp();
+ for (int x = 0; x < bpl; x++)
+ {
+ dest[x + destOffset] = (byte) (src[x + srcOffset] - ((leftPixel(
+ src, srcOffset, srcDy, x) + abovePixel(src, srcOffset,
+ srcDy, x)) >>> 2));
+ }
+ }
+
+ /**
+ * @see org.pdfbox.pdmodel.graphics.predictor.PredictorAlgorithm#decodeLine(byte[], byte[],
+ * int, int, int, int)
+ */
+ public void decodeLine(byte[] src, byte[] dest, int srcDy, int srcOffset,
+ int destDy, int destOffset)
+ {
+ int bpl = getWidth() * getBpp();
+ for (int x = 0; x < bpl; x++)
+ {
+ dest[x + destOffset] = (byte) (src[x + srcOffset] + ((leftPixel(
+ dest, destOffset, destDy, x) + abovePixel(dest,
+ destOffset, destDy, x)) >>> 2));
+ }
+ }
+}
diff --git a/src/main/java/org/pdfbox/pdmodel/graphics/predictor/None.java b/src/main/java/org/pdfbox/pdmodel/graphics/predictor/None.java
new file mode 100644
index 0000000..20ec815
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/graphics/predictor/None.java
@@ -0,0 +1,104 @@
+/**
+ * Copyright (c) 2005, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.graphics.predictor;
+
+/**
+ * The none algorithm.
+ *
+ * <code>None(i,j) = Raw(i,j)</code>
+ *
+ * <code>Raw(i,j) = None(i,j)</code>
+ *
+ * @author xylifyx@yahoo.co.uk
+ * @version $Revision: 1.2 $
+ */
+public class None extends PredictorAlgorithm
+{
+ /**
+ * encode a byte array full of image data using the filter that this object
+ * implements.
+ *
+ * @param src
+ * buffer
+ * @param dest
+ * buffer
+ */
+ public void encode(byte[] src, byte[] dest)
+ {
+ checkBufsiz(dest, src);
+ System.arraycopy(src,0,dest,0,src.length);
+ }
+
+ /**
+ * decode a byte array full of image data using the filter that this object
+ * implements.
+ *
+ * @param src
+ * buffer
+ * @param dest
+ * buffer
+ */
+ public void decode(byte[] src, byte[] dest)
+ {
+ System.arraycopy(src,0,dest,0,src.length);
+ }
+
+
+
+ /**
+ * @see org.pdfbox.pdmodel.graphics.predictor.PredictorAlgorithm#encodeLine(byte[], byte[],
+ * int, int, int, int)
+ */
+ public void encodeLine(byte[] src, byte[] dest, int srcDy, int srcOffset,
+ int destDy, int destOffset)
+ {
+ int bpl = getWidth() * getBpp();
+ for (int x = 0; x < bpl; x++)
+ {
+ dest[destOffset + x] = src[srcOffset + x];
+ }
+ }
+
+ /**
+ * @see org.pdfbox.pdmodel.graphics.predictor.PredictorAlgorithm#decodeLine(byte[], byte[],
+ * int, int, int, int)
+ */
+ public void decodeLine(byte[] src, byte[] dest, int srcDy, int srcOffset,
+ int destDy, int destOffset)
+ {
+ int bpl = getWidth() * getBpp();
+ for (int x = 0; x < bpl; x++)
+ {
+ dest[destOffset + x] = src[srcOffset + x];
+ }
+ }
+
+}
diff --git a/src/main/java/org/pdfbox/pdmodel/graphics/predictor/Paeth.java b/src/main/java/org/pdfbox/pdmodel/graphics/predictor/Paeth.java
new file mode 100644
index 0000000..1fddef0
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/graphics/predictor/Paeth.java
@@ -0,0 +1,121 @@
+/**
+ * Copyright (c) 2005, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ */
+package org.pdfbox.pdmodel.graphics.predictor;
+
+/**
+ * From http://www.w3.org/TR/PNG-Filters.html: The Paeth filter computes a
+ * simple linear function of the three neighboring pixels (left, above, upper
+ * left), then chooses as predictor the neighboring pixel closest to the
+ * computed value. This technique is due to Alan W. Paeth [PAETH].
+ *
+ * To compute the Paeth filter, apply the following formula to each byte of the
+ * scanline:
+ *
+ * <code>Paeth(i,j) = Raw(i,j) - PaethPredictor(Raw(i-1,j), Raw(i,j-1), Raw(i-1,j-1))</code>
+ *
+ * To decode the Paeth filter
+ *
+ * <code>Raw(i,j) = Paeth(i,j) - PaethPredictor(Raw(i-1,j), Raw(i,j-1), Raw(i-1,j-1))</code>
+ *
+ * @author xylifyx@yahoo.co.uk
+ * @version $Revision: 1.2 $
+ */
+public class Paeth extends PredictorAlgorithm
+{
+ /**
+ * The paeth predictor function.
+ *
+ * This function is taken almost directly from the PNG definition on
+ * http://www.w3.org/TR/PNG-Filters.html
+ *
+ * @param a
+ * left
+ * @param b
+ * above
+ * @param c
+ * upper left
+ * @return The result of the paeth predictor.
+ */
+ public int paethPredictor(int a, int b, int c)
+ {
+ int p = a + b - c; // initial estimate
+ int pa = Math.abs(p - a); // distances to a, b, c
+ int pb = Math.abs(p - b);
+ int pc = Math.abs(p - c);
+ // return nearest of a,b,c,
+ // breaking ties in order a,b,c.
+ if (pa <= pb && pa <= pc)
+ {
+ return a;
+ }
+ else if (pb <= pc)
+ {
+ return b;
+ }
+ else
+ {
+ return c;
+ }
+ }
+
+ /**
+ * @see org.pdfbox.pdmodel.graphics.predictor.PredictorAlgorithm#encodeLine(byte[], byte[],
+ * int, int, int, int)
+ */
+ public void encodeLine(byte[] src, byte[] dest, int srcDy, int srcOffset,
+ int destDy, int destOffset)
+ {
+ int bpl = getWidth() * getBpp();
+ for (int x = 0; x < bpl; x++)
+ {
+ dest[x + destOffset] = (byte) (src[x + srcOffset] - paethPredictor(
+ leftPixel(src, srcOffset, srcDy, x), abovePixel(src,
+ srcOffset, srcDy, x), aboveLeftPixel(src,
+ srcOffset, srcDy, x)));
+ }
+ }
+
+ /**
+ * @see org.pdfbox.pdmodel.graphics.predictor.PredictorAlgorithm#decodeLine(byte[], byte[],
+ * int, int, int, int)
+ */
+ public void decodeLine(byte[] src, byte[] dest, int srcDy, int srcOffset,
+ int destDy, int destOffset)
+ {
+ int bpl = getWidth() * getBpp();
+ for (int x = 0; x < bpl; x++)
+ {
+ dest[x + destOffset] = (byte) (src[x + srcOffset] + paethPredictor(
+ leftPixel(dest, destOffset, destDy, x), abovePixel(dest,
+ destOffset, destDy, x), aboveLeftPixel(dest,
+ destOffset, destDy, x)));
+ }
+ }
+}
diff --git a/src/main/java/org/pdfbox/pdmodel/graphics/predictor/PredictorAlgorithm.java b/src/main/java/org/pdfbox/pdmodel/graphics/predictor/PredictorAlgorithm.java
new file mode 100644
index 0000000..11f60f9
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/graphics/predictor/PredictorAlgorithm.java
@@ -0,0 +1,336 @@
+/**
+ * Copyright (c) 2005, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.graphics.predictor;
+
+import java.util.Random;
+
+/**
+ * Implements different PNG predictor algorithms that is used in PDF files.
+ *
+ * @author xylifyx@yahoo.co.uk
+ * @version $Revision: 1.2 $
+ * @see http://www.w3.org/TR/PNG-Filters.html
+ */
+public abstract class PredictorAlgorithm
+{
+ private int width;
+
+ private int height;
+
+ private int bpp;
+
+ /**
+ * check that buffer sizes matches width,height,bpp. This implementation is
+ * used by most of the filters, but not Uptimum.
+ *
+ * @param src The source buffer.
+ * @param dest The destination buffer.
+ */
+ public void checkBufsiz(byte[] src, byte[] dest)
+ {
+ if (src.length != dest.length)
+ {
+ throw new IllegalArgumentException("src.length != dest.length");
+ }
+ if (src.length != getWidth() * getHeight() * getBpp())
+ {
+ throw new IllegalArgumentException(
+ "src.length != width * height * bpp");
+ }
+ }
+
+ /**
+ * encode line of pixel data in src from srcOffset and width*bpp bytes
+ * forward, put the decoded bytes into dest.
+ *
+ * @param src
+ * raw image data
+ * @param dest
+ * encoded data
+ * @param srcDy
+ * byte offset between lines
+ * @param srcOffset
+ * beginning of line data
+ * @param destDy
+ * byte offset between lines
+ * @param destOffset
+ * beginning of line data
+ */
+ public abstract void encodeLine(byte[] src, byte[] dest, int srcDy,
+ int srcOffset, int destDy, int destOffset);
+
+ /**
+ * decode line of pixel data in src from src_offset and width*bpp bytes
+ * forward, put the decoded bytes into dest.
+ *
+ * @param src
+ * encoded image data
+ * @param dest
+ * raw data
+ * @param srcDy
+ * byte offset between lines
+ * @param srcOffset
+ * beginning of line data
+ * @param destDy
+ * byte offset between lines
+ * @param destOffset
+ * beginning of line data
+ */
+ public abstract void decodeLine(byte[] src, byte[] dest, int srcDy,
+ int srcOffset, int destDy, int destOffset);
+
+ /**
+ * Simple command line program to test the algorithm.
+ *
+ * @param args The command line arguments.
+ */
+ public static void main(String[] args)
+ {
+ Random rnd = new Random();
+ int width = 5;
+ int height = 5;
+ int bpp = 3;
+ byte[] raw = new byte[width * height * bpp];
+ rnd.nextBytes(raw);
+ System.out.println("raw: ");
+ dump(raw);
+ for (int i = 10; i < 15; i++)
+ {
+ byte[] decoded = new byte[width * height * bpp];
+ byte[] encoded = new byte[width * height * bpp];
+
+ PredictorAlgorithm filter = PredictorAlgorithm.getFilter(i);
+ filter.setWidth(width);
+ filter.setHeight(height);
+ filter.setBpp(bpp);
+ filter.encode(raw, encoded);
+ filter.decode(encoded, decoded);
+ System.out.println(filter.getClass().getName());
+ dump(decoded);
+ }
+ }
+
+ /**
+ * Get the left pixel from the buffer.
+ *
+ * @param buf The buffer.
+ * @param offset The offset into the buffer.
+ * @param dy The dy value.
+ * @param x The x value.
+ *
+ * @return The left pixel.
+ */
+ public int leftPixel(byte[] buf, int offset, int dy, int x)
+ {
+ return x >= getBpp() ? buf[offset + x - getBpp()] : 0;
+ }
+
+ /**
+ * Get the above pixel from the buffer.
+ *
+ * @param buf The buffer.
+ * @param offset The offset into the buffer.
+ * @param dy The dy value.
+ * @param x The x value.
+ *
+ * @return The above pixel.
+ */
+ public int abovePixel(byte[] buf, int offset, int dy, int x)
+ {
+ return offset >= dy ? buf[offset + x - dy] : 0;
+ }
+
+ /**
+ * Get the above-left pixel from the buffer.
+ *
+ * @param buf The buffer.
+ * @param offset The offset into the buffer.
+ * @param dy The dy value.
+ * @param x The x value.
+ *
+ * @return The above-left pixel.
+ */
+ public int aboveLeftPixel(byte[] buf, int offset, int dy, int x)
+ {
+ return offset >= dy && x >= getBpp() ? buf[offset + x - dy - getBpp()]
+ : 0;
+ }
+
+ /**
+ * Simple helper to print out a buffer.
+ *
+ * @param raw The bytes to print out.
+ */
+ private static void dump(byte[] raw)
+ {
+ for (int i = 0; i < raw.length; i++)
+ {
+ System.out.print(raw[i] + " ");
+ }
+ System.out.println();
+ }
+
+ /**
+ * @return Returns the bpp.
+ */
+ public int getBpp()
+ {
+ return bpp;
+ }
+
+ /**
+ * @param newBpp
+ * The bpp to set.
+ */
+ public void setBpp(int newBpp)
+ {
+ bpp = newBpp;
+ }
+
+ /**
+ * @return Returns the height.
+ */
+ public int getHeight()
+ {
+ return height;
+ }
+
+ /**
+ * @param newHeight
+ * The height to set.
+ */
+ public void setHeight(int newHeight)
+ {
+ height = newHeight;
+ }
+
+ /**
+ * @return Returns the width.
+ */
+ public int getWidth()
+ {
+ return width;
+ }
+
+ /**
+ * @param newWidth
+ * The width to set.
+ */
+ public void setWidth(int newWidth)
+ {
+ this.width = newWidth;
+ }
+
+
+ /**
+ * encode a byte array full of image data using the filter that this object
+ * implements.
+ *
+ * @param src
+ * buffer
+ * @param dest
+ * buffer
+ */
+ public void encode(byte[] src, byte[] dest)
+ {
+ checkBufsiz(dest, src);
+ int dy = getWidth()*getBpp();
+ for (int y = 0; y < height; y++)
+ {
+ int yoffset = y * dy;
+ encodeLine(src, dest, dy, yoffset, dy, yoffset);
+ }
+ }
+
+ /**
+ * decode a byte array full of image data using the filter that this object
+ * implements.
+ *
+ * @param src
+ * buffer
+ * @param dest
+ * buffer
+ */
+ public void decode(byte[] src, byte[] dest)
+ {
+ checkBufsiz(src, dest);
+ int dy = width * bpp;
+ for (int y = 0; y < height; y++)
+ {
+ int yoffset = y * dy;
+ decodeLine(src, dest, dy, yoffset, dy, yoffset);
+ }
+ }
+
+ /**
+ * @param predictor
+ * <ul>
+ * <li>1 No prediction (the default value)
+ * <li>2 TIFF Predictor 2
+ * <li>10 PNG prediction (on encoding, PNG None on all rows)
+ * <li>11 PNG prediction (on encoding, PNG Sub on all rows)
+ * <li>12 PNG prediction (on encoding, PNG Up on all rows)
+ * <li>13 PNG prediction (on encoding, PNG Average on all rows)
+ * <li>14 PNG prediction (on encoding, PNG Paeth on all rows)
+ * <li>15 PNG prediction (on encoding, PNG optimum)
+ * </ul>
+ *
+ * @return The predictor class based on the predictor code.
+ */
+ public static PredictorAlgorithm getFilter(int predictor)
+ {
+ PredictorAlgorithm filter;
+ switch (predictor)
+ {
+ case 10:
+ filter = new None();
+ break;
+ case 11:
+ filter = new Sub();
+ break;
+ case 12:
+ filter = new Up();
+ break;
+ case 13:
+ filter = new Average();
+ break;
+ case 14:
+ filter = new Paeth();
+ break;
+ case 15:
+ filter = new Uptimum();
+ break;
+ default:
+ filter = new None();
+ }
+ return filter;
+ }
+}
diff --git a/src/main/java/org/pdfbox/pdmodel/graphics/predictor/Sub.java b/src/main/java/org/pdfbox/pdmodel/graphics/predictor/Sub.java
new file mode 100644
index 0000000..3959dbe
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/graphics/predictor/Sub.java
@@ -0,0 +1,86 @@
+/**
+ * Copyright (c) 2005, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.graphics.predictor;
+
+/**
+ * The sub algorithm.
+ *
+ * <code>Sub(i,j) = Raw(i,j) - Raw(i-1,j)</code>
+ *
+ * <code>Raw(i,j) = Sub(i,j) + Raw(i-1,j)</code>
+ *
+ * @author xylifyx@yahoo.co.uk
+ * @version $Revision: 1.2 $
+ */
+public class Sub extends PredictorAlgorithm
+{
+ /**
+ * @see org.pdfbox.pdmodel.graphics.predictor.PredictorAlgorithm#encodeLine(byte[], byte[], int, int, int, int)
+ */
+ public void encodeLine(byte[] src, byte[] dest, int srcDy, int srcOffset,
+ int destDy, int destOffset)
+ {
+ int bpl = getWidth()*getBpp();
+ int bpp = getBpp();
+ // case: x < bpp
+ for (int x = 0; x < bpl && x < bpp; x++)
+ {
+ dest[x + destOffset] = src[x + srcOffset];
+ }
+ // otherwise
+ for (int x = getBpp(); x < bpl; x++)
+ {
+ dest[x + destOffset] = (byte) (src[x + srcOffset] - src[x
+ + srcOffset - bpp]);
+ }
+ }
+
+ /**
+ * @see org.pdfbox.pdmodel.graphics.predictor.PredictorAlgorithm#decodeLine(byte[], byte[], int, int, int, int)
+ */
+ public void decodeLine(byte[] src, byte[] dest, int srcDy, int srcOffset,
+ int destDy, int destOffset)
+ {
+ int bpl = getWidth()*getBpp();
+ int bpp = getBpp();
+ // case: x < bpp
+ for (int x = 0; x < bpl && x < bpp; x++)
+ {
+ dest[x + destOffset] = src[x + srcOffset];
+ }
+ // otherwise
+ for (int x = getBpp(); x < bpl; x++)
+ {
+ dest[x + destOffset] = (byte) (src[x + srcOffset] + dest[x
+ + destOffset - bpp]);
+ }
+ }
+}
diff --git a/src/main/java/org/pdfbox/pdmodel/graphics/predictor/Up.java b/src/main/java/org/pdfbox/pdmodel/graphics/predictor/Up.java
new file mode 100644
index 0000000..f1932b4
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/graphics/predictor/Up.java
@@ -0,0 +1,100 @@
+/**
+ * Copyright (c) 2005, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.graphics.predictor;
+
+/**
+ * The up algorithm.
+ *
+ * <code>Up(i,j) = Raw(i,j) - Raw(i,j-1)</code>
+ *
+ * <code>Raw(i,j) = Up(i,j) + Raw(i,j-1)</code>
+ *
+ * @author xylifyx@yahoo.co.uk
+ * @version $Revision: 1.2 $
+ */
+public class Up extends PredictorAlgorithm
+{
+ /**
+ * @see org.pdfbox.pdmodel.graphics.predictor.PredictorAlgorithm#encodeLine(byte[], byte[], int, int, int, int)
+ */
+ public void encodeLine(byte[] src, byte[] dest, int srcDy, int srcOffset,
+ int destDy, int destOffset)
+ {
+ int bpl = getWidth()*getBpp();
+ // case: y = 0;
+ if (srcOffset - srcDy < 0)
+ {
+ if (0 < getHeight())
+ {
+ for (int x = 0; x < bpl; x++)
+ {
+ dest[destOffset + x] = src[srcOffset + x];
+ }
+ }
+ }
+ else
+ {
+ for (int x = 0; x < bpl; x++)
+ {
+ dest[destOffset + x] = (byte) (src[srcOffset + x] - src[srcOffset
+ + x - srcDy]);
+ }
+ }
+ }
+
+ /**
+ * @see org.pdfbox.pdmodel.graphics.predictor.PredictorAlgorithm#decodeLine(byte[], byte[], int, int, int, int)
+ */
+ public void decodeLine(byte[] src, byte[] dest, int srcDy, int srcOffset,
+ int destDy, int destOffset)
+ {
+ // case: y = 0;
+ int bpl = getWidth()*getBpp();
+ if (destOffset - destDy < 0)
+ {
+ if (0 < getHeight())
+ {
+ for (int x = 0; x < bpl; x++)
+ {
+ dest[destOffset + x] = src[srcOffset + x];
+ }
+ }
+ }
+ else
+ {
+ for (int x = 0; x < bpl; x++)
+ {
+ dest[destOffset + x] = (byte) (src[srcOffset + x] + dest[destOffset
+ + x - destDy]);
+ }
+ }
+ }
+}
diff --git a/src/main/java/org/pdfbox/pdmodel/graphics/predictor/Uptimum.java b/src/main/java/org/pdfbox/pdmodel/graphics/predictor/Uptimum.java
new file mode 100644
index 0000000..ac03162
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/graphics/predictor/Uptimum.java
@@ -0,0 +1,153 @@
+/**
+ * Copyright (c) 2005, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.graphics.predictor;
+
+/**
+ *
+ *
+ * In an Uptimum encoded image, each line takes up width*bpp+1 bytes. The first
+ * byte holds a number that signifies which algorithm encoded the line.
+ *
+ * @author xylifyx@yahoo.co.uk
+ * @version $Revision: 1.2 $
+ */
+public class Uptimum extends PredictorAlgorithm
+{
+ /**
+ * @see PredictorAlgorithm#checkBufsiz(byte[], byte[])
+ */
+ public void checkBufsiz(byte[] filtered, byte[] raw)
+ {
+ if (filtered.length != (getWidth() * getBpp() + 1) * getHeight())
+ {
+
+ throw new IllegalArgumentException(
+ "filtered.length != (width*bpp + 1) * height, "
+ + filtered.length + " "
+ + (getWidth() * getBpp() + 1) * getHeight()
+ + "w,h,bpp=" + getWidth() + "," + getHeight() + ","
+ + getBpp());
+ }
+ if (raw.length != getWidth() * getHeight() * getBpp())
+ {
+ throw new IllegalArgumentException(
+ "raw.length != width * height * bpp, raw.length="
+ + raw.length + " w,h,bpp=" + getWidth() + ","
+ + getHeight() + "," + getBpp());
+ }
+ }
+
+ /**
+ * @see org.pdfbox.pdmodel.graphics.predictor.PredictorAlgorithm#encodeLine(byte[], byte[],
+ * int, int, int, int)
+ */
+ public void encodeLine(byte[] src, byte[] dest, int srcDy, int srcOffset,
+ int destDy, int destOffset)
+ {
+ throw new UnsupportedOperationException("encodeLine");
+ }
+
+ /**
+ * @see org.pdfbox.pdmodel.graphics.predictor.PredictorAlgorithm#decodeLine(byte[], byte[],
+ * int, int, int, int)
+ */
+ public void decodeLine(byte[] src, byte[] dest, int srcDy, int srcOffset,
+ int destDy, int destOffset)
+ {
+ throw new UnsupportedOperationException("decodeLine");
+ }
+
+ /**
+ * @see PredictorAlgorithm#encode(byte[], byte[])
+ */
+ public void encode(byte[] src, byte[] dest)
+ {
+ checkBufsiz(dest, src);
+ throw new UnsupportedOperationException("encode");
+ }
+
+ /**
+ * filter indexed by byte code.
+ */
+ PredictorAlgorithm[] filter = { new None(), new Sub(), new Up(), new Average(),
+ new Paeth() };
+
+ /**
+ * @see org.pdfbox.pdmodel.graphics.predictor.PredictorAlgorithm#setBpp(int)
+ */
+ public void setBpp(int bpp)
+ {
+ super.setBpp(bpp);
+ for (int i = 0; i < filter.length; i++)
+ {
+ filter[i].setBpp(bpp);
+ }
+ }
+ /**
+ * @see org.pdfbox.pdmodel.graphics.predictor.PredictorAlgorithm#setHeight(int)
+ */
+ public void setHeight(int height)
+ {
+ super.setHeight(height);
+ for (int i = 0; i < filter.length; i++)
+ {
+ filter[i].setHeight(height);
+ }
+ }
+
+ /**
+ * @see org.pdfbox.pdmodel.graphics.predictor.PredictorAlgorithm#setWidth(int)
+ */
+ public void setWidth(int width)
+ {
+ super.setWidth(width);
+ for (int i = 0; i < filter.length; i++)
+ {
+ filter[i].setWidth(width);
+ }
+ }
+
+ /**
+ * @see PredictorAlgorithm#decode(byte[], byte[])
+ */
+ public void decode(byte[] src, byte[] dest)
+ {
+ checkBufsiz(src, dest);
+ int bpl = getWidth() * getBpp();
+ int srcDy = bpl + 1;
+ for (int y = 0; y < getHeight(); y++)
+ {
+ PredictorAlgorithm f = filter[src[y * srcDy]];
+ int srcOffset = y * srcDy + 1;
+ f.decodeLine(src, dest, srcDy, srcOffset, bpl, y * bpl);
+ }
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/graphics/predictor/package.html b/src/main/java/org/pdfbox/pdmodel/graphics/predictor/package.html
new file mode 100644
index 0000000..127d2e0
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/graphics/predictor/package.html
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+
+</head>
+<body>
+The predictor package contains code for different PNG predictor algorithms that
+are present in PDF documents. These classes are used internally by PDFBox.
+</body>
+</html>
diff --git a/src/main/java/org/pdfbox/pdmodel/graphics/xobject/PDCcitt.java b/src/main/java/org/pdfbox/pdmodel/graphics/xobject/PDCcitt.java
new file mode 100644
index 0000000..59387a0
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/graphics/xobject/PDCcitt.java
@@ -0,0 +1,598 @@
+/**
+ * Copyright (c) 2005, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.graphics.xobject;
+
+import java.awt.image.BufferedImage;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.RandomAccessFile;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.imageio.ImageIO;
+
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSName;
+
+import org.pdfbox.pdmodel.PDDocument;
+import org.pdfbox.pdmodel.common.PDStream;
+import org.pdfbox.pdmodel.graphics.color.PDDeviceGray;
+
+/**
+ * An image class for CCITT Fax.
+ *
+ * @author paul king
+ * @version $Revision: 1.2 $
+ */
+public class PDCcitt extends PDXObjectImage
+{
+ private static final List FAX_FILTERS = new ArrayList();
+
+ static
+ {
+ FAX_FILTERS.add( COSName.CCITTFAX_DECODE.getName() );
+ FAX_FILTERS.add( COSName.CCITTFAX_DECODE_ABBREVIATION.getName() );
+ }
+
+ /**
+ * Standard constructor.
+ *
+ * @param ccitt The PDStream that already contains all ccitt information.
+ */
+ public PDCcitt(PDStream ccitt)
+ {
+ super(ccitt, "tiff");
+
+ }
+
+ /**
+ * Construct from a tiff file.
+ *
+ * @param doc The document to create the image as part of.
+ * @param raf The random access TIFF file which contains a suitable CCITT compressed image
+ * @throws IOException If there is an error reading the tiff data.
+ */
+
+ public PDCcitt( PDDocument doc, java.io.RandomAccessFile raf ) throws IOException
+ {
+ super( new PDStream(doc),"tiff");
+ // super( new PDStream( doc, null, true ), "tiff" );
+
+ COSDictionary decodeParms = new COSDictionary();
+
+ COSDictionary dic = getCOSStream();
+
+ extractFromTiff(raf, getCOSStream().createFilteredStream(),decodeParms);
+
+ dic.setItem( COSName.FILTER, COSName.CCITTFAX_DECODE);
+ dic.setItem( COSName.SUBTYPE, COSName.IMAGE);
+ dic.setItem( COSName.TYPE, COSName.getPDFName( "XObject" ) );
+ dic.setItem( "DecodeParms", decodeParms);
+
+ setBitsPerComponent( 1 );
+ setColorSpace( new PDDeviceGray() );
+ setWidth( decodeParms.getInt("Columns") );
+ setHeight( decodeParms.getInt("Rows") );
+
+ }
+
+ /**
+ * Returns an image of the CCITT Fax, or null if TIFFs are not supported. (Requires additional JAI Image filters )
+ * @see org.pdfbox.pdmodel.graphics.xobject.PDXObjectImage#getRGBImage()
+ */
+ public BufferedImage getRGBImage() throws IOException
+ {
+ // ImageIO.scanForPlugins();
+ return ImageIO.read(new TiffWrapper(getPDStream().getPartiallyFilteredStream( FAX_FILTERS ),getCOSStream()));
+ }
+
+ /**
+ * This writes a tiff to out.
+ * @see org.pdfbox.pdmodel.graphics.xobject.PDXObjectImage#write2OutputStream(java.io.OutputStream)
+ */
+ public void write2OutputStream(OutputStream out) throws IOException
+ {
+ InputStream data = new TiffWrapper(getPDStream().getPartiallyFilteredStream( FAX_FILTERS ),getCOSStream());
+ byte[] buf = new byte[1024];
+ int amountRead = -1;
+ while( (amountRead = data.read( buf )) != -1 )
+ {
+ out.write( buf, 0, amountRead );
+ }
+ }
+
+ /**
+ * Extract the ccitt stream from the tiff file.
+ *
+ * @param raf - TIFF File
+ * @param os - Stream to write raw ccitt data two
+ * @param parms - COSDictionary which the encoding parameters are added to
+ * @throws IOException If there is an error reading/writing to/from the stream
+ */
+ private void extractFromTiff(RandomAccessFile raf, OutputStream os, COSDictionary parms) throws IOException
+ {
+ try
+ {
+
+ // First check the basic tiff header
+ raf.seek(0);
+ char endianess = (char) raf.read();
+ if ((char) raf.read() != endianess)
+ {
+ throw new IOException("Not a valid tiff file");
+ }
+ //ensure that endianess is either M or I
+ if (endianess != 'M' && endianess != 'I')
+ {
+ throw new IOException("Not a valid tiff file");
+ }
+ int magicNumber = readshort(endianess, raf);
+ if( magicNumber != 42)
+ {
+ throw new IOException("Not a valid tiff file");
+ }
+
+ // Relocate to the first set of tags
+ raf.seek(readlong(endianess, raf));
+
+ int numtags = readshort(endianess, raf);
+
+ // The number 50 is somewhat arbitary, it just stops us load up junk from somewhere and tramping on
+ if (numtags > 50)
+ {
+ throw new IOException("Not a valid tiff file");
+ }
+
+ // Loop through the tags, some will convert to items in the parms dictionary
+ // Other point us to where to find the data stream
+ // The only parm which might change as a result of other options is K, so
+ // We'll deal with that as a special;
+
+ int k=-1000; // Default Non CCITT compression
+ int dataoffset=0;
+ int datalength=0;
+
+ for (int i=0; i < numtags; i++)
+ {
+ int tag = readshort(endianess, raf);
+ int type = readshort(endianess, raf);
+ int count = readlong(endianess, raf);
+ int val = readlong(endianess, raf); // See note
+
+ // Note, we treated that value as a long. The value always occupies 4 bytes
+ // But it might only use the first byte or two. Depending on endianess we might need to correct
+ // Note we ignore all other types, they are of little interest for PDFs/CCITT Fax
+ if (endianess == 'M')
+ {
+ switch (type)
+ {
+ case 1:
+ {
+ val = val >> 24;
+ break; // byte value
+ }
+ case 3:
+ {
+ val = val >> 16;
+ break; // short value
+ }
+ case 4:
+ {
+ break; // long value
+ }
+ default:
+ {
+ //do nothing
+ }
+ }
+ }
+ switch (tag)
+ {
+ case 256:
+ {
+ parms.setInt("Columns",val);
+ break;
+ }
+ case 257:
+ {
+ parms.setInt("Rows",val);
+ break;
+ }
+ case 259:
+ {
+ if (val == 4)
+ {
+ k=-1;
+ }
+ if (val == 3)
+ {
+ k=0;
+ }
+ break; // T6/T4 Compression
+ }
+ case 262:
+ {
+ if (val == 1)
+ {
+ parms.setBoolean("BlackIs1", true);
+ }
+ break;
+ }
+ case 273:
+ {
+ if (count == 1)
+ {
+ dataoffset=val;
+ }
+ break;
+ }
+ case 279:
+ {
+ if (count == 1)
+ {
+ datalength=val;
+ }
+ break;
+ }
+ case 292:
+ {
+ if (val == 1)
+ {
+ k=50; // T4 2D - arbitary K value
+ }
+ break;
+ }
+ case 324:
+ {
+ if (count == 1)
+ {
+ dataoffset=val;
+ }
+ break;
+ }
+ case 325:
+ {
+ if (count == 1)
+ {
+ datalength=val;
+ }
+ break;
+ }
+ default:
+ {
+ //do nothing
+ }
+ }
+ }
+
+ if (k == -1000)
+ {
+ throw new IOException("First image in tiff is not CCITT T4 or T6 compressed");
+ }
+ if (dataoffset == 0)
+ {
+ throw new IOException("First image in tiff is not a single tile/strip");
+ }
+
+ parms.setInt("K",k);
+
+ raf.seek(dataoffset);
+
+ byte[] buf = new byte[8192];
+ int amountRead = -1;
+ while( (amountRead = raf.read( buf,0, Math.min(8192,datalength) )) > 0 )
+ {
+ datalength -= amountRead;
+ os.write( buf, 0, amountRead );
+ }
+
+ }
+ finally
+ {
+ os.close();
+ }
+ }
+
+ private int readshort(char endianess, RandomAccessFile raf) throws IOException
+ {
+ if (endianess == 'I')
+ {
+ return raf.read() | (raf.read() << 8);
+ }
+ return (raf.read() << 8) | raf.read();
+ }
+
+ private int readlong(char endianess, RandomAccessFile raf) throws IOException
+ {
+ if (endianess == 'I')
+ {
+ return raf.read() | (raf.read() << 8) | (raf.read() << 16) | (raf.read() << 24);
+ }
+ return (raf.read() << 24) | (raf.read() << 16) | (raf.read() << 8) | raf.read();
+ }
+
+
+ /**
+ * Extends InputStream to wrap the data from the CCITT Fax with a suitable TIFF Header.
+ * For details see www.tiff.org, which contains useful information including pointers to the
+ * TIFF 6.0 Specification
+ *
+ */
+ private class TiffWrapper extends InputStream
+ {
+
+ private int currentOffset; // When reading, where in the tiffheader are we.
+ private byte[] tiffheader; // Byte array to store tiff header data
+ private InputStream datastream; // Original InputStream
+
+ public TiffWrapper(InputStream rawstream, COSDictionary options)
+ {
+ buildHeader(options);
+ currentOffset=0;
+ datastream = rawstream;
+ }
+
+ // Implement basic methods from InputStream
+
+ public boolean markSupported()
+ {
+ return false;
+ }
+
+ public void reset() throws IOException
+ {
+ throw new IOException("reset not supported");
+ }
+
+ // For simple read, take a byte from the tiffheader array or pass through.
+ public int read() throws IOException
+ {
+ if (currentOffset < tiffheader.length)
+ {
+ return tiffheader[currentOffset++];
+ }
+ return datastream.read();
+ }
+
+ // For read methods only return as many bytes as we have left in the header
+ // if we've exhausted the header, pass through to the InputStream of the raw CCITT data
+ public int read(byte[] data) throws IOException
+ {
+ if (currentOffset < tiffheader.length)
+ {
+ int length = java.lang.Math.min(tiffheader.length - currentOffset, data.length);
+ if (length > 0)
+ {
+ System.arraycopy(tiffheader, currentOffset, data, 0, length);
+ }
+ currentOffset += length;
+ return length;
+ }
+ else
+ {
+ return datastream.read(data);
+ }
+ }
+
+ // For read methods only return as many bytes as we have left in the header
+ // if we've exhausted the header, pass through to the InputStream of the raw CCITT data
+ public int read(byte[] data, int off, int len) throws IOException
+ {
+ if (currentOffset < tiffheader.length)
+ {
+ int length = java.lang.Math.min(tiffheader.length - currentOffset, len);
+ if (length > 0)
+ {
+ System.arraycopy(tiffheader, currentOffset, data, off, length);
+ }
+ currentOffset += length;
+ return length;
+ }
+ else
+ {
+ return datastream.read(data,off,len);
+ }
+ }
+
+ // When skipping if any header data not yet read, only allow to skip what we've in the buffer
+ // Otherwise just pass through.
+ public long skip(long n) throws IOException
+ {
+ if (currentOffset < tiffheader.length)
+ {
+ long length = Math.min(tiffheader.length - currentOffset, n);
+ currentOffset += length;
+ return length;
+ }
+ else
+ {
+ return datastream.skip(n);
+ }
+ }
+
+ // Static data for the beginning of the TIFF header
+ private final byte[] basicHeader = {
+ 'I','I',42,0,8,0,0,0, // File introducer and pointer to first IFD
+ 0,0}; // Number of tags start with two
+
+
+ private int additionalOffset; // Offset in header to additional data
+
+ // Builds up the tiffheader based on the options passed through.
+ private void buildHeader(COSDictionary options)
+ {
+
+ final int numOfTags = 10; // The maximum tags we'll fill
+ final int maxAdditionalData = 24; // The maximum amount of additional data
+ // outside the IFDs. (bytes)
+
+ // The length of the header will be the length of the basic header (10)
+ // plus 12 bytes for each IFD, 4 bytes as a pointer to the next IFD (will be 0)
+ // plus the length of the additional data
+
+ tiffheader = new byte[10 + (12 * numOfTags ) + 4 + maxAdditionalData];
+ java.util.Arrays.fill(tiffheader,(byte)0);
+ System.arraycopy(basicHeader,0,tiffheader,0,basicHeader.length);
+
+ // Additional data outside the IFD starts after the IFD's and pointer to the next IFD (0)
+ additionalOffset = 10 + (12 * numOfTags ) + 4;
+
+ // Now work out the variable values from TIFF defaults,
+ // PDF Defaults and the Dictionary for this XObject
+ short cols = 1728;
+ short rows = 0;
+ short blackis1 = 0;
+ short comptype = 3; // T4 compression
+ long t4options = 0; // Will set if 1d or 2d T4
+
+ COSDictionary decodeParms = (COSDictionary) options.getDictionaryObject("DecodeParms");
+
+ if (decodeParms != null)
+ {
+ cols = (short) decodeParms.getInt("Columns", cols);
+ rows = (short) decodeParms.getInt("Rows", rows);
+ if (decodeParms.getBoolean("BlackIs1", false))
+ {
+ blackis1 = 1;
+ }
+ int k = decodeParms.getInt("K"); // Mandatory parm
+ if (k < 0)
+ {
+ //T6
+ comptype = 4;
+ }
+ if (k > 0)
+ {
+ //T4 2D
+ comptype = 3;
+ t4options = 1;
+ }
+ // else k = 0, leave as default T4 1D compression
+ }
+
+ // If we couldn't get the number of rows, use the main item from XObject
+ if (rows == 0)
+ {
+ rows = (short) options.getInt("Height", rows);
+ }
+
+ // Now put the tags into the tiffheader
+ // These musn't exceed the maximum set above, and by TIFF spec should be sorted into
+ // Numeric sequence.
+
+ addTag(256, cols); // Columns
+ addTag(257, rows); // Rows
+ addTag(259, comptype); // T6
+ addTag(262, blackis1); // Photometric Interpretation
+ addTag(273, (long) tiffheader.length); // Offset to start of image data - updated below
+ addTag(279, (long) options.getInt("Length")); // Length of image data
+ addTag(282, 300, 1); // X Resolution 300 (default unit Inches) This is arbitary
+ addTag(283, 300, 1); // Y Resolution 300 (default unit Inches) This is arbitary
+ if (comptype == 3)
+ {
+ addTag(292, t4options);
+ }
+ addTag(305, "PDFBOX"); // Software generating image
+ }
+
+ /* Tiff types 1 = byte, 2=ascii, 3=short, 4=ulong 5=rational */
+
+ private void addTag(int tag,long value)
+ {
+ // Adds a tag of type 4 (ulong)
+ int count = ++tiffheader[8];
+ int offset = (count-1)*12 + 10;
+ tiffheader[offset]=(byte)(tag & 0xff);
+ tiffheader[offset+1]=(byte)((tag>>8) & 0xff);
+ tiffheader[offset+2]=4; // Type Long
+ tiffheader[offset+4]=1; // One Value
+ tiffheader[offset+8]=(byte)(value & 0xff);
+ tiffheader[offset+9]=(byte)((value>>8) & 0xff);
+ tiffheader[offset+10]=(byte)((value>>16) & 0xff);
+ tiffheader[offset+11]=(byte)((value>>24) & 0xff);
+ }
+
+ private void addTag(int tag, short value)
+ {
+ // Adds a tag of type 3 (short)
+ int count = ++tiffheader[8];
+ int offset = (count-1)*12 + 10;
+ tiffheader[offset]=(byte)(tag & 0xff);
+ tiffheader[offset+1]=(byte)((tag>>8) & 0xff);
+ tiffheader[offset+2]=3; // Type Short
+ tiffheader[offset+4]=1; // One Value
+ tiffheader[offset+8]=(byte)(value & 0xff);
+ tiffheader[offset+9]=(byte)((value>>8) & 0xff);
+ }
+
+ private void addTag(int tag, String value)
+ {
+ // Adds a tag of type 2 (ascii)
+ int count = ++tiffheader[8];
+ int offset = (count-1)*12 + 10;
+ tiffheader[offset]=(byte)(tag & 0xff);
+ tiffheader[offset+1]=(byte)((tag>>8) & 0xff);
+ tiffheader[offset+2]=2; // Type Ascii
+ tiffheader[offset+4]=1; // One Value
+ tiffheader[offset+8]=(byte)(additionalOffset & 0xff);
+ tiffheader[offset+9]=(byte)((additionalOffset>>8) & 0xff);
+ tiffheader[offset+10]=(byte)((additionalOffset>>16) & 0xff);
+ tiffheader[offset+11]=(byte)((additionalOffset>>24) & 0xff);
+ System.arraycopy(value.getBytes(), 0, tiffheader, additionalOffset, value.length());
+ additionalOffset += value.length() + 1;
+ }
+
+ private void addTag(int tag, long numerator, long denominator)
+ {
+ // Adds a tag of type 5 (rational)
+ int count = ++tiffheader[8];
+ int offset = (count-1)*12 + 10;
+ tiffheader[offset]=(byte)(tag & 0xff);
+ tiffheader[offset+1]=(byte)((tag>>8) & 0xff);
+ tiffheader[offset+2]=5; // Type Rational
+ tiffheader[offset+4]=1; // One Value
+ tiffheader[offset+8]=(byte)(additionalOffset & 0xff);
+ tiffheader[offset+9]=(byte)((additionalOffset>>8) & 0xff);
+ tiffheader[offset+10]=(byte)((additionalOffset>>16) & 0xff);
+ tiffheader[offset+11]=(byte)((additionalOffset>>24) & 0xff);
+ tiffheader[additionalOffset++]=(byte) ((numerator) & 0xFF);
+ tiffheader[additionalOffset++]=(byte) ((numerator>>8) & 0xFF);
+ tiffheader[additionalOffset++]=(byte) ((numerator>>16) & 0xFF);
+ tiffheader[additionalOffset++]=(byte) ((numerator>>24) & 0xFF);
+ tiffheader[additionalOffset++]=(byte) ((denominator) & 0xFF);
+ tiffheader[additionalOffset++]=(byte) ((denominator>>8) & 0xFF);
+ tiffheader[additionalOffset++]=(byte) ((denominator>>16) & 0xFF);
+ tiffheader[additionalOffset++]=(byte) ((denominator>>24) & 0xFF);
+ }
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/graphics/xobject/PDInlinedImage.java b/src/main/java/org/pdfbox/pdmodel/graphics/xobject/PDInlinedImage.java
new file mode 100644
index 0000000..009743f
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/graphics/xobject/PDInlinedImage.java
@@ -0,0 +1,201 @@
+/**
+ * Copyright (c) 2003-2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.graphics.xobject;
+
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.DataBuffer;
+import java.awt.image.DataBufferByte;
+import java.awt.image.DataBufferInt;
+import java.awt.image.IndexColorModel;
+import java.awt.image.WritableRaster;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.List;
+
+import org.pdfbox.filter.Filter;
+import org.pdfbox.filter.FilterManager;
+import org.pdfbox.pdmodel.graphics.color.PDColorSpace;
+import org.pdfbox.util.ImageParameters;
+
+/**
+ * This class represents an inlined image.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.4 $
+ */
+public class PDInlinedImage
+{
+ private ImageParameters params;
+ private byte[] imageData;
+
+ /**
+ * This will get the image parameters.
+ *
+ * @return The image parameters.
+ */
+ public ImageParameters getImageParameters()
+ {
+ return params;
+ }
+
+ /**
+ * This will set the image parameters for this image.
+ *
+ * @param imageParams The imageParams.
+ */
+ public void setImageParameters( ImageParameters imageParams )
+ {
+ params = imageParams;
+ }
+
+ /**
+ * Get the bytes for the image.
+ *
+ * @return The image data.
+ */
+ public byte[] getImageData()
+ {
+ return imageData;
+ }
+
+ /**
+ * Set the bytes that make up the image.
+ *
+ * @param value The image data.
+ */
+ public void setImageData(byte[] value)
+ {
+ imageData = value;
+ }
+
+ /**
+ * This will take the inlined image information and create a java.awt.Image from
+ * it.
+ *
+ * @return The image that this object represents.
+ *
+ * @throws IOException If there is an error creating the image.
+ */
+ public BufferedImage createImage() throws IOException
+ {
+ /*
+ * This was the previous implementation, not sure which is better right now.
+ * byte[] transparentColors = new byte[]{(byte)0xFF,(byte)0xFF};
+ byte[] colors=new byte[]{0, (byte)0xFF};
+ IndexColorModel colorModel = new IndexColorModel( 1, 2, colors, colors, colors, transparentColors );
+ BufferedImage image = new BufferedImage(
+ params.getWidth(),
+ params.getHeight(),
+ BufferedImage.TYPE_BYTE_BINARY,
+ colorModel );
+ DataBufferByte buffer = new DataBufferByte( getImageData(), 1 );
+ WritableRaster raster =
+ Raster.createPackedRaster(
+ buffer,
+ params.getWidth(),
+ params.getHeight(),
+ params.getBitsPerComponent(),
+ new Point(0,0) );
+ image.setData( raster );
+ return image;
+ */
+
+
+ //verify again pci32.pdf before changing below
+ PDColorSpace pcs = params.getColorSpace();
+ ColorModel colorModel = null;
+ if(pcs != null)
+ {
+ colorModel =
+ params.getColorSpace().createColorModel(
+ params.getBitsPerComponent() );
+ }
+ else
+ {
+ byte[] transparentColors = new
+ byte[]{(byte)0xFF,(byte)0xFF};
+ byte[] colors=new byte[]{0, (byte)0xFF};
+ colorModel = new IndexColorModel( 1, 2,
+ colors, colors, colors, transparentColors );
+ }
+ List filters = params.getFilters();
+ byte[] finalData = null;
+ if( filters == null )
+ {
+ finalData = getImageData();
+ }
+ else
+ {
+ ByteArrayInputStream in = new ByteArrayInputStream( getImageData() );
+ ByteArrayOutputStream out = new ByteArrayOutputStream(getImageData().length);
+ FilterManager filterManager = new FilterManager();
+ for( int i=0; filters != null && i<filters.size(); i++ )
+ {
+ out.reset();
+ Filter filter = filterManager.getFilter( (String)filters.get( i ) );
+ filter.decode( in, out, params.getDictionary() );
+ in = new ByteArrayInputStream( out.toByteArray() );
+ }
+ finalData = out.toByteArray();
+ }
+
+ WritableRaster raster = colorModel.createCompatibleWritableRaster( params.getWidth(), params.getHeight() );
+ /* Raster.createPackedRaster(
+ buffer,
+ params.getWidth(),
+ params.getHeight(),
+ params.getBitsPerComponent(),
+ new Point(0,0) );
+ */
+ DataBuffer rasterBuffer = raster.getDataBuffer();
+ if( rasterBuffer instanceof DataBufferByte )
+ {
+ DataBufferByte byteBuffer = (DataBufferByte)rasterBuffer;
+ byte[] data = byteBuffer.getData();
+ System.arraycopy( finalData, 0, data, 0, data.length );
+ }
+ else if( rasterBuffer instanceof DataBufferInt )
+ {
+ DataBufferInt byteBuffer = (DataBufferInt)rasterBuffer;
+ int[] data = byteBuffer.getData();
+ for( int i=0; i<finalData.length; i++ )
+ {
+ data[i] = (finalData[i]+256)%256;
+ }
+ }
+ BufferedImage image = new BufferedImage(
+ colorModel, raster, false, null );
+ image.setData( raster );
+ return image;
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/graphics/xobject/PDJpeg.java b/src/main/java/org/pdfbox/pdmodel/graphics/xobject/PDJpeg.java
new file mode 100644
index 0000000..79ee8e8
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/graphics/xobject/PDJpeg.java
@@ -0,0 +1,156 @@
+/**
+ * Copyright (c) 2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.graphics.xobject;
+
+import java.awt.image.BufferedImage;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.imageio.ImageIO;
+
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSName;
+
+import org.pdfbox.pdmodel.PDDocument;
+import org.pdfbox.pdmodel.common.PDStream;
+import org.pdfbox.pdmodel.graphics.color.PDDeviceRGB;
+
+/**
+ * An image class for JPegs.
+ *
+ * @author mathiak
+ * @version $Revision: 1.4 $
+ */
+public class PDJpeg extends PDXObjectImage
+{
+
+ private static final List DCT_FILTERS = new ArrayList();
+
+ static
+ {
+ DCT_FILTERS.add( COSName.DCT_DECODE.getName() );
+ DCT_FILTERS.add( COSName.DCT_DECODE_ABBREVIATION.getName() );
+ }
+
+ /**
+ * Standard constructor.
+ *
+ * @param jpeg The COSStream from which to extract the JPeg
+ */
+ public PDJpeg(PDStream jpeg)
+ {
+ super(jpeg, "jpg");
+ }
+
+ /**
+ * Construct from a stream.
+ *
+ * @param doc The document to create the image as part of.
+ * @param is The stream that contains the jpeg data.
+ * @throws IOException If there is an error reading the jpeg data.
+ */
+ public PDJpeg( PDDocument doc, InputStream is ) throws IOException
+ {
+ super( new PDStream( doc, is, true ), "jpg" );
+ COSDictionary dic = getCOSStream();
+ dic.setItem( COSName.FILTER, COSName.DCT_DECODE );
+ dic.setItem( COSName.SUBTYPE, COSName.IMAGE);
+ dic.setItem( COSName.TYPE, COSName.getPDFName( "XObject" ) );
+
+ BufferedImage image = getRGBImage();
+ setBitsPerComponent( 8 );
+ setColorSpace( PDDeviceRGB.INSTANCE );
+ setHeight( image.getHeight() );
+ setWidth( image.getWidth() );
+
+ }
+
+ /**
+ * Construct from a buffered image.
+ *
+ * @param doc The document to create the image as part of.
+ * @param bi The image to convert to a jpeg
+ * @throws IOException If there is an error processing the jpeg data.
+ */
+ public PDJpeg( PDDocument doc, BufferedImage bi ) throws IOException
+ {
+ super( new PDStream( doc ), "jpg" );
+
+ java.io.OutputStream os = getCOSStream().createFilteredStream();
+ try
+ {
+
+ ImageIO.write(bi,"jpeg",os);
+
+ COSDictionary dic = getCOSStream();
+ dic.setItem( COSName.FILTER, COSName.DCT_DECODE );
+ dic.setItem( COSName.SUBTYPE, COSName.IMAGE);
+ dic.setItem( COSName.TYPE, COSName.getPDFName( "XObject" ) );
+
+ setBitsPerComponent( 8 );
+ setColorSpace( PDDeviceRGB.INSTANCE );
+ setHeight( bi.getHeight() );
+ setWidth( bi.getWidth() );
+ }
+ finally
+ {
+ os.close();
+ }
+ }
+
+ /**
+ * Returns an image of the JPeg, or null if JPegs are not supported. (They should be. )
+ * @see org.pdfbox.pdmodel.graphics.xobject.PDXObjectImage#getRGBImage()
+ */
+ public BufferedImage getRGBImage() throws IOException
+ {
+ return ImageIO.read(getPDStream().getPartiallyFilteredStream( DCT_FILTERS ));
+ }
+
+ /**
+ * This writes the JPeg to out.
+ * @see org.pdfbox.pdmodel.graphics.xobject.PDXObjectImage#write2OutputStream(java.io.OutputStream)
+ */
+ public void write2OutputStream(OutputStream out) throws IOException
+ {
+ InputStream data = getPDStream().getPartiallyFilteredStream( DCT_FILTERS );
+ byte[] buf = new byte[1024];
+ int amountRead = -1;
+ while( (amountRead = data.read( buf )) != -1 )
+ {
+ out.write( buf, 0, amountRead );
+ }
+ }
+}
diff --git a/src/main/java/org/pdfbox/pdmodel/graphics/xobject/PDPixelMap.java b/src/main/java/org/pdfbox/pdmodel/graphics/xobject/PDPixelMap.java
new file mode 100644
index 0000000..96a1f29
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/graphics/xobject/PDPixelMap.java
@@ -0,0 +1,236 @@
+/**
+ * Copyright (c) 2004-2005, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.graphics.xobject;
+
+import java.awt.image.DataBufferByte;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.WritableRaster;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import javax.imageio.ImageIO;
+
+import org.pdfbox.cos.COSArray;
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.pdmodel.common.PDStream;
+
+import org.pdfbox.pdmodel.graphics.color.PDColorSpace;
+import org.pdfbox.pdmodel.graphics.predictor.PredictorAlgorithm;
+
+/**
+ * This class contains a PixelMap Image.
+ * @author Ben Litchfield (ben@benlitchfield.com)
+ * @author mathiak
+ * @version $Revision: 1.7 $
+ */
+public class PDPixelMap extends PDXObjectImage
+{
+ private BufferedImage image = null;
+
+ /**
+ * Standard constructor. Basically does nothing.
+ * @param pdStream The stream that holds the pixel map.
+ */
+ public PDPixelMap(PDStream pdStream)
+ {
+ super(pdStream, "png");
+ }
+
+ /**
+ * Construct a pixel map image from an AWT image.
+ *
+ * @param doc The PDF document to embed the image in.
+ * @param awtImage The image to read data from.
+ *
+ * @throws IOException If there is an error while embedding this image.
+ */
+ /*
+ * This method is broken and needs to be implemented, any takers?
+ public PDPixelMap(PDDocument doc, BufferedImage awtImage) throws IOException
+ {
+ super( doc, "png");
+ image = awtImage;
+ setWidth( image.getWidth() );
+ setHeight( image.getHeight() );
+
+ ColorModel cm = image.getColorModel();
+ ColorSpace cs = cm.getColorSpace();
+ PDColorSpace pdColorSpace = PDColorSpaceFactory.createColorSpace( doc, cs );
+ setColorSpace( pdColorSpace );
+ //setColorSpace( )
+
+ PDStream stream = getPDStream();
+ OutputStream output = null;
+ try
+ {
+ output = stream.createOutputStream();
+ DataBuffer buffer = awtImage.getRaster().getDataBuffer();
+ if( buffer instanceof DataBufferByte )
+ {
+ DataBufferByte byteBuffer = (DataBufferByte)buffer;
+ byte[] data = byteBuffer.getData();
+ output.write( data );
+ }
+ setBitsPerComponent( cm.getPixelSize() );
+ }
+ finally
+ {
+ if( output != null )
+ {
+ output.close();
+ }
+ }
+ }*/
+
+ /**
+ * Returns a {@link java.awt.image.BufferedImage} of the COSStream
+ * set in the constructor or null if the COSStream could not be encoded.
+ *
+ * @see org.pdfbox.pdmodel.graphics.xobject.PDXObjectImage#getRGBImage()
+ */
+ public BufferedImage getRGBImage() throws IOException
+ {
+ if( image != null )
+ {
+ return image;
+ }
+
+ //byte[] index =
+ //ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
+ int width = getWidth();
+ int height = getHeight();
+ int bpc = getBitsPerComponent();
+ //COSInteger length =
+ // (COSInteger) stream.getStream().getDictionary().getDictionaryObject(COSName.LENGTH);
+ //byte[] array = new byte[stream.getFilteredStream().];
+ byte[] array = getPDStream().getByteArray();
+
+// Get the ColorModel right
+ PDColorSpace colorspace = getColorSpace();
+ ColorModel cm = colorspace.createColorModel( bpc );
+ WritableRaster raster = cm.createCompatibleWritableRaster( width, height );
+ //DataBufferByte buffer = (DataBufferByte)raster.getDataBuffer();
+ DataBufferByte buffer = (DataBufferByte)raster.getDataBuffer();
+ byte[] bufferData = buffer.getData();
+ //System.arraycopy( array, 0, bufferData, 0, array.length );
+ int predictor = getPredictor();
+
+ PredictorAlgorithm filter = PredictorAlgorithm.getFilter(predictor);
+ filter.setWidth(width);
+ filter.setHeight(height);
+ filter.setBpp((bpc * 3) / 8);
+ filter.decode(array, bufferData);
+ image = new BufferedImage(cm, raster, false, null);
+ return image;
+ }
+
+ /**
+ * Writes the image as .png.
+ *
+ * @see org.pdfbox.pdmodel.graphics.xobject.PDXObjectImage#write2OutputStream(java.io.OutputStream)
+ */
+ public void write2OutputStream(OutputStream out) throws IOException
+ {
+ getRGBImage();
+ if (image!=null)
+ {
+ ImageIO.write(image, "png", out);
+ }
+ }
+
+ /**
+ * DecodeParms is an optional parameter for filters.
+ *
+ * It is provided if any of the filters has nondefault parameters. If there
+ * is only one filter it is a dictionary, if there are multiple filters it
+ * is an array with an entry for each filter. An array entry can hold a null
+ * value if only the default values are used or a dictionary with
+ * parameters.
+ *
+ * @return The decoding parameters.
+ *
+ */
+ public COSDictionary getDecodeParams()
+ {
+ COSBase decodeParms = getCOSStream().getDictionaryObject("DecodeParms");
+ if (decodeParms != null)
+ {
+ if (decodeParms instanceof COSDictionary)
+ {
+ return (COSDictionary) decodeParms;
+ }
+ else if (decodeParms instanceof COSArray)
+ {
+ // not implemented yet, which index should we use?
+ return null;//(COSDictionary)((COSArray)decodeParms).get(0);
+ }
+ else
+ {
+ return null;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * A code that selects the predictor algorithm.
+ *
+ * <ul>
+ * <li>1 No prediction (the default value)
+ * <li>2 TIFF Predictor 2
+ * <li>10 PNG prediction (on encoding, PNG None on all rows)
+ * <li>11 PNG prediction (on encoding, PNG Sub on all rows)
+ * <li>12 PNG prediction (on encoding, PNG Up on all rows)
+ * <li>13 PNG prediction (on encoding, PNG Average on all rows)
+ * <li>14 PNG prediction (on encoding, PNG Paeth on all rows)
+ * <li>15 PNG prediction (on encoding, PNG optimum)
+ * </ul>
+ *
+ * Default value: 1.
+ *
+ * @return predictor algorithm code
+ */
+ public int getPredictor()
+ {
+ COSDictionary decodeParms = getDecodeParams();
+ if (decodeParms != null)
+ {
+ int i = decodeParms.getInt("Predictor");
+ if (i != -1)
+ {
+ return i;
+ }
+ }
+ return 1;
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/graphics/xobject/PDXObject.java b/src/main/java/org/pdfbox/pdmodel/graphics/xobject/PDXObject.java
new file mode 100644
index 0000000..99ac8a5
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/graphics/xobject/PDXObject.java
@@ -0,0 +1,207 @@
+/**
+ * Copyright (c) 2005, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.graphics.xobject;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSName;
+import org.pdfbox.cos.COSStream;
+
+import org.pdfbox.pdmodel.PDDocument;
+import org.pdfbox.pdmodel.common.COSObjectable;
+import org.pdfbox.pdmodel.common.PDMetadata;
+import org.pdfbox.pdmodel.common.PDStream;
+
+/**
+ * The base class for all XObjects in the PDF document.
+ *
+ * @author Ben Litchfield (ben@benlitchfield.com)
+ * @author mathiak
+ * @author Marcel Kammer
+ * @version $Revision: 1.12 $
+ */
+public abstract class PDXObject implements COSObjectable
+{
+ private PDStream xobject;
+
+ /**
+ * Standard constuctor.
+ *
+ * @param xobj The XObject dictionary.
+ */
+ public PDXObject(COSStream xobj)
+ {
+ xobject = new PDStream( xobj );
+ }
+
+ /**
+ * Standard constuctor.
+ *
+ * @param xobj The XObject dictionary.
+ */
+ public PDXObject(PDStream xobj)
+ {
+ xobject = xobj;
+ }
+
+ /**
+ * Standard constuctor.
+ *
+ * @param doc The doc to store the object contents.
+ */
+ public PDXObject(PDDocument doc)
+ {
+ xobject = new PDStream(doc);
+ xobject.getStream().setName( COSName.TYPE, "XObject" );
+ }
+
+ /**
+ * Returns the stream.
+ * @see org.pdfbox.pdmodel.common.COSObjectable#getCOSObject()
+ */
+ public COSBase getCOSObject()
+ {
+ return xobject.getCOSObject();
+ }
+
+ /**
+ * Returns the stream.
+ * @return The stream for this object.
+ */
+ public COSStream getCOSStream()
+ {
+ return xobject.getStream();
+ }
+
+ /**
+ * Returns the stream.
+ * @return The stream for this object.
+ */
+ public PDStream getPDStream()
+ {
+ return xobject;
+ }
+
+ /**
+ * Create the correct xobject from the cos base.
+ *
+ * @param xobject The cos level xobject to create.
+ *
+ * @return a pdmodel xobject
+ * @throws IOException If there is an error creating the xobject.
+ */
+ public static PDXObject createXObject( COSBase xobject ) throws IOException
+ {
+ PDXObject retval = null;
+ if( xobject == null )
+ {
+ retval = null;
+ }
+ else if( xobject instanceof COSStream )
+ {
+ COSStream xstream = (COSStream)xobject;
+ String subtype = xstream.getNameAsString( "Subtype" );
+ if( subtype.equals( PDXObjectImage.SUB_TYPE ) )
+ {
+ PDStream image = new PDStream( xstream );
+ // See if filters are DCT or JPX otherwise treat as Bitmap-like
+ // There might be a problem with several filters, but that's ToDo until
+ // I find an example
+ List filters = image.getFilters();
+ if( filters != null && filters.contains( COSName.DCT_DECODE.getName() ) )
+ {
+ return new PDJpeg(image);
+ }
+ else if ( filters != null && filters.contains( COSName.CCITTFAX_DECODE.getName() ) )
+ {
+ return new PDCcitt(image);
+ }
+ else if( filters != null && filters.contains(COSName.JPX_DECODE.getName()))
+ {
+ //throw new IOException( "JPXDecode has not been implemented for images" );
+ //JPX Decode is not really supported right now, but if we are just doing
+ //text extraction then we don't want to throw an exception, so for now
+ //just return a PDPixelMap, which will break later on if it is
+ //actually used, but for text extraction it is not used.
+ return new PDPixelMap( image );
+
+ }
+ else
+ {
+ retval = new PDPixelMap(image);
+ }
+ }
+ else if( subtype.equals( PDXObjectForm.SUB_TYPE ) )
+ {
+ retval = new PDXObjectForm( xstream );
+ }
+ else
+ {
+ throw new IOException( "Unknown xobject subtype '" + subtype + "'" );
+ }
+ }
+ else
+ {
+ throw new IOException( "Unknown xobject type:" + xobject.getClass().getName() );
+ }
+
+ return retval;
+ }
+
+ /**
+ * Get the metadata that is part of the document catalog. This will
+ * return null if there is no meta data for this object.
+ *
+ * @return The metadata for this object.
+ */
+ public PDMetadata getMetadata()
+ {
+ PDMetadata retval = null;
+ COSStream mdStream = (COSStream)xobject.getStream().getDictionaryObject( "Metadata" );
+ if( mdStream != null )
+ {
+ retval = new PDMetadata( mdStream );
+ }
+ return retval;
+ }
+
+ /**
+ * Set the metadata for this object. This can be null.
+ *
+ * @param meta The meta data for this object.
+ */
+ public void setMetadata( PDMetadata meta )
+ {
+ xobject.getStream().setItem( "Metadata", meta );
+ }
+}
diff --git a/src/main/java/org/pdfbox/pdmodel/graphics/xobject/PDXObjectForm.java b/src/main/java/org/pdfbox/pdmodel/graphics/xobject/PDXObjectForm.java
new file mode 100644
index 0000000..08858ea
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/graphics/xobject/PDXObjectForm.java
@@ -0,0 +1,120 @@
+/**
+ * Copyright (c) 2005, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.graphics.xobject;
+
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSName;
+import org.pdfbox.cos.COSStream;
+
+import org.pdfbox.pdmodel.PDResources;
+import org.pdfbox.pdmodel.common.PDStream;
+
+/**
+ * A form xobject.
+ *
+ * @author Ben Litchfield (ben@benlitchfield.com)
+ * @version $Revision: 1.4 $
+ */
+public class PDXObjectForm extends PDXObject
+{
+ /**
+ * The XObject subtype.
+ */
+ public static final String SUB_TYPE = "Form";
+
+ /**
+ * Standard constuctor.
+ *
+ * @param formStream The XObject is passed as a COSStream.
+ */
+ public PDXObjectForm(PDStream formStream)
+ {
+ super( formStream );
+ }
+
+ /**
+ * Standard constuctor.
+ *
+ * @param formStream The XObject is passed as a COSStream.
+ */
+ public PDXObjectForm(COSStream formStream)
+ {
+ super( formStream );
+ }
+
+ /**
+ * 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 );
+ }
+
+ /**
+ * Set the form type.
+ *
+ * @param formType The new form type.
+ */
+ public void setFormType( int 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.
+ *
+ * @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 )
+ {
+ 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 )
+ {
+ getCOSStream().setItem( COSName.RESOURCES, resources );
+ }
+}
diff --git a/src/main/java/org/pdfbox/pdmodel/graphics/xobject/PDXObjectImage.java b/src/main/java/org/pdfbox/pdmodel/graphics/xobject/PDXObjectImage.java
new file mode 100644
index 0000000..6257113
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/graphics/xobject/PDXObjectImage.java
@@ -0,0 +1,244 @@
+/**
+ * Copyright (c) 2004-2005, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.graphics.xobject;
+
+import java.awt.image.BufferedImage;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSName;
+import org.pdfbox.pdmodel.PDDocument;
+import org.pdfbox.pdmodel.common.PDStream;
+import org.pdfbox.pdmodel.graphics.color.PDColorSpace;
+import org.pdfbox.pdmodel.graphics.color.PDColorSpaceFactory;
+import org.pdfbox.pdmodel.graphics.color.PDDeviceGray;
+
+/**
+ * The prototype for all PDImages.
+ *
+ * @author Ben Litchfield (ben@benlitchfield.com)
+ * @author mathiak
+ * @version $Revision: 1.8 $
+ */
+public abstract class PDXObjectImage extends PDXObject
+{
+ /**
+ * The XObject subtype.
+ */
+ public static final String SUB_TYPE = "Image";
+
+ /**
+ * This contains the suffix used when writing to file.
+ */
+ private String suffix;
+
+ /**
+ * Standard constuctor.
+ *
+ * @param imageStream The XObject is passed as a COSStream.
+ * @param fileSuffix The file suffix, jpg/png.
+ */
+ public PDXObjectImage(PDStream imageStream, String fileSuffix)
+ {
+ super( imageStream );
+ suffix = fileSuffix;
+ }
+
+ /**
+ * Standard constuctor.
+ *
+ * @param doc The document to store the stream in.
+ * @param fileSuffix The file suffix, jpg/png.
+ */
+ public PDXObjectImage(PDDocument doc, String fileSuffix)
+ {
+ super( doc );
+ getCOSStream().setName( COSName.SUBTYPE, SUB_TYPE );
+ suffix = fileSuffix;
+ }
+
+ /**
+ * Returns an java.awt.Image, that can be used for display etc.
+ *
+ * @return This PDF object as an AWT image.
+ *
+ * @throws IOException If there is an error creating the image.
+ */
+ public abstract BufferedImage getRGBImage() throws IOException;
+
+ /**
+ * Writes the Image to out.
+ * @param out the OutputStream that the Image is written to.
+ * @throws IOException when somethings wrong with out
+ */
+ public abstract void write2OutputStream(OutputStream out) throws IOException;
+
+ /**
+ * Writes the image to a file with the filename + an appropriate suffix, like "Image.jpg".
+ * The suffix is automatically set by the
+ * @param filename the filename
+ * @throws IOException When somethings wrong with the corresponding file.
+ */
+ public void write2file(String filename) throws IOException
+ {
+ FileOutputStream out = null;
+ try
+ {
+ out = new FileOutputStream(filename + "." + suffix);
+ write2OutputStream(out);
+ out.flush();
+ }
+ finally
+ {
+ if( out != null )
+ {
+ out.close();
+ }
+ }
+ }
+
+ /**
+ * Get the height of the image.
+ *
+ * @return The height of the image.
+ */
+ public int getHeight()
+ {
+ return getCOSStream().getInt( "Height", -1 );
+ }
+
+ /**
+ * Set the height of the image.
+ *
+ * @param height The height of the image.
+ */
+ public void setHeight( int height )
+ {
+ getCOSStream().setInt( "Height", height );
+ }
+
+ /**
+ * Get the width of the image.
+ *
+ * @return The width of the image.
+ */
+ public int getWidth()
+ {
+ return getCOSStream().getInt( "Width", -1 );
+ }
+
+ /**
+ * Set the width of the image.
+ *
+ * @param width The width of the image.
+ */
+ public void setWidth( int width )
+ {
+ getCOSStream().setInt( "Width", width );
+ }
+
+ /**
+ * The bits per component of this image. This will return -1 if one has not
+ * been set.
+ *
+ * @return The number of bits per component.
+ */
+ public int getBitsPerComponent()
+ {
+ return getCOSStream().getInt( new String[] { "BPC", "BitsPerComponent"}, -1 );
+ }
+
+ /**
+ * Set the number of bits per component.
+ *
+ * @param bpc The number of bits per component.
+ */
+ public void setBitsPerComponent( int bpc )
+ {
+ getCOSStream().setInt( "BitsPerComponent", bpc );
+ }
+
+ /**
+ * This will get the color space or null if none exists.
+ *
+ * @return The color space for this image.
+ *
+ * @throws IOException If there is an error getting the colorspace.
+ */
+ public PDColorSpace getColorSpace() throws IOException
+ {
+ COSBase cs = getCOSStream().getDictionaryObject( new String[]{ "CS", "ColorSpace" } );
+ PDColorSpace retval = null;
+ if( cs != null )
+ {
+ retval = PDColorSpaceFactory.createColorSpace( cs );
+ }
+ else
+ {
+ //there are some cases where the 'required' CS value is not present
+ //but we know that it will be grayscale for a CCITT filter.
+ COSBase filter = getCOSStream().getDictionaryObject( "Filter" );
+ if( COSName.CCITTFAX_DECODE.equals( filter ) ||
+ COSName.CCITTFAX_DECODE_ABBREVIATION.equals( filter ) )
+ {
+ retval = new PDDeviceGray();
+ }
+ }
+ return retval;
+ }
+
+ /**
+ * This will set the color space for this image.
+ *
+ * @param cs The color space for this image.
+ */
+ public void setColorSpace( PDColorSpace cs )
+ {
+ COSBase base = null;
+ if( cs != null )
+ {
+ base = cs.getCOSObject();
+ }
+ getCOSStream().setItem( COSName.getPDFName( "ColorSpace" ), base );
+ }
+
+ /**
+ * This will get the suffix for this image type, jpg/png.
+ *
+ * @return The image suffix.
+ */
+ public String getSuffix()
+ {
+ return suffix;
+ }
+}
diff --git a/src/main/java/org/pdfbox/pdmodel/graphics/xobject/package.html b/src/main/java/org/pdfbox/pdmodel/graphics/xobject/package.html
new file mode 100644
index 0000000..60d3324
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/graphics/xobject/package.html
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+
+</head>
+<body>
+This package deals with images that are stored in a PDF document.
+</body>
+</html>
diff --git a/src/main/java/org/pdfbox/pdmodel/interactive/action/PDActionFactory.java b/src/main/java/org/pdfbox/pdmodel/interactive/action/PDActionFactory.java
new file mode 100644
index 0000000..bf0c156
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/interactive/action/PDActionFactory.java
@@ -0,0 +1,96 @@
+/**
+ * Copyright (c) 2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.interactive.action;
+
+import org.pdfbox.cos.COSDictionary;
+
+import org.pdfbox.pdmodel.interactive.action.type.PDAction;
+import org.pdfbox.pdmodel.interactive.action.type.PDActionGoTo;
+import org.pdfbox.pdmodel.interactive.action.type.PDActionJavaScript;
+import org.pdfbox.pdmodel.interactive.action.type.PDActionLaunch;
+import org.pdfbox.pdmodel.interactive.action.type.PDActionRemoteGoTo;
+import org.pdfbox.pdmodel.interactive.action.type.PDActionURI;
+
+/**
+ * This class will take a dictionary and determine which type of action to create.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.4 $
+ */
+public class PDActionFactory
+{
+ /**
+ * Utility Class.
+ */
+ private PDActionFactory()
+ {
+ //utility class
+ }
+
+ /**
+ * This will create the correct type of action based on the type specified
+ * in the dictionary.
+ *
+ * @param action An action dictionary.
+ *
+ * @return An action of the correct type.
+ */
+ public static PDAction createAction( COSDictionary action )
+ {
+ PDAction retval = null;
+ if( action != null )
+ {
+ String type = action.getNameAsString( "S" );
+ if( PDActionJavaScript.SUB_TYPE.equals( type ) )
+ {
+ retval = new PDActionJavaScript( action );
+ }
+ else if( PDActionGoTo.SUB_TYPE.equals( type ) )
+ {
+ retval = new PDActionGoTo( action );
+ }
+ else if( PDActionLaunch.SUB_TYPE.equals( type ) )
+ {
+ retval = new PDActionLaunch( action );
+ }
+ else if( PDActionRemoteGoTo.SUB_TYPE.equals( type ) )
+ {
+ retval = new PDActionRemoteGoTo( action );
+ }
+ else if( PDActionURI.SUB_TYPE.equals( type ) )
+ {
+ retval = new PDActionURI( action );
+ }
+ }
+ return retval;
+ }
+
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/interactive/action/PDAdditionalActions.java b/src/main/java/org/pdfbox/pdmodel/interactive/action/PDAdditionalActions.java
new file mode 100644
index 0000000..fc2f79b
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/interactive/action/PDAdditionalActions.java
@@ -0,0 +1,106 @@
+/**
+ * Copyright (c) 2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.interactive.action;
+
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSDictionary;
+
+import org.pdfbox.pdmodel.common.COSObjectable;
+import org.pdfbox.pdmodel.interactive.action.type.PDAction;
+
+/**
+ * This represents a dictionary of actions that occur due to events.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.3 $
+ */
+public class PDAdditionalActions implements COSObjectable
+{
+ private COSDictionary actions;
+
+ /**
+ * Default constructor.
+ */
+ public PDAdditionalActions()
+ {
+ actions = new COSDictionary();
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param a The action dictionary.
+ */
+ public PDAdditionalActions( COSDictionary a )
+ {
+ actions = a;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSBase getCOSObject()
+ {
+ return actions;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSDictionary getCOSDictionary()
+ {
+ return actions;
+ }
+
+ /**
+ * Get the F action.
+ *
+ * @return The F action.
+ */
+ public PDAction getF()
+ {
+ return PDActionFactory.createAction( (COSDictionary)actions.getDictionaryObject("F" ) );
+ }
+
+ /**
+ * Set the F action.
+ *
+ * @param action Get the F action.
+ */
+ public void setF( PDAction action )
+ {
+ actions.setItem( "F", action );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/interactive/action/PDAnnotationAdditionalActions.java b/src/main/java/org/pdfbox/pdmodel/interactive/action/PDAnnotationAdditionalActions.java
new file mode 100644
index 0000000..9b9232e
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/interactive/action/PDAnnotationAdditionalActions.java
@@ -0,0 +1,380 @@
+/**
+ * Copyright (c) 2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.interactive.action;
+
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSDictionary;
+
+import org.pdfbox.pdmodel.common.COSObjectable;
+import org.pdfbox.pdmodel.interactive.action.type.PDAction;
+
+/**
+ * This class represents an annotation's dictionary of actions
+ * that occur due to events.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @author Panagiotis Toumasis (ptoumasis@mail.gr)
+ * @version $Revision: 1.1 $
+ */
+public class PDAnnotationAdditionalActions implements COSObjectable
+{
+ private COSDictionary actions;
+
+ /**
+ * Default constructor.
+ */
+ public PDAnnotationAdditionalActions()
+ {
+ actions = new COSDictionary();
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param a The action dictionary.
+ */
+ public PDAnnotationAdditionalActions( COSDictionary a )
+ {
+ actions = a;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSBase getCOSObject()
+ {
+ return actions;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSDictionary getCOSDictionary()
+ {
+ return actions;
+ }
+
+ /**
+ * This will get an action to be performed when the cursor
+ * enters the annotation's active area.
+ *
+ * @return The E entry of annotation's additional actions dictionary.
+ */
+ public PDAction getE()
+ {
+ COSDictionary e = (COSDictionary)actions.getDictionaryObject( "E" );
+ PDAction retval = null;
+ if( e != null )
+ {
+ retval = PDActionFactory.createAction( e );
+ }
+ return retval;
+ }
+
+ /**
+ * This will set an action to be performed when the cursor
+ * enters the annotation's active area.
+ *
+ * @param e The action to be performed.
+ */
+ public void setE( PDAction e )
+ {
+ actions.setItem( "E", e );
+ }
+
+ /**
+ * This will get an action to be performed when the cursor
+ * exits the annotation's active area.
+ *
+ * @return The X entry of annotation's additional actions dictionary.
+ */
+ public PDAction getX()
+ {
+ COSDictionary x = (COSDictionary)actions.getDictionaryObject( "X" );
+ PDAction retval = null;
+ if( x != null )
+ {
+ retval = PDActionFactory.createAction( x );
+ }
+ return retval;
+ }
+
+ /**
+ * This will set an action to be performed when the cursor
+ * exits the annotation's active area.
+ *
+ * @param x The action to be performed.
+ */
+ public void setX( PDAction x )
+ {
+ actions.setItem( "X", x );
+ }
+
+ /**
+ * This will get an action to be performed when the mouse button
+ * is pressed inside the annotation's active area.
+ * The name D stands for "down".
+ *
+ * @return The d entry of annotation's additional actions dictionary.
+ */
+ public PDAction getD()
+ {
+ COSDictionary d = (COSDictionary)actions.getDictionaryObject( "D" );
+ PDAction retval = null;
+ if( d != null )
+ {
+ retval = PDActionFactory.createAction( d );
+ }
+ return retval;
+ }
+
+ /**
+ * This will set an action to be performed when the mouse button
+ * is pressed inside the annotation's active area.
+ * The name D stands for "down".
+ *
+ * @param d The action to be performed.
+ */
+ public void setD( PDAction d )
+ {
+ actions.setItem( "D", d );
+ }
+
+ /**
+ * This will get an action to be performed when the mouse button
+ * is released inside the annotation's active area.
+ * The name U stands for "up".
+ *
+ * @return The U entry of annotation's additional actions dictionary.
+ */
+ public PDAction getU()
+ {
+ COSDictionary u = (COSDictionary)actions.getDictionaryObject( "U" );
+ PDAction retval = null;
+ if( u != null )
+ {
+ retval = PDActionFactory.createAction( u );
+ }
+ return retval;
+ }
+
+ /**
+ * This will set an action to be performed when the mouse button
+ * is released inside the annotation's active area.
+ * The name U stands for "up".
+ *
+ * @param u The action to be performed.
+ */
+ public void setU( PDAction u )
+ {
+ actions.setItem( "U", u );
+ }
+
+ /**
+ * This will get an action to be performed when the annotation
+ * receives the input focus.
+ *
+ * @return The Fo entry of annotation's additional actions dictionary.
+ */
+ public PDAction getFo()
+ {
+ COSDictionary fo = (COSDictionary)actions.getDictionaryObject( "Fo" );
+ PDAction retval = null;
+ if( fo != null )
+ {
+ retval = PDActionFactory.createAction( fo );
+ }
+ return retval;
+ }
+
+ /**
+ * This will set an action to be performed when the annotation
+ * receives the input focus.
+ *
+ * @param fo The action to be performed.
+ */
+ public void setFo( PDAction fo )
+ {
+ actions.setItem( "Fo", fo );
+ }
+
+ /**
+ * This will get an action to be performed when the annotation
+ * loses the input focus.
+ * The name Bl stands for "blurred".
+ *
+ * @return The Bl entry of annotation's additional actions dictionary.
+ */
+ public PDAction getBl()
+ {
+ COSDictionary bl = (COSDictionary)actions.getDictionaryObject( "Bl" );
+ PDAction retval = null;
+ if( bl != null )
+ {
+ retval = PDActionFactory.createAction( bl );
+ }
+ return retval;
+ }
+
+ /**
+ * This will set an action to be performed when the annotation
+ * loses the input focus.
+ * The name Bl stands for "blurred".
+ *
+ * @param bl The action to be performed.
+ */
+ public void setBl( PDAction bl )
+ {
+ actions.setItem( "Bl", bl );
+ }
+
+ /**
+ * This will get an action to be performed when the page containing
+ * the annotation is opened. The action is executed after the O action
+ * in the page's additional actions dictionary and the OpenAction entry
+ * in the document catalog, if such actions are present.
+ *
+ * @return The PO entry of annotation's additional actions dictionary.
+ */
+ public PDAction getPO()
+ {
+ COSDictionary po = (COSDictionary)actions.getDictionaryObject( "PO" );
+ PDAction retval = null;
+ if( po != null )
+ {
+ retval = PDActionFactory.createAction( po );
+ }
+ return retval;
+ }
+
+ /**
+ * This will set an action to be performed when the page containing
+ * the annotation is opened. The action is executed after the O action
+ * in the page's additional actions dictionary and the OpenAction entry
+ * in the document catalog, if such actions are present.
+ *
+ * @param po The action to be performed.
+ */
+ public void setPO( PDAction po )
+ {
+ actions.setItem( "PO", po );
+ }
+
+ /**
+ * This will get an action to be performed when the page containing
+ * the annotation is closed. The action is executed before the C action
+ * in the page's additional actions dictionary, if present.
+ *
+ * @return The PC entry of annotation's additional actions dictionary.
+ */
+ public PDAction getPC()
+ {
+ COSDictionary pc = (COSDictionary)actions.getDictionaryObject( "PC" );
+ PDAction retval = null;
+ if( pc != null )
+ {
+ retval = PDActionFactory.createAction( pc );
+ }
+ return retval;
+ }
+
+ /**
+ * This will set an action to be performed when the page containing
+ * the annotation is closed. The action is executed before the C action
+ * in the page's additional actions dictionary, if present.
+ *
+ * @param pc The action to be performed.
+ */
+ public void setPC( PDAction pc )
+ {
+ actions.setItem( "PC", pc );
+ }
+
+ /**
+ * This will get an action to be performed when the page containing
+ * the annotation becomes visible in the viewer application's user interface.
+ *
+ * @return The PV entry of annotation's additional actions dictionary.
+ */
+ public PDAction getPV()
+ {
+ COSDictionary pv = (COSDictionary)actions.getDictionaryObject( "PV" );
+ PDAction retval = null;
+ if( pv != null )
+ {
+ retval = PDActionFactory.createAction( pv );
+ }
+ return retval;
+ }
+
+ /**
+ * This will set an action to be performed when the page containing
+ * the annotation becomes visible in the viewer application's user interface.
+ *
+ * @param pv The action to be performed.
+ */
+ public void setPV( PDAction pv )
+ {
+ actions.setItem( "PV", pv );
+ }
+
+ /**
+ * This will get an action to be performed when the page containing the annotation
+ * is no longer visible in the viewer application's user interface.
+ *
+ * @return The PI entry of annotation's additional actions dictionary.
+ */
+ public PDAction getPI()
+ {
+ COSDictionary pi = (COSDictionary)actions.getDictionaryObject( "PI" );
+ PDAction retval = null;
+ if( pi != null )
+ {
+ retval = PDActionFactory.createAction( pi );
+ }
+ return retval;
+ }
+
+ /**
+ * This will set an action to be performed when the page containing the annotation
+ * is no longer visible in the viewer application's user interface.
+ *
+ * @param pi The action to be performed.
+ */
+ public void setPI( PDAction pi )
+ {
+ actions.setItem( "PI", pi );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/interactive/action/PDDocumentCatalogAdditionalActions.java b/src/main/java/org/pdfbox/pdmodel/interactive/action/PDDocumentCatalogAdditionalActions.java
new file mode 100644
index 0000000..6164de1
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/interactive/action/PDDocumentCatalogAdditionalActions.java
@@ -0,0 +1,238 @@
+/**
+ * Copyright (c) 2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.interactive.action;
+
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSDictionary;
+
+import org.pdfbox.pdmodel.common.COSObjectable;
+import org.pdfbox.pdmodel.interactive.action.type.PDAction;
+
+/**
+ * This class represents a document catalog's dictionary of actions
+ * that occur due to events.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @author Panagiotis Toumasis (ptoumasis@mail.gr)
+ * @version $Revision: 1.1 $
+ */
+public class PDDocumentCatalogAdditionalActions implements COSObjectable
+{
+ private COSDictionary actions;
+
+ /**
+ * Default constructor.
+ */
+ public PDDocumentCatalogAdditionalActions()
+ {
+ actions = new COSDictionary();
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param a The action dictionary.
+ */
+ public PDDocumentCatalogAdditionalActions( COSDictionary a )
+ {
+ actions = a;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSBase getCOSObject()
+ {
+ return actions;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSDictionary getCOSDictionary()
+ {
+ return actions;
+ }
+
+ /**
+ * This will get a JavaScript action to be performed
+ * before closing a document.
+ * The name WC stands for "will close".
+ *
+ * @return The WC entry of document catalog's additional actions dictionary.
+ */
+ public PDAction getWC()
+ {
+ COSDictionary wc = (COSDictionary)actions.getDictionaryObject( "WC" );
+ PDAction retval = null;
+ if( wc != null )
+ {
+ retval = PDActionFactory.createAction( wc );
+ }
+ return retval;
+ }
+
+ /**
+ * This will set a JavaScript action to be performed
+ * before closing a document.
+ * The name WC stands for "will close".
+ *
+ * @param wc The action to be performed.
+ */
+ public void setWC( PDAction wc )
+ {
+ actions.setItem( "WC", wc );
+ }
+
+ /**
+ * This will get a JavaScript action to be performed
+ * before saving a document.
+ * The name WS stands for "will save".
+ *
+ * @return The WS entry of document catalog's additional actions dictionary.
+ */
+ public PDAction getWS()
+ {
+ COSDictionary ws = (COSDictionary)actions.getDictionaryObject( "WS" );
+ PDAction retval = null;
+ if( ws != null )
+ {
+ retval = PDActionFactory.createAction( ws );
+ }
+ return retval;
+ }
+
+ /**
+ * This will set a JavaScript action to be performed
+ * before saving a document.
+ * The name WS stands for "will save".
+ *
+ * @param ws The action to be performed.
+ */
+ public void setWS( PDAction ws )
+ {
+ actions.setItem( "WS", ws );
+ }
+
+ /**
+ * This will get a JavaScript action to be performed
+ * after saving a document.
+ * The name DS stands for "did save".
+ *
+ * @return The DS entry of document catalog's additional actions dictionary.
+ */
+ public PDAction getDS()
+ {
+ COSDictionary ds = (COSDictionary)actions.getDictionaryObject( "DS" );
+ PDAction retval = null;
+ if( ds != null )
+ {
+ retval = PDActionFactory.createAction( ds );
+ }
+ return retval;
+ }
+
+ /**
+ * This will set a JavaScript action to be performed
+ * after saving a document.
+ * The name DS stands for "did save".
+ *
+ * @param ds The action to be performed.
+ */
+ public void setDS( PDAction ds )
+ {
+ actions.setItem( "DS", ds );
+ }
+
+ /**
+ * This will get a JavaScript action to be performed
+ * before printing a document.
+ * The name WP stands for "will print".
+ *
+ * @return The WP entry of document catalog's additional actions dictionary.
+ */
+ public PDAction getWP()
+ {
+ COSDictionary wp = (COSDictionary)actions.getDictionaryObject( "WP" );
+ PDAction retval = null;
+ if( wp != null )
+ {
+ retval = PDActionFactory.createAction( wp );
+ }
+ return retval;
+ }
+
+ /**
+ * This will set a JavaScript action to be performed
+ * before printing a document.
+ * The name WP stands for "will print".
+ *
+ * @param wp The action to be performed.
+ */
+ public void setWP( PDAction wp )
+ {
+ actions.setItem( "WP", wp );
+ }
+
+ /**
+ * This will get a JavaScript action to be performed
+ * after printing a document.
+ * The name DP stands for "did print".
+ *
+ * @return The DP entry of document catalog's additional actions dictionary.
+ */
+ public PDAction getDP()
+ {
+ COSDictionary dp = (COSDictionary)actions.getDictionaryObject( "DP" );
+ PDAction retval = null;
+ if( dp != null )
+ {
+ retval = PDActionFactory.createAction( dp );
+ }
+ return retval;
+ }
+
+ /**
+ * This will set a JavaScript action to be performed
+ * after printing a document.
+ * The name DP stands for "did print".
+ *
+ * @param dp The action to be performed.
+ */
+ public void setDP( PDAction dp )
+ {
+ actions.setItem( "DP", dp );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/interactive/action/PDFormFieldAdditionalActions.java b/src/main/java/org/pdfbox/pdmodel/interactive/action/PDFormFieldAdditionalActions.java
new file mode 100644
index 0000000..2a594f3
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/interactive/action/PDFormFieldAdditionalActions.java
@@ -0,0 +1,216 @@
+/**
+ * Copyright (c) 2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.interactive.action;
+
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSDictionary;
+
+import org.pdfbox.pdmodel.common.COSObjectable;
+import org.pdfbox.pdmodel.interactive.action.type.PDAction;
+
+/**
+ * This class represents a form field's dictionary of actions
+ * that occur due to events.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @author Panagiotis Toumasis (ptoumasis@mail.gr)
+ * @version $Revision: 1.1 $
+ */
+public class PDFormFieldAdditionalActions implements COSObjectable
+{
+ private COSDictionary actions;
+
+ /**
+ * Default constructor.
+ */
+ public PDFormFieldAdditionalActions()
+ {
+ actions = new COSDictionary();
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param a The action dictionary.
+ */
+ public PDFormFieldAdditionalActions( COSDictionary a )
+ {
+ actions = a;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSBase getCOSObject()
+ {
+ return actions;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSDictionary getCOSDictionary()
+ {
+ return actions;
+ }
+
+ /**
+ * This will get a JavaScript action to be performed when the user
+ * types a keystroke into a text field or combo box or modifies the
+ * selection in a scrollable list box. This allows the keystroke to
+ * be checked for validity and rejected or modified.
+ *
+ * @return The K entry of form field's additional actions dictionary.
+ */
+ public PDAction getK()
+ {
+ COSDictionary k = (COSDictionary)actions.getDictionaryObject( "K" );
+ PDAction retval = null;
+ if( k != null )
+ {
+ retval = PDActionFactory.createAction( k );
+ }
+ return retval;
+ }
+
+ /**
+ * This will set a JavaScript action to be performed when the user
+ * types a keystroke into a text field or combo box or modifies the
+ * selection in a scrollable list box. This allows the keystroke to
+ * be checked for validity and rejected or modified.
+ *
+ * @param k The action to be performed.
+ */
+ public void setK( PDAction k )
+ {
+ actions.setItem( "K", k );
+ }
+
+ /**
+ * This will get a JavaScript action to be performed before
+ * the field is formatted to display its current value. This
+ * allows the field's value to be modified before formatting.
+ *
+ * @return The F entry of form field's additional actions dictionary.
+ */
+ public PDAction getF()
+ {
+ COSDictionary f = (COSDictionary)actions.getDictionaryObject( "F" );
+ PDAction retval = null;
+ if( f != null )
+ {
+ retval = PDActionFactory.createAction( f );
+ }
+ return retval;
+ }
+
+ /**
+ * This will set a JavaScript action to be performed before
+ * the field is formatted to display its current value. This
+ * allows the field's value to be modified before formatting.
+ *
+ * @param f The action to be performed.
+ */
+ public void setF( PDAction f )
+ {
+ actions.setItem( "F", f );
+ }
+
+ /**
+ * This will get a JavaScript action to be performed
+ * when the field's value is changed. This allows the
+ * new value to be checked for validity.
+ * The name V stands for "validate".
+ *
+ * @return The V entry of form field's additional actions dictionary.
+ */
+ public PDAction getV()
+ {
+ COSDictionary v = (COSDictionary)actions.getDictionaryObject( "V" );
+ PDAction retval = null;
+ if( v != null )
+ {
+ retval = PDActionFactory.createAction( v );
+ }
+ return retval;
+ }
+
+ /**
+ * This will set a JavaScript action to be performed
+ * when the field's value is changed. This allows the
+ * new value to be checked for validity.
+ * The name V stands for "validate".
+ *
+ * @param v The action to be performed.
+ */
+ public void setV( PDAction v )
+ {
+ actions.setItem( "V", v );
+ }
+
+ /**
+ * This will get a JavaScript action to be performed in order to recalculate
+ * the value of this field when that of another field changes. The order in which
+ * the document's fields are recalculated is defined by the CO entry in the
+ * interactive form dictionary.
+ * The name C stands for "calculate".
+ *
+ * @return The C entry of form field's additional actions dictionary.
+ */
+ public PDAction getC()
+ {
+ COSDictionary c = (COSDictionary)actions.getDictionaryObject( "C" );
+ PDAction retval = null;
+ if( c != null )
+ {
+ retval = PDActionFactory.createAction( c );
+ }
+ return retval;
+ }
+
+ /**
+ * This will set a JavaScript action to be performed in order to recalculate
+ * the value of this field when that of another field changes. The order in which
+ * the document's fields are recalculated is defined by the CO entry in the
+ * interactive form dictionary.
+ * The name C stands for "calculate".
+ *
+ * @param c The action to be performed.
+ */
+ public void setC( PDAction c )
+ {
+ actions.setItem( "C", c );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/interactive/action/PDPageAdditionalActions.java b/src/main/java/org/pdfbox/pdmodel/interactive/action/PDPageAdditionalActions.java
new file mode 100644
index 0000000..f15ffa7
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/interactive/action/PDPageAdditionalActions.java
@@ -0,0 +1,150 @@
+/**
+ * Copyright (c) 2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.interactive.action;
+
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSDictionary;
+
+import org.pdfbox.pdmodel.common.COSObjectable;
+import org.pdfbox.pdmodel.interactive.action.type.PDAction;
+
+/**
+ * This class represents a page object's dictionary of actions
+ * that occur due to events.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @author Panagiotis Toumasis (ptoumasis@mail.gr)
+ * @version $Revision: 1.1 $
+ */
+public class PDPageAdditionalActions implements COSObjectable
+{
+ private COSDictionary actions;
+
+ /**
+ * Default constructor.
+ */
+ public PDPageAdditionalActions()
+ {
+ actions = new COSDictionary();
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param a The action dictionary.
+ */
+ public PDPageAdditionalActions( COSDictionary a )
+ {
+ actions = a;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSBase getCOSObject()
+ {
+ return actions;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSDictionary getCOSDictionary()
+ {
+ return actions;
+ }
+
+ /**
+ * This will get an action to be performed when the page
+ * is opened. This action is independent of any that may be
+ * defined by the OpenAction entry in the document catalog,
+ * and is executed after such an action.
+ *
+ * @return The O entry of page object's additional actions dictionary.
+ */
+ public PDAction getO()
+ {
+ COSDictionary o = (COSDictionary)actions.getDictionaryObject( "O" );
+ PDAction retval = null;
+ if( o != null )
+ {
+ retval = PDActionFactory.createAction( o );
+ }
+ return retval;
+ }
+
+ /**
+ * This will set an action to be performed when the page
+ * is opened. This action is independent of any that may be
+ * defined by the OpenAction entry in the document catalog,
+ * and is executed after such an action.
+ *
+ * @param o The action to be performed.
+ */
+ public void setO( PDAction o )
+ {
+ actions.setItem( "O", o );
+ }
+
+ /**
+ * This will get an action to be performed when the page
+ * is closed. This action applies to the page being closed,
+ * and is executed before any other page opened.
+ *
+ * @return The C entry of page object's additional actions dictionary.
+ */
+ public PDAction getC()
+ {
+ COSDictionary c = (COSDictionary)actions.getDictionaryObject( "C" );
+ PDAction retval = null;
+ if( c != null )
+ {
+ retval = PDActionFactory.createAction( c );
+ }
+ return retval;
+ }
+
+ /**
+ * This will set an action to be performed when the page
+ * is closed. This action applies to the page being closed,
+ * and is executed before any other page opened.
+ *
+ * @param c The action to be performed.
+ */
+ public void setC( PDAction c )
+ {
+ actions.setItem( "C", c );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/interactive/action/package.html b/src/main/java/org/pdfbox/pdmodel/interactive/action/package.html
new file mode 100644
index 0000000..63cbfc0
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/interactive/action/package.html
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+
+</head>
+<body>
+This package represents actions that can be performed in a PDF document.
+</body>
+</html>
diff --git a/src/main/java/org/pdfbox/pdmodel/interactive/action/type/PDAction.java b/src/main/java/org/pdfbox/pdmodel/interactive/action/type/PDAction.java
new file mode 100644
index 0000000..21d40fc
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/interactive/action/type/PDAction.java
@@ -0,0 +1,187 @@
+/**
+ * Copyright (c) 2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.interactive.action.type;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.pdfbox.cos.COSArray;
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSDictionary;
+
+import org.pdfbox.pdmodel.common.COSObjectable;
+import org.pdfbox.pdmodel.common.COSArrayList;
+import org.pdfbox.pdmodel.interactive.action.PDActionFactory;
+
+/**
+ * This represents an action that can be executed in a PDF document.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @author Panagiotis Toumasis (ptoumasis@mail.gr)
+ * @version $Revision: 1.1 $
+ */
+public abstract class PDAction implements COSObjectable
+{
+ /**
+ * The type of PDF object.
+ */
+ public static final String TYPE = "Action";
+
+ /**
+ * The action dictionary.
+ */
+ protected COSDictionary action;
+
+ /**
+ * Default constructor.
+ */
+ public PDAction()
+ {
+ action = new COSDictionary();
+ setType( TYPE );
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param a The action dictionary.
+ */
+ public PDAction( COSDictionary a )
+ {
+ action = a;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSBase getCOSObject()
+ {
+ return action;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSDictionary getCOSDictionary()
+ {
+ return action;
+ }
+
+ /**
+ * This will get the type of PDF object that the actions dictionary describes.
+ * If present must be Action for an action dictionary.
+ *
+ * @return The Type of PDF object.
+ */
+ public String getType()
+ {
+ return action.getNameAsString( "Type" );
+ }
+
+ /**
+ * This will set the type of PDF object that the actions dictionary describes.
+ * If present must be Action for an action dictionary.
+ *
+ * @param type The new Type for the PDF object.
+ */
+ public void setType( String type )
+ {
+ action.setName( "Type", type );
+ }
+
+ /**
+ * This will get the type of action that the actions dictionary describes.
+ * If present, must be Action for an action dictionary.
+ *
+ * @return The S entry of actions dictionary.
+ */
+ public String getSubType()
+ {
+ return action.getNameAsString( "S" );
+ }
+
+ /**
+ * This will set the type of action that the actions dictionary describes.
+ * If present, must be Action for an action dictionary.
+ *
+ * @param s The new type of action.
+ */
+ public void setSubType( String s )
+ {
+ action.setName( "S", s );
+ }
+
+ /**
+ * This will get the next action, or sequence of actions, to be performed after this one.
+ * The value is either a single action dictionary or an array of action dictionaries
+ * to be performed in order.
+ *
+ * @return The Next action or sequence of actions.
+ */
+ public List getNext()
+ {
+ List retval = null;
+ COSBase next = action.getDictionaryObject( "Next" );
+ if( next instanceof COSDictionary )
+ {
+ PDAction pdAction = PDActionFactory.createAction( (COSDictionary) next );
+ retval = new COSArrayList(pdAction, next, action, "Next" );
+ }
+ else if( next instanceof COSArray )
+ {
+ COSArray array = (COSArray)next;
+ List actions = new ArrayList();
+ for( int i=0; i<array.size(); i++ )
+ {
+ actions.add( PDActionFactory.createAction( (COSDictionary) array.getObject( i )));
+ }
+ retval = new COSArrayList( actions, array );
+ }
+
+ return retval;
+ }
+
+ /**
+ * This will set the next action, or sequence of actions, to be performed after this one.
+ * The value is either a single action dictionary or an array of action dictionaries
+ * to be performed in order.
+ *
+ * @param next The Next action or sequence of actions.
+ */
+ public void setNext( List next )
+ {
+ action.setItem( "Next", COSArrayList.converterToCOSArray( next ) );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/interactive/action/type/PDActionGoTo.java b/src/main/java/org/pdfbox/pdmodel/interactive/action/type/PDActionGoTo.java
new file mode 100644
index 0000000..abf0ab5
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/interactive/action/type/PDActionGoTo.java
@@ -0,0 +1,92 @@
+/**
+ * Copyright (c) 2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.interactive.action.type;
+
+import java.io.IOException;
+
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.pdmodel.interactive.documentnavigation.destination.PDDestination;
+
+/**
+ * This represents a go-to action that can be executed in a PDF document.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @author Panagiotis Toumasis (ptoumasis@mail.gr)
+ * @version $Revision: 1.1 $
+ */
+public class PDActionGoTo extends PDAction
+{
+ /**
+ * This type of action this object represents.
+ */
+ public static final String SUB_TYPE = "GoTo";
+
+ /**
+ * Default constructor.
+ */
+ public PDActionGoTo()
+ {
+ super();
+ setSubType( SUB_TYPE );
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param a The action dictionary.
+ */
+ public PDActionGoTo( COSDictionary a )
+ {
+ super( a );
+ }
+
+ /**
+ * This will get the destination to jump to.
+ *
+ * @return The D entry of the specific go-to action dictionary.
+ *
+ * @throws IOException If there is an error creating the destination.
+ */
+ public PDDestination getDestination() throws IOException
+ {
+ return PDDestination.create( getCOSDictionary().getDictionaryObject( "D" ) );
+ }
+
+ /**
+ * This will set the destination to jump to.
+ *
+ * @param d The destination.
+ */
+ public void setDestination( PDDestination d )
+ {
+ getCOSDictionary().setItem( "D", d );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/interactive/action/type/PDActionJavaScript.java b/src/main/java/org/pdfbox/pdmodel/interactive/action/type/PDActionJavaScript.java
new file mode 100644
index 0000000..3148dd3
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/interactive/action/type/PDActionJavaScript.java
@@ -0,0 +1,102 @@
+/**
+ * Copyright (c) 2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.interactive.action.type;
+
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.pdmodel.common.PDTextStream;
+
+/**
+ * This represents a JavaScript action.
+ *
+ * @author Michael Schwarzenberger (mi2kee@gmail.com)
+ * @version $Revision: 1.1 $
+ */
+public class PDActionJavaScript extends PDAction
+{
+ /**
+ * This type of action this object represents.
+ */
+ public static final String SUB_TYPE = "JavaScript";
+
+ /**
+ * Constructor #1.
+ */
+ public PDActionJavaScript()
+ {
+ super();
+ setSubType( SUB_TYPE );
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param js Some javascript code.
+ */
+ public PDActionJavaScript( String js )
+ {
+ this();
+ setAction( js );
+ }
+
+ /**
+ * Constructor #2.
+ *
+ * @param a The action dictionary.
+ */
+ public PDActionJavaScript(COSDictionary a)
+ {
+ super(a);
+ }
+
+ /**
+ * @param sAction The JavaScript.
+ */
+ public void setAction(PDTextStream sAction)
+ {
+ action.setItem("JS", sAction);
+ }
+
+ /**
+ * @param sAction The JavaScript.
+ */
+ public void setAction(String sAction)
+ {
+ action.setString("JS", sAction);
+ }
+
+ /**
+ * @return The Javascript Code.
+ */
+ public PDTextStream getAction()
+ {
+ return PDTextStream.createTextStream( action.getDictionaryObject("JS") );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/interactive/action/type/PDActionLaunch.java b/src/main/java/org/pdfbox/pdmodel/interactive/action/type/PDActionLaunch.java
new file mode 100644
index 0000000..3c2ef74
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/interactive/action/type/PDActionLaunch.java
@@ -0,0 +1,244 @@
+/**
+ * Copyright (c) 2004-2005, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.interactive.action.type;
+
+import org.pdfbox.cos.COSDictionary;
+
+import org.pdfbox.pdmodel.common.filespecification.PDFileSpecification;
+
+/**
+ * This represents a launch action that can be executed in a PDF document.
+ *
+ * @author Ben Litchfield (ben@benlitchfield.com)
+ * @author Panagiotis Toumasis (ptoumasis@mail.gr)
+ * @version $Revision: 1.3 $
+ */
+public class PDActionLaunch extends PDAction
+{
+
+ /**
+ * This type of action this object represents.
+ */
+ public static final String SUB_TYPE = "Launch";
+
+ /**
+ * Default constructor.
+ */
+ public PDActionLaunch()
+ {
+ super();
+ setSubType( SUB_TYPE );
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param a The action dictionary.
+ */
+ public PDActionLaunch( COSDictionary a )
+ {
+ super( a );
+ }
+
+ /**
+ * This will get the application to be launched or the document
+ * to be opened or printed. It is required if none of the entries
+ * Win, Mac or Unix is present. If this entry is absent and the
+ * viewer application does not understand any of the alternative
+ * entries it should do nothing.
+ *
+ * @return The F entry of the specific launch action dictionary.
+ */
+ public PDFileSpecification getFile()
+ {
+ return PDFileSpecification.createFS( getCOSDictionary().getDictionaryObject( "F" ) );
+ }
+
+ /**
+ * This will set the application to be launched or the document
+ * to be opened or printed. It is required if none of the entries
+ * Win, Mac or Unix is present. If this entry is absent and the
+ * viewer application does not understand any of the alternative
+ * entries it should do nothing.
+ *
+ * @param fs The file specification.
+ */
+ public void setFile( PDFileSpecification fs )
+ {
+ getCOSDictionary().setItem( "F", fs );
+ }
+
+ /**
+ * This will get a dictionary containing Windows-specific launch parameters.
+ *
+ * @return The Win entry of of the specific launch action dictionary.
+ */
+ public PDWindowsLaunchParams getWinLaunchParams()
+ {
+ COSDictionary win = (COSDictionary)action.getDictionaryObject( "Win" );
+ PDWindowsLaunchParams retval = null;
+ if( win != null )
+ {
+ retval = new PDWindowsLaunchParams( win );
+ }
+ return retval;
+ }
+
+ /**
+ * This will set a dictionary containing Windows-specific launch parameters.
+ *
+ * @param win The action to be performed.
+ */
+ public void setWinLaunchParams( PDWindowsLaunchParams win )
+ {
+ action.setItem( "Win", win );
+ }
+
+ /**
+ * This will get the file name to be launched or the document to be opened
+ * or printed, in standard Windows pathname format. If the name string includes
+ * a backslash character (\), the backslash must itself be preceded by a backslash.
+ * This value must be a single string; it is not a file specification.
+ *
+ * @return The F entry of the specific Windows launch parameter dictionary.
+ */
+ public String getF()
+ {
+ return action.getString( "F" );
+ }
+
+ /**
+ * This will set the file name to be launched or the document to be opened
+ * or printed, in standard Windows pathname format. If the name string includes
+ * a backslash character (\), the backslash must itself be preceded by a backslash.
+ * This value must be a single string; it is not a file specification.
+ *
+ * @param f The file name to be launched.
+ */
+ public void setF( String f )
+ {
+ action.setString( "F", f );
+ }
+
+ /**
+ * This will get the string specifying the default directory in standard DOS syntax.
+ *
+ * @return The D entry of the specific Windows launch parameter dictionary.
+ */
+ public String getD()
+ {
+ return action.getString( "D" );
+ }
+
+ /**
+ * This will set the string specifying the default directory in standard DOS syntax.
+ *
+ * @param d The default directory.
+ */
+ public void setD( String d )
+ {
+ action.setString( "D", d );
+ }
+
+ /**
+ * This will get the string specifying the operation to perform:
+ * open to open a document
+ * print to print a document
+ * If the F entry designates an application instead of a document, this entry
+ * is ignored and the application is launched. Default value: open.
+ *
+ * @return The O entry of the specific Windows launch parameter dictionary.
+ */
+ public String getO()
+ {
+ return action.getString( "O" );
+ }
+
+ /**
+ * This will set the string specifying the operation to perform:
+ * open to open a document
+ * print to print a document
+ * If the F entry designates an application instead of a document, this entry
+ * is ignored and the application is launched. Default value: open.
+ *
+ * @param o The operation to perform.
+ */
+ public void setO( String o )
+ {
+ action.setString( "O", o );
+ }
+
+ /**
+ * This will get a parameter string to be passed to the application designated by the F entry.
+ * This entry should be omitted if F designates a document.
+ *
+ * @return The P entry of the specific Windows launch parameter dictionary.
+ */
+ public String getP()
+ {
+ return action.getString( "P" );
+ }
+
+ /**
+ * This will set a parameter string to be passed to the application designated by the F entry.
+ * This entry should be omitted if F designates a document.
+ *
+ * @param p The parameter string.
+ */
+ public void setP( String p )
+ {
+ action.setString( "P", p );
+ }
+
+ /**
+ * This will specify whether to open the destination document in a new window.
+ * If this flag is false, the destination document will replace the current
+ * document in the same window. If this entry is absent, the viewer application
+ * should behave in accordance with the current user preference. This entry is
+ * ignored if the file designated by the F entry is not a PDF document.
+ *
+ * @return A flag specifying whether to open the destination document in a new window.
+ */
+ public boolean shouldOpenInNewWindow()
+ {
+ return action.getBoolean( "NewWindow", true );
+ }
+
+ /**
+ * This will specify the destination document to open in a new window.
+ *
+ * @param value The flag value.
+ */
+ public void setOpenInNewWindow( boolean value )
+ {
+ action.setBoolean( "NewWindow", value );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/interactive/action/type/PDActionRemoteGoTo.java b/src/main/java/org/pdfbox/pdmodel/interactive/action/type/PDActionRemoteGoTo.java
new file mode 100644
index 0000000..73dbc6c
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/interactive/action/type/PDActionRemoteGoTo.java
@@ -0,0 +1,187 @@
+/**
+ * Copyright (c) 2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.interactive.action.type;
+
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSDictionary;
+
+import org.pdfbox.pdmodel.common.filespecification.PDFileSpecification;
+
+/**
+ * This represents a remote go-to action that can be executed in a PDF document.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @author Panagiotis Toumasis (ptoumasis@mail.gr)
+ * @version $Revision: 1.2 $
+ */
+public class PDActionRemoteGoTo extends PDAction
+{
+ /**
+ * This type of action this object represents.
+ */
+ public static final String SUB_TYPE = "GoToR";
+
+ /**
+ * Default constructor.
+ */
+ public PDActionRemoteGoTo()
+ {
+ action = new COSDictionary();
+ setSubType( SUB_TYPE );
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param a The action dictionary.
+ */
+ public PDActionRemoteGoTo( COSDictionary a )
+ {
+ super( a );
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSBase getCOSObject()
+ {
+ return action;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSDictionary getCOSDictionary()
+ {
+ return action;
+ }
+
+ /**
+ * This will get the type of action that the actions dictionary describes.
+ * It must be GoToR for a remote go-to action.
+ *
+ * @return The S entry of the specific remote go-to action dictionary.
+ */
+ public String getS()
+ {
+ return action.getNameAsString( "S" );
+ }
+
+ /**
+ * This will set the type of action that the actions dictionary describes.
+ * It must be GoToR for a remote go-to action.
+ *
+ * @param s The remote go-to action.
+ */
+ public void setS( String s )
+ {
+ action.setName( "S", s );
+ }
+
+ /**
+ * This will get the file in which the destination is located.
+ *
+ * @return The F entry of the specific remote go-to action dictionary.
+ */
+ public PDFileSpecification getFile()
+ {
+ return PDFileSpecification.createFS( action.getDictionaryObject( "F" ) );
+ }
+
+ /**
+ * This will set the file in which the destination is located.
+ *
+ * @param fs The file specification.
+ */
+ public void setFile( PDFileSpecification fs )
+ {
+ action.setItem( "F", fs );
+ }
+
+ /**
+ * This will get the destination to jump to.
+ * If the value is an array defining an explicit destination,
+ * its first element must be a page number within the remote
+ * document rather than an indirect reference to a page object
+ * in the current document. The first page is numbered 0.
+ *
+ * @return The D entry of the specific remote go-to action dictionary.
+ */
+
+ // Array or String.
+ public COSBase getD()
+ {
+ return action.getDictionaryObject( "D" );
+ }
+
+ /**
+ * This will set the destination to jump to.
+ * If the value is an array defining an explicit destination,
+ * its first element must be a page number within the remote
+ * document rather than an indirect reference to a page object
+ * in the current document. The first page is numbered 0.
+ *
+ * @param d The destination.
+ */
+
+ // In case the value is an array.
+ public void setD( COSBase d )
+ {
+ action.setItem( "D", d );
+ }
+
+ /**
+ * This will specify whether to open the destination document in a new window.
+ * If this flag is false, the destination document will replace the current
+ * document in the same window. If this entry is absent, the viewer application
+ * should behave in accordance with the current user preference.
+ *
+ * @return A flag specifying whether to open the destination document in a new window.
+ */
+ public boolean shouldOpenInNewWindow()
+ {
+ return action.getBoolean( "NewWindow", true );
+ }
+
+ /**
+ * This will specify the destination document to open in a new window.
+ *
+ * @param value The flag value.
+ */
+ public void setOpenInNewWindow( boolean value )
+ {
+ action.setBoolean( "NewWindow", value );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/interactive/action/type/PDActionURI.java b/src/main/java/org/pdfbox/pdmodel/interactive/action/type/PDActionURI.java
new file mode 100644
index 0000000..b98495d
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/interactive/action/type/PDActionURI.java
@@ -0,0 +1,183 @@
+/**
+ * Copyright (c) 2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.interactive.action.type;
+
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSDictionary;
+
+/**
+ * This represents a URI action that can be executed in a PDF document.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @author Panagiotis Toumasis (ptoumasis@mail.gr)
+ * @version $Revision: 1.2 $
+ */
+public class PDActionURI extends PDAction
+{
+ /**
+ * This type of action this object represents.
+ */
+ public static final String SUB_TYPE = "URI";
+
+ /**
+ * Default constructor.
+ */
+ public PDActionURI()
+ {
+ action = new COSDictionary();
+ setSubType( SUB_TYPE );
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param a The action dictionary.
+ */
+ public PDActionURI( COSDictionary a )
+ {
+ super( a );
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSBase getCOSObject()
+ {
+ return action;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSDictionary getCOSDictionary()
+ {
+ return action;
+ }
+
+ /**
+ * This will get the type of action that the actions dictionary describes.
+ * It must be URI for a URI action.
+ *
+ * @return The S entry of the specific URI action dictionary.
+ */
+ public String getS()
+ {
+ return action.getNameAsString( "S" );
+ }
+
+ /**
+ * This will set the type of action that the actions dictionary describes.
+ * It must be URI for a URI action.
+ *
+ * @param s The URI action.
+ */
+ public void setS( String s )
+ {
+ action.setName( "S", s );
+ }
+
+ /**
+ * This will get the uniform resource identifier to resolve, encoded in 7-bit ASCII.
+ *
+ * @return The URI entry of the specific URI action dictionary.
+ */
+ public String getURI()
+ {
+ return action.getString( "URI" );
+ }
+
+ /**
+ * This will set the uniform resource identifier to resolve, encoded in 7-bit ASCII.
+ *
+ * @param uri The uniform resource identifier.
+ */
+ public void setURI( String uri )
+ {
+ action.setString( "URI", uri );
+ }
+
+ /**
+ * This will specify whether to track the mouse position when the URI is resolved.
+ * Default value: false.
+ * This entry applies only to actions triggered by the user's clicking an annotation;
+ * it is ignored for actions associated with outline items or with a document's OpenAction entry.
+ *
+ * @return A flag specifying whether to track the mouse position when the URI is resolved.
+ */
+ public boolean shouldTrackMousePosition()
+ {
+ return action.getBoolean( "MousePosition", true );
+ }
+
+ /**
+ * This will specify whether to track the mouse position when the URI is resolved.
+ *
+ * @param value The flag value.
+ */
+ public void setTrackMousePosition( boolean value )
+ {
+ action.setBoolean( "MousePosition", value );
+ }
+
+ /**
+ * This will get the base URI to be used in resolving relative URI references.
+ * URI actions within the document may specify URIs in partial form, to be interpreted
+ * relative to this base address. If no base URI is specified, such partial URIs
+ * will be interpreted relative to the location of the document itself.
+ * The use of this entry is parallel to that of the body element &lt;BASE&gt;, as described
+ * in the HTML 4.01 Specification.
+ *
+ * @return The URI entry of the specific URI dictionary.
+ */
+ public String getBase()
+ {
+ return action.getString( "Base" );
+ }
+
+ /**
+ * This will set the base URI to be used in resolving relative URI references.
+ * URI actions within the document may specify URIs in partial form, to be interpreted
+ * relative to this base address. If no base URI is specified, such partial URIs
+ * will be interpreted relative to the location of the document itself.
+ * The use of this entry is parallel to that of the body element &lt;BASE&gt;, as described
+ * in the HTML 4.01 Specification.
+ *
+ * @param base The the base URI to be used.
+ */
+ public void setBase( String base )
+ {
+ action.setString( "Base", base );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/interactive/action/type/PDWindowsLaunchParams.java b/src/main/java/org/pdfbox/pdmodel/interactive/action/type/PDWindowsLaunchParams.java
new file mode 100644
index 0000000..7af4ff2
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/interactive/action/type/PDWindowsLaunchParams.java
@@ -0,0 +1,180 @@
+/**
+ * Copyright (c) 2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.interactive.action.type;
+
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSDictionary;
+
+import org.pdfbox.pdmodel.common.COSObjectable;
+
+/**
+ * Launch paramaters for the windows OS.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.1 $
+ */
+public class PDWindowsLaunchParams implements COSObjectable
+{
+ /**
+ * The open operation for the launch.
+ */
+ public static final String OPERATION_OPEN = "open";
+ /**
+ * The print operation for the lanuch.
+ */
+ public static final String OPERATION_PRINT = "print";
+
+ /**
+ * The params dictionary.
+ */
+ protected COSDictionary params;
+
+ /**
+ * Default constructor.
+ */
+ public PDWindowsLaunchParams()
+ {
+ params = new COSDictionary();
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param p The params dictionary.
+ */
+ public PDWindowsLaunchParams( COSDictionary p )
+ {
+ params = p;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSBase getCOSObject()
+ {
+ return params;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSDictionary getCOSDictionary()
+ {
+ return params;
+ }
+
+ /**
+ * The file to launch.
+ *
+ * @return The executable/document to launch.
+ */
+ public String getFilename()
+ {
+ return params.getString( "F" );
+ }
+
+ /**
+ * Set the file to launch.
+ *
+ * @param file The executable/document to launch.
+ */
+ public void setFilename( String file )
+ {
+ params.setString( "F", file );
+ }
+
+ /**
+ * The dir to launch from.
+ *
+ * @return The dir of the executable/document to launch.
+ */
+ public String getDirectory()
+ {
+ return params.getString( "D" );
+ }
+
+ /**
+ * Set the dir to launch from.
+ *
+ * @param dir The dir of the executable/document to launch.
+ */
+ public void setDirectory( String dir )
+ {
+ params.setString( "D", dir );
+ }
+
+ /**
+ * Get the operation to perform on the file. This method will not return null,
+ * OPERATION_OPEN is the default.
+ *
+ * @return The operation to perform for the file.
+ * @see PDWindowsLaunchParams#OPERATION_OPEN
+ * @see PDWindowsLaunchParams#OPERATION_PRINT
+ */
+ public String getOperation()
+ {
+ return params.getString( "O", OPERATION_OPEN );
+ }
+
+ /**
+ * Set the operation to perform..
+ *
+ * @param op The operation to perform on the file.
+ */
+ public void setOperation( String op )
+ {
+ params.setString( "D", op );
+ }
+
+ /**
+ * A parameter to pass the executable.
+ *
+ * @return The parameter to pass the executable.
+ */
+ public String getExecuteParam()
+ {
+ return params.getString( "P" );
+ }
+
+ /**
+ * Set the parameter to pass the executable.
+ *
+ * @param param The parameter for the executable.
+ */
+ public void setExecuteParam( String param )
+ {
+ params.setString( "P", param );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/interactive/action/type/package.html b/src/main/java/org/pdfbox/pdmodel/interactive/action/type/package.html
new file mode 100644
index 0000000..f0db5c3
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/interactive/action/type/package.html
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+
+</head>
+<body>
+This package contains all of the available PDF action types.
+</body>
+</html>
diff --git a/src/main/java/org/pdfbox/pdmodel/interactive/annotation/PDAnnotation.java b/src/main/java/org/pdfbox/pdmodel/interactive/annotation/PDAnnotation.java
new file mode 100644
index 0000000..4d245c0
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/interactive/annotation/PDAnnotation.java
@@ -0,0 +1,503 @@
+/**
+ * Copyright (c) 2003-2005, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.interactive.annotation;
+
+import java.io.IOException;
+
+import org.pdfbox.cos.COSArray;
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSName;
+
+import org.pdfbox.pdmodel.common.COSObjectable;
+import org.pdfbox.pdmodel.common.PDRectangle;
+import org.pdfbox.pdmodel.interactive.action.PDAdditionalActions;
+import org.pdfbox.util.BitFlagHelper;
+import org.pdfbox.cos.COSBase;
+
+/**
+ * This class represents a PDF annotation.
+ *
+ * @author Ben Litchfield (ben@benlitchfield.com)
+ * @version $Revision: 1.10 $
+ */
+public abstract class PDAnnotation implements COSObjectable
+{
+ /**
+ * An annotation flag.
+ */
+ public static final int FLAG_INVISIBLE = 1 << 0;
+ /**
+ * An annotation flag.
+ */
+ public static final int FLAG_HIDDEN = 1 << 1;
+ /**
+ * An annotation flag.
+ */
+ public static final int FLAG_PRINTED = 1 << 2;
+ /**
+ * An annotation flag.
+ */
+ public static final int FLAG_NO_ZOOM = 1 << 3;
+ /**
+ * An annotation flag.
+ */
+ public static final int FLAG_NO_ROTATE = 1 << 4;
+ /**
+ * An annotation flag.
+ */
+ public static final int FLAG_NO_VIEW = 1 << 5;
+ /**
+ * An annotation flag.
+ */
+ public static final int FLAG_READ_ONLY = 1 << 6;
+ /**
+ * An annotation flag.
+ */
+ public static final int FLAG_LOCKED = 1 << 7;
+ /**
+ * An annotation flag.
+ */
+ 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.
+ */
+ public static PDAnnotation createAnnotation( COSBase base ) throws IOException
+ {
+ PDAnnotation annot = null;
+ if( base instanceof COSDictionary )
+ {
+ COSDictionary annotDic = (COSDictionary)base;
+ String subtype = annotDic.getString( COSName.SUBTYPE );
+ if( subtype.equals( PDAnnotationRubberStamp.SUB_TYPE ) )
+ {
+ annot = new PDAnnotationRubberStamp(annotDic);
+ }
+ else
+ {
+ annot = new PDAnnotationUnknown( annotDic );
+ }
+ }
+ else
+ {
+ throw new IOException( "Error: Unknown annotation type " + base );
+ }
+
+ return annot;
+ }
+
+ /**
+ * Constructor.
+ */
+ public PDAnnotation()
+ {
+ dictionary = new COSDictionary();
+ dictionary.setItem( COSName.TYPE, COSName.getPDFName( "Annot" ) );
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param dict The annotations dictionary.
+ */
+ public PDAnnotation( COSDictionary dict )
+ {
+ dictionary = dict;
+ }
+
+ /**
+ * returns the dictionary.
+ * @return the dictionary
+ */
+ public COSDictionary getDictionary()
+ {
+ return dictionary;
+ }
+
+ /**
+ * 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.getPDFName( "Rect" ) );
+ PDRectangle rectangle = null;
+ if( rectArray != null )
+ {
+ 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 )
+ {
+ dictionary.setItem( COSName.getPDFName( "Rect" ), rectangle.getCOSArray() );
+ }
+
+ /**
+ * This will get the flags for this field.
+ *
+ * @return flags The set of flags.
+ */
+ public int getAnnotationFlags()
+ {
+ return getDictionary().getInt( "F", 0 );
+ }
+
+ /**
+ * This will set the flags for this field.
+ *
+ * @param flags The new flags.
+ */
+ public void setAnnotationFlags( int flags )
+ {
+ getDictionary().setInt( "F", flags );
+ }
+
+ /**
+ * Interface method for COSObjectable.
+ *
+ * @return This object as a standard COS object.
+ */
+ public COSBase getCOSObject()
+ {
+ return getDictionary();
+ }
+
+ /**
+ * 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.getPDFName( "AS" ) );
+ if( name != null )
+ {
+ retval = name.getName();
+ }
+ return retval;
+ }
+
+ /**
+ * This will set the annotations appearance stream name.
+ *
+ * @param as The name of the appearance stream.
+ */
+ public void setAppearanceStream( String as )
+ {
+ if( as == null )
+ {
+ getDictionary().removeItem( COSName.getPDFName( "AS" ) );
+ }
+ else
+ {
+ getDictionary().setItem( COSName.getPDFName( "AS" ), COSName.getPDFName( as ) );
+ }
+ }
+
+ /**
+ * 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.getPDFName( "AP" ) );
+ if( apDic != null )
+ {
+ 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 )
+ {
+ COSDictionary ap = null;
+ if( appearance != null )
+ {
+ ap = appearance.getDictionary();
+ }
+ dictionary.setItem( COSName.getPDFName( "AP" ), ap );
+ }
+
+ /**
+ * Get the invisible flag.
+ *
+ * @return The invisible flag.
+ */
+ public boolean isInvisible()
+ {
+ return BitFlagHelper.getFlag( getDictionary(), "F", FLAG_INVISIBLE );
+ }
+
+ /**
+ * Set the invisible flag.
+ *
+ * @param invisible The new invisible flag.
+ */
+ public void setInvisible( boolean invisible )
+ {
+ BitFlagHelper.setFlag( getDictionary(), "F", FLAG_INVISIBLE, invisible );
+ }
+
+ /**
+ * Get the hidden flag.
+ *
+ * @return The hidden flag.
+ */
+ public boolean isHidden()
+ {
+ return BitFlagHelper.getFlag( getDictionary(), "F", FLAG_HIDDEN );
+ }
+
+ /**
+ * Set the hidden flag.
+ *
+ * @param hidden The new hidden flag.
+ */
+ public void setHidden( boolean hidden )
+ {
+ BitFlagHelper.setFlag( getDictionary(), "F", FLAG_HIDDEN, hidden );
+ }
+
+ /**
+ * Get the printed flag.
+ *
+ * @return The printed flag.
+ */
+ public boolean isPrinted()
+ {
+ return BitFlagHelper.getFlag( getDictionary(), "F", FLAG_PRINTED );
+ }
+
+ /**
+ * Set the printed flag.
+ *
+ * @param printed The new printed flag.
+ */
+ public void setPrinted( boolean printed )
+ {
+ BitFlagHelper.setFlag( getDictionary(), "F", FLAG_PRINTED, printed );
+ }
+
+ /**
+ * Get the noZoom flag.
+ *
+ * @return The noZoom flag.
+ */
+ public boolean isNoZoom()
+ {
+ return BitFlagHelper.getFlag( getDictionary(), "F", FLAG_NO_ZOOM );
+ }
+
+ /**
+ * Set the noZoom flag.
+ *
+ * @param noZoom The new noZoom flag.
+ */
+ public void setNoZoom( boolean noZoom )
+ {
+ BitFlagHelper.setFlag( getDictionary(), "F", FLAG_NO_ZOOM, noZoom );
+ }
+
+ /**
+ * Get the noRotate flag.
+ *
+ * @return The noRotate flag.
+ */
+ public boolean isNoRotate()
+ {
+ return BitFlagHelper.getFlag( getDictionary(), "F", FLAG_NO_ROTATE );
+ }
+
+ /**
+ * Set the noRotate flag.
+ *
+ * @param noRotate The new noRotate flag.
+ */
+ public void setNoRotate( boolean noRotate )
+ {
+ BitFlagHelper.setFlag( getDictionary(), "F", FLAG_NO_ROTATE, noRotate );
+ }
+
+ /**
+ * Get the noView flag.
+ *
+ * @return The noView flag.
+ */
+ public boolean isNoView()
+ {
+ return BitFlagHelper.getFlag( getDictionary(), "F", FLAG_NO_VIEW );
+ }
+
+ /**
+ * Set the noView flag.
+ *
+ * @param noView The new noView flag.
+ */
+ public void setNoView( boolean noView )
+ {
+ BitFlagHelper.setFlag( getDictionary(), "F", FLAG_NO_VIEW, noView );
+ }
+
+ /**
+ * Get the readOnly flag.
+ *
+ * @return The readOnly flag.
+ */
+ public boolean isReadOnly()
+ {
+ return BitFlagHelper.getFlag( getDictionary(), "F", FLAG_READ_ONLY );
+ }
+
+ /**
+ * Set the readOnly flag.
+ *
+ * @param readOnly The new readOnly flag.
+ */
+ public void setReadOnly( boolean readOnly )
+ {
+ BitFlagHelper.setFlag( getDictionary(), "F", FLAG_READ_ONLY, readOnly );
+ }
+
+ /**
+ * Get the locked flag.
+ *
+ * @return The locked flag.
+ */
+ public boolean isLocked()
+ {
+ return BitFlagHelper.getFlag( getDictionary(), "F", FLAG_LOCKED );
+ }
+
+ /**
+ * Set the locked flag.
+ *
+ * @param locked The new locked flag.
+ */
+ public void setLocked( boolean locked )
+ {
+ BitFlagHelper.setFlag( getDictionary(), "F", FLAG_LOCKED, locked );
+ }
+
+ /**
+ * Get the toggleNoView flag.
+ *
+ * @return The toggleNoView flag.
+ */
+ public boolean isToggleNoView()
+ {
+ return BitFlagHelper.getFlag( getDictionary(), "F", FLAG_TOGGLE_NO_VIEW );
+ }
+
+ /**
+ * Set the toggleNoView flag.
+ *
+ * @param toggleNoView The new toggleNoView flag.
+ */
+ public void setToggleNoView( boolean toggleNoView )
+ {
+ BitFlagHelper.setFlag( getDictionary(), "F", FLAG_TOGGLE_NO_VIEW, toggleNoView );
+ }
+
+ /**
+ * Get the additional actions for this field. This will return null
+ * if there are no additional actions for this field.
+ *
+ * @return The actions of the field.
+ */
+ public PDAdditionalActions getActions()
+ {
+ COSDictionary aa = (COSDictionary)dictionary.getDictionaryObject( "AA" );
+ PDAdditionalActions retval = null;
+ if( aa != null )
+ {
+ retval = new PDAdditionalActions( aa );
+ }
+ return retval;
+ }
+
+ /**
+ * Set the actions of the field.
+ *
+ * @param actions The field actions.
+ */
+ public void setActions( PDAdditionalActions actions )
+ {
+ dictionary.setItem( "AA", actions );
+ }
+
+ /**
+ * Get the "contents" of the field.
+ *
+ * @return the value of the contents
+ */
+ public String getContents()
+ {
+ return dictionary.getString(COSName.CONTENTS);
+ }
+
+ /**
+ * Set the "contents" of the field.
+ *
+ * @param value the value of the contents.
+ */
+ public void setContents( String value)
+ {
+ dictionary.setString(COSName.CONTENTS, value);
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/interactive/annotation/PDAnnotationRubberStamp.java b/src/main/java/org/pdfbox/pdmodel/interactive/annotation/PDAnnotationRubberStamp.java
new file mode 100644
index 0000000..089b19f
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/interactive/annotation/PDAnnotationRubberStamp.java
@@ -0,0 +1,153 @@
+/**
+ * Copyright (c) 2003, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.interactive.annotation;
+
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSName;
+
+/**
+ * This is the class that represents a widget.
+ *
+ * @author Paul King
+ * @version $Revision: 1.1 $
+ */
+public class PDAnnotationRubberStamp extends PDAnnotation
+{
+
+ /*
+ * The various values of the rubber stamp as defined in
+ * the PDF 1.6 reference Table 8.28
+ */
+
+ /**
+ * Constant for the name of a rubber stamp.
+ */
+ public static final String NAME_APPROVED = "Approved";
+ /**
+ * Constant for the name of a rubber stamp.
+ */
+ public static final String NAME_EXPERIMENTAL = "Experimental";
+ /**
+ * Constant for the name of a rubber stamp.
+ */
+ public static final String NAME_NOT_APPROVED = "NotApproved";
+ /**
+ * Constant for the name of a rubber stamp.
+ */
+ public static final String NAME_AS_IS = "AsIs";
+ /**
+ * Constant for the name of a rubber stamp.
+ */
+ public static final String NAME_EXPIRED = "Expired";
+ /**
+ * Constant for the name of a rubber stamp.
+ */
+ public static final String NAME_NOT_FOR_PUBLIC_RELEASE = "NotForPublicRelease";
+ /**
+ * Constant for the name of a rubber stamp.
+ */
+ public static final String NAME_FOR_PUBLIC_RELEASE = "ForPublicRelease";
+ /**
+ * Constant for the name of a rubber stamp.
+ */
+ public static final String NAME_DRAFT = "Draft";
+ /**
+ * Constant for the name of a rubber stamp.
+ */
+ public static final String NAME_FOR_COMMENT = "ForComment";
+ /**
+ * Constant for the name of a rubber stamp.
+ */
+ public static final String NAME_TOP_SECRET = "TopSecret";
+ /**
+ * Constant for the name of a rubber stamp.
+ */
+ public static final String NAME_DEPARTMENTAL = "Departmental";
+ /**
+ * Constant for the name of a rubber stamp.
+ */
+ public static final String NAME_CONFIDENTIAL = "Confidential";
+ /**
+ * Constant for the name of a rubber stamp.
+ */
+ public static final String NAME_FINAL = "Final";
+ /**
+ * Constant for the name of a rubber stamp.
+ */
+ public static final String NAME_SOLD = "Sold";
+
+ /**
+ * The type of annotation.
+ */
+ public static final String SUB_TYPE = "Stamp";
+
+ /**
+ * Constructor.
+ */
+ public PDAnnotationRubberStamp()
+ {
+ super();
+ getDictionary().setItem( COSName.SUBTYPE, COSName.getPDFName( SUB_TYPE ) );
+ }
+
+ /**
+ * Creates a Rubber Stamp annotation from a COSDictionary, expected to be
+ * a correct object definition.
+ *
+ * @param field the PDF objet to represent as a field.
+ */
+ public PDAnnotationRubberStamp(COSDictionary field)
+ {
+ super( field );
+ }
+
+ /**
+ * This will set the name (and hence appearance, AP taking precedence)
+ * For this annotation. See the NAME_XXX constants for valid values.
+ *
+ * @param name The name of the rubber stamp.
+ */
+ public void setName( String name )
+ {
+ getDictionary().setName(COSName.NAME, name);
+ }
+
+ /**
+ * This will retrieve the name (and hence appearance, AP taking precedence)
+ * For this annotation. The default is DRAFT.
+ *
+ * @return The name of this rubber stamp, see the NAME_XXX constants.
+ */
+ public String getName()
+ {
+ return getDictionary().getNameAsString(COSName.NAME, NAME_DRAFT);
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/interactive/annotation/PDAnnotationUnknown.java b/src/main/java/org/pdfbox/pdmodel/interactive/annotation/PDAnnotationUnknown.java
new file mode 100644
index 0000000..408f5fb
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/interactive/annotation/PDAnnotationUnknown.java
@@ -0,0 +1,54 @@
+/**
+ * Copyright (c) 2003, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.interactive.annotation;
+
+import org.pdfbox.cos.COSDictionary;
+
+/**
+ * This is the class that represents an arbitary Unknown Annotation type.
+ *
+ * @author Paul King
+ * @version $Revision: 1.1 $
+ */
+public class PDAnnotationUnknown extends PDAnnotation
+{
+
+ /**
+ * Creates an arbitary annotation from a COSDictionary, expected to be
+ * a correct object definition for some sort of annotation.
+ *
+ * @param dic The dictionary which represents this Annotation.
+ */
+ public PDAnnotationUnknown(COSDictionary dic)
+ {
+ super( dic );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/interactive/annotation/PDAnnotationWidget.java b/src/main/java/org/pdfbox/pdmodel/interactive/annotation/PDAnnotationWidget.java
new file mode 100644
index 0000000..5faf983
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/interactive/annotation/PDAnnotationWidget.java
@@ -0,0 +1,65 @@
+/**
+ * Copyright (c) 2003, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.interactive.annotation;
+
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSName;
+
+/**
+ * This is the class that represents a widget.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.1 $
+ */
+public class PDAnnotationWidget extends PDAnnotation
+{
+
+ /**
+ * Constructor.
+ */
+ public PDAnnotationWidget()
+ {
+ super();
+ getDictionary().setItem( COSName.SUBTYPE, COSName.getPDFName( "Widget" ) );
+ }
+
+
+ /**
+ * Creates a PDWidget from a COSDictionary, expected to be
+ * a correct object definition for a field in PDF.
+ *
+ * @param field the PDF objet to represent as a field.
+ */
+ public PDAnnotationWidget(COSDictionary field)
+ {
+ super( field );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/interactive/annotation/PDAppearanceDictionary.java b/src/main/java/org/pdfbox/pdmodel/interactive/annotation/PDAppearanceDictionary.java
new file mode 100644
index 0000000..da3a182
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/interactive/annotation/PDAppearanceDictionary.java
@@ -0,0 +1,245 @@
+/**
+ * Copyright (c) 2003-2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.interactive.annotation;
+
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSName;
+import org.pdfbox.cos.COSStream;
+
+import org.pdfbox.pdmodel.common.COSObjectable;
+import org.pdfbox.pdmodel.common.COSDictionaryMap;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * This class represents a PDF /AP entry the appearance dictionary.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.3 $
+ */
+public class PDAppearanceDictionary implements COSObjectable
+{
+ private COSDictionary dictionary;
+
+ /**
+ * Constructor.
+ */
+ public PDAppearanceDictionary()
+ {
+ dictionary = new COSDictionary();
+ //the N entry is required.
+ dictionary.setItem( COSName.getPDFName( "N" ), new COSDictionary() );
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param dict The annotations dictionary.
+ */
+ public PDAppearanceDictionary( COSDictionary dict )
+ {
+ dictionary = dict;
+ }
+
+ /**
+ * returns the dictionary.
+ * @return the dictionary
+ */
+ public COSDictionary getDictionary()
+ {
+ return dictionary;
+ }
+
+ /**
+ * returns the dictionary.
+ * @return the dictionary
+ */
+ public COSBase getCOSObject()
+ {
+ return dictionary;
+ }
+
+ /**
+ * This will return a list of appearances. In the case where there is
+ * only one appearance the map will contain one entry whose key is the string
+ * "default".
+ *
+ * @return A list of key(java.lang.String) value(PDAppearanceStream) pairs
+ */
+ public Map getNormalAppearance()
+ {
+ COSBase ap = dictionary.getDictionaryObject( COSName.getPDFName( "N" ) );
+ if( ap instanceof COSStream )
+ {
+ COSStream aux = (COSStream) ap;
+ ap = new COSDictionary();
+ ((COSDictionary)ap).setItem(COSName.getPDFName( "default" ), aux );
+ }
+ COSDictionary map = (COSDictionary)ap;
+ Map actuals = new HashMap();
+ Map retval = new COSDictionaryMap( actuals, map );
+ Iterator asNames = map.keyList().iterator();
+ while( asNames.hasNext() )
+ {
+ COSName asName = (COSName)asNames.next();
+ COSStream as = (COSStream)map.getDictionaryObject( asName );
+ actuals.put( asName.getName(), new PDAppearanceStream( as ) );
+ }
+
+ return retval;
+ }
+
+ /**
+ * This will set a list of appearances. If you would like to set the single
+ * appearance then you should use the key "default", and when the PDF is written
+ * back to the filesystem then there will only be one stream.
+ *
+ * @param appearanceMap The updated map with the appearance.
+ */
+ public void setNormalAppearance( Map appearanceMap )
+ {
+ dictionary.setItem( COSName.getPDFName( "N" ), COSDictionaryMap.convert( appearanceMap ) );
+ }
+
+ /**
+ * This will set the normal appearance when there is only one appearance
+ * to be shown.
+ *
+ * @param ap The appearance stream to show.
+ */
+ public void setNormalAppearance( PDAppearanceStream ap )
+ {
+ dictionary.setItem( COSName.getPDFName( "N" ), ap.getStream() );
+ }
+
+ /**
+ * This will return a list of appearances. In the case where there is
+ * only one appearance the map will contain one entry whose key is the string
+ * "default". If there is no rollover appearance then the normal appearance
+ * will be returned. Which means that this method will never return null.
+ *
+ * @return A list of key(java.lang.String) value(PDAppearanceStream) pairs
+ */
+ public Map getRolloverAppearance()
+ {
+ Map retval = null;
+ COSBase ap = dictionary.getDictionaryObject( COSName.getPDFName( "R" ) );
+ if( ap == null )
+ {
+ retval = getNormalAppearance();
+ }
+ else
+ {
+ if( ap instanceof COSStream )
+ {
+ ap = new COSDictionary();
+ ((COSDictionary)ap).setItem(COSName.getPDFName( "default" ), ap );
+ }
+ COSDictionary map = (COSDictionary)ap;
+ Map actuals = new HashMap();
+ retval = new COSDictionaryMap( actuals, map );
+ Iterator asNames = map.keyList().iterator();
+ while( asNames.hasNext() )
+ {
+ COSName asName = (COSName)asNames.next();
+ COSStream as = (COSStream)map.getDictionaryObject( asName );
+ actuals.put( asName.getName(), new PDAppearanceStream( as ) );
+ }
+ }
+
+ return retval;
+ }
+
+ /**
+ * This will set a list of appearances. If you would like to set the single
+ * appearance then you should use the key "default", and when the PDF is written
+ * back to the filesystem then there will only be one stream.
+ *
+ * @param appearanceMap The updated map with the appearance.
+ */
+ public void setRolloverAppearance( Map appearanceMap )
+ {
+ dictionary.setItem( COSName.getPDFName( "R" ), COSDictionaryMap.convert( appearanceMap ) );
+ }
+
+ /**
+ * This will return a list of appearances. In the case where there is
+ * only one appearance the map will contain one entry whose key is the string
+ * "default". If there is no rollover appearance then the normal appearance
+ * will be returned. Which means that this method will never return null.
+ *
+ * @return A list of key(java.lang.String) value(PDAppearanceStream) pairs
+ */
+ public Map getDownAppearance()
+ {
+ Map retval = null;
+ COSBase ap = dictionary.getDictionaryObject( COSName.getPDFName( "D" ) );
+ if( ap == null )
+ {
+ retval = getNormalAppearance();
+ }
+ else
+ {
+ if( ap instanceof COSStream )
+ {
+ ap = new COSDictionary();
+ ((COSDictionary)ap).setItem(COSName.getPDFName( "default" ), ap );
+ }
+ COSDictionary map = (COSDictionary)ap;
+ Map actuals = new HashMap();
+ retval = new COSDictionaryMap( actuals, map );
+ Iterator asNames = map.keyList().iterator();
+ while( asNames.hasNext() )
+ {
+ COSName asName = (COSName)asNames.next();
+ COSStream as = (COSStream)map.getDictionaryObject( asName );
+ actuals.put( asName.getName(), new PDAppearanceStream( as ) );
+ }
+ }
+
+ return retval;
+ }
+
+ /**
+ * This will set a list of appearances. If you would like to set the single
+ * appearance then you should use the key "default", and when the PDF is written
+ * back to the filesystem then there will only be one stream.
+ *
+ * @param appearanceMap The updated map with the appearance.
+ */
+ public void setDownAppearance( Map appearanceMap )
+ {
+ dictionary.setItem( COSName.getPDFName( "D" ), COSDictionaryMap.convert( appearanceMap ) );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/interactive/annotation/PDAppearanceStream.java b/src/main/java/org/pdfbox/pdmodel/interactive/annotation/PDAppearanceStream.java
new file mode 100644
index 0000000..ca3f4a4
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/interactive/annotation/PDAppearanceStream.java
@@ -0,0 +1,146 @@
+/**
+ * Copyright (c) 2003-2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.interactive.annotation;
+
+import org.pdfbox.cos.COSArray;
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSName;
+import org.pdfbox.cos.COSStream;
+
+import org.pdfbox.pdmodel.common.PDRectangle;
+import org.pdfbox.pdmodel.common.COSObjectable;
+
+import org.pdfbox.pdmodel.PDResources;
+
+
+/**
+ * This class represents an appearance for an annotation.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.3 $
+ */
+public class PDAppearanceStream implements COSObjectable
+{
+ private COSStream stream = null;
+
+
+ /**
+ * Constructor.
+ *
+ * @param s The cos stream for this appearance.
+ */
+ public PDAppearanceStream( COSStream s )
+ {
+ stream = s;
+ }
+
+ /**
+ * This will return the underlying stream.
+ *
+ * @return The wrapped stream.
+ */
+ public COSStream getStream()
+ {
+ return stream;
+ }
+
+ /**
+ * @see COSObjectable#getCOSObject()
+ */
+ public COSBase getCOSObject()
+ {
+ return stream;
+ }
+
+ /**
+ * Get the bounding box for this appearance. This may return null in which
+ * case the Rectangle from the annotation should be used.
+ *
+ * @return The bounding box for this appearance.
+ */
+ public PDRectangle getBoundingBox()
+ {
+ PDRectangle box = null;
+ COSArray bbox = (COSArray)stream.getDictionaryObject( COSName.getPDFName( "BBox" ) );
+ if( bbox != null )
+ {
+ box = new PDRectangle( bbox );
+ }
+ return box;
+ }
+
+ /**
+ * This will set the bounding box for this appearance stream.
+ *
+ * @param rectangle The new bounding box.
+ */
+ public void setBoundingBox( PDRectangle rectangle )
+ {
+ COSArray array = null;
+ if( rectangle != null )
+ {
+ array = rectangle.getCOSArray();
+ }
+ stream.setItem( COSName.getPDFName( "BBox" ), array );
+ }
+
+ /**
+ * This will get the resources for this appearance stream.
+ *
+ * @return The appearance stream resources.
+ */
+ public PDResources getResources()
+ {
+ PDResources retval = null;
+ COSDictionary dict = (COSDictionary)stream.getDictionaryObject( COSName.RESOURCES );
+ if( dict != null )
+ {
+ retval = new PDResources( dict );
+ }
+ return retval;
+ }
+
+ /**
+ * This will set the new resources.
+ *
+ * @param resources The new resources.
+ */
+ public void setResources( PDResources resources )
+ {
+ COSDictionary dict = null;
+ if( resources != null )
+ {
+ dict = resources.getCOSDictionary();
+ }
+ stream.setItem( COSName.RESOURCES, dict );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/interactive/annotation/package.html b/src/main/java/org/pdfbox/pdmodel/interactive/annotation/package.html
new file mode 100644
index 0000000..4d9fdeb
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/interactive/annotation/package.html
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+
+</head>
+<body>
+The annotation package contains classes that work with PDF annotation elements.
+</body>
+</html>
diff --git a/src/main/java/org/pdfbox/pdmodel/interactive/digitalsignature/PDSignature.java b/src/main/java/org/pdfbox/pdmodel/interactive/digitalsignature/PDSignature.java
new file mode 100644
index 0000000..7ef1c1e
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/interactive/digitalsignature/PDSignature.java
@@ -0,0 +1,85 @@
+/**
+ * Copyright (c) 2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.interactive.digitalsignature;
+
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSDictionary;
+
+import org.pdfbox.pdmodel.common.COSObjectable;
+
+/**
+ * This represents a digital signature that can be attached to a document.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.1 $
+ */
+public class PDSignature implements COSObjectable
+{
+ private COSDictionary sig;
+
+ /**
+ * Default constructor.
+ */
+ public PDSignature()
+ {
+ sig = new COSDictionary();
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param s The signature dictionary.
+ */
+ public PDSignature( COSDictionary s )
+ {
+ sig = s;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSBase getCOSObject()
+ {
+ return sig;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSDictionary getCOSDictionary()
+ {
+ return sig;
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/interactive/digitalsignature/package.html b/src/main/java/org/pdfbox/pdmodel/interactive/digitalsignature/package.html
new file mode 100644
index 0000000..d9944e6
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/interactive/digitalsignature/package.html
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+
+</head>
+<body>
+The digitial signature library will manage signatures that are stored in the PDF document.
+</body>
+</html>
diff --git a/src/main/java/org/pdfbox/pdmodel/interactive/documentnavigation/destination/PDDestination.java b/src/main/java/org/pdfbox/pdmodel/interactive/documentnavigation/destination/PDDestination.java
new file mode 100644
index 0000000..98a0345
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/interactive/documentnavigation/destination/PDDestination.java
@@ -0,0 +1,125 @@
+/**
+ * Copyright (c) 2004-2005, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.interactive.documentnavigation.destination;
+
+import java.io.IOException;
+
+import org.pdfbox.cos.COSArray;
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSName;
+import org.pdfbox.cos.COSString;
+
+import org.pdfbox.pdmodel.common.COSObjectable;
+
+/**
+ * This represents a destination in a PDF document.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.4 $
+ */
+public abstract class PDDestination implements COSObjectable
+{
+
+ /**
+ * This will create a new destination depending on the type of COSBase
+ * that is passed in.
+ *
+ * @param base The base level object.
+ *
+ * @return A new destination.
+ *
+ * @throws IOException If the base cannot be converted to a Destination.
+ */
+ public static PDDestination create( COSBase base ) throws IOException
+ {
+ PDDestination retval = null;
+ if( base == null )
+ {
+ //this is ok, just return null.
+ }
+ else if( base instanceof COSArray && ((COSArray)base).size() > 0 )
+ {
+ COSArray array = (COSArray)base;
+ COSName type = (COSName)array.getObject( 1 );
+ String typeString = type.getName();
+ if( typeString.equals( PDPageFitDestination.TYPE ) ||
+ typeString.equals( PDPageFitDestination.TYPE_BOUNDED ))
+ {
+ retval = new PDPageFitDestination( array );
+ }
+ else if( typeString.equals( PDPageFitHeightDestination.TYPE ) ||
+ typeString.equals( PDPageFitHeightDestination.TYPE_BOUNDED ))
+ {
+ retval = new PDPageFitHeightDestination( array );
+ }
+ else if( typeString.equals( PDPageFitRectangleDestination.TYPE ) )
+ {
+ retval = new PDPageFitRectangleDestination( array );
+ }
+ else if( typeString.equals( PDPageFitWidthDestination.TYPE ) ||
+ typeString.equals( PDPageFitWidthDestination.TYPE_BOUNDED ))
+ {
+ retval = new PDPageFitWidthDestination( array );
+ }
+ else if( typeString.equals( PDPageXYZDestination.TYPE ) )
+ {
+ retval = new PDPageXYZDestination( array );
+ }
+ else
+ {
+ throw new IOException( "Unknown destination type:" + type );
+ }
+ }
+ else if( base instanceof COSString )
+ {
+ retval = new PDNamedDestination( (COSString)base );
+ }
+ else if( base instanceof COSName )
+ {
+ retval = new PDNamedDestination( (COSName)base );
+ }
+ else
+ {
+ throw new IOException( "Error: can't convert to Destination " + base );
+ }
+ return retval;
+ }
+
+ /**
+ * Return a string representation of this class.
+ *
+ * @return A human readable string.
+ */
+ public String toString()
+ {
+ return super.toString();
+ }
+}
diff --git a/src/main/java/org/pdfbox/pdmodel/interactive/documentnavigation/destination/PDNamedDestination.java b/src/main/java/org/pdfbox/pdmodel/interactive/documentnavigation/destination/PDNamedDestination.java
new file mode 100644
index 0000000..11da8e7
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/interactive/documentnavigation/destination/PDNamedDestination.java
@@ -0,0 +1,142 @@
+/**
+ * Copyright (c) 2005, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.interactive.documentnavigation.destination;
+
+import java.io.IOException;
+
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSName;
+import org.pdfbox.cos.COSString;
+
+/**
+ * This represents a destination to a page by referencing it with a name.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.2 $
+ */
+public class PDNamedDestination extends PDDestination
+{
+ private COSBase namedDestination;
+
+ /**
+ * Constructor.
+ *
+ * @param dest The named destination.
+ */
+ public PDNamedDestination( COSString dest )
+ {
+ namedDestination = dest;
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param dest The named destination.
+ */
+ public PDNamedDestination( COSName dest )
+ {
+ namedDestination = dest;
+ }
+
+ /**
+ * Default constructor.
+ */
+ public PDNamedDestination()
+ {
+ //default, so do nothing
+ }
+
+ /**
+ * Default constructor.
+ *
+ * @param dest The named destination.
+ */
+ public PDNamedDestination( String dest )
+ {
+ namedDestination = new COSString( dest );
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSBase getCOSObject()
+ {
+ return namedDestination;
+ }
+
+ /**
+ * This will get the name of the destination.
+ *
+ * @return The name of the destination.
+ */
+ public String getNamedDestination()
+ {
+ String retval = null;
+ if( namedDestination instanceof COSString )
+ {
+ retval = ((COSString)namedDestination).getString();
+ }
+ else if( namedDestination instanceof COSName )
+ {
+ retval = ((COSName)namedDestination).getName();
+ }
+
+ return retval;
+ }
+
+ /**
+ * Set the named destination.
+ *
+ * @param dest The new named destination.
+ *
+ * @throws IOException If there is an error setting the named destination.
+ */
+ public void setNamedDestination( String dest ) throws IOException
+ {
+ if( namedDestination instanceof COSString )
+ {
+ COSString string = ((COSString)namedDestination);
+ string.reset();
+ string.append( dest.getBytes() );
+ }
+ else if( dest == null )
+ {
+ namedDestination = null;
+ }
+ else
+ {
+ namedDestination = new COSString( dest );
+ }
+ }
+
+}
diff --git a/src/main/java/org/pdfbox/pdmodel/interactive/documentnavigation/destination/PDPageDestination.java b/src/main/java/org/pdfbox/pdmodel/interactive/documentnavigation/destination/PDPageDestination.java
new file mode 100644
index 0000000..74dbf9a
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/interactive/documentnavigation/destination/PDPageDestination.java
@@ -0,0 +1,155 @@
+/**
+ * Copyright (c) 2005, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.interactive.documentnavigation.destination;
+
+import org.pdfbox.cos.COSArray;
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSNumber;
+
+import org.pdfbox.pdmodel.PDPage;
+
+/**
+ * This represents a destination to a page, see subclasses for specific parameters.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.1 $
+ */
+public abstract class PDPageDestination extends PDDestination
+{
+ /**
+ * Storage for the page destination.
+ */
+ protected COSArray array;
+
+ /**
+ * Constructor to create empty page destination.
+ *
+ */
+ protected PDPageDestination()
+ {
+ array = new COSArray();
+ }
+
+ /**
+ * Constructor to create empty page destination.
+ *
+ * @param arr A page destination array.
+ */
+ protected PDPageDestination( COSArray arr )
+ {
+ array = arr;
+ }
+
+ /**
+ * This will get the page for this destination. A page destination
+ * can either reference a page or a page number(when doing a remote destination to
+ * another PDF). If this object is referencing by page number then this method will
+ * return null and getPageNumber should be used.
+ *
+ * @return The page for this destination.
+ */
+ public PDPage getPage()
+ {
+ PDPage retval = null;
+ if( array.size() > 0 )
+ {
+ COSBase page = array.getObject( 0 );
+ if( page instanceof COSDictionary )
+ {
+ retval = new PDPage( (COSDictionary)page );
+ }
+ }
+ return retval;
+ }
+
+ /**
+ * Set the page for this destination.
+ *
+ * @param page The page for the destination.
+ */
+ public void setPage( PDPage page )
+ {
+ array.set( 0, page );
+ }
+
+ /**
+ * This will get the page number for this destination. A page destination
+ * can either reference a page or a page number(when doing a remote destination to
+ * another PDF). If this object is referencing by page number then this method will
+ * return that number, otherwise -1 will be returned.
+ *
+ * @return The page number for this destination.
+ */
+ public int getPageNumber()
+ {
+ int retval = -1;
+ if( array.size() > 0 )
+ {
+ COSBase page = array.getObject( 0 );
+ if( page instanceof COSNumber )
+ {
+ retval = ((COSNumber)page).intValue();
+ }
+ }
+ return retval;
+ }
+
+ /**
+ * Set the page number for this destination.
+ *
+ * @param pageNumber The page for the destination.
+ */
+ public void setPageNumber( int pageNumber )
+ {
+ array.set( 0, pageNumber );
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSBase getCOSObject()
+ {
+ return array;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSArray getCOSArray()
+ {
+ return array;
+ }
+}
diff --git a/src/main/java/org/pdfbox/pdmodel/interactive/documentnavigation/destination/PDPageFitDestination.java b/src/main/java/org/pdfbox/pdmodel/interactive/documentnavigation/destination/PDPageFitDestination.java
new file mode 100644
index 0000000..8f46bbe
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/interactive/documentnavigation/destination/PDPageFitDestination.java
@@ -0,0 +1,102 @@
+/**
+ * Copyright (c) 2005, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.interactive.documentnavigation.destination;
+
+import org.pdfbox.cos.COSArray;
+
+/**
+ * This represents a destination to a page and the page contents will be magnified to just
+ * fit on the screen.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.1 $
+ */
+public class PDPageFitDestination extends PDPageDestination
+{
+ /**
+ * The type of this destination.
+ */
+ protected static final String TYPE = "Fit";
+ /**
+ * The type of this destination.
+ */
+ protected static final String TYPE_BOUNDED = "FitB";
+
+ /**
+ * Default constructor.
+ *
+ */
+ public PDPageFitDestination()
+ {
+ super();
+ array.growToSize(2);
+ array.setName( 1, TYPE );
+
+ }
+
+ /**
+ * Constructor from an existing destination array.
+ *
+ * @param arr The destination array.
+ */
+ public PDPageFitDestination( COSArray arr )
+ {
+ super( arr );
+ }
+
+ /**
+ * A flag indicating if this page destination should just fit bounding box of the PDF.
+ *
+ * @return true If the destination should fit just the bounding box.
+ */
+ public boolean fitBoundingBox()
+ {
+ return TYPE_BOUNDED.equals( array.getName( 1 ) );
+ }
+
+ /**
+ * Set if this page destination should just fit the bounding box. The default is false.
+ *
+ * @param fitBoundingBox A flag indicating if this should fit the bounding box.
+ */
+ public void setFitBoundingBox( boolean fitBoundingBox )
+ {
+ array.growToSize( 2 );
+ if( fitBoundingBox )
+ {
+ array.setName( 1, TYPE_BOUNDED );
+ }
+ else
+ {
+ array.setName( 1, TYPE );
+ }
+ }
+}
diff --git a/src/main/java/org/pdfbox/pdmodel/interactive/documentnavigation/destination/PDPageFitHeightDestination.java b/src/main/java/org/pdfbox/pdmodel/interactive/documentnavigation/destination/PDPageFitHeightDestination.java
new file mode 100644
index 0000000..64df612
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/interactive/documentnavigation/destination/PDPageFitHeightDestination.java
@@ -0,0 +1,132 @@
+/**
+ * Copyright (c) 2005, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.interactive.documentnavigation.destination;
+
+import org.pdfbox.cos.COSArray;
+import org.pdfbox.cos.COSBase;
+
+/**
+ * This represents a destination to a page at a x location and the height is magnified
+ * to just fit on the screen.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.1 $
+ */
+public class PDPageFitHeightDestination extends PDPageDestination
+{
+ /**
+ * The type of this destination.
+ */
+ protected static final String TYPE = "FitV";
+ /**
+ * The type of this destination.
+ */
+ protected static final String TYPE_BOUNDED = "FitBV";
+
+ /**
+ * Default constructor.
+ *
+ */
+ public PDPageFitHeightDestination()
+ {
+ super();
+ array.growToSize(3);
+ array.setName( 1, TYPE );
+
+ }
+
+ /**
+ * Constructor from an existing destination array.
+ *
+ * @param arr The destination array.
+ */
+ public PDPageFitHeightDestination( COSArray arr )
+ {
+ super( arr );
+ }
+
+ /**
+ * Get the left x coordinate. A return value of -1 implies that the current x-coordinate
+ * will be used.
+ *
+ * @return The left x coordinate.
+ */
+ public int getLeft()
+ {
+ return array.getInt( 2 );
+ }
+
+ /**
+ * Set the left x-coordinate, a value of -1 implies that the current x-coordinate
+ * will be used.
+ * @param x The left x coordinate.
+ */
+ public void setLeft( int x )
+ {
+ array.growToSize( 3 );
+ if( x == -1 )
+ {
+ array.set( 2, (COSBase)null );
+ }
+ else
+ {
+ array.setInt( 2, x );
+ }
+ }
+
+ /**
+ * A flag indicating if this page destination should just fit bounding box of the PDF.
+ *
+ * @return true If the destination should fit just the bounding box.
+ */
+ public boolean fitBoundingBox()
+ {
+ return TYPE_BOUNDED.equals( array.getName( 1 ) );
+ }
+
+ /**
+ * Set if this page destination should just fit the bounding box. The default is false.
+ *
+ * @param fitBoundingBox A flag indicating if this should fit the bounding box.
+ */
+ public void setFitBoundingBox( boolean fitBoundingBox )
+ {
+ array.growToSize( 2 );
+ if( fitBoundingBox )
+ {
+ array.setName( 1, TYPE_BOUNDED );
+ }
+ else
+ {
+ array.setName( 1, TYPE );
+ }
+ }
+}
diff --git a/src/main/java/org/pdfbox/pdmodel/interactive/documentnavigation/destination/PDPageFitRectangleDestination.java b/src/main/java/org/pdfbox/pdmodel/interactive/documentnavigation/destination/PDPageFitRectangleDestination.java
new file mode 100644
index 0000000..00fc5f1
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/interactive/documentnavigation/destination/PDPageFitRectangleDestination.java
@@ -0,0 +1,188 @@
+/**
+ * Copyright (c) 2005, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.interactive.documentnavigation.destination;
+
+import org.pdfbox.cos.COSArray;
+import org.pdfbox.cos.COSBase;
+
+/**
+ * This represents a destination to a page at a y location and the width is magnified
+ * to just fit on the screen.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.1 $
+ */
+public class PDPageFitRectangleDestination extends PDPageDestination
+{
+ /**
+ * The type of this destination.
+ */
+ protected static final String TYPE = "FitR";
+
+ /**
+ * Default constructor.
+ *
+ */
+ public PDPageFitRectangleDestination()
+ {
+ super();
+ array.growToSize(6);
+ array.setName( 1, TYPE );
+
+ }
+
+ /**
+ * Constructor from an existing destination array.
+ *
+ * @param arr The destination array.
+ */
+ public PDPageFitRectangleDestination( COSArray arr )
+ {
+ super( arr );
+ }
+
+ /**
+ * Get the left x coordinate. A return value of -1 implies that the current x-coordinate
+ * will be used.
+ *
+ * @return The left x coordinate.
+ */
+ public int getLeft()
+ {
+ return array.getInt( 2 );
+ }
+
+ /**
+ * Set the left x-coordinate, a value of -1 implies that the current x-coordinate
+ * will be used.
+ * @param x The left x coordinate.
+ */
+ public void setLeft( int x )
+ {
+ array.growToSize( 3 );
+ if( x == -1 )
+ {
+ array.set( 2, (COSBase)null );
+ }
+ else
+ {
+ array.setInt( 2, x );
+ }
+ }
+
+ /**
+ * Get the bottom y coordinate. A return value of -1 implies that the current y-coordinate
+ * will be used.
+ *
+ * @return The bottom y coordinate.
+ */
+ public int getBottom()
+ {
+ return array.getInt( 3 );
+ }
+
+ /**
+ * Set the bottom y-coordinate, a value of -1 implies that the current y-coordinate
+ * will be used.
+ * @param y The bottom y coordinate.
+ */
+ public void setBottom( int y )
+ {
+ array.growToSize( 6 );
+ if( y == -1 )
+ {
+ array.set( 3, (COSBase)null );
+ }
+ else
+ {
+ array.setInt( 3, y );
+ }
+ }
+
+ /**
+ * Get the right x coordinate. A return value of -1 implies that the current x-coordinate
+ * will be used.
+ *
+ * @return The right x coordinate.
+ */
+ public int getRight()
+ {
+ return array.getInt( 4 );
+ }
+
+ /**
+ * Set the right x-coordinate, a value of -1 implies that the current x-coordinate
+ * will be used.
+ * @param x The right x coordinate.
+ */
+ public void setRight( int x )
+ {
+ array.growToSize( 6 );
+ if( x == -1 )
+ {
+ array.set( 4, (COSBase)null );
+ }
+ else
+ {
+ array.setInt( 4, x );
+ }
+ }
+
+
+ /**
+ * Get the top y coordinate. A return value of -1 implies that the current y-coordinate
+ * will be used.
+ *
+ * @return The top y coordinate.
+ */
+ public int getTop()
+ {
+ return array.getInt( 5 );
+ }
+
+ /**
+ * Set the top y-coordinate, a value of -1 implies that the current y-coordinate
+ * will be used.
+ * @param y The top ycoordinate.
+ */
+ public void setTop( int y )
+ {
+ array.growToSize( 6 );
+ if( y == -1 )
+ {
+ array.set( 5, (COSBase)null );
+ }
+ else
+ {
+ array.setInt( 5, y );
+ }
+ }
+}
diff --git a/src/main/java/org/pdfbox/pdmodel/interactive/documentnavigation/destination/PDPageFitWidthDestination.java b/src/main/java/org/pdfbox/pdmodel/interactive/documentnavigation/destination/PDPageFitWidthDestination.java
new file mode 100644
index 0000000..ef7385f
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/interactive/documentnavigation/destination/PDPageFitWidthDestination.java
@@ -0,0 +1,134 @@
+/**
+ * Copyright (c) 2005, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.interactive.documentnavigation.destination;
+
+import org.pdfbox.cos.COSArray;
+import org.pdfbox.cos.COSBase;
+
+/**
+ * This represents a destination to a page at a y location and the width is magnified
+ * to just fit on the screen.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.1 $
+ */
+public class PDPageFitWidthDestination extends PDPageDestination
+{
+
+ /**
+ * The type of this destination.
+ */
+ protected static final String TYPE = "FitH";
+ /**
+ * The type of this destination.
+ */
+ protected static final String TYPE_BOUNDED = "FitBH";
+
+ /**
+ * Default constructor.
+ *
+ */
+ public PDPageFitWidthDestination()
+ {
+ super();
+ array.growToSize(3);
+ array.setName( 1, TYPE );
+
+ }
+
+ /**
+ * Constructor from an existing destination array.
+ *
+ * @param arr The destination array.
+ */
+ public PDPageFitWidthDestination( COSArray arr )
+ {
+ super( arr );
+ }
+
+
+ /**
+ * Get the top y coordinate. A return value of -1 implies that the current y-coordinate
+ * will be used.
+ *
+ * @return The top y coordinate.
+ */
+ public int getTop()
+ {
+ return array.getInt( 2 );
+ }
+
+ /**
+ * Set the top y-coordinate, a value of -1 implies that the current y-coordinate
+ * will be used.
+ * @param y The top ycoordinate.
+ */
+ public void setTop( int y )
+ {
+ array.growToSize( 3 );
+ if( y == -1 )
+ {
+ array.set( 2, (COSBase)null );
+ }
+ else
+ {
+ array.setInt( 2, y );
+ }
+ }
+
+ /**
+ * A flag indicating if this page destination should just fit bounding box of the PDF.
+ *
+ * @return true If the destination should fit just the bounding box.
+ */
+ public boolean fitBoundingBox()
+ {
+ return TYPE_BOUNDED.equals( array.getName( 1 ) );
+ }
+
+ /**
+ * Set if this page destination should just fit the bounding box. The default is false.
+ *
+ * @param fitBoundingBox A flag indicating if this should fit the bounding box.
+ */
+ public void setFitBoundingBox( boolean fitBoundingBox )
+ {
+ array.growToSize( 2 );
+ if( fitBoundingBox )
+ {
+ array.setName( 1, TYPE_BOUNDED );
+ }
+ else
+ {
+ array.setName( 1, TYPE );
+ }
+ }
+}
diff --git a/src/main/java/org/pdfbox/pdmodel/interactive/documentnavigation/destination/PDPageXYZDestination.java b/src/main/java/org/pdfbox/pdmodel/interactive/documentnavigation/destination/PDPageXYZDestination.java
new file mode 100644
index 0000000..543a33c
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/interactive/documentnavigation/destination/PDPageXYZDestination.java
@@ -0,0 +1,159 @@
+/**
+ * Copyright (c) 2005, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.interactive.documentnavigation.destination;
+
+import org.pdfbox.cos.COSArray;
+import org.pdfbox.cos.COSBase;
+
+/**
+ * This represents a destination to a page at an x,y coordinate with a zoom setting.
+ * The default x,y,z will be whatever is the current value in the viewer application and
+ * are not required.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.1 $
+ */
+public class PDPageXYZDestination extends PDPageDestination
+{
+ /**
+ * The type of this destination.
+ */
+ protected static final String TYPE = "XYZ";
+
+ /**
+ * Default constructor.
+ *
+ */
+ public PDPageXYZDestination()
+ {
+ super();
+ array.growToSize(5);
+ array.setName( 1, TYPE );
+
+ }
+
+ /**
+ * Constructor from an existing destination array.
+ *
+ * @param arr The destination array.
+ */
+ public PDPageXYZDestination( COSArray arr )
+ {
+ super( arr );
+ }
+
+ /**
+ * Get the left x coordinate. A return value of -1 implies that the current x-coordinate
+ * will be used.
+ *
+ * @return The left x coordinate.
+ */
+ public int getLeft()
+ {
+ return array.getInt( 2 );
+ }
+
+ /**
+ * Set the left x-coordinate, a value of -1 implies that the current x-coordinate
+ * will be used.
+ * @param x The left x coordinate.
+ */
+ public void setLeft( int x )
+ {
+ array.growToSize( 3 );
+ if( x == -1 )
+ {
+ array.set( 2, (COSBase)null );
+ }
+ else
+ {
+ array.setInt( 2, x );
+ }
+ }
+
+ /**
+ * Get the top y coordinate. A return value of -1 implies that the current y-coordinate
+ * will be used.
+ *
+ * @return The top y coordinate.
+ */
+ public int getTop()
+ {
+ return array.getInt( 3 );
+ }
+
+ /**
+ * Set the top y-coordinate, a value of -1 implies that the current y-coordinate
+ * will be used.
+ * @param y The top ycoordinate.
+ */
+ public void setTop( int y )
+ {
+ array.growToSize( 4 );
+ if( y == -1 )
+ {
+ array.set( 3, (COSBase)null );
+ }
+ else
+ {
+ array.setInt( 3, y );
+ }
+ }
+
+ /**
+ * Get the zoom value. A return value of -1 implies that the current zoom
+ * will be used.
+ *
+ * @return The zoom value for the page.
+ */
+ public int getZoom()
+ {
+ return array.getInt( 4 );
+ }
+
+ /**
+ * Set the zoom value for the page, a value of -1 implies that the current zoom
+ * will be used.
+ * @param zoom The zoom value.
+ */
+ public void setZoom( int zoom )
+ {
+ array.growToSize( 5 );
+ if( zoom == -1 )
+ {
+ array.set( 4, (COSBase)null );
+ }
+ else
+ {
+ array.setInt( 4, zoom );
+ }
+ }
+}
diff --git a/src/main/java/org/pdfbox/pdmodel/interactive/documentnavigation/destination/package.html b/src/main/java/org/pdfbox/pdmodel/interactive/documentnavigation/destination/package.html
new file mode 100644
index 0000000..2122b1d
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/interactive/documentnavigation/destination/package.html
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+
+</head>
+<body>
+The destination package allows destinations into a pdf document to be specified.
+</body>
+</html>
diff --git a/src/main/java/org/pdfbox/pdmodel/interactive/documentnavigation/outline/PDDocumentOutline.java b/src/main/java/org/pdfbox/pdmodel/interactive/documentnavigation/outline/PDDocumentOutline.java
new file mode 100644
index 0000000..157a36f
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/interactive/documentnavigation/outline/PDDocumentOutline.java
@@ -0,0 +1,62 @@
+/**
+ * Copyright (c) 2005, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.interactive.documentnavigation.outline;
+
+import org.pdfbox.cos.COSDictionary;
+
+/**
+ * This represents an outline in a pdf document.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.1 $
+ */
+public class PDDocumentOutline extends PDOutlineNode
+{
+
+ /**
+ * Default Constructor.
+ */
+ public PDDocumentOutline()
+ {
+ super();
+ node.setName( "Type", "Outlines" );
+ }
+
+ /**
+ * Constructor for an existing document outline.
+ *
+ * @param dic The storage dictionary.
+ */
+ public PDDocumentOutline( COSDictionary dic )
+ {
+ super( dic );
+ }
+}
diff --git a/src/main/java/org/pdfbox/pdmodel/interactive/documentnavigation/outline/PDOutlineItem.java b/src/main/java/org/pdfbox/pdmodel/interactive/documentnavigation/outline/PDOutlineItem.java
new file mode 100644
index 0000000..648eb64
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/interactive/documentnavigation/outline/PDOutlineItem.java
@@ -0,0 +1,425 @@
+/**
+ * Copyright (c) 2005, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.interactive.documentnavigation.outline;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.pdfbox.cos.COSArray;
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSFloat;
+import org.pdfbox.exceptions.OutlineNotLocalException;
+import org.pdfbox.pdmodel.PDDestinationNameTreeNode;
+import org.pdfbox.pdmodel.PDDocument;
+import org.pdfbox.pdmodel.PDDocumentNameDictionary;
+import org.pdfbox.pdmodel.PDPage;
+import org.pdfbox.pdmodel.documentinterchange.logicalstructure.PDStructureElement;
+import org.pdfbox.pdmodel.graphics.color.PDColorSpaceInstance;
+import org.pdfbox.pdmodel.graphics.color.PDDeviceRGB;
+import org.pdfbox.pdmodel.interactive.action.type.PDAction;
+import org.pdfbox.pdmodel.interactive.action.type.PDActionGoTo;
+import org.pdfbox.pdmodel.interactive.action.PDActionFactory;
+import org.pdfbox.pdmodel.interactive.documentnavigation.destination.PDDestination;
+import org.pdfbox.pdmodel.interactive.documentnavigation.destination.PDNamedDestination;
+import org.pdfbox.pdmodel.interactive.documentnavigation.destination.PDPageDestination;
+import org.pdfbox.pdmodel.interactive.documentnavigation.destination.PDPageXYZDestination;
+
+/**
+ * This represents an outline in a pdf document.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.5 $
+ */
+public class PDOutlineItem extends PDOutlineNode
+{
+
+ private static final int ITALIC_FLAG = 1;
+ private static final int BOLD_FLAG = 2;
+
+ /**
+ * Default Constructor.
+ */
+ public PDOutlineItem()
+ {
+ super();
+ }
+
+ /**
+ * Constructor for an existing outline item.
+ *
+ * @param dic The storage dictionary.
+ */
+ public PDOutlineItem( COSDictionary dic )
+ {
+ super( dic );
+ }
+
+ /**
+ * Insert a sibling after this node.
+ *
+ * @param item The item to insert.
+ */
+ public void insertSiblingAfter( PDOutlineItem item )
+ {
+ item.setParent( getParent() );
+ PDOutlineItem next = getNextSibling();
+ setNextSibling( item );
+ item.setPreviousSibling( this );
+ if( next != null )
+ {
+ item.setNextSibling( next );
+ next.setPreviousSibling( item );
+ }
+ updateParentOpenCount( 1 );
+ }
+
+ /**
+ * Return the previous sibling or null if there is no sibling.
+ *
+ * @return The previous sibling.
+ */
+ public PDOutlineItem getPreviousSibling()
+ {
+ PDOutlineItem last = null;
+ COSDictionary lastDic = (COSDictionary)node.getDictionaryObject( "Prev" );
+ if( lastDic != null )
+ {
+ last = new PDOutlineItem( lastDic );
+ }
+ return last;
+ }
+
+ /**
+ * Set the previous sibling, this will be maintained by this class.
+ *
+ * @param outlineNode The new previous sibling.
+ */
+ protected void setPreviousSibling( PDOutlineNode outlineNode )
+ {
+ node.setItem( "Prev", outlineNode );
+ }
+
+ /**
+ * Return the next sibling or null if there is no next sibling.
+ *
+ * @return The next sibling.
+ */
+ public PDOutlineItem getNextSibling()
+ {
+ PDOutlineItem last = null;
+ COSDictionary lastDic = (COSDictionary)node.getDictionaryObject( "Next" );
+ if( lastDic != null )
+ {
+ last = new PDOutlineItem( lastDic );
+ }
+ return last;
+ }
+
+ /**
+ * Set the next sibling, this will be maintained by this class.
+ *
+ * @param outlineNode The new next sibling.
+ */
+ protected void setNextSibling( PDOutlineNode outlineNode )
+ {
+ node.setItem( "Next", outlineNode );
+ }
+
+ /**
+ * Get the title of this node.
+ *
+ * @return The title of this node.
+ */
+ public String getTitle()
+ {
+ return node.getString( "Title" );
+ }
+
+ /**
+ * Set the title for this node.
+ *
+ * @param title The new title for this node.
+ */
+ public void setTitle( String title )
+ {
+ node.setString( "Title", title );
+ }
+
+ /**
+ * Get the page destination of this node.
+ *
+ * @return The page destination of this node.
+ * @throws IOException If there is an error creating the destination.
+ */
+ public PDDestination getDestination() throws IOException
+ {
+ return PDDestination.create( node.getDictionaryObject( "Dest" ) );
+ }
+
+ /**
+ * Set the page destination for this node.
+ *
+ * @param dest The new page destination for this node.
+ */
+ public void setDestination( PDDestination dest )
+ {
+ node.setItem( "Dest", dest );
+ }
+
+ /**
+ * A convenience method that will create an XYZ destination using only the defaults.
+ *
+ * @param page The page to refer to.
+ */
+ public void setDestination( PDPage page )
+ {
+ PDPageXYZDestination dest = null;
+ if( page != null )
+ {
+ dest = new PDPageXYZDestination();
+ dest.setPage( page );
+ }
+ setDestination( dest );
+ }
+
+ /**
+ * This method will attempt to find the page in this PDF document that this outline points to.
+ * If the outline does not point to anything then this method will return null. If the outline
+ * is an action that is not a GoTo action then this methods will throw the OutlineNotLocationException
+ *
+ * @param doc The document to get the page from.
+ *
+ * @return The page that this outline will go to when activated or null if it does not point to anything.
+ * @throws IOException If there is an error when trying to find the page.
+ */
+ public PDPage findDestinationPage( PDDocument doc ) throws IOException
+ {
+ PDPage page = null;
+ PDDestination rawDest = getDestination();
+ if( rawDest == null )
+ {
+ PDAction outlineAction = getAction();
+ if( outlineAction instanceof PDActionGoTo )
+ {
+ rawDest = ((PDActionGoTo)outlineAction).getDestination();
+ }
+ else if( outlineAction == null )
+ {
+ //if the outline action is null then this outline does not refer
+ //to anything and we will just return null.
+ }
+ else
+ {
+ throw new OutlineNotLocalException( "Error: Outline does not reference a local page." );
+ }
+ }
+
+ PDPageDestination pageDest = null;
+ if( rawDest instanceof PDNamedDestination )
+ {
+ //if we have a named destination we need to lookup the PDPageDestination
+ PDNamedDestination namedDest = (PDNamedDestination)rawDest;
+ PDDocumentNameDictionary namesDict = doc.getDocumentCatalog().getNames();
+ if( namesDict != null )
+ {
+ PDDestinationNameTreeNode destsTree = namesDict.getDests();
+ if( destsTree != null )
+ {
+ pageDest = (PDPageDestination)destsTree.getValue( namedDest.getNamedDestination() );
+ }
+ }
+ }
+ else if( rawDest instanceof PDPageDestination)
+ {
+ pageDest = (PDPageDestination) rawDest;
+ }
+ else if( rawDest == null )
+ {
+ //if the destination is null then we will simply return a null page.
+ }
+ else
+ {
+ throw new IOException( "Error: Unknown destination type " + rawDest );
+ }
+
+ if( pageDest != null )
+ {
+ page = pageDest.getPage();
+ if( page == null )
+ {
+ int pageNumber = pageDest.getPageNumber();
+ if( pageNumber != -1 )
+ {
+ List allPages = doc.getDocumentCatalog().getAllPages();
+ page = (PDPage)allPages.get( pageNumber );
+ }
+ }
+ }
+
+ return page;
+ }
+
+ /**
+ * Get the action of this node.
+ *
+ * @return The action of this node.
+ */
+ public PDAction getAction()
+ {
+ return PDActionFactory.createAction( (COSDictionary)node.getDictionaryObject( "A" ) );
+ }
+
+ /**
+ * Set the action for this node.
+ *
+ * @param action The new action for this node.
+ */
+ public void setAction( PDAction action )
+ {
+ node.setItem( "A", action );
+ }
+
+ /**
+ * Get the structure element of this node.
+ *
+ * @return The structure element of this node.
+ */
+ public PDStructureElement getStructureElement()
+ {
+ PDStructureElement se = null;
+ COSDictionary dic = (COSDictionary)node.getDictionaryObject( "SE" );
+ if( dic != null )
+ {
+ se = new PDStructureElement( dic );
+ }
+ return se;
+ }
+
+ /**
+ * Set the structure element for this node.
+ *
+ * @param structureElement The new structure element for this node.
+ */
+ public void setAction( PDStructureElement structureElement )
+ {
+ node.setItem( "SE", structureElement );
+ }
+
+ /**
+ * Get the text color of this node. Default is black and this method
+ * will never return null.
+ *
+ * @return The structure element of this node.
+ */
+ public PDColorSpaceInstance getTextColor()
+ {
+ PDColorSpaceInstance retval = null;
+ COSArray csValues = (COSArray)node.getDictionaryObject( "C" );
+ if( csValues == null )
+ {
+ csValues = new COSArray();
+ csValues.growToSize( 3, new COSFloat( 0 ) );
+ node.setItem( "C", csValues );
+ }
+ retval = new PDColorSpaceInstance(csValues);
+ retval.setColorSpace( PDDeviceRGB.INSTANCE );
+ return retval;
+ }
+
+ /**
+ * Set the text color for this node.
+ *
+ * @param textColor The text color for this node.
+ */
+ public void setTextColor( PDColorSpaceInstance textColor )
+ {
+ node.setItem( "C", textColor.getCOSColorSpaceValue() );
+ }
+
+ /**
+ * A flag telling if the text should be italic.
+ *
+ * @return The italic flag.
+ */
+ public boolean isItalic()
+ {
+ return (node.getInt( "F", 0 ) & ITALIC_FLAG) == ITALIC_FLAG;
+ }
+
+ /**
+ * Set the italic property of the text.
+ *
+ * @param italic The new italic flag.
+ */
+ public void setItalic( boolean italic )
+ {
+ int f = node.getInt( "F", 0 );
+ if( italic )
+ {
+ f = f | ITALIC_FLAG;
+ }
+ else
+ {
+ f = f ^ ITALIC_FLAG;
+ }
+ node.setInt( "F", f );
+ }
+
+ /**
+ * A flag telling if the text should be bold.
+ *
+ * @return The bold flag.
+ */
+ public boolean isBold()
+ {
+ return (node.getInt( "F", 0 ) & BOLD_FLAG) == BOLD_FLAG;
+ }
+
+ /**
+ * Set the bold property of the text.
+ *
+ * @param bold The new bold flag.
+ */
+ public void setBold( boolean bold )
+ {
+ int f = node.getInt( "F", 0 );
+ if( bold )
+ {
+ f = f | BOLD_FLAG;
+ }
+ else
+ {
+ f = f ^ BOLD_FLAG;
+ }
+ node.setInt( "F", f );
+ }
+
+}
diff --git a/src/main/java/org/pdfbox/pdmodel/interactive/documentnavigation/outline/PDOutlineNode.java b/src/main/java/org/pdfbox/pdmodel/interactive/documentnavigation/outline/PDOutlineNode.java
new file mode 100644
index 0000000..04cc45f
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/interactive/documentnavigation/outline/PDOutlineNode.java
@@ -0,0 +1,320 @@
+/**
+ * Copyright (c) 2005, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.interactive.documentnavigation.outline;
+
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSDictionary;
+
+import org.pdfbox.pdmodel.common.COSObjectable;
+
+/**
+ * This represents an node in an outline in a pdf document.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.1 $
+ */
+public class PDOutlineNode implements COSObjectable
+{
+ /**
+ * The dictionary for this node.
+ */
+ protected COSDictionary node;
+
+ /**
+ * Default Constructor.
+ */
+ public PDOutlineNode()
+ {
+ node = new COSDictionary();
+ }
+
+ /**
+ * Default Constructor.
+ *
+ * @param dict The dictionary storage.
+ */
+ public PDOutlineNode( COSDictionary dict)
+ {
+ node = dict;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSBase getCOSObject()
+ {
+ return node;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSDictionary getCOSDictionary()
+ {
+ return node;
+ }
+
+ /**
+ * Get the parent of this object. This will either be a DocumentOutline or an OutlineItem.
+ *
+ * @return The parent of this object, or null if this is the document outline and there
+ * is no parent.
+ */
+ public PDOutlineNode getParent()
+ {
+ PDOutlineNode retval = null;
+ COSDictionary parent = (COSDictionary)node.getDictionaryObject( "Parent" );
+ if( parent != null )
+ {
+ if( parent.getDictionaryObject( "Parent") == null )
+ {
+ retval = new PDDocumentOutline( parent );
+ }
+ else
+ {
+ retval = new PDOutlineItem( parent );
+ }
+ }
+
+ return retval;
+ }
+
+ /**
+ * Set the parent of this object, this is maintained by these objects and should not
+ * be called by any clients of PDFBox code.
+ *
+ * @param parent The parent of this object.
+ */
+ protected void setParent( PDOutlineNode parent )
+ {
+ node.setItem( "Parent", parent );
+ }
+
+ /**
+ * append a child node to this node.
+ *
+ * @param outlineNode The node to add.
+ */
+ public void appendChild( PDOutlineItem outlineNode )
+ {
+ outlineNode.setParent( this );
+ if( getFirstChild() == null )
+ {
+ int currentOpenCount = getOpenCount();
+ setFirstChild( outlineNode );
+ //1 for the the item we are adding;
+ int numberOfOpenNodesWeAreAdding = 1;
+ if( outlineNode.isNodeOpen() )
+ {
+ numberOfOpenNodesWeAreAdding += outlineNode.getOpenCount();
+ }
+ if( isNodeOpen() )
+ {
+ setOpenCount( currentOpenCount + numberOfOpenNodesWeAreAdding );
+ }
+ else
+ {
+ setOpenCount( currentOpenCount - numberOfOpenNodesWeAreAdding );
+ }
+ updateParentOpenCount( numberOfOpenNodesWeAreAdding );
+ }
+ else
+ {
+ PDOutlineItem previousLastChild = getLastChild();
+ previousLastChild.insertSiblingAfter( outlineNode );
+ }
+ setLastChild( outlineNode );
+ }
+
+ /**
+ * Return the first child or null if there is no child.
+ *
+ * @return The first child.
+ */
+ public PDOutlineItem getFirstChild()
+ {
+ PDOutlineItem last = null;
+ COSDictionary lastDic = (COSDictionary)node.getDictionaryObject( "First" );
+ if( lastDic != null )
+ {
+ last = new PDOutlineItem( lastDic );
+ }
+ return last;
+ }
+
+ /**
+ * Set the first child, this will be maintained by this class.
+ *
+ * @param outlineNode The new first child.
+ */
+ protected void setFirstChild( PDOutlineNode outlineNode )
+ {
+ node.setItem( "First", outlineNode );
+ }
+
+ /**
+ * Return the last child or null if there is no child.
+ *
+ * @return The last child.
+ */
+ public PDOutlineItem getLastChild()
+ {
+ PDOutlineItem last = null;
+ COSDictionary lastDic = (COSDictionary)node.getDictionaryObject( "Last" );
+ if( lastDic != null )
+ {
+ last = new PDOutlineItem( lastDic );
+ }
+ return last;
+ }
+
+ /**
+ * Set the last child, this will be maintained by this class.
+ *
+ * @param outlineNode The new last child.
+ */
+ protected void setLastChild( PDOutlineNode outlineNode )
+ {
+ node.setItem( "Last", outlineNode );
+ }
+
+ /**
+ * Get the number of open nodes. Or a negative number if this node
+ * is closed. See PDF Reference for more details. This value
+ * is updated as you append children and siblings.
+ *
+ * @return The Count attribute of the outline dictionary.
+ */
+ public int getOpenCount()
+ {
+ return node.getInt( "Count", 0 );
+ }
+
+ /**
+ * Set the open count. This number is automatically managed for you
+ * when you add items to the outline.
+ *
+ * @param openCount The new open cound.
+ */
+ protected void setOpenCount( int openCount )
+ {
+ node.setInt( "Count", openCount );
+ }
+
+ /**
+ * This will set this node to be open when it is shown in the viewer. By default, when
+ * a new node is created it will be closed.
+ * This will do nothing if the node is already open.
+ */
+ public void openNode()
+ {
+ //if the node is already open then do nothing.
+ if( !isNodeOpen() )
+ {
+ int openChildrenCount = 0;
+ PDOutlineItem currentChild = getFirstChild();
+ while( currentChild != null )
+ {
+ //first increase by one for the current child
+ openChildrenCount++;
+ //then increase by the number of open nodes the child has
+ if( currentChild.isNodeOpen() )
+ {
+ openChildrenCount += currentChild.getOpenCount();
+ }
+ currentChild = currentChild.getNextSibling();
+ }
+ setOpenCount( openChildrenCount );
+ updateParentOpenCount( openChildrenCount );
+ }
+ }
+
+ /**
+ * Close this node.
+ *
+ */
+ public void closeNode()
+ {
+ //if the node is already closed then do nothing.
+ if( isNodeOpen() )
+ {
+ int openCount = getOpenCount();
+ updateParentOpenCount( -openCount );
+ setOpenCount( -openCount );
+ }
+ }
+
+ /**
+ * Node is open if the open count is greater than zero.
+ * @return true if this node is open.
+ */
+ public boolean isNodeOpen()
+ {
+ return getOpenCount() > 0;
+ }
+
+ /**
+ * The count parameter needs to be updated when you add or remove elements to
+ * the outline. When you add an element at a lower level then you need to
+ * increase all of the parents.
+ *
+ * @param amount The amount to update by.
+ */
+ protected void updateParentOpenCount( int amount )
+ {
+ PDOutlineNode parent = getParent();
+ if( parent != null )
+ {
+ int currentCount = parent.getOpenCount();
+ //if the currentCount is negative or it is absent then
+ //we will treat it as negative. The default is to be negative.
+ boolean negative = currentCount < 0 ||
+ parent.getCOSDictionary().getDictionaryObject( "Count" ) == null;
+ currentCount = Math.abs( currentCount );
+ currentCount += amount;
+ if( negative )
+ {
+ currentCount = -currentCount;
+ }
+ parent.setOpenCount( currentCount );
+ //recursively call parent to update count, but the parents count is only
+ //updated if this is an open node
+ if( !negative )
+ {
+ parent.updateParentOpenCount( amount );
+ }
+ }
+ }
+}
diff --git a/src/main/java/org/pdfbox/pdmodel/interactive/documentnavigation/outline/package.html b/src/main/java/org/pdfbox/pdmodel/interactive/documentnavigation/outline/package.html
new file mode 100644
index 0000000..4ec0032
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/interactive/documentnavigation/outline/package.html
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+
+</head>
+<body>
+The outline package allows for a PDF outline(bookmarks) to be created.
+</body>
+</html>
diff --git a/src/main/java/org/pdfbox/pdmodel/interactive/documentnavigation/package.html b/src/main/java/org/pdfbox/pdmodel/interactive/documentnavigation/package.html
new file mode 100644
index 0000000..b210cf5
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/interactive/documentnavigation/package.html
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+
+</head>
+<body>
+A package to allow access to document level navigation within a PDF document.
+</body>
+</html>
diff --git a/src/main/java/org/pdfbox/pdmodel/interactive/form/PDAcroForm.java b/src/main/java/org/pdfbox/pdmodel/interactive/form/PDAcroForm.java
new file mode 100644
index 0000000..4fb576d
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/interactive/form/PDAcroForm.java
@@ -0,0 +1,328 @@
+/**
+ * Copyright (c) 2003-2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.interactive.form;
+
+import org.pdfbox.cos.COSArray;
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSName;
+import org.pdfbox.cos.COSString;
+
+import org.pdfbox.pdmodel.PDDocument;
+import org.pdfbox.pdmodel.PDResources;
+
+import org.pdfbox.pdmodel.fdf.FDFDictionary;
+import org.pdfbox.pdmodel.fdf.FDFDocument;
+import org.pdfbox.pdmodel.fdf.FDFCatalog;
+import org.pdfbox.pdmodel.fdf.FDFField;
+
+import java.io.IOException;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * This class represents the acroform of a PDF document.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.8 $
+ */
+public class PDAcroForm
+{
+ private COSDictionary acroForm;
+ private PDDocument document;
+
+ private Map fieldCache;
+
+ /**
+ * Constructor.
+ *
+ * @param doc The document that this form is part of.
+ */
+ public PDAcroForm( PDDocument doc )
+ {
+ document = doc;
+ acroForm = new COSDictionary();
+ COSArray fields = new COSArray();
+ acroForm.setItem( COSName.getPDFName( "Fields" ), fields );
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param doc The document that this form is part of.
+ * @param form The existing acroForm.
+ */
+ public PDAcroForm( PDDocument doc, COSDictionary form )
+ {
+ document = doc;
+ acroForm = form;
+ }
+
+ /**
+ * This will get the document associated with this form.
+ *
+ * @return The PDF document.
+ */
+ public PDDocument getDocument()
+ {
+ return document;
+ }
+
+ /**
+ * This will get the dictionary that this form wraps.
+ *
+ * @return The dictionary for this form.
+ */
+ public COSDictionary getDictionary()
+ {
+ return acroForm;
+ }
+
+ /**
+ * This method will import an entire FDF document into the PDF document
+ * that this acroform is part of.
+ *
+ * @param fdf The FDF document to import.
+ *
+ * @throws IOException If there is an error doing the import.
+ */
+ public void importFDF( FDFDocument fdf ) throws IOException
+ {
+ List fields = fdf.getCatalog().getFDF().getFields();
+ if( fields != null )
+ {
+ for( int i=0; i<fields.size(); i++ )
+ {
+ FDFField fdfField = (FDFField)fields.get( i );
+ PDField docField = getField( fdfField.getPartialFieldName() );
+ if( docField != null )
+ {
+ docField.importFDF( fdfField );
+ }
+ }
+ }
+ }
+
+ /**
+ * This will export all FDF form data.
+ *
+ * @return An FDF document used to export the document.
+ * @throws IOException If there is an error when exporting the document.
+ */
+ public FDFDocument exportFDF() throws IOException
+ {
+ FDFDocument fdf = new FDFDocument();
+ FDFCatalog catalog = fdf.getCatalog();
+ FDFDictionary fdfDict = new FDFDictionary();
+ catalog.setFDF( fdfDict );
+
+ List fdfFields = new ArrayList();
+ List fields = getFields();
+ Iterator fieldIter = fields.iterator();
+ while( fieldIter.hasNext() )
+ {
+ PDField docField = (PDField)fieldIter.next();
+ addFieldAndChildren( docField, fdfFields );
+ }
+ fdfDict.setID( document.getDocument().getDocumentID() );
+ if( fdfFields.size() > 0 )
+ {
+ fdfDict.setFields( fdfFields );
+ }
+ return fdf;
+ }
+
+ private void addFieldAndChildren( PDField docField, List fdfFields ) throws IOException
+ {
+ Object fieldValue = docField.getValue();
+ FDFField fdfField = new FDFField();
+ fdfField.setPartialFieldName( docField.getPartialName() );
+ fdfField.setValue( fieldValue );
+ List kids = docField.getKids();
+ List childFDFFields = new ArrayList();
+ if( kids != null )
+ {
+
+ for( int i=0; i<kids.size(); i++ )
+ {
+ addFieldAndChildren( (PDField)kids.get( i ), childFDFFields );
+ }
+ if( childFDFFields.size() > 0 )
+ {
+ fdfField.setKids( childFDFFields );
+ }
+ }
+ if( fieldValue != null || childFDFFields.size() > 0 )
+ {
+ fdfFields.add( fdfField );
+ }
+ }
+
+ /**
+ * This will return all of the fields in the document. The type
+ * will be a org.pdfbox.pdmodel.field.PDField.
+ *
+ * @return A list of all the fields.
+ * @throws IOException If there is an error while getting the list of fields.
+ */
+ public List getFields() throws IOException
+ {
+ COSArray fields =
+ (COSArray) acroForm.getDictionaryObject(
+ COSName.getPDFName("Fields"));
+
+ List retval = new ArrayList();
+ for (int i = 0; i < fields.size(); i++)
+ {
+ COSDictionary element = (COSDictionary) fields.getObject(i);
+ if (element != null)
+ {
+ PDField field = PDFieldFactory.createField( this, element );
+ if( field != null )
+ {
+ retval.add(field);
+ }
+ }
+ }
+ return retval;
+ }
+
+ /**
+ * This will tell this form to cache the fields into a Map structure
+ * for fast access via the getField method. The default is false. You would
+ * want this to be false if you were changing the COSDictionary behind the scenes,
+ * otherwise setting this to true is acceptable.
+ *
+ * @param cache A boolean telling if we should cache the fields.
+ * @throws IOException If there is an error while caching the fields.
+ */
+ public void setCacheFields( boolean cache ) throws IOException
+ {
+ if( cache )
+ {
+ fieldCache = new HashMap();
+ List fields = getFields();
+ Iterator fieldIter = fields.iterator();
+ while( fieldIter.hasNext() )
+ {
+ PDField next = (PDField)fieldIter.next();
+ fieldCache.put( next.getFullyQualifiedName(), next );
+ }
+ }
+ else
+ {
+ fieldCache = null;
+ }
+ }
+
+ /**
+ * This will tell if this acro form is caching the fields.
+ *
+ * @return true if the fields are being cached.
+ */
+ public boolean isCachingFields()
+ {
+ return fieldCache != null;
+ }
+
+ /**
+ * This will get a field by name, possibly using the cache if setCache is true.
+ *
+ * @param name The name of the field to get.
+ *
+ * @return The field with that name of null if one was not found.
+ *
+ * @throws IOException If there is an error getting the field type.
+ */
+ public PDField getField( String name ) throws IOException
+ {
+ PDField retval = null;
+ if( fieldCache != null )
+ {
+ retval = (PDField)fieldCache.get( name );
+ }
+ else
+ {
+ COSArray fields =
+ (COSArray) acroForm.getDictionaryObject(
+ COSName.getPDFName("Fields"));
+
+ for (int i = 0; i < fields.size() && retval == null; i++)
+ {
+ COSDictionary element = (COSDictionary) fields.getObject(i);
+ if( element != null )
+ {
+ COSString fieldName =
+ (COSString)element.getDictionaryObject( COSName.getPDFName( "T" ) );
+ if( fieldName.getString().equals( name ) )
+ {
+ retval = PDFieldFactory.createField( this, element );
+ }
+ }
+ }
+ }
+ return retval;
+ }
+
+ /**
+ * This will get the default resources for the acro form.
+ *
+ * @return The default resources.
+ */
+ public PDResources getDefaultResources()
+ {
+ PDResources retval = null;
+ COSDictionary dr = (COSDictionary)acroForm.getDictionaryObject( COSName.getPDFName( "DR" ) );
+ if( dr != null )
+ {
+ retval = new PDResources( dr );
+ }
+ return retval;
+ }
+
+ /**
+ * This will set the default resources for the acroform.
+ *
+ * @param dr The new default resources.
+ */
+ public void setDefaultResources( PDResources dr )
+ {
+ COSDictionary drDict = null;
+ if( dr != null )
+ {
+ drDict = dr.getCOSDictionary();
+ }
+ acroForm.setItem( COSName.getPDFName( "DR" ), drDict );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/interactive/form/PDAppearance.java b/src/main/java/org/pdfbox/pdmodel/interactive/form/PDAppearance.java
new file mode 100644
index 0000000..ff18c86
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/interactive/form/PDAppearance.java
@@ -0,0 +1,645 @@
+/**
+ * Copyright (c) 2003-2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.interactive.form;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.pdfbox.cos.COSArray;
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSFloat;
+import org.pdfbox.cos.COSName;
+import org.pdfbox.cos.COSNumber;
+import org.pdfbox.cos.COSStream;
+import org.pdfbox.cos.COSString;
+
+import org.pdfbox.pdfparser.PDFStreamParser;
+import org.pdfbox.pdfwriter.ContentStreamWriter;
+
+import org.pdfbox.pdmodel.PDResources;
+
+import org.pdfbox.pdmodel.common.PDRectangle;
+
+import org.pdfbox.pdmodel.font.PDFont;
+import org.pdfbox.pdmodel.font.PDFontDescriptor;
+import org.pdfbox.pdmodel.font.PDSimpleFont;
+
+import org.pdfbox.pdmodel.interactive.action.PDAdditionalActions;
+import org.pdfbox.pdmodel.interactive.annotation.PDAppearanceDictionary;
+import org.pdfbox.pdmodel.interactive.annotation.PDAppearanceStream;
+import org.pdfbox.pdmodel.interactive.annotation.PDAnnotationWidget;
+
+import org.pdfbox.util.PDFOperator;
+
+/**
+ * This one took me a while, but i'm proud to say that it handles
+ * the appearance of a textbox. This allows you to apply a value to
+ * a field in the document and handle the appearance so that the
+ * value is actually visible too.
+ * The problem was described by Ben Litchfield, the author of the
+ * example: org.pdfbox.examlpes.fdf.ImportFDF. So Ben, here is the
+ * solution.
+ *
+ * @author sug
+ * @author Ben Litchfield (ben@benlitchfield.com)
+ * @version $Revision: 1.17 $
+ */
+public class PDAppearance
+{
+ private PDVariableText parent;
+
+ private String value;
+ private COSString defaultAppearance;
+
+ private PDAcroForm acroForm;
+ private List widgets = new ArrayList();
+
+
+ /**
+ * Constructs a COSAppearnce from the given field.
+ *
+ * @param theAcroForm the acro form that this field is part of.
+ * @param field the field which you wish to control the appearance of
+ * @throws IOException If there is an error creating the appearance.
+ */
+ public PDAppearance( PDAcroForm theAcroForm, PDVariableText field ) throws IOException
+ {
+ acroForm = theAcroForm;
+ parent = field;
+
+ widgets = field.getKids();
+ if( widgets == null )
+ {
+ widgets = new ArrayList();
+ widgets.add( field.getWidget() );
+ }
+
+ defaultAppearance = getDefaultAppearance();
+
+
+ }
+
+ /**
+ * Returns the default apperance of a textbox. If the textbox
+ * does not have one, then it will be taken from the AcroForm.
+ * @return The DA element
+ */
+ private COSString getDefaultAppearance()
+ {
+
+ COSString dap = parent.getDefaultAppearance();
+ if (dap == null)
+ {
+ COSArray kids = (COSArray)parent.getDictionary().getDictionaryObject( "Kids" );
+ if( kids != null && kids.size() > 0 )
+ {
+ COSDictionary firstKid = (COSDictionary)kids.getObject( 0 );
+ dap = (COSString)firstKid.getDictionaryObject( "DA" );
+ }
+ if( dap == null )
+ {
+ dap = (COSString) acroForm.getDictionary().getDictionaryObject(COSName.getPDFName("DA"));
+ }
+ }
+ return dap;
+ }
+
+ private int getQ()
+ {
+ int q = parent.getQ();
+ if( parent.getDictionary().getDictionaryObject( "Q" ) == null )
+ {
+ COSArray kids = (COSArray)parent.getDictionary().getDictionaryObject( "Kids" );
+ if( kids != null && kids.size() > 0 )
+ {
+ COSDictionary firstKid = (COSDictionary)kids.getObject( 0 );
+ COSNumber qNum = (COSNumber)firstKid.getDictionaryObject( "Q" );
+ if( qNum != null )
+ {
+ q = qNum.intValue();
+ }
+ }
+ }
+ return q;
+ }
+
+ /**
+ * Extracts the original appearance stream into a list of tokens.
+ *
+ * @return The tokens in the original appearance stream
+ */
+ private List getStreamTokens( PDAppearanceStream appearanceStream ) throws IOException
+ {
+ List tokens = null;
+ if( appearanceStream != null )
+ {
+ tokens = getStreamTokens( appearanceStream.getStream() );
+ }
+ return tokens;
+ }
+
+ private List getStreamTokens( COSString string ) throws IOException
+ {
+ PDFStreamParser parser;
+
+ List tokens = null;
+ if( string != null )
+ {
+ ByteArrayInputStream stream = new ByteArrayInputStream( string.getBytes() );
+ parser = new PDFStreamParser( stream, acroForm.getDocument().getDocument().getScratchFile() );
+ parser.parse();
+ tokens = parser.getTokens();
+ }
+ return tokens;
+ }
+
+ private List getStreamTokens( COSStream stream ) throws IOException
+ {
+ PDFStreamParser parser;
+
+ List tokens = null;
+ if( stream != null )
+ {
+ parser = new PDFStreamParser( stream );
+ parser.parse();
+ tokens = parser.getTokens();
+ }
+ return tokens;
+ }
+
+ /**
+ * Tests if the apperance stream already contains content.
+ *
+ * @return true if it contains any content
+ */
+ private boolean containsMarkedContent( List stream )
+ {
+ return stream.contains( PDFOperator.getOperator( "BMC" ) );
+ }
+
+ /**
+ * This is the public method for setting the appearance stream.
+ *
+ * @param apValue the String value which the apperance shoud represent
+ *
+ * @throws IOException If there is an error creating the stream.
+ */
+ public void setAppearanceValue(String apValue) throws IOException
+ {
+ // MulitLine check and set
+ if ( parent.isMultiline() && apValue.indexOf('\n') != -1 )
+ {
+ apValue = convertToMultiLine( apValue );
+ }
+
+ value = apValue;
+ Iterator widgetIter = widgets.iterator();
+ while( widgetIter.hasNext() )
+ {
+ Object next = widgetIter.next();
+ PDAnnotationWidget widget = null;
+ if( next instanceof PDField )
+ {
+ widget = ((PDField)next).getWidget();
+ }
+ else
+ {
+ widget = (PDAnnotationWidget)next;
+ }
+ PDAdditionalActions actions = widget.getActions();
+ if( actions != null &&
+ actions.getF() != null &&
+ widget.getDictionary().getDictionaryObject( "AP" ) ==null)
+ {
+ //do nothing because the field will be formatted by acrobat
+ //when it is opened. See FreedomExpressions.pdf for an example of this.
+ }
+ else
+ {
+
+ PDAppearanceDictionary appearance = widget.getAppearance();
+ if( appearance == null )
+ {
+ appearance = new PDAppearanceDictionary();
+ widget.setAppearance( appearance );
+ }
+
+ Map normalAppearance = appearance.getNormalAppearance();
+ PDAppearanceStream appearanceStream = (PDAppearanceStream)normalAppearance.get( "default" );
+ if( appearanceStream == null )
+ {
+ COSStream cosStream = new COSStream( acroForm.getDocument().getDocument().getScratchFile() );
+ appearanceStream = new PDAppearanceStream( cosStream );
+ appearanceStream.setBoundingBox( widget.getRectangle().createRetranslatedRectangle() );
+ appearance.setNormalAppearance( appearanceStream );
+ }
+
+ List tokens = getStreamTokens( appearanceStream );
+ List daTokens = getStreamTokens( getDefaultAppearance() );
+ PDFont pdFont = getFontAndUpdateResources( tokens, appearanceStream );
+
+ if (!containsMarkedContent( tokens ))
+ {
+ ByteArrayOutputStream output = new ByteArrayOutputStream();
+
+ //BJL 9/25/2004 Must prepend existing stream
+ //because it might have operators to draw things like
+ //rectangles and such
+ ContentStreamWriter writer = new ContentStreamWriter( output );
+ writer.writeTokens( tokens );
+
+ output.write( " /Tx BMC\n".getBytes() );
+ insertGeneratedAppearance( widget, output, pdFont, tokens, appearanceStream );
+ output.write( " EMC".getBytes() );
+ writeToStream( output.toByteArray(), appearanceStream );
+ }
+ else
+ {
+ if( tokens != null )
+ {
+ if( daTokens != null )
+ {
+ int bmcIndex = tokens.indexOf( PDFOperator.getOperator( "BMC" ));
+ int emcIndex = tokens.indexOf( PDFOperator.getOperator( "EMC" ));
+ if( bmcIndex != -1 && emcIndex != -1 &&
+ emcIndex == bmcIndex+1 )
+ {
+ //if the EMC immediately follows the BMC index then should
+ //insert the daTokens inbetween the two markers.
+ tokens.addAll( emcIndex, daTokens );
+ }
+ }
+ ByteArrayOutputStream output = new ByteArrayOutputStream();
+ ContentStreamWriter writer = new ContentStreamWriter( output );
+ float fontSize = calculateFontSize( pdFont, appearanceStream.getBoundingBox(), tokens, null );
+ boolean foundString = false;
+ for( int i=0; i<tokens.size(); i++ )
+ {
+ if( tokens.get( i ) instanceof COSString )
+ {
+ foundString = true;
+ COSString drawnString =((COSString)tokens.get(i));
+ drawnString.reset();
+ drawnString.append( apValue.getBytes() );
+ }
+ }
+ int setFontIndex = tokens.indexOf( PDFOperator.getOperator( "Tf" ));
+ tokens.set( setFontIndex-1, new COSFloat( fontSize ) );
+ if( foundString )
+ {
+ writer.writeTokens( tokens );
+ }
+ else
+ {
+ int bmcIndex = tokens.indexOf( PDFOperator.getOperator( "BMC" ) );
+ int emcIndex = tokens.indexOf( PDFOperator.getOperator( "EMC" ) );
+
+ if( bmcIndex != -1 )
+ {
+ writer.writeTokens( tokens, 0, bmcIndex+1 );
+ }
+ else
+ {
+ writer.writeTokens( tokens );
+ }
+ output.write( "\n".getBytes() );
+ insertGeneratedAppearance( widget, output,
+ pdFont, tokens, appearanceStream );
+ if( emcIndex != -1 )
+ {
+ writer.writeTokens( tokens, emcIndex, tokens.size() );
+ }
+ }
+ writeToStream( output.toByteArray(), appearanceStream );
+ }
+ else
+ {
+ //hmm?
+ }
+ }
+ }
+ }
+ }
+
+ private void insertGeneratedAppearance( PDAnnotationWidget fieldWidget, OutputStream output,
+ PDFont pdFont, List tokens, PDAppearanceStream appearanceStream ) throws IOException
+ {
+ PrintWriter printWriter = new PrintWriter( output, true );
+ float fontSize = 0.0f;
+ PDRectangle boundingBox = null;
+ boundingBox = appearanceStream.getBoundingBox();
+ if( boundingBox == null )
+ {
+ boundingBox = fieldWidget.getRectangle().createRetranslatedRectangle();
+ }
+ printWriter.println( "BT" );
+ if( defaultAppearance != null )
+ {
+ String daString = defaultAppearance.getString();
+ PDFStreamParser daParser = new PDFStreamParser(new ByteArrayInputStream( daString.getBytes() ), null );
+ daParser.parse();
+ List daTokens = daParser.getTokens();
+ fontSize = calculateFontSize( pdFont, boundingBox, tokens, daTokens );
+ int fontIndex = daTokens.indexOf( PDFOperator.getOperator( "Tf" ) );
+ if(fontIndex != -1 )
+ {
+ daTokens.set( fontIndex-1, new COSFloat( fontSize ) );
+ }
+ ContentStreamWriter daWriter = new ContentStreamWriter(output);
+ daWriter.writeTokens( daTokens );
+ }
+ printWriter.println( getTextPosition( boundingBox, pdFont, fontSize, tokens ) );
+ int q = getQ();
+ if( q == PDTextbox.QUADDING_LEFT )
+ {
+ //do nothing because left is default
+ }
+ else if( q == PDTextbox.QUADDING_CENTERED ||
+ q == PDTextbox.QUADDING_RIGHT )
+ {
+ float fieldWidth = boundingBox.getWidth();
+ float stringWidth = (pdFont.getStringWidth( value )/1000)*fontSize;
+ float adjustAmount = fieldWidth - stringWidth - 4;
+
+ if( q == PDTextbox.QUADDING_CENTERED )
+ {
+ adjustAmount = adjustAmount/2.0f;
+ }
+
+ printWriter.println( adjustAmount + " 0 Td" );
+ }
+ else
+ {
+ throw new IOException( "Error: Unknown justification value:" + q );
+ }
+ printWriter.println("(" + value + ") Tj");
+ printWriter.println("ET" );
+ printWriter.flush();
+ }
+
+ private PDFont getFontAndUpdateResources( List tokens, PDAppearanceStream appearanceStream ) throws IOException
+ {
+
+ PDFont retval = null;
+ PDResources streamResources = appearanceStream.getResources();
+ PDResources formResources = acroForm.getDefaultResources();
+ if( formResources != null )
+ {
+ if( streamResources == null )
+ {
+ streamResources = new PDResources();
+ appearanceStream.setResources( streamResources );
+ }
+
+ COSString da = getDefaultAppearance();
+ if( da != null )
+ {
+ String data = da.getString();
+ PDFStreamParser streamParser = new PDFStreamParser(
+ new ByteArrayInputStream( data.getBytes() ), null );
+ streamParser.parse();
+ tokens = streamParser.getTokens();
+ }
+
+ int setFontIndex = tokens.indexOf( PDFOperator.getOperator( "Tf" ));
+ COSName cosFontName = (COSName)tokens.get( setFontIndex-2 );
+ String fontName = cosFontName.getName();
+ retval = (PDFont)streamResources.getFonts().get( fontName );
+ if( retval == null )
+ {
+ retval = (PDFont)formResources.getFonts().get( fontName );
+ streamResources.getFonts().put( fontName, retval );
+ }
+ }
+ return retval;
+ }
+
+ private String convertToMultiLine( String line )
+ {
+ int currIdx = 0;
+ int lastIdx = 0;
+ StringBuffer result = new StringBuffer(line.length() + 64);
+ while( (currIdx = line.indexOf('\n',lastIdx )) > -1 )
+ {
+ result.append(value.substring(lastIdx,currIdx));
+ result.append(" ) Tj\n0 -13 Td\n(");
+ lastIdx = currIdx + 1;
+ }
+ result.append(line.substring(lastIdx));
+ return result.toString();
+ }
+
+ /**
+ * Writes the stream to the actual stream in the COSStream.
+ *
+ * @throws IOException If there is an error writing to the stream
+ */
+ private void writeToStream( byte[] data, PDAppearanceStream appearanceStream ) throws IOException
+ {
+ OutputStream out = appearanceStream.getStream().createUnfilteredStream();
+ out.write( data );
+ out.flush();
+ }
+
+
+ /**
+ * w in an appearance stream represents the lineWidth.
+ * @return the linewidth
+ */
+ private float getLineWidth( List tokens )
+ {
+
+ float retval = 1;
+ if( tokens != null )
+ {
+ int btIndex = tokens.indexOf(PDFOperator.getOperator( "BT" ));
+ int wIndex = tokens.indexOf(PDFOperator.getOperator( "w" ));
+ //the w should only be used if it is before the first BT.
+ if( (wIndex > 0) && (wIndex < btIndex) )
+ {
+ retval = ((COSNumber)tokens.get(wIndex-1)).floatValue();
+ }
+ }
+ return retval;
+ }
+
+ private PDRectangle getSmallestDrawnRectangle( PDRectangle boundingBox, List tokens )
+ {
+ PDRectangle smallest = boundingBox;
+ for( int i=0; i<tokens.size(); i++ )
+ {
+ Object next = tokens.get( i );
+ if( next == PDFOperator.getOperator( "re" ) )
+ {
+ COSNumber x = (COSNumber)tokens.get( i-4 );
+ COSNumber y = (COSNumber)tokens.get( i-3 );
+ COSNumber width = (COSNumber)tokens.get( i-2 );
+ COSNumber height = (COSNumber)tokens.get( i-1 );
+ PDRectangle potentialSmallest = new PDRectangle();
+ potentialSmallest.setLowerLeftX( x.floatValue() );
+ potentialSmallest.setLowerLeftY( y.floatValue() );
+ potentialSmallest.setUpperRightX( x.floatValue() + width.floatValue() );
+ potentialSmallest.setUpperRightY( y.floatValue() + height.floatValue() );
+ if( smallest == null ||
+ smallest.getLowerLeftX() < potentialSmallest.getLowerLeftX() ||
+ smallest.getUpperRightY() > potentialSmallest.getUpperRightY() )
+ {
+ smallest = potentialSmallest;
+ }
+
+ }
+ }
+ return smallest;
+ }
+
+ /**
+ * My "not so great" method for calculating the fontsize.
+ * It does not work superb, but it handles ok.
+ * @return the calculated font-size
+ *
+ * @throws IOException If there is an error getting the font height.
+ */
+ private float calculateFontSize( PDFont pdFont, PDRectangle boundingBox, List tokens, List daTokens )
+ throws IOException
+ {
+ float fontSize = 0;
+ if( daTokens != null )
+ {
+ //daString looks like "BMC /Helv 3.4 Tf EMC"
+
+ int fontIndex = daTokens.indexOf( PDFOperator.getOperator( "Tf" ) );
+ if(fontIndex != -1 )
+ {
+ fontSize = ((COSNumber)daTokens.get(fontIndex-1)).floatValue();
+ }
+ }
+ if( parent.doNotScroll() )
+ {
+ //if we don't scroll then we will shrink the font to fit into the text area.
+ float widthAtFontSize1 = pdFont.getStringWidth( value );
+ float availableWidth = boundingBox.getWidth();
+ float perfectFitFontSize = availableWidth / widthAtFontSize1;
+ }
+ else if( fontSize == 0 )
+ {
+ float lineWidth = getLineWidth( tokens );
+ float stringWidth = pdFont.getStringWidth( value );
+ float height = 0;
+ if( pdFont instanceof PDSimpleFont )
+ {
+ height = ((PDSimpleFont)pdFont).getFontDescriptor().getFontBoundingBox().getHeight();
+ }
+ else
+ {
+ //now much we can do, so lets assume font is square and use width
+ //as the height
+ height = pdFont.getAverageFontWidth();
+ }
+ height = height/1000f;
+
+ float availHeight = getAvailableHeight( boundingBox, lineWidth );
+ fontSize =(availHeight/height);
+ }
+ return fontSize;
+ }
+
+ /**
+ * Calculates where to start putting the text in the box.
+ * The positioning is not quite as accurate as when Acrobat
+ * places the elements, but it works though.
+ *
+ * @return the sting for representing the start position of the text
+ *
+ * @throws IOException If there is an error calculating the text position.
+ */
+ private String getTextPosition( PDRectangle boundingBox, PDFont pdFont, float fontSize, List tokens )
+ throws IOException
+ {
+ float lineWidth = getLineWidth( tokens );
+ float pos = 0.0f;
+ if(parent.isMultiline())
+ {
+ int rows = (int) (getAvailableHeight( boundingBox, lineWidth ) / ((int) fontSize));
+ pos = ((rows)*fontSize)-fontSize;
+ }
+ else
+ {
+ if( pdFont instanceof PDSimpleFont )
+ {
+ //BJL 9/25/2004
+ //This algorithm is a little bit of black magic. It does
+ //not appear to be documented anywhere. Through examining a few
+ //PDF documents and the value that Acrobat places in there I
+ //have determined that the below method of computing the position
+ //is correct for certain documents, but maybe not all. It does
+ //work f1040ez.pdf and Form_1.pdf
+ PDFontDescriptor fd = ((PDSimpleFont)pdFont).getFontDescriptor();
+ float bBoxHeight = boundingBox.getHeight();
+ float fontHeight = fd.getFontBoundingBox().getHeight() + 2 * fd.getDescent();
+ fontHeight = (fontHeight/1000) * fontSize;
+ pos = (bBoxHeight - fontHeight)/2;
+ }
+ else
+ {
+ throw new IOException( "Error: Don't know how to calculate the position for non-simple fonts" );
+ }
+ }
+ PDRectangle innerBox = getSmallestDrawnRectangle( boundingBox, tokens );
+ float xInset = 2+ 2*(boundingBox.getWidth() - innerBox.getWidth());
+ return Math.round(xInset) + " "+ pos + " Td";
+ }
+
+ /**
+ * calculates the available width of the box.
+ * @return the calculated available width of the box
+ */
+ private float getAvailableWidth( PDRectangle boundingBox, float lineWidth )
+ {
+ return boundingBox.getWidth() - 2 * lineWidth;
+ }
+
+ /**
+ * calculates the available height of the box.
+ * @return the calculated available height of the box
+ */
+ private float getAvailableHeight( PDRectangle boundingBox, float lineWidth )
+ {
+ return boundingBox.getHeight() - 2 * lineWidth;
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/interactive/form/PDCheckbox.java b/src/main/java/org/pdfbox/pdmodel/interactive/form/PDCheckbox.java
new file mode 100644
index 0000000..2e175d0
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/interactive/form/PDCheckbox.java
@@ -0,0 +1,187 @@
+/**
+ * Copyright (c) 2003-2005, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.interactive.form;
+
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSName;
+
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * A class for handling the PDF field as a checkbox.
+ *
+ * @author sug
+ * @version $Revision: 1.10 $
+ */
+public class PDCheckbox extends PDChoiceButton
+{
+ private static final COSName KEY = COSName.getPDFName("AS");
+ private static final COSName OFF_VALUE = COSName.getPDFName("Off");
+
+ private COSName value;
+
+ /**
+ * @see PDField#PDField(PDAcroForm,COSDictionary)
+ *
+ * @param theAcroForm The acroForm for this field.
+ * @param field The checkbox field dictionary
+ */
+ public PDCheckbox( PDAcroForm theAcroForm, COSDictionary field)
+ {
+ super( theAcroForm, field);
+ COSDictionary ap = (COSDictionary) field.getDictionaryObject(COSName.getPDFName("AP"));
+ if( ap != null )
+ {
+ COSBase n = ap.getDictionaryObject(COSName.getPDFName("N"));
+
+ if( n instanceof COSDictionary )
+ {
+ List li = ((COSDictionary)n).keyList();
+ for( int i=0; i<li.size(); i++ )
+ {
+ COSName name = (COSName)li.get( i );
+ if( !name.equals( OFF_VALUE ))
+ {
+ value = name;
+ }
+ }
+
+ }
+ }
+ else
+ {
+ value = (COSName)getDictionary().getDictionaryObject( "V" );
+ }
+ }
+
+ /**
+ * This will tell if this radio button is currently checked or not.
+ *
+ * @return true If the radio button is checked.
+ */
+ public boolean isChecked()
+ {
+ boolean retval = false;
+ String onValue = getOnValue();
+ COSName radioValue = (COSName)getDictionary().getDictionaryObject( KEY );
+ if( radioValue != null && value != null && radioValue.getName().equals( onValue ) )
+ {
+ retval = true;
+ }
+
+ return retval;
+ }
+
+ /**
+ * Checks the radiobutton.
+ */
+ public void check()
+ {
+ getDictionary().setItem(KEY, value);
+ }
+
+ /**
+ * Unchecks the radiobutton.
+ */
+ public void unCheck()
+ {
+ getDictionary().setItem(KEY, OFF_VALUE);
+ }
+
+ /**
+ * @see org.pdfbox.pdmodel.interactive.form.PDField#setValue(java.lang.String)
+ */
+ public void setValue(String newValue)
+ {
+ getDictionary().setName( "V", newValue );
+ if( newValue == null )
+ {
+ getDictionary().setItem( KEY, OFF_VALUE );
+ }
+ else
+ {
+ getDictionary().setName( KEY, newValue );
+ }
+ }
+
+ /**
+ * This will get the value of the radio button.
+ *
+ * @return The value of the radio button.
+ */
+ public String getOffValue()
+ {
+ return OFF_VALUE.getName();
+ }
+
+ /**
+ * This will get the value of the radio button.
+ *
+ * @return The value of the radio button.
+ */
+ public String getOnValue()
+ {
+ String retval = null;
+ COSDictionary ap = (COSDictionary) getDictionary().getDictionaryObject(COSName.getPDFName("AP"));
+ COSBase n = ap.getDictionaryObject(COSName.getPDFName("N"));
+
+ //N can be a COSDictionary or a COSStream
+ if( n instanceof COSDictionary )
+ {
+ Iterator li = ((COSDictionary)n).keyList().iterator();
+ while( li.hasNext() )
+ {
+ Object key = li.next();
+ if( !key.equals( OFF_VALUE) )
+ {
+ retval = ((COSName)key).getName();
+ }
+ }
+ }
+ return retval;
+ }
+
+ /**
+ * getValue gets the fields value to as a string.
+ *
+ * @return The string value of this field.
+ *
+ * @throws IOException If there is an error getting the value.
+ */
+ public String getValue() throws IOException
+ {
+ return getDictionary().getNameAsString( "V" );
+ }
+
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/interactive/form/PDChoiceButton.java b/src/main/java/org/pdfbox/pdmodel/interactive/form/PDChoiceButton.java
new file mode 100644
index 0000000..5196d85
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/interactive/form/PDChoiceButton.java
@@ -0,0 +1,95 @@
+/**
+ * Copyright (c) 2003, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.interactive.form;
+
+import org.pdfbox.cos.COSArray;
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSName;
+import org.pdfbox.cos.COSString;
+
+import org.pdfbox.pdmodel.common.COSArrayList;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This holds common functionality for check boxes and radio buttons.
+ *
+ * @author sug
+ * @version $Revision: 1.4 $
+ */
+public abstract class PDChoiceButton extends PDField
+{
+
+ /**
+ * @see PDField#PDField(PDAcroForm,org.pdfbox.cos.COSDictionary)
+ *
+ * @param theAcroForm The acroForm for this field.
+ * @param field The field for this button.
+ */
+ public PDChoiceButton( PDAcroForm theAcroForm, COSDictionary field)
+ {
+ super(theAcroForm, field);
+ }
+
+ /**
+ * This will get the option values "Opt" entry of the pdf button.
+ *
+ * @return A list of java.lang.String values.
+ */
+ public List getOptions()
+ {
+ List retval = null;
+ COSArray array = (COSArray)getDictionary().getDictionaryObject( COSName.getPDFName( "Opt" ) );
+ if( array != null )
+ {
+ List strings = new ArrayList();
+ for( int i=0; i<array.size(); i++ )
+ {
+ strings.add( ((COSString)array.getObject( i )).getString() );
+ }
+ retval = new COSArrayList( strings, array );
+ }
+ return retval;
+ }
+
+ /**
+ * This will will set the list of options for this button.
+ *
+ * @param options The list of options for the button.
+ */
+ public void setOptions( List options )
+ {
+ getDictionary().setItem(
+ COSName.getPDFName( "Opt" ),
+ COSArrayList.converterToCOSArray( options ) );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/interactive/form/PDChoiceField.java b/src/main/java/org/pdfbox/pdmodel/interactive/form/PDChoiceField.java
new file mode 100644
index 0000000..ff02cc6
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/interactive/form/PDChoiceField.java
@@ -0,0 +1,127 @@
+/**
+ * Copyright (c) 2003-2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.interactive.form;
+
+import java.io.IOException;
+
+import org.pdfbox.cos.COSArray;
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSName;
+import org.pdfbox.cos.COSString;
+import org.pdfbox.cos.COSInteger;
+
+/**
+ * A class for handling the PDF field as a choicefield.
+ *
+ * @author sug
+ * @version $Revision: 1.6 $
+ */
+public class PDChoiceField extends PDVariableText
+{
+
+ /**
+ * @see org.pdfbox.pdmodel.field.PDField#COSField(org.pdfbox.cos.COSDictionary)
+ *
+ * @param theAcroForm The acroForm for this field.
+ * @param field The field for this choice field.
+ */
+ public PDChoiceField( PDAcroForm theAcroForm, COSDictionary field)
+ {
+ super(theAcroForm, field);
+ }
+
+ /**
+ * @see org.pdfbox.pdmodel.field.PDField#setValue(java.lang.String)
+ *
+ * @param optionValue The new value for this text field.
+ *
+ * @throws IOException If there is an error calculating the appearance stream or the value in not one
+ * of the existing options.
+ */
+ public void setValue(String optionValue) throws IOException
+ {
+ int indexSelected = -1;
+ COSArray options = (COSArray)getDictionary().getDictionaryObject( "Opt" );
+ if( options.size() == 0 )
+ {
+ throw new IOException( "Error: You cannot set a value for a choice field if there are no options." );
+ }
+ else
+ {
+ COSBase option = options.getObject( 0 );
+ if( option instanceof COSArray )
+ {
+ for( int i=0; i<options.size() && indexSelected == -1; i++ )
+ {
+ COSArray keyValuePair = (COSArray)options.get( i );
+ COSString key = (COSString)keyValuePair.getObject( 0 );
+ COSString value = (COSString)keyValuePair.getObject( 1 );
+ if( optionValue.equals( key.getString() ) || optionValue.equals( value.getString() ) )
+ {
+ //have the parent draw the appearance stream with the value
+ super.setValue( value.getString() );
+ //but then use the key as the V entry
+ getDictionary().setItem( COSName.getPDFName( "V" ), key );
+ indexSelected = i;
+ }
+ }
+ }
+ else
+ {
+ for( int i=0; i<options.size() && indexSelected == -1; i++ )
+ {
+ COSString value = (COSString)options.get( i );
+ if( optionValue.equals( value.getString() ) )
+ {
+ setValue( optionValue );
+ indexSelected = i;
+ }
+ }
+ }
+ }
+ if( indexSelected == -1 )
+ {
+ throw new IOException( "Error: '" + optionValue + "' was not an available option.");
+ }
+ else
+ {
+ COSArray indexArray = (COSArray)getDictionary().getDictionaryObject( "I" );
+ if( indexArray != null )
+ {
+ indexArray.clear();
+ indexArray.add( new COSInteger( indexSelected ) );
+ }
+ }
+ }
+
+
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/interactive/form/PDField.java b/src/main/java/org/pdfbox/pdmodel/interactive/form/PDField.java
new file mode 100644
index 0000000..c395794
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/interactive/form/PDField.java
@@ -0,0 +1,610 @@
+/**
+ * Copyright (c) 2003, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.interactive.form;
+
+import org.pdfbox.pdmodel.interactive.action.PDFormFieldAdditionalActions;
+import org.pdfbox.pdmodel.interactive.annotation.PDAnnotationWidget;
+
+import org.pdfbox.pdmodel.common.COSArrayList;
+import org.pdfbox.pdmodel.common.COSObjectable;
+
+import org.pdfbox.cos.COSArray;
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSInteger;
+import org.pdfbox.cos.COSName;
+
+import org.pdfbox.pdmodel.common.PDTextStream;
+
+import org.pdfbox.pdmodel.fdf.FDFField;
+import org.pdfbox.util.BitFlagHelper;
+
+import java.io.IOException;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This is the superclass for a Field element in a PDF.
+ * Based on the COS object model from PDFBox.
+ *
+ * @author sug
+ * @version $Revision: 1.21 $
+ */
+public abstract class PDField implements COSObjectable
+{
+ /**
+ * A Ff flag.
+ */
+ public static final int FLAG_READ_ONLY = 1;
+ /**
+ * A Ff flag.
+ */
+ public static final int FLAG_REQUIRED = 1 << 1;
+ /**
+ * A Ff flag.
+ */
+ public static final int FLAG_NO_EXPORT = 1 << 2;
+
+
+ private PDAcroForm acroForm;
+
+ private COSDictionary dictionary;
+
+ /**
+ * Constructor.
+ *
+ * @param theAcroForm The form that this field is part of.
+ */
+ public PDField( PDAcroForm theAcroForm )
+ {
+ acroForm = theAcroForm;
+ dictionary = new COSDictionary();
+ //no required fields in base field class
+ }
+
+
+ /**
+ * Creates a COSField from a COSDictionary, expected to be
+ * a correct object definition for a field in PDF.
+ *
+ * @param theAcroForm The form that this field is part of.
+ * @param field the PDF objet to represent as a field.
+ */
+ public PDField(PDAcroForm theAcroForm, COSDictionary field)
+ {
+ acroForm = theAcroForm;
+ dictionary = field;
+ }
+
+ /**
+ * Returns the partial name of the field.
+ *
+ * @return the name of the field
+ */
+ public String getPartialName()
+ {
+ return getDictionary().getString( "T" );
+ }
+
+ /**
+ * This will set the partial name of the field.
+ *
+ * @param name The new name for the field.
+ */
+ public void setPartialName( String name )
+ {
+ getDictionary().setString( "T", name );
+ }
+
+ /**
+ * Returns the fully qualified name of the field, which is a concatenation of
+ * the names of all the parents fields.
+ *
+ * @return the name of the field
+ *
+ * @throws IOException If there is an error generating the fully qualified name.
+ */
+ public String getFullyQualifiedName() throws IOException
+ {
+ PDField parent = getParent();
+ String parentName = null;
+ if( parent != null )
+ {
+ parentName = parent.getFullyQualifiedName();
+ }
+ String finalName = getPartialName();
+ if( parentName != null )
+ {
+ finalName = parentName + "." + finalName;
+ }
+ return finalName;
+ }
+
+ /**
+ * Get the FT entry of the field. This is a read only field and is set depending
+ * on the actual type. The field type is an inheritable attribute. This method will
+ * return only the direct value on this object. Use the findFieldType for an upward
+ * recursive search.
+ *
+ * @return The Field type.
+ *
+ * @see PDField#findFieldType()
+ */
+ public String getFieldType()
+ {
+ return getDictionary().getNameAsString( "FT" );
+ }
+
+ /**
+ * Find the field type and optionally do a recursive upward search. Sometimes the fieldtype
+ * will be specified on the parent instead of the direct object. This will look at this
+ * object for the field type, if none is specified then it will look to the parent if there
+ * is a parent. If there is no parent and no field type has been found then this
+ * will return null.
+ *
+ * @return The field type or null if none was found.
+ */
+ public String findFieldType()
+ {
+ return findFieldType( getDictionary() );
+ }
+
+ private String findFieldType( COSDictionary dic )
+ {
+ String retval = dic.getNameAsString( "FT" );
+ if( retval == null )
+ {
+ COSDictionary parent = (COSDictionary)dic.getDictionaryObject( "Parent" );
+ if( parent != null )
+ {
+ retval = findFieldType( parent );
+ }
+ }
+ return retval;
+
+ }
+
+
+ /**
+ * setValue sets the fields value to a given string.
+ *
+ * @param value the string value
+ *
+ * @throws IOException If there is an error creating the appearance stream.
+ */
+ public abstract void setValue(String value) throws IOException;
+
+ /**
+ * getValue gets the fields value to as a string.
+ *
+ * @return The string value of this field.
+ *
+ * @throws IOException If there is an error getting the value.
+ */
+ public abstract String getValue() throws IOException;
+
+ /**
+ * sets the field to be read-only.
+ *
+ * @param readonly The new flag for readonly.
+ */
+ public void setReadonly(boolean readonly)
+ {
+ BitFlagHelper.setFlag( getDictionary(), "Ff", FLAG_READ_ONLY, readonly );
+ }
+
+ /**
+ *
+ * @return true if the field is readonly
+ */
+ public boolean isReadonly()
+ {
+ return BitFlagHelper.getFlag( getDictionary(), "Ff", FLAG_READ_ONLY );
+ }
+
+ /**
+ * sets the field to be required.
+ *
+ * @param required The new flag for required.
+ */
+ public void setRequired(boolean required)
+ {
+ BitFlagHelper.setFlag( getDictionary(), "Ff", FLAG_REQUIRED, required );
+ }
+
+ /**
+ *
+ * @return true if the field is required
+ */
+ public boolean isRequired()
+ {
+ return BitFlagHelper.getFlag( getDictionary(), "Ff", FLAG_REQUIRED );
+ }
+
+ /**
+ * sets the field to be not exported..
+ *
+ * @param noExport The new flag for noExport.
+ */
+ public void setNoExport(boolean noExport)
+ {
+ BitFlagHelper.setFlag( getDictionary(), "Ff", FLAG_NO_EXPORT, noExport );
+ }
+
+ /**
+ *
+ * @return true if the field is not to be exported.
+ */
+ public boolean isNoExport()
+ {
+ return BitFlagHelper.getFlag( getDictionary(), "Ff", FLAG_NO_EXPORT );
+ }
+
+ /**
+ * This will get the flags for this field.
+ *
+ * @return flags The set of flags.
+ */
+ public int getFieldFlags()
+ {
+ int retval = 0;
+ COSInteger ff = (COSInteger)getDictionary().getDictionaryObject( COSName.getPDFName( "Ff" ) );
+ if( ff != null )
+ {
+ retval = ff.intValue();
+ }
+ return retval;
+ }
+
+ /**
+ * This will set the flags for this field.
+ *
+ * @param flags The new flags.
+ */
+ public void setFieldFlags( int flags )
+ {
+ COSInteger ff = new COSInteger( flags );
+ getDictionary().setItem( COSName.getPDFName( "Ff" ), ff );
+ }
+
+ /**
+ * This will import a fdf field from a fdf document.
+ *
+ * @param fdfField The fdf field to import.
+ *
+ * @throws IOException If there is an error importing the data for this field.
+ */
+ public void importFDF( FDFField fdfField ) throws IOException
+ {
+ Object fieldValue = fdfField.getValue();
+ int fieldFlags = getFieldFlags();
+
+ if( fieldValue != null )
+ {
+ if( fieldValue instanceof String )
+ {
+ setValue( (String)fieldValue );
+ }
+ else if( fieldValue instanceof PDTextStream )
+ {
+ setValue( ((PDTextStream)fieldValue).getAsString() );
+ }
+ else
+ {
+ throw new IOException( "Unknown field type:" + fieldValue.getClass().getName() );
+ }
+ }
+ Integer ff = fdfField.getFieldFlags();
+ if( ff != null )
+ {
+ setFieldFlags( ff.intValue() );
+ }
+ else
+ {
+ //these are suppose to be ignored if the Ff is set.
+ Integer setFf = fdfField.getSetFieldFlags();
+
+ if( setFf != null )
+ {
+ int setFfInt = setFf.intValue();
+ fieldFlags = fieldFlags | setFfInt;
+ setFieldFlags( fieldFlags );
+ }
+
+ Integer clrFf = fdfField.getClearFieldFlags();
+ if( clrFf != null )
+ {
+ //we have to clear the bits of the document fields for every bit that is
+ //set in this field.
+ //
+ //Example:
+ //docFf = 1011
+ //clrFf = 1101
+ //clrFfValue = 0010;
+ //newValue = 1011 & 0010 which is 0010
+ int clrFfValue = clrFf.intValue();
+ clrFfValue ^= 0xFFFFFFFF;
+ fieldFlags = fieldFlags & clrFfValue;
+ setFieldFlags( fieldFlags );
+ }
+ }
+
+ PDAnnotationWidget widget = getWidget();
+ if( widget != null )
+ {
+ int annotFlags = widget.getAnnotationFlags();
+ Integer f = fdfField.getWidgetFieldFlags();
+ if( f != null && widget != null )
+ {
+ widget.setAnnotationFlags( f.intValue() );
+ }
+ else
+ {
+ //these are suppose to be ignored if the F is set.
+ Integer setF = fdfField.getSetWidgetFieldFlags();
+ if( setF != null )
+ {
+ annotFlags = annotFlags | setF.intValue();
+ widget.setAnnotationFlags( annotFlags );
+ }
+
+ Integer clrF = fdfField.getClearWidgetFieldFlags();
+ if( clrF != null )
+ {
+ //we have to clear the bits of the document fields for every bit that is
+ //set in this field.
+ //
+ //Example:
+ //docF = 1011
+ //clrF = 1101
+ //clrFValue = 0010;
+ //newValue = 1011 & 0010 which is 0010
+ int clrFValue = clrF.intValue();
+ clrFValue ^= 0xFFFFFFFFL;
+ annotFlags = annotFlags & clrFValue;
+ widget.setAnnotationFlags( annotFlags );
+ }
+ }
+ }
+ List fdfKids = fdfField.getKids();
+ List pdKids = getKids();
+ for( int i=0; fdfKids != null && i<fdfKids.size(); i++ )
+ {
+ FDFField fdfChild = (FDFField)fdfKids.get( i );
+ String fdfName = fdfChild.getPartialFieldName();
+ for( int j=0; j<pdKids.size(); j++ )
+ {
+ Object pdChildObj = pdKids.get( j );
+ if( pdChildObj instanceof PDField )
+ {
+ PDField pdChild = (PDField)pdChildObj;
+ if( fdfName != null && fdfName.equals( pdChild.getPartialName() ) )
+ {
+ pdChild.importFDF( fdfChild );
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * This will get the single associated widget that is part of this field. This
+ * occurs when the Widget is embedded in the fields dictionary. Sometimes there
+ * are multiple sub widgets associated with this field, in which case you want to
+ * use getKids(). If the kids entry is specified, then the first entry in that
+ * list will be returned.
+ *
+ * @return The widget that is associated with this field.
+ * @throws IOException If there is an error getting the widget object.
+ */
+ public PDAnnotationWidget getWidget() throws IOException
+ {
+ PDAnnotationWidget retval = null;
+ List kids = getKids();
+ if( kids == null )
+ {
+ retval = new PDAnnotationWidget( getDictionary() );
+ }
+ else if( kids.size() > 0 )
+ {
+ Object firstKid = kids.get( 0 );
+ if( firstKid instanceof PDAnnotationWidget )
+ {
+ retval = (PDAnnotationWidget)firstKid;
+ }
+ else
+ {
+ retval = ((PDField)firstKid).getWidget();
+ }
+ }
+ else
+ {
+ retval = null;
+ }
+ return retval;
+ }
+
+ /**
+ * Get the parent field to this field, or null if none exists.
+ *
+ * @return The parent field.
+ *
+ * @throws IOException If there is an error creating the parent field.
+ */
+ public PDField getParent() throws IOException
+ {
+ PDField parent = null;
+ COSDictionary parentDic = (COSDictionary)getDictionary().getDictionaryObject( "Parent" );
+ if( parentDic != null )
+ {
+ parent = PDFieldFactory.createField( getAcroForm(), parentDic );
+ }
+ return parent;
+ }
+
+ /**
+ * Set the parent of this field.
+ *
+ * @param parent The parent to this field.
+ */
+ public void setParent( PDField parent )
+ {
+ getDictionary().setItem( "Parent", parent );
+ }
+
+ /**
+ * This will get all the kids of this field. The values in the list
+ * will either be PDWidget or PDField. Normally they will be PDWidget objects
+ * unless this is a non-terminal field and they will be child PDField objects.
+ *
+ * @return A list of either PDWidget or PDField objects.
+ * @throws IOException If there is an error retrieving the kids.
+ */
+ public List getKids() throws IOException
+ {
+ List retval = null;
+ COSArray kids = (COSArray)getDictionary().getDictionaryObject(COSName.KIDS);
+ if( kids != null )
+ {
+ List kidsList = new ArrayList();
+ for (int i = 0; i < kids.size(); i++)
+ {
+ COSDictionary kidDictionary = (COSDictionary)kids.getObject(i);
+ COSDictionary parent = (COSDictionary)kidDictionary.getDictionaryObject( "Parent" );
+ if( kidDictionary.getDictionaryObject( "FT" ) != null ||
+ (parent != null && parent.getDictionaryObject( "FT" ) != null ) )
+ {
+ kidsList.add( PDFieldFactory.createField( acroForm, kidDictionary ));
+ }
+ else if( "Widget".equals( kidDictionary.getNameAsString( "Subtype" ) ) )
+ {
+ kidsList.add( new PDAnnotationWidget( kidDictionary ) );
+ }
+ else
+ {
+ //
+ kidsList.add( PDFieldFactory.createField( acroForm, kidDictionary ));
+ }
+ }
+ retval = new COSArrayList( kidsList, kids );
+ }
+ return retval;
+ }
+
+ /**
+ * This will set the list of kids.
+ *
+ * @param kids The list of child widgets.
+ */
+ public void setKids( List kids )
+ {
+ COSArray kidsArray = COSArrayList.converterToCOSArray( kids );
+ getDictionary().setItem( COSName.KIDS, kidsArray );
+ }
+
+ /**
+ * This will return a string representation of this field.
+ *
+ * @return A string representation of this field.
+ */
+ public String toString()
+ {
+ return "" + getDictionary().getDictionaryObject( COSName.getPDFName( "V" ) );
+ }
+
+ /**
+ * This will get the acroform that this field is part of.
+ *
+ * @return The form this field is on.
+ */
+ public PDAcroForm getAcroForm()
+ {
+ return acroForm;
+ }
+
+ /**
+ * This will set the form this field is on.
+ *
+ * @param value The new form to use.
+ */
+ public void setAcroForm(PDAcroForm value)
+ {
+ acroForm = value;
+ }
+
+ /**
+ * This will get the dictionary associated with this field.
+ *
+ * @return The dictionary that this class wraps.
+ */
+ public COSDictionary getDictionary()
+ {
+ return dictionary;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSBase getCOSObject()
+ {
+ return dictionary;
+ }
+
+ /**
+ * Get the additional actions for this field. This will return null
+ * if there are no additional actions for this field.
+ *
+ * @return The actions of the field.
+ */
+ public PDFormFieldAdditionalActions getActions()
+ {
+ COSDictionary aa = (COSDictionary)dictionary.getDictionaryObject( "AA" );
+ PDFormFieldAdditionalActions retval = null;
+ if( aa != null )
+ {
+ retval = new PDFormFieldAdditionalActions( aa );
+ }
+ return retval;
+ }
+
+ /**
+ * Set the actions of the field.
+ *
+ * @param actions The field actions.
+ */
+ public void setActions( PDFormFieldAdditionalActions actions )
+ {
+ dictionary.setItem( "AA", actions );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/interactive/form/PDFieldFactory.java b/src/main/java/org/pdfbox/pdmodel/interactive/form/PDFieldFactory.java
new file mode 100644
index 0000000..c796714
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/interactive/form/PDFieldFactory.java
@@ -0,0 +1,218 @@
+/**
+ * Copyright (c) 2003-2004, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.interactive.form;
+
+import org.pdfbox.cos.COSArray;
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSName;
+import org.pdfbox.pdmodel.interactive.annotation.PDAnnotationWidget;
+
+import java.io.IOException;
+
+import java.util.List;
+
+/**
+ * This is the Factory for creating and returning the correct
+ * field elements.
+ *
+ * @author sug
+ * @version $Revision: 1.8 $
+ */
+public class PDFieldFactory
+{
+ private static final int RADIO_BITMASK = 32768;
+ private static final int PUSHBUTTON_BITMASK = 65536;
+ private static final int RADIOS_IN_UNISON_BITMASK = 33554432;
+
+ private static final String FIELD_TYPE_BTN = "Btn";
+ private static final String FIELD_TYPE_TX = "Tx";
+ private static final String FIELD_TYPE_CH = "Ch";
+ private static final String FIELD_TYPE_SIG = "Sig";
+
+ /**
+ * Utility class so no constructor.
+ */
+ private PDFieldFactory()
+ {
+ //do nothing.
+ }
+
+ /**
+ * This method creates a COSField subclass from the given field.
+ * The field is a PDF Dictionary object that must represent a
+ * field element. - othewise null is returned
+ *
+ * @param acroForm The form that the field will be part of.
+ * @param field The dictionary representing a field element
+ *
+ * @return a subclass to COSField according to the kind of field passed to createField
+ * @throws IOException If there is an error determining the field type.
+ */
+ public static PDField createField( PDAcroForm acroForm, COSDictionary field) throws IOException
+ {
+ PDField pdField = new PDUnknownField( acroForm, field );
+ if( isButton(pdField) )
+ {
+ int flags = pdField.getFieldFlags();
+ //BJL, I have found that the radio flag bit is not always set
+ //and that sometimes there is just a kids dictionary.
+ //so, if there is a kids dictionary then it must be a radio button
+ //group.
+ COSArray kids = (COSArray)field.getDictionaryObject( COSName.getPDFName( "Kids" ) );
+ if( kids != null || isRadio(flags) )
+ {
+ pdField = new PDRadioCollection( acroForm, field );
+ }
+ else if( isPushButton( flags ) )
+ {
+ pdField = new PDPushButton( acroForm, field );
+ }
+ else
+ {
+ pdField = new PDCheckbox( acroForm, field );
+ }
+
+ }
+ else if (isChoiceField(pdField))
+ {
+ pdField = new PDChoiceField( acroForm, field );
+ }
+ else if (isTextbox(pdField))
+ {
+ pdField = new PDTextbox( acroForm, field );
+ }
+ else if( isSignature( pdField ) )
+ {
+ pdField = new PDSignature( acroForm, field );
+ }
+ else
+ {
+ //do nothing and return an unknown field type.
+ }
+ return pdField;
+ }
+
+ /**
+ * This method determines if the given
+ * field is a radiobutton collection.
+ *
+ * @param flags The field flags.
+ *
+ * @return the result of the determination
+ */
+ private static boolean isRadio( int flags )
+ {
+ return (flags & RADIO_BITMASK) > 0;
+ }
+
+ /**
+ * This method determines if the given
+ * field is a pushbutton.
+ *
+ * @param flags The field flags.
+ *
+ * @return the result of the determination
+ */
+ private static boolean isPushButton( int flags )
+ {
+ return (flags & PUSHBUTTON_BITMASK) > 0;
+ }
+
+ /**
+ * This method determines if the given field is a choicefield
+ * Choicefields are either listboxes or comboboxes.
+ *
+ * @param field the field to determine
+ * @return the result of the determination
+ */
+ private static boolean isChoiceField(PDField field) throws IOException
+ {
+ return FIELD_TYPE_CH.equals(field.findFieldType());
+ }
+
+ /**
+ * This method determines if the given field is a button.
+ *
+ * @param field the field to determine
+ * @return the result of the determination
+ *
+ * @throws IOException If there is an error determining the field type.
+ */
+ private static boolean isButton(PDField field) throws IOException
+ {
+ String ft = field.findFieldType();
+ boolean retval = FIELD_TYPE_BTN.equals( ft );
+ List kids = field.getKids();
+ if( ft == null && kids != null && kids.size() > 0)
+ {
+ //sometimes if it is a button the type is only defined by one
+ //of the kids entries
+ Object obj = kids.get( 0 );
+ COSDictionary kidDict = null;
+ if( obj instanceof PDField )
+ {
+ kidDict = ((PDField)obj).getDictionary();
+ }
+ else if( obj instanceof PDAnnotationWidget )
+ {
+ kidDict = ((PDAnnotationWidget)obj).getDictionary();
+ }
+ else
+ {
+ throw new IOException( "Error:Unexpected type of kids field:" + obj );
+ }
+ retval = isButton( new PDUnknownField( field.getAcroForm(), kidDict ) );
+ }
+ return retval;
+ }
+
+ /**
+ * This method determines if the given field is a signature.
+ *
+ * @param field the field to determine
+ * @return the result of the determination
+ */
+ private static boolean isSignature(PDField field) throws IOException
+ {
+ return FIELD_TYPE_SIG.equals(field.findFieldType());
+ }
+
+ /**
+ * This method determines if the given field is a Textbox.
+ *
+ * @param field the field to determine
+ * @return the result of the determination
+ */
+ private static boolean isTextbox(PDField field) throws IOException
+ {
+ return FIELD_TYPE_TX.equals(field.findFieldType());
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/interactive/form/PDPushButton.java b/src/main/java/org/pdfbox/pdmodel/interactive/form/PDPushButton.java
new file mode 100644
index 0000000..e832921
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/interactive/form/PDPushButton.java
@@ -0,0 +1,84 @@
+/**
+ * Copyright (c) 2003, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.interactive.form;
+
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSName;
+import org.pdfbox.cos.COSString;
+
+import java.io.IOException;
+
+/**
+ * A class for handling the PDF field as a PDPushButton.
+ *
+ * @author sug
+ * @version $Revision: 1.3 $
+ */
+public class PDPushButton extends PDField
+{
+
+ /**
+ * @see org.pdfbox.pdmodel.field.PDField#COSField(org.pdfbox.cos.COSDictionary)
+ *
+ * @param theAcroForm The acroForm for this field.
+ * @param field The field for this push button.
+ */
+ public PDPushButton( PDAcroForm theAcroForm, COSDictionary field)
+ {
+ super(theAcroForm, field);
+ }
+
+ /**
+ * @see as.interactive.pdf.form.cos.COSField#setValue(java.lang.String)
+ *
+ * @param value The new value for the field.
+ *
+ * @throws IOException If there is an error creating the appearance stream.
+ */
+ public void setValue(String value) throws IOException
+ {
+ COSString fieldValue = new COSString(value);
+ getDictionary().setItem( COSName.getPDFName( "V" ), fieldValue );
+ getDictionary().setItem( COSName.getPDFName( "DV" ), fieldValue );
+ }
+
+ /**
+ * getValue gets the fields value to as a string.
+ *
+ * @return The string value of this field.
+ *
+ * @throws IOException If there is an error getting the value.
+ */
+ public String getValue() throws IOException
+ {
+ return getDictionary().getString( "V" );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/interactive/form/PDRadioCollection.java b/src/main/java/org/pdfbox/pdmodel/interactive/form/PDRadioCollection.java
new file mode 100644
index 0000000..27b48d6
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/interactive/form/PDRadioCollection.java
@@ -0,0 +1,170 @@
+/**
+ * Copyright (c) 2003-2005, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.interactive.form;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.pdfbox.cos.COSArray;
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSName;
+
+import org.pdfbox.pdmodel.common.COSArrayList;
+import org.pdfbox.util.BitFlagHelper;
+
+/**
+ * A class for handling the PDF field as a Radio Collection.
+ * This class automatically keeps track of the child radio buttons
+ * in the collection.
+ *
+ * @see PDCheckbox
+ * @author sug
+ * @version $Revision: 1.12 $
+ */
+public class PDRadioCollection extends PDChoiceButton
+{
+ /**
+ * A Ff flag.
+ */
+ public static final int FLAG_RADIOS_IN_UNISON = 1 << 25;
+
+ /**
+ * @see PDField#PDField(PDAcroForm,COSDictionary)
+ *
+ * @param theAcroForm The acroForm for this field.
+ * @param field The field that makes up the radio collection.
+ */
+ public PDRadioCollection( PDAcroForm theAcroForm, COSDictionary field)
+ {
+ super(theAcroForm,field);
+ }
+
+ /**
+ * From the PDF Spec <br/>
+ * If set, a group of radio buttons within a radio button field that
+ * use the same value for the on state will turn on and off in unison; that is if
+ * one is checked, they are all checked. If clear, the buttons are mutually exclusive
+ * (the same behavior as HTML radio buttons).
+ *
+ * @param radiosInUnison The new flag for radiosInUnison.
+ */
+ public void setRadiosInUnison(boolean radiosInUnison)
+ {
+ BitFlagHelper.setFlag( getDictionary(), "Ff", FLAG_RADIOS_IN_UNISON, radiosInUnison );
+ }
+
+ /**
+ *
+ * @return true If the flag is set for radios in unison.
+ */
+ public boolean isRadiosInUnison()
+ {
+ return BitFlagHelper.getFlag( getDictionary(), "Ff", FLAG_RADIOS_IN_UNISON );
+ }
+
+ /**
+ * This setValue method iterates the collection of radiobuttons
+ * and checks or unchecks each radiobutton according to the
+ * given value.
+ * If the value is not represented by any of the radiobuttons,
+ * then none will be checked.
+ *
+ * @see org.pdfbox.pdmodel.interactive.form.PDField#setValue(java.lang.String)
+ */
+ public void setValue(String value) throws IOException
+ {
+ getDictionary().setString( "V", value );
+ List kids = getKids();
+ for (int i = 0; i < kids.size(); i++)
+ {
+ PDCheckbox btn = (PDCheckbox)kids.get(i);
+ if( btn.getOnValue().equals(value) )
+ {
+ btn.check();
+ }
+ else
+ {
+ btn.unCheck();
+ }
+ }
+ }
+
+ /**
+ * getValue gets the fields value to as a string.
+ *
+ * @return The string value of this field.
+ *
+ * @throws IOException If there is an error getting the value.
+ */
+ public String getValue()throws IOException
+ {
+ String retval = null;
+ List kids = getKids();
+ for (int i = 0; i < kids.size(); i++)
+ {
+ PDCheckbox btn = (PDCheckbox)kids.get(i);
+ if( btn.isChecked() )
+ {
+ retval = btn.getOnValue();
+ }
+ }
+ if( retval == null )
+ {
+ retval = getDictionary().getNameAsString( "V" );
+ }
+ return retval;
+ }
+
+
+ /**
+ * This will return a list of PDField objects that are part of this radio collection.
+ *
+ * @see PDField#getWidget()
+ * @return A list of PDWidget objects.
+ * @throws IOException if there is an error while creating the children objects.
+ */
+ public List getKids() throws IOException
+ {
+ List retval = null;
+ COSArray kids = (COSArray)getDictionary().getDictionaryObject(COSName.KIDS);
+ if( kids != null )
+ {
+ List kidsList = new ArrayList();
+ for (int i = 0; i < kids.size(); i++)
+ {
+ kidsList.add( PDFieldFactory.createField( getAcroForm(), (COSDictionary)kids.getObject(i) ) );
+ }
+ retval = new COSArrayList( kidsList, kids );
+ }
+ return retval;
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/interactive/form/PDSignature.java b/src/main/java/org/pdfbox/pdmodel/interactive/form/PDSignature.java
new file mode 100644
index 0000000..66ed3e3
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/interactive/form/PDSignature.java
@@ -0,0 +1,90 @@
+/**
+ * Copyright (c) 2003, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.interactive.form;
+
+import org.pdfbox.cos.COSDictionary;
+
+import java.io.IOException;
+
+/**
+ * A class for handling the PDF field as a signature.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.3 $
+ */
+public class PDSignature extends PDField
+{
+
+ /**
+ * @see org.pdfbox.pdmodel.field.PDField#COSField(org.pdfbox.cos.COSDictionary)
+ *
+ * @param theAcroForm The acroForm for this field.
+ * @param field The dictionary for the signature.
+ */
+ public PDSignature( PDAcroForm theAcroForm, COSDictionary field)
+ {
+ super(theAcroForm,field);
+ }
+
+ /**
+ * @see as.interactive.pdf.form.cos.COSField#setValue(java.lang.String)
+ *
+ * @param value The new value for the field.
+ *
+ * @throws IOException If there is an error creating the appearance stream.
+ */
+ public void setValue(String value) throws IOException
+ {
+ throw new RuntimeException( "Not yet implemented" );
+ }
+
+ /**
+ * @see as.interactive.pdf.form.cos.COSField#setValue(java.lang.String)
+ *
+ * @return The string value of this field.
+ *
+ * @throws IOException If there is an error creating the appearance stream.
+ */
+ public String getValue() throws IOException
+ {
+ throw new RuntimeException( "Not yet implemented" );
+ }
+
+ /**
+ * Return a string rep of this object.
+ *
+ * @return A string rep of this object.
+ */
+ public String toString()
+ {
+ return "PDSignature";
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/interactive/form/PDTextbox.java b/src/main/java/org/pdfbox/pdmodel/interactive/form/PDTextbox.java
new file mode 100644
index 0000000..fd9550e
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/interactive/form/PDTextbox.java
@@ -0,0 +1,64 @@
+/**
+ * Copyright (c) 2003, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.interactive.form;
+
+import org.pdfbox.cos.COSDictionary;
+
+/**
+ * A class for handling the PDF field as a textbox.
+ *
+ * @author sug
+ * @version $Revision: 1.9 $
+ */
+public class PDTextbox extends PDVariableText
+{
+
+ /**
+ * @see PDField#PDField(PDAcroForm,COSDictionary)
+ *
+ * @param theAcroForm The acroform.
+ */
+ public PDTextbox( PDAcroForm theAcroForm )
+ {
+ super( theAcroForm );
+ }
+
+ /**
+ * @see org.pdfbox.pdmodel.interactive.form.PDField#PDField(PDAcroForm,COSDictionary)
+ *
+ * @param theAcroForm The acroForm for this field.
+ * @param field The field's dictionary.
+ */
+ public PDTextbox( PDAcroForm theAcroForm, COSDictionary field)
+ {
+ super( theAcroForm, field);
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/interactive/form/PDUnknownField.java b/src/main/java/org/pdfbox/pdmodel/interactive/form/PDUnknownField.java
new file mode 100644
index 0000000..806b5f5
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/interactive/form/PDUnknownField.java
@@ -0,0 +1,72 @@
+/**
+ * Copyright (c) 2003, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.interactive.form;
+
+import java.io.IOException;
+
+import org.pdfbox.cos.COSDictionary;
+
+/**
+ * This class represents a form field with an unknown type.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.3 $
+ */
+public class PDUnknownField extends PDField
+{
+ /**
+ * @see org.pdfbox.pdmodel.interactive.form.PDField#PDField(PDAcroForm, COSDictionary)
+ *
+ * @param theAcroForm The acroForm for this field.
+ * @param field The field's dictionary.
+ */
+ public PDUnknownField( PDAcroForm theAcroForm, COSDictionary field)
+ {
+ super( theAcroForm, field);
+ }
+
+ /**
+ * @see org.pdfbox.pdmodel.interactive.form.PDField#setValue(String)
+ */
+ public void setValue(String value) throws IOException
+ {
+ //do nothing
+ }
+
+ /**
+ * @see org.pdfbox.pdmodel.interactive.form.PDField#getValue()
+ */
+ public String getValue() throws IOException
+ {
+ return null;
+ }
+
+}
diff --git a/src/main/java/org/pdfbox/pdmodel/interactive/form/PDVariableText.java b/src/main/java/org/pdfbox/pdmodel/interactive/form/PDVariableText.java
new file mode 100644
index 0000000..7ed5008
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/interactive/form/PDVariableText.java
@@ -0,0 +1,324 @@
+/**
+ * Copyright (c) 2004-2005, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.interactive.form;
+
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSInteger;
+import org.pdfbox.cos.COSName;
+import org.pdfbox.cos.COSNumber;
+import org.pdfbox.cos.COSString;
+import org.pdfbox.util.BitFlagHelper;
+
+import java.io.IOException;
+
+/**
+ * A class for handling PDF fields that display text.
+ *
+ * @author Ben Litchfield (ben@benlitchfield.com)
+ * @version $Revision: 1.6 $
+ */
+public abstract class PDVariableText extends PDField
+{
+ /**
+ * A Ff flag.
+ */
+ public static final int FLAG_MULTILINE = 1 << 12;
+ /**
+ * A Ff flag.
+ */
+ public static final int FLAG_PASSWORD = 1 << 13;
+ /**
+ * A Ff flag.
+ */
+ public static final int FLAG_FILE_SELECT = 1 << 20;
+ /**
+ * A Ff flag.
+ */
+ public static final int FLAG_DO_NOT_SPELL_CHECK = 1 << 22;
+ /**
+ * A Ff flag.
+ */
+ public static final int FLAG_DO_NOT_SCROLL = 1 << 23;
+ /**
+ * A Ff flag.
+ */
+ public static final int FLAG_COMB = 1 << 24;
+ /**
+ * A Ff flag.
+ */
+ public static final int FLAG_RICH_TEXT = 1 << 25;
+
+
+ /**
+ * DA Default appearance.
+ */
+ private COSString da;
+
+ private PDAppearance appearance;
+
+
+ /**
+ * A Q value.
+ */
+ public static final int QUADDING_LEFT = 0;
+
+ /**
+ * A Q value.
+ */
+ public static final int QUADDING_CENTERED = 1;
+
+ /**
+ * A Q value.
+ */
+ public static final int QUADDING_RIGHT = 2;
+
+ /**
+ * @see PDField#PDField(PDAcroForm,COSDictionary)
+ *
+ * @param theAcroForm The acroform.
+ */
+ public PDVariableText( PDAcroForm theAcroForm )
+ {
+ super( theAcroForm );
+ }
+
+ /**
+ * @see org.pdfbox.pdmodel.interactive.form.PDField#PDField(PDAcroForm,COSDictionary)
+ *
+ * @param theAcroForm The acroForm for this field.
+ * @param field The field's dictionary.
+ */
+ public PDVariableText( PDAcroForm theAcroForm, COSDictionary field)
+ {
+ super( theAcroForm, field);
+ da = (COSString) field.getDictionaryObject(COSName.getPDFName("DA"));
+ }
+
+ /**
+ * @see org.pdfbox.pdmodel.interactive.form.PDField#setValue(java.lang.String)
+ *
+ * @param value The new value for this text field.
+ *
+ * @throws IOException If there is an error calculating the appearance stream.
+ */
+ public void setValue(String value) throws IOException
+ {
+ COSString fieldValue = new COSString(value);
+ getDictionary().setItem( COSName.getPDFName( "V" ), fieldValue );
+
+ //hmm, not sure what the case where the DV gets set to the field
+ //value, for now leave blank until we can come up with a case
+ //where it needs to be in there
+ //getDictionary().setItem( COSName.getPDFName( "DV" ), fieldValue );
+ if(appearance == null)
+ {
+ this.appearance = new PDAppearance( getAcroForm(), this );
+ }
+ appearance.setAppearanceValue(value);
+ }
+
+ /**
+ * getValue gets the fields value to as a string.
+ *
+ * @return The string value of this field.
+ *
+ * @throws IOException If there is an error getting the value.
+ */
+ public String getValue() throws IOException
+ {
+ return getDictionary().getString( "V" );
+ }
+
+ /**
+ * @return true if the field is multiline
+ */
+ public boolean isMultiline()
+ {
+ return BitFlagHelper.getFlag( getDictionary(), "Ff", FLAG_MULTILINE );
+ }
+
+ /**
+ * Set the multiline bit.
+ *
+ * @param multiline The value for the multiline.
+ */
+ public void setMultiline( boolean multiline )
+ {
+ BitFlagHelper.setFlag( getDictionary(), "Ff", FLAG_MULTILINE, multiline );
+ }
+
+ /**
+ * @return true if the field is a password field.
+ */
+ public boolean isPassword()
+ {
+ return BitFlagHelper.getFlag( getDictionary(), "Ff", FLAG_PASSWORD );
+ }
+
+ /**
+ * Set the password bit.
+ *
+ * @param password The value for the password.
+ */
+ public void setPassword( boolean password )
+ {
+ BitFlagHelper.setFlag( getDictionary(), "Ff", FLAG_PASSWORD, password );
+ }
+
+ /**
+ * @return true if the field is a file select field.
+ */
+ public boolean isFileSelect()
+ {
+ return BitFlagHelper.getFlag( getDictionary(), "Ff", FLAG_FILE_SELECT );
+ }
+
+ /**
+ * Set the file select bit.
+ *
+ * @param fileSelect The value for the fileSelect.
+ */
+ public void setFileSelect( boolean fileSelect )
+ {
+ BitFlagHelper.setFlag( getDictionary(), "Ff", FLAG_FILE_SELECT, fileSelect );
+ }
+
+ /**
+ * @return true if the field is not suppose to spell check.
+ */
+ public boolean doNotSpellCheck()
+ {
+ return BitFlagHelper.getFlag( getDictionary(), "Ff", FLAG_DO_NOT_SPELL_CHECK );
+ }
+
+ /**
+ * Set the doNotSpellCheck bit.
+ *
+ * @param doNotSpellCheck The value for the doNotSpellCheck.
+ */
+ public void setDoNotSpellCheck( boolean doNotSpellCheck )
+ {
+ BitFlagHelper.setFlag( getDictionary(), "Ff", FLAG_DO_NOT_SPELL_CHECK, doNotSpellCheck );
+ }
+
+ /**
+ * @return true if the field is not suppose to scroll.
+ */
+ public boolean doNotScroll()
+ {
+ return BitFlagHelper.getFlag( getDictionary(), "Ff", FLAG_DO_NOT_SCROLL );
+ }
+
+ /**
+ * Set the doNotScroll bit.
+ *
+ * @param doNotScroll The value for the doNotScroll.
+ */
+ public void setDoNotScroll( boolean doNotScroll )
+ {
+ BitFlagHelper.setFlag( getDictionary(), "Ff", FLAG_DO_NOT_SCROLL, doNotScroll );
+ }
+
+ /**
+ * @return true if the field is not suppose to comb the text display.
+ */
+ public boolean shouldComb()
+ {
+ return BitFlagHelper.getFlag( getDictionary(), "Ff", FLAG_COMB );
+ }
+
+ /**
+ * Set the comb bit.
+ *
+ * @param comb The value for the comb.
+ */
+ public void setComb( boolean comb )
+ {
+ BitFlagHelper.setFlag( getDictionary(), "Ff", FLAG_COMB, comb );
+ }
+
+ /**
+ * @return true if the field is a rich text field.
+ */
+ public boolean isRichText()
+ {
+ return BitFlagHelper.getFlag( getDictionary(), "Ff", FLAG_RICH_TEXT );
+ }
+
+ /**
+ * Set the richText bit.
+ *
+ * @param richText The value for the richText.
+ */
+ public void setRichText( boolean richText )
+ {
+ BitFlagHelper.setFlag( getDictionary(), "Ff", FLAG_RICH_TEXT, richText );
+ }
+
+ /**
+ * @return the DA element of the dictionary object
+ */
+ protected COSString getDefaultAppearance()
+ {
+ return da;
+ }
+
+ /**
+ * This will get the 'quadding' or justification of the text to be displayed.
+ * 0 - Left(default)<br/>
+ * 1 - Centered<br />
+ * 2 - Right<br />
+ * Please see the QUADDING_CONSTANTS.
+ *
+ * @return The justification of the text strings.
+ */
+ public int getQ()
+ {
+ int retval = 0;
+ COSNumber number = (COSNumber)getDictionary().getDictionaryObject( COSName.getPDFName( "Q" ) );
+ if( number != null )
+ {
+ retval = number.intValue();
+ }
+ return retval;
+ }
+
+ /**
+ * This will set the quadding/justification of the text. See QUADDING constants.
+ *
+ * @param q The new text justification.
+ */
+ public void setQ( int q )
+ {
+ getDictionary().setItem( COSName.getPDFName( "Q" ), new COSInteger( q ) );
+ }
+
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/interactive/form/package.html b/src/main/java/org/pdfbox/pdmodel/interactive/form/package.html
new file mode 100644
index 0000000..36c4b4b
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/interactive/form/package.html
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+
+</head>
+<body>
+The interactive package contains classes that deal with interactive annotations such as textfields and buttons.
+</body>
+</html>
diff --git a/src/main/java/org/pdfbox/pdmodel/interactive/pagenavigation/PDThread.java b/src/main/java/org/pdfbox/pdmodel/interactive/pagenavigation/PDThread.java
new file mode 100644
index 0000000..5226099
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/interactive/pagenavigation/PDThread.java
@@ -0,0 +1,152 @@
+/**
+ * Copyright (c) 2005, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.interactive.pagenavigation;
+
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSDictionary;
+
+import org.pdfbox.pdmodel.PDDocumentInformation;
+import org.pdfbox.pdmodel.common.COSObjectable;
+
+/**
+ * This a single thread in a PDF document.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.1 $
+ */
+public class PDThread implements COSObjectable
+{
+
+
+ private COSDictionary thread;
+
+ /**
+ * Constructor that is used for a preexisting dictionary.
+ *
+ * @param t The underlying dictionary.
+ */
+ public PDThread( COSDictionary t )
+ {
+ thread = t;
+ }
+
+ /**
+ * Default constructor.
+ *
+ */
+ public PDThread()
+ {
+ thread = new COSDictionary();
+ thread.setName( "Type", "Thread" );
+ }
+
+ /**
+ * This will get the underlying dictionary that this object wraps.
+ *
+ * @return The underlying info dictionary.
+ */
+ public COSDictionary getDictionary()
+ {
+ return thread;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSBase getCOSObject()
+ {
+ return thread;
+ }
+
+ /**
+ * Get info about the thread, or null if there is nothing.
+ *
+ * @return The thread information.
+ */
+ public PDDocumentInformation getThreadInfo()
+ {
+ PDDocumentInformation retval = null;
+ COSDictionary info = (COSDictionary)thread.getDictionaryObject( "I" );
+ if( info != null )
+ {
+ retval = new PDDocumentInformation( info );
+ }
+
+ return retval;
+ }
+
+ /**
+ * Set the thread info, can be null.
+ *
+ * @param info The info dictionary about this thread.
+ */
+ public void setThreadInfo( PDDocumentInformation info )
+ {
+ thread.setItem( "I", info );
+ }
+
+ /**
+ * Get the first bead in the thread, or null if it has not been set yet. This
+ * is a required field for this object.
+ *
+ * @return The first bead in the thread.
+ */
+ public PDThreadBead getFirstBead()
+ {
+ PDThreadBead retval = null;
+ COSDictionary bead = (COSDictionary)thread.getDictionaryObject( "F" );
+ if( bead != null )
+ {
+ retval = new PDThreadBead( bead );
+ }
+
+ return retval;
+ }
+
+ /**
+ * This will set the first bead in the thread. When this is set it will
+ * also set the thread property of the bead object.
+ *
+ * @param bead The first bead in the thread.
+ */
+ public void setFirstBead( PDThreadBead bead )
+ {
+ if( bead != null )
+ {
+ bead.setThread( this );
+ }
+ thread.setItem( "F", bead );
+ }
+
+
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/interactive/pagenavigation/PDThreadBead.java b/src/main/java/org/pdfbox/pdmodel/interactive/pagenavigation/PDThreadBead.java
new file mode 100644
index 0000000..547d4bc
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/interactive/pagenavigation/PDThreadBead.java
@@ -0,0 +1,234 @@
+/**
+ * Copyright (c) 2005, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.interactive.pagenavigation;
+
+import org.pdfbox.cos.COSArray;
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSDictionary;
+import org.pdfbox.cos.COSName;
+
+import org.pdfbox.pdmodel.PDPage;
+import org.pdfbox.pdmodel.common.COSObjectable;
+import org.pdfbox.pdmodel.common.PDRectangle;
+
+/**
+ * This a single bead in a thread in a PDF document.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.3 $
+ */
+public class PDThreadBead implements COSObjectable
+{
+
+
+ private COSDictionary bead;
+
+ /**
+ * Constructor that is used for a preexisting dictionary.
+ *
+ * @param b The underlying dictionary.
+ */
+ public PDThreadBead( COSDictionary b )
+ {
+ bead = b;
+ }
+
+ /**
+ * Default constructor.
+ *
+ */
+ public PDThreadBead()
+ {
+ bead = new COSDictionary();
+ bead.setName( "Type", "Bead" );
+ setNextBead( this );
+ setPreviousBead( this );
+ }
+
+ /**
+ * This will get the underlying dictionary that this object wraps.
+ *
+ * @return The underlying info dictionary.
+ */
+ public COSDictionary getDictionary()
+ {
+ return bead;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSBase getCOSObject()
+ {
+ return bead;
+ }
+
+ /**
+ * This will get the thread that this bead is part of. This is only required
+ * for the first bead in a thread, so other beads 'may' return null.
+ *
+ * @return The thread that this bead is part of.
+ */
+ public PDThread getThread()
+ {
+ PDThread retval = null;
+ COSDictionary dic = (COSDictionary)bead.getDictionaryObject( "T" );
+ if( dic != null )
+ {
+ retval = new PDThread( dic );
+ }
+ return retval;
+ }
+
+ /**
+ * Set the thread that this bead is part of. This is only required for the
+ * first bead in a thread. Note: This property is set for you by the PDThread.setFirstBead() method.
+ *
+ * @param thread The thread that this bead is part of.
+ */
+ public void setThread( PDThread thread )
+ {
+ bead.setItem( "T", thread );
+ }
+
+ /**
+ * This will get the next bead. If this bead is the last bead in the list then this
+ * will return the first bead.
+ *
+ * @return The next bead in the list or the first bead if this is the last bead.
+ */
+ public PDThreadBead getNextBead()
+ {
+ return new PDThreadBead( (COSDictionary) bead.getDictionaryObject( "N" ) );
+ }
+
+ /**
+ * Set the next bead in the thread.
+ *
+ * @param next The next bead.
+ */
+ protected void setNextBead( PDThreadBead next )
+ {
+ bead.setItem( "N", next );
+ }
+
+ /**
+ * This will get the previous bead. If this bead is the first bead in the list then this
+ * will return the last bead.
+ *
+ * @return The previous bead in the list or the last bead if this is the first bead.
+ */
+ public PDThreadBead getPreviousBead()
+ {
+ return new PDThreadBead( (COSDictionary) bead.getDictionaryObject( "V" ) );
+ }
+
+ /**
+ * Set the previous bead in the thread.
+ *
+ * @param previous The previous bead.
+ */
+ protected void setPreviousBead( PDThreadBead previous )
+ {
+ bead.setItem( "V", previous );
+ }
+
+ /**
+ * Append a bead after this bead. This will correctly set the next/previous beads in the
+ * linked list.
+ *
+ * @param append The bead to insert.
+ */
+ public void appendBead( PDThreadBead append )
+ {
+ PDThreadBead nextBead = getNextBead();
+ nextBead.setPreviousBead( append );
+ append.setNextBead( nextBead );
+ setNextBead( append );
+ append.setPreviousBead( this );
+ }
+
+ /**
+ * Get the page that this bead is part of.
+ *
+ * @return The page that this bead is part of.
+ */
+ public PDPage getPage()
+ {
+ PDPage page = null;
+ COSDictionary dic = (COSDictionary)bead.getDictionaryObject( "P" );
+ if( dic != null )
+ {
+ page = new PDPage( dic );
+ }
+ return page;
+ }
+
+ /**
+ * Set the page that this bead is part of. This is a required property and must be
+ * set when creating a new bead. The PDPage object also has a list of beads in the natural
+ * reading order. It is recommended that you add this object to that list as well.
+ *
+ * @param page The page that this bead is on.
+ */
+ public void setPage( PDPage page )
+ {
+ bead.setItem( "P", page );
+ }
+
+ /**
+ * The rectangle on the page that this bead is part of.
+ *
+ * @return The part of the page that this bead covers.
+ */
+ public PDRectangle getRectangle()
+ {
+ PDRectangle rect = null;
+ COSArray array = (COSArray)bead.getDictionaryObject( COSName.R );
+ if( array != null )
+ {
+ rect = new PDRectangle( array );
+ }
+ return rect;
+ }
+
+ /**
+ * Set the rectangle on the page that this bead covers.
+ *
+ * @param rect The portion of the page that this bead covers.
+ */
+ public void setRectangle( PDRectangle rect )
+ {
+ bead.setItem( COSName.R, rect );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/interactive/pagenavigation/package.html b/src/main/java/org/pdfbox/pdmodel/interactive/pagenavigation/package.html
new file mode 100644
index 0000000..5fb1b88
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/interactive/pagenavigation/package.html
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+
+</head>
+<body>
+A package to allow provide access to PDF page navigation functionality.
+</body>
+</html>
diff --git a/src/main/java/org/pdfbox/pdmodel/interactive/viewerpreferences/PDViewerPreferences.java b/src/main/java/org/pdfbox/pdmodel/interactive/viewerpreferences/PDViewerPreferences.java
new file mode 100644
index 0000000..d9958e6
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/interactive/viewerpreferences/PDViewerPreferences.java
@@ -0,0 +1,365 @@
+/**
+ * Copyright (c) 2003-2005, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.interactive.viewerpreferences;
+
+import org.pdfbox.cos.COSBase;
+import org.pdfbox.cos.COSDictionary;
+
+import org.pdfbox.pdmodel.common.COSObjectable;
+
+/**
+ * This is the document viewing preferences.
+ *
+ * @author Ben Litchfield (ben@benlitchfield.com)
+ * @version $Revision: 1.2 $
+ */
+public class PDViewerPreferences implements COSObjectable
+{
+ /**
+ * From PDF Reference: "Neither document outline nor thumbnail images visible".
+ */
+ public static final String NON_FULL_SCREEN_PAGE_MODE_USE_NONE = "UseNone";
+ /**
+ * From PDF Reference: "Document outline visible".
+ */
+ public static final String NON_FULL_SCREEN_PAGE_MODE_USE_OUTLINES = "UseOutlines";
+ /**
+ * From PDF Reference: "Thumbnail images visible".
+ */
+ public static final String NON_FULL_SCREEN_PAGE_MODE_USE_THUMBS = "UseThumbs";
+ /**
+ * From PDF Reference: "Optional content group panel visible".
+ */
+ public static final String NON_FULL_SCREEN_PAGE_MODE_USE_OPTIONAL_CONTENT = "UseOC";
+
+ /**
+ * Reading direction.
+ */
+ public static final String READING_DIRECTION_L2R = "L2R";
+ /**
+ * Reading direction.
+ */
+ public static final String READING_DIRECTION_R2L = "R2L";
+
+ /**
+ * Boundary constant.
+ */
+ public static final String BOUNDARY_MEDIA_BOX = "MediaBox";
+ /**
+ * Boundary constant.
+ */
+ public static final String BOUNDARY_CROP_BOX = "CropBox";
+ /**
+ * Boundary constant.
+ */
+ public static final String BOUNDARY_BLEED_BOX = "BleedBox";
+ /**
+ * Boundary constant.
+ */
+ public static final String BOUNDARY_TRIM_BOX = "TrimBox";
+ /**
+ * Boundary constant.
+ */
+ public static final String BOUNDARY_ART_BOX = "ArtBox";
+
+
+ private COSDictionary prefs;
+
+ /**
+ * Constructor that is used for a preexisting dictionary.
+ *
+ * @param dic The underlying dictionary.
+ */
+ public PDViewerPreferences( COSDictionary dic )
+ {
+ prefs = dic;
+ }
+
+ /**
+ * This will get the underlying dictionary that this object wraps.
+ *
+ * @return The underlying info dictionary.
+ */
+ public COSDictionary getDictionary()
+ {
+ return prefs;
+ }
+
+ /**
+ * Convert this standard java object to a COS object.
+ *
+ * @return The cos object that matches this Java object.
+ */
+ public COSBase getCOSObject()
+ {
+ return prefs;
+ }
+
+ /**
+ * Get the toolbar preference.
+ *
+ * @return the toolbar preference.
+ */
+ public boolean hideToolbar()
+ {
+ return prefs.getBoolean( "HideToolbar", false );
+ }
+
+ /**
+ * Set the toolbar preference.
+ *
+ * @param value Set the toolbar preference.
+ */
+ public void setHideToolbar( boolean value )
+ {
+ prefs.setBoolean( "HideToolbar", value );
+ }
+
+ /**
+ * Get the menubar preference.
+ *
+ * @return the menubar preference.
+ */
+ public boolean hideMenubar()
+ {
+ return prefs.getBoolean( "HideMenubar", false );
+ }
+
+ /**
+ * Set the menubar preference.
+ *
+ * @param value Set the menubar preference.
+ */
+ public void setHideMenubar( boolean value )
+ {
+ prefs.setBoolean( "HideMenubar", value );
+ }
+
+ /**
+ * Get the window UI preference.
+ *
+ * @return the window UI preference.
+ */
+ public boolean hideWindowUI()
+ {
+ return prefs.getBoolean( "HideWindowUI", false );
+ }
+
+ /**
+ * Set the window UI preference.
+ *
+ * @param value Set the window UI preference.
+ */
+ public void setHideWindowUI( boolean value )
+ {
+ prefs.setBoolean( "HideWindowUI", value );
+ }
+
+ /**
+ * Get the fit window preference.
+ *
+ * @return the fit window preference.
+ */
+ public boolean fitWindow()
+ {
+ return prefs.getBoolean( "FitWindow", false );
+ }
+
+ /**
+ * Set the fit window preference.
+ *
+ * @param value Set the fit window preference.
+ */
+ public void setFitWindow( boolean value )
+ {
+ prefs.setBoolean( "FitWindow", value );
+ }
+
+ /**
+ * Get the center window preference.
+ *
+ * @return the center window preference.
+ */
+ public boolean centerWindow()
+ {
+ return prefs.getBoolean( "CenterWindow", false );
+ }
+
+ /**
+ * Set the center window preference.
+ *
+ * @param value Set the center window preference.
+ */
+ public void setCenterWindow( boolean value )
+ {
+ prefs.setBoolean( "CenterWindow", value );
+ }
+
+ /**
+ * Get the display doc title preference.
+ *
+ * @return the display doc title preference.
+ */
+ public boolean displayDocTitle()
+ {
+ return prefs.getBoolean( "DisplayDocTitle", false );
+ }
+
+ /**
+ * Set the display doc title preference.
+ *
+ * @param value Set the display doc title preference.
+ */
+ public void setDisplayDocTitle( boolean value )
+ {
+ prefs.setBoolean( "DisplayDocTitle", value );
+ }
+
+ /**
+ * Get the non full screen page mode preference.
+ *
+ * @return the non full screen page mode preference.
+ */
+ public String getNonFullScreenPageMode()
+ {
+ return prefs.getNameAsString( "NonFullScreenPageMode", NON_FULL_SCREEN_PAGE_MODE_USE_NONE);
+ }
+
+ /**
+ * Set the non full screen page mode preference.
+ *
+ * @param value Set the non full screen page mode preference.
+ */
+ public void setNonFullScreenPageMode( String value )
+ {
+ prefs.setName( "NonFullScreenPageMode", value );
+ }
+
+ /**
+ * Get the reading direction preference.
+ *
+ * @return the reading direction preference.
+ */
+ public String getReadingDirection()
+ {
+ return prefs.getNameAsString( "Direction", READING_DIRECTION_L2R);
+ }
+
+ /**
+ * Set the reading direction preference.
+ *
+ * @param value Set the reading direction preference.
+ */
+ public void setReadingDirection( String value )
+ {
+ prefs.setName( "Direction", value );
+ }
+
+ /**
+ * Get the ViewArea preference. See BOUNDARY_XXX constants.
+ *
+ * @return the ViewArea preference.
+ */
+ public String getViewArea()
+ {
+ return prefs.getNameAsString( "ViewArea", BOUNDARY_CROP_BOX);
+ }
+
+ /**
+ * Set the ViewArea preference. See BOUNDARY_XXX constants.
+ *
+ * @param value Set the ViewArea preference.
+ */
+ public void setViewArea( String value )
+ {
+ prefs.setName( "ViewArea", value );
+ }
+
+ /**
+ * Get the ViewClip preference. See BOUNDARY_XXX constants.
+ *
+ * @return the ViewClip preference.
+ */
+ public String getViewClip()
+ {
+ return prefs.getNameAsString( "ViewClip", BOUNDARY_CROP_BOX);
+ }
+
+ /**
+ * Set the ViewClip preference. See BOUNDARY_XXX constants.
+ *
+ * @param value Set the ViewClip preference.
+ */
+ public void setViewClip( String value )
+ {
+ prefs.setName( "ViewClip", value );
+ }
+
+ /**
+ * Get the PrintArea preference. See BOUNDARY_XXX constants.
+ *
+ * @return the PrintArea preference.
+ */
+ public String getPrintArea()
+ {
+ return prefs.getNameAsString( "PrintArea", BOUNDARY_CROP_BOX);
+ }
+
+ /**
+ * Set the PrintArea preference. See BOUNDARY_XXX constants.
+ *
+ * @param value Set the PrintArea preference.
+ */
+ public void setPrintArea( String value )
+ {
+ prefs.setName( "PrintArea", value );
+ }
+
+ /**
+ * Get the PrintClip preference. See BOUNDARY_XXX constants.
+ *
+ * @return the PrintClip preference.
+ */
+ public String getPrintClip()
+ {
+ return prefs.getNameAsString( "PrintClip", BOUNDARY_CROP_BOX);
+ }
+
+ /**
+ * Set the PrintClip preference. See BOUNDARY_XXX constants.
+ *
+ * @param value Set the PrintClip preference.
+ */
+ public void setPrintClip( String value )
+ {
+ prefs.setName( "PrintClip", value );
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/interactive/viewerpreferences/package.html b/src/main/java/org/pdfbox/pdmodel/interactive/viewerpreferences/package.html
new file mode 100644
index 0000000..310d6b4
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/interactive/viewerpreferences/package.html
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+
+</head>
+<body>
+A package to allow access to document viewing preferences.
+</body>
+</html>
diff --git a/src/main/java/org/pdfbox/pdmodel/package.html b/src/main/java/org/pdfbox/pdmodel/package.html
new file mode 100644
index 0000000..85bbe62
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/package.html
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+
+</head>
+<body>
+The PDModel package represents a high level API for creating and manipulating PDF documents.
+</body>
+</html>
diff --git a/src/main/java/org/pdfbox/pdmodel/text/PDTextState.java b/src/main/java/org/pdfbox/pdmodel/text/PDTextState.java
new file mode 100644
index 0000000..45e9516
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/text/PDTextState.java
@@ -0,0 +1,286 @@
+/**
+ * Copyright (c) 2003, www.pdfbox.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of pdfbox; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.pdfbox.org
+ *
+ */
+package org.pdfbox.pdmodel.text;
+
+import org.pdfbox.pdmodel.font.PDFont;
+
+/**
+ * This class will hold the current state of the text parameters when executing a
+ * content stream.
+ *
+ * @author Ben Litchfield (ben@csh.rit.edu)
+ * @version $Revision: 1.3 $
+ */
+public class PDTextState implements Cloneable
+{
+ /**
+ * See PDF Reference 1.5 Table 5.3.
+ */
+ public static final int RENDERING_MODE_FILL_TEXT = 0;
+ /**
+ * See PDF Reference 1.5 Table 5.3.
+ */
+ public static final int RENDERING_MODE_STROKE_TEXT = 1;
+ /**
+ * See PDF Reference 1.5 Table 5.3.
+ */
+ public static final int RENDERING_MODE_FILL_THEN_STROKE_TEXT = 2;
+ /**
+ * See PDF Reference 1.5 Table 5.3.
+ */
+ public static final int RENDERING_MODE_NEITHER_FILL_NOR_STROKE_TEXT = 3;
+ /**
+ * See PDF Reference 1.5 Table 5.3.
+ */
+ public static final int RENDERING_MODE_FILL_TEXT_AND_ADD_TO_PATH_FOR_CLIPPING = 4;
+ /**
+ * See PDF Reference 1.5 Table 5.3.
+ */
+ public static final int RENDERING_MODE_STROKE_TEXT_AND_ADD_TO_PATH_FOR_CLIPPING = 5;
+ /**
+ * See PDF Reference 1.5 Table 5.3.
+ */
+ public static final int RENDERING_MODE_FILL_THEN_STROKE_TEXT_AND_ADD_TO_PATH_FOR_CLIPPING = 6;
+ /**
+ * See PDF Reference 1.5 Table 5.3.
+ */
+ public static final int RENDERING_MODE_ADD_TEXT_TO_PATH_FOR_CLIPPING = 7;
+
+
+ //these are set default according to PDF Reference 1.5 section 5.2
+ private float characterSpacing = 0;
+ private float wordSpacing = 0;
+ private float horizontalScaling = 100;
+ private float leading = 0;
+ private PDFont font;
+ private float fontSize;
+ private int renderingMode = 0;
+ private float rise = 0;
+ private boolean knockout = true;
+
+ /**
+ * Get the value of the characterSpacing.
+ *
+ * @return The current characterSpacing.
+ */
+ public float getCharacterSpacing()
+ {
+ return characterSpacing;
+ }
+
+ /**
+ * Set the value of the characterSpacing.
+ *
+ * @param value The characterSpacing.
+ */
+ public void setCharacterSpacing(float value)
+ {
+ characterSpacing = value;
+ }
+
+ /**
+ * Get the value of the wordSpacing.
+ *
+ * @return The wordSpacing.
+ */
+ public float getWordSpacing()
+ {
+ return wordSpacing;
+ }
+
+ /**
+ * Set the value of the wordSpacing.
+ *
+ * @param value The wordSpacing.
+ */
+ public void setWordSpacing(float value)
+ {
+ wordSpacing = value;
+ }
+
+ /**
+ * Get the value of the horizontalScaling. The default is 100. This value
+ * is the percentage value 0-100 and not 0-1. So for mathematical operations
+ * you will probably need to divide by 100 first.
+ *
+ * @return The horizontalScaling.
+ */
+ public float getHorizontalScalingPercent()
+ {
+ return horizontalScaling;
+ }
+
+ /**
+ * Set the value of the horizontalScaling.
+ *
+ * @param value The horizontalScaling.
+ */
+ public void setHorizontalScalingPercent(float value)
+ {
+ horizontalScaling = value;
+ }
+
+ /**
+ * Get the value of the leading.
+ *
+ * @return The leading.
+ */
+ public float getLeading()
+ {
+ return leading;
+ }
+
+ /**
+ * Set the value of the leading.
+ *
+ * @param value The leading.
+ */
+ public void setLeading(float value)
+ {
+ leading = value;
+ }
+
+ /**
+ * Get the value of the font.
+ *
+ * @return The font.
+ */
+ public PDFont getFont()
+ {
+ return font;
+ }
+
+ /**
+ * Set the value of the font.
+ *
+ * @param value The font.
+ */
+ public void setFont(PDFont value)
+ {
+ font = value;
+ }
+
+ /**
+ * Get the value of the fontSize.
+ *
+ * @return The fontSize.
+ */
+ public float getFontSize()
+ {
+ return fontSize;
+ }
+
+ /**
+ * Set the value of the fontSize.
+ *
+ * @param value The fontSize.
+ */
+ public void setFontSize(float value)
+ {
+ fontSize = value;
+ }
+
+ /**
+ * Get the value of the renderingMode.
+ *
+ * @return The renderingMode.
+ */
+ public int getRenderingMode()
+ {
+ return renderingMode;
+ }
+
+ /**
+ * Set the value of the renderingMode.
+ *
+ * @param value The renderingMode.
+ */
+ public void setRenderingMode(int value)
+ {
+ renderingMode = value;
+ }
+
+ /**
+ * Get the value of the rise.
+ *
+ * @return The rise.
+ */
+ public float getRise()
+ {
+ return rise;
+ }
+
+ /**
+ * Set the value of the rise.
+ *
+ * @param value The rise.
+ */
+ public void setRise(float value)
+ {
+ rise = value;
+ }
+
+ /**
+ * Get the value of the knockout.
+ *
+ * @return The knockout.
+ */
+ public boolean getKnockoutFlag()
+ {
+ return knockout;
+ }
+
+ /**
+ * Set the value of the knockout.
+ *
+ * @param value The knockout.
+ */
+ public void setKnockoutFlag(boolean value)
+ {
+ knockout = value;
+ }
+
+ /**
+ * @see Object#clone()
+ */
+ public Object clone()
+ {
+ try
+ {
+ return super.clone();
+ }
+ catch (CloneNotSupportedException ignore)
+ {
+ //ignore
+ }
+ return null;
+ }
+} \ No newline at end of file
diff --git a/src/main/java/org/pdfbox/pdmodel/text/package.html b/src/main/java/org/pdfbox/pdmodel/text/package.html
new file mode 100644
index 0000000..50bb7c5
--- /dev/null
+++ b/src/main/java/org/pdfbox/pdmodel/text/package.html
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+
+</head>
+<body>
+The PDModel text package deals with text states, operations, and parameters within the PDF document.
+</body>
+</html> \ No newline at end of file