From db52e4d66d60184d53a27ba4d6772461daacc03d Mon Sep 17 00:00:00 2001 From: tknall Date: Fri, 22 Mar 2013 08:57:51 +0000 Subject: Maintenance update (bugfixes, new features, cleanup...) Refer to /dok/RELEASE_NOTES-3.3.txt for further information. git-svn-id: https://joinup.ec.europa.eu/svn/pdf-as/pdf-as/trunk@931 7b5415b0-85f9-ee4d-85bd-d5d0c3b42d1c --- .../wag/egov/egiz/pdf/AbsoluteTextSignature.java | 4 +- .../wag/egov/egiz/pdf/BinarySignature.java | 215 ++++++++++-------- .../at/knowcenter/wag/egov/egiz/pdf/PDFPage.java | 249 ++++++++++++++++----- .../wag/egov/egiz/pdf/PDFSignatureObjectIText.java | 70 +++--- .../knowcenter/wag/egov/egiz/pdf/PDFUtilities.java | 25 ++- .../wag/egov/egiz/pdf/StructContentHelper.java | 47 ++-- .../wag/egov/egiz/pdf/TextualSignature.java | 56 +++-- .../path/PathConstructionOperatorProcessor.java | 62 +++++ .../path/PathPaintingOperatorProcessor.java | 43 ++++ .../pdf/operator/path/construction/ClosePath.java | 68 ++++++ .../pdf/operator/path/construction/CurveTo.java | 85 +++++++ .../construction/CurveToReplicateFinalPoint.java | 82 +++++++ .../construction/CurveToReplicateInitialPoint.java | 84 +++++++ .../pdf/operator/path/construction/LineTo.java | 71 ++++++ .../pdf/operator/path/construction/MoveTo.java | 73 ++++++ .../operator/path/painting/CloseAndStrokePath.java | 59 +++++ .../painting/CloseFillEvenOddAndStrokePath.java | 60 +++++ .../painting/CloseFillNonZeroAndStrokePath.java | 60 +++++ .../egiz/pdf/operator/path/painting/EndPath.java | 68 ++++++ .../path/painting/FillEvenOddAndStrokePath.java | 72 ++++++ .../path/painting/FillNonZeroAndStrokePath.java | 72 ++++++ .../path/painting/FillPathEvenOddRule.java | 71 ++++++ .../painting/FillPathNonZeroWindingNumberRule.java | 72 ++++++ .../pdf/operator/path/painting/StrokePath.java | 70 ++++++ 24 files changed, 1591 insertions(+), 247 deletions(-) create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/PathConstructionOperatorProcessor.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/PathPaintingOperatorProcessor.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/construction/ClosePath.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/construction/CurveTo.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/construction/CurveToReplicateFinalPoint.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/construction/CurveToReplicateInitialPoint.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/construction/LineTo.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/construction/MoveTo.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/CloseAndStrokePath.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/CloseFillEvenOddAndStrokePath.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/CloseFillNonZeroAndStrokePath.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/EndPath.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/FillEvenOddAndStrokePath.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/FillNonZeroAndStrokePath.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/FillPathEvenOddRule.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/FillPathNonZeroWindingNumberRule.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/StrokePath.java (limited to 'pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf') diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/AbsoluteTextSignature.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/AbsoluteTextSignature.java index fd59d34..7b5a968 100644 --- a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/AbsoluteTextSignature.java +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/AbsoluteTextSignature.java @@ -73,7 +73,9 @@ public class AbsoluteTextSignature public static List getSignatureTypesForTextAnalysis() throws SignatureTypesException { SignatureTypes sig_types = SignatureTypes.getInstance(); - List allSignatureTypes = sig_types.getSignatureTypeDefinitions(); + // use only those profiles that are allowed to be used for verification +// List allSignatureTypes = sig_types.getSignatureTypeDefinitions(); + List allSignatureTypes = sig_types.getSignatureTypeDefinitionsForVerification(); List textSignatureTypes = new ArrayList(allSignatureTypes.size()); Iterator it = allSignatureTypes.iterator(); diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/BinarySignature.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/BinarySignature.java index ece9525..75a64f1 100644 --- a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/BinarySignature.java +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/BinarySignature.java @@ -40,6 +40,7 @@ import java.util.Comparator; import java.util.Iterator; import java.util.List; +import org.apache.commons.io.IOUtils; import org.apache.commons.lang.ArrayUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -89,25 +90,46 @@ import com.lowagie.text.pdf.PdfStamper; import com.lowagie.text.pdf.PdfStamperImp; import com.lowagie.text.pdf.PdfString; import com.lowagie.text.pdf.PdfTemplate; +import com.lowagie.text.pdf.PdfWriter; /** * Contains various extension functions to digitally sign documents. - * + * *

* These functions are used to replace parts of the original Egiz plain text * signature mechanism. *

