use of com.tom_roush.pdfbox.cos.COSArray in project PdfBox-Android by TomRoush.
the class PDDocument method addSignature.
/**
* This will add a signature to the document. If the 0-based page number in the options
* parameter is smaller than 0 or larger than max, the nearest valid page number will be used
* (i.e. 0 or max) and no exception will be thrown.
* <p>
* Only one signature may be added in a document. To sign several times,
* load document, add signature, save incremental and close again.
*
* @param sigObject is the PDSignatureField model
* @param signatureInterface is an interface whose implementation provides
* signing capabilities. Can be null if external signing if used.
* @param options signature options
* @throws IOException if there is an error creating required fields
* @throws IllegalStateException if one attempts to add several signature
* fields.
*/
public void addSignature(PDSignature sigObject, SignatureInterface signatureInterface, SignatureOptions options) throws IOException {
if (signatureAdded) {
throw new IllegalStateException("Only one signature may be added in a document");
}
signatureAdded = true;
// Reserve content
// We need to reserve some space for the signature. Some signatures including
// big certificate chain and we need enough space to store it.
int preferredSignatureSize = options.getPreferredSignatureSize();
if (preferredSignatureSize > 0) {
sigObject.setContents(new byte[preferredSignatureSize]);
} else {
sigObject.setContents(new byte[SignatureOptions.DEFAULT_SIGNATURE_SIZE]);
}
// Reserve ByteRange, will be overwritten in COSWriter
sigObject.setByteRange(RESERVE_BYTE_RANGE);
signInterface = signatureInterface;
// Create SignatureForm for signature and append it to the document
// Get the first valid page
int pageCount = getNumberOfPages();
if (pageCount == 0) {
throw new IllegalStateException("Cannot sign an empty document");
}
int startIndex = Math.min(Math.max(options.getPage(), 0), pageCount - 1);
PDPage page = getPage(startIndex);
// Get the AcroForm from the Root-Dictionary and append the annotation
PDDocumentCatalog catalog = getDocumentCatalog();
PDAcroForm acroForm = catalog.getAcroForm();
catalog.getCOSObject().setNeedToBeUpdated(true);
if (acroForm == null) {
acroForm = new PDAcroForm(this);
catalog.setAcroForm(acroForm);
} else {
acroForm.getCOSObject().setNeedToBeUpdated(true);
}
PDSignatureField signatureField = null;
if (!(acroForm.getCOSObject().getDictionaryObject(COSName.FIELDS) instanceof COSArray)) {
acroForm.getCOSObject().setItem(COSName.FIELDS, new COSArray());
} else {
COSArray fieldArray = (COSArray) acroForm.getCOSObject().getDictionaryObject(COSName.FIELDS);
fieldArray.setNeedToBeUpdated(true);
signatureField = findSignatureField(acroForm.getFieldIterator(), sigObject);
}
if (signatureField == null) {
signatureField = new PDSignatureField(acroForm);
// append the signature object
signatureField.setValue(sigObject);
// backward linking
signatureField.getWidgets().get(0).setPage(page);
} else {
sigObject.getCOSObject().setNeedToBeUpdated(true);
}
// TODO This "overwrites" the settings of the original signature field which might not be intended by the user
// better make it configurable (not all users need/want PDF/A but their own setting):
// to conform PDF/A-1 requirement:
// The /F key's Print flag bit shall be set to 1 and
// its Hidden, Invisible and NoView flag bits shall be set to 0
signatureField.getWidgets().get(0).setPrinted(true);
// Set the AcroForm Fields
List<PDField> acroFormFields = acroForm.getFields();
acroForm.getCOSObject().setDirect(true);
acroForm.setSignaturesExist(true);
acroForm.setAppendOnly(true);
boolean checkFields = checkSignatureField(acroForm.getFieldIterator(), signatureField);
if (checkFields) {
signatureField.getCOSObject().setNeedToBeUpdated(true);
} else {
acroFormFields.add(signatureField);
}
// Get the object from the visual signature
COSDocument visualSignature = options.getVisualSignature();
// Distinction of case for visual and non-visual signature
if (visualSignature == null) {
prepareNonVisibleSignature(signatureField);
return;
}
prepareVisibleSignature(signatureField, acroForm, visualSignature);
// Create Annotation / Field for signature
List<PDAnnotation> annotations = page.getAnnotations();
// Make /Annots a direct object to avoid problem if it is an existing indirect object:
// it would not be updated in incremental save, and if we'd set the /Annots array "to be updated"
// while keeping it indirect, Adobe Reader would claim that the document had been modified.
page.setAnnotations(annotations);
// take care that page and acroforms do not share the same array (if so, we don't need to add it twice)
if (!(annotations instanceof COSArrayList && acroFormFields instanceof COSArrayList && ((COSArrayList<?>) annotations).toList().equals(((COSArrayList<?>) acroFormFields).toList()) && checkFields)) {
PDAnnotationWidget widget = signatureField.getWidgets().get(0);
// use check to prevent the annotation widget from appearing twice
if (checkSignatureAnnotation(annotations, widget)) {
widget.getCOSObject().setNeedToBeUpdated(true);
} else {
annotations.add(widget);
}
}
page.getCOSObject().setNeedToBeUpdated(true);
}
use of com.tom_roush.pdfbox.cos.COSArray in project PdfBox-Android by TomRoush.
the class PDFMergerUtility method acroFormLegacyMode.
/*
* Merge the contents of the source form into the destination form for the
* destination file.
*
* @param cloner the object cloner for the destination document
* @param destAcroForm the destination form
* @param srcAcroForm the source form
* @throws IOException If an error occurs while adding the field.
*/
private void acroFormLegacyMode(PDFCloneUtility cloner, PDAcroForm destAcroForm, PDAcroForm srcAcroForm) throws IOException {
List<PDField> srcFields = srcAcroForm.getFields();
COSArray destFields;
if (srcFields != null && !srcFields.isEmpty()) {
// if a form is merged multiple times using PDFBox the newly generated
// fields starting with dummyFieldName may already exist. We need to determine the last unique
// number used and increment that.
final String prefix = "dummyFieldName";
final int prefixLength = prefix.length();
for (PDField destField : destAcroForm.getFieldTree()) {
String fieldName = destField.getPartialName();
if (fieldName.startsWith(prefix)) {
nextFieldNum = Math.max(nextFieldNum, Integer.parseInt(fieldName.substring(prefixLength, fieldName.length())) + 1);
}
}
// get the destinations root fields. Could be that the entry doesn't exist
// or is of wrong type
COSBase base = destAcroForm.getCOSObject().getItem(COSName.FIELDS);
if (base instanceof COSArray) {
destFields = (COSArray) base;
} else {
destFields = new COSArray();
}
for (PDField srcField : srcAcroForm.getFields()) {
COSDictionary dstField = (COSDictionary) cloner.cloneForNewDocument(srcField.getCOSObject());
// to prevent merge conflicts.
if (destAcroForm.getField(srcField.getFullyQualifiedName()) != null) {
dstField.setString(COSName.T, prefix + nextFieldNum++);
}
destFields.add(dstField);
}
destAcroForm.getCOSObject().setItem(COSName.FIELDS, destFields);
}
}
use of com.tom_roush.pdfbox.cos.COSArray in project PdfBox-Android by TomRoush.
the class PDFMergerUtility method mergeFields.
private void mergeFields(PDFCloneUtility cloner, PDField destField, PDField srcField) {
if (destField instanceof PDNonTerminalField && srcField instanceof PDNonTerminalField) {
Log.i("PdfBox-Android", "Skipping non terminal field " + srcField.getFullyQualifiedName());
return;
}
if (destField.getFieldType() == "Tx" && destField.getFieldType() == "Tx") {
// if the field already has multiple widgets we can add to the array
if (destField.getCOSObject().containsKey(COSName.KIDS)) {
COSArray widgets = destField.getCOSObject().getCOSArray(COSName.KIDS);
for (PDAnnotationWidget srcWidget : srcField.getWidgets()) {
try {
widgets.add(cloner.cloneForNewDocument(srcWidget.getCOSObject()));
} catch (IOException ioe) {
Log.w("PdfBox-Android", "Unable to clone widget for source field " + srcField.getFullyQualifiedName());
}
}
} else {
COSArray widgets = new COSArray();
try {
COSDictionary widgetAsCOS = (COSDictionary) cloner.cloneForNewDocument(destField.getWidgets().get(0));
cleanupWidgetCOSDictionary(widgetAsCOS, true);
widgetAsCOS.setItem(COSName.PARENT, destField);
widgets.add(widgetAsCOS);
for (PDAnnotationWidget srcWidget : srcField.getWidgets()) {
try {
widgetAsCOS = (COSDictionary) cloner.cloneForNewDocument(srcWidget.getCOSObject());
cleanupWidgetCOSDictionary(widgetAsCOS, false);
widgetAsCOS.setItem(COSName.PARENT, destField);
widgets.add(widgetAsCOS);
} catch (IOException ioe) {
Log.w("PdfBox-Android", "Unable to clone widget for source field " + srcField.getFullyQualifiedName());
}
}
destField.getCOSObject().setItem(COSName.KIDS, widgets);
cleanupFieldCOSDictionary(destField.getCOSObject());
} catch (IOException ioe) {
Log.w("PdfBox-Android", "Unable to clone widget for destination field " + destField.getFullyQualifiedName());
}
}
} else {
Log.i("PdfBox-Android", "Only merging two text fields is currently supported");
Log.i("PdfBox-Android", "Skipping merging of " + srcField.getFullyQualifiedName() + " into " + destField.getFullyQualifiedName());
}
}
use of com.tom_roush.pdfbox.cos.COSArray in project PdfBox-Android by TomRoush.
the class BaseParser method parseCOSArray.
/**
* This will parse a PDF array object.
*
* @return The parsed PDF array.
*
* @throws IOException If there is an error parsing the stream.
*/
protected COSArray parseCOSArray() throws IOException {
long startPosition = seqSource.getPosition();
readExpectedChar('[');
COSArray po = new COSArray();
COSBase pbo;
skipSpaces();
int i;
while (((i = seqSource.peek()) > 0) && ((char) i != ']')) {
pbo = parseDirObject();
if (pbo instanceof COSObject) {
// We have to check if the expected values are there or not PDFBOX-385
if (po.size() > 0 && po.get(po.size() - 1) instanceof COSInteger) {
COSInteger genNumber = (COSInteger) po.remove(po.size() - 1);
if (po.size() > 0 && po.get(po.size() - 1) instanceof COSInteger) {
COSInteger number = (COSInteger) po.remove(po.size() - 1);
COSObjectKey key = new COSObjectKey(number.longValue(), genNumber.intValue());
pbo = getObjectFromPool(key);
} else {
// the object reference is somehow wrong
pbo = null;
}
} else {
pbo = null;
}
}
if (pbo != null) {
po.add(pbo);
} else {
// it could be a bad object in the array which is just skipped
Log.w("PdfBox-Android", "Corrupt object reference at offset " + seqSource.getPosition() + ", start offset: " + startPosition);
// This could also be an "endobj" or "endstream" which means we can assume that
// the array has ended.
String isThisTheEnd = readString();
seqSource.unread(isThisTheEnd.getBytes(ISO_8859_1));
if (ENDOBJ_STRING.equals(isThisTheEnd) || ENDSTREAM_STRING.equals(isThisTheEnd)) {
return po;
}
}
skipSpaces();
}
// read ']'
seqSource.read();
skipSpaces();
return po;
}
use of com.tom_roush.pdfbox.cos.COSArray in project PdfBox-Android by TomRoush.
the class Overlay method processPages.
private void processPages(PDDocument document) throws IOException {
int pageCounter = 0;
for (PDPage page : document.getPages()) {
pageCounter++;
COSDictionary pageDictionary = page.getCOSObject();
COSBase originalContent = pageDictionary.getDictionaryObject(COSName.CONTENTS);
COSArray newContentArray = new COSArray();
LayoutPage layoutPage = getLayoutPage(pageCounter, document.getNumberOfPages());
if (layoutPage == null) {
continue;
}
switch(position) {
case FOREGROUND:
// save state
newContentArray.add(createStream("q\n"));
addOriginalContent(originalContent, newContentArray);
// restore state
newContentArray.add(createStream("Q\n"));
// overlay content last
overlayPage(page, layoutPage, newContentArray);
break;
case BACKGROUND:
// overlay content first
overlayPage(page, layoutPage, newContentArray);
addOriginalContent(originalContent, newContentArray);
break;
default:
throw new IOException("Unknown type of position:" + position);
}
pageDictionary.setItem(COSName.CONTENTS, newContentArray);
}
}
Aggregations