All Downloads are FREE. Search and download functionalities are using the official Maven repository.

prerna.reactor.export.pdf.PDFUtility Maven / Gradle / Ivy

The newest version!
package prerna.reactor.export.pdf;

import java.awt.Color;
import java.awt.image.RenderedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.io.FileUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.pdfbox.Loader;
import org.apache.pdfbox.cos.COSDictionary;
import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.io.RandomAccessReadBufferedFile;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDDocumentNameDictionary;
import org.apache.pdfbox.pdmodel.PDEmbeddedFilesNameTreeNode;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.PDPageContentStream.AppendMode;
import org.apache.pdfbox.pdmodel.PDResources;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.common.filespecification.PDComplexFileSpecification;
import org.apache.pdfbox.pdmodel.common.filespecification.PDEmbeddedFile;
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.font.PDType1Font;
import org.apache.pdfbox.pdmodel.font.Standard14Fonts;
import org.apache.pdfbox.pdmodel.graphics.PDXObject;
import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationWidget;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceDictionary;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceEntry;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceStream;
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
import org.apache.pdfbox.pdmodel.interactive.form.PDCheckBox;
import org.apache.pdfbox.pdmodel.interactive.form.PDSignatureField;
import org.apache.pdfbox.pdmodel.interactive.form.PDTextField;
import org.apache.pdfbox.text.PDFTextStripper;
import org.apache.pdfbox.text.TextPosition;
import org.jsoup.nodes.Attributes;

import prerna.util.Constants;



/**
 * An example of creating an AcroForm and an empty signature field from scratch.
 * 
 * An actual signature can be added by clicking on it in Adobe Reader.
 * 
 */
public final class PDFUtility {

	private static final Logger classLogger = LogManager.getLogger(PDFUtility.class);

	/**
	 * Create PDDocument
	 * @param filePath
	 * @return
	 * @throws IOException
	 */
	public static PDDocument createDocument(String filePath) throws IOException {
		File file = new File(filePath);
		return Loader.loadPDF(new RandomAccessReadBufferedFile(file));
	}

	public static void addSignatureBlock(PDDocument document) throws IOException {
		// Get the last page index of document
		int pageNum = document.getNumberOfPages();
		PDPage lastPage = document.getPage(pageNum-1);

		// Add a new AcroForm and add that to the document
		PDAcroForm acroForm = new PDAcroForm(document);
		document.getDocumentCatalog().setAcroForm(acroForm);

		// Create empty signature field for each rectangle
		PDSignatureField signatureField = new PDSignatureField(acroForm);
		signatureField.setPartialName("Signature");
		PDAnnotationWidget widget = signatureField.getWidgets().get(0);
		PDRectangle rect = new PDRectangle(375, 20, 200, 40);
		widget.setRectangle(rect);
		widget.setPage(lastPage);
		widget.setPrinted(true);
		lastPage.getAnnotations().add(widget);
		acroForm.getFields().add(signatureField);
	}

	public static void addSignatureBlock(PDDocument document, FormObject rectPage) throws IOException {
		PDAcroForm acroForm = document.getDocumentCatalog().getAcroForm();
		PDRectangle rect = rectPage.rect;

		if (acroForm == null) {
			// Add a new AcroForm and add that to the document
			acroForm = new PDAcroForm(document);
		}
		document.getDocumentCatalog().setAcroForm(acroForm);
		// Create empty signature field for each rectangle
		PDSignatureField signatureField = new PDSignatureField(acroForm);
		// Warning - partial name must be unique to each signature field
		//signatureField.setPartialName("Signature");
		PDAnnotationWidget widget = signatureField.getWidgets().get(0);       
		// Get the sign page index of document
		int page = rectPage.page;
		PDPage signPage = document.getPage(page-1);
		widget.setRectangle(rect);
		widget.setPage(signPage);
		widget.setPrinted(true);
		signPage.getAnnotations().add(widget);
		acroForm.getFields().add(signatureField);
	}



