aboutsummaryrefslogtreecommitdiff
path: root/pdf-as-pdfbox/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/pdfbox/PDFAsVisualSignatureBuilder.java
diff options
context:
space:
mode:
Diffstat (limited to 'pdf-as-pdfbox/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/pdfbox/PDFAsVisualSignatureBuilder.java')
-rw-r--r--pdf-as-pdfbox/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/pdfbox/PDFAsVisualSignatureBuilder.java994
1 files changed, 994 insertions, 0 deletions
diff --git a/pdf-as-pdfbox/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/pdfbox/PDFAsVisualSignatureBuilder.java b/pdf-as-pdfbox/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/pdfbox/PDFAsVisualSignatureBuilder.java
new file mode 100644
index 00000000..e3ee19f6
--- /dev/null
+++ b/pdf-as-pdfbox/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/pdfbox/PDFAsVisualSignatureBuilder.java
@@ -0,0 +1,994 @@
+/*******************************************************************************
+ * <copyright> Copyright 2014 by E-Government Innovation Center EGIZ, Graz, Austria </copyright>
+ * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a
+ * joint initiative of the Federal Chancellery Austria and Graz University of
+ * Technology.
+ *
+ * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by
+ * the European Commission - subsequent versions of the EUPL (the "Licence");
+ * You may not use this work except in compliance with the Licence.
+ * You may obtain a copy of the Licence at:
+ * http://www.osor.eu/eupl/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the Licence is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing permissions and
+ * limitations under the Licence.
+ *
+ * This product combines work with different licenses. See the "NOTICE" text
+ * file for details on the various modules and licenses.
+ * The "NOTICE" text file is part of the distribution. Any derivative works
+ * that you distribute must include a readable copy of the "NOTICE" text file.
+ ******************************************************************************/
+package at.gv.egiz.pdfas.lib.impl.stamping.pdfbox;
+
+import java.awt.Color;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Point2D;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import javax.imageio.ImageIO;
+
+import org.apache.pdfbox.cos.COSArray;
+import org.apache.pdfbox.cos.COSDictionary;
+import org.apache.pdfbox.cos.COSName;
+import org.apache.pdfbox.pdmodel.PDDocument;
+import org.apache.pdfbox.pdmodel.PDPage;
+import org.apache.pdfbox.pdmodel.PDResources;
+import org.apache.pdfbox.pdmodel.common.PDRectangle;
+import org.apache.pdfbox.pdmodel.common.PDStream;
+import org.apache.pdfbox.pdmodel.edit.PDPageContentStream;
+import org.apache.pdfbox.pdmodel.font.PDFont;
+import org.apache.pdfbox.pdmodel.font.PDType1Font;
+import org.apache.pdfbox.pdmodel.graphics.xobject.PDJpeg;
+import org.apache.pdfbox.pdmodel.graphics.xobject.PDPixelMap;
+import org.apache.pdfbox.pdmodel.graphics.xobject.PDXObjectForm;
+import org.apache.pdfbox.pdmodel.graphics.xobject.PDXObjectImage;
+import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceDictionary;
+import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceStream;
+import org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature;
+import org.apache.pdfbox.pdmodel.interactive.digitalsignature.visible.PDVisibleSigBuilder;
+import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
+import org.apache.pdfbox.pdmodel.interactive.form.PDField;
+import org.apache.pdfbox.pdmodel.interactive.form.PDSignatureField;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import at.gv.egiz.pdfas.common.exceptions.PdfAsException;
+import at.gv.egiz.pdfas.common.settings.ISettings;
+import at.gv.egiz.pdfas.common.utils.ImageUtils;
+import at.knowcenter.wag.egov.egiz.table.Entry;
+import at.knowcenter.wag.egov.egiz.table.Style;
+
+public class PDFAsVisualSignatureBuilder extends PDVisibleSigBuilder {
+
+ private static final Logger logger = LoggerFactory
+ .getLogger(PDFAsVisualSignatureBuilder.class);
+
+ private void drawDebugLine(PDPageContentStream contentStream, float x,
+ float y, float width, float height) {
+ try {
+ contentStream.setStrokingColor(Color.RED);
+ contentStream.drawLine(x, y, x + width, y);
+ contentStream.setStrokingColor(Color.BLUE);
+ contentStream.drawLine(x, y, x, y - height);
+ contentStream.setStrokingColor(Color.GREEN);
+ contentStream.drawLine(x + width, y, x + width, y - height);
+ contentStream.setStrokingColor(Color.ORANGE);
+ contentStream.drawLine(x, y - height, x + width, y - height);
+
+ contentStream.setStrokingColor(Color.BLACK);
+ } catch (Throwable e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void drawDebugPadding(PDPageContentStream contentStream, float x,
+ float y, float padding, float width, float height) {
+ try {
+ contentStream.setStrokingColor(Color.RED);
+ contentStream.drawLine(x, y, x + padding, y - padding);
+ contentStream.drawLine(x + width, y, x + width - padding, y
+ - padding);
+ contentStream.drawLine(x + width, y - height, x + width - padding,
+ y - height + padding);
+ contentStream.drawLine(x, y - height, x + padding, y - height
+ + padding);
+ contentStream.setStrokingColor(Color.BLACK);
+ } catch (Throwable e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void drawTable(PDPage page, PDPageContentStream contentStream,
+ float x, float y, float width, float height,
+ PDFBoxTable abstractTable, PDDocument doc, boolean subtable)
+ throws IOException, PdfAsException {
+
+ final int rows = abstractTable.getRowCount();
+ final int cols = abstractTable.getColCount();
+ float[] colsSizes = abstractTable.getColsRelativeWith();
+ int max_cols = abstractTable.getColCount();
+ float padding = abstractTable.getPadding();
+ float fontSize = PDFBoxFont.defaultFontSize;
+ PDFont textFont = PDFBoxFont.defaultFont;
+ if (colsSizes == null) {
+ colsSizes = new float[max_cols];
+ // set the column ratio for all columns to 1
+ for (int cols_idx = 0; cols_idx < colsSizes.length; cols_idx++) {
+ colsSizes[cols_idx] = 1;
+ }
+ }
+
+ logger.debug("Drawing Table:");
+ abstractTable.dumpTable();
+
+ if (abstractTable.getBGColor() != null) {
+ contentStream.setNonStrokingColor(abstractTable.getBGColor());
+ contentStream.fillRect(x, y, abstractTable.getWidth(),
+ abstractTable.getHeight());
+ contentStream.setNonStrokingColor(Color.BLACK);
+ }
+ float total = 0;
+
+ for (int cols_idx = 0; cols_idx < colsSizes.length; cols_idx++) {
+ total += colsSizes[cols_idx];
+ }
+
+ for (int cols_idx = 0; cols_idx < colsSizes.length; cols_idx++) {
+ colsSizes[cols_idx] = (colsSizes[cols_idx] / total)
+ * abstractTable.getWidth();
+ }
+
+ for (int cols_idx = 0; cols_idx < colsSizes.length; cols_idx++) {
+ logger.debug("Col: " + cols_idx + " : " + colsSizes[cols_idx]);
+ }
+
+ float border = abstractTable.style.getBorder();
+ contentStream.setLineWidth(border);
+
+ float tableHeight = abstractTable.getHeight();
+ float tableWidth = abstractTable.getWidth();
+ final float colWidth = tableWidth / (float) cols;
+
+ // draw if boarder > 0
+ if (border != 0) {
+
+ float nexty = y + tableHeight;
+ float lasty = nexty;
+ for (int i = 0; i < rows; i++) {
+ ArrayList<Entry> row = abstractTable.getRow(i);
+ // Draw row border!
+ logger.debug("ROW LINE: {} {} {} {}", x, nexty, x + width,
+ nexty);
+ contentStream.drawLine(x, nexty, x + width, nexty);
+ lasty = nexty;
+ if (i < abstractTable.getRowHeights().length) {
+ // nexty -= abstractTable.getRowHeights()[i] + padding * 2;
+ nexty -= abstractTable.getRowHeights()[i];
+ }
+
+ // if (subtable && i + 1 ==
+ // abstractTable.getRowHeights().length) {
+ // nexty -= padding;
+ // }
+
+ float nextx = x;
+ float ypos = y;
+ float yheight = y + abstractTable.getHeight();
+ if (subtable) {
+ // ypos -= padding;
+ yheight = y + abstractTable.getHeight();
+ }
+
+ for (int j = 0; j < row.size(); j++) {
+ Entry cell = (Entry) row.get(j);
+
+ if (subtable && j == cols) {
+ continue;
+ }
+ logger.debug("COL LINE: {} {} {} {}", nextx, ypos, nextx,
+ yheight);
+ contentStream.drawLine(nextx, lasty, nextx, nexty);
+ for (int k = 0; k < cell.getColSpan(); k++) {
+ if (k + j < colsSizes.length) {
+ nextx += (colsSizes != null) ? colsSizes[k + j]
+ : colWidth;
+ }
+ }
+ }
+ if (!subtable) {
+ contentStream.drawLine(nextx, lasty, nextx, nexty);
+ }
+ }
+
+ contentStream.drawLine(x, nexty, x + tableWidth, nexty);
+
+ }
+
+ float textx = x;
+ float texty = y + tableHeight;
+ for (int i = 0; i < abstractTable.getRowCount(); i++) {
+ ArrayList<Entry> row = abstractTable.getRow(i);
+ for (int j = 0; j < row.size(); j++) {
+ Entry cell = (Entry) row.get(j);
+
+ Style inherit_style = Style.doInherit(cell.getStyle(),
+ abstractTable.style);
+ cell.setStyle(inherit_style);
+
+ // if(subtable) {
+ drawDebugPadding(contentStream, textx, texty, padding,
+ ((colsSizes != null) ? colsSizes[j] : colWidth),
+ abstractTable.getRowHeights()[i]);
+ // }
+ // if(true) {
+ // textx += (colsSizes != null) ? colsSizes[j] : colWidth;
+ // continue;
+ // }
+
+ if (cell.getType() == Entry.TYPE_CAPTION
+ || cell.getType() == Entry.TYPE_VALUE) {
+
+ if (cell.getType() == Entry.TYPE_CAPTION) {
+ textFont = abstractTable.getFont().getFont(doc);
+ fontSize = abstractTable.getFont().getFontSize();
+ } else if (cell.getType() == Entry.TYPE_VALUE) {
+ textFont = abstractTable.getValueFont().getFont(doc);
+ fontSize = abstractTable.getValueFont().getFontSize();
+ }
+
+ String text = (String) cell.getValue();
+
+ // COSName name = COSName.getPDFName("ANDI_TAG!");
+ // contentStream.beginMarkedContentSequence(COSName.ALT,
+ // name);
+ String fontName = textFont.equals(PDType1Font.COURIER) ? "COURIER"
+ : "HELVETICA";
+
+ float fheight = textFont.getFontDescriptor().getCapHeight()
+ / 1000 * fontSize;
+
+ String[] tlines = text.split("\n");
+ float textHeight = fontSize * tlines.length;
+
+ Style cellStyle = cell.getStyle();
+ String valign = null;
+ String halign = null;
+
+ if (cell.getType() == Entry.TYPE_CAPTION
+ && cellStyle != null) {
+ valign = cellStyle.getVAlign();
+ halign = cellStyle.getHAlign();
+ } else if (cell.getType() == Entry.TYPE_VALUE
+ && cellStyle != null) {
+ valign = cellStyle.getValueVAlign();
+ halign = cellStyle.getValueHAlign();
+ }
+ float ty = texty - padding;
+ float tx = textx + padding;
+ if (Style.BOTTOM.equals(valign)) {
+ float bottom_offset = abstractTable.getRowHeights()[i]
+ - textHeight;
+ ty -= bottom_offset;
+ } else if (Style.MIDDLE.equals(valign)) {
+ float bottom_offset = abstractTable.getRowHeights()[i]
+ - textHeight;
+ bottom_offset = bottom_offset / 2.0f;
+ ty -= bottom_offset;
+ }
+
+ float columnWidth = (colsSizes != null) ? colsSizes[j]
+ : colWidth;
+ float maxWidth = 0;
+ for (int k = 0; k < tlines.length; k++) {
+ float lineWidth;
+ if (textFont instanceof PDType1Font) {
+ lineWidth = textFont.getStringWidth(tlines[k])
+ / 1000.0f * fontSize;
+ } else {
+ float fwidth = textFont
+ .getStringWidth("abcdefghijklmnopqrstuvwxyz ")
+ / 1000.0f * fontSize;
+ fwidth = fwidth
+ / (float) "abcdefghijklmnopqrstuvwxyz"
+ .length();
+ lineWidth = tlines[k].length() * fwidth;
+ }
+
+ if (maxWidth < lineWidth) {
+ maxWidth = lineWidth;
+ }
+ }
+
+ if (Style.CENTER.equals(halign)) {
+ float offset = columnWidth - maxWidth - 2 * padding;
+ if (offset > 0) {
+ offset = offset / 2.0f;
+ tx += offset;
+ }
+ } else if (Style.RIGHT.equals(halign)) {
+ float offset = columnWidth - maxWidth - 2 * padding;
+ if (offset > 0) {
+ tx += offset;
+ }
+ }
+
+ drawDebugLine(contentStream, tx, ty, maxWidth, textHeight);
+
+ contentStream.beginText();
+
+ if (innerFormResources.getFonts().containsValue(textFont)) {
+ String fontID = getFontID(textFont);
+ logger.debug("Using Font: " + fontID);
+ contentStream.appendRawCommands("/" + fontID + " "
+ + fontSize + " Tf\n");
+ } else {
+ contentStream.setFont(textFont, fontSize);
+ }
+
+ logger.debug("Writing: " + tx + " : " + (ty - fheight)
+ + " = " + text + " as " + cell.getType() + " w "
+ + fontName);
+ contentStream.moveTextPositionByAmount(tx, (ty - fheight));
+
+ if (text.contains("\n")) {
+ String[] lines = text.split("\n");
+ contentStream.appendRawCommands(fontSize + " TL\n");
+ for (int k = 0; k < lines.length; k++) {
+ contentStream.drawString(lines[k]);
+ if (k < lines.length - 1) {
+ contentStream.appendRawCommands("T*\n");
+ }
+ }
+ } else {
+ contentStream.drawString(text);
+ }
+ contentStream.endText();
+ // contentStream.endMarkedContentSequence();
+ } else if (cell.getType() == Entry.TYPE_IMAGE) {
+ String img_ref = (String) cell.getValue();
+ if (!images.containsKey(img_ref)) {
+ logger.error("Image not prepared! : " + img_ref);
+ throw new PdfAsException("Image not prepared! : "
+ + img_ref);
+ }
+ ImageObject image = images.get(img_ref);
+ PDXObjectImage pdImage = image.getImage();
+
+ float imgx = textx + padding;
+ float hoffset = ((colsSizes != null) ? colsSizes[j]
+ : colWidth) - image.getWidth();
+ if (cell.getStyle().getImageVAlign() != null
+ && cell.getStyle().getImageVAlign()
+ .equals(Style.CENTER)) {
+ hoffset = hoffset / 2.0f;
+ imgx += hoffset;
+ } else if (cell.getStyle().getImageHAlign() != null
+ && cell.getStyle().getImageHAlign()
+ .equals(Style.RIGHT)) {
+ imgx += hoffset;
+ }
+
+ float imgy = texty - padding;
+ float voffset = abstractTable.getRowHeights()[i]
+ - image.getHeight();
+ if (cell.getStyle().getImageVAlign() != null
+ && cell.getStyle().getImageVAlign()
+ .equals(Style.MIDDLE)) {
+ voffset = voffset / 2.0f;
+ imgy -= voffset;
+ } else if (cell.getStyle().getImageVAlign() != null
+ && cell.getStyle().getImageVAlign()
+ .equals(Style.BOTTOM)) {
+ imgy -= voffset;
+ }
+
+ drawDebugLine(contentStream, imgx, imgy, image.getWidth(),
+ image.getHeight());
+
+ logger.debug("Image: " + imgx + " : "
+ + (imgy - image.getHeight()));
+ contentStream.drawXObject(pdImage, imgx,
+ imgy - image.getHeight(), image.getWidth(),
+ image.getHeight());
+ // contentStream.endMarkedContentSequence();
+
+ } else if (cell.getType() == Entry.TYPE_TABLE) {
+
+ float tableY = texty - abstractTable.getRowHeights()[i];
+ float tableX = textx;
+ // texty = texty - padding;
+ PDFBoxTable tbl_value = (PDFBoxTable) cell.getValue();
+
+ Style inherit_styletab = Style.doInherit(
+ abstractTable.style, cell.getStyle());
+ tbl_value.table.setStyle(inherit_styletab);
+
+ logger.debug("Table: " + tableX + " : " + tableY);
+ // logger.debug("Table height: " + );
+ TableDrawUtils.drawTable(page, contentStream, tableX,
+ tableY, (colsSizes != null) ? colsSizes[j]
+ : colWidth,
+ abstractTable.getRowHeights()[i], tbl_value, doc,
+ true, innerFormResources, images, settings);
+ }
+ textx += (colsSizes != null) ? colsSizes[j] : colWidth;
+ }
+ // if (i + 1 < abstractTable.getRowHeights().length) {
+ logger.debug("Row {} from {} - {} - {} = {}", i, texty,
+ abstractTable.getRowHeights()[i], padding * 2, texty
+ - (abstractTable.getRowHeights()[i]));
+ texty -= abstractTable.getRowHeights()[i];
+ // texty = texty - abstractTable.getRowHeights()[i + 1] - padding
+ // * 2;
+ // texty = texty - abstractTable.getRowHeights()[i] - padding
+ // * 2;
+ // }
+ textx = x;
+ }
+ }
+
+ private void drawTable2(PDPage page, PDPageContentStream contentStream,
+ float x, float y, float width, float height,
+ PDFBoxTable abstractTable, PDDocument doc, boolean subtable) {
+
+ }
+
+ private PDFAsVisualSignatureProperties properties;
+ private PDFAsVisualSignatureDesigner designer;
+ private ISettings settings;
+ private PDResources innerFormResources;
+ private Map<String, ImageObject> images = new HashMap<String, ImageObject>();
+
+ private String getFontID(PDFont font) {
+ Iterator<java.util.Map.Entry<String, PDFont>> it = innerFormResources
+ .getFonts().entrySet().iterator();
+ while (it.hasNext()) {
+ java.util.Map.Entry<String, PDFont> entry = it.next();
+ if (entry.getValue().equals(font)) {
+ return entry.getKey();
+ }
+ }
+ return "";
+ }
+
+ public PDFAsVisualSignatureBuilder(
+ PDFAsVisualSignatureProperties properties, ISettings settings,
+ PDFAsVisualSignatureDesigner designer) {
+ this.properties = properties;
+ this.settings = settings;
+ this.designer = designer;
+ }
+
+ @Override
+ public void createProcSetArray() {
+ COSArray procSetArr = new COSArray();
+ procSetArr.add(COSName.getPDFName("PDF"));
+ procSetArr.add(COSName.getPDFName("Text"));
+ procSetArr.add(COSName.getPDFName("ImageC"));
+ procSetArr.add(COSName.getPDFName("ImageB"));
+ procSetArr.add(COSName.getPDFName("ImageI"));
+ getStructure().setProcSet(procSetArr);
+ logger.debug("ProcSet array has been created");
+ }
+
+ public void createMyPage(PDFAsVisualSignatureDesigner properties) {
+ PDPage page = properties.getSignaturePage();
+ if (page == null) {
+ page = new PDPage();
+ page.setMediaBox(new PDRectangle(properties.getPageWidth(),
+ properties.getPageHeight()));
+
+ }
+ getStructure().setPage(page);
+ logger.info("PDF page has been created");
+ }
+
+ @Override
+ public void createTemplate(PDPage page) throws IOException {
+ PDDocument template = new PDDocument();
+
+ template.addPage(page);
+ getStructure().setTemplate(template);
+ }
+
+ private void readTableResources(PDFBoxTable table, PDDocument template)
+ throws PdfAsException, IOException {
+
+ float[] colsSizes = table.getColsRelativeWith();
+ int max_cols = table.getColCount();
+ float padding = table.getPadding();
+ if (colsSizes == null) {
+ colsSizes = new float[max_cols];
+ // set the column ratio for all columns to 1
+ for (int cols_idx = 0; cols_idx < colsSizes.length; cols_idx++) {
+ colsSizes[cols_idx] = 1;
+ }
+ }
+
+ logger.debug("TOTAL Width: " + table.getWidth());
+
+ float total = 0;
+
+ for (int cols_idx = 0; cols_idx < colsSizes.length; cols_idx++) {
+ total += colsSizes[cols_idx];
+ }
+
+ for (int cols_idx = 0; cols_idx < colsSizes.length; cols_idx++) {
+ colsSizes[cols_idx] = (colsSizes[cols_idx] / total)
+ * table.getWidth();
+ }
+
+ for (int cols_idx = 0; cols_idx < colsSizes.length; cols_idx++) {
+ logger.debug("Col: " + cols_idx + " : " + colsSizes[cols_idx]);
+ }
+
+ /*
+ * if(!addedFonts.contains(table.getFont().getFont(null))) { PDFont font
+ * = table.getFont().getFont(template); addedFonts.add(font);
+ * innerFormResources.addFont(font); }
+ *
+ * if(!addedFonts.contains(table.getValueFont().getFont(null))) { PDFont
+ * font = table.getValueFont().getFont(template); addedFonts.add(font);
+ * innerFormResources.addFont(font); }
+ */
+
+ for (int i = 0; i < table.getRowCount(); i++) {
+ ArrayList<Entry> row = table.getRow(i);
+ for (int j = 0; j < row.size(); j++) {
+ Entry cell = (Entry) row.get(j);
+ if (cell.getType() == Entry.TYPE_IMAGE) {
+ String img_ref = (String) cell.getValue();
+ if (!images.containsKey(img_ref)) {
+ File img_file = new File(img_ref);
+ if (!img_file.isAbsolute()) {
+ logger.debug("Image file declaration is relative. Prepending path of resources directory.");
+ logger.debug("Image Location: "
+ + settings.getWorkingDirectory()
+ + File.separator + img_ref);
+ img_file = new File(settings.getWorkingDirectory()
+ + File.separator + img_ref);
+ } else {
+ logger.debug("Image file declaration is absolute. Skipping file relocation.");
+ }
+
+ if (!img_file.exists()) {
+ logger.debug("Image file \""
+ + img_file.getCanonicalPath()
+ + "\" doesn't exist.");
+ throw new PdfAsException("error.pdf.stamp.04");
+ }
+
+ BufferedImage img = null;
+ try {
+ img = ImageIO.read(img_file);
+ } catch (IOException e) {
+ throw new PdfAsException("error.pdf.stamp.04", e);
+ }
+
+ float width = colsSizes[j];
+ float height = table.getRowHeights()[i] + padding * 2;
+
+ float iwidth = (int) Math.floor((double) width);
+ iwidth -= 2 * padding;
+
+ float iheight = (int) Math.floor((double) height);
+ iheight -= 2 * padding;
+
+ float origWidth = (float) img.getWidth();
+ float origHeight = (float) img.getHeight();
+
+ if (table.style != null) {
+ if (table.style.getImageScaleToFit() != null) {
+ iwidth = table.style.getImageScaleToFit()
+ .getWidth();
+ iheight = table.style.getImageScaleToFit()
+ .getHeight();
+ }
+ }
+
+ float wfactor = iwidth / origWidth;
+ float hfactor = iheight / origHeight;
+ float scaleFactor = wfactor;
+ if (hfactor < wfactor) {
+ scaleFactor = hfactor;
+ }
+
+ iwidth = (float) Math
+ .floor((double) (scaleFactor * origWidth));
+ iheight = (float) Math
+ .floor((double) (scaleFactor * origHeight));
+
+ logger.debug("Scaling image to: " + iwidth + " x "
+ + iheight);
+
+ if (img.getAlphaRaster() == null
+ && img.getColorModel().hasAlpha()) {
+ img = ImageUtils.removeAlphaChannel(img);
+ }
+
+ PDXObjectImage pdImage = new PDPixelMap(template, img);
+
+ ImageObject image = new ImageObject(pdImage, iwidth,
+ iheight);
+ images.put(img_ref, image);
+ innerFormResources.addXObject(pdImage, "Im");
+ }
+ } else if (cell.getType() == Entry.TYPE_TABLE) {
+ PDFBoxTable tbl_value = (PDFBoxTable) cell.getValue();
+ readTableResources(tbl_value, template);
+ }
+ }
+ }
+ }
+
+ public void createInnerFormStreamPdfAs(PDDocument template) throws PdfAsException {
+ try {
+
+ // Hint we have to create all PDXObjectImages before creating the
+ // PDPageContentStream
+ // only PDFbox developers know why ...
+ //if (getStructure().getPage().getResources() != null) {
+ // innerFormResources = getStructure().getPage().getResources();
+ //} else {
+ innerFormResources = new PDResources();
+ getStructure().getPage().setResources(innerFormResources);
+ //}
+ readTableResources(properties.getMainTable(), template);
+
+ PDPageContentStream stream = new PDPageContentStream(template,
+ getStructure().getPage());
+ // stream.setFont(PDType1Font.COURIER, 5);
+ TableDrawUtils.drawTable(getStructure().getPage(), stream, 1, 1,
+ designer.getWidth(), designer.getHeight(),
+ properties.getMainTable(), template, false,
+ innerFormResources, images, settings);
+ stream.close();
+ PDStream innterFormStream = getStructure().getPage().getContents();
+ getStructure().setInnterFormStream(innterFormStream);
+ logger.debug("Strean of another form (inner form - it would be inside holder form) has been created");
+
+ } catch (Throwable e) {
+ logger.error("Failed to create visual signature block", e);
+ throw new PdfAsException("Failed to create visual signature block", e);
+ }
+ }
+
+ @Override
+ public void injectProcSetArray(PDXObjectForm innerForm, PDPage page,
+ PDResources innerFormResources, PDResources imageFormResources,
+ PDResources holderFormResources, COSArray procSet) {
+ innerForm.getResources().getCOSDictionary()
+ .setItem(COSName.PROC_SET, procSet); //
+ page.getCOSDictionary().setItem(COSName.PROC_SET, procSet);
+ innerFormResources.getCOSDictionary()
+ .setItem(COSName.PROC_SET, procSet);
+ /*
+ * imageFormResources.getCOSDictionary() .setItem(COSName.PROC_SET,
+ * procSet);
+ */
+ holderFormResources.getCOSDictionary().setItem(COSName.PROC_SET,
+ procSet);
+ logger.debug("inserted ProcSet to PDF");
+ }
+
+ public void injectAppearanceStreams(PDStream holderFormStream,
+ PDStream innterFormStream, PDStream imageFormStream,
+ String imageObjectName, String imageName, String innerFormName,
+ PDFAsVisualSignatureDesigner properties) throws IOException {
+
+ // 100 means that document width is 100% via the rectangle. if rectangle
+ // is 500px, images 100% is 500px.
+ // String imgFormComment = "q "+imageWidthSize+ " 0 0 50 0 0 cm /" +
+ // imageName + " Do Q\n" + builder.toString();
+ /*
+ * String imgFormComment = "q " + 100 + " 0 0 50 0 0 cm /" + imageName +
+ * " Do Q\n";
+ */
+ double m00 = getStructure().getAffineTransform().getScaleX();
+ double m10 = getStructure().getAffineTransform().getShearY();
+ double m01 = getStructure().getAffineTransform().getShearX();
+ double m11 = getStructure().getAffineTransform().getScaleY();
+ double m02 = getStructure().getAffineTransform().getTranslateX();
+ double m12 = getStructure().getAffineTransform().getTranslateY();
+
+ String holderFormComment = "q " + m00 + " " + m10 + " " + m01 + " "
+ + m11 + " " + m02 + " " + m12 + " cm /" + innerFormName
+ + " Do Q \n";
+
+ logger.debug("Holder Form Stream: " + holderFormComment);
+
+ // String innerFormComment = "q 1 0 0 1 0 0 cm /" + imageObjectName +
+ // " Do Q\n";
+ String innerFormComment = getStructure().getInnterFormStream()
+ .getInputStreamAsString();
+
+ //logger.debug("Inner Form Stream: " + innerFormComment);
+
+ // appendRawCommands(getStructure().getInnterFormStream().createOutputStream(),
+ // getStructure().getInnterFormStream().getInputStreamAsString());
+
+ appendRawCommands(getStructure().getHolderFormStream()
+ .createOutputStream(), holderFormComment);
+ appendRawCommands(getStructure().getInnterFormStream()
+ .createOutputStream(), innerFormComment);
+ // appendRawCommands(getStructure().getImageFormStream().createOutputStream(),
+ // imgFormComment);
+ logger.debug("Injected apereance stream to pdf");
+
+ }
+
+ public void createPage(PDFAsVisualSignatureDesigner properties) {
+ PDPage page = new PDPage();
+ page.setMediaBox(new PDRectangle(properties.getPageWidth(), properties
+ .getPageHeight()));
+ getStructure().setPage(page);
+ logger.debug("PDF page has been created");
+ }
+
+ public void createAcroForm(PDDocument template) {
+ PDAcroForm theAcroForm = new PDAcroForm(template);
+ template.getDocumentCatalog().setAcroForm(theAcroForm);
+ getStructure().setAcroForm(theAcroForm);
+ logger.debug("Acro form page has been created");
+
+ }
+
+ public void createSignatureField(PDAcroForm acroForm) throws IOException {
+ PDSignatureField sf = new PDSignatureField(acroForm);
+ getStructure().setSignatureField(sf);
+ logger.debug("Signature field has been created");
+ }
+
+ public void createSignature(PDSignatureField pdSignatureField, PDPage page,
+ String signatureName) throws IOException {
+ PDSignature pdSignature = new PDSignature();
+ pdSignatureField.setSignature(pdSignature);
+ pdSignatureField.getWidget().setPage(page);
+ page.getAnnotations().add(pdSignatureField.getWidget());
+ pdSignature.setName(signatureName);
+ pdSignature.setByteRange(new int[] { 0, 0, 0, 0 });
+ pdSignature.setContents(new byte[4096]);
+ getStructure().setPdSignature(pdSignature);
+ logger.debug("PDSignatur has been created");
+ }
+
+ public void createAcroFormDictionary(PDAcroForm acroForm,
+ PDSignatureField signatureField) throws IOException {
+ @SuppressWarnings("unchecked")
+ List<PDField> acroFormFields = acroForm.getFields();
+ COSDictionary acroFormDict = acroForm.getDictionary();
+ acroFormDict.setDirect(true);
+ acroFormDict.setInt(COSName.SIG_FLAGS, 3);
+ acroFormFields.add(signatureField);
+ acroFormDict.setString(COSName.DA, "/sylfaen 0 Tf 0 g");
+ getStructure().setAcroFormFields(acroFormFields);
+ getStructure().setAcroFormDictionary(acroFormDict);
+ logger.debug("AcroForm dictionary has been created");
+ }
+
+ public void createSignatureRectangle(PDSignatureField signatureField,
+ PDFAsVisualSignatureDesigner properties, float degrees)
+ throws IOException {
+
+ PDRectangle rect = new PDRectangle();
+
+ Point2D upSrc = new Point2D.Float();
+ upSrc.setLocation(properties.getxAxis() + properties.getWidth(),
+ properties.getPageHeight() - properties.getyAxis());
+
+ Point2D llSrc = new Point2D.Float();
+ llSrc.setLocation(properties.getxAxis(), properties.getPageHeight()
+ - properties.getyAxis() - properties.getHeight());
+ AffineTransform transform = new AffineTransform();
+ transform.setToIdentity();
+ if (degrees % 360 != 0) {
+ transform.setToRotation(Math.toRadians(degrees), llSrc.getX(),
+ llSrc.getY());
+ }
+ Point2D upDst = new Point2D.Float();
+ transform.transform(upSrc, upDst);
+
+ Point2D llDst = new Point2D.Float();
+ transform.transform(llSrc, llDst);
+
+ rect.setUpperRightX((float) upDst.getX());
+ rect.setUpperRightY((float) upDst.getY());
+ rect.setLowerLeftY((float) llDst.getY());
+ rect.setLowerLeftX((float) llDst.getX());
+ logger.debug("rectangle of signature has been created: {}",
+ rect.toString());
+ signatureField.getWidget().setRectangle(rect);
+ getStructure().setSignatureRectangle(rect);
+ logger.debug("rectangle of signature has been created");
+ }
+
+ public void createAffineTransform(float[] params) {
+ AffineTransform transform = new AffineTransform(params[0], params[1],
+ params[2], params[3], params[4], params[5]);
+ // transform.rotate(90);
+ getStructure().setAffineTransform(transform);
+ logger.debug("Matrix has been added");
+ }
+
+ public void createSignatureImage(PDDocument template,
+ InputStream inputStream) throws IOException {
+ PDJpeg img = new PDJpeg(template, inputStream);
+ getStructure().setJpedImage(img);
+ logger.debug("Visible Signature Image has been created");
+ // pdfStructure.setTemplate(template);
+ inputStream.close();
+
+ }
+
+ public void createFormaterRectangle(float[] params) {
+
+ PDRectangle formrect = new PDRectangle();
+ float[] translated = new float[4];
+ getStructure().getAffineTransform().transform(params, 0, translated, 0,
+ 2);
+
+ formrect.setUpperRightX(translated[0]);
+ formrect.setUpperRightY(translated[1]);
+ formrect.setLowerLeftX(translated[2]);
+ formrect.setLowerLeftY(translated[3]);
+
+ getStructure().setFormaterRectangle(formrect);
+ logger.debug("Formater rectangle has been created");
+
+ }
+
+ public void createHolderFormStream(PDDocument template) {
+ PDStream holderForm = new PDStream(template);
+ getStructure().setHolderFormStream(holderForm);
+ logger.debug("Holder form Stream has been created");
+ }
+
+ public void createHolderFormResources() {
+ PDResources holderFormResources = new PDResources();
+ getStructure().setHolderFormResources(holderFormResources);
+ logger.debug("Holder form resources have been created");
+
+ }
+
+ public void createHolderForm(PDResources holderFormResources,
+ PDStream holderFormStream, PDRectangle formrect) {
+
+ PDXObjectForm holderForm = new PDXObjectForm(holderFormStream);
+ holderForm.setResources(holderFormResources);
+ holderForm.setBBox(formrect);
+ holderForm.setFormType(1);
+ getStructure().setHolderForm(holderForm);
+ logger.debug("Holder form has been created");
+
+ }
+
+ public void createAppearanceDictionary(PDXObjectForm holderForml,
+ PDSignatureField signatureField, float degrees) throws IOException {
+
+ PDAppearanceDictionary appearance = new PDAppearanceDictionary();
+ appearance.getCOSObject().setDirect(true);
+
+ PDAppearanceStream appearanceStream = new PDAppearanceStream(
+ holderForml.getCOSStream());
+ AffineTransform transform = new AffineTransform();
+ transform.setToIdentity();
+ transform.rotate(Math.toRadians(degrees));
+ appearanceStream.setMatrix(transform);
+ appearance.setNormalAppearance(appearanceStream);
+ signatureField.getWidget().setAppearance(appearance);
+
+ getStructure().setAppearanceDictionary(appearance);
+ logger.debug("PDF appereance Dictionary has been created");
+
+ }
+
+ public void createInnerFormResource() {
+ getStructure().setInnerFormResources(innerFormResources);
+ logger.debug("Resources of another form (inner form - it would be inside holder form) have been created");
+ }
+
+ public void createInnerForm(PDResources innerFormResources,
+ PDStream innerFormStream, PDRectangle formrect) {
+ PDXObjectForm innerForm = new PDXObjectForm(innerFormStream);
+ innerForm.setResources(innerFormResources);
+ innerForm.setBBox(formrect);
+ innerForm.setFormType(1);
+ getStructure().setInnerForm(innerForm);
+ logger.debug("Another form (inner form - it would be inside holder form) have been created");
+
+ }
+
+ public void insertInnerFormToHolerResources(PDXObjectForm innerForm,
+ PDResources holderFormResources) {
+ String name = holderFormResources.addXObject(innerForm, "FRM");
+ getStructure().setInnerFormName(name);
+ logger.debug("Alerady inserted inner form inside holder form");
+ }
+
+ public void createImageFormStream(PDDocument template) {
+ PDStream imageFormStream = new PDStream(template);
+ getStructure().setImageFormStream(imageFormStream);
+ logger.debug("Created image form Stream");
+ }
+
+ public void createImageFormResources() {
+ PDResources imageFormResources = new PDResources();
+ getStructure().setImageFormResources(imageFormResources);
+ logger.debug("Created image form Resources");
+ }
+
+ public void createImageForm(PDResources imageFormResources,
+ PDResources innerFormResource, PDStream imageFormStream,
+ PDRectangle formrect, AffineTransform affineTransform, PDJpeg img)
+ throws IOException {
+
+ /*
+ * if you need text on the visible signature
+ *
+ * PDFont font = PDTrueTypeFont.loadTTF(this.pdfStructure.getTemplate(),
+ * new File("D:\\arial.ttf")); font.setFontEncoding(new
+ * WinAnsiEncoding());
+ *
+ * Map<String, PDFont> fonts = new HashMap<String, PDFont>();
+ * fonts.put("arial", font);
+ */
+ PDXObjectForm imageForm = new PDXObjectForm(imageFormStream);
+ imageForm.setBBox(formrect);
+ imageForm.setMatrix(affineTransform);
+ imageForm.setResources(imageFormResources);
+ imageForm.setFormType(1);
+ /*
+ * imageForm.getResources().addFont(font);
+ * imageForm.getResources().setFonts(fonts);
+ */
+
+ imageFormResources.getCOSObject().setDirect(true);
+ String imageFormName = innerFormResource.addXObject(imageForm, "n");
+ String imageName = imageFormResources.addXObject(img, "img");
+ this.getStructure().setImageForm(imageForm);
+ this.getStructure().setImageFormName(imageFormName);
+ this.getStructure().setImageName(imageName);
+ logger.debug("Created image form");
+ }
+
+ public void appendRawCommands(OutputStream os, String commands)
+ throws IOException {
+ os.write(commands.getBytes("UTF-8"));
+ os.close();
+ }
+
+ public void createVisualSignature(PDDocument template) {
+ this.getStructure().setVisualSignature(template.getDocument());
+ logger.debug("Visible signature has been created");
+
+ }
+
+ public void createWidgetDictionary(PDSignatureField signatureField,
+ PDResources holderFormResources) throws IOException {
+
+ COSDictionary widgetDict = signatureField.getWidget().getDictionary();
+ widgetDict.setNeedToBeUpdate(true);
+ widgetDict.setItem(COSName.DR, holderFormResources.getCOSObject());
+
+ getStructure().setWidgetDictionary(widgetDict);
+ logger.debug("WidgetDictionary has been crated");
+ }
+
+ public void closeTemplate(PDDocument template) throws IOException {
+ template.close();
+ this.getStructure().getTemplate().close();
+ }
+
+}