From 6025b6016517c6d898d8957d1d7e03ba71431912 Mon Sep 17 00:00:00 2001 From: tknall Date: Fri, 1 Dec 2006 12:20:24 +0000 Subject: Initial import of release 2.2. git-svn-id: https://joinup.ec.europa.eu/svn/pdf-as/trunk@4 7b5415b0-85f9-ee4d-85bd-d5d0c3b42d1c --- .../pdmodel/interactive/form/PDAcroForm.java | 328 +++++++++++ .../pdmodel/interactive/form/PDAppearance.java | 645 +++++++++++++++++++++ .../pdmodel/interactive/form/PDCheckbox.java | 187 ++++++ .../pdmodel/interactive/form/PDChoiceButton.java | 95 +++ .../pdmodel/interactive/form/PDChoiceField.java | 127 ++++ .../pdfbox/pdmodel/interactive/form/PDField.java | 610 +++++++++++++++++++ .../pdmodel/interactive/form/PDFieldFactory.java | 218 +++++++ .../pdmodel/interactive/form/PDPushButton.java | 84 +++ .../interactive/form/PDRadioCollection.java | 170 ++++++ .../pdmodel/interactive/form/PDSignature.java | 90 +++ .../pdfbox/pdmodel/interactive/form/PDTextbox.java | 64 ++ .../pdmodel/interactive/form/PDUnknownField.java | 72 +++ .../pdmodel/interactive/form/PDVariableText.java | 324 +++++++++++ .../pdfbox/pdmodel/interactive/form/package.html | 9 + 14 files changed, 3023 insertions(+) create mode 100644 src/main/java/org/pdfbox/pdmodel/interactive/form/PDAcroForm.java create mode 100644 src/main/java/org/pdfbox/pdmodel/interactive/form/PDAppearance.java create mode 100644 src/main/java/org/pdfbox/pdmodel/interactive/form/PDCheckbox.java create mode 100644 src/main/java/org/pdfbox/pdmodel/interactive/form/PDChoiceButton.java create mode 100644 src/main/java/org/pdfbox/pdmodel/interactive/form/PDChoiceField.java create mode 100644 src/main/java/org/pdfbox/pdmodel/interactive/form/PDField.java create mode 100644 src/main/java/org/pdfbox/pdmodel/interactive/form/PDFieldFactory.java create mode 100644 src/main/java/org/pdfbox/pdmodel/interactive/form/PDPushButton.java create mode 100644 src/main/java/org/pdfbox/pdmodel/interactive/form/PDRadioCollection.java create mode 100644 src/main/java/org/pdfbox/pdmodel/interactive/form/PDSignature.java create mode 100644 src/main/java/org/pdfbox/pdmodel/interactive/form/PDTextbox.java create mode 100644 src/main/java/org/pdfbox/pdmodel/interactive/form/PDUnknownField.java create mode 100644 src/main/java/org/pdfbox/pdmodel/interactive/form/PDVariableText.java create mode 100644 src/main/java/org/pdfbox/pdmodel/interactive/form/package.html (limited to 'src/main/java/org/pdfbox/pdmodel/interactive/form') 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 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 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 -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 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 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
+ * 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)
+ * 1 - Centered
+ * 2 - Right
+ * 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 @@ + + + + + + +The interactive package contains classes that deal with interactive annotations such as textfields and buttons. + + -- cgit v1.2.3