| Method from com.lowagie.text.pdf.PdfReader Detail: |
public static byte[] ASCII85Decode(byte[] in) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
int state = 0;
int chn[] = new int[5];
for (int k = 0; k < in.length; ++k) {
int ch = in[k] & 0xff;
if (ch == '~")
break;
if (PRTokeniser.isWhitespace(ch))
continue;
if (ch == 'z" && state == 0) {
out.write(0);
out.write(0);
out.write(0);
out.write(0);
continue;
}
if (ch < '!" || ch > 'u")
throw new RuntimeException("Illegal character in ASCII85Decode.");
chn[state] = ch - '!";
++state;
if (state == 5) {
state = 0;
int r = 0;
for (int j = 0; j < 5; ++j)
r = r * 85 + chn[j];
out.write((byte)(r > > 24));
out.write((byte)(r > > 16));
out.write((byte)(r > > 8));
out.write((byte)r);
}
}
int r = 0;
// We'll ignore the next two lines for the sake of perpetuating broken PDFs
// if (state == 1)
// throw new RuntimeException("Illegal length in ASCII85Decode.");
if (state == 2) {
r = chn[0] * 85 * 85 * 85 * 85 + chn[1] * 85 * 85 * 85 + 85 * 85 * 85 + 85 * 85 + 85;
out.write((byte)(r > > 24));
}
else if (state == 3) {
r = chn[0] * 85 * 85 * 85 * 85 + chn[1] * 85 * 85 * 85 + chn[2] * 85 * 85 + 85 * 85 + 85;
out.write((byte)(r > > 24));
out.write((byte)(r > > 16));
}
else if (state == 4) {
r = chn[0] * 85 * 85 * 85 * 85 + chn[1] * 85 * 85 * 85 + chn[2] * 85 * 85 + chn[3] * 85 + 85;
out.write((byte)(r > > 24));
out.write((byte)(r > > 16));
out.write((byte)(r > > 8));
}
return out.toByteArray();
}
Decodes a stream that has the ASCII85Decode filter. |
public static byte[] ASCIIHexDecode(byte[] in) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
boolean first = true;
int n1 = 0;
for (int k = 0; k < in.length; ++k) {
int ch = in[k] & 0xff;
if (ch == ' >")
break;
if (PRTokeniser.isWhitespace(ch))
continue;
int n = PRTokeniser.getHex(ch);
if (n == -1)
throw new RuntimeException("Illegal character in ASCIIHexDecode.");
if (first)
n1 = n;
else
out.write((byte)((n1 < < 4) + n));
first = !first;
}
if (!first)
out.write((byte)(n1 < < 4));
return out.toByteArray();
}
Decodes a stream that has the ASCIIHexDecode filter. |
public static byte[] FlateDecode(byte[] in) {
byte b[] = FlateDecode(in, true);
if (b == null)
return FlateDecode(in, false);
return b;
}
Decodes a stream that has the FlateDecode filter. |
public static byte[] FlateDecode(byte[] in,
boolean strict) {
ByteArrayInputStream stream = new ByteArrayInputStream(in);
InflaterInputStream zip = new InflaterInputStream(stream);
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte b[] = new byte[strict ? 4092 : 1];
try {
int n;
while ((n = zip.read(b)) >= 0) {
out.write(b, 0, n);
}
zip.close();
out.close();
return out.toByteArray();
}
catch (Exception e) {
if (strict)
return null;
return out.toByteArray();
}
}
|
public static byte[] LZWDecode(byte[] in) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
LZWDecoder lzw = new LZWDecoder();
lzw.decode(in, out);
return out.toByteArray();
}
Decodes a stream that has the LZWDecode filter. |
public PRIndirectReference addPdfObject(PdfObject obj) {
xrefObj.add(obj);
return new PRIndirectReference(this, xrefObj.size() - 1);
}
|
public void addViewerPreference(PdfName key,
PdfObject value) {
this.viewerPreferences.addViewerPreference(key, value);
setViewerPreferences(this.viewerPreferences);
}
|
public void close() {
if (!partial)
return;
try {
tokens.close();
}
catch (IOException e) {
throw new ExceptionConverter(e);
}
}
|
public byte[] computeUserPassword() {
if (!encrypted || !ownerPasswordUsed) return null;
return decrypt.computeUserPassword(password);
}
|
public void consolidateNamedDestinations() {
if (consolidateNamedDestinations)
return;
consolidateNamedDestinations = true;
HashMap names = getNamedDestination();
if (names.isEmpty())
return;
for (int k = 1; k < = pageRefs.size(); ++k) {
PdfDictionary page = pageRefs.getPageN(k);
PdfObject annotsRef;
PdfArray annots = (PdfArray)getPdfObject(annotsRef = page.get(PdfName.ANNOTS));
int annotIdx = lastXrefPartial;
releaseLastXrefPartial();
if (annots == null) {
pageRefs.releasePage(k);
continue;
}
ArrayList list = annots.getArrayList();
boolean commitAnnots = false;
for (int an = 0; an < list.size(); ++an) {
PdfObject objRef = (PdfObject)list.get(an);
if (replaceNamedDestination(objRef, names) && !objRef.isIndirect())
commitAnnots = true;
}
if (commitAnnots)
setXrefPartialObject(annotIdx, annots);
if (!commitAnnots || annotsRef.isIndirect())
pageRefs.releasePage(k);
}
PdfDictionary outlines = (PdfDictionary)getPdfObjectRelease(catalog.get(PdfName.OUTLINES));
if (outlines == null)
return;
iterateBookmarks(outlines.get(PdfName.FIRST), names);
}
Replaces all the local named links with the actual destinations. |
public int createFakeFontSubsets() {
int total = 0;
for (int k = 1; k < xrefObj.size(); ++k) {
PdfObject obj = getPdfObjectRelease(k);
if (obj == null || !obj.isDictionary())
continue;
PdfDictionary dic = (PdfDictionary)obj;
if (!existsName(dic, PdfName.TYPE, PdfName.FONT))
continue;
if (existsName(dic, PdfName.SUBTYPE, PdfName.TYPE1)
|| existsName(dic, PdfName.SUBTYPE, PdfName.MMTYPE1)
|| existsName(dic, PdfName.SUBTYPE, PdfName.TRUETYPE)) {
String s = getSubsetPrefix(dic);
if (s != null)
continue;
s = getFontName(dic);
if (s == null)
continue;
String ns = BaseFont.createSubsetPrefix() + s;
PdfDictionary fd = (PdfDictionary)getPdfObjectRelease(dic.get(PdfName.FONTDESCRIPTOR));
if (fd == null)
continue;
if (fd.get(PdfName.FONTFILE) == null && fd.get(PdfName.FONTFILE2) == null
&& fd.get(PdfName.FONTFILE3) == null)
continue;
fd = (PdfDictionary)getPdfObject(dic.get(PdfName.FONTDESCRIPTOR));
PdfName newName = new PdfName(ns);
dic.put(PdfName.BASEFONT, newName);
fd.put(PdfName.FONTNAME, newName);
setXrefPartialObject(k, dic);
++total;
}
}
return total;
}
Finds all the fonts not subset but embedded and marks them as subset. |
public static byte[] decodePredictor(byte[] in,
PdfObject dicPar) {
if (dicPar == null || !dicPar.isDictionary())
return in;
PdfDictionary dic = (PdfDictionary)dicPar;
PdfObject obj = getPdfObject(dic.get(PdfName.PREDICTOR));
if (obj == null || !obj.isNumber())
return in;
int predictor = ((PdfNumber)obj).intValue();
if (predictor < 10)
return in;
int width = 1;
obj = getPdfObject(dic.get(PdfName.COLUMNS));
if (obj != null && obj.isNumber())
width = ((PdfNumber)obj).intValue();
int colors = 1;
obj = getPdfObject(dic.get(PdfName.COLORS));
if (obj != null && obj.isNumber())
colors = ((PdfNumber)obj).intValue();
int bpc = 8;
obj = getPdfObject(dic.get(PdfName.BITSPERCOMPONENT));
if (obj != null && obj.isNumber())
bpc = ((PdfNumber)obj).intValue();
DataInputStream dataStream = new DataInputStream(new ByteArrayInputStream(in));
ByteArrayOutputStream fout = new ByteArrayOutputStream(in.length);
int bytesPerPixel = colors * bpc / 8;
int bytesPerRow = (colors*width*bpc + 7)/8;
byte[] curr = new byte[bytesPerRow];
byte[] prior = new byte[bytesPerRow];
// Decode the (sub)image row-by-row
while (true) {
// Read the filter type byte and a row of data
int filter = 0;
try {
filter = dataStream.read();
if (filter < 0) {
return fout.toByteArray();
}
dataStream.readFully(curr, 0, bytesPerRow);
} catch (Exception e) {
return fout.toByteArray();
}
switch (filter) {
case 0: //PNG_FILTER_NONE
break;
case 1: //PNG_FILTER_SUB
for (int i = bytesPerPixel; i < bytesPerRow; i++) {
curr[i] += curr[i - bytesPerPixel];
}
break;
case 2: //PNG_FILTER_UP
for (int i = 0; i < bytesPerRow; i++) {
curr[i] += prior[i];
}
break;
case 3: //PNG_FILTER_AVERAGE
for (int i = 0; i < bytesPerPixel; i++) {
curr[i] += prior[i] / 2;
}
for (int i = bytesPerPixel; i < bytesPerRow; i++) {
curr[i] += ((curr[i - bytesPerPixel] & 0xff) + (prior[i] & 0xff))/2;
}
break;
case 4: //PNG_FILTER_PAETH
for (int i = 0; i < bytesPerPixel; i++) {
curr[i] += prior[i];
}
for (int i = bytesPerPixel; i < bytesPerRow; i++) {
int a = curr[i - bytesPerPixel] & 0xff;
int b = prior[i] & 0xff;
int c = prior[i - bytesPerPixel] & 0xff;
int p = a + b - c;
int pa = Math.abs(p - a);
int pb = Math.abs(p - b);
int pc = Math.abs(p - c);
int ret;
if ((pa < = pb) && (pa < = pc)) {
ret = a;
} else if (pb < = pc) {
ret = b;
} else {
ret = c;
}
curr[i] += (byte)(ret);
}
break;
default:
// Error -- unknown filter type
throw new RuntimeException("PNG filter unknown.");
}
try {
fout.write(curr);
}
catch (IOException ioe) {
// Never happens
}
// Swap curr and prior
byte[] tmp = prior;
prior = curr;
curr = tmp;
}
}
|
public double dumpPerc() {
int total = 0;
for (int k = 0; k < xrefObj.size(); ++k) {
if (xrefObj.get(k) != null)
++total;
}
return (total * 100.0 / xrefObj.size());
}
|
protected static PdfDictionary duplicatePdfDictionary(PdfDictionary original,
PdfDictionary copy,
PdfReader newReader) {
if (copy == null)
copy = new PdfDictionary();
for (Iterator it = original.getKeys().iterator(); it.hasNext();) {
PdfName key = (PdfName)it.next();
copy.put(key, duplicatePdfObject(original.get(key), newReader));
}
return copy;
}
|
protected static PdfObject duplicatePdfObject(PdfObject original,
PdfReader newReader) {
if (original == null)
return null;
switch (original.type()) {
case PdfObject.DICTIONARY: {
return duplicatePdfDictionary((PdfDictionary)original, null, newReader);
}
case PdfObject.STREAM: {
PRStream org = (PRStream)original;
PRStream stream = new PRStream(org, null, newReader);
duplicatePdfDictionary(org, stream, newReader);
return stream;
}
case PdfObject.ARRAY: {
ArrayList list = ((PdfArray)original).getArrayList();
PdfArray arr = new PdfArray();
for (Iterator it = list.iterator(); it.hasNext();) {
arr.add(duplicatePdfObject((PdfObject)it.next(), newReader));
}
return arr;
}
case PdfObject.INDIRECT: {
PRIndirectReference org = (PRIndirectReference)original;
return new PRIndirectReference(newReader, org.getNumber(), org.getGeneration());
}
default:
return original;
}
}
|
public void eliminateSharedStreams() {
if (!sharedStreams)
return;
sharedStreams = false;
if (pageRefs.size() == 1)
return;
ArrayList newRefs = new ArrayList();
ArrayList newStreams = new ArrayList();
IntHashtable visited = new IntHashtable();
for (int k = 1; k < = pageRefs.size(); ++k) {
PdfDictionary page = pageRefs.getPageN(k);
if (page == null)
continue;
PdfObject contents = getPdfObject(page.get(PdfName.CONTENTS));
if (contents == null)
continue;
if (contents.isStream()) {
PRIndirectReference ref = (PRIndirectReference)page.get(PdfName.CONTENTS);
if (visited.containsKey(ref.getNumber())) {
// need to duplicate
newRefs.add(ref);
newStreams.add(new PRStream((PRStream)contents, null));
}
else
visited.put(ref.getNumber(), 1);
}
else if (contents.isArray()) {
PdfArray array = (PdfArray)contents;
ArrayList list = array.getArrayList();
for (int j = 0; j < list.size(); ++j) {
PRIndirectReference ref = (PRIndirectReference)list.get(j);
if (visited.containsKey(ref.getNumber())) {
// need to duplicate
newRefs.add(ref);
newStreams.add(new PRStream((PRStream)getPdfObject(ref), null));
}
else
visited.put(ref.getNumber(), 1);
}
}
}
if (newStreams.isEmpty())
return;
for (int k = 0; k < newStreams.size(); ++k) {
xrefObj.add(newStreams.get(k));
PRIndirectReference ref = (PRIndirectReference)newRefs.get(k);
ref.setNumber(xrefObj.size() - 1, 0);
}
}
Eliminates shared streams if they exist. |
static boolean equalsn(byte[] a1,
byte[] a2) {
int length = a2.length;
for (int k = 0; k < length; ++k) {
if (a1[k] != a2[k])
return false;
}
return true;
}
|
static boolean existsName(PdfDictionary dic,
PdfName key,
PdfName value) {
PdfObject type = getPdfObjectRelease(dic.get(key));
if (type == null || !type.isName())
return false;
PdfName name = (PdfName)type;
return name.equals(value);
}
|
public AcroFields getAcroFields() {
return new AcroFields(this, null);
}
Gets a read-only version of AcroFields. |
public PRAcroForm getAcroForm() {
if (!acroFormParsed) {
acroFormParsed = true;
PdfObject form = catalog.get(PdfName.ACROFORM);
if (form != null) {
try {
acroForm = new PRAcroForm(this);
acroForm.readAcroForm((PdfDictionary)getPdfObject(form));
}
catch (Exception e) {
acroForm = null;
}
}
}
return acroForm;
}
Returns the document's acroform, if it has one. |
public Rectangle getBoxSize(int index,
String boxName) {
PdfDictionary page = pageRefs.getPageNRelease(index);
PdfArray box = null;
if (boxName.equals("trim"))
box = (PdfArray)getPdfObjectRelease(page.get(PdfName.TRIMBOX));
else if (boxName.equals("art"))
box = (PdfArray)getPdfObjectRelease(page.get(PdfName.ARTBOX));
else if (boxName.equals("bleed"))
box = (PdfArray)getPdfObjectRelease(page.get(PdfName.BLEEDBOX));
else if (boxName.equals("crop"))
box = (PdfArray)getPdfObjectRelease(page.get(PdfName.CROPBOX));
else if (boxName.equals("media"))
box = (PdfArray)getPdfObjectRelease(page.get(PdfName.MEDIABOX));
if (box == null)
return null;
return getNormalizedRectangle(box);
}
Gets the box size. Allowed names are: "crop", "trim", "art", "bleed" and "media". |
public PdfDictionary getCatalog() {
return catalog;
}
Returns the document's catalog. This dictionary is not a copy,
any changes will be reflected in the catalog. |
public int getCertificationLevel() {
PdfDictionary dic = (PdfDictionary)getPdfObject(catalog.get(PdfName.PERMS));
if (dic == null)
return PdfSignatureAppearance.NOT_CERTIFIED;
dic = (PdfDictionary)getPdfObject(dic.get(PdfName.DOCMDP));
if (dic == null)
return PdfSignatureAppearance.NOT_CERTIFIED;
PdfArray arr = (PdfArray)getPdfObject(dic.get(PdfName.REFERENCE));
if (arr == null || arr.size() == 0)
return PdfSignatureAppearance.NOT_CERTIFIED;
dic = (PdfDictionary)getPdfObject((PdfObject)(arr.getArrayList().get(0)));
if (dic == null)
return PdfSignatureAppearance.NOT_CERTIFIED;
dic = (PdfDictionary)getPdfObject(dic.get(PdfName.TRANSFORMPARAMS));
if (dic == null)
return PdfSignatureAppearance.NOT_CERTIFIED;
PdfNumber p = (PdfNumber)getPdfObject(dic.get(PdfName.P));
if (p == null)
return PdfSignatureAppearance.NOT_CERTIFIED;
return p.intValue();
}
Gets the certification level for this document. The return values can be PdfSignatureAppearance.NOT_CERTIFIED,
PdfSignatureAppearance.CERTIFIED_NO_CHANGES_ALLOWED,
PdfSignatureAppearance.CERTIFIED_FORM_FILLING and
PdfSignatureAppearance.CERTIFIED_FORM_FILLING_AND_ANNOTATIONS.
No signature validation is made, use the methods available for that in AcroFields.
|
public Rectangle getCropBox(int index) {
PdfDictionary page = pageRefs.getPageNRelease(index);
PdfArray cropBox = (PdfArray)getPdfObjectRelease(page.get(PdfName.CROPBOX));
if (cropBox == null)
return getPageSize(page);
return getNormalizedRectangle(cropBox);
}
Gets the crop box without taking rotation into account. This
is the value of the /CropBox key. The crop box is the part
of the document to be displayed or printed. It usually is the same
as the media box but may be smaller. If the page doesn't have a crop
box the page size will be returned. |
public int getCryptoMode() {
if (decrypt == null)
return -1;
else
return decrypt.getCryptoMode();
}
|
PdfIndirectReference getCryptoRef() {
if (cryptoRef == null)
return null;
return new PdfIndirectReference(0, cryptoRef.getNumber(), cryptoRef.getGeneration());
}
|
PdfEncryption getDecrypt() {
return decrypt;
}
|
public int getEofPos() {
return eofPos;
}
Gets the byte address of the %%EOF marker. |
public int getFileLength() {
return fileLength;
}
Getter for property fileLength. |
static String getFontName(PdfDictionary dic) {
if (dic == null)
return null;
PdfObject type = getPdfObjectRelease(dic.get(PdfName.BASEFONT));
if (type == null || !type.isName())
return null;
return PdfName.decodeName(type.toString());
}
|
public HashMap getInfo() {
HashMap map = new HashMap();
PdfDictionary info = (PdfDictionary)getPdfObject(trailer.get(PdfName.INFO));
if (info == null)
return map;
for (Iterator it = info.getKeys().iterator(); it.hasNext();) {
PdfName key = (PdfName)it.next();
PdfObject obj = getPdfObject(info.get(key));
if (obj == null)
continue;
String value = obj.toString();
switch (obj.type()) {
case PdfObject.STRING: {
value = ((PdfString)obj).toUnicodeString();
break;
}
case PdfObject.NAME: {
value = PdfName.decodeName(value);
break;
}
}
map.put(PdfName.decodeName(key.toString()), value);
}
return map;
}
Returns the content of the document information dictionary as a HashMap
of String. |
public String getJavaScript() throws IOException {
RandomAccessFileOrArray rf = getSafeFile();
try {
rf.reOpen();
return getJavaScript(rf);
}
finally {
try{rf.close();}catch(Exception e){}
}
}
Gets the global document JavaScript. |
public String getJavaScript(RandomAccessFileOrArray file) throws IOException {
PdfDictionary names = (PdfDictionary)getPdfObjectRelease(catalog.get(PdfName.NAMES));
if (names == null)
return null;
PdfDictionary js = (PdfDictionary)getPdfObjectRelease(names.get(PdfName.JAVASCRIPT));
if (js == null)
return null;
HashMap jscript = PdfNameTree.readTree(js);
String sortedNames[] = new String[jscript.size()];
sortedNames = (String[])jscript.keySet().toArray(sortedNames);
Arrays.sort(sortedNames);
StringBuffer buf = new StringBuffer();
for (int k = 0; k < sortedNames.length; ++k) {
PdfDictionary j = (PdfDictionary)getPdfObjectRelease((PdfIndirectReference)jscript.get(sortedNames[k]));
if (j == null)
continue;
PdfObject obj = getPdfObjectRelease(j.get(PdfName.JS));
if (obj != null) {
if (obj.isString())
buf.append(((PdfString)obj).toUnicodeString()).append('\n");
else if (obj.isStream()) {
byte bytes[] = getStreamBytes((PRStream)obj, file);
if (bytes.length >= 2 && bytes[0] == (byte)254 && bytes[1] == (byte)255)
buf.append(PdfEncodings.convertToString(bytes, PdfObject.TEXT_UNICODE));
else
buf.append(PdfEncodings.convertToString(bytes, PdfObject.TEXT_PDFDOCENCODING));
buf.append('\n");
}
}
}
return buf.toString();
}
Gets the global document JavaScript. |
public int getLastXref() {
return lastXref;
}
Gets the byte address of the last xref table. |
public ArrayList getLinks(int page) {
pageRefs.resetReleasePage();
ArrayList result = new ArrayList();
PdfDictionary pageDic = pageRefs.getPageN(page);
if (pageDic.get(PdfName.ANNOTS) != null) {
PdfArray annots = (PdfArray)getPdfObject(pageDic.get(PdfName.ANNOTS));
ArrayList arr = annots.getArrayList();
for (int j = 0; j < arr.size(); ++j) {
PdfDictionary annot = (PdfDictionary)getPdfObjectRelease((PdfObject)arr.get(j));
if (PdfName.LINK.equals(annot.get(PdfName.SUBTYPE))) {
result.add(new PdfAnnotation.PdfImportedLink(annot));
}
}
}
pageRefs.releasePage(page);
pageRefs.resetReleasePage();
return result;
}
|
public byte[] getMetadata() throws IOException {
PdfObject obj = getPdfObject(catalog.get(PdfName.METADATA));
if (!(obj instanceof PRStream))
return null;
RandomAccessFileOrArray rf = getSafeFile();
byte b[] = null;
try {
rf.reOpen();
b = getStreamBytes((PRStream)obj, rf);
}
finally {
try {
rf.close();
}
catch (Exception e) {
// empty on purpose
}
}
return b;
}
|
public HashMap getNamedDestination() {
HashMap names = getNamedDestinationFromNames();
names.putAll(getNamedDestinationFromStrings());
return names;
}
Gets all the named destinations as an HashMap. The key is the name
and the value is the destinations array. |
public HashMap getNamedDestinationFromNames() {
HashMap names = new HashMap();
if (catalog.get(PdfName.DESTS) != null) {
PdfDictionary dic = (PdfDictionary)getPdfObjectRelease(catalog.get(PdfName.DESTS));
if (dic == null)
return names;
Set keys = dic.getKeys();
for (Iterator it = keys.iterator(); it.hasNext();) {
PdfName key = (PdfName)it.next();
String name = PdfName.decodeName(key.toString());
PdfArray arr = getNameArray(dic.get(key));
if (arr != null)
names.put(name, arr);
}
}
return names;
}
Gets the named destinations from the /Dests key in the catalog as an HashMap. The key is the name
and the value is the destinations array. |
public HashMap getNamedDestinationFromStrings() {
if (catalog.get(PdfName.NAMES) != null) {
PdfDictionary dic = (PdfDictionary)getPdfObjectRelease(catalog.get(PdfName.NAMES));
if (dic != null) {
dic = (PdfDictionary)getPdfObjectRelease(dic.get(PdfName.DESTS));
if (dic != null) {
HashMap names = PdfNameTree.readTree(dic);
for (Iterator it = names.entrySet().iterator(); it.hasNext();) {
Map.Entry entry = (Map.Entry)it.next();
PdfArray arr = getNameArray((PdfObject)entry.getValue());
if (arr != null)
entry.setValue(arr);
else
it.remove();
}
return names;
}
}
}
return new HashMap();
}
Gets the named destinations from the /Names key in the catalog as an HashMap. The key is the name
and the value is the destinations array. |
public static Rectangle getNormalizedRectangle(PdfArray box) {
ArrayList rect = box.getArrayList();
float llx = ((PdfNumber)getPdfObjectRelease((PdfObject)rect.get(0))).floatValue();
float lly = ((PdfNumber)getPdfObjectRelease((PdfObject)rect.get(1))).floatValue();
float urx = ((PdfNumber)getPdfObjectRelease((PdfObject)rect.get(2))).floatValue();
float ury = ((PdfNumber)getPdfObjectRelease((PdfObject)rect.get(3))).floatValue();
return new Rectangle(Math.min(llx, urx), Math.min(lly, ury),
Math.max(llx, urx), Math.max(lly, ury));
}
Normalizes a Rectangle so that llx and lly are smaller than urx and ury. |
public int getNumberOfPages() {
return pageRefs.size();
}
Gets the number of pages in the document. |
public byte[] getPageContent(int pageNum) throws IOException {
RandomAccessFileOrArray rf = getSafeFile();
try {
rf.reOpen();
return getPageContent(pageNum, rf);
}
finally {
try{rf.close();}catch(Exception e){}
}
}
Gets the contents of the page. |
public byte[] getPageContent(int pageNum,
RandomAccessFileOrArray file) throws IOException {
PdfDictionary page = getPageNRelease(pageNum);
if (page == null)
return null;
PdfObject contents = getPdfObjectRelease(page.get(PdfName.CONTENTS));
if (contents == null)
return new byte[0];
ByteArrayOutputStream bout = null;
if (contents.isStream()) {
return getStreamBytes((PRStream)contents, file);
}
else if (contents.isArray()) {
PdfArray array = (PdfArray)contents;
ArrayList list = array.getArrayList();
bout = new ByteArrayOutputStream();
for (int k = 0; k < list.size(); ++k) {
PdfObject item = getPdfObjectRelease((PdfObject)list.get(k));
if (item == null || !item.isStream())
continue;
byte[] b = getStreamBytes((PRStream)item, file);
bout.write(b);
if (k != list.size() - 1)
bout.write('\n");
}
return bout.toByteArray();
}
else
return new byte[0];
}
Gets the contents of the page. |
public PdfDictionary getPageN(int pageNum) {
PdfDictionary dic = pageRefs.getPageN(pageNum);
if (dic == null)
return null;
if (appendable)
dic.setIndRef(pageRefs.getPageOrigRef(pageNum));
return dic;
}
Gets the dictionary that represents a page. |
public PdfDictionary getPageNRelease(int pageNum) {
PdfDictionary dic = getPageN(pageNum);
pageRefs.releasePage(pageNum);
return dic;
}
|
public PRIndirectReference getPageOrigRef(int pageNum) {
return pageRefs.getPageOrigRef(pageNum);
}
Gets the page reference to this page. |
public int getPageRotation(int index) {
return getPageRotation(pageRefs.getPageNRelease(index));
}
Gets the page rotation. This value can be 0, 90, 180 or 270. |
int getPageRotation(PdfDictionary page) {
PdfNumber rotate = (PdfNumber)getPdfObject(page.get(PdfName.ROTATE));
if (rotate == null)
return 0;
else {
int n = rotate.intValue();
n %= 360;
return n < 0 ? n + 360 : n;
}
}
|
public Rectangle getPageSize(int index) {
return getPageSize(pageRefs.getPageNRelease(index));
}
Gets the page size without taking rotation into account. This
is the value of the /MediaBox key. |
public Rectangle getPageSize(PdfDictionary page) {
PdfArray mediaBox = (PdfArray)getPdfObject(page.get(PdfName.MEDIABOX));
return getNormalizedRectangle(mediaBox);
}
Gets the page from a page dictionary |
public Rectangle getPageSizeWithRotation(int index) {
return getPageSizeWithRotation(pageRefs.getPageNRelease(index));
}
Gets the page size, taking rotation into account. This
is a Rectangle with the value of the /MediaBox and the /Rotate key. |
public Rectangle getPageSizeWithRotation(PdfDictionary page) {
Rectangle rect = getPageSize(page);
int rotation = getPageRotation(page);
while (rotation > 0) {
rect = rect.rotate();
rotation -= 90;
}
return rect;
}
Gets the rotated page from a page dictionary. |
public static PdfObject getPdfObject(PdfObject obj) {
if (obj == null)
return null;
if (!obj.isIndirect())
return obj;
try {
PRIndirectReference ref = (PRIndirectReference)obj;
int idx = ref.getNumber();
boolean appendable = ref.getReader().appendable;
obj = ref.getReader().getPdfObject(idx);
if (obj == null) {
return null;
}
else {
if (appendable) {
switch (obj.type()) {
case PdfObject.NULL:
obj = new PdfNull();
break;
case PdfObject.BOOLEAN:
obj = new PdfBoolean(((PdfBoolean)obj).booleanValue());
break;
case PdfObject.NAME:
obj = new PdfName(obj.getBytes());
break;
}
obj.setIndRef(ref);
}
return obj;
}
}
catch (Exception e) {
throw new ExceptionConverter(e);
}
}
Reads a PdfObject resolving an indirect reference
if needed. |
public PdfObject getPdfObject(int idx) {
try {
lastXrefPartial = -1;
if (idx < 0 || idx >= xrefObj.size())
return null;
PdfObject obj = (PdfObject)xrefObj.get(idx);
if (!partial || obj != null)
return obj;
if (idx * 2 >= xref.length)
return null;
obj = readSingleObject(idx);
lastXrefPartial = -1;
if (obj != null)
lastXrefPartial = idx;
return obj;
}
catch (Exception e) {
throw new ExceptionConverter(e);
}
}
|
public static PdfObject getPdfObject(PdfObject obj,
PdfObject parent) {
if (obj == null)
return null;
if (!obj.isIndirect()) {
PRIndirectReference ref = null;
if (parent != null && (ref = parent.getIndRef()) != null && ref.getReader().isAppendable()) {
switch (obj.type()) {
case PdfObject.NULL:
obj = new PdfNull();
break;
case PdfObject.BOOLEAN:
obj = new PdfBoolean(((PdfBoolean)obj).booleanValue());
break;
case PdfObject.NAME:
obj = new PdfName(obj.getBytes());
break;
}
obj.setIndRef(ref);
}
return obj;
}
return getPdfObject(obj);
}
|
public static PdfObject getPdfObjectRelease(PdfObject obj) {
PdfObject obj2 = getPdfObject(obj);
releaseLastXrefPartial(obj);
return obj2;
}
|
public PdfObject getPdfObjectRelease(int idx) {
PdfObject obj = getPdfObject(idx);
releaseLastXrefPartial();
return obj;
}
|
public static PdfObject getPdfObjectRelease(PdfObject obj,
PdfObject parent) {
PdfObject obj2 = getPdfObject(obj, parent);
releaseLastXrefPartial(obj);
return obj2;
}
Reads a PdfObject resolving an indirect reference
if needed. If the reader was opened in partial mode the object will be released
to save memory. |
protected PdfReaderInstance getPdfReaderInstance(PdfWriter writer) {
return new PdfReaderInstance(this, writer);
}
|
public char getPdfVersion() {
return pdfVersion;
}
Gets the PDF version. Only the last version char is returned. For example
version 1.4 is returned as '4'. |
public int getPermissions() {
return pValue;
}
Gets the encryption permissions. It can be used directly in
PdfWriter.setEncryption(). |
public RandomAccessFileOrArray getSafeFile() {
return tokens.getSafeFile();
}
Gets a new file instance of the original PDF
document. |
public int getSimpleViewerPreferences() {
return PdfViewerPreferencesImp.getViewerPreferences(catalog).getPageLayoutAndMode();
}
|
public static byte[] getStreamBytes(PRStream stream) throws IOException {
RandomAccessFileOrArray rf = stream.getReader().getSafeFile();
try {
rf.reOpen();
return getStreamBytes(stream, rf);
}
finally {
try{rf.close();}catch(Exception e){}
}
}
Get the content from a stream applying the required filters. |
public static byte[] getStreamBytes(PRStream stream,
RandomAccessFileOrArray file) throws IOException {
PdfObject filter = getPdfObjectRelease(stream.get(PdfName.FILTER));
byte[] b = getStreamBytesRaw(stream, file);
ArrayList filters = new ArrayList();
if (filter != null) {
if (filter.isName())
filters.add(filter);
else if (filter.isArray())
filters = ((PdfArray)filter).getArrayList();
}
ArrayList dp = new ArrayList();
PdfObject dpo = getPdfObjectRelease(stream.get(PdfName.DECODEPARMS));
if (dpo == null || (!dpo.isDictionary() && !dpo.isArray()))
dpo = getPdfObjectRelease(stream.get(PdfName.DP));
if (dpo != null) {
if (dpo.isDictionary())
dp.add(dpo);
else if (dpo.isArray())
dp = ((PdfArray)dpo).getArrayList();
}
String name;
for (int j = 0; j < filters.size(); ++j) {
name = ((PdfName)getPdfObjectRelease((PdfObject)filters.get(j))).toString();
if (name.equals("/FlateDecode") || name.equals("/Fl")) {
b = FlateDecode(b);
PdfObject dicParam = null;
if (j < dp.size()) {
dicParam = (PdfObject)dp.get(j);
b = decodePredictor(b, dicParam);
}
}
else if (name.equals("/ASCIIHexDecode") || name.equals("/AHx"))
b = ASCIIHexDecode(b);
else if (name.equals("/ASCII85Decode") || name.equals("/A85"))
b = ASCII85Decode(b);
else if (name.equals("/LZWDecode")) {
b = LZWDecode(b);
PdfObject dicParam = null;
if (j < dp.size()) {
dicParam = (PdfObject)dp.get(j);
b = decodePredictor(b, dicParam);
}
}
else if (name.equals("/Crypt")) {
}
else
throw new IOException("The filter " + name + " is not supported.");
}
return b;
}
Get the content from a stream applying the required filters. |
public static byte[] getStreamBytesRaw(PRStream stream) throws IOException {
RandomAccessFileOrArray rf = stream.getReader().getSafeFile();
try {
rf.reOpen();
return getStreamBytesRaw(stream, rf);
}
finally {
try{rf.close();}catch(Exception e){}
}
}
Get the content from a stream as it is without applying any filter. |
public static byte[] getStreamBytesRaw(PRStream stream,
RandomAccessFileOrArray file) throws IOException {
PdfReader reader = stream.getReader();
byte b[];
if (stream.getOffset() < 0)
b = stream.getBytes();
else {
b = new byte[stream.getLength()];
file.seek(stream.getOffset());
file.readFully(b);
PdfEncryption decrypt = reader.getDecrypt();
if (decrypt != null) {
PdfObject filter = getPdfObjectRelease(stream.get(PdfName.FILTER));
ArrayList filters = new ArrayList();
if (filter != null) {
if (filter.isName())
filters.add(filter);
else if (filter.isArray())
filters = ((PdfArray)filter).getArrayList();
}
boolean skip = false;
for (int k = 0; k < filters.size(); ++k) {
PdfObject obj = getPdfObjectRelease((PdfObject)filters.get(k));
if (obj != null && obj.toString().equals("/Crypt")) {
skip = true;
break;
}
}
if (!skip) {
decrypt.setHashKey(stream.getObjNum(), stream.getObjGen());
b = decrypt.decryptByteArray(b);
}
}
}
return b;
}
Get the content from a stream as it is without applying any filter. |
static String getSubsetPrefix(PdfDictionary dic) {
if (dic == null)
return null;
String s = getFontName(dic);
if (s == null)
return null;
if (s.length() < 8 || s.charAt(6) != '+")
return null;
for (int k = 0; k < 6; ++k) {
char c = s.charAt(k);
if (c < 'A" || c > 'Z")
return null;
}
return s;
}
|
public PdfDictionary getTrailer() {
return trailer;
}
Gets the trailer dictionary |
public int getXrefSize() {
return xrefObj.size();
}
Gets the number of xref objects. |
public boolean is128Key() {
return rValue == 3;
}
Returns true if the PDF has a 128 bit key encryption. |
public boolean isAppendable() {
return this.appendable;
}
Getter for property appendable. |
public boolean isEncrypted() {
return encrypted;
}
Returns true if the PDF is encrypted. |
public boolean isHybridXref() {
return hybridXref;
}
Getter for property hybridXref. |
public boolean isMetadataEncrypted() {
if (decrypt == null)
return false;
else
return decrypt.isMetadataEncrypted();
}
|
public boolean isNewXrefType() {
return newXrefType;
}
Getter for property newXrefType. |
public final boolean isOpenedWithFullPermissions() {
return !encrypted || ownerPasswordUsed;
}
Checks if the document was opened with the owner password so that the end application
can decide what level of access restrictions to apply. If the document is not encrypted
it will return true. |
public boolean isRebuilt() {
return this.rebuilt;
}
Checks if the document had errors and was rebuilt. |
public boolean isTampered() {
return tampered;
}
Checks if the document was changed. |
public static PdfObject killIndirect(PdfObject obj) {
if (obj == null || obj.isNull())
return null;
PdfObject ret = getPdfObjectRelease(obj);
if (obj.isIndirect()) {
PRIndirectReference ref = (PRIndirectReference)obj;
PdfReader reader = ref.getReader();
int n = ref.getNumber();
reader.xrefObj.set(n, null);
if (reader.partial)
reader.xref[n * 2] = -1;
}
return ret;
}
Eliminates the reference to the object freeing the memory used by it and clearing
the xref entry. |
protected void killXref(PdfObject obj) {
if (obj == null)
return;
if ((obj instanceof PdfIndirectReference) && !obj.isIndirect())
return;
switch (obj.type()) {
case PdfObject.INDIRECT: {
int xr = ((PRIndirectReference)obj).getNumber();
obj = (PdfObject)xrefObj.get(xr);
xrefObj.set(xr, null);
freeXref = xr;
killXref(obj);
break;
}
case PdfObject.ARRAY: {
ArrayList t = ((PdfArray)obj).getArrayList();
for (int i = 0; i < t.size(); ++i)
killXref((PdfObject)t.get(i));
break;
}
case PdfObject.STREAM:
case PdfObject.DICTIONARY: {
PdfDictionary dic = (PdfDictionary)obj;
for (Iterator i = dic.getKeys().iterator(); i.hasNext();){
killXref(dic.get((PdfName)i.next()));
}
break;
}
}
}
|
protected PdfArray readArray() throws IOException {
PdfArray array = new PdfArray();
while (true) {
PdfObject obj = readPRObject();
int type = obj.type();
if (-type == PRTokeniser.TK_END_ARRAY)
break;
if (-type == PRTokeniser.TK_END_DIC)
tokens.throwError("Unexpected ' > >'");
array.add(obj);
}
return array;
}
|
protected PdfDictionary readDictionary() throws IOException {
PdfDictionary dic = new PdfDictionary();
while (true) {
tokens.nextValidToken();
if (tokens.getTokenType() == PRTokeniser.TK_END_DIC)
break;
if (tokens.getTokenType() != PRTokeniser.TK_NAME)
tokens.throwError("Dictionary key is not a name.");
PdfName name = new PdfName(tokens.getStringValue(), false);
PdfObject obj = readPRObject();
int type = obj.type();
if (-type == PRTokeniser.TK_END_DIC)
tokens.throwError("Unexpected ' > >'");
if (-type == PRTokeniser.TK_END_ARRAY)
tokens.throwError("Unexpected ']'");
dic.put(name, obj);
}
return dic;
}
|
protected void readDocObj() throws IOException {
ArrayList streams = new ArrayList();
xrefObj = new ArrayList(xref.length / 2);
xrefObj.addAll(Collections.nCopies(xref.length / 2, null));
for (int k = 2; k < xref.length; k += 2) {
int pos = xref[k];
if (pos < = 0 || xref[k + 1] > 0)
continue;
tokens.seek(pos);
tokens.nextValidToken();
if (tokens.getTokenType() != PRTokeniser.TK_NUMBER)
tokens.throwError("Invalid object number.");
objNum = tokens.intValue();
tokens.nextValidToken();
if (tokens.getTokenType() != PRTokeniser.TK_NUMBER)
tokens.throwError("Invalid generation number.");
objGen = tokens.intValue();
tokens.nextValidToken();
if (!tokens.getStringValue().equals("obj"))
tokens.throwError("Token 'obj' expected.");
PdfObject obj;
try {
obj = readPRObject();
if (obj.isStream()) {
streams.add(obj);
}
}
catch (Exception e) {
obj = null;
}
xrefObj.set(k / 2, obj);
}
for (int k = 0; k < streams.size(); ++k) {
checkPRStreamLength((PRStream)streams.get(k));
}
readDecryptedDocObj();
if (objStmMark != null) {
for (Iterator i = objStmMark.entrySet().iterator(); i.hasNext();) {
Map.Entry entry = (Map.Entry)i.next();
int n = ((Integer)entry.getKey()).intValue();
IntHashtable h = (IntHashtable)entry.getValue();
readObjStm((PRStream)xrefObj.get(n), h);
xrefObj.set(n, null);
}
objStmMark = null;
}
xref = null;
}
|
protected void readDocObjPartial() throws IOException {
xrefObj = new ArrayList(xref.length / 2);
xrefObj.addAll(Collections.nCopies(xref.length / 2, null));
readDecryptedDocObj();
if (objStmToOffset != null) {
int keys[] = objStmToOffset.getKeys();
for (int k = 0; k < keys.length; ++k) {
int n = keys[k];
objStmToOffset.put(n, xref[n * 2]);
xref[n * 2] = -1;
}
}
}
|
protected void readObjStm(PRStream stream,
IntHashtable map) throws IOException {
int first = ((PdfNumber)getPdfObject(stream.get(PdfName.FIRST))).intValue();
int n = ((PdfNumber)getPdfObject(stream.get(PdfName.N))).intValue();
byte b[] = getStreamBytes(stream, tokens.getFile());
PRTokeniser saveTokens = tokens;
tokens = new PRTokeniser(b);
try {
int address[] = new int[n];
int objNumber[] = new int[n];
boolean ok = true;
for (int k = 0; k < n; ++k) {
ok = tokens.nextToken();
if (!ok)
break;
if (tokens.getTokenType() != PRTokeniser.TK_NUMBER) {
ok = false;
break;
}
objNumber[k] = tokens.intValue();
ok = tokens.nextToken();
if (!ok)
break;
if (tokens.getTokenType() != PRTokeniser.TK_NUMBER) {
ok = false;
break;
}
address[k] = tokens.intValue() + first;
}
if (!ok)
throw new IOException("Error reading ObjStm");
for (int k = 0; k < n; ++k) {
if (map.containsKey(k)) {
tokens.seek(address[k]);
PdfObject obj = readPRObject();
xrefObj.set(objNumber[k], obj);
}
}
}
finally {
tokens = saveTokens;
}
}
|
protected PdfObject readOneObjStm(PRStream stream,
int idx) throws IOException {
int first = ((PdfNumber)getPdfObject(stream.get(PdfName.FIRST))).intValue();
byte b[] = getStreamBytes(stream, tokens.getFile());
PRTokeniser saveTokens = tokens;
tokens = new PRTokeniser(b);
try {
int address = 0;
boolean ok = true;
++idx;
for (int k = 0; k < idx; ++k) {
ok = tokens.nextToken();
if (!ok)
break;
if (tokens.getTokenType() != PRTokeniser.TK_NUMBER) {
ok = false;
break;
}
ok = tokens.nextToken();
if (!ok)
break;
if (tokens.getTokenType() != PRTokeniser.TK_NUMBER) {
ok = false;
break;
}
address = tokens.intValue() + first;
}
if (!ok)
throw new IOException("Error reading ObjStm");
tokens.seek(address);
return readPRObject();
}
finally {
tokens = saveTokens;
}
}
|
protected PdfObject readPRObject() throws IOException {
tokens.nextValidToken();
int type = tokens.getTokenType();
switch (type) {
case PRTokeniser.TK_START_DIC: {
PdfDictionary dic = readDictionary();
int pos = tokens.getFilePointer();
// be careful in the trailer. May not be a "next" token.
if (tokens.nextToken() && tokens.getStringValue().equals("stream")) {
int ch = tokens.read();
if (ch != '\n")
ch = tokens.read();
if (ch != '\n")
tokens.backOnePosition(ch);
PRStream stream = new PRStream(this, tokens.getFilePointer());
stream.putAll(dic);
stream.setObjNum(objNum, objGen);
return stream;
}
else {
tokens.seek(pos);
return dic;
}
}
case PRTokeniser.TK_START_ARRAY:
return readArray();
case PRTokeniser.TK_NUMBER:
return new PdfNumber(tokens.getStringValue());
case PRTokeniser.TK_STRING:
PdfString str = new PdfString(tokens.getStringValue(), null).setHexWriting(tokens.isHexString());
str.setObjNum(objNum, objGen);
if (strings != null)
strings.add(str);
return str;
case PRTokeniser.TK_NAME:
return new PdfName(tokens.getStringValue(), false);
case PRTokeniser.TK_REF:
int num = tokens.getReference();
PRIndirectReference ref = new PRIndirectReference(this, num, tokens.getGeneration());
return ref;
default:
String sv = tokens.getStringValue();
if ("null".equals(sv))
return PdfNull.PDFNULL;
else if ("true".equals(sv))
return PdfBoolean.PDFTRUE;
else if ("false".equals(sv))
return PdfBoolean.PDFFALSE;
return new PdfLiteral(-type, tokens.getStringValue());
}
}
|
protected void readPages() throws IOException {
catalog = (PdfDictionary)getPdfObject(trailer.get(PdfName.ROOT));
rootPages = (PdfDictionary)getPdfObject(catalog.get(PdfName.PAGES));
pageRefs = new PageRefs(this);
}
|
protected void readPdf() throws IOException {
try {
fileLength = tokens.getFile().length();
pdfVersion = tokens.checkPdfHeader();
try {
readXref();
}
catch (Exception e) {
try {
rebuilt = true;
rebuildXref();
lastXref = -1;
}
catch (Exception ne) {
throw new IOException("Rebuild failed: " + ne.getMessage() + "; Original message: " + e.getMessage());
}
}
try {
readDocObj();
}
catch (Exception ne) {
if (rebuilt || encryptionError)
throw new IOException(ne.getMessage());
rebuilt = true;
encrypted = false;
rebuildXref();
lastXref = -1;
readDocObj();
}
strings.clear();
readPages();
eliminateSharedStreams();
removeUnusedObjects();
}
finally {
try {
tokens.close();
}
catch (Exception e) {
// empty on purpose
}
}
}
|
protected void readPdfPartial() throws IOException {
try {
fileLength = tokens.getFile().length();
pdfVersion = tokens.checkPdfHeader();
try {
readXref();
}
catch (Exception e) {
try {
rebuilt = true;
rebuildXref();
lastXref = -1;
}
catch (Exception ne) {
throw new IOException("Rebuild failed: " + ne.getMessage() + "; Original message: " + e.getMessage());
}
}
readDocObjPartial();
readPages();
}
catch (IOException e) {
try{tokens.close();}catch(Exception ee){}
throw e;
}
}
|
protected PdfObject readSingleObject(int k) throws IOException {
strings.clear();
int k2 = k * 2;
int pos = xref[k2];
if (pos < 0)
return null;
if (xref[k2 + 1] > 0)
pos = objStmToOffset.get(xref[k2 + 1]);
if (pos == 0)
return null;
tokens.seek(pos);
tokens.nextValidToken();
if (tokens.getTokenType() != PRTokeniser.TK_NUMBER)
tokens.throwError("Invalid object number.");
objNum = tokens.intValue();
tokens.nextValidToken();
if (tokens.getTokenType() != PRTokeniser.TK_NUMBER)
tokens.throwError("Invalid generation number.");
objGen = tokens.intValue();
tokens.nextValidToken();
if (!tokens.getStringValue().equals("obj"))
tokens.throwError("Token 'obj' expected.");
PdfObject obj;
try {
obj = readPRObject();
for (int j = 0; j < strings.size(); ++j) {
PdfString str = (PdfString)strings.get(j);
str.decrypt(this);
}
if (obj.isStream()) {
checkPRStreamLength((PRStream)obj);
}
}
catch (Exception e) {
obj = null;
}
if (xref[k2 + 1] > 0) {
obj = readOneObjStm((PRStream)obj, xref[k2]);
}
xrefObj.set(k, obj);
return obj;
}
|
protected boolean readXRefStream(int ptr) throws IOException {
tokens.seek(ptr);
int thisStream = 0;
if (!tokens.nextToken())
return false;
if (tokens.getTokenType() != PRTokeniser.TK_NUMBER)
return false;
thisStream = tokens.intValue();
if (!tokens.nextToken() || tokens.getTokenType() != PRTokeniser.TK_NUMBER)
return false;
if (!tokens.nextToken() || !tokens.getStringValue().equals("obj"))
return false;
PdfObject object = readPRObject();
PRStream stm = null;
if (object.isStream()) {
stm = (PRStream)object;
if (!PdfName.XREF.equals(stm.get(PdfName.TYPE)))
return false;
}
else
return false;
if (trailer == null) {
trailer = new PdfDictionary();
trailer.putAll(stm);
}
stm.setLength(((PdfNumber)stm.get(PdfName.LENGTH)).intValue());
int size = ((PdfNumber)stm.get(PdfName.SIZE)).intValue();
PdfArray index;
PdfObject obj = stm.get(PdfName.INDEX);
if (obj == null) {
index = new PdfArray();
index.add(new int[]{0, size});
}
else
index = (PdfArray)obj;
PdfArray w = (PdfArray)stm.get(PdfName.W);
int prev = -1;
obj = stm.get(PdfName.PREV);
if (obj != null)
prev = ((PdfNumber)obj).intValue();
// Each xref pair is a position
// type 0 - > -1, 0
// type 1 - > offset, 0
// type 2 - > index, obj num
ensureXrefSize(size * 2);
if (objStmMark == null && !partial)
objStmMark = new HashMap();
if (objStmToOffset == null && partial)
objStmToOffset = new IntHashtable();
byte b[] = getStreamBytes(stm, tokens.getFile());
int bptr = 0;
ArrayList wa = w.getArrayList();
int wc[] = new int[3];
for (int k = 0; k < 3; ++k)
wc[k] = ((PdfNumber)wa.get(k)).intValue();
ArrayList sections = index.getArrayList();
for (int idx = 0; idx < sections.size(); idx += 2) {
int start = ((PdfNumber)sections.get(idx)).intValue();
int length = ((PdfNumber)sections.get(idx + 1)).intValue();
ensureXrefSize((start + length) * 2);
while (length-- > 0) {
int type = 1;
if (wc[0] > 0) {
type = 0;
for (int k = 0; k < wc[0]; ++k)
type = (type < < 8) + (b[bptr++] & 0xff);
}
int field2 = 0;
for (int k = 0; k < wc[1]; ++k)
field2 = (field2 < < 8) + (b[bptr++] & 0xff);
int field3 = 0;
for (int k = 0; k < wc[2]; ++k)
field3 = (field3 < < 8) + (b[bptr++] & 0xff);
int base = start * 2;
if (xref[base] == 0 && xref[base + 1] == 0) {
switch (type) {
case 0:
xref[base] = -1;
break;
case 1:
xref[base] = field2;
break;
case 2:
xref[base] = field3;
xref[base + 1] = field2;
if (partial) {
objStmToOffset.put(field2, 0);
}
else {
Integer on = new Integer(field2);
IntHashtable seq = (IntHashtable)objStmMark.get(on);
if (seq == null) {
seq = new IntHashtable();
seq.put(field3, 1);
objStmMark.put(on, seq);
}
else
seq.put(field3, 1);
}
break;
}
}
++start;
}
}
thisStream *= 2;
if (thisStream < xref.length)
xref[thisStream] = -1;
if (prev == -1)
return true;
return readXRefStream(prev);
}
|
protected void readXref() throws IOException {
hybridXref = false;
newXrefType = false;
tokens.seek(tokens.getStartxref());
tokens.nextToken();
if (!tokens.getStringValue().equals("startxref"))
throw new IOException("startxref not found.");
tokens.nextToken();
if (tokens.getTokenType() != PRTokeniser.TK_NUMBER)
throw new IOException("startxref is not followed by a number.");
int startxref = tokens.intValue();
lastXref = startxref;
eofPos = tokens.getFilePointer();
try {
if (readXRefStream(startxref)) {
newXrefType = true;
return;
}
}
catch (Exception e) {}
xref = null;
tokens.seek(startxref);
trailer = readXrefSection();
PdfDictionary trailer2 = trailer;
while (true) {
PdfNumber prev = (PdfNumber)trailer2.get(PdfName.PREV);
if (prev == null)
break;
tokens.seek(prev.intValue());
trailer2 = readXrefSection();
}
}
|
protected PdfDictionary readXrefSection() throws IOException {
tokens.nextValidToken();
if (!tokens.getStringValue().equals("xref"))
tokens.throwError("xref subsection not found");
int start = 0;
int end = 0;
int pos = 0;
int gen = 0;
while (true) {
tokens.nextValidToken();
if (tokens.getStringValue().equals("trailer"))
break;
if (tokens.getTokenType() != PRTokeniser.TK_NUMBER)
tokens.throwError("Object number of the first object in this xref subsection not found");
start = tokens.intValue();
tokens.nextValidToken();
if (tokens.getTokenType() != PRTokeniser.TK_NUMBER)
tokens.throwError("Number of entries in this xref subsection not found");
end = tokens.intValue() + start;
if (start == 1) { // fix incorrect start number
int back = tokens.getFilePointer();
tokens.nextValidToken();
pos = tokens.intValue();
tokens.nextValidToken();
gen = tokens.intValue();
if (pos == 0 && gen == 65535) {
--start;
--end;
}
tokens.seek(back);
}
ensureXrefSize(end * 2);
for (int k = start; k < end; ++k) {
tokens.nextValidToken();
pos = tokens.intValue();
tokens.nextValidToken();
gen = tokens.intValue();
tokens.nextValidToken();
int p = k * 2;
if (tokens.getStringValue().equals("n")) {
if (xref[p] == 0 && xref[p + 1] == 0) {
// if (pos == 0)
// tokens.throwError("File position 0 cross-reference entry in this xref subsection");
xref[p] = pos;
}
}
else if (tokens.getStringValue().equals("f")) {
if (xref[p] == 0 && xref[p + 1] == 0)
xref[p] = -1;
}
else
tokens.throwError("Invalid cross-reference entry in this xref subsection");
}
}
PdfDictionary trailer = (PdfDictionary)readPRObject();
PdfNumber xrefSize = (PdfNumber)trailer.get(PdfName.SIZE);
ensureXrefSize(xrefSize.intValue() * 2);
PdfObject xrs = trailer.get(PdfName.XREFSTM);
if (xrs != null && xrs.isNumber()) {
int loc = ((PdfNumber)xrs).intValue();
try {
readXRefStream(loc);
newXrefType = true;
hybridXref = true;
}
catch (IOException e) {
xref = null;
throw e;
}
}
return trailer;
}
|
protected void rebuildXref() throws IOException {
hybridXref = false;
newXrefType = false;
tokens.seek(0);
int xr[][] = new int[1024][];
int top = 0;
trailer = null;
byte line[] = new byte[64];
for (;;) {
int pos = tokens.getFilePointer();
if (!tokens.readLineSegment(line))
break;
if (line[0] == 't") {
if (!PdfEncodings.convertToString(line, null).startsWith("trailer"))
continue;
tokens.seek(pos);
tokens.nextToken();
pos = tokens.getFilePointer();
try {
PdfDictionary dic = (PdfDictionary)readPRObject();
if (dic.get(PdfName.ROOT) != null)
trailer = dic;
else
tokens.seek(pos);
}
catch (Exception e) {
tokens.seek(pos);
}
}
else if (line[0] >= '0" && line[0] < = '9") {
int obj[] = PRTokeniser.checkObjectStart(line);
if (obj == null)
continue;
int num = obj[0];
int gen = obj[1];
if (num >= xr.length) {
int newLength = num * 2;
int xr2[][] = new int[newLength][];
System.arraycopy(xr, 0, xr2, 0, top);
xr = xr2;
}
if (num >= top)
top = num + 1;
if (xr[num] == null || gen >= xr[num][1]) {
obj[0] = pos;
xr[num] = obj;
}
}
}
if (trailer == null)
throw new IOException("trailer not found.");
xref = new int[top * 2];
for (int k = 0; k < top; ++k) {
int obj[] = xr[k];
if (obj != null)
xref[k * 2] = obj[0];
}
}
|
public void releaseLastXrefPartial() {
if (partial && lastXrefPartial != -1) {
xrefObj.set(lastXrefPartial, null);
lastXrefPartial = -1;
}
}
|
public static void releaseLastXrefPartial(PdfObject obj) {
if (obj == null)
return;
if (!obj.isIndirect())
return;
PRIndirectReference ref = (PRIndirectReference)obj;
PdfReader reader = ref.getReader();
if (reader.partial && reader.lastXrefPartial != -1 && reader.lastXrefPartial == ref.getNumber()) {
reader.xrefObj.set(reader.lastXrefPartial, null);
}
reader.lastXrefPartial = -1;
}
|
public void releasePage(int pageNum) {
pageRefs.releasePage(pageNum);
}
|
public void removeAnnotations() {
pageRefs.resetReleasePage();
for (int k = 1; k < = pageRefs.size(); ++k) {
PdfDictionary page = pageRefs.getPageN(k);
if (page.get(PdfName.ANNOTS) == null)
pageRefs.releasePage(k);
else
page.remove(PdfName.ANNOTS);
}
catalog.remove(PdfName.ACROFORM);
pageRefs.resetReleasePage();
}
Removes all the annotations and fields from the document. |
public void removeFields() {
pageRefs.resetReleasePage();
for (int k = 1; k < = pageRefs.size(); ++k) {
PdfDictionary page = pageRefs.getPageN(k);
PdfArray annots = (PdfArray)getPdfObject(page.get(PdfName.ANNOTS));
if (annots == null) {
pageRefs.releasePage(k);
continue;
}
ArrayList arr = annots.getArrayList();
for (int j = 0; j < arr.size(); ++j) {
PdfObject obj = getPdfObjectRelease((PdfObject)arr.get(j));
if (obj == null || !obj.isDictionary())
continue;
PdfDictionary annot = (PdfDictionary)obj;
if (PdfName.WIDGET.equals(annot.get(PdfName.SUBTYPE)))
arr.remove(j--);
}
if (arr.isEmpty())
page.remove(PdfName.ANNOTS);
else
pageRefs.releasePage(k);
}
catalog.remove(PdfName.ACROFORM);
pageRefs.resetReleasePage();
}
Removes all the fields from the document. |
protected void removeUnusedNode(PdfObject obj,
boolean[] hits) {
Stack state = new Stack();
state.push(obj);
while (!state.empty()) {
Object current = state.pop();
if (current == null)
continue;
ArrayList ar = null;
PdfDictionary dic = null;
PdfName[] keys = null;
Object[] objs = null;
int idx = 0;
if (current instanceof PdfObject) {
obj = (PdfObject)current;
switch (obj.type()) {
case PdfObject.DICTIONARY:
case PdfObject.STREAM:
dic = (PdfDictionary)obj;
keys = new PdfName[dic.size()];
dic.getKeys().toArray(keys);
break;
case PdfObject.ARRAY:
ar = ((PdfArray)obj).getArrayList();
break;
case PdfObject.INDIRECT:
PRIndirectReference ref = (PRIndirectReference)obj;
int num = ref.getNumber();
if (!hits[num]) {
hits[num] = true;
state.push(getPdfObjectRelease(ref));
}
continue;
default:
continue;
}
}
else {
objs = (Object[])current;
if (objs[0] instanceof ArrayList) {
ar = (ArrayList)objs[0];
idx = ((Integer)objs[1]).intValue();
}
else {
keys = (PdfName[])objs[0];
dic = (PdfDictionary)objs[1];
idx = ((Integer)objs[2]).intValue();
}
}
if (ar != null) {
for (int k = idx; k < ar.size(); ++k) {
PdfObject v = (PdfObject)ar.get(k);
if (v.isIndirect()) {
int num = ((PRIndirectReference)v).getNumber();
if (num >= xrefObj.size() || (!partial && xrefObj.get(num) == null)) {
ar.set(k, PdfNull.PDFNULL);
continue;
}
}
if (objs == null)
state.push(new Object[]{ar, new Integer(k + 1)});
else {
objs[1] = new Integer(k + 1);
state.push(objs);
}
state.push(v);
break;
}
}
else {
for (int k = idx; k < keys.length; ++k) {
PdfName key = keys[k];
PdfObject v = dic.get(key);
if (v.isIndirect()) {
int num = ((PRIndirectReference)v).getNumber();
if (num >= xrefObj.size() || (!partial && xrefObj.get(num) == null)) {
dic.put(key, PdfNull.PDFNULL);
continue;
}
}
if (objs == null)
state.push(new Object[]{keys, dic, new Integer(k + 1)});
else {
objs[2] = new Integer(k + 1);
state.push(objs);
}
state.push(v);
break;
}
}
}
}
|
public int removeUnusedObjects() {
boolean hits[] = new boolean[xrefObj.size()];
removeUnusedNode(trailer, hits);
int total = 0;
if (partial) {
for (int k = 1; k < hits.length; ++k) {
if (!hits[k]) {
xref[k * 2] = -1;
xref[k * 2 + 1] = 0;
xrefObj.set(k, null);
++total;
}
}
}
else {
for (int k = 1; k < hits.length; ++k) {
if (!hits[k]) {
xrefObj.set(k, null);
++total;
}
}
}
return total;
}
Removes all the unreachable objects. |
public void removeUsageRights() {
PdfDictionary perms = (PdfDictionary)getPdfObject(catalog.get(PdfName.PERMS));
if (perms == null)
return;
perms.remove(PdfName.UR);
perms.remove(PdfName.UR3);
if (perms.size() == 0)
catalog.remove(PdfName.PERMS);
}
Removes any usage rights that this PDF may have. Only Adobe can grant usage rights
and any PDF modification with iText will invalidate them. Invalidated usage rights may
confuse Acrobat and it's advisable to remove them altogether. |
public void resetLastXrefPartial() {
lastXrefPartial = -1;
}
|
public void resetReleasePage() {
pageRefs.resetReleasePage();
}
|
public void selectPages(String ranges) {
selectPages(SequenceList.expand(ranges, getNumberOfPages()));
}
Selects the pages to keep in the document. The pages are described as
ranges. The page ordering can be changed but
no page repetitions are allowed. Note that it may be very slow in partial mode. |
public void selectPages(List pagesToKeep) {
pageRefs.selectPages(pagesToKeep);
removeUnusedObjects();
}
Selects the pages to keep in the document. The pages are described as a
List of Integer. The page ordering can be changed but
no page repetitions are allowed. Note that it may be very slow in partial mode. |
public void setAppendable(boolean appendable) {
this.appendable = appendable;
if (appendable)
getPdfObject(trailer.get(PdfName.ROOT));
}
Setter for property appendable. |
public void setPageContent(int pageNum,
byte[] content) {
setPageContent(pageNum, content, PdfStream.DEFAULT_COMPRESSION);
}
Sets the contents of the page. |
public void setPageContent(int pageNum,
byte[] content,
int compressionLevel) {
PdfDictionary page = getPageN(pageNum);
if (page == null)
return;
PdfObject contents = page.get(PdfName.CONTENTS);
freeXref = -1;
killXref(contents);
if (freeXref == -1) {
xrefObj.add(null);
freeXref = xrefObj.size() - 1;
}
page.put(PdfName.CONTENTS, new PRIndirectReference(this, freeXref));
xrefObj.set(freeXref, new PRStream(this, content, compressionLevel));
}
Sets the contents of the page. |
public void setTampered(boolean tampered) {
this.tampered = tampered;
pageRefs.keepPages();
}
Sets the tampered state. A tampered PdfReader cannot be reused in PdfStamper. |
public void setViewerPreferences(int preferences) {
this.viewerPreferences.setViewerPreferences(preferences);
setViewerPreferences(this.viewerPreferences);
}
Sets the viewer preferences as the sum of several constants. |
void setViewerPreferences(PdfViewerPreferencesImp vp) {
vp.addToCatalog(catalog);
}
|
public int shuffleSubsetNames() {
int total = 0;
for (int k = 1; k < xrefObj.size(); ++k) {
PdfObject obj = getPdfObjectRelease(k);
if (obj == null || !obj.isDictionary())
continue;
PdfDictionary dic = (PdfDictionary)obj;
if (!existsName(dic, PdfName.TYPE, PdfName.FONT))
continue;
if (existsName(dic, PdfName.SUBTYPE, PdfName.TYPE1)
|| existsName(dic, PdfName.SUBTYPE, PdfName.MMTYPE1)
|| existsName(dic, PdfName.SUBTYPE, PdfName.TRUETYPE)) {
String s = getSubsetPrefix(dic);
if (s == null)
continue;
String ns = BaseFont.createSubsetPrefix() + s.substring(7);
PdfName newName = new PdfName(ns);
dic.put(PdfName.BASEFONT, newName);
setXrefPartialObject(k, dic);
++total;
PdfDictionary fd = (PdfDictionary)getPdfObject(dic.get(PdfName.FONTDESCRIPTOR));
if (fd == null)
continue;
fd.put(PdfName.FONTNAME, newName);
}
else if (existsName(dic, PdfName.SUBTYPE, PdfName.TYPE0)) {
String s = getSubsetPrefix(dic);
PdfArray arr = (PdfArray)getPdfObject(dic.get(PdfName.DESCENDANTFONTS));
if (arr == null)
continue;
ArrayList list = arr.getArrayList();
if (list.isEmpty())
continue;
PdfDictionary desc = (PdfDictionary)getPdfObject((PdfObject)list.get(0));
String sde = getSubsetPrefix(desc);
if (sde == null)
continue;
String ns = BaseFont.createSubsetPrefix();
if (s != null)
dic.put(PdfName.BASEFONT, new PdfName(ns + s.substring(7)));
setXrefPartialObject(k, dic);
PdfName newName = new PdfName(ns + sde.substring(7));
desc.put(PdfName.BASEFONT, newName);
++total;
PdfDictionary fd = (PdfDictionary)getPdfObject(desc.get(PdfName.FONTDESCRIPTOR));
if (fd == null)
continue;
fd.put(PdfName.FONTNAME, newName);
}
}
return total;
}
Finds all the font subsets and changes the prefixes to some
random values. |