	/**
	 * 
	 * @param document
	 * @throws IOException
	 */
	public static void addSignatureLabel(PDDocument document, String signatureLabel) throws IOException {
		// Get the last page index of document
		int pageNum = document.getNumberOfPages();
		PDPage lastPage = document.getPage(pageNum-1);

		PDPageContentStream contentStream = new PDPageContentStream(document, lastPage, AppendMode.APPEND, true);
		contentStream.beginText();
		contentStream.setFont(new PDType1Font(Standard14Fonts.FontName.TIMES_ROMAN), 12);
		contentStream.setLeading(16f);
		contentStream.newLineAtOffset(375, 65);
		contentStream.showText(signatureLabel);
		contentStream.endText();
		contentStream.close();
	}


	public static void createSignatureBlock(String filePath) throws IOException {
		PDDocument document = createDocument(filePath);
		try {
			addSignatureBlock(document);
			document.save(filePath);
		} finally {
			if(document != null) {
				document.close();
			}
		}
	}

	/**
	 * 
	 * @param filePath
	 * @throws IOException
	 */
	public static void createSignatureLabel(String filePath, String signatureLabel) throws IOException {
		PDDocument document = createDocument(filePath);
		try {
			addSignatureLabel(document, signatureLabel);
			document.save(filePath);
		} finally {
			if(document != null) {
				document.close();
			}
		}
	}


	/**
	 * Identify location of specific string in a document on a specific page
	 */
	static List findSubwords(PDDocument document, int page, List searchTerms) throws IOException
	{
		final List hits = new ArrayList();
		PDFTextStripper stripper = new PDFTextStripper()
		{
			@Override
			protected void writeString(String text, List textPositions) throws IOException
			{
				TextPositionSequence word = new TextPositionSequence(textPositions);
				String string = word.toString();

				int fromIndex = 0;
				int index;

				for ( String searchTerm : searchTerms ) {
					while ((index = string.indexOf(searchTerm, fromIndex)) > -1)
					{
						hits.add(word.subSequence(index, index + searchTerm.length()));
						fromIndex = index + 1;
					}
				}

				super.writeString(text, textPositions);
			}
		};

		stripper.setSortByPosition(true);
		stripper.setStartPage(page);
		stripper.setEndPage(page);
		stripper.getText(document);
		return hits;
	}

	/**
	 * 
	 * Object class returned by findWord
	 */
	public static class RectanglePage {
		public PDRectangle rect;
		public final int page;
		public String keyword;


		public RectanglePage(PDRectangle rect, int page, String keyword) {
			this.rect = rect;
			this.page = page;
			this.keyword = keyword;
		}

		public void setRectangle(PDRectangle newRect) {
			this.rect = newRect;
		}

		public PDRectangle getRectangle() {
			return this.rect;
		}

		public void setKeyword(String newKeyword) {
			this.keyword = newKeyword;
		}

		public String getKeyword() {
			return this.keyword;
		}

	}

	public static class FormObject {
		public PDRectangle rect;
		public final int page;
		public String keyword;
		public String formType;

		public FormObject(PDRectangle rect, int page, String keyword) {
			this.rect = rect;
			this.page = page;
			this.keyword = keyword;
		}		

		public FormObject(PDRectangle rect, int page, String keyword, String formType) {
			this.rect = rect;
			this.page = page;
			this.keyword = keyword;
			this.formType = formType;
		}

		public void setRectangle(PDRectangle newRect) {
			this.rect = newRect;
		}

		public PDRectangle getRectangle() {
			return this.rect;
		}

		public void setKeyword(String newKeyword) {
			this.keyword = newKeyword;
		}

		public String getKeyword() {
			return this.keyword;
		}

	}

	public static class pageLocation {
		public float xCoord;
		public float yCoord;
		public final int page;
		public String keyword;

		public pageLocation(float xCoord, float yCoord, int page, String keyword) {
			this.xCoord = xCoord;
			this.yCoord = yCoord;
			this.page = page;
			this.keyword = keyword;
		}

		public void setKeyword(String newKeyword) {
			this.keyword = newKeyword;
		}

		public String getKeyword() {
			return this.keyword;
		}

	}

