/** * This will return a list of signature fields. * * @param onlyEmptyFields only empty signature fields will be returned * @return list of signature dictionaries as COSDictionary * @throws IOException if no document catalog can be found */ public List<COSDictionary> getSignatureFields(boolean onlyEmptyFields) throws IOException { COSObject documentCatalog = getCatalog(); if (documentCatalog != null) { COSDictionary acroForm = (COSDictionary) documentCatalog.getDictionaryObject(COSName.ACRO_FORM); if (acroForm != null) { COSArray fields = (COSArray) acroForm.getDictionaryObject(COSName.FIELDS); if (fields != null) { // Some fields may contain twice references to a single field. // This will prevent such double entries. HashMap<COSObjectKey, COSDictionary> signatures = new HashMap<COSObjectKey, COSDictionary>(); for (Object object : fields) { COSObject dict = (COSObject) object; if (COSName.SIG.equals(dict.getItem(COSName.FT))) { COSBase dictionaryObject = dict.getDictionaryObject(COSName.V); if (dictionaryObject == null || (dictionaryObject != null && !onlyEmptyFields)) { signatures.put(new COSObjectKey(dict), (COSDictionary) dict.getObject()); } } } return new LinkedList<COSDictionary>(signatures.values()); } } } return Collections.emptyList(); }
/** * This method checks the AP entry of the Annotation Dictionary. If the AP key is missing, this * method returns true. If the AP key exists, only the N entry is authorized and must be a Stream * which define the appearance of the annotation. (Currently, only the type of the N entry is * checked because of the Appearance stream is a Form XObject, so it will be checked by the * Graphics Helper) * * <p>If the AP content isn't valid, this method return false and updates the errors list. * * @param errors list of errors which is updated if validation fails * @return */ protected boolean checkAP(List<ValidationError> errors) { PDAppearanceDictionary ap = this.pdAnnot.getAppearance(); if (ap != null) { COSDictionary apDict = ap.getDictionary(); // ---- Only N entry is authorized if (apDict.getItem(COSName.getPDFName(ANNOT_DICTIONARY_KEY_D)) != null || apDict.getItem(COSName.getPDFName(ANNOT_DICTIONARY_KEY_R)) != null) { errors.add( new ValidationResult.ValidationError( ValidationConstants.ERROR_ANNOT_INVALID_AP_CONTENT, "Only the N Appearance is authorized")); return false; } else if (apDict.getItem(COSName.getPDFName(ANNOT_DICTIONARY_KEY_N)) == null) { // ---- N entry is required errors.add( new ValidationResult.ValidationError( ValidationConstants.ERROR_ANNOT_MISSING_AP_N_CONTENT, "The N Appearance must be present")); return false; } else { // ---- the N entry must be a Stream (Dictionaries are forbidden) COSBase apn = apDict.getItem(COSName.getPDFName(ANNOT_DICTIONARY_KEY_N)); if (!COSUtils.isStream(apn, this.cosDoc)) { errors.add( new ValidationResult.ValidationError( ValidationConstants.ERROR_ANNOT_INVALID_AP_CONTENT, "The N Appearance must be a Stream")); return false; } } } // else ok, nothing to check,this field is optional return true; }
public Map<String, Image> getImages() { Map<String, Image> images = new HashMap<String, Image>(); COSDictionary xobjectsDictionary = (COSDictionary) getDictionary().getDictionaryObject(COSName.XOBJECT); if (xobjectsDictionary == null) { return images; } for (COSName objName : xobjectsDictionary.keySet()) { try { COSBase xobject = xobjectsDictionary.getDictionaryObject(objName); if (xobject instanceof COSStream) { COSStream xstream = (COSStream) xobject; String subtype = xstream.getNameAsString(COSName.SUBTYPE); if (!subtype.equals("Image")) { continue; } PDFunction tintTransformer = getTintTransformer(xstream); PDStream pdstream = new PDStream(xstream); byte[] data = getStreamData(pdstream); Image image = processStream(data, tintTransformer); if (image != null) { images.put(objName.getName(), image); } } } catch (Exception e) { LOG.error("error while creating a image", e); } } return images; }
/** * This will close all storage and delete the tmp files. * * @throws IOException If there is an error close resources. */ public void close() throws IOException { if (!closed) { scratchFile.close(); if (tmpFile != null) { tmpFile.delete(); } if (trailer != null) { trailer.clear(); trailer = null; } // Clear object pool for (COSObject object : objectPool.values()) { COSBase cosObject = object.getObject(); // clear the resources of the pooled objects if (cosObject instanceof COSStream) { ((COSStream) cosObject).close(); } else if (cosObject instanceof COSDictionary) { ((COSDictionary) cosObject).clear(); } else if (cosObject instanceof COSArray) { ((COSArray) cosObject).clear(); } // TODO are there other kind of COSObjects to be cleared? } objectPool.clear(); closed = true; } }
private InfoDictionaryImpl getInfo() { COSDictionary trailer = this.document.getDocument().getTrailer(); COSBase infoDict = trailer.getDictionaryObject(COSName.INFO); return !(infoDict instanceof COSDictionary) ? null : new InfoDictionaryImpl(new PDDocumentInformation((COSDictionary) infoDict)); }
private void writeColorSpace(PDColorSpace colorSpace) throws IOException { COSName key = null; if (colorSpace instanceof PDDeviceGray || colorSpace instanceof PDDeviceRGB || colorSpace instanceof PDDeviceCMYK) { key = COSName.getPDFName(colorSpace.getName()); } else { COSDictionary colorSpaces = (COSDictionary) resources.getCOSDictionary().getDictionaryObject(COSName.COLORSPACE); if (colorSpaces == null) { colorSpaces = new COSDictionary(); resources.getCOSDictionary().setItem(COSName.COLORSPACE, colorSpaces); } key = colorSpaces.getKeyForValue(colorSpace.getCOSObject()); if (key == null) { int counter = 0; String csName = "CS"; while (colorSpaces.containsValue(csName + counter)) { counter++; } key = COSName.getPDFName(csName + counter); colorSpaces.setItem(key, colorSpace); } } key.writePDF(output); appendRawCommands(SPACE); }
/** * This is a convenience method that will convert the value to a COSInteger object. * * @param embeddedDictionary The embedded dictionary. * @param key The key to the object, * @param value The int value for the name. */ public void setEmbeddedInt(String embeddedDictionary, COSName key, int value) { COSDictionary embedded = (COSDictionary) getDictionaryObject(embeddedDictionary); if (embedded == null) { embedded = new COSDictionary(); setItem(embeddedDictionary, embedded); } embedded.setInt(key, value); }
/** * This is a convenience method that will get the dictionary object that is expected to be a name * and convert it to a string. Null is returned if the entry does not exist in the dictionary. * * @param embedded The embedded dictionary. * @param key The key to the item in the dictionary. * @param defaultValue The default value to return. * @return The name converted to a string. */ public String getEmbeddedString(String embedded, COSName key, String defaultValue) { String retval = defaultValue; COSDictionary dic = (COSDictionary) getDictionaryObject(embedded); if (dic != null) { retval = dic.getString(key, defaultValue); } return retval; }
/** * Get an integer from an embedded dictionary. Useful for 1-1 mappings. * * @param embeddedDictionary The name of the embedded dictionary. * @param key The key in the embedded dictionary. * @param defaultValue The value if there is no embedded dictionary or it does not contain the * key. * @return The value of the embedded integer. */ public int getEmbeddedInt(String embeddedDictionary, COSName key, int defaultValue) { int retval = defaultValue; COSDictionary embedded = (COSDictionary) getDictionaryObject(embeddedDictionary); if (embedded != null) { retval = embedded.getInt(key, defaultValue); } return retval; }
/** * This is a convenience method that will get the dictionary object that is expected to be a date. * Null is returned if the entry does not exist in the dictionary. * * @param embedded The embedded dictionary to get. * @param key The key to the item in the dictionary. * @param defaultValue The default value to return. * @return The name converted to a string. * @throws IOException If there is an error converting to a date. */ public Calendar getEmbeddedDate(String embedded, COSName key, Calendar defaultValue) throws IOException { Calendar retval = defaultValue; COSDictionary eDic = (COSDictionary) getDictionaryObject(embedded); if (eDic != null) { retval = eDic.getDate(key, defaultValue); } return retval; }
/** * Returns the given attribute, inheriting from parent nodes if necessary. * * @param key the key to look up * @return COS value for the given key */ protected COSBase getInheritableAttribute(COSName key) { if (dictionary.containsKey(key)) { return dictionary.getDictionaryObject(key); } else if (parent != null) { return parent.getInheritableAttribute(key); } else { return acroForm.getCOSObject().getDictionaryObject(key); } }
/** true if catalog contain OCProperties key */ @Override public Boolean getisOptionalContentPresent() { try { COSDictionary root = (COSDictionary) ((COSDocument) baseObject).getCatalog().getObject(); return Boolean.valueOf(root.getItem(COSName.OCPROPERTIES) != null); } catch (IOException e) { return Boolean.FALSE; } }
/** * Set the date object. * * @param embedded The embedded dictionary. * @param key The key to the date. * @param date The date to set. */ public void setEmbeddedDate(String embedded, COSName key, Calendar date) { COSDictionary dic = (COSDictionary) getDictionaryObject(embedded); if (dic == null && date != null) { dic = new COSDictionary(); setItem(embedded, dic); } if (dic != null) { dic.setDate(key, date); } }
public COSBase getCOSObject() { COSDictionary dict = new COSDictionary(); COSArray arr = new COSArray(); for (Entry<Integer, PDPageLabelRange> i : labels.entrySet()) { arr.add(COSInteger.get(i.getKey())); arr.add(i.getValue()); } dict.setItem(COSName.NUMS, arr); return dict; }
/** * This is a convenience method that will convert the value to a COSString object. If it is null * then the object will be removed. * * @param embedded The embedded dictionary to set the item in. * @param key The key to the object, * @param value The string value for the name. */ public void setEmbeddedString(String embedded, COSName key, String value) { COSDictionary dic = (COSDictionary) getDictionaryObject(embedded); if (dic == null && value != null) { dic = new COSDictionary(); setItem(embedded, dic); } if (dic != null) { dic.setString(key, value); } }
/** * This will return a list of signature dictionaries as COSDictionary. * * @return list of signature dictionaries as COSDictionary * @throws IOException if no document catalog can be found */ public List<COSDictionary> getSignatureDictionaries() throws IOException { List<COSDictionary> signatureFields = getSignatureFields(false); List<COSDictionary> signatures = new LinkedList<COSDictionary>(); for (COSDictionary dict : signatureFields) { COSBase dictionaryObject = dict.getDictionaryObject(COSName.V); if (dictionaryObject != null) { signatures.add((COSDictionary) dictionaryObject); } } return signatures; }
/** * Decode JBIG2 data using Java ImageIO library. * * <p>{@inheritDoc} */ public void decode( InputStream compressedData, OutputStream result, COSDictionary options, int filterIndex) throws IOException { /** * A working JBIG2 ImageIO plugin is needed to decode JBIG2 encoded streams. The following is * known to be working. It can't be bundled with PDFBox because of an incompatible license. * http://code.google.com/p/jbig2-imageio/ */ Iterator<ImageReader> readers = ImageIO.getImageReadersByFormatName("JBIG2"); if (!readers.hasNext()) { LOG.error("Can't find an ImageIO plugin to decode the JBIG2 encoded datastream."); return; } ImageReader reader = readers.next(); COSDictionary decodeP = (COSDictionary) options.getDictionaryObject(COSName.DECODE_PARMS); COSInteger bits = (COSInteger) options.getDictionaryObject(COSName.BITS_PER_COMPONENT); COSStream st = null; if (decodeP != null) { st = (COSStream) decodeP.getDictionaryObject(COSName.JBIG2_GLOBALS); } if (st != null) { reader.setInput( ImageIO.createImageInputStream( new SequenceInputStream(st.getFilteredStream(), compressedData))); } else { reader.setInput(ImageIO.createImageInputStream(compressedData)); } BufferedImage bi = reader.read(0); reader.dispose(); if (bi != null) { // I am assuming since JBIG2 is always black and white // depending on your renderer this might or might be needed if (bi.getColorModel().getPixelSize() != bits.intValue()) { if (bits.intValue() != 1) { LOG.error("Do not know how to deal with JBIG2 with more than 1 bit"); return; } BufferedImage packedImage = new BufferedImage(bi.getWidth(), bi.getHeight(), BufferedImage.TYPE_BYTE_BINARY); Graphics graphics = packedImage.getGraphics(); graphics.drawImage(bi, 0, 0, null); graphics.dispose(); bi = packedImage; } DataBuffer dBuf = bi.getData().getDataBuffer(); if (dBuf.getDataType() == DataBuffer.TYPE_BYTE) { result.write(((DataBufferByte) dBuf).getData()); } else { LOG.error("Image data buffer not of type byte but type " + dBuf.getDataType()); } } else { LOG.error("Something went wrong when decoding the JBIG2 encoded datastream."); } }
/** @return list of embedded files */ private List<Object> getEmbeddedFiles() { List<Object> files = new ArrayList<>(); try { COSDictionary buffer = (COSDictionary) pdDocument.getDocument().getCatalog().getObject(); buffer = getCosDictionary(buffer.getItem(COSName.NAMES)); if (buffer != null) { buffer = getCosDictionary(buffer.getItem(COSName.EMBEDDED_FILES)); } getNamesEmbeddedFiles(files, buffer); } catch (IOException e) { logger.error( "Something wrong with getting embedded files - return empty list. " + e.getMessage()); } return files; }
/** * 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.FONT_NAME, name); }
/** * 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.CHAR_SET, name); }
/** * 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.FONT_BBOX, array); }
/** * 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.FONT_STRETCH, name); }
/** * 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.FONT_FAMILY, name); }
/** * Creates a new instance based on a given {@link COSDictionary}. * * @param dict the dictionary */ public PDOptionalContentGroup(COSDictionary dict) { super(dict); if (!dict.getItem(COSName.TYPE).equals(COSName.OCG)) { throw new IllegalArgumentException( "Provided dictionary is not of type '" + COSName.OCG + "'"); } }
/** * 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(COSName.AA); if (aa != null) { return new PDFormFieldAdditionalActions(aa); } return null; }
/** * This will find one of the child elements. The name array are the components of the name to * search down the tree of names. The nameIndex is where to start in that array. This method is * called recursively until it finds the end point based on the name array. * * @param name An array that picks the path to the field. * @param nameIndex The index into the array. * @return The field at the endpoint or null if none is found. */ PDField findKid(String[] name, int nameIndex) { PDField retval = null; COSArray kids = (COSArray) dictionary.getDictionaryObject(COSName.KIDS); if (kids != null) { for (int i = 0; retval == null && i < kids.size(); i++) { COSDictionary kidDictionary = (COSDictionary) kids.getObject(i); if (name[nameIndex].equals(kidDictionary.getString(COSName.T))) { retval = PDField.fromDictionary(acroForm, kidDictionary, (PDNonTerminalField) this); if (retval != null && name.length > nameIndex + 1) { retval = retval.findKid(name, nameIndex + 1); } } } } return retval; }
/** * This will tell if this is an encrypted document. * * @return true If this document is encrypted. */ public boolean isEncrypted() { boolean encrypted = false; if (trailer != null) { encrypted = trailer.getDictionaryObject(COSName.ENCRYPT) != null; } return encrypted; }
/** * 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 PDSignatureField(acroForm, field); } else { // do nothing and return an unknown field type. } return pdField; }
/** * This will add all of the dictionarys keys/values to this dictionary, but only if they don't * already exist. If a key already exists in this dictionary then nothing is changed. * * @param dic The dic to get the keys from. */ public void mergeInto(COSDictionary dic) { for (Map.Entry<COSName, COSBase> entry : dic.entrySet()) { if (getItem(entry.getKey()) == null) { setItem(entry.getKey(), entry.getValue()); } } }
/** * Get the font name. * * @return The name of the font. */ public String getFontName() { String retval = null; COSName name = (COSName) dic.getDictionaryObject(COSName.FONT_NAME); if (name != null) { retval = name.getName(); } return retval; }