- * + * * @author wprinz */ public abstract class BinarySignature { //23.11.2010 changed by exthex - added replacePlaceholder(PdfStamper stamper, int pageNr, String placeholderName) method - + protected static Log logger = LogFactory.getLog(BinarySignature.class); + + /** + * The resource path of the srgb profile to be embedded in case of PDF/A-1b. + */ + private static final String srgbProfileResource = "/at/gv/egiz/pdfas/itext/srgb.profile"; + + /** + * The color profile to be embedded in case of PDF/A-1b. + */ + private static final byte[] SRGB_PROFILE; + + static { + try { + logger.debug("Preloading srgb color profile '" + srgbProfileResource + "."); + SRGB_PROFILE = IOUtils.toByteArray(BinarySignature.class.getResourceAsStream(srgbProfileResource)); + } catch (IOException e) { + throw new RuntimeException("Unable to preload srgb color profile.", e); + } + } + /** * The tolerance area of the line break algorithm. - * + * * @see Placeholder#replacePlaceholderWithTolerance(byte[], List, byte[], int) */ public static final int LINE_BREAK_TOLERANCE = 10; @@ -116,11 +138,11 @@ public abstract class BinarySignature * The number of bytes left out for the certificate placeholder. */ public static final int CERTIFICATE_PLACEHOLDER_LENGTH = 10000; - + /** * The number of bytes left out for the timestamp placeholder. */ - public static final int TIMESTAMP_PLACEHOLDER_LENGTH = 5000; + public static final int TIMESTAMP_PLACEHOLDER_LENGTH = 5000; /** * The placeholder character used to fill out Strings in the layout process. @@ -162,11 +184,11 @@ public abstract class BinarySignature * The SIG_ID brev. */ public static final byte[] BREV_SID = { 's', 'i', 'd' }; - + /** * The SIG_ALG brev. */ - public static final byte[] BREV_ALG = { 'a', 'l', 'g' }; + public static final byte[] BREV_ALG = { 'a', 'l', 'g' }; /** * No explicit encoding. @@ -185,7 +207,7 @@ public abstract class BinarySignature /** * The PDFName of the Egiz Dictionary. - * + * *

* Used to locate and identify the Egiz Dictionary in the document. *

@@ -195,7 +217,7 @@ public abstract class BinarySignature /** * The PDFName of the Original Document Size (ODS) field in an Egiz * Dictionary. - * + * *

* The ODS must be a positive integral number. *

@@ -226,7 +248,7 @@ public abstract class BinarySignature * The PdfName of the certificate array. */ public static final PdfName EGIZ_CERTIFICATE_NAME = new PdfName("Cert"); - + /** * The PdfName of the Timestamp */ @@ -239,7 +261,7 @@ public abstract class BinarySignature /** * The PDFName of the Signature XObject field in an Egiz Dictionary. - * + * *

* This must be an indirect reference to the XObject containing the Signature * table. @@ -251,17 +273,17 @@ public abstract class BinarySignature * The number placeholder that is used to give numbers a fixed length. */ protected static final PdfNumber NUMBER_PLACEHOLDER = new PdfNumber(999999999); - + /** * Extracts the signature text only. - * + * *

* The signature text is the text of the Signature XObject. *

- * + * * @param egiz_dict * The Egiz Dictionary. - * + * * @return Returns the signature text. */ public static String extractSignatureTextOnly(PdfDictionary egiz_dict) throws IOException @@ -276,7 +298,7 @@ public abstract class BinarySignature /** * Retrieves the size of the original document from the Egiz Dictionary. - * + * * @param egiz_dict * The Egiz Dictionary. * @return Returns the size (in bytes) of the original document. @@ -292,7 +314,7 @@ public abstract class BinarySignature /** * Retrieves the previous Egiz dictionary from the given one, if a previous * dictionary exists. - * + * * @param egiz_dict * The Egiz Dictionary. * @return Returns the previous Egiz Dictionary, or null if there is none. @@ -306,7 +328,7 @@ public abstract class BinarySignature /** * Retrieves the Egiz Dictionary from the document if present. - * + * * @param reader * The reader to retrieve the dictionary from. * @return Returns the Egiz Dictionary, if present, or returns null, if no @@ -327,7 +349,7 @@ public abstract class BinarySignature /** * Retrieves the Egiz Dictionary's indirect reference from the reader. - * + * * @param reader * The reader. * @return Returns the indirect reference of the Egiz Dictionary, or null, if @@ -342,14 +364,14 @@ public abstract class BinarySignature /** * Retrieves the chain of Egiz Dictionaries from the reader. - * + * *

* The first element in the List will be the top most (oldest) Egiz * Dictionary. The last element in the List will be the bottom most (latest) * Egiz Dictionary. If the list is empty, no dictionary could be found at all, * which means that the document is not digitally signed. *

- * + * * @param reader * The reader. * @return Returns the List of PdfDictionaries from the document. @@ -374,7 +396,7 @@ public abstract class BinarySignature /** * Builds a digest of the given data. - * + * * @param data * The data to be digested. * @param length @@ -393,7 +415,6 @@ public abstract class BinarySignature } catch (NoSuchAlgorithmException e) { - e.printStackTrace(); throw new PDFDocumentException(202, "Digest algorithm not supported - NoSuchAlgorithmException", e); } @@ -406,7 +427,7 @@ public abstract class BinarySignature /** * Retrieves the signable text from the given document. - * + * * @param data * The data. * @param ods @@ -423,7 +444,7 @@ public abstract class BinarySignature /** * Fills the holes in the byte ranges with the SIGN_PLACEHOLDER. - * + * * @param data * The given byte ranged data. * @param byte_ranges @@ -697,7 +718,7 @@ public abstract class BinarySignature // throw new PresentableException(e); // } // } - + protected static int getLineBreakTolerance(IncrementalUpdateInformation iui) throws PDFDocumentException { SettingsReader settings; @@ -717,7 +738,7 @@ public abstract class BinarySignature } return lineBreakTolerance; } - + protected static int getCertificatePlaceholderLength(IncrementalUpdateInformation iui) throws SettingNotFoundException { SettingsReader settings; @@ -737,7 +758,7 @@ public abstract class BinarySignature } return certLen; } - + protected static int getTimestampPlaceholderLength(IncrementalUpdateInformation iui) throws SettingNotFoundException { SettingsReader settings; @@ -761,7 +782,7 @@ public abstract class BinarySignature /** * Signs a document with the given signature table using the Incremental * Update method. - * + * *

* The table containing the signature text will be appended. As specified by * the parameters, the signature will be appended to the last page, or a plain @@ -777,7 +798,7 @@ public abstract class BinarySignature * information about the signature. Basically the size of the original * document and the reference of the signature table. *

- * + * * @param original_document * The original document. * @param pdf_table @@ -811,10 +832,7 @@ public abstract class BinarySignature // System.out.println("wprinz: STAMPING PDF"); // InputStream is = original_document.createInputStream(); - byte[] pdf_data = original_document.getAsByteArray(); - PdfReader reader = new PdfReader(pdf_data); - PDFASUtils.checkReaderPermissions(reader); - // is.close(); + PdfReader reader = PDFASUtils.createPdfReaderCheckingPermissions(original_document); OutputStream baos = written_pdf.createOutputStream("application/pdf"); // ByteArrayOutputStream baos = new ByteArrayOutputStream(); @@ -823,7 +841,7 @@ public abstract class BinarySignature // incremental updated // The stamper allows this by setting append = true boolean adobeSigField = AdobeSignatureHelper.isAdobeSignatureFieldEnabled(so.getSignatureTypeDefinition().getType()); - PdfStamper stamper = null; + PdfStamper stamper = null; if (adobeSigField) { stamper = PdfStamper.createSignature(reader, baos, '\0', null, true); } else { @@ -843,13 +861,13 @@ public abstract class BinarySignature { throw new PDFDocumentException(224, "The provided page (=" + pi.getPage() + ") is out of range."); } - + if (SignaturePlaceholderContext.isSignaturePlaceholderDataSet() && SignaturePlaceholderContext.getSignaturePlaceholderData().getPlaceholderName() != null) { replacePlaceholder(stamper, pi.getPage(), SignaturePlaceholderContext.getSignaturePlaceholderData().getPlaceholderName()); } - + PdfContentByte content = stamper.getOverContent(pi.getPage()); // content = StampContent einer PageStamp. @@ -857,12 +875,12 @@ public abstract class BinarySignature // table_height = " + pdf_table.getTotalHeight()); PdfTemplate table_template = content.createTemplate(pdf_table.getTotalWidth(), pdf_table.getTotalHeight()); - table_template.setCompress(Boolean.FALSE); // do not compress sigblock because we rewrite it afterwards for bin sig + table_template.setCompress(Boolean.FALSE); // do not compress sigblock because we rewrite it afterwards for bin sig // exthex StructContentHelper structHelper = new StructContentHelper(stamper, content, pi.getPage()); structHelper.prepareStructData(table_template); - + pdf_table.writeSelectedRows(0, -1, 0, pdf_table.getTotalHeight(), table_template); // table_template.moveTo(0, 0); @@ -876,13 +894,13 @@ public abstract class BinarySignature // pdf_table.writeSelectedRows(0, -1, SIGNATURE_BORDER / 2, // table_position, content); - + structHelper.beginSigBlockContent(); - + content.addTemplate(table_template, pi.getX(), pi.getY() - pdf_table.getTotalHeight()); - - structHelper.endSigBlockContent(); - + + structHelper.endSigBlockContent(); + ActualTablePos atp = new ActualTablePos(); atp.page = pi.getPage(); @@ -891,13 +909,13 @@ public abstract class BinarySignature atp.width = pdf_table.getTotalWidth(); atp.height = pdf_table.getTotalHeight(); iui.actualTablePos = atp; - + structHelper.buildFigureStructData(so, table_template); structHelper.buildSigBlockStructData(); structHelper.finishMainStructData(); - + structHelper.buildVerifyLinkStructData(table_template, atp); - + // For debugging print a 100x100 grid // { // Rectangle psize = reader.getPageSizeWithRotation(pos.page); @@ -940,7 +958,22 @@ public abstract class BinarySignature // PdfObject value = resources.get(key); // System.out.println(" " + key + " = " + value); // } - + + // added by dti: fixing PDF/A-1b + if (PDFASUtils.isPdfAEnabled(profile)) { + logger.debug("Adding sRGB IEC61966-2.1 color profile (output intent) in order to satisfy PDF/A-1b requirements."); + PdfWriter writer = stamper.getWriter(); + writer.setOutputIntents("Custom", "sRGB", "", "sRGB IEC61966-2.1", SRGB_PROFILE); + PdfArray a = writer.getExtraCatalog().getAsArray(PdfName.OUTPUTINTENTS); + if (a != null) { + PdfDictionary d = a.getAsDict(0); + if (d != null) { + // overwrite PDF/X entry with PDF/A entry + d.put(PdfName.S, PdfName.GTS_PDFA1); + } + } + } + // add the EGIZ dict: if (variable_field_definitions != null) { @@ -964,22 +997,20 @@ public abstract class BinarySignature } catch (IOException e) { - e.printStackTrace(); throw new PresentableException(ErrorCode.CANNOT_WRITE_PDF, e); } catch (DocumentException e) { - e.printStackTrace(); throw new PresentableException(ErrorCode.CANNOT_WRITE_PDF, e); } } - + private static void replacePlaceholder(PdfStamper stamper, int pageNr, String placeholderName) throws BadElementException, MalformedURLException, IOException, BadPdfFormatException, PresentableException { Image img = Image.getInstance(SignaturePlaceholderData.class.getResource("empty.jpg")); PdfImage pImg = new PdfImage(img, "Imwurscht", null); PdfStamperImp stamperImp = (PdfStamperImp)stamper.getWriter(); PdfIndirectObject ind = stamperImp.addToBody(pImg); - + PdfDictionary resources = stamper.getReader().getPageN(pageNr).getAsDict(PdfName.RESOURCES); if (ind != null && resources != null) { @@ -999,11 +1030,11 @@ public abstract class BinarySignature throw new PresentableException(ErrorCode.CANNOT_WRITE_PDF, new NullPointerException("Resource dictionary not found in document structure!")); } } - + /** * Creates the EGIZ Dictionary and adds it to the document. - * + * * @param stamper * The PdfStamper. * @param table_template @@ -1092,11 +1123,11 @@ public abstract class BinarySignature // /encodings replaces_array.add(new PdfName(new String(BREV_NIL, "US-ASCII"))); // the // /Cert - + if (iui.timeStamper != null) { encodings_array.add(new PdfName(new String(ENCODING_NIL))); // the /Timestamp replaces_array.add(new PdfName(new String(BREV_NIL, "US-ASCII"))); // the /timestamp - + } // hidden replaces @@ -1153,9 +1184,9 @@ public abstract class BinarySignature } PdfString cert_placeholder = new PdfString(cert_bytes); cert_array.add(cert_placeholder); - egiz_dict.put(EGIZ_CERTIFICATE_NAME, cert_array); - - // Timestamp + egiz_dict.put(EGIZ_CERTIFICATE_NAME, cert_array); + + // Timestamp if (iui.timeStamper != null) { // only if handler is available PdfArray timestamp_array = new PdfArray(); @@ -1167,10 +1198,10 @@ public abstract class BinarySignature } PdfString timestamp_placeholder = new PdfString(timestamp_bytes); timestamp_array.add(timestamp_placeholder); - egiz_dict.put(EGIZ_TIMESTAMP_NAME, timestamp_array); + egiz_dict.put(EGIZ_TIMESTAMP_NAME, timestamp_array); } - + // /Data array with hidden information if (has_hidden_variable_fields || invisibleKZString != null) { @@ -1221,7 +1252,7 @@ public abstract class BinarySignature /** * Converts a field name (type) to the corresponding BREV. - * + * * @param type * The field name (type). * @return Returns the corresponding BREV, or BREV_NIL if the type is not @@ -1261,12 +1292,12 @@ public abstract class BinarySignature /** * Updates the information in the egiz dictionary to reflect the real offsets * of the byte ranges. - * + * *

* This replaces the "dummy numbers" in the egiz dictionary with the correct * values. *

- * + * * @param iui * The IncrementalUpdateInformation. * @throws PDFDocumentException @@ -1309,7 +1340,7 @@ public abstract class BinarySignature byte[] cert_bytes = cert_str.getBytes("US-ASCII"); int cert_index = ByteArrayUtils.indexOf(signed_pdf, obj_start, cert_bytes); int cert_start = cert_index + cert_bytes.length; - + //Timestamp int timestamp_index = 0; int timestamp_start = 0; @@ -1325,14 +1356,14 @@ public abstract class BinarySignature int cur_pos = array_start; int cur_br_start = 0; - + // write the /encodings byte range { int num_replaces = calcNumReps(iui.replaces); - int num_holes = num_replaces + 1 + 1; + int num_holes = num_replaces + 1 + 1; // +1 = the /encodings hole - // +1 = the /Cert + // +1 = the /Cert // +1 = the /Timestamp if (iui.timeStamper != null) { num_holes += 1; @@ -1376,7 +1407,7 @@ public abstract class BinarySignature iui.cert_start = cert_start; } - + // write the /Timestamp byte range if (iui.timeStamper != null) { StringInfo byte_range = new StringInfo(); @@ -1394,7 +1425,7 @@ public abstract class BinarySignature cur_br_start = timestamp_start + iui.timestamp_length; iui.timestamp_start = timestamp_start; - } + } // determine the /Data byte ranges if any List ifd = iui.invisible_field_definitions; @@ -1411,7 +1442,7 @@ public abstract class BinarySignature { StringInfo si = (StringInfo) iui.kz_list.get(0); si.string_start = hole_start; - + hole_start += si.string_length + 2; } @@ -1468,7 +1499,7 @@ public abstract class BinarySignature cur_pos += num_digits; cur_pos += 1; - + // update the Kennzeichnung byte ranges cur_pos = kz_start; for (int i = 0; i < iui.kz_list.size(); i++) @@ -1494,7 +1525,7 @@ public abstract class BinarySignature /** * Replaces the certificate placeholder with the certificate from the signed * Signature Object. - * + * * @param iui * The IncrementalUpdateInformation. * @throws PDFDocumentException @@ -1550,7 +1581,7 @@ public abstract class BinarySignature /** * Replaces the timestam placeholder with the timestamp from the signed * Signature Object. - * + * * @param iui * The IncrementalUpdateInformation. * @throws PDFDocumentException @@ -1558,27 +1589,27 @@ public abstract class BinarySignature public static void replaceTimestamp(IncrementalUpdateInformation iui) throws PDFDocumentException { String timestamp = iui.signed_signature_object.getSigTimeStamp(); - if (timestamp != null) { + if (timestamp != null) { byte[] escaped = Placeholder.escapePDFString(timestamp.getBytes()); if (escaped.length > iui.timestamp_length) { throw new PlaceholderException("timestamp", escaped.length - iui.timestamp_length); } - System.arraycopy(escaped, 0, iui.signed_pdf, iui.timestamp_start, escaped.length); + System.arraycopy(escaped, 0, iui.signed_pdf, iui.timestamp_start, escaped.length); } } - + /** * Replaces the placeholders with values from the signed SignatureObject. - * + * * @param iui * The IncrementalUpdateInformation. * @throws PDFDocumentException */ public static void replacePlaceholders(IncrementalUpdateInformation iui) throws PDFDocumentException { - final int lineBreakTolerance = getLineBreakTolerance(iui); - + final int lineBreakTolerance = getLineBreakTolerance(iui); + final byte[] signed_pdf = iui.signed_pdf; // int num_replaces = calcNumReps(iui.replaces); @@ -1661,7 +1692,7 @@ public abstract class BinarySignature * carried out. Accordingly to this number, entries in the dictionary are * created. *

- * + * * @param replaces * The ReplaceInfo list. * @return Returns the number of string replaces. @@ -1681,12 +1712,12 @@ public abstract class BinarySignature /** * Determines the List of ReplaceInfo objects of replaces in the content * stream regarding the given field definitions. - * + * *

* This method collects all variable String fields in a content stream and * orders them according to their start offset. *

- * + * * @param pdf * The PDF. * @param begin @@ -1760,7 +1791,7 @@ public abstract class BinarySignature /** * Determines the Kennzeichnug in the content stream. - * + * * @param pdf * The PDF. * @param begin @@ -1819,7 +1850,7 @@ public abstract class BinarySignature /** * Finds the index of the StringInfo within the StringInfo list that has the * given content (caption). - * + * * @param strings * The list of StringInfos. * @param caption @@ -1886,7 +1917,7 @@ public abstract class BinarySignature /** * Tells, if the given StringInfo contains only placeholder characters. - * + * * @param si * The StringInfo. * @param placeholder @@ -1935,7 +1966,7 @@ public abstract class BinarySignature /** * Finds the first string after and at the given index not being a placeholder * string. - * + * * @param strings * The list of StringInfos. * @param start @@ -1958,7 +1989,7 @@ public abstract class BinarySignature /** * Restores the given String to its placeholder. - * + * * @param pdf * The PDF. * @param si @@ -1978,7 +2009,7 @@ public abstract class BinarySignature /** * Reconstructs the replaces from the PDF and forms suitable value strings. - * + * * @param pdf * The PDF. * @param brevs @@ -2044,7 +2075,7 @@ public abstract class BinarySignature /** * Reads an unsigned integer number. - * + * * @param pdf * The PDF. * @param start_index @@ -2073,7 +2104,7 @@ public abstract class BinarySignature /** * Replaces a number by the new value. - * + * * @param pdf * The PDF. * @param start_index diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFPage.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFPage.java index 7de89d2..1a89b7b 100644 --- a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFPage.java +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFPage.java @@ -25,15 +25,19 @@ */ package at.knowcenter.wag.egov.egiz.pdf; +import java.awt.Rectangle; +import java.awt.geom.GeneralPath; import java.io.IOException; import java.util.List; import java.util.Map; +import org.apache.commons.lang.math.NumberUtils; import org.apache.log4j.Logger; import org.pdfbox.cos.COSName; import org.pdfbox.cos.COSStream; import org.pdfbox.pdmodel.PDPage; import org.pdfbox.pdmodel.PDResources; +import org.pdfbox.pdmodel.common.PDRectangle; import org.pdfbox.pdmodel.common.PDStream; import org.pdfbox.pdmodel.graphics.xobject.PDXObject; import org.pdfbox.pdmodel.graphics.xobject.PDXObjectForm; @@ -44,6 +48,21 @@ import org.pdfbox.util.TextPosition; import org.pdfbox.util.operator.OperatorProcessor; import at.knowcenter.wag.egov.egiz.cfg.ConfigLogger; +import at.knowcenter.wag.egov.egiz.pdf.operator.path.construction.ClosePath; +import at.knowcenter.wag.egov.egiz.pdf.operator.path.construction.CurveTo; +import at.knowcenter.wag.egov.egiz.pdf.operator.path.construction.CurveToReplicateFinalPoint; +import at.knowcenter.wag.egov.egiz.pdf.operator.path.construction.CurveToReplicateInitialPoint; +import at.knowcenter.wag.egov.egiz.pdf.operator.path.construction.LineTo; +import at.knowcenter.wag.egov.egiz.pdf.operator.path.construction.MoveTo; +import at.knowcenter.wag.egov.egiz.pdf.operator.path.painting.CloseAndStrokePath; +import at.knowcenter.wag.egov.egiz.pdf.operator.path.painting.CloseFillEvenOddAndStrokePath; +import at.knowcenter.wag.egov.egiz.pdf.operator.path.painting.CloseFillNonZeroAndStrokePath; +import at.knowcenter.wag.egov.egiz.pdf.operator.path.painting.EndPath; +import at.knowcenter.wag.egov.egiz.pdf.operator.path.painting.FillEvenOddAndStrokePath; +import at.knowcenter.wag.egov.egiz.pdf.operator.path.painting.FillNonZeroAndStrokePath; +import at.knowcenter.wag.egov.egiz.pdf.operator.path.painting.FillPathEvenOddRule; +import at.knowcenter.wag.egov.egiz.pdf.operator.path.painting.FillPathNonZeroWindingNumberRule; +import at.knowcenter.wag.egov.egiz.pdf.operator.path.painting.StrokePath; /** * PDFPage is an inner class that is used to calculate the page length of a PDF @@ -52,7 +71,7 @@ import at.knowcenter.wag.egov.egiz.cfg.ConfigLogger; * This method is called when processing the FileStream. By calling the method * {@link org.pdfbox.util.PDFStreamEngine#processStream(org.pdfbox.pdmodel.PDPage, org.pdfbox.pdmodel.PDResources, org.pdfbox.cos.COSStream)} * the implemented method showCharacter is called. - * + * * @author wlackner * @see PDFTextStripper */ @@ -67,41 +86,167 @@ public class PDFPage extends PDFTextStripper * The maximum (lowest) y position of a character. */ protected float max_character_ypos = Float.NEGATIVE_INFINITY; - + /** * The maximum (lowest y position of an image. */ protected float max_image_ypos = Float.NEGATIVE_INFINITY; - + /** * The effective page height. */ protected float effectivePageHeight; - + + /** + * The path currently being constructed. + */ + private GeneralPath currentPath = new GeneralPath(); + + /** + * The lowest position of a drawn path (originating from top). + */ + private float maxPathRelatedYPositionFromTop = Float.NEGATIVE_INFINITY; + /** * Constructor. - * + * * @param effectivePageHeight The height of the page to be evaluated. PDF elements outside this height will not be considered. - * + * * @throws IOException */ public PDFPage(float effectivePageHeight) throws IOException { super(); - + this.effectivePageHeight = effectivePageHeight; - + OperatorProcessor newInvoke = new MyInvoke(); newInvoke.setContext(this); operators.put("Do", newInvoke); + + registerCustomPathOperators(); } + /** + * Registers operators responsible for path construction and painting in order to fix auto positioning on pages with + * path elements. + * + * @author Datentechnik Innovation GmbH + */ + @SuppressWarnings("unchecked") + private void registerCustomPathOperators() { + + // *** path construction + + operators.put("m", new MoveTo(this)); + operators.put("l", new LineTo(this)); + operators.put("c", new CurveTo(this)); + operators.put("y", new CurveToReplicateFinalPoint(this)); + operators.put("v", new CurveToReplicateInitialPoint(this)); + operators.put("h", new ClosePath(this)); + + // *** path painting + + // "S": stroke path + operators.put("S", new StrokePath(this)); + operators.put("s", new CloseAndStrokePath(this)); + operators.put("f", new FillPathNonZeroWindingNumberRule(this)); + operators.put("F", new FillPathNonZeroWindingNumberRule(this)); + operators.put("f*", new FillPathEvenOddRule(this)); + operators.put("b", new CloseFillNonZeroAndStrokePath(this)); + operators.put("B", new FillNonZeroAndStrokePath(this)); + operators.put("b*", new CloseFillEvenOddAndStrokePath(this)); + operators.put("B*", new FillEvenOddAndStrokePath(this)); + operators.put("n", new EndPath(this)); + + // Note: The graphic context (org.pdfbox.pdmodel.graphics.PDGraphicsState) of the underlying pdfbox library does + // not yet support clipping. This prevents feasible usage of clipping operators (W, W*). +// operators.put("W", new ...(this)); +// operators.put("W*", new ...(this)); + + } + + /** + * Returns the path currently being constructed. + * + * @return The path currently being constructed. + */ + public GeneralPath getCurrentPath() { + return currentPath; + } + + /** + * Sets the current path. + * @param currentPath The new current path. + */ + public void setCurrentPath(GeneralPath currentPath) { + this.currentPath = currentPath; + } + + /** + * Registers a rectangle that bounds the path currently being drawn. + * + * @param bounds + * A rectangle depicting the bounds (coordinates originating from bottom left). + * @author Datentechnik Innovation GmbH + */ + public void registerPathBounds(Rectangle bounds) { + if (!bounds.isEmpty()) { + logger_.trace("Registering path bounds: " + bounds); + + // vertical start of rectangle (counting from top of page) + float upperBoundYPositionFromTop; + + // vertical end of rectangle (counting from top of page) + // this depicts the current end of path-related page content + float lowerBoundYPositionFromTop; + + PDRectangle boundaryBox = page.findMediaBox(); + float pageHeight; + + switch (page.findRotation()) { + case 90: // CW + pageHeight = boundaryBox.getWidth(); + upperBoundYPositionFromTop = (float) bounds.getMinX(); + lowerBoundYPositionFromTop = (float) bounds.getMaxX(); + break; + case 180: + pageHeight = boundaryBox.getHeight(); + upperBoundYPositionFromTop = (float) bounds.getMinY(); + lowerBoundYPositionFromTop = (float) bounds.getMaxY(); + break; + case 270: // CCW + pageHeight = boundaryBox.getWidth(); + upperBoundYPositionFromTop = pageHeight - (float) bounds.getMaxX(); + lowerBoundYPositionFromTop = pageHeight - (float) bounds.getMinX(); + break; + default: + pageHeight = boundaryBox.getHeight(); + upperBoundYPositionFromTop = pageHeight - (float) bounds.getMaxY(); + lowerBoundYPositionFromTop = pageHeight - (float) bounds.getMinY(); + break; + } + + // new maximum ? + if (lowerBoundYPositionFromTop > maxPathRelatedYPositionFromTop) { + // Is the rectangle (at least partly) located above the footer line? + // (effective page height := page height - footer line) + if (upperBoundYPositionFromTop <= effectivePageHeight) { + // yes: update current end of path-related page content + maxPathRelatedYPositionFromTop = lowerBoundYPositionFromTop; + logger_.trace("New max path related y position (from top): " + maxPathRelatedYPositionFromTop); + } else { + // no: rectangle is fully located below the footer line -> ignore + logger_.trace("Ignoring path bound below the footer line."); + } + } + } + } protected void processOperator(PDFOperator operator, List arguments) throws IOException { - //logger_.debug("operator = " + operator); - - super.processOperator(operator, arguments); +// logger_.debug("operator = " + operator); + super.processOperator(operator, arguments); } // exthex @@ -111,7 +256,7 @@ public class PDFPage extends PDFTextStripper * is used to calculate the latest position of a text in the page. Sorry for * this missinterpretation of the method, but it is the only way to do this * (provided by PDFBox)!!! - * + * * @param text * the character to be displayed -> calculate there y position. */ @@ -119,7 +264,7 @@ public class PDFPage extends PDFTextStripper { float current_y = text.getY(); final String character = text.getCharacter(); - + int pageRotation = page.findRotation(); //logger_.debug("PageRotation = " + pageRotation); if (pageRotation == 0) @@ -146,7 +291,7 @@ public class PDFPage extends PDFTextStripper //logger_.debug("character is below footer_line. footer_line = " + this.footer_line + ", text.character=" + character + ", y=" + current_y); return; } - + // store ypos of the char if it is not empty if (!character.equals(" ") && current_y > this.max_character_ypos) { @@ -160,26 +305,18 @@ public class PDFPage extends PDFTextStripper // logger_.debug(new String(string)); // } - /** - * Returns the calculated page length. - * - * @return the max page length value - */ - public float getMaxPageLength() - { - float max_ypos = Float.NEGATIVE_INFINITY; - - if (this.max_character_ypos > this.max_image_ypos) - { - max_ypos = this.max_character_ypos; - } - else - { - max_ypos = this.max_image_ypos; - } - - return max_ypos; - } + /** + * Returns the calculated page length. + * + * @return the max page length value + */ + public float getMaxPageLength() { + if (logger_.isDebugEnabled()) { + logger_.debug("Determining page content length: text=" + max_character_ypos + ", image=" + max_image_ypos + + ", path=" + maxPathRelatedYPositionFromTop); + } + return NumberUtils.max(max_character_ypos, max_image_ypos, maxPathRelatedYPositionFromTop); + } public class MyInvoke extends OperatorProcessor { @@ -192,26 +329,26 @@ public class PDFPage extends PDFTextStripper Map xobjects = context.getXObjects(); PDXObject xobject = (PDXObject) xobjects.get(name.getName()); - + PDStream stream = xobject.getPDStream(); COSStream cos_stream = stream.getStream(); - + COSName subtype = (COSName) cos_stream.getDictionaryObject(COSName.SUBTYPE); if (subtype.equals(COSName.IMAGE)) { logger_.debug("XObject Image"); - + Matrix ctm = context.getGraphicsState().getCurrentTransformationMatrix(); logger_.debug("ctm = " + ctm); - + Pos [] coordinates = new Pos [] { new Pos(0, 0, 1), new Pos(1, 0, 1), new Pos(0, 1, 1), new Pos(1, 1, 1) }; - + Pos [] transformed_coordinates = transtormCoordinates(coordinates, ctm); - + /********************************************************** * pdf-as fix: * calculating min and max point of an image to look where @@ -219,10 +356,10 @@ public class PDFPage extends PDFTextStripper * fix solves problems with footer and images and * placement of the signature in an image only pdf document **********************************************************/ - + float actual_lowest_point = Float.NaN; float actual_starting_point = Float.NaN; - + int pageRotation = page.findRotation(); logger_.debug("PageRotation = " + pageRotation); if (pageRotation == 0) @@ -231,7 +368,7 @@ public class PDFPage extends PDFTextStripper logger_.debug("min_y = " + min_y); float page_height = page.findMediaBox().getHeight(); logger_.debug("page_height = " + page_height); - + actual_lowest_point = page_height - min_y; actual_starting_point = page_height - findMaxY(transformed_coordinates); } @@ -243,7 +380,7 @@ public class PDFPage extends PDFTextStripper logger_.debug("page_width = " + page_width); actual_lowest_point = max_x; - actual_starting_point = findMinX(transformed_coordinates); + actual_starting_point = findMinX(transformed_coordinates); } if (pageRotation == 180) { @@ -257,17 +394,17 @@ public class PDFPage extends PDFTextStripper { float min_x = findMinX(transformed_coordinates); logger_.debug("min_x = " + min_x); - + float page_width = page.findMediaBox().getWidth(); logger_.debug("page_width = " + page_width); - + actual_lowest_point = page_width - min_x; - actual_starting_point = page_width - findMaxX(transformed_coordinates); + actual_starting_point = page_width - findMaxX(transformed_coordinates); } - + logger_.debug("actual_lowest_point = " + actual_lowest_point); - + if (actual_lowest_point > PDFPage.this.effectivePageHeight && actual_starting_point > PDFPage.this.effectivePageHeight) { logger_.debug("image is below footer_line"); @@ -278,7 +415,7 @@ public class PDFPage extends PDFTextStripper { PDFPage.this.max_image_ypos = actual_lowest_point; } - + return; } @@ -297,7 +434,7 @@ public class PDFPage extends PDFTextStripper } } } - + public static Pos [] transtormCoordinates (Pos [] coordinates, Matrix m) { Pos [] transformed = new Pos [coordinates.length]; @@ -307,18 +444,18 @@ public class PDFPage extends PDFTextStripper } return transformed; } - + public static Pos transtormCoordinate (Pos pos, Matrix m) { Pos transformed = new Pos(); transformed.x = pos.x * m.getValue(0, 0) + pos.y * m.getValue(1, 0) + pos.z * m.getValue(2, 0); transformed.y = pos.x * m.getValue(0, 1) + pos.y * m.getValue(1, 1) + pos.z * m.getValue(2, 1); transformed.z = pos.x * m.getValue(0, 2) + pos.y * m.getValue(1, 2) + pos.z * m.getValue(2, 2); - + logger_.debug(" transformed " + pos + " --> " + transformed); return transformed; } - + public static float findMinY (Pos [] coordinates) { float min = Float.POSITIVE_INFINITY; @@ -331,7 +468,7 @@ public class PDFPage extends PDFTextStripper } return min; } - + public static float findMaxY(Pos[] coordinates) { float max = 0; for (int i = 0; i < coordinates.length; i++) { @@ -341,7 +478,7 @@ public class PDFPage extends PDFTextStripper } return max; } - + public static float findMaxX (Pos [] coordinates) { float max = Float.NEGATIVE_INFINITY; diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFSignatureObjectIText.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFSignatureObjectIText.java index a8a150e..3b9909f 100644 --- a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFSignatureObjectIText.java +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFSignatureObjectIText.java @@ -35,6 +35,7 @@ import org.apache.log4j.Level; import org.apache.log4j.Logger; import at.gv.egiz.pdfas.exceptions.ErrorCode; +import at.gv.egiz.pdfas.utils.PDFASUtils; import at.knowcenter.wag.egov.egiz.cfg.ConfigLogger; import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; import at.knowcenter.wag.egov.egiz.exceptions.PDFDocumentException; @@ -59,7 +60,7 @@ import com.lowagie.text.pdf.SubsetLocal; * This class is the IText implementation of the PDFSignatureObject interface. * The class takes an abstract definition of a signature object and convert them * into a pdf table that is used to sign a pdf document. - * + * * @author wlackner * @see at.knowcenter.wag.egov.egiz.sig.SignatureObject * @see at.knowcenter.wag.egov.egiz.table.Table @@ -76,8 +77,6 @@ public class PDFSignatureObjectIText implements PDFSignatureObject // Also fixed a minor bug which prevented proper style inheritment (Bug Nr. #534). // 04.11.2010 changed by exthex - allow setting separate hAlign and vAlign for image cells analog to value cells. - private static final String SIG_PDFA1_B_VALID = "SIG_PDFA1B_VALID"; - /** * The default font definition */ @@ -116,7 +115,7 @@ public class PDFSignatureObjectIText implements PDFSignatureObject /** * The empty constructor. It loads the ui definitions from signature tables * and init the align map. - * + * * @throws PDFDocumentException */ public PDFSignatureObjectIText() throws PDFDocumentException @@ -127,7 +126,7 @@ public class PDFSignatureObjectIText implements PDFSignatureObject /** * load the class settings - * + * * @throws PDFDocumentException * @see SettingsReader */ @@ -174,7 +173,7 @@ public class PDFSignatureObjectIText implements PDFSignatureObject /** * Set the abstract signature definition. - * + * * @param signatorObject * the abstract signator object * @see at.knowcenter.wag.egov.egiz.pdf.PDFSignatureObject#setSignatorObject(at.knowcenter.wag.egov.egiz.sig.SignatureObject) @@ -186,7 +185,7 @@ public class PDFSignatureObjectIText implements PDFSignatureObject /** * This method maps the table cell definitions to the pdfCell element. - * + * * @param pdfCell * the pdf cell to be styled * @param cellStyle @@ -226,7 +225,7 @@ public class PDFSignatureObjectIText implements PDFSignatureObject align = ((Integer) alignMap_.get(cellStyle.getVAlign())).intValue(); if (align != -1) pdfCell.setVerticalAlignment(align); - + align = -1; if (type == Entry.TYPE_VALUE && cellStyle.getValueHAlign() != null) align = ((Integer) alignMap_.get(cellStyle.getValueHAlign())).intValue(); @@ -242,7 +241,7 @@ public class PDFSignatureObjectIText implements PDFSignatureObject /** * This method maps the cell font definition to the iText Font Object - * + * * @param fontString * @return the corresponding iText Font Object * @see com.lowagie.text.Font @@ -277,12 +276,12 @@ public class PDFSignatureObjectIText implements PDFSignatureObject int face = ((Integer) font_face).intValue(); float height = Float.parseFloat(font_arr[1]); int weight = ((Integer) font_weight).intValue(); - + font = new Font(face, height, weight); fontMap_.put(fontString, font); return font; } - + /** * Creates a custom * @param fontString @@ -305,15 +304,15 @@ public class PDFSignatureObjectIText implements PDFSignatureObject } } logger_.debug("TrueType Font detected:"+fontName +" ("+fontSize+")"); - + try { Font font = (Font) fontMap_.get(fontString); - + if (font == null) { logger_.debug("Font \"" + fontString + "\" not in cache. Instantiating font."); String fontPath = SettingsReader.RESOURCES_PATH + "fonts" + File.separator + fontName; logger_.debug("Instantiating \"" + fontPath + "\"."); - + font = new Font(BaseFont.createFont(fontPath, BaseFont.WINANSI, true), fontSize); fontMap_.put(fontString, font); } @@ -334,7 +333,7 @@ public class PDFSignatureObjectIText implements PDFSignatureObject *
  • images
  • *
  • tables
  • * - * + * * @param abstractCell * the abstract cell definition * @return the new redererd pdf table cell @@ -345,27 +344,8 @@ public class PDFSignatureObjectIText implements PDFSignatureObject */ private PdfPCell renderCell(Entry abstractCell) throws PDFDocumentException { - boolean pdfaValid =false; - try - { - String profileid = sigObject_.getSignatureTypeDefinition().getType(); - String pdfa = SettingsReader.getInstance().getSetting("sig_obj." +profileid+".key."+SIG_PDFA1_B_VALID, "default."+SIG_PDFA1_B_VALID, "false"); - pdfaValid= "true".equalsIgnoreCase(pdfa); - -// exthex test - //SubsetLocal.set(!pdfaValid); - -// boolean forceSubset = true; // get this from config, default to false - //String - - //SubsetLocal.set(true); // exthex - - logger_.trace("Sign PDF/A compliant:"+pdfa); - } catch (SettingsException e1) - { - logger_.error(e1); - } - + boolean pdfaValid = PDFASUtils.isPdfAEnabled(sigObject_.getSignatureTypeDefinition().getType()); + PdfPCell pdf_cell = null; Style cell_style = abstractCell.getStyle(); boolean isValue = true; @@ -384,7 +364,7 @@ public class PDFSignatureObjectIText implements PDFSignatureObject { font_string = cell_style.getValueFont(); } - + logger_.trace("using cell font: "+font_string); Font cell_font; @@ -402,7 +382,7 @@ public class PDFSignatureObjectIText implements PDFSignatureObject } // exthex if (pdfaValid && abstractCell.getType() == Entry.TYPE_VALUE) { - SubsetLocal.addNonSubsetFont(cell_font.getBaseFont()); + SubsetLocal.addNonSubsetFont(cell_font.getBaseFont()); } Phrase text_phrase = new Phrase(text, cell_font); pdf_cell = new PdfPCell(text_phrase); @@ -429,9 +409,9 @@ public class PDFSignatureObjectIText implements PDFSignatureObject } Image image = Image.getInstance(img_file.getCanonicalPath()); logger_.debug("Using image file \"" + img_file.getCanonicalPath() + "\"."); - + image.scaleToFit(80.0f, 80.0f); - boolean fit = true; + boolean fit = true; Style.ImageScaleToFit istf = cell_style.getImageScaleToFit(); if (istf != null) { @@ -490,7 +470,7 @@ public class PDFSignatureObjectIText implements PDFSignatureObject * This method visualize an abstract table into a corresponding pdf table. The * new pdf table is redered and get the style information from the abstract * cell. - * + * * @param abstractTable * the abstract table definition * @return the new redererd pdf table cell @@ -558,7 +538,7 @@ public class PDFSignatureObjectIText implements PDFSignatureObject /** * This method creates the pdf table object. It takes the abstract table * definition from the signature object and render the abstract table. - * + * * @param sigObject * the signature object, the base for the abstract table definition * @return R @@ -587,7 +567,7 @@ public class PDFSignatureObjectIText implements PDFSignatureObject /** * Converts the current abstract signature object in a pdf signature object * implementation - * + * * @return the converted pdf signature object * @see at.knowcenter.wag.egov.egiz.pdf.PDFSignatureObject#getSignatureObject() */ @@ -603,11 +583,11 @@ public class PDFSignatureObjectIText implements PDFSignatureObject /** * Converts a abstract signature object in a pdf signature object * implementation - * + * * @param sigObject * the abstract signatorObject to convert * @return the converted pdf signature object - * @throws PDFDocumentException + * @throws PDFDocumentException * @see at.knowcenter.wag.egov.egiz.pdf.PDFSignatureObject#getSignatureObject(at.knowcenter.wag.egov.egiz.sig.SignatureObject) */ public Object getSignatureObject(SignatureObject sigObject) throws PDFDocumentException diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFUtilities.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFUtilities.java index bdc1078..b3adb71 100644 --- a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFUtilities.java +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/PDFUtilities.java @@ -32,6 +32,7 @@ import java.util.List; import at.gv.egiz.pdfas.framework.input.PdfDataSource; import at.gv.egiz.pdfas.impl.input.ByteArrayPdfDataSourceImpl; +import at.gv.egiz.pdfas.utils.PDFASUtils; import org.pdfbox.pdfparser.PDFParser; import org.pdfbox.pdmodel.PDDocument; @@ -44,7 +45,7 @@ import com.lowagie.text.DocumentException; /** * Contains useful helpers for accessing PDF documents. - * + * * @author wprinz * @author mruhmer */ @@ -52,12 +53,13 @@ public abstract class PDFUtilities { public static float calculatePageLength(final PdfDataSource pdfDataSource, int page, float effectivePageHeight, int pagerotation) throws PDFDocumentException { + PDDocument pdfDocument_ = null; try { //ByteArrayInputStream original_bais = new ByteArrayInputStream(pdf); //byte [] normalized_pdf = TextualSignature.normalizePDF(original_bais); byte [] normalized_pdf = TextualSignature.normalizePDF(pdfDataSource); - + // PERF: The whole PDF normalization process is costy ByteArrayInputStream bais = new ByteArrayInputStream(normalized_pdf); @@ -66,9 +68,8 @@ public abstract class PDFUtilities parser.setTempDirectory(temporary_dir); parser.parse(); - PDDocument pdfDocument_ = parser.getPDDocument(); + pdfDocument_ = parser.getPDDocument(); float page_length = calculatePageLength(pdfDocument_, page, effectivePageHeight, pagerotation); - pdfDocument_.close(); return page_length; } catch (IOException e) @@ -78,8 +79,10 @@ public abstract class PDFUtilities catch (DocumentException e) { throw new PDFDocumentException(201, e); + } finally { + PDFASUtils.closeQuietly(pdfDocument_); } - } + } public static float calculatePageLength(PDDocument document, int page, float effectivePageHeight, int pagerotation) throws IOException { //int last_page_id = document.getNumberOfPages(); @@ -87,8 +90,8 @@ public abstract class PDFUtilities PDPage pdpage = (PDPage) allPages.get(page); pdpage.setRotation(pagerotation); return calculatePageLength(pdpage, effectivePageHeight); - } - + } + /** * @deprecated * @param pdf @@ -98,12 +101,13 @@ public abstract class PDFUtilities */ public static float calculateLastPageLength(final byte[] pdf, float effectivePageHeight) throws PDFDocumentException { + PDDocument pdfDocument_ = null; try { //ByteArrayInputStream original_bais = new ByteArrayInputStream(pdf); PdfDataSource dataSource = new ByteArrayPdfDataSourceImpl(pdf); byte [] normalized_pdf = TextualSignature.normalizePDF(dataSource); - + ByteArrayInputStream bais = new ByteArrayInputStream(normalized_pdf); PDFParser parser = new PDFParser(bais); @@ -111,9 +115,8 @@ public abstract class PDFUtilities parser.setTempDirectory(temporary_dir); parser.parse(); - PDDocument pdfDocument_ = parser.getPDDocument(); + pdfDocument_ = parser.getPDDocument(); float last_page_length = calculateLastPageLength(pdfDocument_, effectivePageHeight); - pdfDocument_.close(); return last_page_length; } @@ -124,6 +127,8 @@ public abstract class PDFUtilities catch (DocumentException e) { throw new PDFDocumentException(201, e); + } finally { + PDFASUtils.closeQuietly(pdfDocument_); } } diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/StructContentHelper.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/StructContentHelper.java index a9c1c54..deb5fed 100644 --- a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/StructContentHelper.java +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/StructContentHelper.java @@ -173,9 +173,8 @@ public class StructContentHelper implements StructContentWriter { } } catch (Exception ex) { - logger.error("error", ex); - throw new PresentableException(ErrorCode.CANNOT_WRITE_PDF, - "error writing structured signature content", ex); + logger.warn("Unable to process structured document data. Going to write untagged signature block.", ex); + isTagged = false; } } @@ -471,16 +470,38 @@ public class StructContentHelper implements StructContentWriter { } } - private void checkTagging() { - PdfDictionary markDict = stamper.getReader().getCatalog().getAsDict(PdfName.MARKINFO); - if (markDict != null) { - isTagged = markDict.getAsBoolean(PdfName.MARKED).booleanValue(); - } - if (!isTagged) { - logger.debug("input document is not tagged. no structure/wai information is written"); - } - logger.debug("Input is tagged. Writing structure/WAI data."); - } + private void checkTagging() { + PdfDictionary markDict = stamper.getReader().getCatalog().getAsDict(PdfName.MARKINFO); + if (markDict != null) { + isTagged = markDict.getAsBoolean(PdfName.MARKED).booleanValue(); + } + if (!isTagged) { + logger.debug("Input document is not tagged. No structure data will be attached to signature block."); + } else { + logger.trace("Document claims to be tagged. Checking availability of structured tree root."); + PdfDictionary structTreeRoot; + if ((structTreeRoot = getStructTreeRoot()) == null) { + // document claimed to be tagged but document does not contain structural information + isTagged = false; + logger.debug("Document claims to be tagged structured tree root was not found."); + } else if (getParentTreeNums() == null) { + // document claimed to be tagged but document does not contain structural information + isTagged = false; + logger.debug("Document claims to be tagged but required information is missing."); + } else if (structTreeRoot.getDirectObject(PdfName.K) == null) { + // structured content + isTagged = false; + logger.debug("Document claims to be tagged but required information is missing."); + } else { + logger.debug("Input is tagged and required structure data seems to be available. Going to write structured signature block."); + } + if (!isTagged) { + logger.info("Unable to process structured document data. Going to write untagged signature block."); + } + } + } + + diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/TextualSignature.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/TextualSignature.java index 35a0768..3ce690b 100644 --- a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/TextualSignature.java +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/TextualSignature.java @@ -53,7 +53,7 @@ import com.lowagie.text.pdf.PdfWriter; /** * Contains helper function for textual signatures. - * + * * @author wprinz */ public class TextualSignature @@ -62,21 +62,22 @@ public class TextualSignature * The logger definition. */ private static final Logger logger_ = ConfigLogger.getLogger(TextualSignature.class); - + /** * Extracts the document text from a given pdf. - * + * * @param pdf_stream * The pdf_input stream. * @return Returns the extracted document text. - * @throws PDFDocumentException + * @throws PDFDocumentException * @throws TextExtractionException * Forwarded exception. */ - public static String extractTextTextual(PdfDataSource pdfDataSource, String encoding) throws PDFDocumentException + public static String extractTextTextual(PdfDataSource pdfDataSource, String encoding) throws PDFDocumentException { PerformanceCounters.textExtractions.increment(); - + PDDocument doc = null; + Document document = null; try { int first_page_rotation = 0; @@ -90,12 +91,8 @@ public class TextualSignature // byte[] bytes = normalizePDF(pdf_stream); - //iText - - byte [] pdf_data = pdfDataSource.getAsByteArray(); - PdfReader reader = new PdfReader(pdf_data); - PDFASUtils.checkReaderPermissions(reader); - //pdf_stream.close(); + + PdfReader reader = PDFASUtils.createPdfReaderCheckingPermissions(pdfDataSource); // PERF: PDF normalization needs byte array - this is costy ByteArrayOutputStream baos = new ByteArrayOutputStream(4096); @@ -108,7 +105,7 @@ public class TextualSignature // this method (although it works when a Table is appended)... very // fragile. - Document document = new Document(); + document = new Document(); PdfWriter writer = PdfWriter.getInstance(document, baos); document.open(); @@ -126,7 +123,7 @@ public class TextualSignature first_page_rotation = new_size_withrot.getRotation(); //logger_.info("iText first_page_rotation="+new_size_withrot.getRotation()); } - //logger_.info("iText set PageSize of page:"+page_num+" to: "+new_size_withrot); + //logger_.info("iText set PageSize of page:"+page_num+" to: "+new_size_withrot); //document.setPageSize(new_size); document.setPageSize(new_size_withrot); document.newPage(); @@ -163,15 +160,15 @@ public class TextualSignature //logger_.info("temporary_dir="+temporary_dir.getAbsolutePath()); parser.setTempDirectory(temporary_dir); parser.parse(); - - PDDocument doc = parser.getPDDocument(); + + doc = parser.getPDDocument(); //System.out.println("pdfBox.getNumberOfPages()"+doc.getNumberOfPages()); - + PDFTextStripper stripper = new PDFTextStripper(); stripper.setSortByPosition(false); stripper.setGetFirstPageRotationFromThis(true); stripper.setFirstPageRotation(first_page_rotation); - + // stripper.setStartPage(4); // stripper.setEndPage(4); logger_.debug("TextualSignator extractTextTextual: Begin stripping text"); @@ -182,8 +179,7 @@ public class TextualSignature throw new PDFDocumentException(ErrorCode.TEXT_EXTRACTION_EXCEPTION, "Unable to extract textual content.", e); } logger_.debug("TextualSignator extractTextTextual: Stripping text ended"); - - doc.close(); + //logger_.debug("TextualSignator extractTextTextual="+text); return text; @@ -199,39 +195,39 @@ public class TextualSignature catch (DocumentException e) { throw new PDFDocumentException(ErrorCode.DOCUMENT_CANNOT_BE_READ, e); + } finally { + PDFASUtils.closeQuietly(doc); + PDFASUtils.closeQuietly(document); } } - + /** * Normalizes a given binary PDF to a version PDFbox can handle correctly. - * + * *

    * PDFbox has serious problems with documents that use incremental updates or * XObject forms. Therefor use this to remove incremental updates and create a * streamlined document. *

    - * + * *

    * Note that this has nothing to do with text normalization. It just unifies * the PDF documents that are fed into PDFbox for text extraction and page * length determination. *

    - * + * * @param input_pdf * The input pdf to be normalized. * @return Returns the normalized pdf. * @throws IOException * @throws DocumentException - * @throws PDFDocumentException + * @throws PDFDocumentException */ public static byte[] normalizePDF(PdfDataSource pdfDataSource) throws IOException, DocumentException, PDFDocumentException { //iText - byte [] pdf_data = pdfDataSource.getAsByteArray(); - PdfReader reader = new PdfReader(pdf_data); - PDFASUtils.checkReaderPermissions(reader); - //input_pdf.close(); - + PdfReader reader = PDFASUtils.createPdfReaderCheckingPermissions(pdfDataSource); + // PERF: PDF Normalization needs byte array ByteArrayOutputStream baos = new ByteArrayOutputStream(); // For some reason the Reader -> ImportPage -> Writer mechanism produces diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/PathConstructionOperatorProcessor.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/PathConstructionOperatorProcessor.java new file mode 100644 index 0000000..143a6b6 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/PathConstructionOperatorProcessor.java @@ -0,0 +1,62 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * 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.knowcenter.wag.egov.egiz.pdf.operator.path; + +import java.awt.geom.Point2D; + +import org.pdfbox.util.operator.OperatorProcessor; + +import at.knowcenter.wag.egov.egiz.pdf.PDFPage; + +/** + * Provides functions for path construction operators. + * + * @see "PDF 1.7 specification, Section 8.5.2 'Path Construction Operators'" + * @author Datentechnik Innovation GmbH + * + */ +public abstract class PathConstructionOperatorProcessor extends OperatorProcessor { + + public PathConstructionOperatorProcessor(PDFPage context) { + setContext(context); + } + + /** + * Transforms the given point from user space coordinates to device space coordinates based on the current + * transition matrix. + * + * @param x + * The x axis value of the user space coordinates. + * @param y + * The y axis value of the user space coordinates. + * @return The transformed point. + */ + public Point2D transform(double x, double y) { + double[] position = { x, y }; + context.getGraphicsState().getCurrentTransformationMatrix().createAffineTransform() + .transform(position, 0, position, 0, 1); + return new Point2D.Double(position[0], position[1]); + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/PathPaintingOperatorProcessor.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/PathPaintingOperatorProcessor.java new file mode 100644 index 0000000..9a76f87 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/PathPaintingOperatorProcessor.java @@ -0,0 +1,43 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * 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.knowcenter.wag.egov.egiz.pdf.operator.path; + +import org.pdfbox.util.operator.OperatorProcessor; + +import at.knowcenter.wag.egov.egiz.pdf.PDFPage; + +/** + * Provides functions for path painting operators. + * + * @see "PDF 1.7 specification, Section 8.5.2 'Path Construction Operators'" + * @author Datentechnik Innovation GmbH + * + */ +public abstract class PathPaintingOperatorProcessor extends OperatorProcessor { + + public PathPaintingOperatorProcessor(PDFPage context) { + setContext(context); + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/construction/ClosePath.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/construction/ClosePath.java new file mode 100644 index 0000000..ea87887 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/construction/ClosePath.java @@ -0,0 +1,68 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * 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.knowcenter.wag.egov.egiz.pdf.operator.path.construction; + +import java.io.IOException; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.pdfbox.util.PDFOperator; + +import at.knowcenter.wag.egov.egiz.pdf.PDFPage; +import at.knowcenter.wag.egov.egiz.pdf.operator.path.PathConstructionOperatorProcessor; + +/** + * Close the current subpath by appending a straight line segment from the current point to the starting point of the + * subpath. If the current subpath is already closed, h shall donothing. This operator terminates the current subpath. + * Appending another segment to the current path shall begin a new subpath, even if the new segment begins at the + * endpoint reached by the h operation. + * + * @see "PDF 1.7 specification, Section 8.5.2 'Path Construction Operators'" + * @author PdfBox, modified by Datentechnik Innovation GmbH + */ +public class ClosePath extends PathConstructionOperatorProcessor { + + private Log log = LogFactory.getLog(getClass()); + + public ClosePath(PDFPage context) { + super(context); + } + + @Override + public void process(PDFOperator operator, List operands) throws IOException { + try { + PDFPage pdfPage = (PDFPage) context; + + pdfPage.getCurrentPath().closePath(); + + if (log.isTraceEnabled()) { + log.trace("Closing current path."); + } + } catch (Exception e) { + log.warn("Error processing operator 'h'.", e); + } + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/construction/CurveTo.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/construction/CurveTo.java new file mode 100644 index 0000000..a2fc8de --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/construction/CurveTo.java @@ -0,0 +1,85 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * 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.knowcenter.wag.egov.egiz.pdf.operator.path.construction; + +import java.awt.geom.Point2D; +import java.io.IOException; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.pdfbox.cos.COSNumber; +import org.pdfbox.util.PDFOperator; + +import at.knowcenter.wag.egov.egiz.pdf.PDFPage; +import at.knowcenter.wag.egov.egiz.pdf.operator.path.PathConstructionOperatorProcessor; + +/** + * Append a cubic Bezier curve to the current path. The curve shall extend from the current point to the point (x3, y3), + * using (x1, y1) and (x2, y2) as the Bezier control points (see 8.5.2.2, "Cubic Bezier Curves"). The new current point + * shall be (x3, y3). + * + * @see "PDF 1.7 specification, Section 8.5.2 'Path Construction Operators'" + * @author PdfBox, modified by Datentechnik Innovation GmbH + */ +public class CurveTo extends PathConstructionOperatorProcessor { + + private Log log = LogFactory.getLog(getClass()); + + public CurveTo(PDFPage context) { + super(context); + } + + @Override + public void process(PDFOperator operator, List operands) throws IOException { + try { + PDFPage pdfPage = (PDFPage) context; + + COSNumber x1 = (COSNumber) operands.get(0); + COSNumber y1 = (COSNumber) operands.get(1); + COSNumber x2 = (COSNumber) operands.get(2); + COSNumber y2 = (COSNumber) operands.get(3); + COSNumber x3 = (COSNumber) operands.get(4); + COSNumber y3 = (COSNumber) operands.get(5); + + Point2D p1 = transform(x1.doubleValue(), y1.doubleValue()); + Point2D p2 = transform(x2.doubleValue(), y2.doubleValue()); + Point2D p3 = transform(x3.doubleValue(), y3.doubleValue()); + + pdfPage.getCurrentPath().curveTo( + (float) p1.getX(), (float) p1.getY(), + (float) p2.getX(), (float) p2.getY(), + (float) p3.getX(), (float) p3.getY() + ); + + if (log.isTraceEnabled()) { + log.trace("Appending cubic Bezier curve with x1:" + p1.getX() + ",y1:" + p1.getY() + ", x2:" + + p2.getX() + ",y2:" + p2.getY() + ", x3:" + p3.getX() + ",y3:" + p3.getY()); + } + } catch (Exception e) { + log.warn("Error processing operator 'c'.", e); + } + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/construction/CurveToReplicateFinalPoint.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/construction/CurveToReplicateFinalPoint.java new file mode 100644 index 0000000..bb5c86c --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/construction/CurveToReplicateFinalPoint.java @@ -0,0 +1,82 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * 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.knowcenter.wag.egov.egiz.pdf.operator.path.construction; + +import java.awt.geom.Point2D; +import java.io.IOException; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.pdfbox.cos.COSNumber; +import org.pdfbox.util.PDFOperator; + +import at.knowcenter.wag.egov.egiz.pdf.PDFPage; +import at.knowcenter.wag.egov.egiz.pdf.operator.path.PathConstructionOperatorProcessor; + +/** + * Append a cubic Bezier curve to the current path. The curve shall extend from the current point to the point (x3, y3), + * using (x1, y1) and (x3, y3) as the Bezier control points (see 8.5.2.2, "Cubic Bezier Curves"). The new current point + * shall be (x3, y3). + * + * @see "PDF 1.7 specification, Section 8.5.2 'Path Construction Operators'" + * @author PdfBox, modified by Datentechnik Innovation GmbH + */ +public class CurveToReplicateFinalPoint extends PathConstructionOperatorProcessor { + + private Log log = LogFactory.getLog(getClass()); + + public CurveToReplicateFinalPoint(PDFPage context) { + super(context); + } + + @Override + public void process(PDFOperator operator, List operands) throws IOException { + try { + PDFPage pdfPage = (PDFPage) context; + + COSNumber x1 = (COSNumber) operands.get(0); + COSNumber y1 = (COSNumber) operands.get(1); + COSNumber x3 = (COSNumber) operands.get(2); + COSNumber y3 = (COSNumber) operands.get(3); + + Point2D p1 = transform(x1.doubleValue(), y1.doubleValue()); + Point2D p3 = transform(x3.doubleValue(), y3.doubleValue()); + + pdfPage.getCurrentPath().curveTo( + (float) p1.getX(), (float) p1.getY(), + (float) p3.getX(), (float) p3.getY(), + (float) p3.getX(), (float) p3.getY() + ); + + if (log.isTraceEnabled()) { + log.trace("Appending cubic Bezier curve with x1:" + p1.getX() + ",y1:" + p1.getY() + ", x3:" + + p3.getX() + ",y3:" + p3.getY()); + } + } catch (Exception e) { + log.warn("Error processing operator 'y'.", e); + } + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/construction/CurveToReplicateInitialPoint.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/construction/CurveToReplicateInitialPoint.java new file mode 100644 index 0000000..b35bcaf --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/construction/CurveToReplicateInitialPoint.java @@ -0,0 +1,84 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * 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.knowcenter.wag.egov.egiz.pdf.operator.path.construction; + +import java.awt.geom.Point2D; +import java.io.IOException; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.pdfbox.cos.COSNumber; +import org.pdfbox.util.PDFOperator; + +import at.knowcenter.wag.egov.egiz.pdf.PDFPage; +import at.knowcenter.wag.egov.egiz.pdf.operator.path.PathConstructionOperatorProcessor; + +/** + * Append a cubic Bezier curve to the current path. The curve shall extend from the current point to the point (x3, y3), + * using the current point and (x2, y2) as the Bezier control points (see 8.5.2.2, "Cubic Bezier Curves"). The new + * current point shall be (x3, y3). + * + * @see "PDF 1.7 specification, Section 8.5.2 'Path Construction Operators'" + * @author PdfBox, modified by Datentechnik Innovation GmbH + */ +public class CurveToReplicateInitialPoint extends PathConstructionOperatorProcessor { + + private Log log = LogFactory.getLog(getClass()); + + public CurveToReplicateInitialPoint(PDFPage context) { + super(context); + } + + @Override + public void process(PDFOperator operator, List operands) throws IOException { + try { + PDFPage pdfPage = (PDFPage) context; + + COSNumber x2 = (COSNumber) operands.get(0); + COSNumber y2 = (COSNumber) operands.get(1); + COSNumber x3 = (COSNumber) operands.get(2); + COSNumber y3 = (COSNumber) operands.get(3); + + Point2D currentPoint = pdfPage.getCurrentPath().getCurrentPoint(); + Point2D p2 = transform(x2.doubleValue(), y2.doubleValue()); + Point2D p3 = transform(x3.doubleValue(), y3.doubleValue()); + + pdfPage.getCurrentPath().curveTo( + (float)currentPoint.getX(), (float)currentPoint.getY(), + (float) p2.getX(), (float) p2.getY(), + (float) p3.getX(), (float) p3.getY() + ); + + if (log.isTraceEnabled()) { + log.trace("Appending cubic Bezier curve with x2:" + p2.getX() + ",y2:" + p2.getY() + ", x3:" + + p3.getX() + ",y3:" + p3.getY() + ", using current point x:" + currentPoint.getX() + ",y:" + + currentPoint.getY()); + } + } catch (Exception e) { + log.warn("Error processing operator 'v'.", e); + } + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/construction/LineTo.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/construction/LineTo.java new file mode 100644 index 0000000..ae5894d --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/construction/LineTo.java @@ -0,0 +1,71 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * 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.knowcenter.wag.egov.egiz.pdf.operator.path.construction; + +import java.awt.geom.Point2D; +import java.io.IOException; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.pdfbox.cos.COSNumber; +import org.pdfbox.util.PDFOperator; + +import at.knowcenter.wag.egov.egiz.pdf.PDFPage; +import at.knowcenter.wag.egov.egiz.pdf.operator.path.PathConstructionOperatorProcessor; + +/** + * Append a straight line segment from the current point to the point (x, y). The new current point shall be (x, y). + * + * @see "PDF 1.7 specification, Section 8.5.2 'Path Construction Operators'" + * @author PdfBox, modified by Datentechnik Innovation GmbH + */ +public class LineTo extends PathConstructionOperatorProcessor { + + private Log log = LogFactory.getLog(getClass()); + + public LineTo(PDFPage context) { + super(context); + } + + @Override + public void process(PDFOperator operator, List operands) throws IOException { + try { + PDFPage pdfPage = (PDFPage) context; + + COSNumber x = (COSNumber) operands.get(0); + COSNumber y = (COSNumber) operands.get(1); + Point2D p = transform(x.doubleValue(), y.doubleValue()); + + pdfPage.getCurrentPath().lineTo((float) p.getX(), (float) p.getY()); + + if (log.isTraceEnabled()) { + log.trace("Adding line to x:" + p.getX() + ",y:" + p.getY()); + } + } catch (Exception e) { + log.warn("Error processing operator 'l'.", e); + } + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/construction/MoveTo.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/construction/MoveTo.java new file mode 100644 index 0000000..b43de2e --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/construction/MoveTo.java @@ -0,0 +1,73 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * 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.knowcenter.wag.egov.egiz.pdf.operator.path.construction; + +import java.awt.geom.Point2D; +import java.io.IOException; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.pdfbox.cos.COSNumber; +import org.pdfbox.util.PDFOperator; + +import at.knowcenter.wag.egov.egiz.pdf.PDFPage; +import at.knowcenter.wag.egov.egiz.pdf.operator.path.PathConstructionOperatorProcessor; + +/** + * Begin a new subpath by moving the current point to coordinates (x, y), omitting any connecting line segment. If the + * previous path construction operator in the current path was also m, the new m overrides it; no vestige of the + * previous m operation remains in the path. + * + * @see "PDF 1.7 specification, Section 8.5.2 'Path Construction Operators'" + * @author PdfBox, modified by Datentechnik Innovation GmbH + */ +public class MoveTo extends PathConstructionOperatorProcessor { + + private Log log = LogFactory.getLog(getClass()); + + public MoveTo(PDFPage context) { + super(context); + } + + @Override + public void process(PDFOperator operator, List operands) throws IOException { + try { + PDFPage pdfPage = (PDFPage) context; + + COSNumber x = (COSNumber) operands.get(0); + COSNumber y = (COSNumber) operands.get(1); + Point2D p = transform(x.doubleValue(), y.doubleValue()); + + pdfPage.getCurrentPath().moveTo((float) p.getX(), (float) p.getY()); + + if (log.isTraceEnabled()) { + log.trace("Moving current path to x:" + p.getX() + ",y:" + p.getY()); + } + } catch (Exception e) { + log.warn("Error processing operator 'm'.", e); + } + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/CloseAndStrokePath.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/CloseAndStrokePath.java new file mode 100644 index 0000000..54f4af8 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/CloseAndStrokePath.java @@ -0,0 +1,59 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * 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.knowcenter.wag.egov.egiz.pdf.operator.path.painting; + +import java.io.IOException; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.pdfbox.util.PDFOperator; + +import at.knowcenter.wag.egov.egiz.pdf.PDFPage; +import at.knowcenter.wag.egov.egiz.pdf.operator.path.PathPaintingOperatorProcessor; + +/** + * Close and stroke the path. This operator shall have the same effect as the sequence h S. + * + * @see "PDF 1.7 specification, Section 8.5.3 'Path-Painting Operators'" + * @author PdfBox, modified by Datentechnik Innovation GmbH + */ +public class CloseAndStrokePath extends PathPaintingOperatorProcessor { + + private Log log = LogFactory.getLog(getClass()); + + public CloseAndStrokePath(PDFPage context) { + super(context); + } + + @Override + public void process(PDFOperator operator, List operands) throws IOException { + if (log.isTraceEnabled()) { + log.trace("Closing and stroking path."); + } + context.processOperator("h", operands); + context.processOperator("S", operands); + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/CloseFillEvenOddAndStrokePath.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/CloseFillEvenOddAndStrokePath.java new file mode 100644 index 0000000..6a84cf4 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/CloseFillEvenOddAndStrokePath.java @@ -0,0 +1,60 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * 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.knowcenter.wag.egov.egiz.pdf.operator.path.painting; + +import java.io.IOException; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.pdfbox.util.PDFOperator; + +import at.knowcenter.wag.egov.egiz.pdf.PDFPage; +import at.knowcenter.wag.egov.egiz.pdf.operator.path.PathPaintingOperatorProcessor; + +/** + * Close, fill, and then stroke the path, using the even-odd rule to determine the region to fill. This operator shall + * have the same effect as the sequence h B*. + * + * @see "PDF 1.7 specification, Section 8.5.3 'Path-Painting Operators'" + * @author PdfBox, modified by Datentechnik Innovation GmbH + */ +public class CloseFillEvenOddAndStrokePath extends PathPaintingOperatorProcessor { + + private Log log = LogFactory.getLog(getClass()); + + public CloseFillEvenOddAndStrokePath(PDFPage context) { + super(context); + } + + @Override + public void process(PDFOperator operator, List operands) throws IOException { + if (log.isTraceEnabled()) { + log.trace("Closing, filling (even odd rule) and stroking path."); + } + context.processOperator("h", operands); + context.processOperator("B*", operands); + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/CloseFillNonZeroAndStrokePath.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/CloseFillNonZeroAndStrokePath.java new file mode 100644 index 0000000..f8db567 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/CloseFillNonZeroAndStrokePath.java @@ -0,0 +1,60 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * 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.knowcenter.wag.egov.egiz.pdf.operator.path.painting; + +import java.io.IOException; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.pdfbox.util.PDFOperator; + +import at.knowcenter.wag.egov.egiz.pdf.PDFPage; +import at.knowcenter.wag.egov.egiz.pdf.operator.path.PathPaintingOperatorProcessor; + +/** + * Close, fill, and then stroke the path, using the nonzero winding number rule to determine the region to fill. This + * operator shall have the same effect as the sequence h B. + * + * @see "PDF 1.7 specification, Section 8.5.3 'Path-Painting Operators'" + * @author PdfBox, modified by Datentechnik Innovation GmbH + */ +public class CloseFillNonZeroAndStrokePath extends PathPaintingOperatorProcessor { + + private Log log = LogFactory.getLog(getClass()); + + public CloseFillNonZeroAndStrokePath(PDFPage context) { + super(context); + } + + @Override + public void process(PDFOperator operator, List operands) throws IOException { + if (log.isTraceEnabled()) { + log.trace("Closing, filling (non zero rule) and stroking path."); + } + context.processOperator("h", operands); + context.processOperator("B", operands); + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/EndPath.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/EndPath.java new file mode 100644 index 0000000..4448a1e --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/EndPath.java @@ -0,0 +1,68 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * 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.knowcenter.wag.egov.egiz.pdf.operator.path.painting; + +import java.io.IOException; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.pdfbox.util.PDFOperator; + +import at.knowcenter.wag.egov.egiz.pdf.PDFPage; +import at.knowcenter.wag.egov.egiz.pdf.operator.path.PathPaintingOperatorProcessor; + +/** + * End the path object without filling or stroking it. This operator shall be a path-painting no-op, used primarily for + * the side effect of changing the current clipping path. + * + * @see "PDF 1.7 specification, Section 8.5.3 'Path-Painting Operators'" + * @author PdfBox, modified by Datentechnik Innovation GmbH + */ +public class EndPath extends PathPaintingOperatorProcessor { + + private Log log = LogFactory.getLog(getClass()); + + public EndPath(PDFPage context) { + super(context); + } + + @Override + public void process(PDFOperator operator, List operands) throws IOException { + try { + PDFPage pdfPage = (PDFPage) context; + + log.debug("Ending path " + pdfPage.getCurrentPath()); + pdfPage.getCurrentPath().reset(); + + if (log.isTraceEnabled()) { + log.trace("End path without filling or stroking."); + } + + } catch (Exception e) { + log.warn("Error processing operator 'n'.", e); + } + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/FillEvenOddAndStrokePath.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/FillEvenOddAndStrokePath.java new file mode 100644 index 0000000..8a42dff --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/FillEvenOddAndStrokePath.java @@ -0,0 +1,72 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * 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.knowcenter.wag.egov.egiz.pdf.operator.path.painting; + +import java.awt.geom.GeneralPath; +import java.io.IOException; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.pdfbox.util.PDFOperator; + +import at.knowcenter.wag.egov.egiz.pdf.PDFPage; +import at.knowcenter.wag.egov.egiz.pdf.operator.path.PathPaintingOperatorProcessor; + +/** + * Fill and then stroke the path, using the even-odd rule to determine the region to fill. This operator shall produce + * the same result as B, except that the path is filled as if with f* instead of + * f. + * + * @see "PDF 1.7 specification, Section 8.5.3 'Path-Painting Operators'" + * @author PdfBox, modified by Datentechnik Innovation GmbH + */ +public class FillEvenOddAndStrokePath extends PathPaintingOperatorProcessor { + + private Log log = LogFactory.getLog(getClass()); + + public FillEvenOddAndStrokePath(PDFPage context) { + super(context); + } + + @Override + public void process(PDFOperator operator, List operands) throws IOException { + try { + PDFPage pdfPage = (PDFPage) context; + + if (log.isTraceEnabled()) { + log.trace("Filling (even odd rule) and stroking path."); + } + + GeneralPath currentPath = (GeneralPath) pdfPage.getCurrentPath().clone(); + context.processOperator("f*", operands); + pdfPage.setCurrentPath(currentPath); + context.processOperator("S", operands); + + } catch (Exception e) { + log.warn("Error processing operator 'B*'.", e); + } + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/FillNonZeroAndStrokePath.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/FillNonZeroAndStrokePath.java new file mode 100644 index 0000000..96025ed --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/FillNonZeroAndStrokePath.java @@ -0,0 +1,72 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * 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.knowcenter.wag.egov.egiz.pdf.operator.path.painting; + +import java.awt.geom.GeneralPath; +import java.io.IOException; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.pdfbox.util.PDFOperator; + +import at.knowcenter.wag.egov.egiz.pdf.PDFPage; +import at.knowcenter.wag.egov.egiz.pdf.operator.path.PathPaintingOperatorProcessor; + +/** + * Fill and then stroke the path, using the nonzero winding number rule to determine the region to fill. This operator + * shall produce the same result as constructing two identical path objects, painting the first with f and + * the second with S. + * + * @see "PDF 1.7 specification, Section 8.5.3 'Path-Painting Operators'" + * @author PdfBox, modified by Datentechnik Innovation GmbH + */ +public class FillNonZeroAndStrokePath extends PathPaintingOperatorProcessor { + + private Log log = LogFactory.getLog(getClass()); + + public FillNonZeroAndStrokePath(PDFPage context) { + super(context); + } + + @Override + public void process(PDFOperator operator, List operands) throws IOException { + try { + PDFPage pdfPage = (PDFPage) context; + + if (log.isTraceEnabled()) { + log.trace("Filling (non zero rule) and stroking path."); + } + + GeneralPath currentPath = (GeneralPath) pdfPage.getCurrentPath().clone(); + context.processOperator("f", operands); + pdfPage.setCurrentPath(currentPath); + context.processOperator("S", operands); + + } catch (Exception e) { + log.warn("Error processing operator 'B'.", e); + } + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/FillPathEvenOddRule.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/FillPathEvenOddRule.java new file mode 100644 index 0000000..c6417ea --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/FillPathEvenOddRule.java @@ -0,0 +1,71 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * 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.knowcenter.wag.egov.egiz.pdf.operator.path.painting; + +import java.awt.Rectangle; +import java.io.IOException; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.pdfbox.util.PDFOperator; + +import at.knowcenter.wag.egov.egiz.pdf.PDFPage; +import at.knowcenter.wag.egov.egiz.pdf.operator.path.PathPaintingOperatorProcessor; + +/** + * Fill the path, using the even-odd rule to determine the region to fill. + * + * @see "PDF 1.7 specification, Section 8.5.3 'Path-Painting Operators'" + * @author PdfBox, modified by Datentechnik Innovation GmbH + */ +public class FillPathEvenOddRule extends PathPaintingOperatorProcessor { + + private Log log = LogFactory.getLog(getClass()); + + public FillPathEvenOddRule(PDFPage context) { + super(context); + } + + @Override + public void process(PDFOperator operator, List operands) throws IOException { + try { + PDFPage pdfPage = (PDFPage) context; + + pdfPage.getCurrentPath().setWindingRule(java.awt.geom.GeneralPath.WIND_EVEN_ODD); + Rectangle bounds = pdfPage.getCurrentPath().getBounds(); + pdfPage.getCurrentPath().reset(); + + if (log.isTraceEnabled()) { + log.trace("Filling path, using even-odd rule."); + } + + pdfPage.registerPathBounds(bounds); + + } catch (Exception e) { + log.warn("Error processing operator 'f*'.", e); + } + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/FillPathNonZeroWindingNumberRule.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/FillPathNonZeroWindingNumberRule.java new file mode 100644 index 0000000..b350009 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/FillPathNonZeroWindingNumberRule.java @@ -0,0 +1,72 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * 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.knowcenter.wag.egov.egiz.pdf.operator.path.painting; + +import java.awt.Rectangle; +import java.io.IOException; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.pdfbox.util.PDFOperator; + +import at.knowcenter.wag.egov.egiz.pdf.PDFPage; +import at.knowcenter.wag.egov.egiz.pdf.operator.path.PathPaintingOperatorProcessor; + +/** + * Fill the path, using the nonzero winding number rule to determine the region to fill. Any subpaths that are open + * shall be implicitly closed before being filled. + * + * @see "PDF 1.7 specification, Section 8.5.3 'Path-Painting Operators'" + * @author PdfBox, modified by Datentechnik Innovation GmbH + */ +public class FillPathNonZeroWindingNumberRule extends PathPaintingOperatorProcessor { + + private Log log = LogFactory.getLog(getClass()); + + public FillPathNonZeroWindingNumberRule(PDFPage context) { + super(context); + } + + @Override + public void process(PDFOperator operator, List operands) throws IOException { + try { + PDFPage pdfPage = (PDFPage) context; + + pdfPage.getCurrentPath().setWindingRule(java.awt.geom.GeneralPath.WIND_NON_ZERO); + Rectangle bounds = pdfPage.getCurrentPath().getBounds(); + pdfPage.getCurrentPath().reset(); + + if (log.isTraceEnabled()) { + log.trace("Filling path, using nonzero winding number rule."); + } + + pdfPage.registerPathBounds(bounds); + + } catch (Exception e) { + log.warn("Error processing operator 'f/F'.", e); + } + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/StrokePath.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/StrokePath.java new file mode 100644 index 0000000..9dfce7e --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/pdf/operator/path/painting/StrokePath.java @@ -0,0 +1,70 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * 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.knowcenter.wag.egov.egiz.pdf.operator.path.painting; + +import java.awt.Rectangle; +import java.io.IOException; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.pdfbox.util.PDFOperator; + +import at.knowcenter.wag.egov.egiz.pdf.PDFPage; +import at.knowcenter.wag.egov.egiz.pdf.operator.path.PathPaintingOperatorProcessor; + +/** + * Strokes the path. + * + * @see "PDF 1.7 specification, Section 8.5.3 'Path-Painting Operators'" + * @author PdfBox, modified by Datentechnik Innovation GmbH + */ +public class StrokePath extends PathPaintingOperatorProcessor { + + private Log log = LogFactory.getLog(getClass()); + + public StrokePath(PDFPage context) { + super(context); + } + + @Override + public void process(PDFOperator operator, List operands) throws IOException { + try { + PDFPage pdfPage = (PDFPage) context; + + Rectangle bounds = pdfPage.getCurrentPath().getBounds(); + pdfPage.getCurrentPath().reset(); + + if (log.isTraceEnabled()) { + log.trace("Stroking path."); + } + + pdfPage.registerPathBounds(bounds); + + } catch (Exception e) { + log.warn("Error processing operator 'S'.", e); + } + } + +} -- cgit v1.2.3