	/**
	 * 
	 * Function returns Rectangle and Page to use for placing signature field within PDF
	 * 
	 */
	/**
	public static ArrayList findWordLocation(PDDocument document, List searchTerms) throws IOException
	{	
		float x = 0;
		float y = 0;
		int pageFound = 0;

		ArrayList ret = new ArrayList();
	    //System.out.printf("* Looking for '%s'\n", searchTerm);

		for (int page = 1; page <= document.getNumberOfPages(); page++) {
	        List hits = findSubwords(document, page, searchTerms);
	        for (TextPositionSequence hit : hits) {
		        x = hit.getX();
		        y = hit.textPositions.get(0).getPageHeight() - hit.getY();
		        pageFound = page;
		        PDRectangle rect = new PDRectangle(x, y - 42, 180, 40);
		        RectanglePage addToList = new RectanglePage(rect, pageFound, hit.toString());		        
		        ret.add(addToList);	        
	        }
	    }

	    return ret;
	}
	 */

	/**
	 * 
	 * @param document
	 * @param searchTerms
	 * @return
	 * @throws IOException
	 * 
	 * Returns corresponding page location list object for search term list object
	 * 
	 */
	public static ArrayList findWordLocation(PDDocument document, List searchTerms) throws IOException
	{	
		float x = 0;
		float y = 0;
		int pageFound = 0;

		ArrayList ret = new ArrayList();
		//System.out.printf("* Looking for '%s'\n", searchTerm);

		for (int page = 1; page <= document.getNumberOfPages(); page++) {
			List hits = findSubwords(document, page, searchTerms);
			for (TextPositionSequence hit : hits) {
				x = hit.getX();
				y = hit.textPositions.get(0).getPageHeight() - hit.getY();
				pageFound = page;
				pageLocation addToList = new pageLocation(x, y, pageFound, hit.toString());		        
				ret.add(addToList);	        
			}
		}

		return ret;
	}


	/**
	 * 
	 * Helper class
	 */
	public static class TextPositionSequence implements CharSequence
	{
		public TextPositionSequence(List textPositions)
		{
			this(textPositions, 0, textPositions.size());
		}

		public TextPositionSequence(List textPositions, int start, int end)
		{
			this.textPositions = textPositions;
			this.start = start;
			this.end = end;
		}

		@Override
		public int length()
		{
			return end - start;
		}

		@Override
		public char charAt(int index)
		{
			TextPosition textPosition = textPositionAt(index);
			String text = textPosition.getUnicode();
			return text.charAt(0);
		}

		@Override
		public TextPositionSequence subSequence(int start, int end)
		{
			return new TextPositionSequence(textPositions, this.start + start, this.start + end);
		}

		@Override
		public String toString()
		{
			StringBuilder builder = new StringBuilder(length());
			for (int i = 0; i < length(); i++)
			{
				builder.append(charAt(i));
			}
			return builder.toString();
		}

		public TextPosition textPositionAt(int index)
		{
			return textPositions.get(start + index);
		}

		public float getX()
		{
			return textPositions.get(start).getXDirAdj();
		}

		public float getY()
		{
			return textPositions.get(start).getYDirAdj();
		}

		public float getWidth()
		{
			if (end == start)
				return 0;
			TextPosition first = textPositions.get(start);
			TextPosition last = textPositions.get(end - 1);
			return last.getWidthDirAdj() + last.getXDirAdj() - first.getXDirAdj();
		}

		final List textPositions;
		final int start, end;
	}



	/**
	 * 
	 * @param document
	 * @throws IOException
	 */
	public static void addPageNumbers(PDDocument document, int startingNumber, boolean ignoreFirstPage) throws IOException {
		int numPages = document.getNumberOfPages();
		for(int i = 0; i < numPages; i++) {
			if(i == 0 && ignoreFirstPage) {
				continue;
			}
			PDPage thisPage = document.getPage(i);

			PDPageContentStream contentStream = new PDPageContentStream(document, thisPage, AppendMode.APPEND, true);
			contentStream.beginText();
			contentStream.setFont(new PDType1Font(Standard14Fonts.FontName.TIMES_ROMAN), 8);
			contentStream.setLeading(16f);
			contentStream.newLineAtOffset(thisPage.getMediaBox().getWidth()/2, 10);
			contentStream.showText((startingNumber++) + "");
			contentStream.endText();
			contentStream.close();
		}
	}

