/** * Translate a PRIndirectReference to a PdfIndirectReference In addition, translates the object * numbers, and copies the referenced object to the output file. NB: PRIndirectReferences (and * PRIndirectObjects) really need to know what file they came from, because each file has its own * namespace. The translation we do from their namespace to ours is *at best* heuristic, and * guaranteed to fail under some circumstances. */ protected PdfIndirectReference copyIndirect(PRIndirectReference in) throws IOException, BadPdfFormatException { PdfIndirectReference theRef; RefKey key = new RefKey(in); IndirectReferences iRef = (IndirectReferences) indirects.get(key); if (iRef != null) { theRef = iRef.getRef(); if (iRef.getCopied()) { return theRef; } } else { theRef = body.getPdfIndirectReference(); iRef = new IndirectReferences(theRef); indirects.put(key, iRef); } PdfObject obj = PdfReader.getPdfObjectRelease(in); if (obj != null && obj.isDictionary()) { PdfObject type = PdfReader.getPdfObjectRelease(((PdfDictionary) obj).get(PdfName.TYPE)); if (type != null && PdfName.PAGE.equals(type)) { return theRef; } } iRef.setCopied(); obj = copyObject(obj); addToBody(obj, theRef); return theRef; }
/** * Gets the content stream of a page as a PdfStream object. * * @param pageNumber the page of which you want the stream * @param compressionLevel the compression level you want to apply to the stream * @return a PdfStream object * @since 2.1.3 (the method already existed without param compressionLevel) */ PdfStream getFormXObject(int pageNumber, int compressionLevel) throws IOException { PdfDictionary page = reader.getPageNRelease(pageNumber); PdfObject contents = PdfReader.getPdfObjectRelease(page.get(PdfName.CONTENTS)); PdfDictionary dic = new PdfDictionary(); byte bout[] = null; if (contents != null) { if (contents.isStream()) dic.putAll((PRStream) contents); else bout = reader.getPageContent(pageNumber, file); } else bout = new byte[0]; dic.put(PdfName.RESOURCES, PdfReader.getPdfObjectRelease(page.get(PdfName.RESOURCES))); dic.put(PdfName.TYPE, PdfName.XOBJECT); dic.put(PdfName.SUBTYPE, PdfName.FORM); PdfImportedPage impPage = (PdfImportedPage) importedPages.get(new Integer(pageNumber)); dic.put(PdfName.BBOX, new PdfRectangle(impPage.getBoundingBox())); PdfArray matrix = impPage.getMatrix(); if (matrix == null) dic.put(PdfName.MATRIX, IDENTITYMATRIX); else dic.put(PdfName.MATRIX, matrix); dic.put(PdfName.FORMTYPE, ONE); PRStream stream; if (bout == null) { stream = new PRStream((PRStream) contents, dic); } else { stream = new PRStream(reader, bout, compressionLevel); stream.putAll(dic); } return stream; }
/** * Retrieves the page labels from a PDF as an array of String objects. * * @param reader a PdfReader object that has the page labels you want to retrieve * @return a String array or <code>null</code> if no page labels are present */ public static String[] getPageLabels(PdfReader reader) { int n = reader.getNumberOfPages(); PdfDictionary dict = reader.getCatalog(); PdfDictionary labels = (PdfDictionary) PdfReader.getPdfObjectRelease(dict.get(PdfName.PAGELABELS)); if (labels == null) return null; String[] labelstrings = new String[n]; HashMap<Integer, PdfObject> numberTree = PdfNumberTree.readTree(labels); int pagecount = 1; Integer current; String prefix = ""; char type = 'D'; for (int i = 0; i < n; i++) { current = Integer.valueOf(i); if (numberTree.containsKey(current)) { PdfDictionary d = (PdfDictionary) PdfReader.getPdfObjectRelease(numberTree.get(current)); if (d.contains(PdfName.ST)) { pagecount = ((PdfNumber) d.get(PdfName.ST)).intValue(); } else { pagecount = 1; } if (d.contains(PdfName.P)) { prefix = ((PdfString) d.get(PdfName.P)).toUnicodeString(); } if (d.contains(PdfName.S)) { type = ((PdfName) d.get(PdfName.S)).toString().charAt(1); } else { type = 'e'; } } switch (type) { default: labelstrings[i] = prefix + pagecount; break; case 'R': labelstrings[i] = prefix + RomanNumberFactory.getUpperCaseString(pagecount); break; case 'r': labelstrings[i] = prefix + RomanNumberFactory.getLowerCaseString(pagecount); break; case 'A': labelstrings[i] = prefix + RomanAlphabetFactory.getUpperCaseString(pagecount); break; case 'a': labelstrings[i] = prefix + RomanAlphabetFactory.getLowerCaseString(pagecount); break; case 'e': labelstrings[i] = prefix; break; } pagecount++; } return labelstrings; }
/** * Retrieves the page labels from a PDF as an array of {@link PdfPageLabelFormat} objects. * * @param reader a PdfReader object that has the page labels you want to retrieve * @return a PdfPageLabelEntry array, containing an entry for each format change or <code>null * </code> if no page labels are present */ public static PdfPageLabelFormat[] getPageLabelFormats(PdfReader reader) { PdfDictionary dict = reader.getCatalog(); PdfDictionary labels = (PdfDictionary) PdfReader.getPdfObjectRelease(dict.get(PdfName.PAGELABELS)); if (labels == null) return null; HashMap<Integer, PdfObject> numberTree = PdfNumberTree.readTree(labels); Integer numbers[] = new Integer[numberTree.size()]; numbers = numberTree.keySet().toArray(numbers); Arrays.sort(numbers); PdfPageLabelFormat[] formats = new PdfPageLabelFormat[numberTree.size()]; String prefix; int numberStyle; int pagecount; for (int k = 0; k < numbers.length; ++k) { Integer key = numbers[k]; PdfDictionary d = (PdfDictionary) PdfReader.getPdfObjectRelease(numberTree.get(key)); if (d.contains(PdfName.ST)) { pagecount = ((PdfNumber) d.get(PdfName.ST)).intValue(); } else { pagecount = 1; } if (d.contains(PdfName.P)) { prefix = ((PdfString) d.get(PdfName.P)).toUnicodeString(); } else { prefix = ""; } if (d.contains(PdfName.S)) { char type = ((PdfName) d.get(PdfName.S)).toString().charAt(1); switch (type) { case 'R': numberStyle = UPPERCASE_ROMAN_NUMERALS; break; case 'r': numberStyle = LOWERCASE_ROMAN_NUMERALS; break; case 'A': numberStyle = UPPERCASE_LETTERS; break; case 'a': numberStyle = LOWERCASE_LETTERS; break; default: numberStyle = DECIMAL_ARABIC_NUMERALS; break; } } else { numberStyle = EMPTY; } formats[k] = new PdfPageLabelFormat(key.intValue() + 1, numberStyle, prefix, pagecount); } return formats; }
/** * After reading, we index all of the fields. Recursive. * * @param fieldlist An array of fields * @param fieldDict the last field dictionary we encountered (recursively) * @param title the pathname of the field, up to this point or null */ protected void iterateFields(PdfArray fieldlist, PRIndirectReference fieldDict, String title) { for (Iterator it = fieldlist.getArrayList().iterator(); it.hasNext(); ) { PRIndirectReference ref = (PRIndirectReference) it.next(); PdfDictionary dict = (PdfDictionary) PdfReader.getPdfObjectRelease(ref); // if we are not a field dictionary, pass our parent's values PRIndirectReference myFieldDict = fieldDict; String myTitle = title; PdfString tField = (PdfString) dict.get(PdfName.T); boolean isFieldDict = tField != null; if (isFieldDict) { myFieldDict = ref; if (title == null) myTitle = tField.toString(); else myTitle = title + '.' + tField.toString(); } PdfArray kids = (PdfArray) dict.get(PdfName.KIDS); if (kids != null) { pushAttrib(dict); iterateFields(kids, myFieldDict, myTitle); stack.remove(stack.size() - 1); // pop } else { // leaf node if (myFieldDict != null) { PdfDictionary mergedDict = (PdfDictionary) stack.get(stack.size() - 1); if (isFieldDict) mergedDict = mergeAttrib(mergedDict, dict); mergedDict.put(PdfName.T, new PdfString(myTitle)); FieldInformation fi = new FieldInformation(myTitle, mergedDict, myFieldDict); fields.add(fi); fieldByName.put(myTitle, fi); } } } }
/** * Read, and comprehend the acroform * * @param root the docment root */ public void readAcroForm(PdfDictionary root) { if (root == null) return; hashMap = root.hashMap; pushAttrib(root); PdfArray fieldlist = (PdfArray) PdfReader.getPdfObjectRelease(root.get(PdfName.FIELDS)); iterateFields(fieldlist, null, null); }
void propagate(PdfObject obj, PdfIndirectReference refo, boolean restricted) throws IOException { if (obj == null) return; // if (refo != null) // addToBody(obj, refo); if (obj instanceof PdfIndirectReference) return; switch (obj.type()) { case PdfObject.DICTIONARY: case PdfObject.STREAM: { PdfDictionary dic = (PdfDictionary) obj; for (PdfName key : dic.getKeys()) { if (restricted && (key.equals(PdfName.PARENT) || key.equals(PdfName.KIDS))) continue; PdfObject ob = dic.get(key); if (ob != null && ob.isIndirect()) { PRIndirectReference ind = (PRIndirectReference) ob; if (!setVisited(ind) && !isPage(ind)) { PdfIndirectReference ref = getNewReference(ind); propagate(PdfReader.getPdfObjectRelease(ind), ref, restricted); } } else propagate(ob, null, restricted); } break; } case PdfObject.ARRAY: { // PdfArray arr = new PdfArray(); for (Iterator<PdfObject> it = ((PdfArray) obj).listIterator(); it.hasNext(); ) { PdfObject ob = it.next(); if (ob != null && ob.isIndirect()) { PRIndirectReference ind = (PRIndirectReference) ob; if (!isVisited(ind) && !isPage(ind)) { PdfIndirectReference ref = getNewReference(ind); propagate(PdfReader.getPdfObjectRelease(ind), ref, restricted); } } else propagate(ob, null, restricted); } break; } case PdfObject.INDIRECT: { throw new RuntimeException( MessageLocalization.getComposedMessage("reference.pointing.to.reference")); } } }
private IntHashtable readWidths(PdfArray ws) { IntHashtable hh = new IntHashtable(); if (ws == null) return hh; for (int k = 0; k < ws.size(); ++k) { int c1 = ((PdfNumber) PdfReader.getPdfObjectRelease(ws.getPdfObject(k))).intValue(); PdfObject obj = PdfReader.getPdfObjectRelease(ws.getPdfObject(++k)); if (obj.isArray()) { PdfArray a2 = (PdfArray) obj; for (int j = 0; j < a2.size(); ++j) { int c2 = ((PdfNumber) PdfReader.getPdfObjectRelease(a2.getPdfObject(j))).intValue(); hh.put(c1++, c2); } } else { int c2 = ((PdfNumber) obj).intValue(); int w = ((PdfNumber) PdfReader.getPdfObjectRelease(ws.getPdfObject(++k))).intValue(); for (; c1 <= c2; ++c1) hh.put(c1, w); } } return hh; }
void writeAllVisited() throws IOException { while (!nextRound.isEmpty()) { ArrayList vec = nextRound; nextRound = new ArrayList(); for (int k = 0; k < vec.size(); ++k) { Integer i = (Integer) vec.get(k); if (!visited.containsKey(i)) { visited.put(i, null); int n = i.intValue(); writer.addToBody(reader.getPdfObjectRelease(n), myXref[n]); } } } }
private CMapToUnicode processToUnicode() { CMapToUnicode cmapRet = null; PdfObject toUni = PdfReader.getPdfObjectRelease(this.font.get(PdfName.TOUNICODE)); if (toUni instanceof PRStream) { try { byte[] touni = PdfReader.getStreamBytes((PRStream) toUni); CidLocationFromByte lb = new CidLocationFromByte(touni); cmapRet = new CMapToUnicode(); CMapParserEx.parseCid("", cmapRet, lb); } catch (Exception e) { cmapRet = null; } } return cmapRet; }
/** * Translate a PRDictionary to a PdfDictionary. Also translate all of the objects contained in it. */ protected PdfDictionary copyDictionary(PdfDictionary in) throws IOException, BadPdfFormatException { PdfDictionary out = new PdfDictionary(); PdfObject type = PdfReader.getPdfObjectRelease(in.get(PdfName.TYPE)); for (Iterator it = in.getKeys().iterator(); it.hasNext(); ) { PdfName key = (PdfName) it.next(); PdfObject value = in.get(key); // System.out.println("Copy " + key); if (type != null && PdfName.PAGE.equals(type)) { if (!key.equals(PdfName.B) && !key.equals(PdfName.PARENT)) out.put(key, copyObject(value)); } else out.put(key, copyObject(value)); } return out; }
/** Creates the new PDF by merging the fields and forms. */ protected void closeIt() throws IOException { for (int k = 0; k < readers.size(); ++k) { readers.get(k).removeFields(); } for (int r = 0; r < readers.size(); ++r) { PdfReader reader = readers.get(r); for (int page = 1; page <= reader.getNumberOfPages(); ++page) { pageRefs.add(getNewReference(reader.getPageOrigRef(page))); pageDics.add(reader.getPageN(page)); } } mergeFields(); createAcroForms(); for (int r = 0; r < readers.size(); ++r) { PdfReader reader = readers.get(r); for (int page = 1; page <= reader.getNumberOfPages(); ++page) { PdfDictionary dic = reader.getPageN(page); PdfIndirectReference pageRef = getNewReference(reader.getPageOrigRef(page)); PdfIndirectReference parent = root.addPageRef(pageRef); dic.put(PdfName.PARENT, parent); propagate(dic, pageRef, false); } } for (Map.Entry<PdfReader, IntHashtable> entry : readers2intrefs.entrySet()) { PdfReader reader = entry.getKey(); try { file = reader.getSafeFile(); file.reOpen(); IntHashtable t = entry.getValue(); int keys[] = t.toOrderedKeys(); for (int k = 0; k < keys.length; ++k) { PRIndirectReference ref = new PRIndirectReference(reader, keys[k]); addToBody(PdfReader.getPdfObjectRelease(ref), t.get(keys[k])); } } finally { try { file.close(); // TODO: Removed - the user should be responsible for closing all PdfReaders. But, this // could cause a lot of memory leaks in code out there that hasn't been properly closing // things - maybe add a finalizer to PdfReader that calls PdfReader#close() ?? // reader.close(); } catch (Exception e) { // empty on purpose } } } pdf.close(); }
private void processType0(PdfDictionary font) { try { PdfObject toUniObject = PdfReader.getPdfObjectRelease(font.get(PdfName.TOUNICODE)); PdfArray df = (PdfArray) PdfReader.getPdfObjectRelease(font.get(PdfName.DESCENDANTFONTS)); PdfDictionary cidft = (PdfDictionary) PdfReader.getPdfObjectRelease(df.getPdfObject(0)); PdfNumber dwo = (PdfNumber) PdfReader.getPdfObjectRelease(cidft.get(PdfName.DW)); int dw = 1000; if (dwo != null) dw = dwo.intValue(); IntHashtable widths = readWidths((PdfArray) PdfReader.getPdfObjectRelease(cidft.get(PdfName.W))); PdfDictionary fontDesc = (PdfDictionary) PdfReader.getPdfObjectRelease(cidft.get(PdfName.FONTDESCRIPTOR)); fillFontDesc(fontDesc); if (toUniObject instanceof PRStream) { fillMetrics(PdfReader.getStreamBytes((PRStream) toUniObject), widths, dw); } } catch (Exception e) { throw new ExceptionConverter(e); } }
PdfObject getResources(int pageNumber) { PdfObject obj = PdfReader.getPdfObjectRelease(reader.getPageNRelease(pageNumber).get(PdfName.RESOURCES)); return obj; }