/*
* Copyright (c) 1997-2025 IDRsolutions (https://www.idrsolutions.com)
*/
package org.jpedal.examples;
import org.jpedal.PdfDecoderServer;
import org.jpedal.exception.PdfException;
import org.jpedal.external.ExternalHandlers;
import org.jpedal.fonts.FontMappings;
import org.jpedal.objects.PdfFileInformation;
import org.jpedal.objects.PdfPageData;
import org.jpedal.objects.PdfResources;
import org.jpedal.objects.raw.PdfDictionary;
import org.jpedal.objects.raw.PdfObject;
import org.jpedal.objects.structuredtext.MarkedContentGenerator;
import org.jpedal.parser.image.ImageCommands;
import org.jpedal.render.DynamicVectorRenderer;
import java.util.HashMap;
import java.util.Map;
/**
* <h2>PdfUtilities</h2>
* <p>
* This class provides a simple Java API to access general PDF features in JPEDAL via a simple API
*/
public class PdfUtilities extends BaseExample {
/**
* <pre><code>
* PdfUtilities pdfUtils=new PdfUtilities("C:/pdfs/mypdf.pdf");
* // pdfUtils.setPassword("password");
* if (pdfUtils.openPDFFile()) {
* int commandsOnPage=pdfUtils.getCommandCountForPageStream();
* }
* pdfUtils.closePDFfile();
* </code></pre>
*
* @param page pdf logical page
*
* @return The count of Postscript commands from the page
*/
public int getCommandCountForPageStream(final int page) {
decode_pdf.setExtractionMode(0);
decode_pdf.decodePage(page);
return decode_pdf.getDynamicRenderer().getValue(DynamicVectorRenderer.TOKEN_NUMBER);
}
public enum PageUnits {
Pixels,
Inches,
Centimetres
}
public enum PageSizeType {
MediaBox,
CropBox
}
private PdfFileInformation currentFileInformation;
private boolean hasEmbeddedFonts;
private boolean testIfFontsEmbedded;
private PdfPageData currentPageData;
public PdfUtilities(final String fileName) {
this.fileName = fileName;
init();
}
public PdfUtilities(final byte[] byteArray) {
this.byteArray = byteArray;
init();
}
/**
* @param password the USER or OWNER password for the PDF file
*/
public void setPassword(final String password) {
this.password = password;
}
private void init() {
FontMappings.setFontReplacements();
decode_pdf = new PdfDecoderServer(false); //false as no GUI display needed
}
@Override
public boolean openPDFFile() throws PdfException {
if (super.openPDFFile()) {
/*get the Pdf file information object to extract info from*/
currentFileInformation = decode_pdf.getFileInformationData();
currentPageData = decode_pdf.getPdfPageData();
return true;
}
return false;
}
/**
* number of pages in PDF file (starting at 1)
*
* @return page count
*/
public int getPageCount() {
checkFileOpened();
return decode_pdf.getPageCount();
}
/**
* get the PDF version number
*
* @return PDF version
*/
public String getPDFVersion() {
checkFileOpened();
return decode_pdf.getPDFVersion();
}
/**
* get image data on pages in PDF file (starting at 1) (Method IS NOT THREADSAFE)
*
* <pre><code>
* PdfUtilities pdfUtils=new PdfUtilities("C:/pdfs/mypdf.pdf");
* // pdfUtils.setPassword("password");
* if (pdfUtils.openPDFFile()) {
* String pageImages=pdfUtils.getXImageDataForPage(int page);
* }
* pdfUtils.closePDFfile();
* </code></pre>
*
* @param page logical page in pdf file
*
* @return The image data on the page
*/
public String getXImageDataForPage(final int page) {
ImageCommands.trackImages = true;
checkFileOpened(); // creates instance of decode_pdf
decode_pdf.decodePage(page);
ImageCommands.trackImages = false;
return decode_pdf.getInfo(PdfDictionary.Image);
}
/**
* get XObject data on pages in PDF file (starting at 1)
*
* <pre><code>
* PdfUtilities pdfUtils = new PdfUtilities("C:/pdfs/mypdf.pdf");
* // pdfUtils.setPassword("password");
* if (pdfUtils.openPDFFile()) {
* String pageXObjects = pdfUtils.getXObjectsForPage(int page);
* }
*
* pdfUtils.closePDFfile();
* </code></pre>
*
* @param page logical page in pdf file
*
* @return The XObject data on the page
*/
public String getXObjectsForPage(final int page) {
checkFileOpened(); // creates instance of decode_pdf
return decode_pdf.getIO().getXObjectsForPage(page);
}
/**
* return a String detailing the fonts from page
*
* <pre><code>
* PdfUtilities pdfUtils=new PdfUtilities("C:/pdfs/mypdf.pdf");
* // pdfUtils.setPassword("password");
* if (pdfUtils.openPDFFile()) {
* String fontDetailsOnPage = pdfUtils.getFontDataForPage(int oage);
* }
*
* pdfUtils.closePDFfile();
* </code></pre>
*
* @param page pdf logical page
*
* @return the fonts on the page
*/
public String getFontDataForPage(final int page) {
checkFileOpened(); // creates instance of decode_pdf
decode_pdf.decodePage(page);
return decode_pdf.getInfo(PdfDictionary.Font);
}
public Map<Integer, String> getAllFontDataForDocument() {
ImageCommands.trackImages = true;
final Map<Integer, String> font_data = new HashMap<>();
checkFileOpened(); // creates instance of decode_pdf
for (int page = 1; page <= getPageCount(); page++) {
decode_pdf.decodePage(page);
font_data.put(page, decode_pdf.getInfo(PdfDictionary.Font));
}
return font_data;
}
/**
* ensure PDF file is closed once no longer needed and all resources released
*/
@Override
public void closePDFfile() {
checkFileOpened();
super.closePDFfile();
//reset in case instance reused
hasEmbeddedFonts = false;
testIfFontsEmbedded = false;
}
/**
* return boolean to show if Pdf file contains embedded fonts
*
* <pre><code>
* PdfUtilities pdfUtils=new PdfUtilities("C:/pdfs/mypdf.pdf");
* // pdfUtils.setPassword("password");
* if (pdfUtils.openPDFFile()) {
* boolean usesEmbeddedFonts=pdfUtils.hasEmbeddedFonts();
* }
* pdfUtils.closePDFfile();
* </code></pre>
*
* @return {@code true} if present in pdf file
*/
public boolean hasEmbeddedFonts() {
checkFileOpened();
if (!testIfFontsEmbedded) {
testIfFontsEmbedded = true;
final int pageCount = getPageCount();
for (int page = 1; page < pageCount + 1; page++) {
decode_pdf.decodePage(page);
hasEmbeddedFonts = decode_pdf.hasEmbeddedFonts();
// exit on first true
if (hasEmbeddedFonts) {
page = pageCount;
}
}
}
return hasEmbeddedFonts;
}
/**
* return a Map containing the pair value properties (if present) from the open PDF file -
*
* <pre><code>
* PdfUtilities pdfUtils = new PdfUtilities("C:/pdfs/mypdf.pdf");
* // pdfUtils.setPassword("password");
* if (pdfUtils.openPDFFile()) {
* Map mapOfValuePairs = pdfUtils.getDocumentPropertyStringValuesAsMap();
* }
*
* pdfUtils.closePDFfile();
* </code></pre>
*
* @return A map of document properties from the PDF file
*/
public Map<String, String> getDocumentPropertyStringValuesAsMap() {
checkFileOpened();
final String[] names = PdfFileInformation.getFieldNames();
final int count = names.length;
final String[] keys = currentFileInformation.getFieldValues();
final Map<String, String> map = new HashMap<>();
for (int i = 0; i < count; i++) {
map.put(names[i], keys[i]);
}
return map;
}
/**
* access the XML Document properties String (if present) from the open PDF file
*
* <pre><code>
* PdfUtilities pdfUtils = new PdfUtilities("C:/pdfs/mypdf.pdf");
* // pdfUtils.setPassword("password");
* if (pdfUtils.openPDFFile()) {
* String XMLStringData = pdfUtils.getDocumentPropertyFieldsInXML();
* }
*
* pdfUtils.closePDFfile();
* </code></pre>
*
* @return String containing the raw text data
*/
public String getDocumentPropertyFieldsInXML() {
checkFileOpened();
return currentFileInformation.getFileXMLMetaData();
}
/**
* <pre><code>
* PdfUtilities pdfUtils = new PdfUtilities("C:/pdfs/mypdf.pdf");
* // pdfUtils.setPassword("password");
* if (pdfUtils.openPDFFile()) {
* float[] pageDimensions = pdfUtils.getPageDimensions(pageNum, PageUnits.Inches, PageSizeType.CropBox);
* }
*
* pdfUtils.closePDFfile();
* </code></pre>
*
* @param page is pageNumber
* @param units units to use for pageSize dimensions (pixels, Inches, Centimetres) except rotation which is always
* in degrees
* @param type which values to select (MediaBox, CropBox)
*
* @return a float[] with 5 values:- x,y,w,h, pageRotation
*/
public float[] getPageDimensions(final int page, final PageUnits units, final PageSizeType type) {
checkFileOpened();
final float[] pageSize = new float[5];
final float factor = switch (units) {
case Pixels -> 1f;
case Inches -> 72f;
case Centimetres -> 72f / 2.54f;
};
switch (type) {
case MediaBox:
pageSize[0] = currentPageData.getMediaBoxX(page) / factor;
pageSize[1] = currentPageData.getMediaBoxY(page) / factor;
pageSize[2] = currentPageData.getMediaBoxWidth(page) / factor;
pageSize[3] = currentPageData.getMediaBoxHeight(page) / factor;
break;
case CropBox:
pageSize[0] = currentPageData.getCropBoxX(page) / factor;
pageSize[1] = currentPageData.getCropBoxY(page) / factor;
pageSize[2] = currentPageData.getCropBoxWidth(page) / factor;
pageSize[3] = currentPageData.getCropBoxHeight(page) / factor;
break;
}
pageSize[4] = currentPageData.getRotation(page);
return pageSize;
}
private void checkFileOpened() {
if (!isOpen) {
throw new RuntimeException("PDF file needs to be opened with openPDFFile() method first");
}
}
/**
* <pre><code>
* PdfUtilities pdfUtils = new PdfUtilities("C:/pdfs/mypdf.pdf");
* // pdfUtils.setPassword("password");
* if (pdfUtils.isPDFLinearized()) {
* // file is Linearized and has FastWeb view
* }
*
* pdfUtils.closePDFfile();
* </code></pre>
*
* @return a boolean to show if file is Linearized
*/
public boolean isPDFLinearized() {
return (decode_pdf != null && decode_pdf.getJPedalObject(PdfDictionary.Linearized) != null);
}
/**
* <pre><code>
* PdfUtilities pdfUtils = new PdfUtilities("C:/pdfs/mypdf.pdf");
* // pdfUtils.setPassword("password");
* if (pdfUtils.openPDFFile()) {
* int P = pdfUtils.getPdfFilePermissions();
* }
*
* pdfUtils.closePDFfile();
* </code></pre>
*
* @return an unsigned 32-bit integer containing a set of permission flags
*/
public int getPdfFilePermissions() {
int P = -1;
if (decode_pdf != null) {
final PdfObject encryptObj = decode_pdf.getIO().getPDFObject(PdfDictionary.Encrypt);
if (encryptObj != null) {
P = encryptObj.getInt(PdfDictionary.P);
}
}
return P;
}
/**
* <pre><code>
* PdfUtilities pdfUtils = new PdfUtilities("C:/pdfs/mypdf.pdf");
* // pdfUtils.setPassword("password");
* if (pdfUtils.openPDFFile()) {
* boolean isMarked = pdfUtils.isMarkedContent();
* }
*
* pdfUtils.closePDFfile();
* </code></pre>
*
* @return {@code true} if fully meets MarkedContent specification - may still be able to extract something if
* false
*/
public boolean isMarkedContent() {
boolean isMarked = false;
if (decode_pdf != null) {
isMarked = new MarkedContentGenerator((PdfResources) decode_pdf.getJPedalObject(PdfDictionary.Resources), new ExternalHandlers(), decode_pdf.getDecoderOptions()).isMarkedContent();
}
return isMarked;
}
/**
* <pre><code>
* PdfUtilities pdfUtils = new PdfUtilities("C:/pdfs/mypdf.pdf");
* // pdfUtils.setPassword("password");
* if (pdfUtils.openPDFFile()) {
* int P = pdfUtils.getPdfFilePermissions();
* PdfUtilities.showPermissionsAsString(P);
* }
*
* pdfUtils.closePDFfile();
* </code></pre>
*
* @param P a 32-bit integer containing permission flags extracted from PDF
*/
public static void showPermissionsAsString(final int P) {
//power of 2 lookup table
final int[] lookup = new int[32];
int power = 1;
for (int ptr = 0; ptr < 32; ptr++) {
lookup[ptr] = power;
power *= 2;
}
System.out.println("PDF Security settings in Encryption Object");
System.out.println("------------------------------------------");
System.out.println("raw P value = " + Integer.toBinaryString(P));
final Object[] flags = {3, "Printing", 4, "Modify", 5, "Copy/extract", 6, "Add/modify Annotation",
9, "Fill in existing forms", 10, "Extraction for accessibility", 11, "Document Assembly", 12, "Printing High-quality"};
final int count = flags.length;
for (int ptr = 0; ptr < count; ptr += 2) {
final int bitToTest = (Integer) flags[ptr];
final String value = (String) flags[ptr + 1];
if ((P & lookup[bitToTest]) == lookup[bitToTest]) {
System.out.println(value + " (bit " + bitToTest + ") is allowed");
} else {
System.out.println(value + " (bit " + bitToTest + ") is NOT allowed");
}
}
}
@Override
protected void decodeFile(final String rootDir) throws PdfException {
//Thie example does not require the file to be decoded
}
}
|