	public static String parseStyleAttr(String style, String styleAttr) {
		styleAttr = styleAttr + ":";
		styleAttr = styleAttr.toLowerCase();
		style = style.toLowerCase();
		String attr = "";

		if ( style.lastIndexOf(styleAttr) >= 0 ) {
			attr = style.substring(style.lastIndexOf(styleAttr) + styleAttr.length()).trim();
			attr = attr.substring(0, attr.indexOf(";"));
			attr = attr.replace("px", "");
			attr = attr.replace("em", "");
		}

		return attr;
	}

	/**
	 * Converts to PDF pts (pts = px * inch / px * pt / inch)
	 * 
	 * @param px
	 * @return
	 */
	public static float convertToPts(float px) {
		return 72 * px / 96;
	}

	/**
	 * Sets the form object location based on page location and element attributes
	 * 
	 * @param elementAttributes
	 * @param pageLocationList
	 * @return
	 * @throws IOException
	 */
	public static ArrayList setFormObjectLocation(List elementAttributes, List pageLocationList) throws IOException {
		String heightS;
		String widthS;
		String keyword;
		String formType;
		String xShiftS;
		String yShiftS;
		float heightSize;
		float widthSize;
		float xShift;
		float yShift;
		int index = 0;
		float LLX;
		float LLY;
		int pageNum;
		ArrayList formObjectList = new ArrayList();


		// we are going through this list more than we have page location objects
		for (Attributes elementAttrs : elementAttributes) {

			formType = (String) elementAttrs.get("smss-type");
			if (formType.equals("")) {			
				formType = "textbox";
			}


			try {
				heightS = (String) elementAttrs.get("smss-height");
				heightSize = Float.parseFloat(heightS);
			} catch (Exception e) {
				// Specify conditioned on the object type
				if (formType.equals("signature")) {
					heightSize = 53;
				} else if (formType.equals("checkbox")) {
					heightSize = 12;
				} else if (formType.equals("textbox")) {
					heightSize = 55;
				} else {
					heightSize = 53;
				}

			}


			try {
				widthS = (String) elementAttrs.get("smss-width");
				widthSize = Float.parseFloat(widthS);
			} catch (Exception e) {
				// Specify conditioned on the object type
				if (formType.equals("signature")) {
					widthSize = 227;
				} else if (formType.equals("checkbox")) {
					widthSize = 12;
				} else if (formType.equals("textbox")) {
					widthSize = 627;
				} else {
					widthSize = 227;
				}

			}


			try {
				xShiftS = (String) elementAttrs.get("smss-xshift");
				xShift = Float.parseFloat(xShiftS);
			} catch (Exception e) {
				// Specify conditioned on the object type
				if (formType.equals("signature")) {
					xShift = 0;
				} else if (formType.equals("checkbox")) {
					xShift = 110;
				} else if (formType.equals("textbox")) {
					xShift = 0;
				} else {
					xShift = 0;
				}
			}


			try {
				yShiftS = (String) elementAttrs.get("smss-yshift");
				yShift = Float.parseFloat(yShiftS);
			} catch (Exception e) {
				// Specify conditioned on the object type
				if (formType.equals("signature")) {
					yShift = - heightSize - 5;
				} else if (formType.equals("checkbox")) {
					yShift = 0;
				} else if (formType.equals("textbox")) {
					yShift = - heightSize - 5;
				} else {
					yShift = 0;
				}
			}

			// Convert to PDF pts (pts = px * inch / px * pt / inch)
			//			heightSize = 72 * heightSize / 96;
			//			widthSize = 72 * widthSize / 96;
			//			xShift = 72 * xShift / 96;
			//			yShift = 72 * yShift / 96;

			heightSize = convertToPts(heightSize);
			widthSize = convertToPts(widthSize);
			xShift = convertToPts(xShift);
			yShift = convertToPts(yShift);

			// Need to determine the tag that we will use
			LLX = pageLocationList.get(index).xCoord;
			LLY = pageLocationList.get(index).yCoord;
			pageNum = pageLocationList.get(index).page;

			keyword = (String) elementAttrs.get("smss-value");
			if (keyword.equals("")) {			
				keyword = formType + String.valueOf(index);
			}

			//formObjectList.add(new FormObject(new PDRectangle(LLX, LLY, widthSize, heightSize), pageNum, keyword));

			formObjectList.add(new FormObject(new PDRectangle(LLX + xShift, LLY + yShift, widthSize, heightSize), pageNum, keyword, formType));

			//System.out.println("Attributes in set form: x: " + (LLX + xShift)  + ", y: " + (LLY + yShift)  + ", pageNum: " + pageNum  + ", keyword: " + keyword + ", formType: "  + formType + ", heightSize: " + heightSize + ", widthSize: " + widthSize + ", xshift: " + xShift + ", yshift: " + yShift);

			index++;
		}
		return formObjectList;
	}


	/**
	public static ArrayList setFormObjectLocation(List widthHeightStyle, List pageLocationList) throws IOException {
		String heightS;
		String widthS;
		String keyword;
		String formType;
		String xShiftS;
		String yShiftS;
		float heightSize;
		float widthSize;
		float xShift;
		float yShift;
		int index = 0;
		float LLX;
		float LLY;
		int pageNum;
		ArrayList formObjectList = new ArrayList();

		for (String styleAttr : widthHeightStyle) {

			heightS = parseStyleAttr(styleAttr, "height");
			heightSize = Float.parseFloat(heightS);
			widthS = parseStyleAttr(styleAttr, "width");
			widthSize = Float.parseFloat(widthS);
			xShiftS = parseStyleAttr(styleAttr, "xshift");
			yShiftS = parseStyleAttr(styleAttr, "yshift");

			if (!xShiftS.equals("")) {
				xShift = Float.parseFloat(xShiftS);
			} else {
				xShift = 0;
			}
			if (!yShiftS.equals("")) {
				yShift = Float.parseFloat(yShiftS);
			} else {
				yShift = 0;
			}

			// Convert to PDF pts (pts = px * inch / px * pt / inch)
			heightSize = 72 * heightSize / 96;
			widthSize = 72 * widthSize / 96;
			xShift = 72 * xShift / 96;
			yShift = 72 * yShift / 96;

			// Need to determine the tag that we will use
			formType = parseStyleAttr(styleAttr, "objecttype");
			LLX = pageLocationList.get(index).xCoord;
			LLY = pageLocationList.get(index).yCoord;
			pageNum = pageLocationList.get(index).page;
			keyword = parseStyleAttr(styleAttr, "defaultValue");

			if (keyword.equals("")) {			
				keyword = formType + String.valueOf(index);
			}

			//formObjectList.add(new FormObject(new PDRectangle(LLX, LLY, widthSize, heightSize), pageNum, keyword));

			formObjectList.add(new FormObject(new PDRectangle(LLX + xShift, LLY + yShift, widthSize, heightSize), pageNum, keyword, formType));

			index++;
		}
		return formObjectList;
	}
	 */


	/**
	 * 
	 * Parse height and width from style attribute and adjust size of corresponding rectangle
	 * 
	 * TODO: If we find more elements than signature blocks or vice versa, throw warning
	 * TODO: Generalize to adjust the size of any rectangle field we put in the PDF
	 * 	- pass xShift, yShift in style attr
	 * 	- parse from style attr
	 *  - apply xShift, yShift
	 */
	public static void adjustBlockSizes(List widthHeightStyle, List rectPageList) throws IOException {
		String heightS;
		String widthS;
		float heightSize;
		float widthSize;
		int index = 0;
		float LLX;
		float LLY;
		for (String styleAttr : widthHeightStyle) {

			heightS = styleAttr.substring(styleAttr.lastIndexOf("height:") + 7).trim();
			heightS = heightS.substring(0, heightS.indexOf(";"));
			heightS = heightS.replace("px", "");

			heightSize = Float.parseFloat(heightS);

			widthS = styleAttr.substring(styleAttr.lastIndexOf("width:") + 6).trim();
			widthS = widthS.substring(0, widthS.indexOf(";"));
			widthS = widthS.replace("px", "");

			widthSize = Float.parseFloat(widthS);						

			// Convert to PDF pts (pts = px * inch / px * pt / inch)

			heightSize = 72 * heightSize / 96;
			widthSize = 72 * widthSize / 96;

			LLX = rectPageList.get(index).rect.getLowerLeftX();
			LLY = rectPageList.get(index).rect.getLowerLeftY();

			// Reset the rectangle based on new dimensions

			// Need a way to ensure that the element actually matches the signature label - maybe we use ids?
			rectPageList.get(index).setRectangle(new PDRectangle(LLX, LLY, widthSize, heightSize));

			index++;
		}
	}

	/**
	 * 
	 * @param rectPageList
	 * @throws IOException
	 * 
	 * TODO: Consider adding a "shift" argument, or getting this from the style attr
	 * 	- right - apply a shift to put checkbox to right of search term
	 * 	- left - apply a shift to put checkbox to left of search term
	 *  - above - apply shift to put above
	 *  - below - apply shift to put above
	 *  Could also consider passing the x, y shift as px values in the style attr
	 */
	public static void adjustChecboxSizes(List rectPageList) throws IOException {

		int index = 0;
		float LLX;
		float LLY;

		for (RectanglePage rp : rectPageList ) {	
			LLX = rectPageList.get(index).rect.getLowerLeftX();
			LLY = rectPageList.get(index).rect.getLowerLeftY();

			rectPageList.get(index).setRectangle(new PDRectangle(LLX + 80, LLY + 40, 9, 9));

			String newKeyword = rectPageList.get(index).getKeyword() + String.valueOf(index);
			rectPageList.get(index).setKeyword(newKeyword);

			index++;
		}
	}



	public static void adjustTextboxSizes(List rectPageList) throws IOException {

		int index = 0;
		float LLX;
		float LLY;

		for (RectanglePage rp : rectPageList ) {	
			LLX = rectPageList.get(index).rect.getLowerLeftX();
			LLY = rectPageList.get(index).rect.getLowerLeftY();

			rectPageList.get(index).setRectangle(new PDRectangle(LLX, LLY - 5, 470, 40));

			String newKeyword = "Name, Title; Organization";
			rectPageList.get(index).setKeyword(newKeyword);

			index++;
		}

	}



	/**
	 * 
	 * Add files in a directory as attachments to an existing PDF
	 * @throws IOException 
	 * 
	 */
	public static void attachFiles(PDDocument document, File filedir) throws IOException  {
		PDEmbeddedFilesNameTreeNode efTree = new PDEmbeddedFilesNameTreeNode();
		Collection files = FileUtils.listFiles(filedir, null, true);
		InputStream is;
		PDComplexFileSpecification fs;
		PDEmbeddedFile ef;
		Map efMap = new HashMap();
		List filesToEmbed = new ArrayList<>();

		for (File file2 : files) {
			fs = new PDComplexFileSpecification();
			fs.setFile(file2.getName());
			try {
				is = new FileInputStream(file2.getAbsolutePath());
			} catch (FileNotFoundException e) {
				classLogger.error("Error finding file with path: {}", file2.getAbsolutePath());
				classLogger.error(Constants.STACKTRACE, e);
				throw new FileNotFoundException("Could not find file. See logs for more details.");
			}
			ef = new PDEmbeddedFile(document, is);
			filesToEmbed.add(ef);

			// set some of the attributes of the embedded file
			ef.setSubtype("test/plain");
			ef.setCreationDate(new GregorianCalendar());
			fs.setEmbeddedFile(ef);

			efMap.put(file2.getName(), fs);
		}

		efTree.setNames( efMap );
		PDDocumentNameDictionary names = new PDDocumentNameDictionary( document.getDocumentCatalog() );
		names.setEmbeddedFiles( efTree );
		document.getDocumentCatalog().setNames( names );
	}

	/**
	 * 
	 * @param document
	 * @param rectPage
	 * @throws IOException
	 */
	public static void addTextField(PDDocument document, FormObject rectPage) throws IOException {
		int pageNum = rectPage.page;
		PDPage page = document.getPage(pageNum-1);
		PDRectangle rect = rectPage.rect;
		PDAcroForm acroForm = document.getDocumentCatalog().getAcroForm();
		if (acroForm == null) {
			// Add a new AcroForm and add that to the document
			acroForm = new PDAcroForm(document);
		}
		document.getDocumentCatalog().setAcroForm(acroForm);

		PDAppearanceStream pdAppearanceStream = new PDAppearanceStream(document);

		COSDictionary normalAppearances = new COSDictionary();
		PDAppearanceDictionary pdAppearanceDictionary = new PDAppearanceDictionary();
		pdAppearanceDictionary.setNormalAppearance(new PDAppearanceEntry(normalAppearances));
		pdAppearanceDictionary.setDownAppearance(new PDAppearanceEntry(normalAppearances));

		pdAppearanceStream.setBBox(rect);
		normalAppearances.setItem("Yes", pdAppearanceStream);

		PDPageContentStream contentStream = new PDPageContentStream(document, page, AppendMode.APPEND, false);
		contentStream.addRect(rect.getLowerLeftX(), rect.getLowerLeftY(), rect.getWidth(), rect.getHeight());
		contentStream.setLineWidth(1);
		contentStream.setNonStrokingColor(Color.WHITE);
		contentStream.setStrokingColor(Color.BLACK);
		contentStream.stroke();
		contentStream.close();

		PDTextField textBox = new PDTextField(acroForm);
		acroForm.getFields().add(textBox);
		textBox.setPartialName(rectPage.keyword);
		textBox.setFieldFlags(4);
		textBox.setMultiline(true);

		PDFont font = new PDType1Font(Standard14Fonts.FontName.HELVETICA);
		PDResources resources = new PDResources();
		resources.put(COSName.getPDFName("Helv"), font);
		acroForm.setDefaultResources(resources);

		String defaultAppearance = "/Helv 12 Tf 0 0 0 rg";
		textBox.setDefaultAppearance(defaultAppearance);

		List widgets = textBox.getWidgets();
		for (PDAnnotationWidget pdAnnotationWidget : widgets)
		{
			pdAnnotationWidget.setRectangle(rect);
			pdAnnotationWidget.setPage(page);
			page.getAnnotations().add(pdAnnotationWidget);

			pdAnnotationWidget.setAppearance(pdAppearanceDictionary);
		}
		textBox.setValue(rectPage.getKeyword());
	}

	/**
	 * 
	 * @param document
	 * @param rectPage
	 * @throws IOException
	 */
	public static void addCheckbox(PDDocument document, FormObject rectPage) throws IOException {
		int pageNum = rectPage.page;
		PDPage page = document.getPage(pageNum-1);
		PDRectangle rect = rectPage.rect;
		PDAcroForm acroForm = document.getDocumentCatalog().getAcroForm();
		if (acroForm == null) {
			// Add a new AcroForm and add that to the document
			acroForm = new PDAcroForm(document);
		}
		document.getDocumentCatalog().setAcroForm(acroForm);

		COSDictionary normalAppearances = new COSDictionary();
		PDAppearanceDictionary pdAppearanceDictionary = new PDAppearanceDictionary();
		pdAppearanceDictionary.setNormalAppearance(new PDAppearanceEntry(normalAppearances));
		pdAppearanceDictionary.setDownAppearance(new PDAppearanceEntry(normalAppearances));

		PDAppearanceStream pdAppearanceStream = new PDAppearanceStream(document);
		pdAppearanceStream.setResources(new PDResources());
		try (PDPageContentStream pdPageContentStream = new PDPageContentStream(document, pdAppearanceStream))
		{
			float fontSize = Float.min(rect.getWidth(), rect.getHeight()) - 2;
			pdPageContentStream.setFont(new PDType1Font(Standard14Fonts.FontName.ZAPF_DINGBATS), fontSize);
			pdPageContentStream.beginText();
			pdPageContentStream.newLineAtOffset(3, 4);
			pdPageContentStream.showText("\u2714");
			pdPageContentStream.endText();
		}
		pdAppearanceStream.setBBox(new PDRectangle(rect.getWidth(), rect.getHeight()));
		normalAppearances.setItem("Yes", pdAppearanceStream);

		pdAppearanceStream = new PDAppearanceStream(document);
		pdAppearanceStream.setResources(new PDResources());
		try (PDPageContentStream pdPageContentStream = new PDPageContentStream(document, pdAppearanceStream))
		{
			pdPageContentStream.setFont(new PDType1Font(Standard14Fonts.FontName.ZAPF_DINGBATS), 14.5f);
			pdPageContentStream.beginText();
			pdPageContentStream.newLineAtOffset(3, 4);
			pdPageContentStream.showText(" ");
			pdPageContentStream.endText();
		}
		pdAppearanceStream.setBBox(new PDRectangle(rect.getWidth(), rect.getHeight()));
		normalAppearances.setItem("Off", pdAppearanceStream);

		PDPageContentStream contentStream = new PDPageContentStream(document, page, AppendMode.APPEND, false);
		contentStream.addRect(rect.getLowerLeftX(), rect.getLowerLeftY(), rect.getWidth(), rect.getHeight());
		contentStream.setLineWidth(1);
		contentStream.setNonStrokingColor(Color.WHITE);
		contentStream.setStrokingColor(Color.BLACK);
		contentStream.stroke();
		contentStream.close();

		PDCheckBox checkBox = new PDCheckBox(acroForm);
		acroForm.getFields().add(checkBox);
		checkBox.setPartialName(rectPage.keyword);
		checkBox.setFieldFlags(4);

		List widgets = checkBox.getWidgets();
		for (PDAnnotationWidget pdAnnotationWidget : widgets)
		{
			pdAnnotationWidget.setRectangle(rect);
			pdAnnotationWidget.setPage(page);
			page.getAnnotations().add(pdAnnotationWidget);

			pdAnnotationWidget.setAppearance(pdAppearanceDictionary);
		}
		checkBox.unCheck();
	}



	public static void addPDFObjects(PDDocument document, ArrayList formObjectList) throws IOException {
		for (FormObject fo : formObjectList ) {
			if (fo.formType.equals("signature")) {
				//System.out.println("Trying to add signature");
				addSignatureBlock(document, fo);
			} else if (fo.formType.equals("checkbox")) {
				//System.out.println("Trying to add check");
				addCheckbox(document, fo);
			} else if (fo.formType.equals("textbox")) {
				//System.out.println("Trying to add textbox");
				addTextField(document, fo);
			}
		}
	}

	public static boolean pdfContainsImages(String filePath) throws IOException {
		boolean status = false;
		try (PDDocument document = Loader.loadPDF(new RandomAccessReadBufferedFile(new File(filePath)))) {
			int count = getPDFImagesCount(document);
			if (count > 0) {
				status = true;
			}
		} catch (IOException e) {
			classLogger.error(Constants.STACKTRACE, e);
		}
		return status;
	}

	public static int getPDFImagesCount(PDDocument document) throws IOException {
		return getImagesFromPDF(document).size();
	}

	/*
	 * get the list of PDF images
	 */
	public static List getImagesFromPDF(PDDocument document) throws IOException {
		List images = new ArrayList<>();
		for (PDPage page : document.getPages()) {
			images.addAll(getImagesFromResources(page.getResources()));
		}

		return images;
	}

	private static List getImagesFromResources(PDResources resources) throws IOException {
		List images = new ArrayList<>();

		for (COSName xObjectName : resources.getXObjectNames()) {
			PDXObject xObject = resources.getXObject(xObjectName);

			if (xObject instanceof PDFormXObject) {
				images.addAll(getImagesFromResources(((PDFormXObject) xObject).getResources()));
			} else if (xObject instanceof PDImageXObject) {
				images.add(((PDImageXObject) xObject).getImage());
			}
		}

		return images;
	}


}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy