From 6d7df4a683bb07ec4cfbba1fec73b2779cd87557 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Lehmk=C3=BChler?= Date: Mon, 14 Mar 2016 16:54:25 +0000 Subject: [PATCH 0001/2182] [maven-release-plugin] copy for branch 2.0 git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1734961 13f79535-47bb-0310-9956-ffa450edef68 From 869dec2473f2641c795b6c7ea7e9bb5947c98bb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Lehmk=C3=BChler?= Date: Mon, 14 Mar 2016 17:09:06 +0000 Subject: [PATCH 0002/2182] prepare 2.0.0 release git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1734967 13f79535-47bb-0310-9956-ffa450edef68 --- RELEASE-NOTES.txt | 59 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 54 insertions(+), 5 deletions(-) diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt index b756fe0379e..9cd461fa045 100644 --- a/RELEASE-NOTES.txt +++ b/RELEASE-NOTES.txt @@ -5,10 +5,8 @@ Introduction The Apache PDFBox library is an open source Java tool for working with PDF documents. -This is the third release candidate for the upcoming major release 2.0.0 of PDFBox. -This release contains a lot of improvements, fixes and refactorings. The API is -supposed to be stable, but we can't guarantee that there won't be any last changes -to it before providing the final release candidate. +This is the long awaited final release of PDFBox 2.0.0. It contains a lot of improvements, +fixes and refactorings. For more details on these changes and all the other fixes and improvements included in this release, please refer to the following issues on the @@ -58,6 +56,8 @@ Sub-task [PDFBOX-3127] - Text with vertical font not extracted correctly [PDFBOX-3129] - NullPointerException in PDFStreamEngine.showText() [PDFBOX-3186] - Parsing fails when XRef stream object is 1 byte later +[PDFBOX-3208] - The trailer rebuild mechnism doesn't work +[PDFBOX-3264] - One 32kb truncated file causes OOM in 2.0.0-trunk Bug @@ -102,12 +102,14 @@ Bug [PDFBOX-728] - Text extracted from a TeX-created PDF file comes in some form of hex encoding [PDFBOX-778] - OutOfMemory when extracting text from pdf [PDFBOX-785] - Spliting a PDF creates unnecessarily large files +[PDFBOX-816] - 1.2.1 - PDFTextStripper* uses different Y values when cropbox has non-zero Y: not so for X coordinates. [PDFBOX-823] - NullPointerException in DateConverter.toISO8601(DateConverter.java:221) [PDFBOX-833] - Wrong encoding with Type1C font when specific encoding is defined [PDFBOX-837] - Wrong RevisionNumber when disabling all permissions and using 128bit encryption [PDFBOX-877] - processOperator breaks contract - never throws IOException [PDFBOX-904] - Potential issue with COSString and UTF-16-encoded Strings. [PDFBOX-905] - NullPointerException when writing pdf to image +[PDFBOX-908] - Gracefull handle corrupt PDFs [PDFBOX-923] - pdf gets messed up when updated with xfdf data [PDFBOX-924] - Image not getting rendered correctly.. [PDFBOX-932] - Swedish characters are garbled in form @@ -722,6 +724,7 @@ Bug [PDFBOX-2724] - Importing a XFDF file doesn't populate the field value [PDFBOX-2726] - org.apache.pdfbox.cos.COSArray cannot be cast to org.apache.pdfbox.cos.COSDictionary [PDFBOX-2728] - java.awt.geom.IllegalPathStateException: missing initial moveto in path definition +[PDFBOX-2729] - Can't sign encrypted PDF files [PDFBOX-2730] - PDFSplit slow and keeps unused pages [PDFBOX-2733] - Nullpointer exception in PDFXrefStreamParser.parse [PDFBOX-2734] - Can't create PDF with DeviceN colorspace @@ -814,6 +817,7 @@ Bug [PDFBOX-2950] - Chinese font substitution issue [PDFBOX-2951] - quotedbl causes NullPointerException [PDFBOX-2956] - PDFontDescriptor doesn't contain method getCIDSet. +[PDFBOX-2957] - Glyphs rendered as gibberish [PDFBOX-2958] - TIFF-Predictor with 1 bit per component not supported [PDFBOX-2959] - type3 font glyphs overlapped [PDFBOX-2960] - ClassCastException when pattern name is indirect object @@ -878,10 +882,13 @@ Bug [PDFBOX-3109] - DrawPrintTextLocations with incorrect coordinates when cropbox [PDFBOX-3110] - Extract by beads doesn't work [PDFBOX-3114] - Visible signatures in different pages changes previous revision +[PDFBOX-3116] - COSNumber NumberFormatException for large number +[PDFBOX-3120] - ArrayIndexOutOfBoundsException in CodespaceRange.isPartialMatch / CMap is invalid [PDFBOX-3130] - Recent regression in PDFTextStripper, text getting garbled [PDFBOX-3139] - Custom FontMapper cant be used [PDFBOX-3140] - Different fallback font rendering first and second time [PDFBOX-3141] - Link annotation borders not rendered +[PDFBOX-3142] - PDFMergerUtility with scratch file generates result with blank pages for certain source files. [PDFBOX-3143] - Added PDEmbeddedFile constructor with COSName parameter [PDFBOX-3144] - NullPointerException in TTFSubsetter [PDFBOX-3145] - Security manager fails for .pdfbox.cache @@ -905,6 +912,36 @@ Bug [PDFBOX-3181] - java.lang.ArrayIndexOutOfBoundsException: Coordinate out of bounds! in org.apache.pdfbox.pdmodel.graphics.image.LosslessFactory.createFromImage [PDFBOX-3184] - Throwing in PDType1Font.encode for chars above 255 is wrong. [PDFBOX-3187] - NullPointerException CFFParser +[PDFBOX-3188] - java.io.IOException: Error: source PDF is encrypted, can't append encrypted PDF documents +[PDFBOX-3189] - java.io.IOException is thrown from both NonSequentialPDFParser and PDFParser +[PDFBOX-3190] - Links don't work in firefox +[PDFBOX-3191] - PDFDebugger does not handle cancelling of "Open URL" dialog +[PDFBOX-3195] - ExtractText add space at start of text +[PDFBOX-3199] - JPEG input file not closed when creating PDImageXObject +[PDFBOX-3201] - Skip zlib-header and checksum to avoid DataFormatException +[PDFBOX-3203] - Fractional font sizes are reported scaled +[PDFBOX-3204] - JVM crashes on PDFRenderer.renderImageWithDPI +[PDFBOX-3209] - Overlay class does not work with in-memory PDFs +[PDFBOX-3217] - PdfaExtensionHelper.populatePDFAPropertyType +[PDFBOX-3219] - Suggestion for log4j.xml example inside preflight source +[PDFBOX-3221] - /TR /TR2 Transfer function not implemented +[PDFBOX-3226] - No such Element Exception processing File +[PDFBOX-3229] - Decryption fails when Metadata not encrypted but EncryptMetadata is true/default. +[PDFBOX-3237] - ASCII85Filter does not use or recognize the correct end-of-data terminator +[PDFBOX-3240] - Missing Type for standard type 1 fonts +[PDFBOX-3242] - Problem displaying document created by PDFBox 2.0RC3 in Acrobat Reader +[PDFBOX-3249] - PDAnnotationMarkup.getInReplyTo throws exception when no element +[PDFBOX-3250] - Possible errors in TrueType table 'name' parsing. +[PDFBOX-3252] - java.lang.ExceptionInInitializerError in PDFBox +[PDFBOX-3253] - Close all COSStreams when creating a new pdf +[PDFBOX-3254] - Corrupted XMP causes java.lang.StringIndexOutOfBoundsException +[PDFBOX-3258] - XMPBox XMPBasicSchema setters don't work if already set +[PDFBOX-3259] - ClassCastException in PDTilingPattern.getContents +[PDFBOX-3263] - Overlaying 2 pdfs corrupts cross-reference stream +[PDFBOX-3266] - Overlay doesn't work anymore +[PDFBOX-3268] - Corners of stroked type are inaccurate when rendered as an image +[PDFBOX-3271] - Incomplete widths array for CID-fonts +[PDFBOX-3272] - Loaded fonts file descriptors open after closing document Improvement @@ -1073,6 +1110,7 @@ Improvement [PDFBOX-2566] - Remove logging from operator classes [PDFBOX-2580] - Decouple implementation specific forms handling from interactive.form PD Model [PDFBOX-2587] - PDF takes minutes to convert (sRGB) +[PDFBOX-2590] - Improve PDPageContentStream API [PDFBOX-2591] - Allow using custom Filters [PDFBOX-2592] - Allow sharing of COS objects between different documents [PDFBOX-2594] - Set default params in JBIG2Filter @@ -1118,6 +1156,7 @@ Improvement [PDFBOX-2893] - Simplify COSStream encoding and decoding [PDFBOX-2894] - Remove COSStreamArray / SequenceRandomAccessRead [PDFBOX-2905] - Replace PDFReader with PDFDebugger +[PDFBOX-2918] - Allow to refresh an AcroForm field appearance [PDFBOX-2922] - Printing issues with landscape pages [PDFBOX-2928] - Add numPages parameter of Book in Printing.printWithPaper example [PDFBOX-2931] - Make PDFPrintable margin-aligning and centering optional @@ -1125,10 +1164,12 @@ Improvement [PDFBOX-2943] - PDType3Font.getWidthFromFont not supported [PDFBOX-2945] - PDType1Font.getNameInFont(String) very slow when Unicode fallback is used [PDFBOX-2962] - Handle TIFF predictor for bpc 2 and 4 / optimize existing predictor code +[PDFBOX-2970] - Add capability to flatten AcroForm form fields [PDFBOX-2973] - Actions shortage [PDFBOX-2978] - Add support for grouped checkboxes [PDFBOX-2997] - Make FontMapper into a singleton interface [PDFBOX-3072] - Allow missing page type +[PDFBOX-3084] - More generic PDPageContentStream constructor [PDFBOX-3088] - Cache glyph table to optimize concurrent access [PDFBOX-3103] - Slow performance when printing PDF (fix provided) [PDFBOX-3104] - Font Cache is taking a lot of time @@ -1143,8 +1184,14 @@ Improvement [PDFBOX-3163] - PDImageXObject.createFromFile should relies on header bytes [PDFBOX-3176] - Add a removeRegion method in PDFTextSTripperByArea class [PDFBOX-3178] - Make PDFTextStreamEngine class public +[PDFBOX-3200] - Performance improvement in PDPageContentStream.setFont +[PDFBOX-3202] - Rename structure element setter of PDOutlineItem +[PDFBOX-3224] - Cache Font Bounding Boxes for Performance in Text Extraction +[PDFBOX-3231] - Update PDPropBuildDataDict +[PDFBOX-3234] - Rename check box field type to match PDF 2.0 specification +[PDFBOX-3245] - Add fill and stroke operators -Feature +New Feature [PDFBOX-52] - DCTFilter is not implemented yet [PDFBOX-149] - Update encryption algorithms @@ -1187,6 +1234,7 @@ Task [PDFBOX-3011] - Find out why trunk CreateVisibleSignature example produces incorrect output pdf [PDFBOX-3020] - Set libraries to current versions for RC [PDFBOX-3040] - Move website to local build tool +[PDFBOX-3058] - Support TIKA Migration to PDFBox 2.0 Test @@ -1211,6 +1259,7 @@ Wish [PDFBOX-2692] - Possibility to use our own and/or overwrite PageDrawer class [PDFBOX-2738] - Make org.apache.pdfbox.pdmodel.PDDocument#getFontsToSubset public [PDFBOX-2770] - Provide the sources along with SNAPSHOT releases +[PDFBOX-3233] - Create default resources with cache Release Contents ---------------- From f7d4843e70d1af9c916adc9cc8093c2148783e95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Lehmk=C3=BChler?= Date: Mon, 14 Mar 2016 17:21:53 +0000 Subject: [PATCH 0003/2182] [maven-release-plugin] prepare release 2.0.0 git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1734970 13f79535-47bb-0310-9956-ffa450edef68 --- app/pom.xml | 2 +- debugger-app/pom.xml | 2 +- debugger/pom.xml | 2 +- examples/pom.xml | 2 +- fontbox/pom.xml | 2 +- parent/pom.xml | 8 ++++---- pdfbox/pom.xml | 2 +- pom.xml | 8 ++++---- preflight-app/pom.xml | 2 +- preflight/pom.xml | 2 +- tools/pom.xml | 2 +- xmpbox/pom.xml | 2 +- 12 files changed, 18 insertions(+), 18 deletions(-) diff --git a/app/pom.xml b/app/pom.xml index ec6a2de6bf5..2240b75d224 100644 --- a/app/pom.xml +++ b/app/pom.xml @@ -23,7 +23,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.0-SNAPSHOT + 2.0.0 ../parent/pom.xml diff --git a/debugger-app/pom.xml b/debugger-app/pom.xml index 1b6432bfb95..67c4a7ccd1f 100644 --- a/debugger-app/pom.xml +++ b/debugger-app/pom.xml @@ -23,7 +23,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.0-SNAPSHOT + 2.0.0 ../parent/pom.xml diff --git a/debugger/pom.xml b/debugger/pom.xml index 35cf888b2a6..851574ebb39 100644 --- a/debugger/pom.xml +++ b/debugger/pom.xml @@ -23,7 +23,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.0-SNAPSHOT + 2.0.0 ../parent/pom.xml diff --git a/examples/pom.xml b/examples/pom.xml index 189b33e754d..3dc08f8bd27 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -23,7 +23,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.0-SNAPSHOT + 2.0.0 ../parent/pom.xml diff --git a/fontbox/pom.xml b/fontbox/pom.xml index 7c78d228b66..0723a24b104 100644 --- a/fontbox/pom.xml +++ b/fontbox/pom.xml @@ -21,7 +21,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.0-SNAPSHOT + 2.0.0 ../parent/pom.xml diff --git a/parent/pom.xml b/parent/pom.xml index bd56f56231f..41719ad66af 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -29,7 +29,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.0-SNAPSHOT + 2.0.0 pom PDFBox parent @@ -377,8 +377,8 @@ - scm:svn:http://svn.apache.org/repos/asf/maven/pom/branches/2.0/pdfbox-parent - scm:svn:https://svn.apache.org/repos/asf/maven/pom/branches/2.0/pdfbox-parent - http://svn.apache.org/viewvc/maven/pom/branches/2.0/pdfbox-parent + scm:svn:http://svn.apache.org/repos/asf/maven/pom/tags/2.0.0/pdfbox-parent + scm:svn:https://svn.apache.org/repos/asf/maven/pom/tags/2.0.0/pdfbox-parent + http://svn.apache.org/viewvc/maven/pom/tags/2.0.0/pdfbox-parent diff --git a/pdfbox/pom.xml b/pdfbox/pom.xml index a044baecba9..2ee00a24a49 100644 --- a/pdfbox/pom.xml +++ b/pdfbox/pom.xml @@ -23,7 +23,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.0-SNAPSHOT + 2.0.0 ../parent/pom.xml diff --git a/pom.xml b/pom.xml index 6c875c6dc3a..ce2e12c674d 100644 --- a/pom.xml +++ b/pom.xml @@ -23,7 +23,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.0-SNAPSHOT + 2.0.0 parent/pom.xml @@ -34,12 +34,12 @@ - scm:svn:http://svn.apache.org/repos/asf/pdfbox/branches/2.0 + scm:svn:http://svn.apache.org/repos/asf/pdfbox/tags/2.0.0 - scm:svn:https://svn.apache.org/repos/asf/pdfbox/branches/2.0 + scm:svn:https://svn.apache.org/repos/asf/pdfbox/tags/2.0.0 - http://svn.apache.org/viewvc/pdfbox/branches/2.0 + http://svn.apache.org/viewvc/pdfbox/tags/2.0.0 diff --git a/preflight-app/pom.xml b/preflight-app/pom.xml index cafd44b899f..4e3ab2715f4 100644 --- a/preflight-app/pom.xml +++ b/preflight-app/pom.xml @@ -23,7 +23,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.0-SNAPSHOT + 2.0.0 ../parent/pom.xml diff --git a/preflight/pom.xml b/preflight/pom.xml index 6bc2870b235..fc492e93534 100644 --- a/preflight/pom.xml +++ b/preflight/pom.xml @@ -26,7 +26,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.0-SNAPSHOT + 2.0.0 ../parent/pom.xml diff --git a/tools/pom.xml b/tools/pom.xml index 0b65d4c1650..b35ff7d4857 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -23,7 +23,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.0-SNAPSHOT + 2.0.0 ../parent/pom.xml diff --git a/xmpbox/pom.xml b/xmpbox/pom.xml index 401bdaf7875..00ecc4f5c7a 100644 --- a/xmpbox/pom.xml +++ b/xmpbox/pom.xml @@ -27,7 +27,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.0-SNAPSHOT + 2.0.0 ../parent/pom.xml From 8e073f4bb3a5928eab5f4b77b9e6728955e07e70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Lehmk=C3=BChler?= Date: Mon, 14 Mar 2016 17:22:16 +0000 Subject: [PATCH 0004/2182] [maven-release-plugin] prepare for next development iteration git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1734972 13f79535-47bb-0310-9956-ffa450edef68 --- app/pom.xml | 2 +- debugger-app/pom.xml | 2 +- debugger/pom.xml | 2 +- examples/pom.xml | 2 +- fontbox/pom.xml | 2 +- parent/pom.xml | 8 ++++---- pdfbox/pom.xml | 2 +- pom.xml | 8 ++++---- preflight-app/pom.xml | 2 +- preflight/pom.xml | 2 +- tools/pom.xml | 2 +- xmpbox/pom.xml | 2 +- 12 files changed, 18 insertions(+), 18 deletions(-) diff --git a/app/pom.xml b/app/pom.xml index 2240b75d224..d190b69e299 100644 --- a/app/pom.xml +++ b/app/pom.xml @@ -23,7 +23,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.0 + 2.0.1-SNAPSHOT ../parent/pom.xml diff --git a/debugger-app/pom.xml b/debugger-app/pom.xml index 67c4a7ccd1f..8813ffba10a 100644 --- a/debugger-app/pom.xml +++ b/debugger-app/pom.xml @@ -23,7 +23,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.0 + 2.0.1-SNAPSHOT ../parent/pom.xml diff --git a/debugger/pom.xml b/debugger/pom.xml index 851574ebb39..dcb3aabb337 100644 --- a/debugger/pom.xml +++ b/debugger/pom.xml @@ -23,7 +23,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.0 + 2.0.1-SNAPSHOT ../parent/pom.xml diff --git a/examples/pom.xml b/examples/pom.xml index 3dc08f8bd27..b6ba2c1f863 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -23,7 +23,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.0 + 2.0.1-SNAPSHOT ../parent/pom.xml diff --git a/fontbox/pom.xml b/fontbox/pom.xml index 0723a24b104..6a5da3b1c89 100644 --- a/fontbox/pom.xml +++ b/fontbox/pom.xml @@ -21,7 +21,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.0 + 2.0.1-SNAPSHOT ../parent/pom.xml diff --git a/parent/pom.xml b/parent/pom.xml index 41719ad66af..b2b441f0bb4 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -29,7 +29,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.0 + 2.0.1-SNAPSHOT pom PDFBox parent @@ -377,8 +377,8 @@ - scm:svn:http://svn.apache.org/repos/asf/maven/pom/tags/2.0.0/pdfbox-parent - scm:svn:https://svn.apache.org/repos/asf/maven/pom/tags/2.0.0/pdfbox-parent - http://svn.apache.org/viewvc/maven/pom/tags/2.0.0/pdfbox-parent + scm:svn:http://svn.apache.org/repos/asf/maven/pom/branches/2.0/pdfbox-parent + scm:svn:https://svn.apache.org/repos/asf/maven/pom/branches/2.0/pdfbox-parent + http://svn.apache.org/viewvc/maven/pom/branches/2.0/pdfbox-parent diff --git a/pdfbox/pom.xml b/pdfbox/pom.xml index 2ee00a24a49..15f02219808 100644 --- a/pdfbox/pom.xml +++ b/pdfbox/pom.xml @@ -23,7 +23,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.0 + 2.0.1-SNAPSHOT ../parent/pom.xml diff --git a/pom.xml b/pom.xml index ce2e12c674d..d27d3fcfeb9 100644 --- a/pom.xml +++ b/pom.xml @@ -23,7 +23,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.0 + 2.0.1-SNAPSHOT parent/pom.xml @@ -34,12 +34,12 @@ - scm:svn:http://svn.apache.org/repos/asf/pdfbox/tags/2.0.0 + scm:svn:http://svn.apache.org/repos/asf/pdfbox/branches/2.0 - scm:svn:https://svn.apache.org/repos/asf/pdfbox/tags/2.0.0 + scm:svn:https://svn.apache.org/repos/asf/pdfbox/branches/2.0 - http://svn.apache.org/viewvc/pdfbox/tags/2.0.0 + http://svn.apache.org/viewvc/pdfbox/branches/2.0 diff --git a/preflight-app/pom.xml b/preflight-app/pom.xml index 4e3ab2715f4..d704beaee5a 100644 --- a/preflight-app/pom.xml +++ b/preflight-app/pom.xml @@ -23,7 +23,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.0 + 2.0.1-SNAPSHOT ../parent/pom.xml diff --git a/preflight/pom.xml b/preflight/pom.xml index fc492e93534..8ac09f49b4f 100644 --- a/preflight/pom.xml +++ b/preflight/pom.xml @@ -26,7 +26,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.0 + 2.0.1-SNAPSHOT ../parent/pom.xml diff --git a/tools/pom.xml b/tools/pom.xml index b35ff7d4857..daf2fc3ae82 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -23,7 +23,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.0 + 2.0.1-SNAPSHOT ../parent/pom.xml diff --git a/xmpbox/pom.xml b/xmpbox/pom.xml index 00ecc4f5c7a..556f816dda8 100644 --- a/xmpbox/pom.xml +++ b/xmpbox/pom.xml @@ -27,7 +27,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.0 + 2.0.1-SNAPSHOT ../parent/pom.xml From adde8e003d512a2be898336822872f07271ea650 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Tue, 15 Mar 2016 17:32:54 +0000 Subject: [PATCH 0005/2182] PDFBOX-3273: round result of int division git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1735148 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/fontbox/cff/Type1CharString.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fontbox/src/main/java/org/apache/fontbox/cff/Type1CharString.java b/fontbox/src/main/java/org/apache/fontbox/cff/Type1CharString.java index cd72b4f12ed..ad222f4f166 100644 --- a/fontbox/src/main/java/org/apache/fontbox/cff/Type1CharString.java +++ b/fontbox/src/main/java/org/apache/fontbox/cff/Type1CharString.java @@ -289,7 +289,7 @@ else if ("div".equals(name)) int b = numbers.get(numbers.size() -1); int a = numbers.get(numbers.size() -2); - int result = a / b; // TODO loss of precision, should be float + int result = Math.round(a / (float) b); // TODO loss of precision, result should be float List list = new ArrayList(numbers); list.remove(list.size() - 1); From b5c1168ca19b9a91c49ac56e719265751303412d Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Fri, 18 Mar 2016 16:54:06 +0000 Subject: [PATCH 0006/2182] PDFBOX-3276: /Encrypt dictionary has already been written, so don't make it direct and write it a second time git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1735641 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/pdfbox/pdfparser/PDFXRefStream.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/PDFXRefStream.java b/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/PDFXRefStream.java index 5a5f4705471..e1a6ed3dc08 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/PDFXRefStream.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/PDFXRefStream.java @@ -111,6 +111,11 @@ public COSStream getStream() throws IOException { continue; } + // this one too, because it has already been written in COSWriter.doWriteBody() + if (COSName.ENCRYPT.equals(cosName)) + { + continue; + } COSBase dictionaryObject = this.stream.getDictionaryObject(cosName); dictionaryObject.setDirect(true); } From 93bb015e2b1eddbed5b5845cb4d8fe03fad784d3 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Fri, 18 Mar 2016 18:43:44 +0000 Subject: [PATCH 0007/2182] PDFBOX-3276: refactor double code git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1735657 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/pdfbox/pdfwriter/COSWriter.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdfwriter/COSWriter.java b/pdfbox/src/main/java/org/apache/pdfbox/pdfwriter/COSWriter.java index 204c4b98f6d..6a356e019d9 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdfwriter/COSWriter.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdfwriter/COSWriter.java @@ -471,18 +471,18 @@ protected void doWriteBody(COSDocument doc) throws IOException addObjectToWrite( info ); } - while( objectsToWrite.size() > 0 ) - { - COSBase nextObject = objectsToWrite.removeFirst(); - objectsToWriteSet.remove(nextObject); - doWriteObject( nextObject ); - } + doWriteObjects(); willEncrypt = false; if( encrypt != null ) { addObjectToWrite( encrypt ); } + doWriteObjects(); + } + + private void doWriteObjects() throws IOException + { while( objectsToWrite.size() > 0 ) { COSBase nextObject = objectsToWrite.removeFirst(); From a4b947905a4a898dc9803ec4ba965d33ec8cd2bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Lehmk=C3=BChler?= Date: Tue, 22 Mar 2016 18:21:33 +0000 Subject: [PATCH 0008/2182] PDFBOX-3272: close replaced font when creating subset git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1736224 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/pdfbox/pdmodel/font/TrueTypeEmbedder.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/TrueTypeEmbedder.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/TrueTypeEmbedder.java index 54a8a48e2cd..a9af87d88cc 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/TrueTypeEmbedder.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/TrueTypeEmbedder.java @@ -103,6 +103,11 @@ public void buildFontFile2(InputStream ttfStream) throws IOException try { input = stream.createInputStream(); + if (ttf != null) + { + // close the replaced true type font + ttf.close(); + } ttf = new TTFParser().parseEmbedded(input); if (!isEmbeddingPermitted(ttf)) { From 9739a2b4bfb0cb1d84e3a7a645432a9572138bb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Lehmk=C3=BChler?= Date: Tue, 22 Mar 2016 18:31:16 +0000 Subject: [PATCH 0009/2182] PDFBOX-3279: avoid creating unneeded stream git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1736229 13f79535-47bb-0310-9956-ffa450edef68 --- pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java index fb3662fe4b3..b8b583a99b2 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java @@ -521,7 +521,7 @@ public PDPage importPage(PDPage page) throws IOException in = page.getContents(); if (in != null) { - PDStream dest = new PDStream(this, page.getContents(), COSName.FLATE_DECODE); + PDStream dest = new PDStream(this, in, COSName.FLATE_DECODE); importedPage.setContents(dest); } addPage(importedPage); @@ -530,7 +530,6 @@ public PDPage importPage(PDPage page) throws IOException { IOUtils.closeQuietly(in); } - return importedPage; } From e659cc8a4a8648955e761cde2a9ea7430df75ca5 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Thu, 24 Mar 2016 06:54:35 +0000 Subject: [PATCH 0010/2182] PDFBOX-3289: rename constant as suggested by Dmitry Zvorygin git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1736397 13f79535-47bb-0310-9956-ffa450edef68 --- .../pdfbox/pdmodel/common/PDRectangle.java | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/PDRectangle.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/PDRectangle.java index d0ee11bc5cb..de2a5e91a41 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/PDRectangle.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/PDRectangle.java @@ -34,8 +34,11 @@ */ public class PDRectangle implements COSObjectable { + /** user space units per inch */ private static final float POINTS_PER_INCH = 72; - private static final float MM_PER_INCH = 1 / (10 * 2.54f) * POINTS_PER_INCH; + + /** user space units per millimeter */ + private static final float POINTS_PER_MM = 1 / (10 * 2.54f) * POINTS_PER_INCH; /** A rectangle the size of U.S. Letter, 8.5" x 11". */ public static final PDRectangle LETTER = new PDRectangle(8.5f * POINTS_PER_INCH, @@ -44,25 +47,25 @@ public class PDRectangle implements COSObjectable public static final PDRectangle LEGAL = new PDRectangle(8.5f * POINTS_PER_INCH, 14f * POINTS_PER_INCH); /** A rectangle the size of A0 Paper. */ - public static final PDRectangle A0 = new PDRectangle(841 * MM_PER_INCH, 1189 * MM_PER_INCH); + public static final PDRectangle A0 = new PDRectangle(841 * POINTS_PER_MM, 1189 * POINTS_PER_MM); /** A rectangle the size of A1 Paper. */ - public static final PDRectangle A1 = new PDRectangle(594 * MM_PER_INCH, 841 * MM_PER_INCH); + public static final PDRectangle A1 = new PDRectangle(594 * POINTS_PER_MM, 841 * POINTS_PER_MM); /** A rectangle the size of A2 Paper. */ - public static final PDRectangle A2 = new PDRectangle(420 * MM_PER_INCH, 594 * MM_PER_INCH); + public static final PDRectangle A2 = new PDRectangle(420 * POINTS_PER_MM, 594 * POINTS_PER_MM); /** A rectangle the size of A3 Paper. */ - public static final PDRectangle A3 = new PDRectangle(297 * MM_PER_INCH, 420 * MM_PER_INCH); + public static final PDRectangle A3 = new PDRectangle(297 * POINTS_PER_MM, 420 * POINTS_PER_MM); /** A rectangle the size of A4 Paper. */ - public static final PDRectangle A4 = new PDRectangle(210 * MM_PER_INCH, 297 * MM_PER_INCH); + public static final PDRectangle A4 = new PDRectangle(210 * POINTS_PER_MM, 297 * POINTS_PER_MM); /** A rectangle the size of A5 Paper. */ - public static final PDRectangle A5 = new PDRectangle(148 * MM_PER_INCH, 210 * MM_PER_INCH); + public static final PDRectangle A5 = new PDRectangle(148 * POINTS_PER_MM, 210 * POINTS_PER_MM); /** A rectangle the size of A6 Paper. */ - public static final PDRectangle A6 = new PDRectangle(105 * MM_PER_INCH, 148 * MM_PER_INCH); + public static final PDRectangle A6 = new PDRectangle(105 * POINTS_PER_MM, 148 * POINTS_PER_MM); private final COSArray rectArray; From 736da3fa2445fb21d8b9ffecbefaa3691250a17c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Lehmk=C3=BChler?= Date: Fri, 25 Mar 2016 16:44:24 +0000 Subject: [PATCH 0011/2182] PDFBOX-3286: fixed constant value and constant usage as proposed by Christophe Bouchon git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1736616 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/pdfbox/pdmodel/font/TrueTypeEmbedder.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/TrueTypeEmbedder.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/TrueTypeEmbedder.java index a9af87d88cc..9a12abe3983 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/TrueTypeEmbedder.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/TrueTypeEmbedder.java @@ -50,7 +50,7 @@ abstract class TrueTypeEmbedder implements Subsetter { private static final int ITALIC = 1; - private static final int OBLIQUE = 256; + private static final int OBLIQUE = 512; private static final String BASE25 = "BCDEFGHIJKLMNOPQRSTUVWXYZ"; private final PDDocument document; @@ -185,8 +185,7 @@ private PDFontDescriptor createFontDescriptor(TrueTypeFont ttf) throws IOExcepti ttf.getHorizontalHeader().getNumberOfHMetrics() == 1); int fsSelection = os2.getFsSelection(); - fd.setItalic((fsSelection & ITALIC) == fsSelection || - (fsSelection & OBLIQUE) == fsSelection); + fd.setItalic(((fsSelection & (ITALIC | OBLIQUE)) != 0)); switch (os2.getFamilyClass()) { From 134058acf000864bbc946557d4812517c89a636e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Lehmk=C3=BChler?= Date: Tue, 29 Mar 2016 20:37:59 +0000 Subject: [PATCH 0012/2182] PDFBOX-3295: avoid using XrefTrailerResolver#getContainedObjectNumbers as proposed by Andrea Vacondio to speed up the parsing of object streams git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1737044 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/pdfbox/pdfparser/COSParser.java | 6 +----- .../org/apache/pdfbox/preflight/parser/PreflightParser.java | 6 +----- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/COSParser.java b/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/COSParser.java index aa1882a14cd..47bfe38b04b 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/COSParser.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/COSParser.java @@ -836,15 +836,11 @@ private void parseObjectStream(int objstmObjNr) throws IOException throw exception; } } - - // get set of object numbers referenced for this object stream - final Set refObjNrs = xrefTrailerResolver.getContainedObjectNumbers(objstmObjNr); - // register all objects which are referenced to be contained in object stream for (COSObject next : parser.getObjects()) { COSObjectKey stmObjKey = new COSObjectKey(next); - if (refObjNrs.contains(stmObjKey.getNumber())) + if (xrefTrailerResolver.getXrefTable().containsKey(stmObjKey)) { COSObject stmObj = document.getObjectFromPool(stmObjKey); stmObj.setObject(next.getObject()); diff --git a/preflight/src/main/java/org/apache/pdfbox/preflight/parser/PreflightParser.java b/preflight/src/main/java/org/apache/pdfbox/preflight/parser/PreflightParser.java index 97ed2680012..9e0945cba6b 100644 --- a/preflight/src/main/java/org/apache/pdfbox/preflight/parser/PreflightParser.java +++ b/preflight/src/main/java/org/apache/pdfbox/preflight/parser/PreflightParser.java @@ -28,7 +28,6 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; -import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.activation.DataSource; @@ -830,14 +829,11 @@ else if (securityHandler != null) PDFObjectStreamParser parser = new PDFObjectStreamParser((COSStream) objstmBaseObj, document); parser.parse(); - // get set of object numbers referenced for this object stream - final Set refObjNrs = xrefTrailerResolver.getContainedObjectNumbers(objstmObjNr); - // register all objects which are referenced to be contained in object stream for (COSObject next : parser.getObjects()) { COSObjectKey stmObjKey = new COSObjectKey(next); - if (refObjNrs.contains(stmObjKey.getNumber())) + if (xrefTrailerResolver.getXrefTable().containsKey(stmObjKey)) { COSObject stmObj = document.getObjectFromPool(stmObjKey); stmObj.setObject(next.getObject()); From a99ec158589da64bf764356f8c33a8bd49493138 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Wed, 30 Mar 2016 07:44:31 +0000 Subject: [PATCH 0013/2182] PDFBOX-2852: fix typo git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1737081 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/pdfbox/examples/interactive/form/FillFormField.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/src/main/java/org/apache/pdfbox/examples/interactive/form/FillFormField.java b/examples/src/main/java/org/apache/pdfbox/examples/interactive/form/FillFormField.java index 045867b4499..c391ce8ef66 100644 --- a/examples/src/main/java/org/apache/pdfbox/examples/interactive/form/FillFormField.java +++ b/examples/src/main/java/org/apache/pdfbox/examples/interactive/form/FillFormField.java @@ -46,7 +46,7 @@ public static void main(String[] args) throws IOException // as there might not be an AcroForm entry a null check is necessary if (acroForm != null) { - // Retrieve an individual field and set it's value. + // Retrieve an individual field and set its value. PDTextField field = (PDTextField) acroForm.getField( "sampleField" ); field.setValue("Text Entry"); From 68d8f5cc655705d2c17171081bd420b3f4fac269 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Lehmk=C3=BChler?= Date: Wed, 30 Mar 2016 16:31:45 +0000 Subject: [PATCH 0014/2182] PDFBOX-3295: compare the object stream index instead of simply checking if it exists git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1737133 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/pdfbox/pdfparser/COSParser.java | 3 ++- .../org/apache/pdfbox/preflight/parser/PreflightParser.java | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/COSParser.java b/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/COSParser.java index 47bfe38b04b..90f7db9bd80 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/COSParser.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/COSParser.java @@ -840,7 +840,8 @@ private void parseObjectStream(int objstmObjNr) throws IOException for (COSObject next : parser.getObjects()) { COSObjectKey stmObjKey = new COSObjectKey(next); - if (xrefTrailerResolver.getXrefTable().containsKey(stmObjKey)) + Long offset = xrefTrailerResolver.getXrefTable().get(stmObjKey); + if (offset != null && offset == -objstmObjNr) { COSObject stmObj = document.getObjectFromPool(stmObjKey); stmObj.setObject(next.getObject()); diff --git a/preflight/src/main/java/org/apache/pdfbox/preflight/parser/PreflightParser.java b/preflight/src/main/java/org/apache/pdfbox/preflight/parser/PreflightParser.java index 9e0945cba6b..e463a7495eb 100644 --- a/preflight/src/main/java/org/apache/pdfbox/preflight/parser/PreflightParser.java +++ b/preflight/src/main/java/org/apache/pdfbox/preflight/parser/PreflightParser.java @@ -833,7 +833,8 @@ else if (securityHandler != null) for (COSObject next : parser.getObjects()) { COSObjectKey stmObjKey = new COSObjectKey(next); - if (xrefTrailerResolver.getXrefTable().containsKey(stmObjKey)) + Long offset = xrefTrailerResolver.getXrefTable().get(stmObjKey); + if (offset != null && offset == -objstmObjNr) { COSObject stmObj = document.getObjectFromPool(stmObjKey); stmObj.setObject(next.getObject()); From d1c79f7bfcef0e2eb83b34a0b24c3ffad70500a1 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Thu, 31 Mar 2016 17:01:35 +0000 Subject: [PATCH 0015/2182] PDFBOX-3297: optimize function creation git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1737260 13f79535-47bb-0310-9956-ffa450edef68 --- .../common/function/PDFunctionType3.java | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/PDFunctionType3.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/PDFunctionType3.java index f79ca60b04c..db33a642744 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/PDFunctionType3.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/PDFunctionType3.java @@ -30,10 +30,10 @@ */ public class PDFunctionType3 extends PDFunction { - private COSArray functions = null; private COSArray encode = null; private COSArray bounds = null; + private PDFunction[] functionsArray = null; /** * Constructor. @@ -68,13 +68,21 @@ public float[] eval(float[] input) throws IOException PDRange domain = getDomainForInput(0); // clip input value to domain x = clipToRange(x, domain.getMin(), domain.getMax()); + + if (functionsArray == null) + { + COSArray ar = getFunctions(); + functionsArray = new PDFunction[ar.size()]; + for (int i = 0; i < ar.size(); ++i) + { + functionsArray[i] = PDFunction.create(ar.getObject(i)); + } + } - COSArray functionsArray = getFunctions(); - int numberOfFunctions = functionsArray.size(); - // This doesn't make sense but it may happen ... - if (numberOfFunctions == 1) + if (functionsArray.length == 1) { - function = PDFunction.create(functionsArray.get(0)); + // This doesn't make sense but it may happen ... + function = functionsArray[0]; PDRange encRange = getEncodeForParameter(0); x = interpolate(x, domain.getMin(), domain.getMax(), encRange.getMin(), encRange.getMax()); } @@ -95,7 +103,7 @@ public float[] eval(float[] input) throws IOException if ( x >= partitionValues[i] && (x < partitionValues[i+1] || (i == partitionValuesSize - 2 && x == partitionValues[i+1]))) { - function = PDFunction.create(functionsArray.get(i)); + function = functionsArray[i]; PDRange encRange = getEncodeForParameter(i); x = interpolate(x, partitionValues[i], partitionValues[i+1], encRange.getMin(), encRange.getMax()); break; From 25f5bb72838766aac37b3c6d303900820d1cb243 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Thu, 31 Mar 2016 17:18:11 +0000 Subject: [PATCH 0016/2182] PDFBOX-3299: TIFF-files with FillOrder=2 can't be converted to PDF git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1737262 13f79535-47bb-0310-9956-ffa450edef68 --- .../pdfbox/pdmodel/graphics/image/CCITTFactory.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/CCITTFactory.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/CCITTFactory.java index 37ca491401b..0601cdd0b9f 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/CCITTFactory.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/CCITTFactory.java @@ -282,6 +282,14 @@ private static void extractFromTiff(RandomAccess reader, OutputStream os, } break; } + case 266: + { + if (val != 1) + { + throw new IOException("FillOrder " + val + " is not supported"); + } + break; + } case 273: { if (count == 1) From 342936cef0c67cf2eec0001a18178edb6f97c8a2 Mon Sep 17 00:00:00 2001 From: Maruan Sahyoun Date: Fri, 1 Apr 2016 12:34:09 +0000 Subject: [PATCH 0017/2182] PDFBOX-3301: lookup widgets page reference if there is no /P entry git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1737365 13f79535-47bb-0310-9956-ffa450edef68 --- .../pdmodel/interactive/form/PDAcroForm.java | 36 ++++++++++++++++++ .../interactive/form/PDAcroFormTest.java | 29 ++++++++++++++ .../AlignmentTests-flattened-noRef.pdf-1.png | Bin 0 -> 64491 bytes 3 files changed, 65 insertions(+) create mode 100644 pdfbox/src/test/resources/org/apache/pdfbox/pdmodel/interactive/form/AlignmentTests-flattened-noRef.pdf-1.png diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDAcroForm.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDAcroForm.java index d11fd76859c..0d7e051d298 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDAcroForm.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDAcroForm.java @@ -220,6 +220,11 @@ public void flatten(List fields, boolean refreshAppearances) throws IOE // the content stream to write to PDPageContentStream contentStream; + // Hold a reference between the annotations and the page they are on. + // This will only be used in case a PDAnnotationWidget doesn't contain + // a /P entry specifying the page it's on as the /P entry is optional + Map annotationToPageRef = null; + // Iterate over all form fields and their widgets and create a // FormXObject at the page content level from that for (PDField field : fields) @@ -229,6 +234,18 @@ public void flatten(List fields, boolean refreshAppearances) throws IOE if (widget.getNormalAppearanceStream() != null) { PDPage page = widget.getPage(); + + // resolve the page from looking at the annotations + if (widget.getPage() == null) { + if (annotationToPageRef == null) { + annotationToPageRef = buildAnnotationToPageRef(); + } + Integer pageRef = annotationToPageRef.get(widget.getCOSObject()); + if (pageRef != null) { + page = document.getPage((int) pageRef); + } + } + if (!isContentStreamWrapped) { contentStream = new PDPageContentStream(document, page, AppendMode.APPEND, true, true); @@ -616,4 +633,23 @@ public void setAppendOnly(boolean appendOnly) { dictionary.setFlag(COSName.SIG_FLAGS, FLAG_APPEND_ONLY, appendOnly); } + + private Map buildAnnotationToPageRef() { + Map annotationToPageRef = new HashMap(); + + int idx = 0; + for (PDPage page : document.getPages()) { + try { + for (PDAnnotation annotation : page.getAnnotations()) { + if (annotation instanceof PDAnnotationWidget) { + annotationToPageRef.put(annotation.getCOSObject(), idx); + } + } + } catch (IOException e) { + LOG.warn("Can't retriev annotations for page " + idx); + } + idx++; + } + return annotationToPageRef; + } } diff --git a/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/interactive/form/PDAcroFormTest.java b/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/interactive/form/PDAcroFormTest.java index baee95f6059..6a45d9c3f80 100644 --- a/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/interactive/form/PDAcroFormTest.java +++ b/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/interactive/form/PDAcroFormTest.java @@ -26,6 +26,7 @@ import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationWidget; import org.apache.pdfbox.rendering.TestPDFToImage; import org.junit.After; import org.junit.Before; @@ -101,6 +102,34 @@ public void testFlatten() throws IOException } + /* + * Same as above but remove the page reference from the widget annotation + * before doing the flatten() to ensure that the widgets page reference is properly looked up + * (PDFBOX-3301) + */ + @Test + public void testFlattenWidgetNoRef() throws IOException + { + PDDocument testPdf = PDDocument.load(new File(IN_DIR, "AlignmentTests.pdf")); + PDAcroForm acroForm = testPdf.getDocumentCatalog().getAcroForm(); + for (PDField field : acroForm.getFieldTree()) { + for (PDAnnotationWidget widget : field.getWidgets()) { + widget.getCOSObject().removeItem(COSName.P); + } + } + testPdf.getDocumentCatalog().getAcroForm().flatten(); + assertTrue(testPdf.getDocumentCatalog().getAcroForm().getFields().isEmpty()); + File file = new File(OUT_DIR, "AlignmentTests-flattened-noRef.pdf"); + testPdf.save(file); + // compare rendering + TestPDFToImage testPDFToImage = new TestPDFToImage(TestPDFToImage.class.getName()); + if (!testPDFToImage.doTestFile(file, IN_DIR.getAbsolutePath(), OUT_DIR.getAbsolutePath())) + { + // don't fail, rendering is different on different systems, result must be viewed manually + System.out.println("Rendering of " + file + " failed or is not identical to expected rendering in " + IN_DIR + " directory"); + } + } + @After public void tearDown() throws IOException { diff --git a/pdfbox/src/test/resources/org/apache/pdfbox/pdmodel/interactive/form/AlignmentTests-flattened-noRef.pdf-1.png b/pdfbox/src/test/resources/org/apache/pdfbox/pdmodel/interactive/form/AlignmentTests-flattened-noRef.pdf-1.png new file mode 100644 index 0000000000000000000000000000000000000000..f5cc79cb9604f430e090beb44292b6736b58266b GIT binary patch literal 64491 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

OC&5qC#M+okgi5Q1#XE|cU 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�!d)N(r~bm4Ak61g$I-D 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 d0vWqJr!W!U&Yb@af@T&L Date: Sat, 2 Apr 2016 12:08:26 +0000 Subject: [PATCH 0018/2182] PDFBOX-3303: set widget connection to parent git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1737492 13f79535-47bb-0310-9956-ffa450edef68 --- .../pdfbox/pdmodel/interactive/form/PDTerminalField.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDTerminalField.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDTerminalField.java index 5a9b0515119..4fce12807b9 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDTerminalField.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDTerminalField.java @@ -192,6 +192,10 @@ public void setWidgets(List children) { COSArray kidsArray = COSArrayList.converterToCOSArray(children); getCOSObject().setItem(COSName.KIDS, kidsArray); + for (PDAnnotationWidget widget : children) + { + widget.getCOSObject().setItem(COSName.PARENT, this); + } } /** From 8fd8980b69c7ae23410694e1c9c8cd9900a521a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Lehmk=C3=BChler?= Date: Sun, 3 Apr 2016 20:20:10 +0000 Subject: [PATCH 0019/2182] PDFBOX-3273: replace List with List to increase accuracy git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1737606 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/fontbox/cff/CharStringHandler.java | 10 +-- .../apache/fontbox/cff/Type1CharString.java | 32 +++++----- .../apache/fontbox/cff/Type2CharString.java | 63 +++++++++++-------- 3 files changed, 57 insertions(+), 48 deletions(-) diff --git a/fontbox/src/main/java/org/apache/fontbox/cff/CharStringHandler.java b/fontbox/src/main/java/org/apache/fontbox/cff/CharStringHandler.java index 9fd53915983..8f29ab71e60 100644 --- a/fontbox/src/main/java/org/apache/fontbox/cff/CharStringHandler.java +++ b/fontbox/src/main/java/org/apache/fontbox/cff/CharStringHandler.java @@ -35,14 +35,14 @@ public abstract class CharStringHandler * @param sequence of CharStringCommands * */ - public List handleSequence(List sequence) + public List handleSequence(List sequence) { - Stack stack = new Stack(); + Stack stack = new Stack(); for (Object obj : sequence) { if (obj instanceof CharStringCommand) { - List results = handleCommand(stack, (CharStringCommand)obj); + List results = handleCommand(stack, (CharStringCommand)obj); stack.clear(); // this is basically returning the new stack if (results != null) { @@ -51,7 +51,7 @@ public List handleSequence(List sequence) } else { - stack.push((Integer)obj); + stack.push((Number)obj); } } return stack; @@ -63,5 +63,5 @@ public List handleSequence(List sequence) * @param numbers a list of numbers * @param command the CharStringCommand */ - public abstract List handleCommand(List numbers, CharStringCommand command); + public abstract List handleCommand(List numbers, CharStringCommand command); } \ No newline at end of file diff --git a/fontbox/src/main/java/org/apache/fontbox/cff/Type1CharString.java b/fontbox/src/main/java/org/apache/fontbox/cff/Type1CharString.java index ad222f4f166..cc7551892f9 100644 --- a/fontbox/src/main/java/org/apache/fontbox/cff/Type1CharString.java +++ b/fontbox/src/main/java/org/apache/fontbox/cff/Type1CharString.java @@ -139,7 +139,7 @@ private void render() width = 0; CharStringHandler handler = new CharStringHandler() { @Override - public List handleCommand(List numbers, CharStringCommand command) + public List handleCommand(List numbers, CharStringCommand command) { return Type1CharString.this.handleCommand(numbers, command); } @@ -147,7 +147,7 @@ public List handleCommand(List numbers, CharStringCommand comm handler.handleSequence(type1Sequence); } - private List handleCommand(List numbers, CharStringCommand command) + private List handleCommand(List numbers, CharStringCommand command) { commandCount++; String name = CharStringCommand.TYPE1_VOCABULARY.get(command.getKey()); @@ -158,7 +158,7 @@ private List handleCommand(List numbers, CharStringCommand com { if (isFlex) { - flexPoints.add(new Point2D.Float(numbers.get(0), numbers.get(1))); + flexPoints.add(new Point2D.Float(numbers.get(0).floatValue(), numbers.get(1).floatValue())); } else { @@ -173,7 +173,7 @@ else if ("vmoveto".equals(name)) if (isFlex) { // not in the Type 1 spec, but exists in some fonts - flexPoints.add(new Point2D.Float(0, numbers.get(0))); + flexPoints.add(new Point2D.Float(0f, numbers.get(0).floatValue())); } else { @@ -188,7 +188,7 @@ else if ("hmoveto".equals(name)) if (isFlex) { // not in the Type 1 spec, but exists in some fonts - flexPoints.add(new Point2D.Float(numbers.get(0), 0)); + flexPoints.add(new Point2D.Float(numbers.get(0).floatValue(), 0f)); } else { @@ -233,8 +233,8 @@ else if ("sbw".equals(name)) { if (numbers.size() >= 3) { - leftSideBearing = new Point2D.Float(numbers.get(0), numbers.get(1)); - width = numbers.get(2); + leftSideBearing = new Point2D.Float(numbers.get(0).floatValue(), numbers.get(1).floatValue()); + width = numbers.get(2).intValue(); current.setLocation(leftSideBearing); } } @@ -242,8 +242,8 @@ else if ("hsbw".equals(name)) { if (numbers.size() >= 2) { - leftSideBearing = new Point2D.Float(numbers.get(0), 0); - width = numbers.get(1); + leftSideBearing = new Point2D.Float(numbers.get(0).floatValue(), 0); + width = numbers.get(1).intValue(); current.setLocation(leftSideBearing); } } @@ -281,17 +281,17 @@ else if ("callothersubr".equals(name)) { if (numbers.size() >= 1) { - callothersubr(numbers.get(0)); + callothersubr(numbers.get(0).intValue()); } } else if ("div".equals(name)) { - int b = numbers.get(numbers.size() -1); - int a = numbers.get(numbers.size() -2); + float b = numbers.get(numbers.size() -1).floatValue(); + float a = numbers.get(numbers.size() -2).floatValue(); - int result = Math.round(a / (float) b); // TODO loss of precision, result should be float + float result = a / b; - List list = new ArrayList(numbers); + List list = new ArrayList(numbers); list.remove(list.size() - 1); list.remove(list.size() - 1); list.add(result); @@ -330,9 +330,9 @@ else if (name != null) * Sets the current absolute point without performing a moveto. * Used only with results from callothersubr */ - private void setcurrentpoint(int x, int y) + private void setcurrentpoint(Number x, Number y) { - current.setLocation(x, y); + current.setLocation(x.floatValue(), y.floatValue()); } /** diff --git a/fontbox/src/main/java/org/apache/fontbox/cff/Type2CharString.java b/fontbox/src/main/java/org/apache/fontbox/cff/Type2CharString.java index 2733f7a3707..8dbc63a1b9f 100644 --- a/fontbox/src/main/java/org/apache/fontbox/cff/Type2CharString.java +++ b/fontbox/src/main/java/org/apache/fontbox/cff/Type2CharString.java @@ -31,8 +31,8 @@ */ public class Type2CharString extends Type1CharString { - private int defWidthX = 0; - private int nominalWidthX = 0; + private float defWidthX = 0; + private float nominalWidthX = 0; private int pathCount = 0; private final List type2sequence; private final int gid; @@ -84,7 +84,7 @@ private void convertType1ToType2(List sequence) pathCount = 0; CharStringHandler handler = new CharStringHandler() { @Override - public List handleCommand(List numbers, CharStringCommand command) + public List handleCommand(List numbers, CharStringCommand command) { return Type2CharString.this.handleCommand(numbers, command); } @@ -93,7 +93,7 @@ public List handleCommand(List numbers, CharStringCommand comm } @SuppressWarnings(value = { "unchecked" }) - private List handleCommand(List numbers, CharStringCommand command) + private List handleCommand(List numbers, CharStringCommand command) { commandCount++; String name = CharStringCommand.TYPE2_VOCABULARY.get(command.getKey()); @@ -167,24 +167,24 @@ else if ("hvcurveto".equals(name)) } else if ("hflex".equals(name)) { - List first = Arrays.asList(numbers.get(0), 0, + List first = Arrays.asList(numbers.get(0), 0, numbers.get(1), numbers.get(2), numbers.get(3), 0); - List second = Arrays.asList(numbers.get(4), 0, - numbers.get(5), -numbers.get(2), + List second = Arrays.asList(numbers.get(4), 0, + numbers.get(5), -(numbers.get(2).floatValue()), numbers.get(6), 0); addCommandList(Arrays.asList(first, second), new CharStringCommand(8)); } else if ("flex".equals(name)) { - List first = numbers.subList(0, 6); - List second = numbers.subList(6, 12); + List first = numbers.subList(0, 6); + List second = numbers.subList(6, 12); addCommandList(Arrays.asList(first, second), new CharStringCommand(8)); } else if ("hflex1".equals(name)) { - List first = Arrays.asList(numbers.get(0), numbers.get(1), + List first = Arrays.asList(numbers.get(0), numbers.get(1), numbers.get(2), numbers.get(3), numbers.get(4), 0); - List second = Arrays.asList(numbers.get(5), 0, + List second = Arrays.asList(numbers.get(5), 0, numbers.get(6), numbers.get(7), numbers.get(8), 0); addCommandList(Arrays.asList(first, second), new CharStringCommand(8)); } @@ -194,11 +194,11 @@ else if ("flex1".equals(name)) int dy = 0; for(int i = 0; i < 5; i++) { - dx += numbers.get(i * 2); - dy += numbers.get(i * 2 + 1); + dx += numbers.get(i * 2).intValue(); + dy += numbers.get(i * 2 + 1).intValue(); } - List first = numbers.subList(0, 6); - List second = Arrays.asList(numbers.get(6), numbers.get(7), numbers.get(8), + List first = numbers.subList(0, 6); + List second = Arrays.asList(numbers.get(6), numbers.get(7), numbers.get(8), numbers.get(9), (Math.abs(dx) > Math.abs(dy) ? numbers.get(10) : -dx), (Math.abs(dx) > Math.abs(dy) ? -dy : numbers.get(10))); addCommandList(Arrays.asList(first, second), new CharStringCommand(8)); @@ -250,20 +250,19 @@ else if ("hhcurveto".equals(name)) return null; } - private List clearStack(List numbers, boolean flag) + private List clearStack(List numbers, boolean flag) { if (type1Sequence.isEmpty()) { if (flag) { - addCommand(Arrays.asList(0, numbers.get(0) + nominalWidthX), + addCommand(asNumberList(0f, numbers.get(0).floatValue() + nominalWidthX), new CharStringCommand(13)); - numbers = numbers.subList(1, numbers.size()); } else { - addCommand(Arrays.asList(0, defWidthX), + addCommand(asNumberList(0f, defWidthX), new CharStringCommand(13)); } } @@ -274,7 +273,7 @@ private List clearStack(List numbers, boolean flag) * @param numbers * @param horizontal */ - private void expandStemHints(List numbers, boolean horizontal) + private void expandStemHints(List numbers, boolean horizontal) { // TODO } @@ -297,11 +296,11 @@ private void closePath() CharStringCommand closepathCommand = new CharStringCommand(9); if (command != null && !closepathCommand.equals(command)) { - addCommand(Collections. emptyList(), closepathCommand); + addCommand(Collections. emptyList(), closepathCommand); } } - private void drawAlternatingLine(List numbers, boolean horizontal) + private void drawAlternatingLine(List numbers, boolean horizontal) { while (numbers.size() > 0) { @@ -312,7 +311,7 @@ private void drawAlternatingLine(List numbers, boolean horizontal) } } - private void drawAlternatingCurve(List numbers, boolean horizontal) + private void drawAlternatingCurve(List numbers, boolean horizontal) { while (numbers.size() > 0) { @@ -336,7 +335,7 @@ private void drawAlternatingCurve(List numbers, boolean horizontal) } } - private void drawCurve(List numbers, boolean horizontal) + private void drawCurve(List numbers, boolean horizontal) { while (numbers.size() > 0) { @@ -361,20 +360,30 @@ private void drawCurve(List numbers, boolean horizontal) } } - private void addCommandList(List> numbers, CharStringCommand command) + private void addCommandList(List> numbers, CharStringCommand command) { - for (List ns : numbers) + for (List ns : numbers) { addCommand(ns, command); } } - private void addCommand(List numbers, CharStringCommand command) + private void addCommand(List numbers, CharStringCommand command) { type1Sequence.addAll(numbers); type1Sequence.add(command); } + private List asNumberList(Float... a) + { + List list = new ArrayList(a.length); + for(int i = 0; i < a.length; i++) + { + list.add(a[i]); + } + return list; + } + private static List> split(List list, int size) { List> result = new ArrayList>(); From 7cc82ddb95c00ec0ef278c06e66e0585dec9c257 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Mon, 4 Apr 2016 18:57:15 +0000 Subject: [PATCH 0020/2182] PDFBOX-2941: keep zoom scales in a file, by Khyrul Bashar git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1737731 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/pdfbox/debugger/PDFDebugger.java | 1 + .../pdfbox/debugger/pagepane/PagePane.java | 7 ++-- .../debugger/streampane/StreamImageView.java | 8 ++-- .../apache/pdfbox/debugger/ui/ZoomMenu.java | 39 +++++++++++++++++-- 4 files changed, 46 insertions(+), 9 deletions(-) diff --git a/debugger/src/main/java/org/apache/pdfbox/debugger/PDFDebugger.java b/debugger/src/main/java/org/apache/pdfbox/debugger/PDFDebugger.java index 11bc176ab45..97954aa11a6 100644 --- a/debugger/src/main/java/org/apache/pdfbox/debugger/PDFDebugger.java +++ b/debugger/src/main/java/org/apache/pdfbox/debugger/PDFDebugger.java @@ -1212,6 +1212,7 @@ private void initTree() { File file = new File(currentFilePath); DocumentEntry documentEntry = new DocumentEntry(document, file.getName()); + ZoomMenu.getInstance().resetZoom(); tree.setModel(new PDFTreeModel(documentEntry)); // Root/Pages/Kids/[0] is not always the first page, so use the first row instead: tree.setSelectionPath(tree.getPathForRow(1)); diff --git a/debugger/src/main/java/org/apache/pdfbox/debugger/pagepane/PagePane.java b/debugger/src/main/java/org/apache/pdfbox/debugger/pagepane/PagePane.java index 40b30b9930d..94300c215b9 100644 --- a/debugger/src/main/java/org/apache/pdfbox/debugger/pagepane/PagePane.java +++ b/debugger/src/main/java/org/apache/pdfbox/debugger/pagepane/PagePane.java @@ -81,9 +81,11 @@ private void initUI() panel.add(label); panel.addAncestorListener(this); + zoomMenu = ZoomMenu.getInstance(); + zoomMenu.changeZoomSelection(zoomMenu.getPageZoomScale()); // render in a background thread: rendering is read-only, so this should be ok, despite // the fact that PDDocument is not officially thread safe - new RenderWorker(1, 0).execute(); + new RenderWorker(zoomMenu.getPageZoomScale(), 0).execute(); } /** @@ -103,15 +105,14 @@ public void actionPerformed(ActionEvent actionEvent) if (ZoomMenu.isZoomMenu(actionCommand) || RotationMenu.isRotationMenu(actionCommand)) { new RenderWorker(ZoomMenu.getZoomScale(), RotationMenu.getRotationDegrees()).execute(); + zoomMenu.setPageZoomScale(ZoomMenu.getZoomScale()); } } @Override public void ancestorAdded(AncestorEvent ancestorEvent) { - zoomMenu = ZoomMenu.getInstance(); zoomMenu.addMenuListeners(this); - zoomMenu.setZoomSelection(ZoomMenu.ZOOM_100_PERCENT); zoomMenu.setEnableMenu(true); rotationMenu = RotationMenu.getInstance(); diff --git a/debugger/src/main/java/org/apache/pdfbox/debugger/streampane/StreamImageView.java b/debugger/src/main/java/org/apache/pdfbox/debugger/streampane/StreamImageView.java index 6accf5ffc56..f3ee089aa2d 100644 --- a/debugger/src/main/java/org/apache/pdfbox/debugger/streampane/StreamImageView.java +++ b/debugger/src/main/java/org/apache/pdfbox/debugger/streampane/StreamImageView.java @@ -66,10 +66,13 @@ private void initUI() JPanel panel = new JPanel(); panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); + zoomMenu = ZoomMenu.getInstance(); + zoomMenu.changeZoomSelection(zoomMenu.getImageZoomScale()); + label = new JLabel(); label.setBorder(new LineBorder(Color.BLACK)); label.setAlignmentX(Component.CENTER_ALIGNMENT); - label.setIcon(new ImageIcon(image)); + addImage(zoomImage(image, zoomMenu.getImageZoomScale(), RotationMenu.getRotationDegrees())); panel.add(Box.createVerticalGlue()); panel.add(label); @@ -105,6 +108,7 @@ public void actionPerformed(ActionEvent actionEvent) if (ZoomMenu.isZoomMenu(actionCommand) || RotationMenu.isRotationMenu(actionCommand)) { addImage(zoomImage(image, ZoomMenu.getZoomScale(), RotationMenu.getRotationDegrees())); + zoomMenu.setImageZoomScale(ZoomMenu.getZoomScale()); } } @@ -117,9 +121,7 @@ private void addImage(Image img) @Override public void ancestorAdded(AncestorEvent ancestorEvent) { - zoomMenu = ZoomMenu.getInstance(); zoomMenu.addMenuListeners(this); - zoomMenu.setZoomSelection(ZoomMenu.ZOOM_100_PERCENT); zoomMenu.setEnableMenu(true); rotationMenu = RotationMenu.getInstance(); diff --git a/debugger/src/main/java/org/apache/pdfbox/debugger/ui/ZoomMenu.java b/debugger/src/main/java/org/apache/pdfbox/debugger/ui/ZoomMenu.java index f46de343c3e..179832e3d8a 100644 --- a/debugger/src/main/java/org/apache/pdfbox/debugger/ui/ZoomMenu.java +++ b/debugger/src/main/java/org/apache/pdfbox/debugger/ui/ZoomMenu.java @@ -42,7 +42,8 @@ private static class ZoomMenuItem extends JRadioButtonMenuItem } } - public static final String ZOOM_100_PERCENT = "100%"; + private float pageZoomScale = 1; + private float imageZoomScale = 1; private static final int[] ZOOMS = new int[] { 25, 50, 100, 200, 400 }; private static ZoomMenu instance; @@ -81,11 +82,12 @@ public static ZoomMenu getInstance() /** * Set the zoom selection. * - * @param selection zoom menu string, e.g. "100%". + * @param zoomValue, e.g. 1, 0.25, 4. * @throws IllegalArgumentException if the parameter doesn't belong to a zoom menu item. */ - public void setZoomSelection(String selection) + public void changeZoomSelection(float zoomValue) { + String selection = (int)(zoomValue*100) +"%"; for (Component comp : menu.getMenuComponents()) { JRadioButtonMenuItem menuItem = (JRadioButtonMenuItem) comp; @@ -132,4 +134,35 @@ public static float getZoomScale() } throw new IllegalStateException("no zoom menu item is selected"); } + + public float getPageZoomScale() + { + return pageZoomScale; + } + + public void setPageZoomScale(float pageZoomValue) + { + pageZoomScale = pageZoomValue; + } + + public float getImageZoomScale() + { + return imageZoomScale; + } + + public void setImageZoomScale(float imageZoomValue) + { + imageZoomScale = imageZoomValue; + } + + /** + * When a new file is loaded zoom values should be reset. + * + */ + public void resetZoom() + { + setPageZoomScale(1); + setImageZoomScale(1); + changeZoomSelection(1); + } } From 3ad9bc4328b919f6fb4e310aeda531b1834f7303 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Mon, 4 Apr 2016 18:59:28 +0000 Subject: [PATCH 0021/2182] PDFBOX-2941: show error dialog when error after drag 'n drop git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1737733 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/pdfbox/debugger/PDFDebugger.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/debugger/src/main/java/org/apache/pdfbox/debugger/PDFDebugger.java b/debugger/src/main/java/org/apache/pdfbox/debugger/PDFDebugger.java index 97954aa11a6..a81e515d196 100644 --- a/debugger/src/main/java/org/apache/pdfbox/debugger/PDFDebugger.java +++ b/debugger/src/main/java/org/apache/pdfbox/debugger/PDFDebugger.java @@ -270,7 +270,8 @@ public boolean importData(TransferSupport transferSupport) } catch (IOException e) { - throw new RuntimeException(e); + new ErrorDialog(e).setVisible(true); + return true; } catch (UnsupportedFlavorException e) { From 6bf8c264ce7ed5e0c8b4dbdfff0acbdc8045ac5f Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Tue, 5 Apr 2016 18:02:25 +0000 Subject: [PATCH 0022/2182] PDFBOX-3307: Enable AES128 encryption git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1737861 13f79535-47bb-0310-9956-ffa450edef68 --- .../encryption/StandardProtectionPolicy.java | 25 +++++++++++ .../encryption/StandardSecurityHandler.java | 7 ++- .../TestSymmetricKeyEncryption.java | 44 +++++++++++-------- 3 files changed, 55 insertions(+), 21 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/StandardProtectionPolicy.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/StandardProtectionPolicy.java index 7a687705b8f..e0156970d45 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/StandardProtectionPolicy.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/StandardProtectionPolicy.java @@ -38,6 +38,7 @@ public final class StandardProtectionPolicy extends ProtectionPolicy private AccessPermission permissions; private String ownerPassword = ""; private String userPassword = ""; + private boolean preferAES = false; /** * Creates an new instance of the standard protection policy @@ -108,4 +109,28 @@ public void setUserPassword(String userPassword) { this.userPassword = userPassword; } + + /** + * Tell whether AES encryption is preferred when several encryption methods are available for + * the chosen key length. The default is false. This setting is only relevant if the key length + * is 128 bits. + * + * @return + */ + public boolean isPreferAES() + { + return this.preferAES; + } + + /** + * Set whether AES encryption is preferred when several encryption methods are available for the + * chosen key length. The default is false. This setting is only relevant if the key length is + * 128 bits. + * + * @param preferAES + */ + public void setPreferAES(boolean preferAES) + { + this.preferAES = preferAES; + } } diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/StandardSecurityHandler.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/StandardSecurityHandler.java index 4a1203f25c4..4b15e6d6444 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/StandardSecurityHandler.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/StandardSecurityHandler.java @@ -109,8 +109,11 @@ private int computeVersionNumber() { return DEFAULT_VERSION; } - //TODO return 4 if keyLength is 128 to enable AES128 functionality - else if(keyLength == 256) + else if (keyLength == 128 && policy.isPreferAES()) + { + return 4; + } + else if (keyLength == 256) { return 5; } diff --git a/pdfbox/src/test/java/org/apache/pdfbox/encryption/TestSymmetricKeyEncryption.java b/pdfbox/src/test/java/org/apache/pdfbox/encryption/TestSymmetricKeyEncryption.java index 9733400ee2e..6a6094852cc 100644 --- a/pdfbox/src/test/java/org/apache/pdfbox/encryption/TestSymmetricKeyEncryption.java +++ b/pdfbox/src/test/java/org/apache/pdfbox/encryption/TestSymmetricKeyEncryption.java @@ -184,8 +184,7 @@ private void checkPerms(byte[] inputFileAsByteArray, String password, } /** - * Protect a document with a key and try to reopen it with that key and - * compare. + * Protect a document with a key and try to reopen it with that key and compare. * * @throws Exception If there is an unexpected error during the test. */ @@ -194,13 +193,16 @@ public void testProtection() throws Exception byte[] inputFileAsByteArray = getFileResourceAsByteArray("Acroform-PDFBOX-2333.pdf"); int sizePriorToEncryption = inputFileAsByteArray.length; - testSymmEncrForKeySize(40, sizePriorToEncryption, inputFileAsByteArray, + testSymmEncrForKeySize(40, false, sizePriorToEncryption, inputFileAsByteArray, USERPASSWORD, OWNERPASSWORD, permission); - testSymmEncrForKeySize(128, sizePriorToEncryption, inputFileAsByteArray, + testSymmEncrForKeySize(128, false, sizePriorToEncryption, inputFileAsByteArray, USERPASSWORD, OWNERPASSWORD, permission); - testSymmEncrForKeySize(256, sizePriorToEncryption, inputFileAsByteArray, + testSymmEncrForKeySize(128, true, sizePriorToEncryption, inputFileAsByteArray, + USERPASSWORD, OWNERPASSWORD, permission); + + testSymmEncrForKeySize(256, true, sizePriorToEncryption, inputFileAsByteArray, USERPASSWORD, OWNERPASSWORD, permission); } @@ -220,17 +222,20 @@ public void testProtectionInnerAttachment() throws Exception File extractedEmbeddedFile = extractEmbeddedFile(new ByteArrayInputStream(inputFileWithEmbeddedFileAsByteArray), "innerFile.pdf"); - testSymmEncrForKeySizeInner(40, sizeOfFileWithEmbeddedFile, + testSymmEncrForKeySizeInner(40, false, sizeOfFileWithEmbeddedFile, + inputFileWithEmbeddedFileAsByteArray, extractedEmbeddedFile, USERPASSWORD, OWNERPASSWORD); + + testSymmEncrForKeySizeInner(128, false, sizeOfFileWithEmbeddedFile, inputFileWithEmbeddedFileAsByteArray, extractedEmbeddedFile, USERPASSWORD, OWNERPASSWORD); - testSymmEncrForKeySizeInner(128, sizeOfFileWithEmbeddedFile, + testSymmEncrForKeySizeInner(128, true, sizeOfFileWithEmbeddedFile, inputFileWithEmbeddedFileAsByteArray, extractedEmbeddedFile, USERPASSWORD, OWNERPASSWORD); - testSymmEncrForKeySizeInner(256, sizeOfFileWithEmbeddedFile, + testSymmEncrForKeySizeInner(256, true, sizeOfFileWithEmbeddedFile, inputFileWithEmbeddedFileAsByteArray, extractedEmbeddedFile, USERPASSWORD, OWNERPASSWORD); } - private void testSymmEncrForKeySize(int keyLength, + private void testSymmEncrForKeySize(int keyLength, boolean preferAES, int sizePriorToEncr, byte[] inputFileAsByteArray, String userpassword, String ownerpassword, AccessPermission permission) throws IOException @@ -250,7 +255,7 @@ private void testSymmEncrForKeySize(int keyLength, srcContentStreamTab.add(bytes); } - PDDocument encryptedDoc = encrypt(keyLength, sizePriorToEncr, document, + PDDocument encryptedDoc = encrypt(keyLength, preferAES, sizePriorToEncr, document, prefix, permission, userpassword, ownerpassword); Assert.assertEquals(numSrcPages, encryptedDoc.getNumberOfPages()); @@ -270,7 +275,7 @@ private void testSymmEncrForKeySize(int keyLength, bytes); } - File pdfFile = new File(testResultsDir, prefix + keyLength + "-bit-decrypted.pdf"); + File pdfFile = new File(testResultsDir, prefix + keyLength + "-bit-" + (preferAES ? "AES" : "RC4") + "-decrypted.pdf"); encryptedDoc.setAllSecurityToBeRemoved(true); encryptedDoc.save(pdfFile); encryptedDoc.close(); @@ -278,13 +283,14 @@ private void testSymmEncrForKeySize(int keyLength, // encrypt with keylength and permission, save, check sizes before and after encryption // reopen, decrypt and return document - private PDDocument encrypt(int keyLength, int sizePriorToEncr, + private PDDocument encrypt(int keyLength, boolean preferAES, int sizePriorToEncr, PDDocument doc, String prefix, AccessPermission permission, String userpassword, String ownerpassword) throws IOException { AccessPermission ap = new AccessPermission(); StandardProtectionPolicy spp = new StandardProtectionPolicy(ownerpassword, userpassword, ap); spp.setEncryptionKeyLength(keyLength); + spp.setPreferAES(preferAES); spp.setPermissions(permission); // This must have no effect and should only log a warning. @@ -292,13 +298,13 @@ private PDDocument encrypt(int keyLength, int sizePriorToEncr, doc.protect(spp); - File pdfFile = new File(testResultsDir, prefix + keyLength + "-bit-encrypted.pdf"); + File pdfFile = new File(testResultsDir, prefix + keyLength + "-bit-" + (preferAES ? "AES" : "RC4") + "-encrypted.pdf"); doc.save(pdfFile); doc.close(); long sizeEncrypted = pdfFile.length(); Assert.assertTrue(keyLength - + "-bit encrypted pdf should not have same size as plain one", + + "-bit " + (preferAES ? "AES" : "RC4") + " encrypted pdf should not have same size as plain one", sizeEncrypted != sizePriorToEncr); PDDocument encryptedDoc; @@ -347,21 +353,21 @@ private File extractEmbeddedFile(InputStream pdfInputStream, String name) throws return resultFile; } - private void testSymmEncrForKeySizeInner(int keyLength, + private void testSymmEncrForKeySizeInner(int keyLength, boolean preferAES, int sizePriorToEncr, byte[] inputFileWithEmbeddedFileAsByteArray, File embeddedFilePriorToEncryption, String userpassword, String ownerpassword) throws IOException { PDDocument document = PDDocument.load(new ByteArrayInputStream(inputFileWithEmbeddedFileAsByteArray)); - PDDocument encryptedDoc = encrypt(keyLength, sizePriorToEncr, document, "ContainsEmbedded-", permission, userpassword, ownerpassword); + PDDocument encryptedDoc = encrypt(keyLength, preferAES, sizePriorToEncr, document, "ContainsEmbedded-", permission, userpassword, ownerpassword); - File decryptedFile = new File(testResultsDir, "DecryptedContainsEmbedded-" + keyLength + "-bit.pdf"); + File decryptedFile = new File(testResultsDir, "DecryptedContainsEmbedded-" + keyLength + "-bit-" + (preferAES ? "AES" : "RC4") + ".pdf"); encryptedDoc.setAllSecurityToBeRemoved(true); encryptedDoc.save(decryptedFile); - File extractedEmbeddedFile = extractEmbeddedFile(new FileInputStream(decryptedFile), "decryptedInnerFile-" + keyLength + "-bit.pdf"); + File extractedEmbeddedFile = extractEmbeddedFile(new FileInputStream(decryptedFile), "decryptedInnerFile-" + keyLength + "-bit-" + (preferAES ? "AES" : "RC4") + ".pdf"); - Assert.assertEquals(keyLength + "-bit decrypted inner attachment pdf should have same size as plain one", + Assert.assertEquals(keyLength + "-bit " + (preferAES ? "AES" : "RC4") + " decrypted inner attachment pdf should have same size as plain one", embeddedFilePriorToEncryption.length(), extractedEmbeddedFile.length()); // compare the two embedded files From b9c70df868a28ae910c16ce5e789cebbcca4e339 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Tue, 5 Apr 2016 18:11:57 +0000 Subject: [PATCH 0023/2182] PDFBOX-3308: add NUL and FF as name delimiters, as suggested by Andrea Vacondio git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1737865 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/pdfbox/pdfparser/BaseParser.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/BaseParser.java b/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/BaseParser.java index 379e72eb54d..a8541661ee8 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/BaseParser.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/BaseParser.java @@ -707,7 +707,8 @@ protected COSArray parseCOSArray() throws IOException protected boolean isEndOfName(int ch) { return ch == ASCII_SPACE || ch == ASCII_CR || ch == ASCII_LF || ch == 9 || ch == '>' || - ch == '<' || ch == '[' || ch =='/' || ch ==']' || ch ==')' || ch =='('; + ch == '<' || ch == '[' || ch =='/' || ch ==']' || ch ==')' || ch =='(' || + ch == 0 || ch == '\f'; } /** From f2c0dd0aba0b86d1ca65b4ec31615a5c46dd7a0b Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Thu, 7 Apr 2016 17:25:27 +0000 Subject: [PATCH 0024/2182] PDFBOX-3089: calculate the end of coutour index only once per endPtIndex value git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1738156 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/fontbox/ttf/GlyphRenderer.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/fontbox/src/main/java/org/apache/fontbox/ttf/GlyphRenderer.java b/fontbox/src/main/java/org/apache/fontbox/ttf/GlyphRenderer.java index 00e7274ed35..3deb8d96f33 100644 --- a/fontbox/src/main/java/org/apache/fontbox/ttf/GlyphRenderer.java +++ b/fontbox/src/main/java/org/apache/fontbox/ttf/GlyphRenderer.java @@ -63,13 +63,19 @@ public GeneralPath getPath() private Point[] describe(GlyphDescription gd) { int endPtIndex = 0; + int endPtOfContourIndex = -1; Point[] points = new Point[gd.getPointCount()]; for (int i = 0; i < gd.getPointCount(); i++) { - boolean endPt = gd.getEndPtOfContours(endPtIndex) == i; + if (endPtOfContourIndex == -1) + { + endPtOfContourIndex = gd.getEndPtOfContours(endPtIndex); + } + boolean endPt = endPtOfContourIndex == i; if (endPt) { endPtIndex++; + endPtOfContourIndex = -1; } points[i] = new Point(gd.getXCoordinate(i), gd.getYCoordinate(i), (gd.getFlags(i) & GlyfDescript.ON_CURVE) != 0, endPt); From c254cf204feac321e7079ef1a1ad613048385f5d Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Sat, 9 Apr 2016 15:35:06 +0000 Subject: [PATCH 0025/2182] PDFBOX-3312: avoid NPE if document wasn't loaded / fix javadoc git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1738360 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/pdfbox/pdmodel/PDDocument.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java index b8b583a99b2..4aa17b2c98e 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java @@ -1108,17 +1108,22 @@ public void save(OutputStream output) throws IOException } /** - * Save the PDF as an incremental update. This is only possible if the PDF was loaded from a file. + * Save the PDF as an incremental update. This is only possible if the PDF was loaded from a + * file or a stream, not if the document was created in PDFBox itself. * * @param output stream to write * @throws IOException if the output could not be written - * @throws IllegalStateException if the document was not loaded from a file. + * @throws IllegalStateException if the document was not loaded from a file or a stream. */ public void saveIncremental(OutputStream output) throws IOException { COSWriter writer = null; try { + if (pdfSource == null) + { + throw new IllegalStateException("document was not loaded from a file or a stream"); + } writer = new COSWriter(output, pdfSource); writer.write(this, signInterface); writer.close(); From ec144d0189e1390a514abb729e59a3fca19cb7e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Lehmk=C3=BChler?= Date: Tue, 12 Apr 2016 10:22:23 +0000 Subject: [PATCH 0026/2182] PDFBOX-3292: check the dictionary of a possible xref-stream to avoid false positives git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1738756 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/pdfbox/pdfparser/COSParser.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/COSParser.java b/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/COSParser.java index 90f7db9bd80..51ad3267ecd 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/COSParser.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/COSParser.java @@ -1216,8 +1216,13 @@ private long checkXRefStreamOffset(long startXRefOffset, boolean checkOnly) thro readObjectNumber(); readGenerationNumber(); readExpectedString(OBJ_MARKER, true); + // check the dictionary to avoid false positives + COSDictionary dict = parseCOSDictionary(); source.seek(startXRefOffset); - return startXRefOffset; + if (dict != null && "XRef".equals(dict.getNameAsString(COSName.TYPE))) + { + return startXRefOffset; + } } catch (IOException exception) { From b917ff1a0932000c96707db34658ecf637e67fb8 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Thu, 14 Apr 2016 18:18:33 +0000 Subject: [PATCH 0027/2182] PDFBOX-3305: Add method to allow drawing of image with custom matrix, by John Hewson git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1739150 13f79535-47bb-0310-9956-ffa450edef68 --- .../pdfbox/pdmodel/PDPageContentStream.java | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPageContentStream.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPageContentStream.java index 860c51cc046..62e257bd2d0 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPageContentStream.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPageContentStream.java @@ -613,6 +613,33 @@ public void drawImage(PDImageXObject image, float x, float y, float width, float restoreGraphicsState(); } + /** + * Draw an image at the origin with the given transformation matrix. + * + * @param image The image to draw. + * @param matrix The transformation matrix to apply to the image. + * + * @throws IOException If there is an error writing to the stream. + * @throws IllegalStateException If the method was called within a text block. + */ + public void drawImage(PDImageXObject image, Matrix matrix) throws IOException + { + if (inTextMode) + { + throw new IllegalStateException("Error: drawImage is not allowed within a text block."); + } + + saveGraphicsState(); + + AffineTransform transform = matrix.createAffineTransform(); + transform(new Matrix(transform)); + + writeOperand(resources.add(image)); + writeOperator("Do"); + + restoreGraphicsState(); + } + /** * Draw an inline image at the x,y coordinates, with the default size of the image. * From 6f16ae84e43fff6589edace358e9ee5007ecedbd Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Sat, 16 Apr 2016 20:52:43 +0000 Subject: [PATCH 0028/2182] PDFBOX-3317: copy outputIntents, avoid certain duplicates git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1739511 13f79535-47bb-0310-9956-ffa450edef68 --- .../pdfbox/multipdf/PDFMergerUtility.java | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/multipdf/PDFMergerUtility.java b/pdfbox/src/main/java/org/apache/pdfbox/multipdf/PDFMergerUtility.java index e984c1af267..d913345bc80 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/multipdf/PDFMergerUtility.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/multipdf/PDFMergerUtility.java @@ -49,6 +49,7 @@ import org.apache.pdfbox.pdmodel.common.PDStream; import org.apache.pdfbox.pdmodel.documentinterchange.logicalstructure.PDMarkInfo; import org.apache.pdfbox.pdmodel.documentinterchange.logicalstructure.PDStructureTreeRoot; +import org.apache.pdfbox.pdmodel.graphics.color.PDOutputIntent; import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotation; import org.apache.pdfbox.pdmodel.interactive.documentnavigation.outline.PDDocumentOutline; import org.apache.pdfbox.pdmodel.interactive.documentnavigation.outline.PDOutlineItem; @@ -429,6 +430,8 @@ public void appendDocument(PDDocument destination, PDDocument source) throws IOE destCatalog.getCOSObject().setItem(COSName.METADATA, newStream); } + mergeOutputIntents(cloner, srcCatalog, destCatalog); + // merge logical structure hierarchy if logical structure information is available in both source pdf and // destination pdf boolean mergeStructTree = false; @@ -538,6 +541,38 @@ public void appendDocument(PDDocument destination, PDDocument source) throws IOE } } + // copy outputIntents to destination, but avoid duplicate OutputConditionIdentifier, + // except when it is missing or is named "Custom". + private void mergeOutputIntents(PDFCloneUtility cloner, + PDDocumentCatalog srcCatalog, PDDocumentCatalog destCatalog) throws IOException + { + List srcOutputIntents = srcCatalog.getOutputIntents(); + List dstOutputIntents = destCatalog.getOutputIntents(); + for (PDOutputIntent srcOI : srcOutputIntents) + { + String srcOCI = srcOI.getOutputConditionIdentifier(); + if (srcOCI != null && !"Custom".equals(srcOCI)) + { + // is that identifier already there? + boolean skip = false; + for (PDOutputIntent dstOI : dstOutputIntents) + { + if (dstOI.getOutputConditionIdentifier().equals(srcOCI)) + { + skip = true; + break; + } + } + if (skip) + { + continue; + } + } + destCatalog.addOutputIntent(new PDOutputIntent((COSDictionary) cloner.cloneForNewDocument(srcOI))); + dstOutputIntents.add(srcOI); + } + } + private int nextFieldNum = 1; /** From 4e61c8d5189fe8da54362d273d5767522dacf317 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Sun, 17 Apr 2016 09:36:53 +0000 Subject: [PATCH 0029/2182] PDFBOX-2852: improve factory config git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1739565 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/pdfbox/pdmodel/fdf/XMLUtil.java | 6 ++++++ .../pdfbox/pdmodel/interactive/form/PDXFAResource.java | 6 ++++++ .../src/main/java/org/apache/xmpbox/xml/DomXmpParser.java | 6 ++++++ 3 files changed, 18 insertions(+) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/fdf/XMLUtil.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/fdf/XMLUtil.java index 5f114a1109f..6e65b832d2b 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/fdf/XMLUtil.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/fdf/XMLUtil.java @@ -58,6 +58,12 @@ public static Document parse(InputStream is) throws IOException try { DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); + builderFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); + builderFactory.setFeature("http://xml.org/sax/features/external-general-entities", false); + builderFactory.setFeature("http://xml.org/sax/features/external-parameter-entities", false); + builderFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); + builderFactory.setXIncludeAware(false); + builderFactory.setExpandEntityReferences(false); DocumentBuilder builder = builderFactory.newDocumentBuilder(); return builder.parse(is); } diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDXFAResource.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDXFAResource.java index aab6bcc7195..ec29e10836d 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDXFAResource.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDXFAResource.java @@ -150,6 +150,12 @@ else if (xfa.getCOSObject() instanceof COSStream) public Document getDocument() throws ParserConfigurationException, SAXException, IOException { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); + factory.setFeature("http://xml.org/sax/features/external-general-entities", false); + factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false); + factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); + factory.setXIncludeAware(false); + factory.setExpandEntityReferences(false); factory.setNamespaceAware(true); DocumentBuilder builder = factory.newDocumentBuilder(); return builder.parse(new ByteArrayInputStream(this.getBytes())); diff --git a/xmpbox/src/main/java/org/apache/xmpbox/xml/DomXmpParser.java b/xmpbox/src/main/java/org/apache/xmpbox/xml/DomXmpParser.java index b3709183e2a..ebb6dec816a 100644 --- a/xmpbox/src/main/java/org/apache/xmpbox/xml/DomXmpParser.java +++ b/xmpbox/src/main/java/org/apache/xmpbox/xml/DomXmpParser.java @@ -78,6 +78,12 @@ public DomXmpParser() throws XmpParsingException try { DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); + dbFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); + dbFactory.setFeature("http://xml.org/sax/features/external-general-entities", false); + dbFactory.setFeature("http://xml.org/sax/features/external-parameter-entities", false); + dbFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); + dbFactory.setXIncludeAware(false); + dbFactory.setExpandEntityReferences(false); dbFactory.setNamespaceAware(true); dBuilder = dbFactory.newDocumentBuilder(); nsFinder = new NamespaceFinder(); From 4b55d25f4d1eba96018b12da0fa26c4c533db24c Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Tue, 19 Apr 2016 16:02:02 +0000 Subject: [PATCH 0030/2182] PDFBOX-3319: correct handling of partially monospaced fonts git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1739952 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/fontbox/ttf/TTFSubsetter.java | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/fontbox/src/main/java/org/apache/fontbox/ttf/TTFSubsetter.java b/fontbox/src/main/java/org/apache/fontbox/ttf/TTFSubsetter.java index d11844fb2a5..895d2023d80 100755 --- a/fontbox/src/main/java/org/apache/fontbox/ttf/TTFSubsetter.java +++ b/fontbox/src/main/java/org/apache/fontbox/ttf/TTFSubsetter.java @@ -249,7 +249,14 @@ private byte[] buildHheaTable() throws IOException writeSInt16(out, h.getReserved4()); writeSInt16(out, h.getReserved5()); writeSInt16(out, h.getMetricDataFormat()); - writeUint16(out, glyphIds.subSet(0, h.getNumberOfHMetrics()).size()); + + // is there a GID >= numberOfHMetrics ? Then keep the last entry of original hmtx table + int hmetrics = glyphIds.subSet(0, h.getNumberOfHMetrics()).size(); + if (glyphIds.last() >= h.getNumberOfHMetrics()) + { + ++hmetrics; + } + writeUint16(out, hmetrics); out.flush(); return bos.toByteArray(); @@ -864,11 +871,21 @@ private byte[] buildHmtxTable() throws IOException HorizontalMetricsTable hm = ttf.getHorizontalMetrics(); byte [] buf = new byte[4]; InputStream is = ttf.getOriginalData(); + + // is there a GID >= numberOfHMetrics ? Then keep the last entry of original hmtx table + SortedSet gidSet = glyphIds; + if (glyphIds.last() >= h.getNumberOfHMetrics()) + { + // Create a deep copy of the glyph set that has the last entry + gidSet = new TreeSet(glyphIds); + gidSet.add(ttf.getHorizontalHeader().getNumberOfHMetrics() - 1); + } + try { is.skip(hm.getOffset()); long lastOff = 0; - for (Integer glyphId : glyphIds) + for (Integer glyphId : gidSet) { // offset in original file long off; From 80ed5863f9c5709b9576ccd8a2a6049f62f9111f Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Tue, 19 Apr 2016 16:16:23 +0000 Subject: [PATCH 0031/2182] PDFBOX-3319: skip default width 1000 git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1739958 13f79535-47bb-0310-9956-ffa450edef68 --- .../pdfbox/pdmodel/font/PDCIDFontType2Embedder.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType2Embedder.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType2Embedder.java index 672edfbf82b..f9aa14b0123 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType2Embedder.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType2Embedder.java @@ -277,7 +277,12 @@ private void buildWidths(Map cidToGid) throws IOException for (int cid : keys) { int gid = cidToGid.get(cid); - float width = ttf.getHorizontalMetrics().getAdvanceWidth(gid) * scaling; + long width = Math.round(ttf.getHorizontalMetrics().getAdvanceWidth(gid) * scaling); + if (width == 1000) + { + // skip default width + continue; + } // c [w1 w2 ... wn] if (prev != cid - 1) { @@ -285,7 +290,7 @@ private void buildWidths(Map cidToGid) throws IOException widths.add(COSInteger.get(cid)); // c widths.add(ws); } - ws.add(COSInteger.get(Math.round(width))); // wi + ws.add(COSInteger.get(width)); // wi prev = cid; } cidFont.setItem(COSName.W, widths); From 1f33c4565c2f040565ec8134172ea6bb2d3fe177 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Lehmk=C3=BChler?= Date: Wed, 20 Apr 2016 15:58:55 +0000 Subject: [PATCH 0032/2182] PDFBOX-3281: ignore encoding parameter when writing html output git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1740161 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/pdfbox/tools/ExtractText.java | 10 ++++++-- .../org/apache/pdfbox/tools/PDFText2HTML.java | 25 ++++++------------- 2 files changed, 16 insertions(+), 19 deletions(-) diff --git a/tools/src/main/java/org/apache/pdfbox/tools/ExtractText.java b/tools/src/main/java/org/apache/pdfbox/tools/ExtractText.java index 0541a7b113a..bed5bd0b03d 100644 --- a/tools/src/main/java/org/apache/pdfbox/tools/ExtractText.java +++ b/tools/src/main/java/org/apache/pdfbox/tools/ExtractText.java @@ -49,8 +49,9 @@ public final class ExtractText private static final String SORT = "-sort"; private static final String IGNORE_BEADS = "-ignoreBeads"; private static final String DEBUG = "-debug"; - // jjb - added simple HTML output private static final String HTML = "-html"; + + private static final String STD_ENCODING = "UTF-8"; /* * debug flag @@ -93,7 +94,7 @@ public void startExtraction( String[] args ) throws IOException boolean sort = false; boolean separateBeads = true; String password = ""; - String encoding = "UTF-8"; + String encoding = STD_ENCODING; String pdfFile = null; String outputFile = null; // Defaults to text files @@ -204,6 +205,11 @@ else if( args[i].equals( CONSOLE ) ) } else { + if (toHTML && !STD_ENCODING.equals(encoding)) + { + encoding = STD_ENCODING; + System.out.println("The encoding parameter is ignored when writing html output."); + } output = new OutputStreamWriter( new FileOutputStream( outputFile ), encoding ); } diff --git a/tools/src/main/java/org/apache/pdfbox/tools/PDFText2HTML.java b/tools/src/main/java/org/apache/pdfbox/tools/PDFText2HTML.java index 4a55ebb1ddf..24ab30c7850 100644 --- a/tools/src/main/java/org/apache/pdfbox/tools/PDFText2HTML.java +++ b/tools/src/main/java/org/apache/pdfbox/tools/PDFText2HTML.java @@ -39,7 +39,6 @@ public class PDFText2HTML extends PDFTextStripper { private static final int INITIAL_PDF_TO_HTML_BYTES = 8192; - private boolean onFirstPage = true; private final FontState fontState = new FontState(); /** @@ -64,34 +63,26 @@ public PDFText2HTML() throws IOException * * @throws IOException * If there is a problem writing out the header to the document. + * @deprecated deprecated, use {@link #startDocument(PDDocument)} */ protected void writeHeader() throws IOException + { + } + + @Override + protected void startDocument(PDDocument document) throws IOException { StringBuilder buf = new StringBuilder(INITIAL_PDF_TO_HTML_BYTES); buf.append("\n"); buf.append(""); buf.append("").append(escape(getTitle())).append("\n"); - buf.append("\n"); + buf.append("\n"); buf.append("\n"); buf.append("\n"); super.writeString(buf.toString()); } - - /** - * {@inheritDoc} - */ - @Override - protected void writePage() throws IOException - { - if (onFirstPage) - { - writeHeader(); - onFirstPage = false; - } - super.writePage(); - } - + /** * {@inheritDoc} */ From 102c41f1e73b2b8b01b93c52751d6fdff870be39 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Wed, 20 Apr 2016 17:13:05 +0000 Subject: [PATCH 0033/2182] PDFBOX-2852: close document git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1740174 13f79535-47bb-0310-9956-ffa450edef68 --- .../pdfbox/preflight/action/pdfa1b/AbstractTestAction.java | 1 + 1 file changed, 1 insertion(+) diff --git a/preflight/src/test/java/org/apache/pdfbox/preflight/action/pdfa1b/AbstractTestAction.java b/preflight/src/test/java/org/apache/pdfbox/preflight/action/pdfa1b/AbstractTestAction.java index 6f9aa80d3d3..a2000f6becc 100644 --- a/preflight/src/test/java/org/apache/pdfbox/preflight/action/pdfa1b/AbstractTestAction.java +++ b/preflight/src/test/java/org/apache/pdfbox/preflight/action/pdfa1b/AbstractTestAction.java @@ -135,5 +135,6 @@ protected void valid(COSDictionary action, boolean valid, String expectedCode) t assertTrue(errors.isEmpty()); } } + ctx.getDocument().close(); } } From 3a72d602c920388e86f46c9318e503751dcf57aa Mon Sep 17 00:00:00 2001 From: Maruan Sahyoun Date: Fri, 22 Apr 2016 15:24:10 +0000 Subject: [PATCH 0034/2182] PDFBOX-2852: fix Javadoc for PDField.getWidgets() git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1740540 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/pdfbox/pdmodel/interactive/form/PDField.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDField.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDField.java index 1729ddd094b..b8e6586e875 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDField.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDField.java @@ -131,7 +131,7 @@ else if (parent != null) * For {@link PDNonTerminalField} the list will be empty as non terminal fields * have no visual representation in the form. * - * @return A non-null string. + * @return @return a List of {@link PDAnnotationWidget} annotations. */ public abstract List getWidgets(); From 3b0d07e5d337aa486ecb20d024bd51e66ffe86d4 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Fri, 22 Apr 2016 15:42:32 +0000 Subject: [PATCH 0035/2182] PDFBOX-3323: add possibility to set info and xmp after merge git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1740546 13f79535-47bb-0310-9956-ffa450edef68 --- .../pdfbox/multipdf/PDFMergerUtility.java | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/multipdf/PDFMergerUtility.java b/pdfbox/src/main/java/org/apache/pdfbox/multipdf/PDFMergerUtility.java index d913345bc80..eca69d4aad3 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/multipdf/PDFMergerUtility.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/multipdf/PDFMergerUtility.java @@ -45,6 +45,7 @@ import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.PDResources; import org.apache.pdfbox.pdmodel.PageMode; +import org.apache.pdfbox.pdmodel.common.PDMetadata; import org.apache.pdfbox.pdmodel.common.PDNumberTreeNode; import org.apache.pdfbox.pdmodel.common.PDStream; import org.apache.pdfbox.pdmodel.documentinterchange.logicalstructure.PDMarkInfo; @@ -71,6 +72,8 @@ public class PDFMergerUtility private String destinationFileName; private OutputStream destinationStream; private boolean ignoreAcroFormErrors = false; + private PDDocumentInformation destinationDocumentInformation = null; + private PDMetadata destinationMetadata = null; /** * Instantiate a new PDFMergerUtility. @@ -121,6 +124,50 @@ public void setDestinationStream(OutputStream destStream) destinationStream = destStream; } + /** + * Get the destination document information that is to be set in {@link #mergeDocuments(org.apache.pdfbox.io.MemoryUsageSetting) + * }. The default is null, which means that it is ignored. + * + * @return The destination document information. + */ + public PDDocumentInformation getDestinationDocumentInformation() + { + return destinationDocumentInformation; + } + + /** + * Set the destination document information that is to be set in {@link #mergeDocuments(org.apache.pdfbox.io.MemoryUsageSetting) + * }. The default is null, which means that it is ignored. + * + * @param info The destination document information. + */ + public void setDestinationDocumentInformation(PDDocumentInformation info) + { + destinationDocumentInformation = info; + } + + /** + * Set the destination metadata that is to be set in {@link #mergeDocuments(org.apache.pdfbox.io.MemoryUsageSetting) + * }. The default is null, which means that it is ignored. + * + * @return The destination metadata. + */ + public PDMetadata getDestinationMetadata() + { + return destinationMetadata; + } + + /** + * Set the destination metadata that is to be set in {@link #mergeDocuments(org.apache.pdfbox.io.MemoryUsageSetting) + * }. The default is null, which means that it is ignored. + * + * @param meta The destination metadata. + */ + public void setDestinationMetadata(PDMetadata meta) + { + destinationMetadata = meta; + } + /** * Add a source file to the list of files to merge. * @@ -213,6 +260,17 @@ public void mergeDocuments(MemoryUsageSetting memUsageSetting) throws IOExceptio tobeclosed.add(source); appendDocument(destination, source); } + + // optionally set meta data + if (destinationDocumentInformation != null) + { + destination.setDocumentInformation(destinationDocumentInformation); + } + if (destinationMetadata != null) + { + destination.getDocumentCatalog().setMetadata(destinationMetadata); + } + if (destinationStream == null) { destination.save(destinationFileName); From 74216ccf077998ab9fda35da9f0ce5dc7320caea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Lehmk=C3=BChler?= Date: Fri, 22 Apr 2016 16:56:50 +0000 Subject: [PATCH 0036/2182] prepare 2.0.1 release git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1740565 13f79535-47bb-0310-9956-ffa450edef68 --- RELEASE-NOTES.txt | 1268 +-------------------------------------------- 1 file changed, 23 insertions(+), 1245 deletions(-) diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt index 9cd461fa045..ea785c48e8b 100644 --- a/RELEASE-NOTES.txt +++ b/RELEASE-NOTES.txt @@ -1,1265 +1,43 @@ -Release Notes -- Apache PDFBox -- Version 2.0.0-RC3 +Release Notes -- Apache PDFBox -- Version 2.0.1 Introduction ------------ The Apache PDFBox library is an open source Java tool for working with PDF documents. -This is the long awaited final release of PDFBox 2.0.0. It contains a lot of improvements, -fixes and refactorings. +This is an incremental bugfix release based on the earlier 2.0.0 release. It contains +a couple of fixes and small improvements. For more details on these changes and all the other fixes and improvements included in this release, please refer to the following issues on the PDFBox issue tracker at https://issues.apache.org/jira/browse/PDFBOX. -Sub-task - -[PDFBOX-1869] - Implementation for ShadingType 1 -[PDFBOX-1870] - PDFunctionType0 incorrect -[PDFBOX-2117] - AxialShadingContext is slow -[PDFBOX-2279] - Text with gradient not shown -[PDFBOX-2529] - Preflight: mention the page on which a problem has been found -[PDFBOX-2531] - better error message on not yet read stream -[PDFBOX-2535] - mention subtype in COSStream IOException -[PDFBOX-2536] - More specific TIFFFaxDecoder exceptions -[PDFBOX-2537] - do not discard underlying cause when creating validation error -[PDFBOX-2611] - possibly incorrect error message "Hexa String must have only Hexadecimal Characters" in preflight -[PDFBOX-2612] - error "Destination contains invalid page reference 'null'" is not detected by preflight -[PDFBOX-2613] - Conflicting /N information for OutputIntent not detected by preflight -[PDFBOX-2614] - missing /Type/FontDescriptor not detected by preflight -[PDFBOX-2619] - XMP dates contain time zone, while document info dates do not, and this isn't detected by preflight -[PDFBOX-2625] - Preflight error: The character with CID 0 should have a width equals to 57.0, but has 57.78 -[PDFBOX-2627] - Add block composer to handle multiline text -[PDFBOX-2630] - "loop in destinations" not detected by preflight -[PDFBOX-2647] - Check thumbnails in XMP metadata -[PDFBOX-2718] - Allow to create new AcroForm fields from scratch -[PDFBOX-2783] - Remove getCOSDictionary() method, adjust getCOSObject() return type -[PDFBOX-2849] - fix problems with setting existing AcroForm buttons -[PDFBOX-2863] - Support the comb flag for PDF forms -[PDFBOX-2877] - Wrong text placement for autosize fields compared to Adobe generated -[PDFBOX-2889] - Support appearance generation for choice fields -[PDFBOX-2900] - PDF Debugger doesn't print inline images correctly -[PDFBOX-2993] - Create a PDTransparencyGroup for added code clarity -[PDFBOX-2994] - Rename PDGroup to PDTransparencyGroupAttributes -[PDFBOX-3051] - COSArray.getObject() incorrect handling of indirect reference to COSNull -[PDFBOX-3052] - NPE in PDFStreamEngine.ShowText when no font set -[PDFBOX-3053] - Text extraction fails with type 3 fonts -[PDFBOX-3057] - NPE in CFFParser.parseType1Dicts() -[PDFBOX-3060] - Catalog cannot be found -[PDFBOX-3061] - Word concatenation in 2.0 not in 1.8 -[PDFBOX-3062] - Text extraction and height different in 2.0 -[PDFBOX-3068] - Null metadata in 2.0 in some files that had metadata in 1.8.10 with old parser -[PDFBOX-3112] - Avoid crazy /Length1 values in font descriptor -[PDFBOX-3123] - Text extraction garbled in this file, was OK in 1.8 -[PDFBOX-3125] - IndexOutOfBoundsException in PDFont.getWidth() -[PDFBOX-3126] - IndexOutOfBoundsException in PfbParser.parsePfb -[PDFBOX-3127] - Text with vertical font not extracted correctly -[PDFBOX-3129] - NullPointerException in PDFStreamEngine.showText() -[PDFBOX-3186] - Parsing fails when XRef stream object is 1 byte later -[PDFBOX-3208] - The trailer rebuild mechnism doesn't work -[PDFBOX-3264] - One 32kb truncated file causes OOM in 2.0.0-trunk - Bug -[PDFBOX-31] - bug with the Type3 font -[PDFBOX-37] - Text Extraction Weirdness -[PDFBOX-40] - Font problem when setting form value -[PDFBOX-53] - Problem getting value from PDRadioCollection -[PDFBOX-54] - please correct the SetField example -[PDFBOX-62] - Incorrect (zero) character widths returned in some docs -[PDFBOX-101] - ImportXFDF results in PDF with larger text fields -[PDFBOX-123] - too many space made in extracted text file -[PDFBOX-129] - Error when setting the value of a combo box to " " -[PDFBOX-159] - Field renaming character set problem -[PDFBOX-161] - java.util.EmptyStackException from PDFTextStripper.writeText -[PDFBOX-166] - ConvertColorSpace RGB to CMYK -[PDFBOX-198] - Tiff image problems -[PDFBOX-205] - Miscellaneous errors on valid files -[PDFBOX-239] - PDFToImage prints every word at the start of the line -[PDFBOX-283] - Character encoding/appearance issues when filling forms -[PDFBOX-297] - Printing fails -[PDFBOX-308] - Unknown encoding for 'UniJIS-UCS2-H' -[PDFBOX-317] - PDFont.getStringWidth() returns incorrect values -[PDFBOX-326] - TrueType and characterHorizontalDisplacement -[PDFBOX-412] - Failure to render PDFs with embedded fonts -[PDFBOX-427] - ArrayIndexOutOfBoundsException in drawString -[PDFBOX-447] - Image Convert Issue -[PDFBOX-451] - PDFImageWriter does not convert chinese PDF correctly -[PDFBOX-465] - invalid date formats -[PDFBOX-484] - Spaces, numbers and some letters not display correctly -[PDFBOX-488] - Invalid memory access of location 00000000 eip=968f5aa7 (MAC OS X) -[PDFBOX-490] - Pdf Printing of text from embedded fonts -[PDFBOX-501] - Open a trueType Font PDF, content become square box -[PDFBOX-538] - CryptographyException on Adobe Distiller generated file -[PDFBOX-587] - build script should support building without an internet connection -[PDFBOX-648] - PdfBox can't be buit from behind a firewall/proxy -[PDFBOX-649] - loading an fdf containing a file attachment throws IOException -[PDFBOX-657] - PDFToImage does not work with certain fonts (for eg. PDF documents created by MS Office and OpenOffice) -[PDFBOX-664] - Incorrect rendering of Slovak language PDF -[PDFBOX-677] - Lines not showing in PrintPDF print-out (Table borders and SVG figures) -[PDFBOX-723] - Our test hangs with custom pdf file on operation PDPage.convertToImage() -[PDFBOX-725] - Text extraction fails due to font problem with Type0, supplement-0 font -[PDFBOX-728] - Text extracted from a TeX-created PDF file comes in some form of hex encoding -[PDFBOX-778] - OutOfMemory when extracting text from pdf -[PDFBOX-785] - Spliting a PDF creates unnecessarily large files -[PDFBOX-816] - 1.2.1 - PDFTextStripper* uses different Y values when cropbox has non-zero Y: not so for X coordinates. -[PDFBOX-823] - NullPointerException in DateConverter.toISO8601(DateConverter.java:221) -[PDFBOX-833] - Wrong encoding with Type1C font when specific encoding is defined -[PDFBOX-837] - Wrong RevisionNumber when disabling all permissions and using 128bit encryption -[PDFBOX-877] - processOperator breaks contract - never throws IOException -[PDFBOX-904] - Potential issue with COSString and UTF-16-encoded Strings. -[PDFBOX-905] - NullPointerException when writing pdf to image -[PDFBOX-908] - Gracefull handle corrupt PDFs -[PDFBOX-923] - pdf gets messed up when updated with xfdf data -[PDFBOX-924] - Image not getting rendered correctly.. -[PDFBOX-932] - Swedish characters are garbled in form -[PDFBOX-934] - ImageToPDF.createPDFFromImage causes problems for certain TIFF inputs -[PDFBOX-940] - [pdmodel.font.PDFont] Error: Could not parse predefined CMAP file for 'PDFXC-Indentity0-0' -[PDFBOX-962] - All sort of Problems when importing Xfdf files into PDFs -> damaged pdfs and NPEs -[PDFBOX-965] - Printing of PDF with embedded OTF/TTF fonts is not working -[PDFBOX-984] - When create images from PDF File with characters from PT-BR it´s printing wrong -[PDFBOX-988] - pdmodel.font.PDSimpleFont hanging on TrueType font (ubuntu) -[PDFBOX-989] - Scale Pdf: Fit to Printable Area -[PDFBOX-1002] - Form field not rendered after being processed by pdfbox-1.1.0, wrong position of same field in pdfbox-1.5.0 -[PDFBOX-1007] - Maven performs textual filtering of binary resources [patch] -[PDFBOX-1019] - PDF conversion to image crashes the JVM -[PDFBOX-1020] - Can't read embedded font YDLRUT+ArialMT -[PDFBOX-1036] - FDFExport/Import gives strange results -[PDFBOX-1058] - Converting PDF to Image gives error and the image generated is of poor quality -[PDFBOX-1060] - convertToImage includes "ghost" annotation outlines -[PDFBOX-1069] - Ubuntu throws exceptions when fonts missing -[PDFBOX-1071] - Can not generate chinese character PDF file -[PDFBOX-1074] - TIFFFaxDecoder5 when using PDFImageWriter -[PDFBOX-1086] - Error when decoding CCITT compressed data that contains EOLs, fill bits etc. -[PDFBOX-1087] - FDF parsing is unreliable when xref are missing -[PDFBOX-1107] - PDF created by Bullzip PDF Printer / www.bullzip.com / Freeware Edition shows weird characters -[PDFBOX-1109] - Data corruption related to scratch file use -[PDFBOX-1134] - fontbox not decoding font correctly for all characters -[PDFBOX-1147] - Printing a PDF with an image inside show black. -[PDFBOX-1148] - PDF with embedded fonts (Identity-H) not print. -[PDFBOX-1152] - Gets scrambled japanese text while reading a PDF file -[PDFBOX-1155] - setSuppressDuplicateOverlappingText sometimes removes characters that it shouldn't -[PDFBOX-1164] - Inline image parsing error causes RuntimeException + FIX -[PDFBOX-1206] - TrueType glyphs render incorrectly -[PDFBOX-1207] - PDFPageProcessor.processStream() take 10 minutes to return -[PDFBOX-1219] - org.apache.jempbox.impl.DateConverter unable to parse correct date value -[PDFBOX-1231] - AcroForm appearance generator -[PDFBOX-1234] - NPE at org.apache.pdfbox.pdmodel.interactive.form.PDAppearance.calculateFontSize(PDAppearance.java:551) -[PDFBOX-1242] - Handle non ISO-8859-1 chars with drawString -[PDFBOX-1250] - CFF to Type1 Font conversion is missing/corrupting the font metrics -[PDFBOX-1268] - OutOfMemory Error because of huge colors -[PDFBOX-1273] - java.io.IOException: Error: Unknown annotation type null -[PDFBOX-1276] - java.lang.NullPointerException on trying to set value for PDTextBox in pdf file. -[PDFBOX-1278] - PDF file containing PDCIDFontType0 (PDType1CFont) does not render correctly to image -[PDFBOX-1282] - Unicode characters displayed with wrong glyps because of interpretation as 8 bit strings -[PDFBOX-1283] - Unicode characters displayed with wrong Advance -[PDFBOX-1292] - Rendering of certain documents results in large tracts of blank space - even though contents can be extracted -[PDFBOX-1296] - Warnung: Changing font on < > from to the default font -[PDFBOX-1301] - Wrong characters in HTML/TXT file from PDF containing scanned pages/images -[PDFBOX-1302] - Got ArrayIndexOutOfBoundsException in parsing a Chinese ttf file. -[PDFBOX-1304] - Text extraction meets "Could not parse predefined CMAP" and returns just a small part of the content containing garbage chars. -[PDFBOX-1307] - extracted images from a PDF sometimes come out inverted -[PDFBOX-1321] - PDF rendered as black box -[PDFBOX-1325] - Converting page to png creates an empty image -[PDFBOX-1332] - Some inline font is can not parsed out -[PDFBOX-1336] - JVM Crashes on Linux OS + Sun JVM + PDFBox -[PDFBOX-1342] - Tags not fully preserved when merging PDFs. -[PDFBOX-1348] - ExtractImages jpg and tiff picture from pdf but color wrong -[PDFBOX-1351] - False paragraph caused by superscript (1.7 regression) -[PDFBOX-1372] - NullPointerException with loadDescriptorDictionary -[PDFBOX-1391] - Document with "embedded subset" fonts is displayed incorrect -[PDFBOX-1403] - Retrieve FontDescription from descendant font -[PDFBOX-1405] - Non-Ascii chars are not decoded correctly by pdfbox but works fine with pdftotext -[PDFBOX-1412] - NullPointerException when getting fields from a PDF file -[PDFBOX-1413] - Spaces replaced by é when exporting image -[PDFBOX-1414] - EXCEPTION_ACCESS_VIOLATION in fontmanager.dll -[PDFBOX-1419] - PDField.setValue is not behave correctly -[PDFBOX-1426] - JVM crashes when trying to process the attached pdf's -[PDFBOX-1435] - text is obscured by the Images -[PDFBOX-1442] - bar chart converted from PDF is totally a black area. -[PDFBOX-1452] - Greek Pdfs print out wrong characters -[PDFBOX-1466] - Rendering of pattern colorspace fails -[PDFBOX-1474] - PDDocument.decrypt does not throws InvalidPasswordException -[PDFBOX-1478] - Problem with printing landscape document -[PDFBOX-1506] - Incorrect visualization of PDF document via PageDrawer -[PDFBOX-1511] - pdfMerger App produces Garbage -[PDFBOX-1512] - TextPositionComparator is not compatible with Java 7 -[PDFBOX-1533] - When merging certain PDF's several odd looking empty pages occur in the result -[PDFBOX-1541] - expected='endstream' actual='' failure to parse -[PDFBOX-1550] - Helv vs. Helvetica font names cause PDField.setValue to fail -[PDFBOX-1570] - PDFImageWriter creates black boxes for some images in the pdf -[PDFBOX-1574] - ImportFDF fails to do anything -[PDFBOX-1576] - StackOverflowError [COSDictionary.toString(COSDictionary.java:1418)] -[PDFBOX-1585] - org.apache.pdfbox.util.PDFTextStripper.getText() causes thread to block indefinitely -[PDFBOX-1595] - PDFMerger failed with the following exception: java.lang.NullPointerException -[PDFBOX-1604] - FontBox is not storing all subroutines for CID-Keyed OTF CFF fonts possibly leading to rendering / width issues -[PDFBOX-1606] - NonSequentialPDFParser produces garbage text in document info -[PDFBOX-1607] - StringIndexOutOfBoundsException in PDFParser -[PDFBOX-1608] - Rendering problem with Java 7 update 21 -[PDFBOX-1617] - Null pointer exception -[PDFBOX-1618] - Split PDF file to single page files, some files are inflated in size -[PDFBOX-1620] - Missing text in pdf reader view -[PDFBOX-1622] - TextNormalize init not thread-safe, may lead to infinite loop -[PDFBOX-1625] - java.lang.IndexOutOfBoundsException at writing PDF file -[PDFBOX-1627] - Exception in thread "main" java.lang.NullPointerException -[PDFBOX-1628] - Type 3 Fonts are not processed by PDPage.createImage -[PDFBOX-1629] - Null PointerException -[PDFBOX-1630] - An interesting Exception error -[PDFBOX-1631] - Group Exception -[PDFBOX-1632] - Exception with validation -[PDFBOX-1633] - DateConverter needs to work -[PDFBOX-1637] - Faulty documentation of PDStream.getInputStreamAsString() -[PDFBOX-1638] - PDCcitt doesn't use color space -[PDFBOX-1639] - Infinite loop with PDFParser used by tika. -[PDFBOX-1642] - NPE when parsing XMP schema definition with "closed Choice" value type -[PDFBOX-1643] - Check for missing validation processes does not work properly in Preflight -[PDFBOX-1651] - PDFBox doesn't read the permission bits correct. PDDocument.getCurrentAccessPermission().canPrint() is allways returning true irrespective of the document print permissions -[PDFBOX-1653] - Fix pdfbox eating up big chunks of memory for identical CID mappings -[PDFBOX-1654] - Wasted work in XMLUtil.getNodeValue -[PDFBOX-1655] - Wasted work (or incorrect behavior) in PDCIDFontType2Font.readCIDToGIDMapping -[PDFBOX-1657] - glyph contours missing -[PDFBOX-1658] - TTC fonts not supported for substitution -[PDFBOX-1659] - Preflight 2.0.0 doesn't properly identify PDFs with encryption -[PDFBOX-1660] - Error 6.2.4 results in description that looks more like the one belonging to 6.2.3 -[PDFBOX-1663] - Hello World using a TrueType font ArrayIndexOutOfBoundsException -[PDFBOX-1664] - NullPointerException in PDType1Font.java -[PDFBOX-1666] - Missing StemV font descriptor entry when embedding AFM fonts -[PDFBOX-1668] - Loading a Russian PDF never finishes -[PDFBOX-1670] - Printing pages rotated by 180 degrees is not working -[PDFBOX-1671] - Error printing document java.lang.ArrayIndexOutOfBoundsException: 346 -[PDFBOX-1672] - Some characteres are missing after print thru PDFBox -[PDFBOX-1674] - Preflight doesn't correctly parse PDF if obj identifier not followed by line terminator -[PDFBOX-1678] - Convert to image problem -[PDFBOX-1679] - java.io.IOException: Error: Expected an integer type, actual='f' -[PDFBOX-1681] - java.lang.IllegalArgumentException: Color parameter outside of expected range: Red -[PDFBOX-1683] - 2.0 build fails -[PDFBOX-1688] - File with embedded subset renders no text -[PDFBOX-1689] - Partial failure to render PDF -[PDFBOX-1691] - "Foreign" characters are not rendered -[PDFBOX-1692] - java.lang.OutOfMemoryError: Java heap space -[PDFBOX-1694] - Bug in org.apache.pdfbox.io.Ascii85InputStream -[PDFBOX-1696] - Bug in org.apache.pdfbox.io.Ascii85OutputStream -[PDFBOX-1699] - Problem with generate jpg from pdf -[PDFBOX-1705] - can not Write Hebrew and Chinese word into a PDF -[PDFBOX-1708] - IndexOutOfBoundsException on convertToImage with an embedded Fax-Image -[PDFBOX-1713] - [PATCH] Bullet character not rendered -[PDFBOX-1714] - Merging PDFs results in java.io.IOException: expected='R' actual='0' -[PDFBOX-1717] - Rendering to image has misplaced characters -[PDFBOX-1718] - wrong glyphs displayed -[PDFBOX-1719] - NPE while signing PDF - acroform without fields -[PDFBOX-1724] - Method createColorModel not implemented for PDCalGray -[PDFBOX-1725] - Character rendered at wrong position -[PDFBOX-1727] - Content outside the MediaBox should not be rendered -[PDFBOX-1730] - Image in PDF has extremely different colors when rendered -[PDFBOX-1733] - Rectangles have one rounded edge in rendered image only -[PDFBOX-1735] - Convert page pdf to image -[PDFBOX-1737] - Skip whitespaces when resolving a XRef -[PDFBOX-1740] - Umlaut not rendered correctly in TTF composite glyph -[PDFBOX-1741] - [PATCH] Text should be in italic but is rendered upright -[PDFBOX-1742] - type1CFont font with null encoding -[PDFBOX-1743] - OutOfMemoryError in fontbox -[PDFBOX-1749] - Out of memory exception when parsing TTF file -[PDFBOX-1750] - PDTextbox and PDAnnotationWidget are not correct initialized from it's own constructor . -[PDFBOX-1752] - Rendering PDF containing Jpeg2000 fails -[PDFBOX-1753] - The font gets gibbrish when adding a line of text to an existing PDF with a table -[PDFBOX-1754] - Preflight doesn't detect JavaScript for some PDFs -[PDFBOX-1756] - ClassCastException CosString cannot be cast to COSName -[PDFBOX-1758] - Preflight doesn't report Filespec dictionary that refers (indirectly) to an EmbeddedFile entry in some cases -[PDFBOX-1760] - Regressions 28 Oct 2013 -[PDFBOX-1763] - Exception caused by "Invalid ICC Profile Data" -[PDFBOX-1764] - PDFBox takes ages to render page 2 of the attached PDF -[PDFBOX-1765] - Null pointer exception in PDFToImage -[PDFBOX-1768] - cannot build last source code -[PDFBOX-1770] - ExtractText gets all "?" when pdf 's font is instance of PDType1Font -[PDFBOX-1771] - Cannot render FOP pdf with subsetted OTF CFF for both standard and CID-Keyed fonts -[PDFBOX-1773] - Regression? Type 3 Fonts are not processed by RenderUtil.convertToImage -[PDFBOX-1774] - StackOverflowError; Preflight->Font -[PDFBOX-1776] - Print pdf with font embedded(SimSun TrueType(CID) Identity-H) -[PDFBOX-1777] - memory leak in org.apache.pdfbox.cos.COSDocument -[PDFBOX-1778] - Rounding issue in generated PDF file -[PDFBOX-1780] - previous revision is damaged after signing -[PDFBOX-1789] - NullPointerException at PDPageContentStream.setFont -[PDFBOX-1790] - NPE during PDTrueTypeFont.loadTTF() on Mac TrueType font lacking Windows-platformID CMAPEncodingEntry -[PDFBOX-1791] - Type3 glyphs with partial black background -[PDFBOX-1794] - Rendering Problem with Type 3 Fonts -[PDFBOX-1796] - Infiniteloop BaseParser.java:1010 -[PDFBOX-1799] - NullPointerException when constructing a PDJPeg using a BufferedImage -[PDFBOX-1801] - xmp serializer does not generate valid xml for structured types -[PDFBOX-1802] - COSDictionary in COSArray setDirect(true) but dic written indirect -[PDFBOX-1804] - PDFTextStripper Issue related to word positions not correctly being parsed -[PDFBOX-1808] - PDFTextStripper.getText - hight memory usage -[PDFBOX-1810] - PDFToImage: Image of pdf is resized and drawn multiple times at top of output image -[PDFBOX-1811] - java.io.IOException: Object at offset does not end with 'endobj' -[PDFBOX-1812] - Illegal characters in XML output -[PDFBOX-1813] - Stack overflow error in Main (no output file produced) -[PDFBOX-1814] - In some cases PDPage converttoimage is extremely slow -[PDFBOX-1818] - Push back buffer is full error -[PDFBOX-1819] - Rendering problem with JPX image -[PDFBOX-1822] - Signature byte range is Invalid -[PDFBOX-1824] - [PATCH] CFF fonts render wrong glyphs -[PDFBOX-1825] - [PATCH] Many pdfbox tests are never run -[PDFBOX-1829] - PDF Extract Image Pixelmap Issue -[PDFBOX-1830] - Grey background rectangle rendered at different position -[PDFBOX-1831] - [PATCH] Fix: "Foreign" characters are not rendered -[PDFBOX-1845] - PDDocument.load() give Error: Expected a long type at offset 1633 -[PDFBOX-1849] - Isartor test 6-3-5-t01-fail-a does not return the expected error code -[PDFBOX-1860] - HTML converter escapes formatting close tags -[PDFBOX-1861] - Line is incorrectly dashed -[PDFBOX-1862] - Incomplete signature creation (regression in 1.8.3 with PDFBOX-1780) -[PDFBOX-1864] - Non-embedded fonts not detected (or are they?) -[PDFBOX-1865] - RenderUtil - rendering blank pages as images from PDF -[PDFBOX-1868] - Garbled / distorted fonts during PDF to image conversion on recent versions -[PDFBOX-1871] - Content appears a few px higher when rasterizing PDF -[PDFBOX-1872] - PDMetadata.exportXMPMetadata fails when Metadata has encrypted stream -[PDFBOX-1874] - PDFTextStripper.isParagraphSeparation(...) -[PDFBOX-1875] - Image and some text missing in rendered file -[PDFBOX-1876] - Incorrect color for DeviceN type 4 shading object -[PDFBOX-1877] - Radial Shading (type 3) fails Ghent Workgroup tests -[PDFBOX-1879] - Gibberish characters when converting pdf to image -[PDFBOX-1880] - [PATCH] Type 1 Shading must not ignore current transformation matrix -[PDFBOX-1882] - Negative array size exception when reading a string from a OTF font -[PDFBOX-1884] - Avoid NPE when encountering null PDComplexFileSpecification -[PDFBOX-1887] - Bugfixes + Optimization of Gouraud Shading -[PDFBOX-1888] - JBIG2Filter is creating an ImageInputStream (with temp file) and not closing it -[PDFBOX-1892] - Empty pages after rendering images: org.apache.pdfbox.util.operator.pagedrawer.Invoke -[PDFBOX-1895] - Type0 settings /Registry and /Ordering are not decrypted when writing document -[PDFBOX-1896] - Support MMType1 (Multiple Master) Fonts -[PDFBOX-1900] - ConvertToImage - pdf - checkbox wrongly rendered -[PDFBOX-1901] - null check confusing -[PDFBOX-1908] - Drop shadow is too heavy (Transparency Groups) -[PDFBOX-1910] - Text rendered as question marks -[PDFBOX-1911] - Orange background from the pdf gets turned into blue in the png files. -[PDFBOX-1916] - java.lang.ArrayIndexOutOfBoundsException in inlineimage -[PDFBOX-1917] - Rendering hangs -[PDFBOX-1918] - PDF with incorrect startxref -[PDFBOX-1922] - NonSequentialParser not reading version in header and trailer -[PDFBOX-1924] - Gouraud shading: detect empty triangles -[PDFBOX-1925] - DeviceCMYK Colorspace: PDFToImage gives wrong output -[PDFBOX-1928] - PDResources.getFonts() and PDresources.getXObjects() change underlying COSDictionary -[PDFBOX-1929] - Drop shadow on text appears as a box -[PDFBOX-1930] - TimesNewRoman font should be substituted -[PDFBOX-1931] - Radial shading is missing -[PDFBOX-1934] - converttoimage error and part of the pdf is not rendered -[PDFBOX-1940] - Faulty pdf->image rendering -[PDFBOX-1942] - Regression: java.lang.IndexOutOfBoundsException in shading -[PDFBOX-1944] - Regression: NPE in test file -[PDFBOX-1945] - Regression: NPE with inline image -[PDFBOX-1948] - Regression: page renders mostly empty, text missing -[PDFBOX-1950] - Inline image mask does not mask -[PDFBOX-1953] - java.lang.IllegalArgumentException in SampledImageReader.getRGBImage() -[PDFBOX-1954] - Regression: Some lines are too small / too long -[PDFBOX-1955] - Regression: Colors much lighter -[PDFBOX-1961] - Page with annotations renders fine with 1.8 but not with 2.0 -[PDFBOX-1965] - NPE in NonSequentialPDFParser when parseMinimal property is set to true -[PDFBOX-1966] - Type 1, 4 and 5 shadings for shFill() -[PDFBOX-1969] - JPEGFactory bug -[PDFBOX-1977] - LZWFilter fails -[PDFBOX-1978] - Type1FontUtilTest is non-deterministic -[PDFBOX-1979] - TypeTestingHelper is non-deterministic -[PDFBOX-1980] - TestCOSFloat is non-deterministic -[PDFBOX-1981] - CryptographyException for file that isn't encrypted -[PDFBOX-1983] - Unable to add TIF images, CCITTFactory not working -[PDFBOX-1984] - PDFont documentation correction needed for getFontWidth and getFontHeight -[PDFBOX-1988] - PDFBox ExtractText issue of PDF with no embedded fonts -[PDFBOX-1992] - text in pdf with convertToImage not rendered -[PDFBOX-1993] - Gray color images much lighter -[PDFBOX-1995] - AdobePDFSchema.getProducer() returns empty string -[PDFBOX-1997] - CIE LAB item missing in rendering -[PDFBOX-1999] - JBIG2Filter - FlateDecoded Globals Table -[PDFBOX-2000] - White page when converting first page to image -[PDFBOX-2001] - Digital Signature information (parser bug?) -[PDFBOX-2005] - JDK 1.8 build fails in TestTTFParser -[PDFBOX-2007] - Performance regression since PDFRenderer -[PDFBOX-2008] - Off-by-one error in BaseParser.readGenerationNumber() -[PDFBOX-2009] - PDFStreamEngine.processEncodedText incorrectly handling UTF-16 text with BOM FEFF -[PDFBOX-2015] - Hybrid reference pdf still contain XRefStm info in the trailer dictionary afterPDDocument#save -[PDFBOX-2016] - Stream parsing still incorrect if length value is wrong -[PDFBOX-2020] - PDF/A Validation raises NullPointerException for PDFs without ImageColorSpace -[PDFBOX-2021] - PDFPrinter problem with landscape and rotated pages -[PDFBOX-2022] - silentPrint(no args) doesn't use the printerJob field -[PDFBOX-2023] - Text extraction gets zero font height for type3 fonts -[PDFBOX-2024] - /Rotate 180 PDF is not displayed correctly in PDFReader app -[PDFBOX-2026] - cannot load jpg into new pdf -[PDFBOX-2032] - [PATCH] TTF Type12 IOException: Invalid Characters codes -[PDFBOX-2035] - Ignore badly formatted toUnicode CMaps -[PDFBOX-2036] - Add test with LZW fail sequence -[PDFBOX-2037] - Glyph in type1CFont not rendered -[PDFBOX-2038] - Method VisualSignatureParser#parse does not close COSDocument -[PDFBOX-2042] - ColorSpace with empty Range array -[PDFBOX-2044] - TrueType glyphs not displayed in rendering -[PDFBOX-2045] - Merging PDFs with a Form has no effect -[PDFBOX-2046] - [PATCH] Can't read the embedded Type1 font -[PDFBOX-2047] - read operations alter PDLab object -[PDFBOX-2050] - Add predictor to LZW filter -[PDFBOX-2054] - Remove System.out.println() -[PDFBOX-2057] - Importing BufferedImage into PDPixelMap is broken in 1.8.5 -[PDFBOX-2058] - The text of pdfs using Type1C can't be extracted correct -[PDFBOX-2062] - Setting a PDFFormField's value with a specific font size causes the font size to change on click -[PDFBOX-2063] - Incomplete EOF detection in ASCIIHexFilter -[PDFBOX-2065] - Missing getCOSObject() in PDCalRGB -[PDFBOX-2067] - Error creating JPEG image with SMask -[PDFBOX-2070] - Filter.decode() modifies PDF if there is a filter array -[PDFBOX-2072] - Wrong calculation of space char width in PDFStreamEngine -[PDFBOX-2073] - PDF files with unusual Japanese font can not be rewrite correctly -[PDFBOX-2074] - 4-bytes CMap entry causes exception -[PDFBOX-2079] - Extra new line characters extracted in 1.8.5 for embedded files leading to ZipFile exception in Java 1.6 -[PDFBOX-2082] - signing corrupts PDF when signature exactly fits allocated space -[PDFBOX-2091] - Some characters are not rendered (font with symbol encoding) -[PDFBOX-2095] - Useless memory allocation in GlyfDescript -[PDFBOX-2098] - Gouraud shading doesn't appear -[PDFBOX-2100] - Gouraud shading doesn't work with function -[PDFBOX-2101] - Surprising memory consumption when extracting images -[PDFBOX-2102] - Characters swallowed on COSString.getString() -[PDFBOX-2103] - JPXFilter fails to decode some Jpeg2000 images -[PDFBOX-2106] - getSuffix() returns null for RLE encoding -[PDFBOX-2108] - Type0 CFF Font with identity encoding rendered incorrectly -[PDFBOX-2109] - CFFParser uses String constructor without encoding -[PDFBOX-2110] - Font not found: CourierNew -[PDFBOX-2111] - Cast error in Gouraud shadings -[PDFBOX-2114] - ObjStm is being processed to late -[PDFBOX-2115] - Use unfiltered stream in gouraud shadings -[PDFBOX-2120] - Regression: Type 1 font corrupted -[PDFBOX-2122] - FontBox's TTFDataStream doesn't set timezone in readInternationalDate -[PDFBOX-2128] - CMYK images are not supported correctly -[PDFBOX-2133] - Parsing of a Type1 font fails with a NumberFormatException -[PDFBOX-2134] - Parsing of a Type1 font fails with a NPE -[PDFBOX-2140] - non embedded Type1 symbol glyph not rendered -[PDFBOX-2141] - Shading not applied to text -[PDFBOX-2147] - Clean up code with "inspect and transform" -[PDFBOX-2153] - Setting the correct clipping path for shading -[PDFBOX-2155] - Fix JavaDocs warnings -[PDFBOX-2156] - different shading patterns at different resolutions when ctm is null -[PDFBOX-2158] - ExtractText missing most of text in this PDF file, due to font bounding box with minus infinity -[PDFBOX-2160] - PDFTextStripper doesn't always write paragraph start -[PDFBOX-2163] - inline image with EI in the middle incorrectly parsed -[PDFBOX-2166] - AIOOBE with barcode ttf font -[PDFBOX-2168] - Different behavior of Undo feature when form was pre filled by PDFBox -[PDFBOX-2170] - java.lang.ClassCastException: org.apache.fontbox.cff.CharStringCommand cannot be cast to java.lang.Integer -[PDFBOX-2171] - UnsupportedOperationException for stencil image / pattern -[PDFBOX-2173] - Nullpointer when validating empty file -[PDFBOX-2176] - Ignore IllegalArgumentException when reading an ICCProfile -[PDFBOX-2177] - [PATCH] IndexOutOfBoundsException reading embedded OpenType font -[PDFBOX-2178] - Invalid color space kind: COSName{DeviceGray} -[PDFBOX-2179] - Regression: Some isartor tests are not passing in 2.0.0 -[PDFBOX-2181] - Regression: NPE in PreflightContentStream -[PDFBOX-2183] - COSArray cannot be cast to COSNumber -[PDFBOX-2184] - CMMException: Invalid profile data -[PDFBOX-2185] - Rotation and skew not applied on rectangles -[PDFBOX-2186] - java.io.IOException: Catalog cannot be found -[PDFBOX-2187] - ArrayIndexOutOfBoundsException in TIFFFaxDecoder -[PDFBOX-2188] - java.io.IOException: Expected a name or array but got: COSObject{1823, 0} -[PDFBOX-2189] - java.awt.geom.IllegalPathStateException: missing initial moveto in path definition -[PDFBOX-2191] - Identity function not implemented -[PDFBOX-2192] - "unknown command" in Type1CharString.handleCommand -[PDFBOX-2193] - ClassCastException in PDExtendedGraphicsState.getFontSetting() -[PDFBOX-2194] - Refactor predictor -[PDFBOX-2195] - Missing text when converting PDF to image -[PDFBOX-2198] - ClassCastException in COSArrayList.convertIntegerCOSArrayToList for font widths -[PDFBOX-2199] - Found Token[kind=NAME, text=dup] but expected begin -[PDFBOX-2200] - Memory leak with org.apache.pdfbox.pdmodel.font.PDFont#cmapObjects -[PDFBOX-2201] - getKeywords returns null although keywords are present -[PDFBOX-2202] - java.io.IOException: Found Token[kind=NAME, text=readonly] but expected def -[PDFBOX-2203] - java.lang.IllegalArgumentException: alpha value out of range -[PDFBOX-2204] - Indexed color space in JPX -[PDFBOX-2206] - Cannot save a document which has been closed -[PDFBOX-2207] - Stream parsing still incorrect if length value is wrong -[PDFBOX-2212] - OutOfMemoryError in GlyfCompositeDescrip -[PDFBOX-2214] - EmptyStackException in PDFStreamEngine -[PDFBOX-2215] - NPE in PDTrueTypeFont.makeFontDescriptor -[PDFBOX-2216] - java.io.IOException: Found Token[kind=NAME, text= ] but expected LITERAL for type1 font -[PDFBOX-2217] - Matrix transform ignored in axial and radial shadings (in PDFToImage output) -[PDFBOX-2221] - Text is pink -[PDFBOX-2222] - NPE in PDFStreamEngine -[PDFBOX-2225] - ClassCastException in PDFMergerUtility.appendDocument -[PDFBOX-2227] - java.io.IOException: Found Token[kind=NAME, text= ] but expected LITERAL for type1 font -[PDFBOX-2228] - LZW EarlyChange parameter isn't supported -[PDFBOX-2229] - NPE in GlyfCompositeDescript.getPointCount -[PDFBOX-2234] - [PATCH] Invalid Color space preflight error on Java 8 -[PDFBOX-2237] - java.io.IOException: Image stream is empty for inline image -[PDFBOX-2240] - ArrayIndexOutOfBoundsException PDImageXObject.applyMask -[PDFBOX-2241] - IOException: Expected INTEGER or REAL but got NAME -[PDFBOX-2243] - java.lang.IllegalArgumentException: negative dash phase -[PDFBOX-2244] - java.lang.IndexOutOfBoundsException in callothersubr -[PDFBOX-2245] - java.lang.StringIndexOutOfBoundsException in PDTrueTypeFont.getGIDForCharacterCode -[PDFBOX-2247] - Regression in text extraction between 1.8.5 and 1.8.6 -[PDFBOX-2251] - NoSuchElementException when reading cmap format 4 subtable -[PDFBOX-2256] - Text size renders wrong -[PDFBOX-2257] - BufferedInputStream wrapped in BufferedInputStream -[PDFBOX-2261] - Extremely long hang during getFields() on a few PDF files -[PDFBOX-2265] - ArrayIndexOutOfBoundsException in PDICCBased.loadICCProfile -[PDFBOX-2266] - NPE when converting page to image -[PDFBOX-2267] - IOException and partial rendering and colorspace creation error -[PDFBOX-2268] - AES-256 decryptions fails -[PDFBOX-2270] - PDField.getFullyQualifiedName() returns name adding suffix '.null' -[PDFBOX-2271] - Potential NPE in PDAppearanceString.java -[PDFBOX-2275] - ClassCastException in PDResources -[PDFBOX-2278] - Exception in thread "main" java.lang.IllegalStateException: Call to processSubStream() before processStream() or initStream() -[PDFBOX-2280] - Text not italic -[PDFBOX-2281] - Yellow box shown -[PDFBOX-2283] - Incorrect transform for annotations / appearance streams -[PDFBOX-2284] - NullPointerException in PDFieldTreeNode -[PDFBOX-2285] - debugLogMetadata doesn't log -[PDFBOX-2287] - [PATCH] COSStream loses contents in setFilters() -[PDFBOX-2291] - Differences in Overlay stamping between version 1.8.2 and 1.8.6 -[PDFBOX-2292] - Saving of decrypted version of password protected document gives an error -[PDFBOX-2293] - NonSequential parser gives an error -[PDFBOX-2295] - Checkboxes missing -[PDFBOX-2296] - Wrong stream length -[PDFBOX-2298] - Wrong scaling of embedded type 1 font -[PDFBOX-2299] - Isartor tests don't work anymore -[PDFBOX-2300] - Glyphs rendered at wrong position -[PDFBOX-2301] - RandomAccessBuffer consumes too much memory. -[PDFBOX-2304] - square glyphs missing -[PDFBOX-2306] - Error reading stream, expected='endstream' actual='endobj' -[PDFBOX-2307] - NPE in TrueTypeFont.getWidth -[PDFBOX-2309] - UnsupportedOperationException: not implemented: missing CFF -[PDFBOX-2310] - codeToGID NPE -[PDFBOX-2311] - color space 'COSName{DefaultRGB}' does not exist in the current page's resources -[PDFBOX-2312] - IllegalArgumentException: Built-in Encoding required for symbolic font -[PDFBOX-2313] - ExtractImages finds never-rendered images -[PDFBOX-2314] - Restore backward compatibility between Overlay and OverlayPDF -[PDFBOX-2315] - Found Token[kind=NAME, text=ND] but expected ND -[PDFBOX-2317] - ZapfDingbats should use its own glyph list -[PDFBOX-2318] - NPE in new DomXmpParser when no type is found -[PDFBOX-2319] - Date Converter needs to handle miliseconds and other formats -[PDFBOX-2320] - IOException: Could not read embedded TTF for font TimesNewRoman -[PDFBOX-2323] - More flexible image caching (OOM) -[PDFBOX-2324] - Failure to render DeviceN image -[PDFBOX-2325] - Failure to render OpenType (TrueType) -[PDFBOX-2326] - IllegalArgumentException: Use PDType1CFont for FontFile3 -[PDFBOX-2327] - Glyph list ligatures are decomposed too early -[PDFBOX-2330] - Typo on usage message; "PDFDBox" instead of "PDFBox" -[PDFBOX-2332] - Error reading stream, expected='endstream' actual='endstream8' at offset 1993 -[PDFBOX-2334] - codeToGID NPE -[PDFBOX-2338] - IllegalStateException: recursive definition -[PDFBOX-2339] - ArrayIndexOutOfBoundsException when type1 font is empty -[PDFBOX-2342] - WriteDecodedDoc cant decrypt pdf form correctly -[PDFBOX-2343] - Giving NullPoint exception when we call PDType1Font.HELVETICA_BOLD.getStringWidth("Some String") -[PDFBOX-2344] - NegativeArraySizeException in radial shading -[PDFBOX-2345] - IndexOutOfBoundsException reading encrypted pdf -[PDFBOX-2347] - NPE while creating security handler for decryption -[PDFBOX-2350] - Type1 Parser hangs indefinitely -[PDFBOX-2351] - /XRefStm content missing in saved file -[PDFBOX-2352] - NegativeArraySizeException in HorizontalMetricsTable.read -[PDFBOX-2355] - newDocuments is private in Splitter -[PDFBOX-2356] - Error Validating PDF Archive Document with half hour timezone -[PDFBOX-2357] - PDTrueTypeFont has no method to load font from stream -[PDFBOX-2358] - ExternalFonts uses classloader of class in font-box -[PDFBOX-2360] - PDFont had methods removed -[PDFBOX-2363] - wrong color in rendering -[PDFBOX-2364] - CCITT image renders incorrectly -[PDFBOX-2365] - NPE with file with PDFDocEncoding -[PDFBOX-2367] - Ligature glyph widths wrong -[PDFBOX-2372] - Trash Glyphs: Regressions 19.9.2014 -[PDFBOX-2373] - Rendering at 72 dpi crashes java -[PDFBOX-2376] - Small regression in text extraction with PDFBox 1.8.7 vs. 1.8.6 -[PDFBOX-2379] - glyphlist_ext is not OSGI compatible -[PDFBOX-2380] - Glyphlist .properties are not ordered -[PDFBOX-2381] - BaseParser - IOException: Push back buffer is full -[PDFBOX-2383] - PDFBox tests include copyright files -[PDFBOX-2384] - ExtractText should default to UTF-8 -[PDFBOX-2385] - inline image with EI at the end incorrectly parsed -[PDFBOX-2390] - PDExtendedGraphicsState is incorrectly named -[PDFBOX-2395] - Signing PDF document changes documentID -[PDFBOX-2396] - Comment on `org.apache.pdfbox.util.Splitter.createNewDocumentIfNecessary` is out of date -[PDFBOX-2399] - font.getFontDescriptor() for PDType1Font.HELVETICA is null -[PDFBOX-2401] - Image has wrong colors after Merge -[PDFBOX-2402] - NonSequentialPDFParser cannot recover from spurious closing brackets -[PDFBOX-2403] - false negative? "Font damaged, The FontFile can't be read" -[PDFBOX-2405] - false negatives: Invalid Font definition, Some required fields are missing from the Font ... ? -[PDFBOX-2406] - fix typo "AlpaConstant" -[PDFBOX-2407] - false negative: 2.4.3 : Invalid Color space, The operator "f" can't be used without Color Profile ? -[PDFBOX-2408] - false negative? 1.2.1 : Body Syntax error, Single space expected ... -[PDFBOX-2409] - got the wrong result from Arabic text extraction -[PDFBOX-2411] - Pushback buffer is full on seamingly small PDF -[PDFBOX-2412] - Loading XFDF document fails with ClassCastException -[PDFBOX-2413] - Loaded FDF document returns null fields -[PDFBOX-2415] - java.lang.ClassCastException: org.apache.pdfbox.pdmodel.font.PDType1CFont cannot be cast to org.apache.pdfbox.pdmodel.font.PDType1Font -[PDFBOX-2416] - xmp regression? 7.3 : Error on MetaData, Cannot find a definition for the namespace http://ns.adobe.com/xap/1.0/t/pg/ -[PDFBOX-2417] - xmp regression? 7.3 : Error on MetaData, Schema is not set in this document : http://ns.adobe.com/xap/1.0/sType/Dimensions# -[PDFBOX-2418] - xmp regression? 7.3 : Error on MetaData, Schema is not set in this document : http://ns.adobe.com/xap/1.0/g/img/ -[PDFBOX-2419] - XFDF export is not XML compliant -[PDFBOX-2421] - Poor text extraction and rendering of file with non embedded type1 font -[PDFBOX-2422] - PDFont.getStringWidth results in stackoverflow -[PDFBOX-2424] - ClassCastException in getMetaData if no real meta data -[PDFBOX-2426] - Make ExternalFonts.getProvider public -[PDFBOX-2428] - An error occured when reading table hmtx -[PDFBOX-2429] - Times New Roman rendered as Arial -[PDFBOX-2433] - PDFPrinter does not print Acroform fields -[PDFBOX-2434] - ClassCastException in readVersionInTrailer -[PDFBOX-2436] - Parsing error -[PDFBOX-2437] - PDFont isSymbolic() has unexpected return value -[PDFBOX-2439] - [PATCH] ArrayIndexOutOfBoundsException in multithreaded system -[PDFBOX-2441] - Improve XRef self healing mechanism when more than one xref table -[PDFBOX-2445] - Out of Memory - Extract text for Apache_Solr_4.7_Ref_Guide.pdf -[PDFBOX-2447] - "Cannot save a document which has been closed" when encrypting -[PDFBOX-2448] - ligatures and some glyphs missing -[PDFBOX-2453] - Building on OpenJDK throws javax.imageio.IIOException -[PDFBOX-2455] - NonSequentialParser does not tolerate missing %%EOF markers -[PDFBOX-2457] - LogFactory is intialized with a wrong class -[PDFBOX-2458] - Signing doesn't work anymore using BC 1.51 instead of 1.50 -[PDFBOX-2460] - fix TestPublicKeyEncryption.java -[PDFBOX-2462] - NullPointerException in (PDFStreamParser.java:109) -[PDFBOX-2465] - NPE in PdfaExtensionHelper.populateSchemaMapping -[PDFBOX-2466] - 2.4 : Invalid Color space, Unable to read default color space : Missing color space: DefaultRGB -[PDFBOX-2469] - javax.crypto.BadPaddingException in PDFBox 1.8.8-SNAPSHOT -[PDFBOX-2470] - Exception in PDDocument.addSignature(PDSignature sigObject, SignatureInterface signatureInterface, SignatureOptions options)) -[PDFBOX-2471] - AES encryption failing to write Acroform field names and values -[PDFBOX-2477] - NPE in DomXmpParser.createProperty -[PDFBOX-2478] - NPE in XObjImageValidator.checkColorSpaceAndImageMask -[PDFBOX-2479] - NPE in PDICCBased.getColorSpaceType -[PDFBOX-2481] - Adding large TYPE_BYTE_BINARY image to pdf document generates distorted result -[PDFBOX-2483] - StackOverflowError in preflight -[PDFBOX-2484] - Cannot decrypt AES256 encrypted files with nonSeq parser -[PDFBOX-2485] - IllegalArgumentException in TypeMapping.instanciateSimpleProperty -[PDFBOX-2486] - ClassCastException in preflight: PDNonTerminalField cannot be cast to PDField -[PDFBOX-2487] - ArrayIndexOutOfBoundsException in Type1CharString -[PDFBOX-2488] - NPE in FontValidator.isSubSet in preflight -[PDFBOX-2489] - StackOverflowError in PDSimpleFont.isFontSymbolic -[PDFBOX-2490] - Return value of COSDocument#isEncrypted is unclear -[PDFBOX-2491] - NPE in PDFAIdentificationValidation.checkConformanceLevel() -[PDFBOX-2492] - Java 8u25 IllegalBlockSizeException decrypting pdf -[PDFBOX-2495] - Black shapes in the background of some rendered pages of some PDFs -[PDFBOX-2496] - PNG filesize is larger -[PDFBOX-2498] - ArrayIndexOutOfBoundsException in PreflightParser.lastIndexOf -[PDFBOX-2499] - EOF and NPE in PDType1CFont.getFontMatrix -[PDFBOX-2500] - ClassCastException in StreamValidationProcess.checkFilters -[PDFBOX-2501] - Page render without barcode -[PDFBOX-2502] - false negative? 1.4.6 : Trailer Syntax error, ID is different in the first and the last trailer -[PDFBOX-2503] - false negative? 1: 7.2 : Error on MetaData, Producer present in the document catalog dictionary doesn't match with XMP information -[PDFBOX-2504] - ClassCastException in preflight: PDAnnotationWidget cannot be cast to PDField -[PDFBOX-2505] - ArrayIndexOutOfBoundsException in PDColor constructor -[PDFBOX-2507] - Annotation example not rendered to image -[PDFBOX-2508] - Text extraction getting zero font height, bad widths, and ? for text in this PDF with Type 3 Fonts -[PDFBOX-2509] - Korean Text font substitution issues -[PDFBOX-2513] - false negative? RuntimeException: EOL encountered in white run -[PDFBOX-2517] - Better error message on pdfA identification -[PDFBOX-2519] - Regression: Box color missing -[PDFBOX-2520] - Don't decrypt already decrypted pdfs -[PDFBOX-2521] - Don't throw IOException if stream length is missing in lenient mode -[PDFBOX-2523] - IOException: Error: Expected a long type at offset 1218571, instead got 'xref' -[PDFBOX-2525] - Overlay: data black & white after import -[PDFBOX-2526] - Arial black not black -[PDFBOX-2527] - IOException: Negative seek offset in NonSequentialPDFParser -[PDFBOX-2528] - IOException: Object must be defined and must not be compressed object: 0:0 -[PDFBOX-2533] - Poor rendering with non-sequential parser -[PDFBOX-2540] - ArrayIndexOutOfBoundsException in Type1Parser.parseASCII -[PDFBOX-2541] - ClassCastException in BaseParser.parseCOSDictionaryValue -[PDFBOX-2542] - IllegalArgumentException: root must be of type Pages -[PDFBOX-2543] - ClassCastException in PDFontDescriptor.getFontFile2 -[PDFBOX-2546] - IllegalArgumentException: resourceDictionary is null in PDFMerger -[PDFBOX-2549] - TIFF-Predictor with 16 bits per component not supported -[PDFBOX-2550] - ClassCastException in PDAnnotation.getColour -[PDFBOX-2552] - Blank rendering when negative page rotation -[PDFBOX-2553] - CalRGB colors different -[PDFBOX-2557] - Yellow text not using heavy font -[PDFBOX-2559] - TTF font cannot be loaded -[PDFBOX-2560] - Arial Truetype CID font rendering incorrect -[PDFBOX-2561] - Rendering of PDIndexed line incorrect -[PDFBOX-2563] - [PATCH] Use cmap for Type0/TTF fallback -[PDFBOX-2569] - COSNumber fails to parse numbers like "+018" in JRE <= 1.6 -[PDFBOX-2570] - ClassCastException in PDCalGray: COSFloat cannot be cast to COSArray -[PDFBOX-2571] - IllegalStateException: Not a CIDFont -[PDFBOX-2572] - ArrayIndexOutOfBoundsException in CmapSubtable.processSubtype12 -[PDFBOX-2573] - IllegalStateException: PDFBox bug: encoding should not be null! -[PDFBOX-2579] - Exception in thread "main" java.io.IOException: Error: Expected a long type at offset 1029, instead got '12688(Deleted' -[PDFBOX-2582] - Form fields missing entirely or incorrect in PDField list -[PDFBOX-2583] - Error when rendering a PDF with annotations -[PDFBOX-2586] - IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher -[PDFBOX-2588] - Text fields if initialy empty in AcroForms do not contain a COSName.V in its dictionary and therefore does not get rendered. -[PDFBOX-2595] - Pdfbox always sets the second part of documentID to the same value -[PDFBOX-2598] - IllegalArgumentException in CFFParser.readCharset -[PDFBOX-2599] - failure to render file with utf8 CID TT fonts -[PDFBOX-2601] - fix getHashObjectIdentifier in TSAClient -[PDFBOX-2605] - Multiple text operations on page cause NPE in TTFSubsetter -[PDFBOX-2606] - Support OS with no fonts -[PDFBOX-2607] - Failed reading embedded Font -[PDFBOX-2608] - false negative on pdf/A validation? -[PDFBOX-2615] - IllegalArgumentException in PDPageTree constructor: root cannot be null -[PDFBOX-2616] - JVM crashes while trying to convert PDF to JPG image (only on Windows) -[PDFBOX-2617] - Group of Button fields treated as a Radio Button group -[PDFBOX-2620] - Support named actions -[PDFBOX-2621] - Files created with CreatePDFA.java are not PDF/A-1b -[PDFBOX-2622] - PDAnnotationLink::getBorderStyle() don't understand external border style -[PDFBOX-2629] - PDAnnotation should not use PDGamma for colors -[PDFBOX-2632] - Lost output when mixing subset and non-subset of the same font -[PDFBOX-2634] - Multiple text operations on multiple pages cause NPE in TTFSubsetter -[PDFBOX-2635] - PrintImageLocations outputs utter nonsense -[PDFBOX-2636] - Colorspaces of annotations not treated correctly -[PDFBOX-2640] - Fields within a fields kids entry are not correctly recognized -[PDFBOX-2641] - ArrayIndexOutOfBoundsException in PDType1Font constructor -[PDFBOX-2646] - A text including single-quote is malformed with Embedded TTF font -[PDFBOX-2649] - Character widths incorrect in a loaded font -[PDFBOX-2650] - Type1Equivalent: TrueType must use 'cmap' when 'post' table is empty -[PDFBOX-2651] - Preflight doesn't check for valid destination syntax -[PDFBOX-2652] - Document Outlines (Bookmark) and Link Annotation validation do not validate /Dest item -[PDFBOX-2653] - Image extraction fails with attached PDF -[PDFBOX-2654] - NullPointerException when reading a GIF file with a transparent color -[PDFBOX-2655] - PDCIDFontType2Embedder.buildCIDSet() ArrayOutOfBounds -[PDFBOX-2656] - Trailer isn't written when signing a PDF -[PDFBOX-2660] - Text missing -[PDFBOX-2664] - PDDocumentInformation shouldn't throw IOException -[PDFBOX-2665] - PDType1Font (HELVETICA) encode getting NullPointerException -[PDFBOX-2667] - StandardSecurityHandler should throw InvalidPasswordException -[PDFBOX-2668] - intersectClippingPath does a shallow copy -[PDFBOX-2675] - PDOutlineNode.getParent uses /P item as fallback for /Parent -[PDFBOX-2676] - PDPageLabelRange.setLabelItem() should not allow negative startPage -[PDFBOX-2677] - Negative Outlines COUNT and various issues -[PDFBOX-2678] - possible NPE in ExtractText tool of trunk -[PDFBOX-2679] - Blank page rendered with wrong xref start objid -[PDFBOX-2687] - ClassCastException when trying to get OutputIntents or add to it -[PDFBOX-2693] - OutOfMemoryError at org.apache.fontbox.cff.IndexData.initData(IndexData.java:95) -[PDFBOX-2698] - PDFToImage IndexOutOfBoundsException -[PDFBOX-2702] - Merging PDFs created using "Nuance PDF Create" not possible -[PDFBOX-2704] - PDPageTree.indexOf doesn't find page numbers -[PDFBOX-2708] - PDDocument.removePage() deletes the last page regardless of parameter passed -[PDFBOX-2711] - Japanese text not extracted -[PDFBOX-2713] - Preserve the origin pdf version when splitting a pdf -[PDFBOX-2714] - Type1Fonts working on one computer, not another -[PDFBOX-2715] - Pages in a PDF being dropped with just an error-log message -[PDFBOX-2717] - Keep type and subtype for PDWidgetAnnotation created from field -[PDFBOX-2719] - The addSignature() method always set the visual signature on the last page of the PDF -[PDFBOX-2720] - Can't sign PDF document with forms or annotations -[PDFBOX-2723] - PDFBox*.tmp files not deleted by COSParser -[PDFBOX-2724] - Importing a XFDF file doesn't populate the field value -[PDFBOX-2726] - org.apache.pdfbox.cos.COSArray cannot be cast to org.apache.pdfbox.cos.COSDictionary -[PDFBOX-2728] - java.awt.geom.IllegalPathStateException: missing initial moveto in path definition -[PDFBOX-2729] - Can't sign encrypted PDF files -[PDFBOX-2730] - PDFSplit slow and keeps unused pages -[PDFBOX-2733] - Nullpointer exception in PDFXrefStreamParser.parse -[PDFBOX-2734] - Can't create PDF with DeviceN colorspace -[PDFBOX-2739] - Saving merged documents causes IOException -[PDFBOX-2741] - IndexOutOfBoundsException when calling PDSeparation.setAlternateColorSpace -[PDFBOX-2745] - PDPageXYZDestination zoom property can't be set lower than 100% -[PDFBOX-2746] - PDPageContentStream.saveGraphicsState() saves wrong nonStrokingColor and throws an exception -[PDFBOX-2747] - pdfbox: garbled japanese txt output -[PDFBOX-2750] - Rendering in poor quality in 2.0 but not in 1.8.* -[PDFBOX-2759] - NPE in BaseParser.parseCOSDictionaryValue() due to object reference in content stream -[PDFBOX-2760] - NPE in MoveText.process() -[PDFBOX-2767] - ClassCastException in PDDocument.addSignature -[PDFBOX-2769] - NPE when saving encrypted file -[PDFBOX-2771] - COSString encodes Euro sign wrongly -[PDFBOX-2772] - EI token lost for rewrite -[PDFBOX-2773] - ClassCastException in PDDocumentCatalog.java:339 -[PDFBOX-2774] - Can't encode Euro with WinAnsiEncoding -[PDFBOX-2775] - ArrayIndexOutOfBoundsException in PDFTextStripper.processTextPosition() -[PDFBOX-2778] - PDF to Image conversion fails with "Invalid code word encountered" -[PDFBOX-2781] - Opening pdf document after encrypting it with PDFBox throws IllegalBlockSizeException -[PDFBOX-2786] - PDPageDestination page index off by one -[PDFBOX-2789] - TTF encoding issues -[PDFBOX-2792] - Text extraction ignores bookmarks -[PDFBOX-2793] - /Dests dictionary isn't supported -[PDFBOX-2794] - UnsupportedOperationException: not supported for Type 3 fonts -[PDFBOX-2795] - PrintRequestAttributeSet is being ignored -[PDFBOX-2797] - PDJavascriptNameTreeNode does not support dictionaries -[PDFBOX-2798] - PDTextStream does not support UTF16 with BOM -[PDFBOX-2799] - PDOptionalContentProperties.setGroupEnabled not working -[PDFBOX-2801] - SecurityHandler does not tolerate plain-text COSString -[PDFBOX-2802] - TestFontEmbedding sometimes fails due to non-determinism -[PDFBOX-2803] - NullPointerException into class PDType0Font -[PDFBOX-2808] - Can't merge to files with bookmarks -[PDFBOX-2811] - Infinite loop within RandomAccessBuffer -[PDFBOX-2812] - NPE in PDColorSpaceFactory.createColorSpace with PDICCBased -[PDFBOX-2814] - Text not rendered in mode 7 -[PDFBOX-2816] - PDFBox makes disallowed changes when signing a signed document -[PDFBOX-2819] - invalid ICC Profile when reading from a byte array -[PDFBOX-2822] - infinite loop of searching for a key in PDResources -[PDFBOX-2824] - ArrayIndexOutOfBoundsException in GlyfSimpleDescript.readFlags() when multithreading -[PDFBOX-2826] - Mouse position shown when mouse outside of PDFReader window -[PDFBOX-2829] - PDBox 2.0 Throws IndexOutOfBoundsException (severe offset errors as well) -[PDFBOX-2830] - Can't draw color border around a PDTextBox + create example -[PDFBOX-2832] - Remove obsolete methods from fontbox's Encoding -[PDFBOX-2833] - Add an API to get the COSObjectKey of a given object -[PDFBOX-2834] - Violation in PDOutputIntent.getDestOutputProfile() method -[PDFBOX-2836] - COSName should be interpreted as UTF-8 -[PDFBOX-2837] - PDFBox creates files with EBCDIC code on z/OS -[PDFBOX-2843] - widthOfSpace() appears wrong in TextPosition -[PDFBOX-2844] - Printing has bigger margins than expected -[PDFBOX-2845] - Error parsing PDF -[PDFBOX-2846] - setValue failing with font issues. -[PDFBOX-2847] - mergeDocumentsNonSeq does not utilize scratchFile -[PDFBOX-2851] - getExportValue() non functional in PDRadioButton -[PDFBOX-2856] - Markedly slower processing for particular file in 2.0.0-trunk vs 1.8.9 -[PDFBOX-2862] - GlyphList doesn't appear to be thread safe in trunk...or user error? -[PDFBOX-2867] - Correct use of Float.NaN -[PDFBOX-2868] - NPE in Acroform getValueAsString -[PDFBOX-2869] - Corruption in ScratchFileBuffer -[PDFBOX-2871] - Performance issue when filling the first PDTextField of an AcroForm -[PDFBOX-2872] - Matrix.toCOSArray() has constant return -[PDFBOX-2875] - Type 1 fonts are embedded incorrectly -[PDFBOX-2876] - Better support for embedding of simple TrueType fonts -[PDFBOX-2881] - Radial and Axial shading steps are calculated incorrectly -[PDFBOX-2884] - NPE in FontMapper.getFont() -[PDFBOX-2885] - NPE in PDNonTerminalField.getChildren() -[PDFBOX-2886] - "IllegalArgumentException root cannot be null" in 2.0.0 for file that was parsed in 1.8.x -[PDFBOX-2887] - NPE in PDFXrefStreamParser in 2.0 trunk -[PDFBOX-2896] - XMPBox not creating valid "title" entry in DublinCoreSchema in trunk -[PDFBOX-2898] - Incorrect key for color space in PDGroup -[PDFBOX-2899] - Text not rendered in mode 7 (2) -[PDFBOX-2901] - High CPU load and OutOfMemoryError when rendering shading -[PDFBOX-2904] - IndexOutOfBoundsException in CFFType1Font.getType2CharString() -[PDFBOX-2906] - NullPointerException in PDFStreamEngine.showText -[PDFBOX-2908] - PDFTextStripper.writeText is slow -[PDFBOX-2909] - NullPointerException when rendering shading with no function -[PDFBOX-2911] - Merge does not close input streams -[PDFBOX-2916] - ArrayIndexOutOfBoundsException in CmapSubtable.processSubtype6 -[PDFBOX-2924] - ClassCastException when doing PDFSplit -[PDFBOX-2927] - Print with PrintRanges printRequestAttribute causing document to be cropped -[PDFBOX-2929] - "Illegal instruction: 4" with PDFToImage -[PDFBOX-2930] - PDFPageable does not rotate portrait document with 90°/270° rotation well -[PDFBOX-2932] - NPE in PDSignature.getValuesAsString() when field contains no value -[PDFBOX-2935] - Problem while extracting font from PDFontSetting (used in PDExtendedGraphicsState) -[PDFBOX-2937] - Field duplication in PDIndexed color space -[PDFBOX-2939] - PDFRenderer.renderImageWithDPI exception with certain PDFs -[PDFBOX-2946] - Symbol glyphs not aligned -[PDFBOX-2948] - NPE in PDStream.createInputStream -[PDFBOX-2949] - Rendering to ARGB brings black background -[PDFBOX-2950] - Chinese font substitution issue -[PDFBOX-2951] - quotedbl causes NullPointerException -[PDFBOX-2956] - PDFontDescriptor doesn't contain method getCIDSet. -[PDFBOX-2957] - Glyphs rendered as gibberish -[PDFBOX-2958] - TIFF-Predictor with 1 bit per component not supported -[PDFBOX-2959] - type3 font glyphs overlapped -[PDFBOX-2960] - ClassCastException when pattern name is indirect object -[PDFBOX-2961] - Checkbox with multiple widgets doesn't reflect check() state. -[PDFBOX-2965] - NPE in PDAcroForm.getField() if the /Fields entry is missing -[PDFBOX-2966] - Glyphs overlapping in rendering -[PDFBOX-2969] - RandomAccessBuffer clone is broken for non-default chunk size -[PDFBOX-2971] - CalGray white rendered as cyan -[PDFBOX-2972] - Exception when RenderingIntent value is not one of the predefined. -[PDFBOX-2976] - java.util.zip.DataFormatException: incorrect data check -[PDFBOX-2982] - fix ClassCastExceptions in operator methods -[PDFBOX-2985] - Potential NPE in PDMarkedContent#getMCID() -[PDFBOX-2986] - Potential resource leak in TTFParser's use of RAFDataStream -[PDFBOX-2989] - LZW decode filter shouldn't throw IndexOutOfBoundsException -[PDFBOX-2990] - PDDocument.load fails to load a PDF document. -[PDFBOX-2992] - Add .gitignore -[PDFBOX-2995] - PDAcroForm getDefaultAppearance throws NPE if DA is not defined -[PDFBOX-2996] - StackOverflow in Quicksort -[PDFBOX-3001] - FileSystemFontProvider cache instability -[PDFBOX-3002] - PDF files not closed after load fails -[PDFBOX-3003] - Incorrect color space processing for inline images -[PDFBOX-3005] - Incorrect property names for lists -[PDFBOX-3008] - Memory leak in preflight -[PDFBOX-3010] - SignatureOptions object must not be closed before calling saveIncremental in trunk's CreateVisibleSignature example -[PDFBOX-3012] - PDAcroForm flatten() throws ClassCastException -[PDFBOX-3013] - Incorrect accordance between attributes and properties -[PDFBOX-3014] - ZapfDingbats not finding a substitute in Windows 8.1 Pro -[PDFBOX-3018] - IOException "head is mandatory" when using getOriginalData() of TT font from TTC file -[PDFBOX-3019] - Unwanted spaces in text extraction -[PDFBOX-3021] - Class Cast Exception: COSString -> COSName -[PDFBOX-3022] - Maven repos should be https -[PDFBOX-3025] - Test case for unwanted spaces in text extraction -[PDFBOX-3027] - Incorrect enumeration of conformances for PDFAIdentificationSchema -[PDFBOX-3033] - Usage methods references incorrect package -[PDFBOX-3034] - Newly created XRef stream has direct root objects -[PDFBOX-3035] - Files with missing xref table must fail -[PDFBOX-3037] - Text extraction decodes image files -[PDFBOX-3038] - Text extraction shows glyphs with zero height -[PDFBOX-3041] - Wrong default type in Xref stream W0 element -[PDFBOX-3042] - Bad space calculation in text extraction -[PDFBOX-3056] - Make PDFTextStreamEngine public -[PDFBOX-3067] - Text strings being returned as single characters, regression from version 1.8 -[PDFBOX-3070] - Incorrect DefaultRGB color space obtain -[PDFBOX-3073] - Change to use media box for page size instead of cropbox. -[PDFBOX-3075] - Changed to the getHeight function for fonts so it will return a more accurate height -[PDFBOX-3076] - Type3 Font that is getting zero height text, even in latest 2.0 -[PDFBOX-3081] - Create example to draw glyph sizes in rendered images -[PDFBOX-3082] - High memory consumption while building font cache -[PDFBOX-3083] - Form fields are missing when rendering -[PDFBOX-3087] - Metadata stream should not be compressed -[PDFBOX-3090] - ArrayIndexOutOfBoundsException in CmapSubtable.processSubtype2 -[PDFBOX-3091] - java.lang.ClassCastException: org.apache.fontbox.cff.CharStringCommand cannot be cast to java.lang.Integer -[PDFBOX-3093] - Exception in TTFParser -[PDFBOX-3094] - Merging PDFs with a Form is not retaining the field name values -[PDFBOX-3095] - Space size NaN -[PDFBOX-3097] - ClassCastException in Axial / Radial shading when object reference in extends -[PDFBOX-3102] - getGlyphs returns empty array now -[PDFBOX-3105] - Image with mask missing in rendering -[PDFBOX-3106] - Allow access to font data -[PDFBOX-3107] - Asterisk character not displaying properly in Adobe Reader -[PDFBOX-3108] - Font cache is always rebuilt when font skipped -[PDFBOX-3109] - DrawPrintTextLocations with incorrect coordinates when cropbox -[PDFBOX-3110] - Extract by beads doesn't work -[PDFBOX-3114] - Visible signatures in different pages changes previous revision -[PDFBOX-3116] - COSNumber NumberFormatException for large number -[PDFBOX-3120] - ArrayIndexOutOfBoundsException in CodespaceRange.isPartialMatch / CMap is invalid -[PDFBOX-3130] - Recent regression in PDFTextStripper, text getting garbled -[PDFBOX-3139] - Custom FontMapper cant be used -[PDFBOX-3140] - Different fallback font rendering first and second time -[PDFBOX-3141] - Link annotation borders not rendered -[PDFBOX-3142] - PDFMergerUtility with scratch file generates result with blank pages for certain source files. -[PDFBOX-3143] - Added PDEmbeddedFile constructor with COSName parameter -[PDFBOX-3144] - NullPointerException in TTFSubsetter -[PDFBOX-3145] - Security manager fails for .pdfbox.cache -[PDFBOX-3146] - Ink annotation borders not rendered -[PDFBOX-3148] - Multiline fields won't get rendered correctly if there are multiple paragraphs in field value -[PDFBOX-3149] - Failure to decrypt empty strings (AES 128) -[PDFBOX-3151] - getStringWidth is terribly slow (and resulting document is invalid) -[PDFBOX-3152] - NullPointerException in PDType1Font.encode() with centered dot -[PDFBOX-3153] - Direct JPEG extraction results in invalid images in 2.0.0 releases. -[PDFBOX-3154] - PDDocumentCatalog.getDocumentCatalog().getPages().getCount() returns 0 - first page is -1 -[PDFBOX-3155] - org.apache.pdfbox.util.PDFTextStripper class initialization throws NumberFormatException with recent Verona-enabled Java 9 JVMs -[PDFBOX-3157] - PDOutputIntent has N=3 (RGB) hardcoded -[PDFBOX-3160] - Problem with org.apache.xmpbox.DateConverter -[PDFBOX-3164] - XFDF annotations partially incorrectly applied to existing PDF or exceptions when parsing -[PDFBOX-3167] - IllegalArgumentException: dash lengths all zero -[PDFBOX-3169] - SaveIncremental does not work without signature -[PDFBOX-3172] - PDPage.getContentStreams() always returns empty when content stream field is an array -[PDFBOX-3173] - Signature dictionary is not decrypted in encrypted files -[PDFBOX-3175] - PDFTextStreamEngine probably miscalculates text height -[PDFBOX-3179] - PDDocument.load() Error: Expected a long type at offset 2, instead got 'DF-1.4' -[PDFBOX-3181] - java.lang.ArrayIndexOutOfBoundsException: Coordinate out of bounds! in org.apache.pdfbox.pdmodel.graphics.image.LosslessFactory.createFromImage -[PDFBOX-3184] - Throwing in PDType1Font.encode for chars above 255 is wrong. -[PDFBOX-3187] - NullPointerException CFFParser -[PDFBOX-3188] - java.io.IOException: Error: source PDF is encrypted, can't append encrypted PDF documents -[PDFBOX-3189] - java.io.IOException is thrown from both NonSequentialPDFParser and PDFParser -[PDFBOX-3190] - Links don't work in firefox -[PDFBOX-3191] - PDFDebugger does not handle cancelling of "Open URL" dialog -[PDFBOX-3195] - ExtractText add space at start of text -[PDFBOX-3199] - JPEG input file not closed when creating PDImageXObject -[PDFBOX-3201] - Skip zlib-header and checksum to avoid DataFormatException -[PDFBOX-3203] - Fractional font sizes are reported scaled -[PDFBOX-3204] - JVM crashes on PDFRenderer.renderImageWithDPI -[PDFBOX-3209] - Overlay class does not work with in-memory PDFs -[PDFBOX-3217] - PdfaExtensionHelper.populatePDFAPropertyType -[PDFBOX-3219] - Suggestion for log4j.xml example inside preflight source -[PDFBOX-3221] - /TR /TR2 Transfer function not implemented -[PDFBOX-3226] - No such Element Exception processing File -[PDFBOX-3229] - Decryption fails when Metadata not encrypted but EncryptMetadata is true/default. -[PDFBOX-3237] - ASCII85Filter does not use or recognize the correct end-of-data terminator -[PDFBOX-3240] - Missing Type for standard type 1 fonts -[PDFBOX-3242] - Problem displaying document created by PDFBox 2.0RC3 in Acrobat Reader -[PDFBOX-3249] - PDAnnotationMarkup.getInReplyTo throws exception when no element -[PDFBOX-3250] - Possible errors in TrueType table 'name' parsing. -[PDFBOX-3252] - java.lang.ExceptionInInitializerError in PDFBox -[PDFBOX-3253] - Close all COSStreams when creating a new pdf -[PDFBOX-3254] - Corrupted XMP causes java.lang.StringIndexOutOfBoundsException -[PDFBOX-3258] - XMPBox XMPBasicSchema setters don't work if already set -[PDFBOX-3259] - ClassCastException in PDTilingPattern.getContents -[PDFBOX-3263] - Overlaying 2 pdfs corrupts cross-reference stream -[PDFBOX-3266] - Overlay doesn't work anymore -[PDFBOX-3268] - Corners of stroked type are inaccurate when rendered as an image -[PDFBOX-3271] - Incomplete widths array for CID-fonts [PDFBOX-3272] - Loaded fonts file descriptors open after closing document +[PDFBOX-3273] - Fonts not rendered correctly +[PDFBOX-3276] - Double encryption dictionary for files with XRef stream +[PDFBOX-3279] - PDDocument.importPage creates two inputstreams +[PDFBOX-3281] - HTML output wrongly specifies UTF-16 in header +[PDFBOX-3286] - Think I found a bad constant (TTF) value and constant use in PDFBox source +[PDFBOX-3292] - Error reading stream, expected='endstream' actual='' in non-truncated files +[PDFBOX-3297] - Infinite loop +[PDFBOX-3299] - TIFF-files with FillOrder=2 can't be converted to PDF +[PDFBOX-3301] - NPE in PDAcroForm.flatten if a widget doesn't contain a /P entry +[PDFBOX-3303] - setWidgets should set connection to parent +[PDFBOX-3308] - Missing endOfName chars +[PDFBOX-3312] - NPE in saveIncremental() / fix javadoc +[PDFBOX-3317] - Merged PDF/A files no longer valid PDF/A +[PDFBOX-3319] - Chinese character overlap other chinese character Improvement -[PDFBOX-193] - Getting tiff - PDCcitt.TiffWrapper object -[PDFBOX-408] - Optional logger calls could be added to COSDocument & PDJpeg when an error occurs. -[PDFBOX-678] - Support missing Text Rendering Modes when rendering a PDF -[PDFBOX-870] - PDF-To-IMAGE output is not anti-aliased -[PDFBOX-996] - need to insert a child as the first child of an outline but you can only append to the outline. -[PDFBOX-1083] - PDType0Font incomplete -[PDFBOX-1094] - Pattern colorspace support -[PDFBOX-1167] - PDFStreamEngine#processSubStream should throw original IOException instead of RuntimeException + FIX -[PDFBOX-1182] - Create a module for the commandline tools -[PDFBOX-1213] - Adding style information to the PDF to HTML converter -[PDFBOX-1270] - Change internal page resolution to float everywhere -[PDFBOX-1329] - Update PDPage to enum -[PDFBOX-1356] - Support lucene 3.6.0 -[PDFBOX-1384] - Proposals for a new PDNameTreeNode and PDNumberTreeNode -[PDFBOX-1402] - Improve handling of multiline text boxes -[PDFBOX-1444] - Capability to use custom PageDrawer in PDPage.convertToImage -[PDFBOX-1503] - Double logging of exceptions -[PDFBOX-1523] - Manifest should support Specification entries -[PDFBOX-1543] - Remove the ReplaceString example -[PDFBOX-1564] - Extending COSName to produce PDF/A with correct OutputIntents -[PDFBOX-1566] - reduce duplicated code and add caching to pdpagenode -[PDFBOX-1587] - Update the dependency on Bouncy Castle to 1.48 -[PDFBOX-1591] - Resources should implement java.io.closeable -[PDFBOX-1594] - Add support for AES256 Encryption -[PDFBOX-1596] - OverlayPDF logic should be moved into a library class -[PDFBOX-1613] - The ability to inject the time/random component into the COSWriter process to write a PDF document allows some advanced signature creation scenarios where the signature is generated on a separate server that does not hold the full PDF document. -[PDFBOX-1621] - Add setModifiedDate(Calendar c) to PDAnnotation -[PDFBOX-1645] - [PATCH] Improved the accuracy of the bounding box for each rendered CFF glyph -[PDFBOX-1648] - FontBox can't load CMaps with no spaces between tokens -[PDFBOX-1656] - Enable PDFMergeUtility to merge Encrypted PDFs -[PDFBOX-1665] - Replace external glyphlist.txt with our onw implementation -[PDFBOX-1667] - org.apache.pdfbox.pdmodel.graphics.color.PDOutputIntent throws Exception while it can throw IOException instead -[PDFBOX-1669] - Update the dependency on Bouncy Castle to 1.49 -[PDFBOX-1687] - add dispose() in pdfbox\pdmodel\PDPage.convertToImage() -[PDFBOX-1690] - Add description to embedded file -[PDFBOX-1695] - Improve pdfbox tests -[PDFBOX-1698] - Remove the print and the convertToImage stuff from PDPage and PDDocument -[PDFBOX-1702] - Performance improvement in PDPageContentStream.drawString -[PDFBOX-1707] - Add dispose() when done with graphics -[PDFBOX-1720] - BouncyCastle 1.49: ambigous constructor usage -[PDFBOX-1734] - ImageIoUtil.WriteImage doesn't work with tiff images -[PDFBOX-1738] - PDF with parsing IOException -[PDFBOX-1739] - Load document error for two RegisSTAR documents -[PDFBOX-1744] - Be resilient to PDFs with missing version info -[PDFBOX-1782] - Add getMaxLength() and setMaxLength() methods to PDTextbox -[PDFBOX-1784] - Update parent pom/rat plugin version -[PDFBOX-1798] - Performance problem with PDDocument.saveIncremental (when signing document) -[PDFBOX-1815] - Suggestion: close files in COSStream -[PDFBOX-1820] - Suggestion: close streams in PDIndex and PDJpeg -[PDFBOX-1828] - Remove not needed CMaps -[PDFBOX-1833] - BaseParser tidy up -[PDFBOX-1834] - Remove old Overlay implementation -[PDFBOX-1836] - Use the latest dependencies -[PDFBOX-1839] - PDFImageWriter default BufferedImage type makes output colors look poor -[PDFBOX-1840] - Automatically load isartor for preflight tests -[PDFBOX-1844] - [PATCH] Parser for Type 1 Fonts -[PDFBOX-1847] - TSA Time Signature -[PDFBOX-1850] - Speed up TestImageIOUtils -[PDFBOX-1851] - [PATCH] Improved CMYK color space conversion -[PDFBOX-1852] - [PATCH] Alternative patch to speed up TestImageIOUtils -[PDFBOX-1854] - Include AFM files for Core 14 fonts -[PDFBOX-1889] - Remove the ConvertColorspace class -[PDFBOX-1890] - Merge PdfDecompressor and WriteDecodedDoc -[PDFBOX-1891] - Remove the ant module -[PDFBOX-1893] - Refactor color spaces -[PDFBOX-1897] - There are some errors within the source code documentation (javadocs) -[PDFBOX-1902] - generics added to maputil -[PDFBOX-1903] - refactor pdmodel (pdpage) -[PDFBOX-1905] - Remove the PDPage reference from PageDrawer/PDFStreamEngine -[PDFBOX-1906] - Don't use a src subdirectory as output directory for a test case -[PDFBOX-1909] - Close open streams -[PDFBOX-1914] - Shading package: Move "function" methods to base class and more refactoring -[PDFBOX-1915] - Implement shading with Coons and tensor-product patch meshes -[PDFBOX-1941] - Refactor PageDrawer operators -[PDFBOX-1943] - Move pdfbox-tools to its own package -[PDFBOX-1959] - Remove AWT Fonts -[PDFBOX-1962] - Refactor the packages in the core pdfbox module -[PDFBOX-1963] - PDFImageWriter doesn't make use of PDFStreamEngine -[PDFBOX-1964] - PDFMergerUtility support merging using non sequential parser -[PDFBOX-1972] - WrappedIOException no longer needed in Java 1.6 -[PDFBOX-1973] - Exception Refactoring (Don't wrap Exceptions with COSVisitorException) -[PDFBOX-1976] - DocumentEncryption and PDFEncryption are deprecated and should be removed -[PDFBOX-1982] - Standardise AcroForm Fields -[PDFBOX-1985] - Replace List with List in PDDocument and PDPageNode -[PDFBOX-1986] - Move SecurityHandler to PDEncryptionDictionary -[PDFBOX-1989] - Save LZW and other encoded PDImageXObject resources -[PDFBOX-1990] - Support creating PDF from lossless encoded images -[PDFBOX-1991] - Shading PaintContexts should not depend on the page height -[PDFBOX-2002] - Show deprecation in the build / fix deprecated calls / delete longtime deprecated stuff -[PDFBOX-2034] - TestFilters is non-deterministic -[PDFBOX-2039] - Class PDDocument should implement java.io.Closeable -[PDFBOX-2051] - PDFPrinter does not use getPageable() -[PDFBOX-2052] - PDFCloneUtility does not handle COSStreamArray -[PDFBOX-2066] - RubberStampWithImage should support more image types -[PDFBOX-2068] - Add filter parameter to PDImageXObject(document, filteredStream) constructor -[PDFBOX-2071] - Insert inline image in page content stream -[PDFBOX-2088] - Support Bouncycastle 1.50 -[PDFBOX-2094] - Add PrintRequestAttributeSet parameter to silentPrint() -[PDFBOX-2097] - Remove pdfbox-war subproject -[PDFBOX-2099] - Improve handling and writing of header and trailer versions -[PDFBOX-2104] - Implement transparency groups -[PDFBOX-2105] - Support for multipage TIFFs in CCITTFactory, makes PDFBox capable of doing tiff2pdf -[PDFBOX-2107] - Make PDFBox XMP library agnostic -[PDFBOX-2113] - Update documentation to reflect the requirement for JBIG2 decoders -[PDFBOX-2118] - Remove ICU4J dependency -[PDFBOX-2123] - Optimize reading of 1-bit depth images in SampleImageReader -[PDFBOX-2126] - Optimize clipping -[PDFBOX-2127] - Optimize calls of getPixel in SampledImageReader and PDImageXObject -[PDFBOX-2129] - Add PDFBox version to the title -[PDFBOX-2131] - Avoid constructing debug messages if debug log is off -[PDFBOX-2132] - Provide a pluggable exception handler to PDFStreamEngine -[PDFBOX-2136] - Use the Type1Parser to extract the encoding -[PDFBOX-2144] - Provide a pluggable font manager -[PDFBOX-2146] - remove unused imports / fix imports -[PDFBOX-2148] - Handle the Fully Qualified Name of duplicate fields better -[PDFBOX-2149] - Font Refactoring -[PDFBOX-2151] - Replace log4j with commons logging -[PDFBOX-2152] - Unable to print the PDF with Acrobat shrink to fit print -[PDFBOX-2157] - Remove AFMFormatter -[PDFBOX-2174] - Suppress the Dock icon on OS X -[PDFBOX-2196] - [PATCH] Type safety in PDNameTreeNode and PDNumberTreeNode via generics -[PDFBOX-2205] - (Graphics) Operator Refactoring -[PDFBOX-2220] - [PATCH] Differences array without BaseEncoding (Type1C) -[PDFBOX-2239] - Add missing values to PDComplexFileSpecification -[PDFBOX-2250] - Improve XRef self healing mechanism -[PDFBOX-2262] - Remove usage of AWT fonts -[PDFBOX-2269] - Support for AES-256 Rev. 5 Decryption (Acrobat 9) -[PDFBOX-2294] - Improve vertical text drawing as an experiment -[PDFBOX-2302] - Make better use of RenderingHints -[PDFBOX-2303] - Lazy loading of glyphs in TrueType fonts -[PDFBOX-2328] - Give PDColor access to its underling PDColorSpace -[PDFBOX-2329] - add toString method to PDRange -[PDFBOX-2333] - Overhaul the appearance generation for PDF forms -[PDFBOX-2362] - Remove .properties file usage in PDFStreamEngine -[PDFBOX-2366] - Improve high-level font APIs -[PDFBOX-2370] - Move caching outside of PDResources -[PDFBOX-2374] - Make JavaDocs for trunk builds available via our website -[PDFBOX-2386] - Move operators and content streams out of "pdfbox.util" -[PDFBOX-2387] - ImageIOUtil, JPEGUtil, TIFFUtil and MetaUtil are not needed in "pdfbox" -[PDFBOX-2388] - Move printing classes into top-level "printing" package -[PDFBOX-2389] - Move Encoding classes into "font" package -[PDFBOX-2391] - Use an enum for RenderingIntent -[PDFBOX-2392] - PDPropertyList belongs in "markedcontent" package -[PDFBOX-2394] - Add example code to extract embedded files in annotations -[PDFBOX-2414] - Allow non-sequential parser for PDFMerger in app -[PDFBOX-2423] - Page tree handling needs rewriting -[PDFBOX-2430] - Make the non-sequential parser the default parser -[PDFBOX-2440] - xref stream is saved as table -[PDFBOX-2444] - Add radial shading example -[PDFBOX-2452] - Continuous log "Nonsymbolic Type 0 font: SNCFYS+ARStdKai" -[PDFBOX-2456] - create TestSymmetricKeyEncryption.java -[PDFBOX-2459] - Share functionality between Page Tree and Field Tree -[PDFBOX-2461] - Clear Checkstyle errors in source -[PDFBOX-2464] - Document crypto build dependencies -[PDFBOX-2467] - "Arial,Bold" always substituted with "Helvetica-Bold" -[PDFBOX-2468] - Switch FDFDocument.load from PDFParser to NonSequentialParser -[PDFBOX-2473] - Remove the CopyDoc example -[PDFBOX-2474] - Remove the direct usage of PDFParser -[PDFBOX-2515] - Improve the non sequential parser to be used when signing a pdf -[PDFBOX-2516] - Further align AcroForms and Fields PDModel with PDF specification -[PDFBOX-2530] - Improve PDFDebugger -[PDFBOX-2565] - Subset embedded TTF fonts -[PDFBOX-2566] - Remove logging from operator classes -[PDFBOX-2580] - Decouple implementation specific forms handling from interactive.form PD Model -[PDFBOX-2587] - PDF takes minutes to convert (sRGB) -[PDFBOX-2590] - Improve PDPageContentStream API -[PDFBOX-2591] - Allow using custom Filters -[PDFBOX-2592] - Allow sharing of COS objects between different documents -[PDFBOX-2594] - Set default params in JBIG2Filter -[PDFBOX-2597] - Provide easier access to AcroForm field tree -[PDFBOX-2600] - Remove old parser -[PDFBOX-2623] - PDFPrinter.getPrintable returns Pageable instead of PDFPageable for easier extending -[PDFBOX-2628] - XmpSerializer will never throw XmpSerializationException -[PDFBOX-2645] - Open PDF file from byte array without temp file -[PDFBOX-2669] - Make internal PageDrawer font classes package-private -[PDFBOX-2670] - Move orphaned COSObjectKey class -[PDFBOX-2680] - Move multi-pdf classes from util into their own package -[PDFBOX-2683] - Remove SignatureInterface dependency from COSDocument -[PDFBOX-2689] - Implement page transitions -[PDFBOX-2695] - Iterate PDOutlineNode children -[PDFBOX-2700] - support JPEG color space code 11 (JCS_YCCK) -[PDFBOX-2703] - Remove javacc generated PDFParser from preflight -[PDFBOX-2707] - Remove redundant IOUtils.closeQuietly -[PDFBOX-2716] - Use saveIncremental() method on a document opened with an InputStream does not work -[PDFBOX-2727] - Cache color space instances -[PDFBOX-2735] - Keyboard shortcuts in PDFReader -[PDFBOX-2736] - First page and last page navigation with keyboard shortcuts in PDFReader -[PDFBOX-2744] - Add validation check for setNonStrokingColor and setStrokingColor -[PDFBOX-2748] - Recent files in PDF reader -[PDFBOX-2753] - Improve rendering of filled thin lines -[PDFBOX-2758] - Support additional annotation types when importing XFDF files -[PDFBOX-2764] - Allow setting extended graphics state in PDPageContentStream -[PDFBOX-2777] - Create convenience method to create an XImage object -[PDFBOX-2782] - Enhance toString() output for AcroForm fields -[PDFBOX-2791] - Provide access to Type 1 font data -[PDFBOX-2806] - The 'kern' table type is not supported. -[PDFBOX-2807] - The vertical layout table types 'vhea', 'vmtx', 'VORG' are not supported. -[PDFBOX-2838] - Please make PDPageContentStream non-final -[PDFBOX-2841] - Make it easier to work with RadioButton Groups -[PDFBOX-2842] - Overhaul font substitution -[PDFBOX-2865] - Downgrade logging "Using last-resort fallback for x font" to warn in 2.0.0? -[PDFBOX-2870] - Use animal sniffer maven plugin to detect non java 6 api usage -[PDFBOX-2878] - Align annotation and form public API -[PDFBOX-2880] - Allow Type 1 embedding without AFM file -[PDFBOX-2882] - Improve performance when using scratch file -[PDFBOX-2883] - Unify memory handling -[PDFBOX-2888] - setAllSecurityToBeRemoved(true) before calling protect() should have no effect -[PDFBOX-2892] - Invisible signature annotation violates PDF/A -[PDFBOX-2893] - Simplify COSStream encoding and decoding -[PDFBOX-2894] - Remove COSStreamArray / SequenceRandomAccessRead -[PDFBOX-2905] - Replace PDFReader with PDFDebugger -[PDFBOX-2918] - Allow to refresh an AcroForm field appearance -[PDFBOX-2922] - Printing issues with landscape pages -[PDFBOX-2928] - Add numPages parameter of Book in Printing.printWithPaper example -[PDFBOX-2931] - Make PDFPrintable margin-aligning and centering optional -[PDFBOX-2933] - Drop ant build including .NET build support -[PDFBOX-2943] - PDType3Font.getWidthFromFont not supported -[PDFBOX-2945] - PDType1Font.getNameInFont(String) very slow when Unicode fallback is used -[PDFBOX-2962] - Handle TIFF predictor for bpc 2 and 4 / optimize existing predictor code -[PDFBOX-2970] - Add capability to flatten AcroForm form fields -[PDFBOX-2973] - Actions shortage -[PDFBOX-2978] - Add support for grouped checkboxes -[PDFBOX-2997] - Make FontMapper into a singleton interface -[PDFBOX-3072] - Allow missing page type -[PDFBOX-3084] - More generic PDPageContentStream constructor -[PDFBOX-3088] - Cache glyph table to optimize concurrent access -[PDFBOX-3103] - Slow performance when printing PDF (fix provided) -[PDFBOX-3104] - Font Cache is taking a lot of time -[PDFBOX-3115] - Fix high memory usage during signing -[PDFBOX-3121] - Buffer save(File) -[PDFBOX-3122] - IllegalArgumentException: dash lengths all zero -[PDFBOX-3131] - Reduce amount of intermediate data and objects to reduce memory footprint/complexity -[PDFBOX-3133] - PDFBox 2.0.0-RC2 and earlier 2.0.0 SNAPSHOT Versions print performance is poor with systems having low RAM < 3GB and lower number of fonts. -[PDFBOX-3137] - Reduce/remove dependency on commons.io in preflight/xmpbox -[PDFBOX-3158] - Add constructor with BufferedImage to PDVisibleSignDesigner -[PDFBOX-3161] - No glyph for U+0009 in font ArialUnicodeMS -[PDFBOX-3163] - PDImageXObject.createFromFile should relies on header bytes -[PDFBOX-3176] - Add a removeRegion method in PDFTextSTripperByArea class -[PDFBOX-3178] - Make PDFTextStreamEngine class public -[PDFBOX-3200] - Performance improvement in PDPageContentStream.setFont -[PDFBOX-3202] - Rename structure element setter of PDOutlineItem -[PDFBOX-3224] - Cache Font Bounding Boxes for Performance in Text Extraction -[PDFBOX-3231] - Update PDPropBuildDataDict -[PDFBOX-3234] - Rename check box field type to match PDF 2.0 specification -[PDFBOX-3245] - Add fill and stroke operators - -New Feature - -[PDFBOX-52] - DCTFilter is not implemented yet -[PDFBOX-149] - Update encryption algorithms -[PDFBOX-151] - Correct calculation of Type0Font size. -[PDFBOX-615] - shfill operator needs implementation -[PDFBOX-830] - Setting of logical page numbers -[PDFBOX-922] - True type PDFont subclass only supports WinAnsiEncoding (hardcoded!) -[PDFBOX-953] - PDFBox fails to ExtractText from Adobe Acrobat X 256-bit AES encrypted documents -[PDFBOX-1054] - DateConverter: allow for external adding of potential date parsing formats -[PDFBOX-1209] - Add insertSiblingBefore() to PDOutlineItem -[PDFBOX-1223] - Strange color issues with convertToImage method -[PDFBOX-1462] - Use file backed buffer for FlateFilter? -[PDFBOX-1494] - PDF box color distortion -[PDFBOX-1589] - Switch to java 1.6 as minimum requirement for PDFBox -[PDFBOX-1766] - [PATCH] Visible Signature using PDFbox -[PDFBOX-2211] - Create sample code for creating a PDF with shading -[PDFBOX-2276] - Remove Jempbox subproject -[PDFBOX-2400] - Add insertPage() method -[PDFBOX-2624] - "CIDSet entry is missing for the Composite Subset" when creating PDF/A-1b file with PDType0Font.load() -[PDFBOX-2673] - Add output path prefix param in PDFSplit/Splitter -[PDFBOX-2752] - Support TTC font files -[PDFBOX-2766] - Missing PDDocument.load() overload -[PDFBOX-2821] - Add PDDocument(boolean) constructor for creating new documents using scratch files -[PDFBOX-3074] - Mark transparency groups - -Task - -[PDFBOX-1600] - COSDocument and PDDocument declare throws IOException when they don't -[PDFBOX-1675] - Preflight : improve error information -[PDFBOX-1685] - Verify interpretation of rdf:about for PDF/A -[PDFBOX-1975] - Improve TestImageIOUtils unit tests to check image resolution and compression -[PDFBOX-2197] - Add sample how to import a page as PDFormXObject -[PDFBOX-2480] - Add information about Snapshots to download section -[PDFBOX-2576] - Improve code quality -[PDFBOX-2610] - Expand Isartor test for Bavaria test suite and other tests -[PDFBOX-2674] - Remove two unused methods from COSStream -[PDFBOX-2712] - Remove commented out lines of code -[PDFBOX-2762] - remove parseCOSStream() call from PDFStreamParser -[PDFBOX-2768] - Remove VisualSignatureParser -[PDFBOX-3011] - Find out why trunk CreateVisibleSignature example produces incorrect output pdf -[PDFBOX-3020] - Set libraries to current versions for RC -[PDFBOX-3040] - Move website to local build tool -[PDFBOX-3058] - Support TIKA Migration to PDFBox 2.0 - -Test - -[PDFBOX-1584] - Add unit test for RandomAccessFileOutputStream -[PDFBOX-1673] - Tests with selection of files from Adobe Acrobat Engineering website -[PDFBOX-2369] - how to convert pdf to image - -Wish - -[PDFBOX-1187] - Cut dependency between pdfbox and jempbox -[PDFBOX-1224] - Angle units are not consistent -[PDFBOX-1450] - document how to encrypt with AES 256 with the release of 2.0 -[PDFBOX-1540] - Add XML output option to preflight -[PDFBOX-1590] - Unify logging between preflight and other modules -[PDFBOX-1769] - Fix crash on invalid xref -[PDFBOX-1946] - Running within an Applet has many AccessControlException 's -[PDFBOX-2011] - Please extend base class "Encoding" with 2 methods to access global name2char and char2name maps -[PDFBOX-2012] - Extend CMAPEncodingEntry API -[PDFBOX-2013] - Please extend PDTrueTypeFont API -[PDFBOX-2190] - Disable console logging for preflight Isartor tests -[PDFBOX-2209] - [PATCH] Restore shading API -[PDFBOX-2692] - Possibility to use our own and/or overwrite PageDrawer class -[PDFBOX-2738] - Make org.apache.pdfbox.pdmodel.PDDocument#getFontsToSubset public -[PDFBOX-2770] - Provide the sources along with SNAPSHOT releases -[PDFBOX-3233] - Create default resources with cache +[PDFBOX-3275] - Show glyph bounds in DrawPrintTextLocations +[PDFBOX-3289] - Wrong unit MM_PER_INCH in PDRectangle +[PDFBOX-3295] - Improve parsing performance of object streams +[PDFBOX-3305] - PDPageContentStream should allow drawing images at current position +[PDFBOX-3307] - Enable AES128 encryption +[PDFBOX-3323] - Cannot set destination meta data in PDFMergerUtility Release Contents ---------------- From 696cccbaf9c1748a30809c1e9cf66940059e9a12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Lehmk=C3=BChler?= Date: Fri, 22 Apr 2016 17:02:28 +0000 Subject: [PATCH 0037/2182] [maven-release-plugin] prepare release 2.0.1 git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1740567 13f79535-47bb-0310-9956-ffa450edef68 --- app/pom.xml | 2 +- debugger-app/pom.xml | 2 +- debugger/pom.xml | 2 +- examples/pom.xml | 2 +- fontbox/pom.xml | 2 +- parent/pom.xml | 8 ++++---- pdfbox/pom.xml | 2 +- pom.xml | 8 ++++---- preflight-app/pom.xml | 2 +- preflight/pom.xml | 2 +- tools/pom.xml | 2 +- xmpbox/pom.xml | 2 +- 12 files changed, 18 insertions(+), 18 deletions(-) diff --git a/app/pom.xml b/app/pom.xml index d190b69e299..1fb2321b09b 100644 --- a/app/pom.xml +++ b/app/pom.xml @@ -23,7 +23,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.1-SNAPSHOT + 2.0.1 ../parent/pom.xml diff --git a/debugger-app/pom.xml b/debugger-app/pom.xml index 8813ffba10a..f71f0d7b537 100644 --- a/debugger-app/pom.xml +++ b/debugger-app/pom.xml @@ -23,7 +23,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.1-SNAPSHOT + 2.0.1 ../parent/pom.xml diff --git a/debugger/pom.xml b/debugger/pom.xml index dcb3aabb337..3ef24e61a34 100644 --- a/debugger/pom.xml +++ b/debugger/pom.xml @@ -23,7 +23,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.1-SNAPSHOT + 2.0.1 ../parent/pom.xml diff --git a/examples/pom.xml b/examples/pom.xml index b6ba2c1f863..00de6453a21 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -23,7 +23,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.1-SNAPSHOT + 2.0.1 ../parent/pom.xml diff --git a/fontbox/pom.xml b/fontbox/pom.xml index 6a5da3b1c89..bb1e681fdb6 100644 --- a/fontbox/pom.xml +++ b/fontbox/pom.xml @@ -21,7 +21,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.1-SNAPSHOT + 2.0.1 ../parent/pom.xml diff --git a/parent/pom.xml b/parent/pom.xml index b2b441f0bb4..0a9f65e75f1 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -29,7 +29,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.1-SNAPSHOT + 2.0.1 pom PDFBox parent @@ -377,8 +377,8 @@ - scm:svn:http://svn.apache.org/repos/asf/maven/pom/branches/2.0/pdfbox-parent - scm:svn:https://svn.apache.org/repos/asf/maven/pom/branches/2.0/pdfbox-parent - http://svn.apache.org/viewvc/maven/pom/branches/2.0/pdfbox-parent + scm:svn:http://svn.apache.org/repos/asf/maven/pom/tags/2.0.1/pdfbox-parent + scm:svn:https://svn.apache.org/repos/asf/maven/pom/tags/2.0.1/pdfbox-parent + http://svn.apache.org/viewvc/maven/pom/tags/2.0.1/pdfbox-parent diff --git a/pdfbox/pom.xml b/pdfbox/pom.xml index 15f02219808..4c63ec05b75 100644 --- a/pdfbox/pom.xml +++ b/pdfbox/pom.xml @@ -23,7 +23,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.1-SNAPSHOT + 2.0.1 ../parent/pom.xml diff --git a/pom.xml b/pom.xml index d27d3fcfeb9..8b87ea194c9 100644 --- a/pom.xml +++ b/pom.xml @@ -23,7 +23,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.1-SNAPSHOT + 2.0.1 parent/pom.xml @@ -34,12 +34,12 @@ - scm:svn:http://svn.apache.org/repos/asf/pdfbox/branches/2.0 + scm:svn:http://svn.apache.org/repos/asf/pdfbox/tags/2.0.1 - scm:svn:https://svn.apache.org/repos/asf/pdfbox/branches/2.0 + scm:svn:https://svn.apache.org/repos/asf/pdfbox/tags/2.0.1 - http://svn.apache.org/viewvc/pdfbox/branches/2.0 + http://svn.apache.org/viewvc/pdfbox/tags/2.0.1 diff --git a/preflight-app/pom.xml b/preflight-app/pom.xml index d704beaee5a..d2fe8a26a85 100644 --- a/preflight-app/pom.xml +++ b/preflight-app/pom.xml @@ -23,7 +23,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.1-SNAPSHOT + 2.0.1 ../parent/pom.xml diff --git a/preflight/pom.xml b/preflight/pom.xml index 8ac09f49b4f..f3af5937b60 100644 --- a/preflight/pom.xml +++ b/preflight/pom.xml @@ -26,7 +26,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.1-SNAPSHOT + 2.0.1 ../parent/pom.xml diff --git a/tools/pom.xml b/tools/pom.xml index daf2fc3ae82..5d207dbe864 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -23,7 +23,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.1-SNAPSHOT + 2.0.1 ../parent/pom.xml diff --git a/xmpbox/pom.xml b/xmpbox/pom.xml index 556f816dda8..01108fe29af 100644 --- a/xmpbox/pom.xml +++ b/xmpbox/pom.xml @@ -27,7 +27,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.1-SNAPSHOT + 2.0.1 ../parent/pom.xml From a2f46dec3c861670bddbb22999433aadae838896 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Lehmk=C3=BChler?= Date: Fri, 22 Apr 2016 17:02:47 +0000 Subject: [PATCH 0038/2182] [maven-release-plugin] prepare for next development iteration git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1740569 13f79535-47bb-0310-9956-ffa450edef68 --- app/pom.xml | 2 +- debugger-app/pom.xml | 2 +- debugger/pom.xml | 2 +- examples/pom.xml | 2 +- fontbox/pom.xml | 2 +- parent/pom.xml | 8 ++++---- pdfbox/pom.xml | 2 +- pom.xml | 8 ++++---- preflight-app/pom.xml | 2 +- preflight/pom.xml | 2 +- tools/pom.xml | 2 +- xmpbox/pom.xml | 2 +- 12 files changed, 18 insertions(+), 18 deletions(-) diff --git a/app/pom.xml b/app/pom.xml index 1fb2321b09b..dc7144c67a8 100644 --- a/app/pom.xml +++ b/app/pom.xml @@ -23,7 +23,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.1 + 2.0.2-SNAPSHOT ../parent/pom.xml diff --git a/debugger-app/pom.xml b/debugger-app/pom.xml index f71f0d7b537..9e0c45cc527 100644 --- a/debugger-app/pom.xml +++ b/debugger-app/pom.xml @@ -23,7 +23,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.1 + 2.0.2-SNAPSHOT ../parent/pom.xml diff --git a/debugger/pom.xml b/debugger/pom.xml index 3ef24e61a34..88c56defcd0 100644 --- a/debugger/pom.xml +++ b/debugger/pom.xml @@ -23,7 +23,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.1 + 2.0.2-SNAPSHOT ../parent/pom.xml diff --git a/examples/pom.xml b/examples/pom.xml index 00de6453a21..1faf4c07ff6 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -23,7 +23,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.1 + 2.0.2-SNAPSHOT ../parent/pom.xml diff --git a/fontbox/pom.xml b/fontbox/pom.xml index bb1e681fdb6..f059397f8f2 100644 --- a/fontbox/pom.xml +++ b/fontbox/pom.xml @@ -21,7 +21,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.1 + 2.0.2-SNAPSHOT ../parent/pom.xml diff --git a/parent/pom.xml b/parent/pom.xml index 0a9f65e75f1..54cd845d502 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -29,7 +29,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.1 + 2.0.2-SNAPSHOT pom PDFBox parent @@ -377,8 +377,8 @@ - scm:svn:http://svn.apache.org/repos/asf/maven/pom/tags/2.0.1/pdfbox-parent - scm:svn:https://svn.apache.org/repos/asf/maven/pom/tags/2.0.1/pdfbox-parent - http://svn.apache.org/viewvc/maven/pom/tags/2.0.1/pdfbox-parent + scm:svn:http://svn.apache.org/repos/asf/maven/pom/branches/2.0/pdfbox-parent + scm:svn:https://svn.apache.org/repos/asf/maven/pom/branches/2.0/pdfbox-parent + http://svn.apache.org/viewvc/maven/pom/branches/2.0/pdfbox-parent diff --git a/pdfbox/pom.xml b/pdfbox/pom.xml index 4c63ec05b75..d04466a07ef 100644 --- a/pdfbox/pom.xml +++ b/pdfbox/pom.xml @@ -23,7 +23,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.1 + 2.0.2-SNAPSHOT ../parent/pom.xml diff --git a/pom.xml b/pom.xml index 8b87ea194c9..b5ed02fdf53 100644 --- a/pom.xml +++ b/pom.xml @@ -23,7 +23,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.1 + 2.0.2-SNAPSHOT parent/pom.xml @@ -34,12 +34,12 @@ - scm:svn:http://svn.apache.org/repos/asf/pdfbox/tags/2.0.1 + scm:svn:http://svn.apache.org/repos/asf/pdfbox/branches/2.0 - scm:svn:https://svn.apache.org/repos/asf/pdfbox/tags/2.0.1 + scm:svn:https://svn.apache.org/repos/asf/pdfbox/branches/2.0 - http://svn.apache.org/viewvc/pdfbox/tags/2.0.1 + http://svn.apache.org/viewvc/pdfbox/branches/2.0 diff --git a/preflight-app/pom.xml b/preflight-app/pom.xml index d2fe8a26a85..8afec57668e 100644 --- a/preflight-app/pom.xml +++ b/preflight-app/pom.xml @@ -23,7 +23,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.1 + 2.0.2-SNAPSHOT ../parent/pom.xml diff --git a/preflight/pom.xml b/preflight/pom.xml index f3af5937b60..9f8c4ff59df 100644 --- a/preflight/pom.xml +++ b/preflight/pom.xml @@ -26,7 +26,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.1 + 2.0.2-SNAPSHOT ../parent/pom.xml diff --git a/tools/pom.xml b/tools/pom.xml index 5d207dbe864..291612a973c 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -23,7 +23,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.1 + 2.0.2-SNAPSHOT ../parent/pom.xml diff --git a/xmpbox/pom.xml b/xmpbox/pom.xml index 01108fe29af..84ff8d6ffd3 100644 --- a/xmpbox/pom.xml +++ b/xmpbox/pom.xml @@ -27,7 +27,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.1 + 2.0.2-SNAPSHOT ../parent/pom.xml From 09691750711c46d980623bb442da0bde0c81d8c9 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Fri, 22 Apr 2016 20:39:20 +0000 Subject: [PATCH 0039/2182] PDFBOX-2941: support signature flags git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1740607 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/pdfbox/debugger/PDFDebugger.java | 1 + .../debugger/flagbitspane/FlagBitsPane.java | 6 ++ .../pdfbox/debugger/flagbitspane/SigFlag.java | 64 +++++++++++++++++++ 3 files changed, 71 insertions(+) create mode 100644 debugger/src/main/java/org/apache/pdfbox/debugger/flagbitspane/SigFlag.java diff --git a/debugger/src/main/java/org/apache/pdfbox/debugger/PDFDebugger.java b/debugger/src/main/java/org/apache/pdfbox/debugger/PDFDebugger.java index a81e515d196..8b512198f85 100644 --- a/debugger/src/main/java/org/apache/pdfbox/debugger/PDFDebugger.java +++ b/debugger/src/main/java/org/apache/pdfbox/debugger/PDFDebugger.java @@ -712,6 +712,7 @@ private boolean isFlagNode(Object selectedNode, Object parentNode) (COSName.F.equals(key) && isAnnot(parentNode)) || COSName.FF.equals(key) || COSName.PANOSE.equals(key) || + COSName.SIG_FLAGS.equals(key) || (COSName.P.equals(key) && isEncrypt(parentNode)); } return false; diff --git a/debugger/src/main/java/org/apache/pdfbox/debugger/flagbitspane/FlagBitsPane.java b/debugger/src/main/java/org/apache/pdfbox/debugger/flagbitspane/FlagBitsPane.java index 7b8520c4460..01d2db27147 100644 --- a/debugger/src/main/java/org/apache/pdfbox/debugger/flagbitspane/FlagBitsPane.java +++ b/debugger/src/main/java/org/apache/pdfbox/debugger/flagbitspane/FlagBitsPane.java @@ -77,6 +77,12 @@ private void createPane(final COSDictionary dictionary, final COSName flagType) view = new FlagBitsPaneView( flag.getFlagType(), flag.getFlagValue(), flag.getFlagBits(), flag.getColumnNames()); } + if (COSName.SIG_FLAGS.equals(flagType)) + { + flag = new SigFlag(dictionary); + view = new FlagBitsPaneView( + flag.getFlagType(), flag.getFlagValue(), flag.getFlagBits(), flag.getColumnNames()); + } } /** diff --git a/debugger/src/main/java/org/apache/pdfbox/debugger/flagbitspane/SigFlag.java b/debugger/src/main/java/org/apache/pdfbox/debugger/flagbitspane/SigFlag.java new file mode 100644 index 00000000000..aa2ff76ffa3 --- /dev/null +++ b/debugger/src/main/java/org/apache/pdfbox/debugger/flagbitspane/SigFlag.java @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.pdfbox.debugger.flagbitspane; + +import org.apache.pdfbox.cos.COSDictionary; +import org.apache.pdfbox.cos.COSName; +import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm; + +/** + * @author Tilman Hausherr + * + * A class that provides signature flag bits. + */ +public class SigFlag extends Flag +{ + private final COSDictionary acroformDictionary; + + /** + * Constructor + * + * @param acroFormDictionary COSDictionary instance. + */ + SigFlag(COSDictionary acroFormDictionary) + { + acroformDictionary = acroFormDictionary; + } + + @Override + String getFlagType() + { + return "Signature flag"; + } + + @Override + String getFlagValue() + { + return "Flag value: " + acroformDictionary.getInt(COSName.SIG_FLAGS); + } + + @Override + Object[][] getFlagBits() + { + PDAcroForm acroForm = new PDAcroForm(null, acroformDictionary); + return new Object[][]{ + new Object[]{1, "SignaturesExist", acroForm.isSignaturesExist()}, + new Object[]{2, "AppendOnly", acroForm.isAppendOnly()}, + }; + } +} From 276597e14099c63f445989489c2bfe9ba9878df8 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Mon, 25 Apr 2016 16:38:23 +0000 Subject: [PATCH 0040/2182] PDFBOX-3326 return correct result for STROKE_CLIP, thanks PDFBOX-3326 git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1740862 13f79535-47bb-0310-9956-ffa450edef68 --- .../pdmodel/graphics/state/RenderingMode.java | 240 +++++++++--------- 1 file changed, 120 insertions(+), 120 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/state/RenderingMode.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/state/RenderingMode.java index 32932fa1d42..a0426bc113d 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/state/RenderingMode.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/state/RenderingMode.java @@ -1,120 +1,120 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.pdfbox.pdmodel.graphics.state; - -/** - * Text Rendering Mode. - * - * @author John Hewson - */ -public enum RenderingMode -{ - /** - * Fill text. - */ - FILL(0), - - /** - * Stroke text. - */ - STROKE(1), - - /** - * Fill, then stroke text. - */ - FILL_STROKE(2), - - /** - * Neither fill nor stroke text (invisible) - */ - NEITHER(3), - - /** - * Fill text and add to path for clipping. - */ - FILL_CLIP(4), - - /** - * Stroke text and add to path for clipping. - */ - STROKE_CLIP(5), - - /** - * Fill, then stroke text and add to path for clipping. - */ - FILL_STROKE_CLIP(6), - - /** - * Add text to path for clipping. - */ - NEITHER_CLIP(7); - - private static final RenderingMode[] VALUES = RenderingMode.values(); - - public static RenderingMode fromInt(int value) - { - return VALUES[value]; - } - - private final int value; - - RenderingMode(int value) - { - this.value = value; - } - - /** - * Returns the integer value of this mode, as used in a PDF file. - */ - public int intValue() - { - return value; - } - - /** - * Returns true is this mode fills text. - */ - public boolean isFill() - { - return this == FILL || - this == FILL_STROKE || - this == FILL_CLIP || - this == FILL_STROKE_CLIP; - } - - /** - * Returns true is this mode strokes text. - */ - public boolean isStroke() - { - return this == STROKE || - this == FILL_STROKE || - this == STROKE || - this == FILL_STROKE_CLIP; - } - - /** - * Returns true is this mode clips text. - */ - public boolean isClip() - { - return this == FILL_CLIP || - this == STROKE_CLIP || - this == FILL_STROKE_CLIP || - this == NEITHER_CLIP; - } -} +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.pdfbox.pdmodel.graphics.state; + +/** + * Text Rendering Mode. + * + * @author John Hewson + */ +public enum RenderingMode +{ + /** + * Fill text. + */ + FILL(0), + + /** + * Stroke text. + */ + STROKE(1), + + /** + * Fill, then stroke text. + */ + FILL_STROKE(2), + + /** + * Neither fill nor stroke text (invisible) + */ + NEITHER(3), + + /** + * Fill text and add to path for clipping. + */ + FILL_CLIP(4), + + /** + * Stroke text and add to path for clipping. + */ + STROKE_CLIP(5), + + /** + * Fill, then stroke text and add to path for clipping. + */ + FILL_STROKE_CLIP(6), + + /** + * Add text to path for clipping. + */ + NEITHER_CLIP(7); + + private static final RenderingMode[] VALUES = RenderingMode.values(); + + public static RenderingMode fromInt(int value) + { + return VALUES[value]; + } + + private final int value; + + RenderingMode(int value) + { + this.value = value; + } + + /** + * Returns the integer value of this mode, as used in a PDF file. + */ + public int intValue() + { + return value; + } + + /** + * Returns true is this mode fills text. + */ + public boolean isFill() + { + return this == FILL || + this == FILL_STROKE || + this == FILL_CLIP || + this == FILL_STROKE_CLIP; + } + + /** + * Returns true is this mode strokes text. + */ + public boolean isStroke() + { + return this == STROKE || + this == FILL_STROKE || + this == STROKE_CLIP || + this == FILL_STROKE_CLIP; + } + + /** + * Returns true is this mode clips text. + */ + public boolean isClip() + { + return this == FILL_CLIP || + this == STROKE_CLIP || + this == FILL_STROKE_CLIP || + this == NEITHER_CLIP; + } +} From 29e604197bcccc3d5398d5f7702f27f508247bb6 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Wed, 27 Apr 2016 15:43:42 +0000 Subject: [PATCH 0041/2182] PDFBOX-3327: simplify and avoid alleged IOOBE as proposed by Tim Koopman git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1741280 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/fontbox/ttf/KerningSubtable.java | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/fontbox/src/main/java/org/apache/fontbox/ttf/KerningSubtable.java b/fontbox/src/main/java/org/apache/fontbox/ttf/KerningSubtable.java index dcae5117060..51fcae73a52 100644 --- a/fontbox/src/main/java/org/apache/fontbox/ttf/KerningSubtable.java +++ b/fontbox/src/main/java/org/apache/fontbox/ttf/KerningSubtable.java @@ -283,17 +283,11 @@ public void read(TTFDataStream data) throws IOException public int getKerning(int l, int r) { int[] key = new int[] { l, r, 0 }; - int index; - index = Arrays.binarySearch(pairs, 0, searchRange, key, this); + int index = Arrays.binarySearch(pairs, key, this); if (index >= 0) { return pairs[index][2]; } - index = Arrays.binarySearch(pairs, searchRange, pairs.length, key, this); - if (index >= 0) - { - return pairs[searchRange + index][2]; - } return 0; } From b6ce6c990af4a56ff3598864483535f993e7241f Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Wed, 27 Apr 2016 16:23:21 +0000 Subject: [PATCH 0042/2182] PDFBOX-3280: make class public again, to allow cloning in importPage() git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1741286 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/pdfbox/multipdf/PDFCloneUtility.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/multipdf/PDFCloneUtility.java b/pdfbox/src/main/java/org/apache/pdfbox/multipdf/PDFCloneUtility.java index f7d53050dfc..f529819a357 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/multipdf/PDFCloneUtility.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/multipdf/PDFCloneUtility.java @@ -36,7 +36,7 @@ * Utility class used to clone PDF objects. It keeps track of objects it has already cloned. * */ -class PDFCloneUtility +public class PDFCloneUtility { private final PDDocument destination; @@ -46,7 +46,7 @@ class PDFCloneUtility * Creates a new instance for the given target document. * @param dest the destination PDF document that will receive the clones */ - PDFCloneUtility(PDDocument dest) + public PDFCloneUtility(PDDocument dest) { this.destination = dest; } From 7e9e01a6c46e1605d47a7ce669cfc25320d6a117 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Wed, 27 Apr 2016 17:23:43 +0000 Subject: [PATCH 0043/2182] PDFBOX-3280: create a test that fails git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1741293 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/pdfbox/pdmodel/TestPDDocument.java | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/TestPDDocument.java b/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/TestPDDocument.java index e203c1d86cc..4494113fa57 100644 --- a/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/TestPDDocument.java +++ b/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/TestPDDocument.java @@ -16,6 +16,7 @@ */ package org.apache.pdfbox.pdmodel; +import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; @@ -33,6 +34,8 @@ import static junit.framework.TestCase.assertNull; import static junit.framework.TestCase.assertTrue; import static junit.framework.TestCase.fail; +import org.apache.pdfbox.pdmodel.graphics.image.LosslessFactory; +import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject; /** * Testcase introduced with PDFBOX-1581. @@ -250,4 +253,27 @@ public void testDeleteGoodFile() throws IOException boolean deleted = f.delete(); assertTrue("delete good file failed after successful load() and close()", deleted); } + + /** + * Test whether importPage does a deep copy (if not, the save would fail, see PDFBOX-3328) + * + * @throws java.io.IOException + */ + public void testImportPage() throws IOException + { + PDDocument doc1 = new PDDocument(); + PDPage page = new PDPage(); + PDPageContentStream pageContentStream = new PDPageContentStream(doc1, page); + BufferedImage bim = new BufferedImage(20, 20, BufferedImage.TYPE_INT_RGB); + PDImageXObject img = LosslessFactory.createFromImage(doc1, bim); + pageContentStream.drawImage(img, 0, 0); + pageContentStream.close(); + doc1.addPage(page); + + PDDocument doc2 = new PDDocument(); + doc2.importPage(doc1.getPage(0)); + doc1.close(); + doc2.save(new ByteArrayOutputStream()); + doc2.close(); + } } From 3d68e70cdf040c8048978625efc9cfdd4da82fe2 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Wed, 27 Apr 2016 17:29:14 +0000 Subject: [PATCH 0044/2182] PDFBOX-3280: do a deep clone, as suggested by Cornelis Hoeflake git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1741294 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/pdfbox/pdmodel/PDDocument.java | 33 ++++++++----------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java index 4aa17b2c98e..07b31d1ac81 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java @@ -42,6 +42,7 @@ import org.apache.pdfbox.io.RandomAccessBufferedFileInputStream; import org.apache.pdfbox.io.RandomAccessRead; import org.apache.pdfbox.io.ScratchFile; +import org.apache.pdfbox.multipdf.PDFCloneUtility; import org.apache.pdfbox.pdfparser.PDFParser; import org.apache.pdfbox.pdfwriter.COSWriter; import org.apache.pdfbox.pdmodel.common.COSArrayList; @@ -502,34 +503,26 @@ public void removePage(int pageNumber) * document and want to copy the contents to this document's scratch file then use this method otherwise just use * the {@link #addPage} method. * - * Unlike {@link #addPage}, this method does a deep copy. If your page has annotations, and if - * these link to pages not in the target document, then the target document might become huge. - * What you need to do is to delete page references of such annotations. See + * Unlike {@link #addPage}, this method does a deep clone. This will be slower and have a larger + * memory footprint. However the deep clone is important to avoid resources getting lost if the + * source document is closed when the destination document is saved. + * + * If your page has annotations, and if these link to pages not in the target document, then the + * target document might become huge. What you need to do is to delete page references of such + * annotations. See * here for how to do this. * * @param page The page to import. * @return The page that was imported. - * + * * @throws IOException If there is an error copying the page. */ public PDPage importPage(PDPage page) throws IOException { - PDPage importedPage = new PDPage(new COSDictionary(page.getCOSObject()), resourceCache); - InputStream in = null; - try - { - in = page.getContents(); - if (in != null) - { - PDStream dest = new PDStream(this, in, COSName.FLATE_DECODE); - importedPage.setContents(dest); - } - addPage(importedPage); - } - catch (IOException e) - { - IOUtils.closeQuietly(in); - } + PDFCloneUtility cloner = new PDFCloneUtility(this); + COSBase pageBase = cloner.cloneForNewDocument(page.getCOSObject()); + PDPage importedPage = new PDPage((COSDictionary) pageBase, resourceCache); + addPage(importedPage); return importedPage; } From 93d1c4f7784c951c0d0f984072b65b89355f2e63 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Wed, 27 Apr 2016 19:10:02 +0000 Subject: [PATCH 0045/2182] PDFBOX-3280: improve test with rendering comparison git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1741317 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/pdfbox/pdmodel/TestPDDocument.java | 34 +++++++++++++++++-- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/TestPDDocument.java b/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/TestPDDocument.java index 4494113fa57..40cf3ccf733 100644 --- a/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/TestPDDocument.java +++ b/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/TestPDDocument.java @@ -16,6 +16,9 @@ */ package org.apache.pdfbox.pdmodel; +import java.awt.Color; +import java.awt.Font; +import java.awt.Graphics; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -34,8 +37,11 @@ import static junit.framework.TestCase.assertNull; import static junit.framework.TestCase.assertTrue; import static junit.framework.TestCase.fail; +import org.apache.pdfbox.pdmodel.font.PDType1Font; import org.apache.pdfbox.pdmodel.graphics.image.LosslessFactory; import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject; +import org.apache.pdfbox.rendering.PDFRenderer; +import org.junit.Assert; /** * Testcase introduced with PDFBOX-1581. @@ -264,16 +270,38 @@ public void testImportPage() throws IOException PDDocument doc1 = new PDDocument(); PDPage page = new PDPage(); PDPageContentStream pageContentStream = new PDPageContentStream(doc1, page); - BufferedImage bim = new BufferedImage(20, 20, BufferedImage.TYPE_INT_RGB); + BufferedImage bim = new BufferedImage(100, 50, BufferedImage.TYPE_INT_RGB); + Graphics g = bim.getGraphics(); + Font font = new Font("Dialog", Font.PLAIN, 20); + g.setFont(font); + g.drawString("PDFBox", 10, 30); + g.dispose(); PDImageXObject img = LosslessFactory.createFromImage(doc1, bim); - pageContentStream.drawImage(img, 0, 0); + pageContentStream.drawImage(img, 200, 500); + pageContentStream.setFont(PDType1Font.HELVETICA, 20); + pageContentStream.beginText(); + pageContentStream.setNonStrokingColor(Color.blue); + pageContentStream.newLineAtOffset(200, 600); + pageContentStream.showText("PDFBox"); + pageContentStream.endText(); pageContentStream.close(); doc1.addPage(page); - + BufferedImage bim1 = new PDFRenderer(doc1).renderImage(0); + PDDocument doc2 = new PDDocument(); doc2.importPage(doc1.getPage(0)); doc1.close(); + BufferedImage bim2 = new PDFRenderer(doc2).renderImage(0); doc2.save(new ByteArrayOutputStream()); doc2.close(); + + assertEquals(bim1.getWidth(), bim2.getWidth()); + assertEquals(bim1.getHeight(), bim2.getHeight()); + int w = bim1.getWidth(); + int h = bim1.getHeight(); + int[] pixels1 = bim1.getRaster().getPixels(0, 0, w, h, (int[]) null); + int[] pixels2 = bim2.getRaster().getPixels(0, 0, w, h, (int[]) null); + assertEquals(w * h * 3, pixels1.length); + Assert.assertArrayEquals(pixels1, pixels2); } } From b61cf19c9e33488c2715270d4051002211fb349d Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Wed, 27 Apr 2016 21:08:49 +0000 Subject: [PATCH 0046/2182] PDFBOX-3316: allow to write a comment, as suggested by Jerrol Etheredge git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1741342 13f79535-47bb-0310-9956-ffa450edef68 --- .../pdfbox/pdmodel/PDPageContentStream.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPageContentStream.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPageContentStream.java index 62e257bd2d0..9827b92e5a1 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPageContentStream.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPageContentStream.java @@ -2195,6 +2195,25 @@ public void setGraphicsStateParameters(PDExtendedGraphicsState state) throws IOE writeOperator("gs"); } + /** + * Write a comment line. + * + * @param comment + * @throws IOException If the content stream could not be written. + * @throws IllegalArgumentException If the comment contains a newline. This is not allowed, + * because the next line could be ordinary PDF content. + */ + public void addComment(String comment) throws IOException + { + if (comment.indexOf('\n') >= 0 || comment.indexOf('\r') >= 0) + { + throw new IllegalArgumentException("comment should not include a newline"); + } + output.write('%'); + output.write(comment.getBytes(Charsets.US_ASCII)); + output.write('\n'); + } + /** * Writes a real real to the content stream. */ From b6abef6de8ce71775591d3a974b2434cac578ab9 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Fri, 29 Apr 2016 16:29:26 +0000 Subject: [PATCH 0047/2182] PDFBOX-2852: simplify code git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1741660 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/pdfbox/pdmodel/PDDocument.java | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java index 07b31d1ac81..6d80a0f5a04 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java @@ -214,23 +214,20 @@ public void addSignature(PDSignature sigObject, SignatureInterface signatureInte signInterface = signatureInterface; - // - // Create SignatureForm for signature - // and appending it to the document - // + // Create SignatureForm for signature and append it to the document - // Get the first page - PDDocumentCatalog catalog = getDocumentCatalog(); - int pageCount = catalog.getPages().getCount(); + // Get the first valid page + int pageCount = getNumberOfPages(); if (pageCount == 0) { throw new IllegalStateException("Cannot sign an empty document"); } int startIndex = Math.min(Math.max(options.getPage(), 0), pageCount - 1); - PDPage page = catalog.getPages().get(startIndex); + PDPage page = getPage(startIndex); // Get the AcroForm from the Root-Dictionary and append the annotation + PDDocumentCatalog catalog = getDocumentCatalog(); PDAcroForm acroForm = catalog.getAcroForm(); catalog.getCOSObject().setNeedToBeUpdated(true); From 5e04e95e59cdd42f76d368e30dc6d9b4f23c8ade Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Fri, 29 Apr 2016 18:27:11 +0000 Subject: [PATCH 0048/2182] PDFBOX-2852: class javadoc git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1741679 13f79535-47bb-0310-9956-ffa450edef68 --- .../pdmodel/interactive/digitalsignature/SignatureOptions.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/SignatureOptions.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/SignatureOptions.java index a009eb9046f..33d2bfe27f0 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/SignatureOptions.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/SignatureOptions.java @@ -27,7 +27,7 @@ import org.apache.pdfbox.pdmodel.interactive.digitalsignature.visible.PDVisibleSigProperties; /** - * TODO description needed + * This contains the visual signature as a COSDocument, its preferred size and the page. */ public class SignatureOptions implements Closeable { From 4a69c19e06b227648ffb309a65d79976ee59a304 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Fri, 29 Apr 2016 19:05:36 +0000 Subject: [PATCH 0049/2182] PDFBOX-2852: Avoid unclosed input stream, refactor double code git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1741691 13f79535-47bb-0310-9956-ffa450edef68 --- .../visible/PDVisibleSignDesigner.java | 50 +++++++++++++------ 1 file changed, 35 insertions(+), 15 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDVisibleSignDesigner.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDVisibleSignDesigner.java index 42e520dad9f..cf082c3b221 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDVisibleSignDesigner.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDVisibleSignDesigner.java @@ -17,6 +17,7 @@ package org.apache.pdfbox.pdmodel.interactive.digitalsignature.visible; import java.awt.image.BufferedImage; +import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; @@ -58,7 +59,11 @@ public class PDVisibleSignDesigner public PDVisibleSignDesigner(String filename, InputStream imageStream, int page) throws IOException { - this(new FileInputStream(filename), imageStream, page); + // set visible signature image Input stream + readImageStream(imageStream); + + // calculate height and width of document page + calculatePageSizeFromFile(filename, page); } /** @@ -75,13 +80,8 @@ public PDVisibleSignDesigner(InputStream documentStream, InputStream imageStream // set visible signature image Input stream readImageStream(imageStream); - // create PD document - PDDocument document = PDDocument.load(documentStream); - // calculate height and width of document page - calculatePageSize(document, page); - - document.close(); + calculatePageSizeFromStream(documentStream, page); } /** @@ -109,7 +109,11 @@ public PDVisibleSignDesigner(PDDocument document, InputStream imageStream, int p public PDVisibleSignDesigner(String filename, BufferedImage image, int page) throws IOException { - this(new FileInputStream(filename), image, page); + // set visible signature image + setImage(image); + + // calculate height and width of document page + calculatePageSizeFromFile(filename, page); } /** @@ -126,13 +130,8 @@ public PDVisibleSignDesigner(InputStream documentStream, BufferedImage image, in // set visible signature image setImage(image); - // create PD document - PDDocument document = PDDocument.load(documentStream); - // calculate height and width of document page - calculatePageSize(document, page); - - document.close(); + calculatePageSizeFromStream(documentStream, page); } /** @@ -148,6 +147,28 @@ public PDVisibleSignDesigner(PDDocument document, BufferedImage image, int page) calculatePageSize(document, page); } + private void calculatePageSizeFromFile(String filename, int page) throws IOException + { + // create PD document + PDDocument document = PDDocument.load(new File(filename)); + + // calculate height and width of document page + calculatePageSize(document, page); + + document.close(); + } + + private void calculatePageSizeFromStream(InputStream documentStream, int page) throws IOException + { + // create PD document + PDDocument document = PDDocument.load(documentStream); + + // calculate height and width of document page + calculatePageSize(document, page); + + document.close(); + } + /** * Each page of document can be different sizes. This method calculates the page size based on * the page media box. @@ -163,7 +184,6 @@ private void calculatePageSize(PDDocument document, int page) throw new IllegalArgumentException("First page of pdf is 1, not " + page); } - PDPage firstPage = document.getPage(page - 1); PDRectangle mediaBox = firstPage.getMediaBox(); pageHeight(mediaBox.getHeight()); From 24a291ad5fa44c70410fcb7970f2d929b17f3829 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Sat, 30 Apr 2016 10:46:50 +0000 Subject: [PATCH 0050/2182] PDFBOX-3329: Create PDFMergerUtility example with improved metadata handling, by Alexander Kriegisch git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1741743 13f79535-47bb-0310-9956-ffa450edef68 --- .../examples/util/PDFMergerExample.java | 174 ++++++++++++++++++ 1 file changed, 174 insertions(+) create mode 100644 examples/src/main/java/org/apache/pdfbox/examples/util/PDFMergerExample.java diff --git a/examples/src/main/java/org/apache/pdfbox/examples/util/PDFMergerExample.java b/examples/src/main/java/org/apache/pdfbox/examples/util/PDFMergerExample.java new file mode 100644 index 00000000000..bbfc638c545 --- /dev/null +++ b/examples/src/main/java/org/apache/pdfbox/examples/util/PDFMergerExample.java @@ -0,0 +1,174 @@ +/* + * Copyright 2016 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.pdfbox.examples.util; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import org.apache.pdfbox.cos.COSStream; +import org.apache.pdfbox.io.MemoryUsageSetting; +import org.apache.pdfbox.multipdf.PDFMergerUtility; +import org.apache.pdfbox.pdmodel.PDDocumentInformation; +import org.apache.pdfbox.pdmodel.common.PDMetadata; +import org.apache.xmpbox.XMPMetadata; +import org.apache.xmpbox.schema.DublinCoreSchema; +import org.apache.xmpbox.schema.PDFAIdentificationSchema; +import org.apache.xmpbox.schema.XMPBasicSchema; +import org.apache.xmpbox.type.BadFieldValueException; +import org.apache.xmpbox.xml.XmpSerializer; + +import java.util.Calendar; +import java.util.List; +import javax.xml.transform.TransformerException; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.pdfbox.io.IOUtils; + +/** + * + * This example demonstrates the use of the new methods {@link PDFMergerUtility#setDestinationDocumentInformation(org.apache.pdfbox.pdmodel.PDDocumentInformation) + * } and {@link PDFMergerUtility#setDestinationMetadata(org.apache.pdfbox.pdmodel.common.PDMetadata) + * } that were added in April 2016. These allow to control the meta data in a merge without having + * to reopen the result file. + * + * @author Alexander Kriegisch + */ +public class PDFMergerExample +{ + private static final Log LOG = LogFactory.getLog(PDFMergerExample.class); + + /** + * Creates a compound PDF document from a list of input documents. + *

+ * The merged document is PDF/A-1b compliant, provided the source documents are as well. It + * contains document properties title, creator and subject, currently hard-coded. + * + * @param sources list of source PDF document streams. + * @return compound PDF document as a readable input stream. + * @throws IOException if anything goes wrong during PDF merge. + */ + public InputStream merge(final List sources) throws IOException + { + String title = "My title"; + String creator = "Alexander Kriegisch"; + String subject = "Subject with umlauts ÄÖÜ"; + + ByteArrayOutputStream mergedPDFOutputStream = null; + COSStream cosStream = null; + try + { + // If you're merging in a servlet, you can modify this example to use the outputStream only + // as the response as shown here: http://stackoverflow.com/a/36894346/535646 + mergedPDFOutputStream = new ByteArrayOutputStream(); + cosStream = new COSStream(); + + PDFMergerUtility pdfMerger = createPDFMergerUtility(sources, mergedPDFOutputStream); + + // PDF and XMP properties must be identical, otherwise document is not PDF/A compliant + PDDocumentInformation pdfDocumentInfo = createPDFDocumentInfo(title, creator, subject); + PDMetadata xmpMetadata = createXMPMetadata(cosStream, title, creator, subject); + pdfMerger.setDestinationDocumentInformation(pdfDocumentInfo); + pdfMerger.setDestinationMetadata(xmpMetadata); + + LOG.info("Merging " + sources.size() + " source documents into one PDF"); + pdfMerger.mergeDocuments(MemoryUsageSetting.setupMainMemoryOnly()); + LOG.info("PDF merge successful, size = {" + mergedPDFOutputStream.size() + "} bytes"); + + return new ByteArrayInputStream(mergedPDFOutputStream.toByteArray()); + } + catch (BadFieldValueException e) + { + throw new IOException("PDF merge problem", e); + } + catch (TransformerException e) + { + throw new IOException("PDF merge problem", e); + } + finally + { + for (InputStream source : sources) + { + IOUtils.closeQuietly(source); + } + IOUtils.closeQuietly(cosStream); + IOUtils.closeQuietly(mergedPDFOutputStream); + } + } + + private PDFMergerUtility createPDFMergerUtility(List sources, ByteArrayOutputStream mergedPDFOutputStream) + { + LOG.info("Initialising PDF merge utility"); + PDFMergerUtility pdfMerger = new PDFMergerUtility(); + pdfMerger.addSources(sources); + pdfMerger.setDestinationStream(mergedPDFOutputStream); + return pdfMerger; + } + + private PDDocumentInformation createPDFDocumentInfo(String title, String creator, String subject) + { + LOG.info("Setting document info (title, author, subject) for merged PDF"); + PDDocumentInformation documentInformation = new PDDocumentInformation(); + documentInformation.setTitle(title); + documentInformation.setCreator(creator); + documentInformation.setSubject(subject); + return documentInformation; + } + + private PDMetadata createXMPMetadata(COSStream cosStream, String title, String creator, String subject) + throws BadFieldValueException, TransformerException, IOException + { + LOG.info("Setting XMP metadata (title, author, subject) for merged PDF"); + XMPMetadata xmpMetadata = XMPMetadata.createXMPMetadata(); + + // PDF/A-1b properties + PDFAIdentificationSchema pdfaSchema = xmpMetadata.createAndAddPFAIdentificationSchema(); + pdfaSchema.setPart(1); + pdfaSchema.setConformance("B"); + + // Dublin Core properties + DublinCoreSchema dublinCoreSchema = xmpMetadata.createAndAddDublinCoreSchema(); + dublinCoreSchema.setTitle(title); + dublinCoreSchema.addCreator(creator); + dublinCoreSchema.setDescription(subject); + + // XMP Basic properties + XMPBasicSchema basicSchema = xmpMetadata.createAndAddXMPBasicSchema(); + Calendar creationDate = Calendar.getInstance(); + basicSchema.setCreateDate(creationDate); + basicSchema.setModifyDate(creationDate); + basicSchema.setMetadataDate(creationDate); + basicSchema.setCreatorTool(creator); + + // Create and return XMP data structure in XML format + ByteArrayOutputStream xmpOutputStream = null; + OutputStream cosXMPStream = null; + try + { + xmpOutputStream = new ByteArrayOutputStream(); + cosXMPStream = cosStream.createOutputStream(); + new XmpSerializer().serialize(xmpMetadata, xmpOutputStream, true); + cosXMPStream.write(xmpOutputStream.toByteArray()); + return new PDMetadata(cosStream); + } + finally + { + IOUtils.closeQuietly(xmpOutputStream); + IOUtils.closeQuietly(cosXMPStream); + } + } +} From c21488420f1c528aed90892f1ba1e3734e49f407 Mon Sep 17 00:00:00 2001 From: Maruan Sahyoun Date: Sun, 1 May 2016 11:21:54 +0000 Subject: [PATCH 0051/2182] PDFBOX-3333: keep existing transformation matrix git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1741859 13f79535-47bb-0310-9956-ffa450edef68 --- .../interactive/form/AppearanceGeneratorHelper.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/AppearanceGeneratorHelper.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/AppearanceGeneratorHelper.java index f5a9f067bb8..e2314f3f3c5 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/AppearanceGeneratorHelper.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/AppearanceGeneratorHelper.java @@ -36,6 +36,7 @@ import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceEntry; import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceStream; import org.apache.pdfbox.pdmodel.interactive.annotation.PDBorderStyleDictionary; +import org.apache.pdfbox.util.Matrix; /** * Create the AcroForms field appearance helper. @@ -262,7 +263,13 @@ private void insertGeneratedAppearance(PDAnnotationWidget widget, PDPageContentStream contents = new PDPageContentStream(field.getAcroForm().getDocument(), appearanceStream, output); - appearanceStream.setMatrix(new AffineTransform()); + // Set an identity transformation in case there is no Matrix entry + Matrix matrix = appearanceStream.getMatrix(); + if (matrix == null) + { + appearanceStream.setMatrix(new AffineTransform()); + } + appearanceStream.setFormType(1); // Acrobat calculates the left and right padding dependent on the offset of the border edge From 3c7911a22bb012cfccecce8a48f4d3dc5956160f Mon Sep 17 00:00:00 2001 From: Maruan Sahyoun Date: Sun, 1 May 2016 19:43:15 +0000 Subject: [PATCH 0052/2182] PDFBOX-3333: calculate bbox and transformation matrix respecting rotation git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1741883 13f79535-47bb-0310-9956-ffa450edef68 --- .../form/AppearanceGeneratorHelper.java | 78 +++++++++++++++---- 1 file changed, 64 insertions(+), 14 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/AppearanceGeneratorHelper.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/AppearanceGeneratorHelper.java index e2314f3f3c5..ea25cb61d44 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/AppearanceGeneratorHelper.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/AppearanceGeneratorHelper.java @@ -17,6 +17,7 @@ package org.apache.pdfbox.pdmodel.interactive.form; import java.awt.geom.AffineTransform; +import java.awt.geom.Point2D; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; @@ -126,14 +127,28 @@ public void setAppearanceValue(String apValue) throws IOException else { appearanceStream = new PDAppearanceStream(field.getAcroForm().getDocument()); - appearanceStream.setBBox(widget.getRectangle().createRetranslatedRectangle()); + + PDRectangle rect = widget.getRectangle(); + + // Calculate the entries for the bounding box and the transformation matrix + // settings for the appearance stream + int rotation = resolveRotation(widget); + Matrix matrix = Matrix.getRotateInstance(Math.toRadians(rotation), 0, 0); + Point2D.Float point2D = matrix.transformPoint(rect.getWidth(), rect.getHeight()); + + PDRectangle bbox = new PDRectangle(Math.abs((float) point2D.getX()), Math.abs((float) point2D.getY())); + appearanceStream.setBBox(bbox); + + appearanceStream.setMatrix(calculateMatrix(bbox, rotation)); + appearanceStream.setFormType(1); + appearanceDict.setNormalAppearance(appearanceStream); // TODO support appearances other than "normal" } /* * Adobe Acrobat always recreates the complete appearance stream if there is an appearance characteristics - * entry (the widget dictionaries MK entry). In addition if there is no content yet also create the apperance + * entry (the widget dictionaries MK entry). In addition if there is no content yet also create the appearance * stream from the entries. * */ @@ -146,7 +161,20 @@ public void setAppearanceValue(String apValue) throws IOException } } } - + + + private int resolveRotation(PDAnnotationWidget widget) + { + PDAppearanceCharacteristicsDictionary characteristicsDictionary = widget.getAppearanceCharacteristics(); + if (characteristicsDictionary != null) + { + // 0 is the default value if the R key doesn't exist + return characteristicsDictionary.getRotation(); + } + return 0; + } + + /** * Initialize the content of the appearance stream. * @@ -262,16 +290,9 @@ private void insertGeneratedAppearance(PDAnnotationWidget widget, { PDPageContentStream contents = new PDPageContentStream(field.getAcroForm().getDocument(), appearanceStream, output); - - // Set an identity transformation in case there is no Matrix entry - Matrix matrix = appearanceStream.getMatrix(); - if (matrix == null) - { - appearanceStream.setMatrix(new AffineTransform()); - } - - appearanceStream.setFormType(1); - + + PDRectangle bbox = resolveBoundingBox(widget, appearanceStream); + // Acrobat calculates the left and right padding dependent on the offset of the border edge // This calculation works for forms having been generated by Acrobat. // The minimum distance is always 1f even if there is no rectangle being drawn around. @@ -280,7 +301,6 @@ private void insertGeneratedAppearance(PDAnnotationWidget widget, { borderWidth = widget.getBorderStyle().getWidth(); } - PDRectangle bbox = resolveBoundingBox(widget, appearanceStream); PDRectangle clipRect = applyPadding(bbox, Math.max(1f, borderWidth)); PDRectangle contentRect = applyPadding(clipRect, Math.max(1f, borderWidth)); @@ -384,6 +404,36 @@ else if (field instanceof PDListBox) contents.restoreGraphicsState(); contents.close(); } + + private AffineTransform calculateMatrix(PDRectangle bbox, int rotation) + { + if (rotation == 0) + { + return new AffineTransform(); + } + else + { + float tx=0, ty=0; + + if (rotation == 90) + { + tx = bbox.getUpperRightY(); + } + else if (rotation == 180) + { + tx = bbox.getUpperRightY(); + ty = bbox.getUpperRightX(); + } + else if (rotation == 270) + { + ty = bbox.getUpperRightX(); + } + + Matrix matrix = Matrix.getRotateInstance(Math.toRadians(rotation), tx, ty); + return matrix.createAffineTransform(); + } + } + private boolean isMultiLine() { From b6170eeb156ee13df720eee694a0e7f863cb0a84 Mon Sep 17 00:00:00 2001 From: Maruan Sahyoun Date: Mon, 2 May 2016 09:48:45 +0000 Subject: [PATCH 0053/2182] PDFBOX-3333: add unit test with rendering git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1741948 13f79535-47bb-0310-9956-ffa450edef68 --- .../form/AcroFormsRotationTest.java | 114 ++++++++++++++++++ .../interactive/form/AcroFormsRotation.pdf | Bin 0 -> 42637 bytes .../form/AcroFormsRotation.pdf-1.png | Bin 0 -> 80737 bytes .../form/AcroFormsRotation.pdf-2.png | Bin 0 -> 83051 bytes 4 files changed, 114 insertions(+) create mode 100644 pdfbox/src/test/java/org/apache/pdfbox/pdmodel/interactive/form/AcroFormsRotationTest.java create mode 100644 pdfbox/src/test/resources/org/apache/pdfbox/pdmodel/interactive/form/AcroFormsRotation.pdf create mode 100644 pdfbox/src/test/resources/org/apache/pdfbox/pdmodel/interactive/form/AcroFormsRotation.pdf-1.png create mode 100644 pdfbox/src/test/resources/org/apache/pdfbox/pdmodel/interactive/form/AcroFormsRotation.pdf-2.png diff --git a/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/interactive/form/AcroFormsRotationTest.java b/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/interactive/form/AcroFormsRotationTest.java new file mode 100644 index 00000000000..52a0eb31f24 --- /dev/null +++ b/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/interactive/form/AcroFormsRotationTest.java @@ -0,0 +1,114 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.pdfbox.pdmodel.interactive.form; + +import java.io.File; +import java.io.IOException; + +import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.rendering.TestPDFToImage; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class AcroFormsRotationTest +{ + + private static final File OUT_DIR = new File("target/test-output"); + private static final File IN_DIR = new File("src/test/resources/org/apache/pdfbox/pdmodel/interactive/form"); + private static final String NAME_OF_PDF = "AcroFormsRotation.pdf"; + private static final String TEST_VALUE = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr," + + " sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua."; + + private PDDocument document; + private PDAcroForm acroForm; + + @Before + public void setUp() throws IOException + { + document = PDDocument.load(new File(IN_DIR, NAME_OF_PDF)); + acroForm = document.getDocumentCatalog().getAcroForm(); + OUT_DIR.mkdirs(); + } + + @Test + public void fillFields() throws IOException + { + + // portrait page + // single line fields + PDField field = acroForm.getField("pdfbox.portrait.single.rotation0"); + field.setValue(field.getFullyQualifiedName()); + field = acroForm.getField("pdfbox.portrait.single.rotation90"); + field.setValue(field.getFullyQualifiedName()); + field = acroForm.getField("pdfbox.portrait.single.rotation180"); + field.setValue(field.getFullyQualifiedName()); + field = acroForm.getField("pdfbox.portrait.single.rotation270"); + field.setValue(field.getFullyQualifiedName()); + + // multiline fields + field = acroForm.getField("pdfbox.portrait.multi.rotation0"); + field.setValue(field.getFullyQualifiedName() + "\n" + TEST_VALUE); + field = acroForm.getField("pdfbox.portrait.multi.rotation90"); + field.setValue(field.getFullyQualifiedName() + "\n" + TEST_VALUE); + field = acroForm.getField("pdfbox.portrait.multi.rotation180"); + field.setValue(field.getFullyQualifiedName() + "\n" + TEST_VALUE); + field = acroForm.getField("pdfbox.portrait.multi.rotation270"); + field.setValue(field.getFullyQualifiedName() + "\n" + TEST_VALUE); + + // 90 degrees rotated page + // single line fields + field = acroForm.getField("pdfbox.page90.single.rotation0"); + field.setValue("pdfbox.page90.single.rotation0"); + field = acroForm.getField("pdfbox.page90.single.rotation90"); + field.setValue("pdfbox.page90.single.rotation90"); + field = acroForm.getField("pdfbox.page90.single.rotation180"); + field.setValue("pdfbox.page90.single.rotation180"); + field = acroForm.getField("pdfbox.page90.single.rotation270"); + field.setValue("pdfbox.page90.single.rotation270"); + + // multiline fields + field = acroForm.getField("pdfbox.page90.multi.rotation0"); + field.setValue(field.getFullyQualifiedName() + "\n" + TEST_VALUE); + field = acroForm.getField("pdfbox.page90.multi.rotation90"); + field.setValue(field.getFullyQualifiedName() + "\n" + TEST_VALUE); + field = acroForm.getField("pdfbox.page90.multi.rotation180"); + field.setValue(field.getFullyQualifiedName() + "\n" + TEST_VALUE); + field = acroForm.getField("pdfbox.page90.multi.rotation270"); + field.setValue(field.getFullyQualifiedName() + "\n" + TEST_VALUE); + + // compare rendering + File file = new File(OUT_DIR, NAME_OF_PDF); + document.save(file); + TestPDFToImage testPDFToImage = new TestPDFToImage(TestPDFToImage.class.getName()); + if (!testPDFToImage.doTestFile(file, IN_DIR.getAbsolutePath(), OUT_DIR.getAbsolutePath())) + { + // don't fail, rendering is different on different systems, result + // must be viewed manually + System.err.println("Rendering of " + file + " failed or is not identical to expected rendering in " + IN_DIR + + " directory"); + } + } + + @After + public void tearDown() throws IOException + { + document.close(); + } + +} diff --git a/pdfbox/src/test/resources/org/apache/pdfbox/pdmodel/interactive/form/AcroFormsRotation.pdf b/pdfbox/src/test/resources/org/apache/pdfbox/pdmodel/interactive/form/AcroFormsRotation.pdf new file mode 100644 index 0000000000000000000000000000000000000000..0a41bc7cc1eba0fd3739893d93046a7db790f807 GIT binary patch literal 42637 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 literal 0 HcmV?d00001 diff --git a/pdfbox/src/test/resources/org/apache/pdfbox/pdmodel/interactive/form/AcroFormsRotation.pdf-1.png b/pdfbox/src/test/resources/org/apache/pdfbox/pdmodel/interactive/form/AcroFormsRotation.pdf-1.png new file mode 100644 index 0000000000000000000000000000000000000000..f243d96b00598cfc827b7b1466ef12ffd32a4fa8 GIT binary patch literal 80737 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%0AM00kliKUKC4U#_ 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 literal 0 HcmV?d00001 diff --git a/pdfbox/src/test/resources/org/apache/pdfbox/pdmodel/interactive/form/AcroFormsRotation.pdf-2.png b/pdfbox/src/test/resources/org/apache/pdfbox/pdmodel/interactive/form/AcroFormsRotation.pdf-2.png new file mode 100644 index 0000000000000000000000000000000000000000..a7dace4189d1a858d22bf7b64a6d7d3487cf3e69 GIT binary patch literal 83051 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 literal 0 HcmV?d00001 From 7b9ba8fd10edbcff76cfe189b42a262b7fc085bb Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Mon, 2 May 2016 20:38:26 +0000 Subject: [PATCH 0054/2182] PDFBOX-3335: keep the first /OCProperties git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1742037 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/pdfbox/multipdf/PDFMergerUtility.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/multipdf/PDFMergerUtility.java b/pdfbox/src/main/java/org/apache/pdfbox/multipdf/PDFMergerUtility.java index eca69d4aad3..78ff4fadc3d 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/multipdf/PDFMergerUtility.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/multipdf/PDFMergerUtility.java @@ -488,6 +488,13 @@ public void appendDocument(PDDocument destination, PDDocument source) throws IOE destCatalog.getCOSObject().setItem(COSName.METADATA, newStream); } + COSDictionary destOCP = (COSDictionary) destCatalog.getCOSObject().getDictionaryObject(COSName.OCPROPERTIES); + COSDictionary srcOCP = (COSDictionary) srcCatalog.getCOSObject().getDictionaryObject(COSName.OCPROPERTIES); + if (destOCP == null && srcOCP != null) + { + destCatalog.getCOSObject().setItem(COSName.OCPROPERTIES, cloner.cloneForNewDocument(srcOCP)); + } + mergeOutputIntents(cloner, srcCatalog, destCatalog); // merge logical structure hierarchy if logical structure information is available in both source pdf and From a0070bd2fe6090dc36be83f3878ae3efc3424bdf Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Tue, 3 May 2016 20:14:59 +0000 Subject: [PATCH 0055/2182] PDFBOX-3336: partial revert of 1734615, keep "highest object number+1" size that is set by setSize() call in COSWriter git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1742193 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/pdfbox/pdfparser/PDFXRefStream.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/PDFXRefStream.java b/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/PDFXRefStream.java index e1a6ed3dc08..63a829fdb09 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/PDFXRefStream.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/PDFXRefStream.java @@ -77,8 +77,7 @@ public COSStream getStream() throws IOException { throw new IllegalArgumentException("size is not set in xrefstream"); } - // add one for object number 0 - stream.setLong(COSName.SIZE, streamData.size() + 1); + stream.setLong(COSName.SIZE, size); List indexEntry = getIndexEntry(); COSArray indexAsArray = new COSArray(); From 2a7ca65bb9d2e8dde3a1edfc27756f301315223f Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Wed, 4 May 2016 07:34:46 +0000 Subject: [PATCH 0056/2182] PDFBOX-3336: flag signature object for update if existing git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1742218 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java index 6d80a0f5a04..f5b7bc0e539 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java @@ -256,6 +256,10 @@ public void addSignature(PDSignature sigObject, SignatureInterface signatureInte // backward linking signatureField.getWidgets().get(0).setPage(page); } + else + { + signatureField.getCOSObject().setNeedToBeUpdated(true); + } // to conform PDF/A-1 requirement: // The /F key's Print flag bit shall be set to 1 and // its Hidden, Invisible and NoView flag bits shall be set to 0 From 4ea837faa844adbcb99945e64170e6e527128dd4 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Wed, 4 May 2016 08:19:01 +0000 Subject: [PATCH 0057/2182] PDFBOX-3336: flag field array for update if existing git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1742230 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java index f5b7bc0e539..b7e0d1df00c 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java @@ -247,6 +247,11 @@ public void addSignature(PDSignature sigObject, SignatureInterface signatureInte fields = new ArrayList(); acroForm.setFields(fields); } + else + { + COSArray fieldArray = (COSArray) acroForm.getCOSObject().getDictionaryObject(COSName.FIELDS); + fieldArray.setNeedToBeUpdated(true); + } PDSignatureField signatureField = findSignatureField(fields, sigObject); if (signatureField == null) { From 9bfd8b7ee1e98055e584ad385129e28505c1d56e Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Wed, 4 May 2016 08:34:00 +0000 Subject: [PATCH 0058/2182] PDFBOX-3336: revert 1742217, this is already done in checkSignatureField git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1742232 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java index b7e0d1df00c..f9368c1e693 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java @@ -261,10 +261,6 @@ public void addSignature(PDSignature sigObject, SignatureInterface signatureInte // backward linking signatureField.getWidgets().get(0).setPage(page); } - else - { - signatureField.getCOSObject().setNeedToBeUpdated(true); - } // to conform PDF/A-1 requirement: // The /F key's Print flag bit shall be set to 1 and // its Hidden, Invisible and NoView flag bits shall be set to 0 From 8fa7f17e735a5045f2dd017807d09e7584088638 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Wed, 4 May 2016 10:59:40 +0000 Subject: [PATCH 0059/2182] PDFBOX-2852: fix javadoc git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1742247 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/pdfbox/pdmodel/interactive/form/PDField.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDField.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDField.java index b8e6586e875..972a3550bfa 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDField.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDField.java @@ -131,7 +131,7 @@ else if (parent != null) * For {@link PDNonTerminalField} the list will be empty as non terminal fields * have no visual representation in the form. * - * @return @return a List of {@link PDAnnotationWidget} annotations. + * @return a List of {@link PDAnnotationWidget} annotations. */ public abstract List getWidgets(); From 443a6cbacc7e4d43d835c3218aabbcccc0799b8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Lehmk=C3=BChler?= Date: Thu, 5 May 2016 15:25:30 +0000 Subject: [PATCH 0060/2182] PDFBOX-2852: added missing override annotation git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1742438 13f79535-47bb-0310-9956-ffa450edef68 --- .../pdfbox/pdmodel/font/encoding/DictionaryEncoding.java | 6 +----- .../pdfbox/pdmodel/font/encoding/MacOSRomanEncoding.java | 6 +----- .../pdfbox/pdmodel/font/encoding/MacRomanEncoding.java | 6 +----- .../pdfbox/pdmodel/font/encoding/StandardEncoding.java | 6 +----- .../pdfbox/pdmodel/font/encoding/WinAnsiEncoding.java | 6 +----- 5 files changed, 5 insertions(+), 25 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/DictionaryEncoding.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/DictionaryEncoding.java index a56f24d2cbe..f2fbe22afd7 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/DictionaryEncoding.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/DictionaryEncoding.java @@ -160,11 +160,7 @@ public Map getDifferences() return differences; } - /** - * Convert this standard java object to a COS object. - * - * @return The cos object that matches this Java object. - */ + @Override public COSBase getCOSObject() { return encoding; diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/MacOSRomanEncoding.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/MacOSRomanEncoding.java index fb467f845be..b602a8e8708 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/MacOSRomanEncoding.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/MacOSRomanEncoding.java @@ -73,11 +73,7 @@ public MacOSRomanEncoding() } - /** - * Convert this standard java object to a COS object. - * - * @return The cos object that matches this Java object. - */ + @Override public COSBase getCOSObject() { return null; diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/MacRomanEncoding.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/MacRomanEncoding.java index aac797c415b..b895662dfeb 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/MacRomanEncoding.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/MacRomanEncoding.java @@ -263,11 +263,7 @@ public MacRomanEncoding() } } - /** - * Convert this standard java object to a COS object. - * - * @return The cos object that matches this Java object. - */ + @Override public COSBase getCOSObject() { return COSName.MAC_ROMAN_ENCODING; diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/StandardEncoding.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/StandardEncoding.java index d3d676ff564..ab49f5b6279 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/StandardEncoding.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/StandardEncoding.java @@ -204,11 +204,7 @@ public StandardEncoding() } } - /** - * Convert this standard java object to a COS object. - * - * @return The cos object that matches this Java object. - */ + @Override public COSBase getCOSObject() { return COSName.STANDARD_ENCODING; diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/WinAnsiEncoding.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/WinAnsiEncoding.java index 41a2eb4999a..fab011a4ff6 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/WinAnsiEncoding.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/WinAnsiEncoding.java @@ -283,11 +283,7 @@ public WinAnsiEncoding() } } - /** - * Convert this standard java object to a COS object. - * - * @return The cos object that matches this Java object. - */ + @Override public COSBase getCOSObject() { return COSName.WIN_ANSI_ENCODING; From 47cfa68c6d7e03e16d7d169961dece7e85ceb71b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Lehmk=C3=BChler?= Date: Thu, 5 May 2016 15:54:23 +0000 Subject: [PATCH 0061/2182] PDFBOX-3332: don't add the reverse mapping for some special cases to avoid overriding the origin mapping git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1742443 13f79535-47bb-0310-9956-ffa450edef68 --- .../pdfbox/pdmodel/font/encoding/MacRomanEncoding.java | 7 ++++--- .../pdfbox/pdmodel/font/encoding/WinAnsiEncoding.java | 10 ++++++---- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/MacRomanEncoding.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/MacRomanEncoding.java index b895662dfeb..eb20ef7bc5d 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/MacRomanEncoding.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/MacRomanEncoding.java @@ -240,9 +240,7 @@ public class MacRomanEncoding extends Encoding {0330, "ydieresis"}, {0264, "yen"}, {0172, "z"}, - {060, "zero"}, - // adding an additional mapping as defined in Appendix D of the pdf spec - {0312, "space"} + {060, "zero"} }; /** @@ -261,6 +259,9 @@ public MacRomanEncoding() { add((Integer) encodingEntry[CHAR_CODE], encodingEntry[CHAR_NAME].toString()); } + // adding an additional mapping as defined in Appendix D of the pdf spec + // don't add the reverse mapping as we have to preserve the origin mapping for the given glyph name + codeToName.put(0312, "space"); } @Override diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/WinAnsiEncoding.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/WinAnsiEncoding.java index fab011a4ff6..c74143b85fb 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/WinAnsiEncoding.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/WinAnsiEncoding.java @@ -249,10 +249,7 @@ public class WinAnsiEncoding extends Encoding {0245, "yen"}, {0172, "z"}, {0236, "zcaron"}, - {060, "zero"}, - // adding some additional mappings as defined in Appendix D of the pdf spec - {0240, "space"}, - {0255, "hyphen"} + {060, "zero"} }; /** @@ -272,6 +269,11 @@ public WinAnsiEncoding() add((Integer) encodingEntry[CHAR_CODE], encodingEntry[CHAR_NAME].toString()); } + // adding some additional mappings as defined in Appendix D of the pdf spec + // don't add the reverse mapping as we have to preserve the origin mapping for the given glyph names + codeToName.put(0240, "space"); + codeToName.put(0255, "hyphen"); + // From the PDF specification: // In WinAnsiEncoding, all unused codes greater than 40 map to the bullet character. for (int i = 041; i <= 255; i++) From f7b7fd415a2c5f139888cbcecddfa997eb2a98d8 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Thu, 5 May 2016 21:46:54 +0000 Subject: [PATCH 0062/2182] PDFBOX-3341: test set access permissions to read only when not owner git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1742478 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/pdfbox/encryption/TestSymmetricKeyEncryption.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pdfbox/src/test/java/org/apache/pdfbox/encryption/TestSymmetricKeyEncryption.java b/pdfbox/src/test/java/org/apache/pdfbox/encryption/TestSymmetricKeyEncryption.java index 6a6094852cc..b9a30ef09b5 100644 --- a/pdfbox/src/test/java/org/apache/pdfbox/encryption/TestSymmetricKeyEncryption.java +++ b/pdfbox/src/test/java/org/apache/pdfbox/encryption/TestSymmetricKeyEncryption.java @@ -168,7 +168,10 @@ private void checkPerms(byte[] inputFileAsByteArray, String password, // check permissions assertEquals(expectedPermissions.isOwnerPermission(), currentAccessPermission.isOwnerPermission()); - assertEquals(expectedPermissions.isReadOnly(), currentAccessPermission.isReadOnly()); + if (!expectedPermissions.isOwnerPermission()) + { + assertEquals(true, currentAccessPermission.isReadOnly()); + } assertEquals(expectedPermissions.canAssembleDocument(), currentAccessPermission.canAssembleDocument()); assertEquals(expectedPermissions.canExtractContent(), currentAccessPermission.canExtractContent()); assertEquals(expectedPermissions.canExtractForAccessibility(), currentAccessPermission.canExtractForAccessibility()); From 3b154ef4fe221abb7819696c3adb6180a636eaf4 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Thu, 5 May 2016 21:48:20 +0000 Subject: [PATCH 0063/2182] PDFBOX-3341: set access permissions to read only when not owner git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1742479 13f79535-47bb-0310-9956-ffa450edef68 --- .../pdfbox/pdmodel/encryption/StandardSecurityHandler.java | 1 + 1 file changed, 1 insertion(+) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/StandardSecurityHandler.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/StandardSecurityHandler.java index 4b15e6d6444..1271a977d72 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/StandardSecurityHandler.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/StandardSecurityHandler.java @@ -237,6 +237,7 @@ else if( isUserPassword(password.getBytes(passwordCharset), userKey, ownerKey, dicLength, encryptMetadata) ) { currentAccessPermission = new AccessPermission(dicPermissions); + currentAccessPermission.setReadOnly(); setCurrentAccessPermission(currentAccessPermission); encryptionKey = From c932f9f425b86d1bec1bf93e60a290d3410f03fd Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Sat, 7 May 2016 12:11:56 +0000 Subject: [PATCH 0064/2182] PDFBOX-3342: jump to a local page git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1742705 13f79535-47bb-0310-9956-ffa450edef68 --- .../examples/pdmodel/AddAnnotations.java | 81 ++++++++++++++++--- 1 file changed, 69 insertions(+), 12 deletions(-) diff --git a/examples/src/main/java/org/apache/pdfbox/examples/pdmodel/AddAnnotations.java b/examples/src/main/java/org/apache/pdfbox/examples/pdmodel/AddAnnotations.java index e7360fc5737..021c5a2ef27 100644 --- a/examples/src/main/java/org/apache/pdfbox/examples/pdmodel/AddAnnotations.java +++ b/examples/src/main/java/org/apache/pdfbox/examples/pdmodel/AddAnnotations.java @@ -26,6 +26,7 @@ import org.apache.pdfbox.pdmodel.font.PDType1Font; import org.apache.pdfbox.pdmodel.graphics.color.PDColor; import org.apache.pdfbox.pdmodel.graphics.color.PDDeviceRGB; +import org.apache.pdfbox.pdmodel.interactive.action.PDActionGoTo; import org.apache.pdfbox.pdmodel.interactive.action.PDActionURI; import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotation; import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationLine; @@ -33,6 +34,8 @@ import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationSquareCircle; import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationTextMarkup; import org.apache.pdfbox.pdmodel.interactive.annotation.PDBorderStyleDictionary; +import org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination.PDPageDestination; +import org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination.PDPageFitWidthDestination; /** * Add annotations to pages of a PDF document. @@ -56,9 +59,13 @@ public static void main(String[] args) throws IOException PDDocument document = new PDDocument(); try { - PDPage page = new PDPage(); - document.addPage(page); - List annotations = page.getAnnotations(); + PDPage page1 = new PDPage(); + PDPage page2 = new PDPage(); + PDPage page3 = new PDPage(); + document.addPage(page1); + document.addPage(page2); + document.addPage(page3); + List annotations = page1.getAnnotations(); // Some basic reusable objects/constants // Annotations themselves can only be used once! @@ -76,18 +83,20 @@ public static void main(String[] args) throws IOException borderULine.setStyle(PDBorderStyleDictionary.STYLE_UNDERLINE); borderULine.setWidth(INCH / 72); // 1 point - float pw = page.getMediaBox().getUpperRightX(); - float ph = page.getMediaBox().getUpperRightY(); + float pw = page1.getMediaBox().getUpperRightX(); + float ph = page1.getMediaBox().getUpperRightY(); // First add some text, two lines we'll add some annotations to this later PDFont font = PDType1Font.HELVETICA_BOLD; - PDPageContentStream contents = new PDPageContentStream(document, page); + PDPageContentStream contents = new PDPageContentStream(document, page1); contents.beginText(); contents.setFont(font, 18); contents.newLineAtOffset(INCH, ph - INCH - 18); contents.showText("PDFBox"); contents.newLineAtOffset(0, -(INCH / 2)); - contents.showText("Click Here"); + contents.showText("External URL"); + contents.newLineAtOffset(0, -(INCH / 2)); + contents.showText("Jump to page three"); contents.endText(); contents.close(); @@ -102,7 +111,7 @@ public static void main(String[] args) throws IOException PDRectangle position = new PDRectangle(); position.setLowerLeftX(INCH); position.setLowerLeftY(ph - INCH - 18); - position.setUpperRightX(72 + textWidth); + position.setUpperRightX(INCH + textWidth); position.setUpperRightY(ph - INCH); txtMark.setRectangle(position); @@ -124,16 +133,16 @@ public static void main(String[] args) throws IOException txtMark.setContents("Highlighted since it's important"); annotations.add(txtMark); - // Now add the link annotation, so the clickme works + // Now add the link annotation, so the click on "External URL" works PDAnnotationLink txtLink = new PDAnnotationLink(); txtLink.setBorderStyle(borderULine); // Set the rectangle containing the link - textWidth = font.getStringWidth("Click Here") / 1000 * 18; + textWidth = font.getStringWidth("External URL") / 1000 * 18; position = new PDRectangle(); position.setLowerLeftX(INCH); position.setLowerLeftY(ph - 1.5f * INCH -20); // down a couple of points - position.setUpperRightX(72 + textWidth); + position.setUpperRightX(INCH + textWidth); position.setUpperRightY(ph - 1.5f * INCH); txtLink.setRectangle(position); @@ -168,7 +177,7 @@ public static void main(String[] args) throws IOException aSquare.setColor(red); // Outline in red, not setting a fill aSquare.setBorderStyle(borderThick); - // Place the annotation on the page, we'll make this 1" (72points) square + // Place the annotation on the page, we'll make this 1" (72 points) square // 3.5" down, 1" in from the right on the page position = new PDRectangle(); // Reuse the variable, but note it's a new object! position.setLowerLeftX(pw - 2 * INCH); // 1" in from right, 1" wide @@ -203,7 +212,36 @@ public static void main(String[] args) throws IOException aLine.setBorderStyle(borderThick); aLine.setColor(black); annotations.add(aLine); + + + // Now add the link annotation, so the click on "Jump to page three" works + PDAnnotationLink pageLink = new PDAnnotationLink(); + pageLink.setBorderStyle(borderULine); + + // Set the rectangle containing the link + textWidth = font.getStringWidth("Jump to page three") / 1000 * 18; + position = new PDRectangle(); + position.setLowerLeftX(INCH); + position.setLowerLeftY(ph - 2 * INCH - 20); // down a couple of points + position.setUpperRightX(INCH + textWidth); + position.setUpperRightY(ph - 2 * INCH); + pageLink.setRectangle(position); + // add the GoTo action + PDActionGoTo actionGoto = new PDActionGoTo(); + // see javadoc for other types of PDPageDestination + PDPageDestination dest = new PDPageFitWidthDestination(); + // do not use setPageNumber(), this is for external destinations only + dest.setPage(page3); + actionGoto.setDestination(dest); + pageLink.setAction(actionGoto); + annotations.add(pageLink); + + + showPageNo(document, page1, "Page 1"); + showPageNo(document, page2, "Page 2"); + showPageNo(document, page3, "Page 3"); + // save the PDF document.save(args[0]); } @@ -212,4 +250,23 @@ public static void main(String[] args) throws IOException document.close(); } } + + private static void showPageNo(PDDocument document, PDPage page, String pageText) + throws IOException + { + int fontSize = 10; + + PDPageContentStream contents = + new PDPageContentStream(document, page, PDPageContentStream.AppendMode.PREPEND, true); + float pageWidth = page.getMediaBox().getWidth(); + float pageHeight = page.getMediaBox().getHeight(); + PDFont font = PDType1Font.HELVETICA; + contents.setFont(font, fontSize); + float textWidth = font.getStringWidth(pageText) / 1000 * fontSize; + contents.beginText(); + contents.newLineAtOffset(pageWidth / 2 - textWidth / 2, pageHeight - INCH / 2); + contents.showText(pageText); + contents.endText(); + contents.close(); + } } From ecbbd482f34bdbb74503c6e2e228127e4bd1d887 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Mon, 9 May 2016 11:56:48 +0000 Subject: [PATCH 0065/2182] PDFBOX-2941: enable printing after opening URL git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1742931 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/pdfbox/debugger/PDFDebugger.java | 1 + 1 file changed, 1 insertion(+) diff --git a/debugger/src/main/java/org/apache/pdfbox/debugger/PDFDebugger.java b/debugger/src/main/java/org/apache/pdfbox/debugger/PDFDebugger.java index 8b512198f85..34e4361a574 100644 --- a/debugger/src/main/java/org/apache/pdfbox/debugger/PDFDebugger.java +++ b/debugger/src/main/java/org/apache/pdfbox/debugger/PDFDebugger.java @@ -1191,6 +1191,7 @@ private void readPDFurl(String urlString, String password) throws IOException currentFilePath = urlString; URL url = new URL(urlString); document = PDDocument.load(url.openStream(), password); + printMenuItem.setEnabled(true); initTree(); From c587752caf96779f0ea0e28a1959d78518d2e903 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Mon, 9 May 2016 13:27:12 +0000 Subject: [PATCH 0066/2182] PDFBOX-3344: avoid ClassCastException git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1742946 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/pdfbox/pdmodel/font/FontMapperImpl.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontMapperImpl.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontMapperImpl.java index d19cdbdb60a..1ca63a9c3fc 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontMapperImpl.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontMapperImpl.java @@ -30,8 +30,6 @@ import java.util.PriorityQueue; import java.util.Set; import org.apache.fontbox.FontBoxFont; -import org.apache.fontbox.cff.CFFFont; -import org.apache.fontbox.cff.CFFType1Font; import org.apache.fontbox.ttf.OpenTypeFont; import org.apache.fontbox.ttf.TTFParser; import org.apache.fontbox.ttf.TrueTypeFont; @@ -381,10 +379,10 @@ private FontBoxFont findFontBoxFont(String postScriptName) return t1; } - CFFFont cff = (CFFFont)findFont(FontFormat.OTF, postScriptName); - if (cff instanceof CFFType1Font) + OpenTypeFont otf = (OpenTypeFont) findFont(FontFormat.OTF, postScriptName); + if (otf instanceof OpenTypeFont) { - return cff; + return otf; } TrueTypeFont ttf = (TrueTypeFont)findFont(FontFormat.TTF, postScriptName); From f59d91a8c2e9ac0f9c8321478a170c8cd039a82f Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Tue, 10 May 2016 10:16:48 +0000 Subject: [PATCH 0067/2182] =?UTF-8?q?PDFBOX-3344:=20replace=20the=20instan?= =?UTF-8?q?ceof=20with=20a=20not=20null=20clause,=20optimize=20sort=20orde?= =?UTF-8?q?r,=20as=20suggested=20by=20Andreas=20Lehmk=C3=BChler?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1743148 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/pdfbox/pdmodel/font/FontMapperImpl.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontMapperImpl.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontMapperImpl.java index 1ca63a9c3fc..1c4893d8a45 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontMapperImpl.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontMapperImpl.java @@ -379,18 +379,18 @@ private FontBoxFont findFontBoxFont(String postScriptName) return t1; } - OpenTypeFont otf = (OpenTypeFont) findFont(FontFormat.OTF, postScriptName); - if (otf instanceof OpenTypeFont) - { - return otf; - } - TrueTypeFont ttf = (TrueTypeFont)findFont(FontFormat.TTF, postScriptName); if (ttf != null) { return ttf; } + OpenTypeFont otf = (OpenTypeFont) findFont(FontFormat.OTF, postScriptName); + if (otf != null) + { + return otf; + } + return null; } From 394282da1bc02d7526f306ce0a5d0e447a2ae0ec Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Tue, 10 May 2016 16:32:30 +0000 Subject: [PATCH 0068/2182] PDFBOX-3346: example with empty signature git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1743227 13f79535-47bb-0310-9956-ffa450edef68 --- .../signature/CreateEmptySignatureForm.java | 83 +++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 examples/src/main/java/org/apache/pdfbox/examples/signature/CreateEmptySignatureForm.java diff --git a/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateEmptySignatureForm.java b/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateEmptySignatureForm.java new file mode 100644 index 00000000000..5ab8ec4f29a --- /dev/null +++ b/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateEmptySignatureForm.java @@ -0,0 +1,83 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.pdfbox.examples.signature; + +import java.io.IOException; +import org.apache.pdfbox.cos.COSName; +import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.pdmodel.PDPage; +import org.apache.pdfbox.pdmodel.PDResources; +import org.apache.pdfbox.pdmodel.common.PDRectangle; +import org.apache.pdfbox.pdmodel.font.PDFont; +import org.apache.pdfbox.pdmodel.font.PDType1Font; +import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationWidget; +import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm; +import org.apache.pdfbox.pdmodel.interactive.form.PDSignatureField; + +/** + * An example of creating an AcroForm and an empty signature field from scratch. + * + * An actual signature can be added by clicking on it in Adobe Reader. + * + */ +public final class CreateEmptySignatureForm +{ + private CreateEmptySignatureForm() + { + } + + public static void main(String[] args) throws IOException + { + // Create a new document with an empty page. + PDDocument document = new PDDocument(); + PDPage page = new PDPage(PDRectangle.A4); + document.addPage(page); + + // Adobe Acrobat uses Helvetica as a default font and + // stores that under the name '/Helv' in the resources dictionary + PDFont font = PDType1Font.HELVETICA; + PDResources resources = new PDResources(); + resources.put(COSName.getPDFName("Helv"), font); + + // Add a new AcroForm and add that to the document + PDAcroForm acroForm = new PDAcroForm(document); + document.getDocumentCatalog().setAcroForm(acroForm); + + // Add and set the resources and default appearance at the form level + acroForm.setDefaultResources(resources); + + // Acrobat sets the font size on the form level to be + // auto sized as default. This is done by setting the font size to '0' + String defaultAppearanceString = "/Helv 0 Tf 0 g"; + acroForm.setDefaultAppearance(defaultAppearanceString); + + // --- end of general AcroForm stuff --- + + // Create empty signature field, it will get the name "Signature1" + PDSignatureField signatureField = new PDSignatureField(acroForm); + PDAnnotationWidget widget = signatureField.getWidgets().get(0); + PDRectangle rect = new PDRectangle(50, 650, 200, 50); + widget.setRectangle(rect); + widget.setPage(page); + page.getAnnotations().add(widget); + + + document.save("target/EmptySignatureForm.pdf"); + document.close(); + } +} From a28df4f06e4b5dedc98cbe29cde18050be080e49 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Wed, 11 May 2016 18:40:07 +0000 Subject: [PATCH 0069/2182] PDFBOX-3348: avoid NPE git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1743408 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/fontbox/type1/Type1Parser.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/fontbox/src/main/java/org/apache/fontbox/type1/Type1Parser.java b/fontbox/src/main/java/org/apache/fontbox/type1/Type1Parser.java index 7e448060ad9..504f3e17798 100644 --- a/fontbox/src/main/java/org/apache/fontbox/type1/Type1Parser.java +++ b/fontbox/src/main/java/org/apache/fontbox/type1/Type1Parser.java @@ -462,9 +462,15 @@ private void parseBinary(byte[] bytes) throws IOException lexer = new Type1Lexer(decrypted); // find /Private dict - while (!lexer.peekToken().getText().equals("Private")) + Token peekToken = lexer.peekToken(); + while (peekToken != null && !peekToken.getText().equals("Private")) { lexer.nextToken(); + peekToken = lexer.peekToken(); + } + if (peekToken == null) + { + throw new IOException("/Private token not found"); } // Private dict From 6727adc2c4ab899faba88cc35be845424217fc82 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Tue, 17 May 2016 10:47:51 +0000 Subject: [PATCH 0070/2182] PDFBOX-3351: ignore border if border color array is empty git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1744251 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/pdfbox/rendering/PageDrawer.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/rendering/PageDrawer.java b/pdfbox/src/main/java/org/apache/pdfbox/rendering/PageDrawer.java index 80187627448..579cc5ee698 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/rendering/PageDrawer.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/rendering/PageDrawer.java @@ -1026,7 +1026,7 @@ private AnnotationBorder getAnnotationBorder(PDAnnotation annotation, private void drawAnnotationLinkBorder(PDAnnotationLink link) throws IOException { AnnotationBorder ab = getAnnotationBorder(link, link.getBorderStyle()); - if (ab.width == 0) + if (ab.width == 0 || ab.color.getComponents().length == 0) { return; } @@ -1063,7 +1063,7 @@ private void drawAnnotationInk(PDAnnotationMarkup inkAnnotation) throws IOExcept } // PDF spec does not mention /Border for ink annotations, but it is used if /BS is not available AnnotationBorder ab = getAnnotationBorder(inkAnnotation, inkAnnotation.getBorderStyle()); - if (ab.width == 0) + if (ab.width == 0 || ab.color.getComponents().length == 0) { return; } From f1dd643ea8b56e8afd9a460315d50a87758a248a Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Thu, 19 May 2016 18:32:19 +0000 Subject: [PATCH 0071/2182] PDFBOX-3354: fix bug, averageWidth is not local, as reported by Gabriel Carabas git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1744614 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFont.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFont.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFont.java index ea2ec096cc1..a685eca0a17 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFont.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFont.java @@ -318,7 +318,7 @@ public float getAverageFontWidth() totalWidths += width; } } - float averageWidth = totalWidths / characterCount; + averageWidth = totalWidths / characterCount; if (averageWidth <= 0 || Float.isNaN(averageWidth)) { averageWidth = getDefaultWidth(); From 025650fcf788a2b6aeda23184b0355058eb7b94b Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Fri, 20 May 2016 10:45:36 +0000 Subject: [PATCH 0072/2182] PDFBOX-3355: makeLetterLabel should return lower case like makeRomanLabel to fix bug reported by Carlos Cabral git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1744695 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/pdfbox/pdmodel/common/PDPageLabels.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/PDPageLabels.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/PDPageLabels.java index 7844250e5b1..903bee85ce6 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/PDPageLabels.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/PDPageLabels.java @@ -397,14 +397,14 @@ private static String makeRomanLabel(int pageIndex) } /** - * A..Z, AA..ZZ, AAA..ZZZ ... labeling as described in PDF32000-1:2008, + * a..z, aa..zz, aaa..zzz ... labeling as described in PDF32000-1:2008, * Table 159, Page 375. */ private static String makeLetterLabel(int num) { StringBuilder buf = new StringBuilder(); int numLetters = num / 26 + Integer.signum(num % 26); - int letter = num % 26 + 26 * (1 - Integer.signum(num % 26)) + 64; + int letter = num % 26 + 26 * (1 - Integer.signum(num % 26)) + 'a' - 1; for (int i = 0; i < numLetters; i++) { buf.appendCodePoint(letter); From ae4ac231fd4612e0e042f7c9449b36c1939225da Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Fri, 20 May 2016 10:56:41 +0000 Subject: [PATCH 0073/2182] PDFBOX-2852: use operator assignment git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1744701 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/pdfbox/pdmodel/common/PDPageLabels.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/PDPageLabels.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/PDPageLabels.java index 903bee85ce6..f468df9e3ba 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/PDPageLabels.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/PDPageLabels.java @@ -379,7 +379,7 @@ private static String makeRomanLabel(int pageIndex) while (power < 3 && pageIndex > 0) { buf.insert(0, ROMANS[power][pageIndex % 10]); - pageIndex = pageIndex / 10; + pageIndex /= 10; power++; } // Prepend as many m as there are thousands (which is From 20efa1db81936aebd85456f0dfac77a0c0947494 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Fri, 20 May 2016 11:32:13 +0000 Subject: [PATCH 0074/2182] PDFBOX-3352: set zone id git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1744718 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/xmpbox/DateConverter.java | 39 ++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/xmpbox/src/main/java/org/apache/xmpbox/DateConverter.java b/xmpbox/src/main/java/org/apache/xmpbox/DateConverter.java index cca75ff9c9f..9b5b50c3968 100644 --- a/xmpbox/src/main/java/org/apache/xmpbox/DateConverter.java +++ b/xmpbox/src/main/java/org/apache/xmpbox/DateConverter.java @@ -190,6 +190,7 @@ else if (date.startsWith("D:")) } else { + updateZoneId(zone); retval = new GregorianCalendar(zone); } retval.clear(); @@ -229,7 +230,43 @@ else if (date.startsWith("D:")) } return retval; } - + + /** + * Update the zone ID based on the raw offset. This is either GMT, GMT+hh:mm or GMT-hh:mm, where + * n is between 1 and 14. The highest negative hour is -14, the highest positive hour is 12. + * Zones that don't fit in this schema are set to zone ID "unknown". + * + * @param tz the time zone to update. + */ + private static void updateZoneId(TimeZone tz) + { + int offset = tz.getRawOffset(); + char pm = '+'; + if (offset < 0) + { + pm = '-'; + offset = -offset; + } + int hh = offset / 3600000; + int mm = offset % 3600000 / 60000; + if (offset == 0) + { + tz.setID("GMT"); + } + else if (pm == '+' && hh <= 12) + { + tz.setID(String.format("GMT+%02d:%02d", hh, mm)); + } + else if (pm == '-' && hh <= 14) + { + tz.setID(String.format("GMT-%02d:%02d", hh, mm)); + } + else + { + tz.setID("unknown"); + } + } + /** * Convert the date to iso 8601 string format. * From cebb517e3eb6ddc7769e0696b7ebf2b9c214edfb Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Fri, 20 May 2016 11:33:21 +0000 Subject: [PATCH 0075/2182] PDFBOX-3352: set zone id git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1744719 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/pdfbox/util/DateConverter.java | 40 ++++++++++++++++++- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/util/DateConverter.java b/pdfbox/src/main/java/org/apache/pdfbox/util/DateConverter.java index 3bc91882da2..ee5c342d134 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/util/DateConverter.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/util/DateConverter.java @@ -432,7 +432,7 @@ static boolean parseTZoffset(String text, GregorianCalendar cal, int hrSign = (sign == '-' ? -1 : 1); tz.setRawOffset(restrainTZoffset(hrSign * (tzHours * MILLIS_PER_HOUR + tzMin * (long) MILLIS_PER_MINUTE))); - tz.setID("unknown"); + updateZoneId(tz); } else if ( ! hadGMT) { @@ -455,7 +455,43 @@ else if ( ! hadGMT) initialWhere.setIndex(where.getIndex()); return true; } - + + /** + * Update the zone ID based on the raw offset. This is either GMT, GMT+hh:mm or GMT-hh:mm, where + * n is between 1 and 14. The highest negative hour is -14, the highest positive hour is 12. + * Zones that don't fit in this schema are set to zone ID "unknown". + * + * @param tz the time zone to update. + */ + private static void updateZoneId(TimeZone tz) + { + int offset = tz.getRawOffset(); + char pm = '+'; + if (offset < 0) + { + pm = '-'; + offset = -offset; + } + int hh = offset / 3600000; + int mm = offset % 3600000 / 60000; + if (offset == 0) + { + tz.setID("GMT"); + } + else if (pm == '+' && hh <= 12) + { + tz.setID(String.format("GMT+%02d:%02d", hh, mm)); + } + else if (pm == '-' && hh <= 14) + { + tz.setID(String.format("GMT-%02d:%02d", hh, mm)); + } + else + { + tz.setID("unknown"); + } + } + /* * Parses a big-endian date: year month day hour min sec. * The year must be four digits. Other fields may be adjacent From 9158818fe9ae06c4775846ed208850d6314d38d6 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Sat, 21 May 2016 19:47:23 +0000 Subject: [PATCH 0076/2182] PDFBOX-3359: fill the scaled size with white background, as suggested by Ivan Ridao Freitas git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1744973 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/pdfbox/rendering/PDFRenderer.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/rendering/PDFRenderer.java b/pdfbox/src/main/java/org/apache/pdfbox/rendering/PDFRenderer.java index 61931834d67..364c549a918 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/rendering/PDFRenderer.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/rendering/PDFRenderer.java @@ -173,10 +173,10 @@ public void renderPageToGraphics(int pageIndex, Graphics2D graphics, float scale private void renderPage(PDPage page, Graphics2D graphics, int width, int height, float scaleX, float scaleY) throws IOException { - graphics.clearRect(0, 0, width, height); - graphics.scale(scaleX, scaleY); // TODO should we be passing the scale to PageDrawer rather than messing with Graphics? + + graphics.clearRect(0, 0, width, height); PDRectangle cropBox = page.getCropBox(); int rotationAngle = page.getRotation(); From 30da2e909b8de08a3e48c8f170ba8aa037533d4c Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Sun, 22 May 2016 13:32:03 +0000 Subject: [PATCH 0077/2182] PDFBOX-2852: avoid ClassCastException / ArrayOutOfBoundsExceptions git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1745041 13f79535-47bb-0310-9956-ffa450edef68 --- .../contentstream/operator/state/SetFlatness.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/contentstream/operator/state/SetFlatness.java b/pdfbox/src/main/java/org/apache/pdfbox/contentstream/operator/state/SetFlatness.java index 6b1592edd79..4e6f59105aa 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/contentstream/operator/state/SetFlatness.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/contentstream/operator/state/SetFlatness.java @@ -19,6 +19,7 @@ import java.io.IOException; import java.util.List; +import org.apache.pdfbox.contentstream.operator.MissingOperandException; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSNumber; import org.apache.pdfbox.contentstream.operator.Operator; @@ -34,7 +35,15 @@ public class SetFlatness extends OperatorProcessor @Override public void process(Operator operator, List operands) throws IOException { - COSNumber value = (COSNumber)operands.get(0); + if (operands.size() < 1) + { + throw new MissingOperandException(operator, operands); + } + if (!checkArrayTypesClass(operands, COSNumber.class)) + { + return; + } + COSNumber value = (COSNumber) operands.get(0); context.getGraphicsState().setFlatness(value.floatValue()); } From e7289f86fa27aa2bb61e03fdf678400c75bda524 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Mon, 23 May 2016 19:13:54 +0000 Subject: [PATCH 0078/2182] PDFBOX-3360: avoid infinite or NaN values for dash git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1745244 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/pdfbox/rendering/PageDrawer.java | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/rendering/PageDrawer.java b/pdfbox/src/main/java/org/apache/pdfbox/rendering/PageDrawer.java index 579cc5ee698..bfa5a6beec6 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/rendering/PageDrawer.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/rendering/PageDrawer.java @@ -561,10 +561,22 @@ private BasicStroke getStroke() phaseStart = (int)transformWidth(phaseStart); // empty dash array is illegal - if (dashArray.length == 0) + // avoid also infinite and NaN values (PDFBOX-3360) + if (dashArray.length == 0 || Float.isInfinite(phaseStart) || Float.isNaN(phaseStart)) { dashArray = null; } + else + { + for (int i = 0; i < dashArray.length; ++i) + { + if (Float.isInfinite(dashArray[i]) || Float.isNaN(dashArray[i])) + { + dashArray = null; + break; + } + } + } } return new BasicStroke(lineWidth, state.getLineCap(), state.getLineJoin(), state.getMiterLimit(), dashArray, phaseStart); From 020d326c102f22d1be774591e35d408f8ffd5058 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Wed, 25 May 2016 15:48:09 +0000 Subject: [PATCH 0079/2182] PDFBOX-3362: add missing TwoColumnRight git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1745508 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/pdfbox/pdmodel/PageLayout.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PageLayout.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PageLayout.java index b268eca779f..dc8e9187b9b 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PageLayout.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PageLayout.java @@ -56,6 +56,10 @@ else if (value.equals("TwoColumnLeft")) { return TWO_COLUMN_LEFT; } + else if (value.equals("TwoColumnRight")) + { + return TWO_COLUMN_RIGHT; + } else if (value.equals("TwoPageLeft")) { return TWO_PAGE_LEFT; From 4ffb9a8663ae948ea1236f01e1f0f20af8f6c8d1 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Wed, 25 May 2016 15:50:35 +0000 Subject: [PATCH 0080/2182] PDFBOX-3362: add test git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1745512 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/pdfbox/pdmodel/PageLayoutTest.java | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 pdfbox/src/test/java/org/apache/pdfbox/pdmodel/PageLayoutTest.java diff --git a/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/PageLayoutTest.java b/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/PageLayoutTest.java new file mode 100644 index 00000000000..375cc2e2e93 --- /dev/null +++ b/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/PageLayoutTest.java @@ -0,0 +1,46 @@ +/* + * Copyright 2016 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.pdfbox.pdmodel; + +import java.util.EnumSet; +import java.util.HashSet; +import java.util.Set; +import static org.junit.Assert.assertEquals; +import org.junit.Test; + +/** + * @author Tilman Hausherr + */ +public class PageLayoutTest +{ + /** + * Test for completeness (PDFBOX-3362). + */ + @Test + public void testValues() + { + Set pageLayoutSet = EnumSet.noneOf(PageLayout.class); + Set stringSet = new HashSet(); + for (PageLayout pl : PageLayout.values()) + { + String s = pl.stringValue(); + stringSet.add(s); + pageLayoutSet.add(PageLayout.fromString(s)); + } + assertEquals(PageLayout.values().length, pageLayoutSet.size()); + assertEquals(PageLayout.values().length, stringSet.size()); + } +} From 64dedc0771b07f7e5073304dfe7aa27d8e0f9890 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Wed, 25 May 2016 17:34:01 +0000 Subject: [PATCH 0081/2182] PDFBOX-3363: close temp file, as suggested by Damien Butaye git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1745522 13f79535-47bb-0310-9956-ffa450edef68 --- .../digitalsignature/SignatureOptions.java | 62 +++++++++++-------- 1 file changed, 37 insertions(+), 25 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/SignatureOptions.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/SignatureOptions.java index 33d2bfe27f0..7229e256758 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/SignatureOptions.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/SignatureOptions.java @@ -23,6 +23,7 @@ import org.apache.pdfbox.cos.COSDocument; import org.apache.pdfbox.io.RandomAccessBufferedFileInputStream; +import org.apache.pdfbox.io.RandomAccessRead; import org.apache.pdfbox.pdfparser.PDFParser; import org.apache.pdfbox.pdmodel.interactive.digitalsignature.visible.PDVisibleSigProperties; @@ -34,7 +35,11 @@ public class SignatureOptions implements Closeable private COSDocument visualSignature; private int preferredSignatureSize; private int pageNo; - + + // the pdf to be read + // this is done analog to PDDocument + private RandomAccessRead pdfSource = null; + public static final int DEFAULT_SIGNATURE_SIZE = 0x2500; /** @@ -47,85 +52,88 @@ public SignatureOptions() /** * Set the 0-based page number. - * + * * @param pageNo the page number */ public void setPage(int pageNo) { this.pageNo = pageNo; } - + /** * Get the 0-based page number. - * + * * @return the page number */ - public int getPage() + public int getPage() { return pageNo; } - + /** * Reads the visual signature from the given file. - * + * * @param file the file containing the visual signature - * @throws IOException when something went wrong during parsing + * @throws IOException when something went wrong during parsing */ public void setVisualSignature(File file) throws IOException - { - PDFParser parser = new PDFParser(new RandomAccessBufferedFileInputStream(file)); + { + pdfSource = new RandomAccessBufferedFileInputStream(file); + PDFParser parser = new PDFParser(pdfSource); parser.parse(); visualSignature = parser.getDocument(); } - + /** * Reads the visual signature from the given input stream. - * + * * @param is the input stream containing the visual signature - * @throws IOException when something went wrong during parsing + * @throws IOException when something went wrong during parsing */ public void setVisualSignature(InputStream is) throws IOException - { - PDFParser parser = new PDFParser(new RandomAccessBufferedFileInputStream(is)); + { + pdfSource = new RandomAccessBufferedFileInputStream(is); + PDFParser parser = new PDFParser(pdfSource); parser.parse(); visualSignature = parser.getDocument(); } - + /** * Reads the visual signature from the given visual signature properties - * - * @param visSignatureProperties the PDVisibleSigProperties object containing the visual signature - * + * + * @param visSignatureProperties the PDVisibleSigProperties object containing the + * visual signature + * * @throws IOException when something went wrong during parsing */ public void setVisualSignature(PDVisibleSigProperties visSignatureProperties) throws IOException - { + { setVisualSignature(visSignatureProperties.getVisibleSignature()); } /** * Get the visual signature. - * + * * @return the visual signature */ public COSDocument getVisualSignature() { return visualSignature; } - + /** * Get the preferred size of the signature. - * + * * @return the preferred size of the signature in bytes. */ public int getPreferredSignatureSize() { return preferredSignatureSize; } - + /** * Set the preferred size of the signature. - * + * * @param size the size of the signature in bytes. Only values above 0 will be considered. */ public void setPreferredSignatureSize(int size) @@ -148,5 +156,9 @@ public void close() throws IOException { visualSignature.close(); } + if (pdfSource != null) + { + pdfSource.close(); + } } } From 35da4746d6073975e3a056793715b4d15821c342 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Lehmk=C3=BChler?= Date: Thu, 26 May 2016 12:46:34 +0000 Subject: [PATCH 0082/2182] PDFBOX-3089: cache pointCount to avoid recalculations git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1745598 13f79535-47bb-0310-9956-ffa450edef68 --- .../fontbox/ttf/GlyfCompositeDescript.java | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/fontbox/src/main/java/org/apache/fontbox/ttf/GlyfCompositeDescript.java b/fontbox/src/main/java/org/apache/fontbox/ttf/GlyfCompositeDescript.java index 9245a431dc1..f2561887019 100644 --- a/fontbox/src/main/java/org/apache/fontbox/ttf/GlyfCompositeDescript.java +++ b/fontbox/src/main/java/org/apache/fontbox/ttf/GlyfCompositeDescript.java @@ -44,7 +44,7 @@ public class GlyfCompositeDescript extends GlyfDescript private GlyphTable glyphTable = null; private boolean beingResolved = false; private boolean resolved = false; - + private int pointCount = -1; /** * Constructor. * @@ -203,14 +203,21 @@ public int getPointCount() { LOG.error("getPointCount called on unresolved GlyfCompositeDescript"); } - GlyfCompositeComp c = components.get(components.size() - 1); - GlyphDescription gd = getGlypDescription(c.getGlyphIndex()); - if (gd == null) + if (pointCount < 0) { - LOG.error("getGlypDescription(" + c.getGlyphIndex() + ") is null, returning 0"); - return 0; - } - return c.getFirstIndex() + gd.getPointCount(); + GlyfCompositeComp c = components.get(components.size() - 1); + GlyphDescription gd = getGlypDescription(c.getGlyphIndex()); + if (gd == null) + { + LOG.error("getGlypDescription(" + c.getGlyphIndex() + ") is null, returning 0"); + pointCount = 0; + } + else + { + pointCount = c.getFirstIndex() + gd.getPointCount(); + } + } + return pointCount; } /** From 5fc9b40acd0393cb0d57a757a499931314d17af1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Lehmk=C3=BChler?= Date: Thu, 26 May 2016 13:43:52 +0000 Subject: [PATCH 0083/2182] added rat exclude rule git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1745607 13f79535-47bb-0310-9956-ffa450edef68 --- pdfbox/pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/pdfbox/pom.xml b/pdfbox/pom.xml index d04466a07ef..d05554bd036 100644 --- a/pdfbox/pom.xml +++ b/pdfbox/pom.xml @@ -153,6 +153,7 @@ src/test/resources/org/apache/pdfbox/encryption/*.der src/test/resources/org/apache/pdfbox/encryption/*.pfx src/test/resources/org/apache/pdfbox/filter/*.bin + src/test/resources/org/apache/pdfbox/text/*.txt From 44f2ab11ba347bf8cf654975673c7518843869fe Mon Sep 17 00:00:00 2001 From: Maruan Sahyoun Date: Thu, 26 May 2016 15:42:55 +0000 Subject: [PATCH 0084/2182] PDFBOX-3364: include descendant PDSignature fields in List for getSignatureFields() git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1745618 13f79535-47bb-0310-9956-ffa450edef68 --- pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java index f9368c1e693..e614ed5f38e 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java @@ -698,7 +698,7 @@ public List getSignatureFields() throws IOException if (acroForm != null) { // fixme: non-terminal fields are ignored, could have descendant signatures - for (PDField field : acroForm.getFields()) + for (PDField field : acroForm.getFieldTree()) { if (field instanceof PDSignatureField) { From 32e8a3987f9519321a5aa7db865ed588eeb6dd95 Mon Sep 17 00:00:00 2001 From: Maruan Sahyoun Date: Thu, 26 May 2016 15:44:10 +0000 Subject: [PATCH 0085/2182] PDFBOX-3364: remove obsolete source code comment in PDSignature.getSignatureFields() git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1745619 13f79535-47bb-0310-9956-ffa450edef68 --- pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java | 1 - 1 file changed, 1 deletion(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java index e614ed5f38e..23d2a5efdd1 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java @@ -697,7 +697,6 @@ public List getSignatureFields() throws IOException PDAcroForm acroForm = getDocumentCatalog().getAcroForm(); if (acroForm != null) { - // fixme: non-terminal fields are ignored, could have descendant signatures for (PDField field : acroForm.getFieldTree()) { if (field instanceof PDSignatureField) From 2f038049613c79e4a850fc69bbb2e3bb82efc9c1 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Fri, 27 May 2016 17:18:10 +0000 Subject: [PATCH 0086/2182] PDFBOX-2852: nested enum types are implicitly static git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1745778 13f79535-47bb-0310-9956-ffa450edef68 --- fontbox/src/main/java/org/apache/fontbox/type1/Token.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fontbox/src/main/java/org/apache/fontbox/type1/Token.java b/fontbox/src/main/java/org/apache/fontbox/type1/Token.java index d37a40e978b..08844e06637 100644 --- a/fontbox/src/main/java/org/apache/fontbox/type1/Token.java +++ b/fontbox/src/main/java/org/apache/fontbox/type1/Token.java @@ -30,7 +30,7 @@ class Token * All different types of tokens. * */ - static enum Kind + enum Kind { NONE, STRING, NAME, LITERAL, REAL, INTEGER, START_ARRAY, END_ARRAY, START_PROC, From 0daf27fe8f1e18f64b2df20c496566674c08b5b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Lehmk=C3=BChler?= Date: Fri, 27 May 2016 17:21:05 +0000 Subject: [PATCH 0087/2182] PDFBOX-3267: synchronize render operation for thread safety git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1745783 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/fontbox/cff/Type1CharString.java | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/fontbox/src/main/java/org/apache/fontbox/cff/Type1CharString.java b/fontbox/src/main/java/org/apache/fontbox/cff/Type1CharString.java index cc7551892f9..3cae4b70548 100644 --- a/fontbox/src/main/java/org/apache/fontbox/cff/Type1CharString.java +++ b/fontbox/src/main/java/org/apache/fontbox/cff/Type1CharString.java @@ -87,9 +87,12 @@ public String getName() */ public Rectangle2D getBounds() { - if (path == null) + synchronized(LOG) { - render(); + if (path == null) + { + render(); + } } return path.getBounds2D(); } @@ -100,9 +103,12 @@ public Rectangle2D getBounds() */ public int getWidth() { - if (path == null) + synchronized(LOG) { - render(); + if (path == null) + { + render(); + } } return width; } @@ -113,9 +119,12 @@ public int getWidth() */ public GeneralPath getPath() { - if (path == null) + synchronized(LOG) { - render(); + if (path == null) + { + render(); + } } return path; } From 620cb641deb63db2ebf455d57597d3ed587d4c02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Lehmk=C3=BChler?= Date: Fri, 27 May 2016 17:21:54 +0000 Subject: [PATCH 0088/2182] PDFBOX-3267: synchronize parts of loadICCProfile as proposed by Tilman Hausherr git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1745784 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/pdfbox/pdmodel/graphics/color/PDICCBased.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDICCBased.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDICCBased.java index 96f8b7c2dd5..17523cfc7b6 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDICCBased.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDICCBased.java @@ -116,7 +116,11 @@ private void loadICCProfile() throws IOException // if the embedded profile is sRGB then we can use Java's built-in profile, which // results in a large performance gain as it's our native color space, see PDFBOX-2587 - ICC_Profile profile = ICC_Profile.getInstance(input); + ICC_Profile profile; + synchronized (LOG) + { + profile = ICC_Profile.getInstance(input); + } if (is_sRGB(profile)) { awtColorSpace = (ICC_ColorSpace)ColorSpace.getInstance(ColorSpace.CS_sRGB); From 450174fcc39acaa1426ce46a564a3d23c76fa284 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Fri, 27 May 2016 17:21:57 +0000 Subject: [PATCH 0089/2182] PDFBOX-2852: nested enum types are implicitly static git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1745785 13f79535-47bb-0310-9956-ffa450edef68 --- .../viewerpreferences/PDViewerPreferences.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/viewerpreferences/PDViewerPreferences.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/viewerpreferences/PDViewerPreferences.java index 24ea2a79f9d..9c26b66b4c2 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/viewerpreferences/PDViewerPreferences.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/viewerpreferences/PDViewerPreferences.java @@ -57,7 +57,7 @@ public class PDViewerPreferences implements COSObjectable /** * Enumeration containing all valid values for NonFullScreenPageMode. */ - public static enum NON_FULL_SCREEN_PAGE_MODE + public enum NON_FULL_SCREEN_PAGE_MODE { /** * From PDF Reference: "Neither document outline nor thumbnail images visible". @@ -92,7 +92,7 @@ public static enum NON_FULL_SCREEN_PAGE_MODE /** * Enumeration containing all valid values for ReadingDirection. */ - public static enum READING_DIRECTION + public enum READING_DIRECTION { /** * left to right. @@ -137,7 +137,7 @@ public static enum READING_DIRECTION /** * Enumeration containing all valid values for boundaries. */ - public static enum BOUNDARY + public enum BOUNDARY { /** * use media box as boundary. @@ -164,7 +164,7 @@ public static enum BOUNDARY /** * Enumeration containing all valid values for duplex. */ - public static enum DUPLEX + public enum DUPLEX { /** * simplex printing. @@ -183,7 +183,7 @@ public static enum DUPLEX /** * Enumeration containing all valid values for printscaling. */ - public static enum PRINT_SCALING + public enum PRINT_SCALING { /** * no scaling. From 9424584b6d8ec2cd5041e4a65805ec5e4d00619b Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Fri, 27 May 2016 17:22:13 +0000 Subject: [PATCH 0090/2182] PDFBOX-2852: nested enum types are implicitly static git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1745786 13f79535-47bb-0310-9956-ffa450edef68 --- .../graphics/optionalcontent/PDOptionalContentProperties.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/optionalcontent/PDOptionalContentProperties.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/optionalcontent/PDOptionalContentProperties.java index 30b2374c1d4..c18a1e8290c 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/optionalcontent/PDOptionalContentProperties.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/optionalcontent/PDOptionalContentProperties.java @@ -36,7 +36,7 @@ public class PDOptionalContentProperties implements COSObjectable /** * Enumeration for the BaseState dictionary entry on the "D" dictionary. */ - public static enum BaseState + public enum BaseState { /** The "ON" value. */ From 52dd8615241c2dcd7f3f964a52568368dc654aea Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Fri, 27 May 2016 17:22:37 +0000 Subject: [PATCH 0091/2182] PDFBOX-2852: nested enum types are implicitly static git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1745787 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/pdfbox/pdmodel/common/function/type4/Parser.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/Parser.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/Parser.java index f29828e9220..da828844ca9 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/Parser.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/Parser.java @@ -25,7 +25,7 @@ public final class Parser { /** Used to indicate the parsers current state. */ - private static enum State + private enum State { NEWLINE, WHITESPACE, COMMENT, TOKEN } From a0e011389bec98ad62440aa2c33a8ee2f120158e Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Fri, 27 May 2016 18:17:30 +0000 Subject: [PATCH 0092/2182] PDFBOX-2852: fix javadoc; add @deprecated annotation that is already in javadoc git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1745800 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/pdfbox/pdmodel/common/function/PDFunction.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/PDFunction.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/PDFunction.java index b188d2614c1..40151b5dd9f 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/PDFunction.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/PDFunction.java @@ -153,9 +153,9 @@ else if( functionType == 4 ) * have a range specified. A range for output parameters * is optional so this may return zero for a function * that does have output parameters, this will simply return the - * number that have the rnage specified. + * number that have the range specified. * - * @return The number of input parameters that have a range + * @return The number of output parameters that have a range * specified. */ public int getNumberOfOutputParameters() @@ -240,6 +240,7 @@ public void setDomainValues(COSArray domainValues) /** * @deprecated Replaced by {@link #eval(float[] input)} */ + @Deprecated public COSArray eval(COSArray input) throws IOException { float[] outputValues = eval(input.toFloatArray()); From 00ae7e6f351df6de3b3de0b4fda44b1c5da7d8d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Lehmk=C3=BChler?= Date: Sat, 28 May 2016 10:54:00 +0000 Subject: [PATCH 0093/2182] PDFBOX-3089: cache GlyphDescription git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1745866 13f79535-47bb-0310-9956-ffa450edef68 --- .../fontbox/ttf/GlyfCompositeDescript.java | 56 +++++++++++-------- 1 file changed, 34 insertions(+), 22 deletions(-) diff --git a/fontbox/src/main/java/org/apache/fontbox/ttf/GlyfCompositeDescript.java b/fontbox/src/main/java/org/apache/fontbox/ttf/GlyfCompositeDescript.java index f2561887019..6a0ec271cdc 100644 --- a/fontbox/src/main/java/org/apache/fontbox/ttf/GlyfCompositeDescript.java +++ b/fontbox/src/main/java/org/apache/fontbox/ttf/GlyfCompositeDescript.java @@ -20,8 +20,11 @@ Licensed to the Apache Software Foundation (ASF) under one or more import java.io.IOException; import java.util.ArrayList; +import java.util.HashMap; import java.util.Iterator; import java.util.List; +import java.util.Map; + import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -41,10 +44,13 @@ public class GlyfCompositeDescript extends GlyfDescript private static final Log LOG = LogFactory.getLog(GlyfCompositeDescript.class); private final List components = new ArrayList(); + private final Map descriptions = new HashMap(); private GlyphTable glyphTable = null; private boolean beingResolved = false; private boolean resolved = false; private int pointCount = -1; + private int contourCount = -1; + /** * Constructor. * @@ -72,6 +78,7 @@ public GlyfCompositeDescript(TTFDataStream bais, GlyphTable glyphTable) throws I { readInstructions(bais, (bais.readUnsignedShort())); } + initDescriptions(); } /** @@ -101,8 +108,7 @@ public void resolve() comp.setFirstIndex(firstIndex); comp.setFirstContour(firstContour); - GlyphDescription desc; - desc = getGlypDescription(comp.getGlyphIndex()); + GlyphDescription desc = descriptions.get(comp.getGlyphIndex()); if (desc != null) { desc.resolve(); @@ -123,7 +129,7 @@ public int getEndPtOfContours(int i) GlyfCompositeComp c = getCompositeCompEndPt(i); if (c != null) { - GlyphDescription gd = getGlypDescription(c.getGlyphIndex()); + GlyphDescription gd = descriptions.get(c.getGlyphIndex()); return gd.getEndPtOfContours(i - c.getFirstContour()) + c.getFirstIndex(); } return 0; @@ -138,7 +144,7 @@ public byte getFlags(int i) GlyfCompositeComp c = getCompositeComp(i); if (c != null) { - GlyphDescription gd = getGlypDescription(c.getGlyphIndex()); + GlyphDescription gd = descriptions.get(c.getGlyphIndex()); return gd.getFlags(i - c.getFirstIndex()); } return 0; @@ -153,7 +159,7 @@ public short getXCoordinate(int i) GlyfCompositeComp c = getCompositeComp(i); if (c != null) { - GlyphDescription gd = getGlypDescription(c.getGlyphIndex()); + GlyphDescription gd = descriptions.get(c.getGlyphIndex()); int n = i - c.getFirstIndex(); int x = gd.getXCoordinate(n); int y = gd.getYCoordinate(n); @@ -173,7 +179,7 @@ public short getYCoordinate(int i) GlyfCompositeComp c = getCompositeComp(i); if (c != null) { - GlyphDescription gd = getGlypDescription(c.getGlyphIndex()); + GlyphDescription gd = descriptions.get(c.getGlyphIndex()); int n = i - c.getFirstIndex(); int x = gd.getXCoordinate(n); int y = gd.getYCoordinate(n); @@ -206,7 +212,7 @@ public int getPointCount() if (pointCount < 0) { GlyfCompositeComp c = components.get(components.size() - 1); - GlyphDescription gd = getGlypDescription(c.getGlyphIndex()); + GlyphDescription gd = descriptions.get(c.getGlyphIndex()); if (gd == null) { LOG.error("getGlypDescription(" + c.getGlyphIndex() + ") is null, returning 0"); @@ -230,8 +236,12 @@ public int getContourCount() { LOG.error("getContourCount called on unresolved GlyfCompositeDescript"); } - GlyfCompositeComp c = components.get(components.size() - 1); - return c.getFirstContour() + getGlypDescription(c.getGlyphIndex()).getContourCount(); + if (contourCount < 0) + { + GlyfCompositeComp c = components.get(components.size() - 1); + contourCount = c.getFirstContour() + descriptions.get(c.getGlyphIndex()).getContourCount(); + } + return contourCount; } /** @@ -248,7 +258,7 @@ private GlyfCompositeComp getCompositeComp(int i) { for (GlyfCompositeComp c : components) { - GlyphDescription gd = getGlypDescription(c.getGlyphIndex()); + GlyphDescription gd = descriptions.get(c.getGlyphIndex()); if (c.getFirstIndex() <= i && i < (c.getFirstIndex() + gd.getPointCount())) { return c; @@ -261,7 +271,7 @@ private GlyfCompositeComp getCompositeCompEndPt(int i) { for (GlyfCompositeComp c : components) { - GlyphDescription gd = getGlypDescription(c.getGlyphIndex()); + GlyphDescription gd = descriptions.get(c.getGlyphIndex()); if (c.getFirstContour() <= i && i < (c.getFirstContour() + gd.getContourCount())) { return c; @@ -270,21 +280,23 @@ private GlyfCompositeComp getCompositeCompEndPt(int i) return null; } - private GlyphDescription getGlypDescription(int index) + private void initDescriptions() { - try + for (GlyfCompositeComp component : components) { - GlyphData glyph = glyphTable.getGlyph(index); - if (glyph != null) + try { - return glyph.getDescription(); + int index = component.getGlyphIndex(); + GlyphData glyph = glyphTable.getGlyph(index); + if (glyph != null) + { + descriptions.put(index, glyph.getDescription()); + } } - return null; - } - catch (IOException e) - { - LOG.error(e); - return null; + catch (IOException e) + { + LOG.error(e); + } } } } From 74284f613b269e75a82f10c42f15159fabc6b225 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Lehmk=C3=BChler?= Date: Mon, 30 May 2016 16:17:21 +0000 Subject: [PATCH 0094/2182] PDFBOX-3368: use the underlying map to check if a key is present git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1746153 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/pdfbox/pdmodel/common/COSDictionaryMap.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/COSDictionaryMap.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/COSDictionaryMap.java index 643110d985e..90eaf7cb6c3 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/COSDictionaryMap.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/COSDictionaryMap.java @@ -78,7 +78,7 @@ public boolean isEmpty() @Override public boolean containsKey(Object key) { - return map.keySet().contains( key ); + return actuals.containsKey( key ); } /** From 93bfa75edb78c307de6e3ec42a618b7a19d20395 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Mon, 30 May 2016 19:23:19 +0000 Subject: [PATCH 0095/2182] PDFBOX-3338: add ccitt decode from twelvemonkeys from Harald Kuhr and Oliver Schmidtmer with some modifications by Petr Slaby git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1746169 13f79535-47bb-0310-9956-ffa450edef68 --- .../pdfbox/filter/CCITTFaxDecoderStream.java | 809 ++++++++++++++++++ .../apache/pdfbox/filter/CCITTFaxFilter.java | 44 +- .../apache/pdfbox/filter/TIFFExtension.java | 106 +++ 3 files changed, 944 insertions(+), 15 deletions(-) create mode 100644 pdfbox/src/main/java/org/apache/pdfbox/filter/CCITTFaxDecoderStream.java create mode 100644 pdfbox/src/main/java/org/apache/pdfbox/filter/TIFFExtension.java diff --git a/pdfbox/src/main/java/org/apache/pdfbox/filter/CCITTFaxDecoderStream.java b/pdfbox/src/main/java/org/apache/pdfbox/filter/CCITTFaxDecoderStream.java new file mode 100644 index 00000000000..c36cbcd52ee --- /dev/null +++ b/pdfbox/src/main/java/org/apache/pdfbox/filter/CCITTFaxDecoderStream.java @@ -0,0 +1,809 @@ +/* + * Copyright (c) 2012, Harald Kuhr + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name "TwelveMonkeys" nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.apache.pdfbox.filter; + + +import java.io.EOFException; +import java.io.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Arrays; + +/** + * CCITT Modified Huffman RLE, Group 3 (T4) and Group 4 (T6) fax compression. + * + * @author Harald Kuhr + * @author Oliver Schmidtmer + * @author last modified by $Author: haraldk$ + * @version $Id: CCITTFaxDecoderStream.java,v 1.0 23.05.12 15:55 haraldk Exp$ + * + * Taken from commit fa0341f30237effe523e9905e672d709ffe9c6bd of 7.5.2016 from twelvemonkeys/imageio/plugins/tiff/CCITTFaxDecoderStream.java + * + * Initial changes for PDFBox, discussed in PDFBOX-3338: + * - added optionByteAligned to constructor and to each decodeRowType() method + * - removed Validate() usages + * - catch VALUE_EOL in decode1D() + */ +final class CCITTFaxDecoderStream extends FilterInputStream { + // See TIFF 6.0 Specification, Section 10: "Modified Huffman Compression", page 43. + + private final int columns; + private final byte[] decodedRow; + + private int decodedLength; + private int decodedPos; + + // Need to take fill order into account (?) (use flip table?) + private final int fillOrder; + private final int type; + + private int[] changesReferenceRow; + private int[] changesCurrentRow; + private int changesReferenceRowCount; + private int changesCurrentRowCount; + + private boolean optionG32D = false; + + @SuppressWarnings("unused") // Leading zeros for aligning EOL + private boolean optionG3Fill = false; + + private boolean optionUncompressed = false; + private boolean optionByteAligned = false; + + CCITTFaxDecoderStream(final InputStream stream, final int columns, final int type, final int fillOrder, + final long options) { + super(stream); + + this.columns = columns; + // We know this is only used for b/w (1 bit) + this.decodedRow = new byte[(columns + 7) / 8]; + this.type = type; + + this.fillOrder = fillOrder; + + this.changesReferenceRow = new int[columns+1]; + this.changesCurrentRow = new int[columns+1]; + + switch (type) { + case TIFFExtension.COMPRESSION_CCITT_MODIFIED_HUFFMAN_RLE: + optionByteAligned = (options & TIFFExtension.GROUP3OPT_BYTEALIGNED) != 0; + break; + case TIFFExtension.COMPRESSION_CCITT_T4: + optionG32D = (options & TIFFExtension.GROUP3OPT_2DENCODING) != 0; + optionG3Fill = (options & TIFFExtension.GROUP3OPT_FILLBITS) != 0; + optionUncompressed = (options & TIFFExtension.GROUP3OPT_UNCOMPRESSED) != 0; + optionByteAligned = (options & TIFFExtension.GROUP3OPT_BYTEALIGNED) != 0; + break; + case TIFFExtension.COMPRESSION_CCITT_T6: + optionUncompressed = (options & TIFFExtension.GROUP4OPT_UNCOMPRESSED) != 0; + optionByteAligned = (options & TIFFExtension.GROUP4OPT_BYTEALIGNED) != 0; + break; + } + + } + + private void fetch() throws IOException { + if (decodedPos >= decodedLength) { + decodedLength = 0; + + try { + decodeRow(); + } + catch (EOFException e) { + // TODO: Rewrite to avoid throw/catch for normal flow... + if (decodedLength != 0) { + throw e; + } + + // ..otherwise, just client code trying to read past the end of + // stream + decodedLength = -1; + } + + decodedPos = 0; + } + } + + private void decode1D() throws IOException { + int index = 0; + boolean white = true; + changesCurrentRowCount = 0; + + do { + int completeRun; + + if (white) { + completeRun = decodeRun(whiteRunTree); + } + else { + completeRun = decodeRun(blackRunTree); + } + + if (completeRun == VALUE_EOL) + { + continue; + } + + index += completeRun; + changesCurrentRow[changesCurrentRowCount++] = index; + + // Flip color for next run + white = !white; + } while (index < columns); + } + + private void decode2D() throws IOException { + changesReferenceRowCount = changesCurrentRowCount; + int[] tmp = changesCurrentRow; + changesCurrentRow = changesReferenceRow; + changesReferenceRow = tmp; + + boolean white = true; + int index = 0; + changesCurrentRowCount = 0; + + mode: while (index < columns) { + // read mode + Node n = codeTree.root; + + while (true) { + n = n.walk(readBit()); + + if (n == null) { + continue mode; + } + else if (n.isLeaf) { + switch (n.value) { + case VALUE_HMODE: + int runLength; + runLength = decodeRun(white ? whiteRunTree : blackRunTree); + index += runLength; + changesCurrentRow[changesCurrentRowCount++] = index; + + runLength = decodeRun(white ? blackRunTree : whiteRunTree); + index += runLength; + changesCurrentRow[changesCurrentRowCount++] = index; + break; + + case VALUE_PASSMODE: + int pChangingElement = getNextChangingElement(index, white) + 1; + + if (pChangingElement >= changesReferenceRowCount || pChangingElement == -1) { + index = columns; + } + else { + index = changesReferenceRow[pChangingElement]; + } + + break; + + default: + // Vertical mode (-3 to 3) + int vChangingElement = getNextChangingElement(index, white); + + if (vChangingElement >= changesReferenceRowCount || vChangingElement == -1) { + index = columns + n.value; + } + else { + index = changesReferenceRow[vChangingElement] + n.value; + } + + changesCurrentRow[changesCurrentRowCount] = index; + changesCurrentRowCount++; + white = !white; + + break; + } + + continue mode; + } + } + } + } + + private int getNextChangingElement(final int a0, final boolean white) { + int start = white ? 0 : 1; + + for (int i = start; i < changesReferenceRowCount; i += 2) { + if (a0 < changesReferenceRow[i] || (a0 == 0 && changesReferenceRow[i] == 0)) { + return i; + } + } + + return -1; + } + + private void decodeRowType2() throws IOException { + if (optionByteAligned) + { + resetBuffer(); + } + decode1D(); + } + + private void decodeRowType4() throws IOException { + if(optionByteAligned) { + bufferPos = -1; // Skip remaining bits and fetch the next byte at row start + } + eof: while (true) { + // read till next EOL code + Node n = eolOnlyTree.root; + + while (true) { + n = n.walk(readBit()); + + if (n == null) { + continue eof; + } + + if (n.isLeaf) { + break eof; + } + } + } + + if (!optionG32D || readBit()) { + decode1D(); + } + else { + decode2D(); + } + } + + private void decodeRowType6() throws IOException { + if(optionByteAligned) { + bufferPos = -1; // Skip remaining bits and fetch the next byte at row start + } + decode2D(); + } + + private void decodeRow() throws IOException { + switch (type) { + case TIFFExtension.COMPRESSION_CCITT_MODIFIED_HUFFMAN_RLE: + decodeRowType2(); + break; + case TIFFExtension.COMPRESSION_CCITT_T4: + decodeRowType4(); + break; + case TIFFExtension.COMPRESSION_CCITT_T6: + decodeRowType6(); + break; + } + + int index = 0; + boolean white = true; + + for (int i = 0; i <= changesCurrentRowCount; i++) { + int nextChange = columns; + + if (i != changesCurrentRowCount) { + nextChange = changesCurrentRow[i]; + } + + if (nextChange > columns) { + nextChange = columns; + } + + int byteIndex = index / 8; + + while (index % 8 != 0 && (nextChange - index) > 0) { + decodedRow[byteIndex] |= (white ? 0 : 1 << (7 - ((index) % 8))); + index++; + } + + if (index % 8 == 0) { + byteIndex = index / 8; + final byte value = (byte) (white ? 0x00 : 0xff); + + while ((nextChange - index) > 7) { + decodedRow[byteIndex] = value; + index += 8; + ++byteIndex; + } + } + + while ((nextChange - index) > 0) { + if (index % 8 == 0) { + decodedRow[byteIndex] = 0; + } + + decodedRow[byteIndex] |= (white ? 0 : 1 << (7 - ((index) % 8))); + index++; + } + + white = !white; + } + + if (index != columns) { + throw new IOException("Sum of run-lengths does not equal scan line width: " + index + " > " + columns); + } + + decodedLength = (index + 7) / 8; + } + + private int decodeRun(final Tree tree) throws IOException { + int total = 0; + + Node n = tree.root; + + while (true) { + boolean bit = readBit(); + n = n.walk(bit); + + if (n == null) { + throw new IOException("Unknown code in Huffman RLE stream"); + } + + if (n.isLeaf) { + total += n.value; + if (n.value < 64) { + return total; + } + else { + n = tree.root; + } + } + } + } + + private void resetBuffer() throws IOException { + for (int i = 0; i < decodedRow.length; i++) { + decodedRow[i] = 0; + } + + while (true) { + if (bufferPos == -1) { + return; + } + + readBit(); + } + } + + int buffer = -1; + int bufferPos = -1; + + private boolean readBit() throws IOException { + if (bufferPos < 0 || bufferPos > 7) { + buffer = in.read(); + + if (buffer == -1) { + throw new EOFException("Unexpected end of Huffman RLE stream"); + } + + bufferPos = 0; + } + + boolean isSet; + + if (fillOrder == TIFFExtension.FILL_LEFT_TO_RIGHT) { + isSet = ((buffer >> (7 - bufferPos)) & 1) == 1; + } + else { + isSet = ((buffer >> (bufferPos)) & 1) == 1; + } + + bufferPos++; + + if (bufferPos > 7) { + bufferPos = -1; + } + + return isSet; + } + + @Override + public int read() throws IOException { + if (decodedLength < 0) { + return 0x0; + } + + if (decodedPos >= decodedLength) { + fetch(); + + if (decodedLength < 0) { + return 0x0; + } + } + + return decodedRow[decodedPos++] & 0xff; + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + if (decodedLength < 0) { + //TODO better? Math.min(off + len, b.length) + Arrays.fill(b, off, off + len, (byte) 0x0); + return len; + } + + if (decodedPos >= decodedLength) { + fetch(); + + if (decodedLength < 0) { + Arrays.fill(b, off, off + len, (byte) 0x0); + return len; + } + } + + int read = Math.min(decodedLength - decodedPos, len); + System.arraycopy(decodedRow, decodedPos, b, off, read); + decodedPos += read; + + return read; + } + + @Override + public long skip(long n) throws IOException { + if (decodedLength < 0) { + return -1; + } + + if (decodedPos >= decodedLength) { + fetch(); + + if (decodedLength < 0) { + return -1; + } + } + + int skipped = (int) Math.min(decodedLength - decodedPos, n); + decodedPos += skipped; + + return skipped; + } + + @Override + public boolean markSupported() { + return false; + } + + @Override + public synchronized void reset() throws IOException { + throw new IOException("mark/reset not supported"); + } + + private static final class Node { + Node left; + Node right; + + int value; // > 63 non term. + + boolean canBeFill = false; + boolean isLeaf = false; + + void set(final boolean next, final Node node) { + if (!next) { + left = node; + } + else { + right = node; + } + } + + Node walk(final boolean next) { + return next ? right : left; + } + + @Override + public String toString() { + return "[leaf=" + isLeaf + ", value=" + value + ", canBeFill=" + canBeFill + "]"; + } + } + + private static final class Tree { + final Node root = new Node(); + + void fill(final int depth, final int path, final int value) throws IOException { + Node current = root; + + for (int i = 0; i < depth; i++) { + int bitPos = depth - 1 - i; + boolean isSet = ((path >> bitPos) & 1) == 1; + Node next = current.walk(isSet); + + if (next == null) { + next = new Node(); + + if (i == depth - 1) { + next.value = value; + next.isLeaf = true; + } + + if (path == 0) { + next.canBeFill = true; + } + + current.set(isSet, next); + } + else { + if (next.isLeaf) { + throw new IOException("node is leaf, no other following"); + } + } + + current = next; + } + } + + void fill(final int depth, final int path, final Node node) throws IOException { + Node current = root; + + for (int i = 0; i < depth; i++) { + int bitPos = depth - 1 - i; + boolean isSet = ((path >> bitPos) & 1) == 1; + Node next = current.walk(isSet); + + if (next == null) { + if (i == depth - 1) { + next = node; + } + else { + next = new Node(); + } + + if (path == 0) { + next.canBeFill = true; + } + + current.set(isSet, next); + } + else { + if (next.isLeaf) { + throw new IOException("node is leaf, no other following"); + } + } + + current = next; + } + } + } + + static final short[][] BLACK_CODES = { + { // 2 bits + 0x2, 0x3, + }, + { // 3 bits + 0x2, 0x3, + }, + { // 4 bits + 0x2, 0x3, + }, + { // 5 bits + 0x3, + }, + { // 6 bits + 0x4, 0x5, + }, + { // 7 bits + 0x4, 0x5, 0x7, + }, + { // 8 bits + 0x4, 0x7, + }, + { // 9 bits + 0x18, + }, + { // 10 bits + 0x17, 0x18, 0x37, 0x8, 0xf, + }, + { // 11 bits + 0x17, 0x18, 0x28, 0x37, 0x67, 0x68, 0x6c, 0x8, 0xc, 0xd, + }, + { // 12 bits + 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x1c, 0x1d, 0x1e, 0x1f, 0x24, 0x27, 0x28, 0x2b, 0x2c, 0x33, + 0x34, 0x35, 0x37, 0x38, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x64, 0x65, + 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xd2, 0xd3, + 0xd4, 0xd5, 0xd6, 0xd7, 0xda, 0xdb, + }, + { // 13 bits + 0x4a, 0x4b, 0x4c, 0x4d, 0x52, 0x53, 0x54, 0x55, 0x5a, 0x5b, 0x64, 0x65, 0x6c, 0x6d, 0x72, 0x73, + 0x74, 0x75, 0x76, 0x77, + } + }; + static final short[][] BLACK_RUN_LENGTHS = { + { // 2 bits + 3, 2, + }, + { // 3 bits + 1, 4, + }, + { // 4 bits + 6, 5, + }, + { // 5 bits + 7, + }, + { // 6 bits + 9, 8, + }, + { // 7 bits + 10, 11, 12, + }, + { // 8 bits + 13, 14, + }, + { // 9 bits + 15, + }, + { // 10 bits + 16, 17, 0, 18, 64, + }, + { // 11 bits + 24, 25, 23, 22, 19, 20, 21, 1792, 1856, 1920, + }, + { // 12 bits + 1984, 2048, 2112, 2176, 2240, 2304, 2368, 2432, 2496, 2560, 52, 55, 56, 59, 60, 320, 384, 448, 53, + 54, 50, 51, 44, 45, 46, 47, 57, 58, 61, 256, 48, 49, 62, 63, 30, 31, 32, 33, 40, 41, 128, 192, 26, + 27, 28, 29, 34, 35, 36, 37, 38, 39, 42, 43, + }, + { // 13 bits + 640, 704, 768, 832, 1280, 1344, 1408, 1472, 1536, 1600, 1664, 1728, 512, 576, 896, 960, 1024, 1088, + 1152, 1216, + } + }; + + public static final short[][] WHITE_CODES = { + { // 4 bits + 0x7, 0x8, 0xb, 0xc, 0xe, 0xf, + }, + { // 5 bits + 0x12, 0x13, 0x14, 0x1b, 0x7, 0x8, + }, + { // 6 bits + 0x17, 0x18, 0x2a, 0x2b, 0x3, 0x34, 0x35, 0x7, 0x8, + }, + { // 7 bits + 0x13, 0x17, 0x18, 0x24, 0x27, 0x28, 0x2b, 0x3, 0x37, 0x4, 0x8, 0xc, + }, + { // 8 bits + 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x1a, 0x1b, 0x2, 0x24, 0x25, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, + 0x3, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x4, 0x4a, 0x4b, 0x5, 0x52, 0x53, 0x54, 0x55, 0x58, 0x59, + 0x5a, 0x5b, 0x64, 0x65, 0x67, 0x68, 0xa, 0xb, + }, + { // 9 bits + 0x98, 0x99, 0x9a, 0x9b, 0xcc, 0xcd, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, + }, + { // 10 bits + }, + { // 11 bits + 0x8, 0xc, 0xd, + }, + { // 12 bits + 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x1c, 0x1d, 0x1e, 0x1f, + } + }; + + public static final short[][] WHITE_RUN_LENGTHS = { + { // 4 bits + 2, 3, 4, 5, 6, 7, + }, + { // 5 bits + 128, 8, 9, 64, 10, 11, + }, + { // 6 bits + 192, 1664, 16, 17, 13, 14, 15, 1, 12, + }, + { // 7 bits + 26, 21, 28, 27, 18, 24, 25, 22, 256, 23, 20, 19, + }, + { // 8 bits + 33, 34, 35, 36, 37, 38, 31, 32, 29, 53, 54, 39, 40, 41, 42, 43, 44, 30, 61, 62, 63, 0, 320, 384, 45, + 59, 60, 46, 49, 50, 51, 52, 55, 56, 57, 58, 448, 512, 640, 576, 47, 48, + }, + { // 9 bits + 1472, 1536, 1600, 1728, 704, 768, 832, 896, 960, 1024, 1088, 1152, 1216, 1280, 1344, 1408, + }, + { // 10 bits + }, + { // 11 bits + 1792, 1856, 1920, + }, + { // 12 bits + 1984, 2048, 2112, 2176, 2240, 2304, 2368, 2432, 2496, 2560, + } + }; + + final static Node EOL; + final static Node FILL; + final static Tree blackRunTree; + final static Tree whiteRunTree; + final static Tree eolOnlyTree; + final static Tree codeTree; + + final static int VALUE_EOL = -2000; + final static int VALUE_FILL = -1000; + final static int VALUE_PASSMODE = -3000; + final static int VALUE_HMODE = -4000; + + static { + EOL = new Node(); + EOL.isLeaf = true; + EOL.value = VALUE_EOL; + FILL = new Node(); + FILL.value = VALUE_FILL; + FILL.left = FILL; + FILL.right = EOL; + + eolOnlyTree = new Tree(); + try { + eolOnlyTree.fill(12, 0, FILL); + eolOnlyTree.fill(12, 1, EOL); + } + catch (IOException e) { + throw new AssertionError(e); + } + + blackRunTree = new Tree(); + try { + for (int i = 0; i < BLACK_CODES.length; i++) { + for (int j = 0; j < BLACK_CODES[i].length; j++) { + blackRunTree.fill(i + 2, BLACK_CODES[i][j], BLACK_RUN_LENGTHS[i][j]); + } + } + blackRunTree.fill(12, 0, FILL); + blackRunTree.fill(12, 1, EOL); + } + catch (IOException e) { + throw new AssertionError(e); + } + + whiteRunTree = new Tree(); + try { + for (int i = 0; i < WHITE_CODES.length; i++) { + for (int j = 0; j < WHITE_CODES[i].length; j++) { + whiteRunTree.fill(i + 4, WHITE_CODES[i][j], WHITE_RUN_LENGTHS[i][j]); + } + } + + whiteRunTree.fill(12, 0, FILL); + whiteRunTree.fill(12, 1, EOL); + } + catch (IOException e) { + throw new AssertionError(e); + } + + codeTree = new Tree(); + try { + codeTree.fill(4, 1, VALUE_PASSMODE); // pass mode + codeTree.fill(3, 1, VALUE_HMODE); // H mode + codeTree.fill(1, 1, 0); // V(0) + codeTree.fill(3, 3, 1); // V_R(1) + codeTree.fill(6, 3, 2); // V_R(2) + codeTree.fill(7, 3, 3); // V_R(3) + codeTree.fill(3, 2, -1); // V_L(1) + codeTree.fill(6, 2, -2); // V_L(2) + codeTree.fill(7, 2, -3); // V_L(3) + } + catch (IOException e) { + throw new AssertionError(e); + } + } +} + diff --git a/pdfbox/src/main/java/org/apache/pdfbox/filter/CCITTFaxFilter.java b/pdfbox/src/main/java/org/apache/pdfbox/filter/CCITTFaxFilter.java index 72b859c7e2d..4ca7e122d44 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/filter/CCITTFaxFilter.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/filter/CCITTFaxFilter.java @@ -21,10 +21,6 @@ import java.io.OutputStream; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; -import org.apache.pdfbox.filter.ccitt.CCITTFaxG31DDecodeInputStream; -import org.apache.pdfbox.filter.ccitt.FillOrderChangeInputStream; -import org.apache.pdfbox.filter.ccitt.TIFFFaxDecoder; -import org.apache.pdfbox.io.IOUtils; /** * Decodes image data that has been encoded using either Group 3 or Group 4 @@ -66,30 +62,32 @@ public DecodeResult decode(InputStream encoded, OutputStream decoded, boolean encodedByteAlign = decodeParms.getBoolean(COSName.ENCODED_BYTE_ALIGN, false); int arraySize = (cols + 7) / 8 * rows; // TODO possible options?? - long tiffOptions = 0; - byte[] decompressed; + byte[] decompressed = new byte[arraySize]; + CCITTFaxDecoderStream s; + int type; + long tiffOptions; if (k == 0) { - InputStream in = new CCITTFaxG31DDecodeInputStream(encoded, cols, rows, encodedByteAlign); - in = new FillOrderChangeInputStream(in); - decompressed = IOUtils.toByteArray(in); - in.close(); + tiffOptions = encodedByteAlign ? TIFFExtension.GROUP3OPT_BYTEALIGNED : 0; + type = TIFFExtension.COMPRESSION_CCITT_MODIFIED_HUFFMAN_RLE; } else { - TIFFFaxDecoder faxDecoder = new TIFFFaxDecoder(1, cols, rows); - byte[] compressed = IOUtils.toByteArray(encoded); - decompressed = new byte[arraySize]; if (k > 0) { - faxDecoder.decode2D(decompressed, compressed, 0, rows, tiffOptions); + tiffOptions = encodedByteAlign ? TIFFExtension.GROUP3OPT_BYTEALIGNED : 0; + tiffOptions |= TIFFExtension.GROUP3OPT_2DENCODING; + type = TIFFExtension.COMPRESSION_CCITT_T4; } else { // k < 0 - faxDecoder.decodeT6(decompressed, compressed, 0, rows, tiffOptions, encodedByteAlign); + tiffOptions = encodedByteAlign ? TIFFExtension.GROUP4OPT_BYTEALIGNED : 0; + type = TIFFExtension.COMPRESSION_CCITT_T6; } } + s = new CCITTFaxDecoderStream(encoded, cols, type, TIFFExtension.FILL_LEFT_TO_RIGHT, tiffOptions); + readFromDecoderStream(s, decompressed); // invert bitmap boolean blackIsOne = decodeParms.getBoolean(COSName.BLACK_IS_1, false); @@ -112,6 +110,22 @@ public DecodeResult decode(InputStream encoded, OutputStream decoded, return new DecodeResult(parameters); } + public void readFromDecoderStream(CCITTFaxDecoderStream decoderStream, byte[] result) + throws IOException + { + int pos = 0; + int read; + while ((read = decoderStream.read(result, pos, result.length - pos)) > -1) + { + pos += read; + if (pos >= result.length) + { + break; + } + } + decoderStream.close(); + } + private void invertBitmap(byte[] bufferData) { for (int i = 0, c = bufferData.length; i < c; i++) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/filter/TIFFExtension.java b/pdfbox/src/main/java/org/apache/pdfbox/filter/TIFFExtension.java new file mode 100644 index 00000000000..392f43feb06 --- /dev/null +++ b/pdfbox/src/main/java/org/apache/pdfbox/filter/TIFFExtension.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2012, Harald Kuhr + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name "TwelveMonkeys" nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.apache.pdfbox.filter; + +/** + * TIFFExtension + * + * @author Harald Kuhr + * @author last modified by $Author: haraldk$ + * @version $Id: TIFFExtension.java,v 1.0 08.05.12 16:45 haraldk Exp$ + */ +interface TIFFExtension { + /** CCITT T.4/Group 3 Fax compression. */ + int COMPRESSION_CCITT_T4 = 3; + /** CCITT T.6/Group 4 Fax compression. */ + int COMPRESSION_CCITT_T6 = 4; + /** LZW Compression. Was baseline, but moved to extension due to license issues in the LZW algorithm. */ + int COMPRESSION_LZW = 5; + /** Deprecated. For backwards compatibility only ("Old-style" JPEG). */ + int COMPRESSION_OLD_JPEG = 6; + /** JPEG Compression (lossy). */ + int COMPRESSION_JPEG = 7; + /** Custom: PKZIP-style Deflate. */ + int COMPRESSION_DEFLATE = 32946; + /** Adobe-style Deflate. */ + int COMPRESSION_ZLIB = 8; + + int PHOTOMETRIC_SEPARATED = 5; + int PHOTOMETRIC_YCBCR = 6; + int PHOTOMETRIC_CIELAB = 8; + int PHOTOMETRIC_ICCLAB = 9; + int PHOTOMETRIC_ITULAB = 10; + + int PLANARCONFIG_PLANAR = 2; + + int PREDICTOR_HORIZONTAL_DIFFERENCING = 2; + int PREDICTOR_HORIZONTAL_FLOATINGPOINT = 3; + + int FILL_RIGHT_TO_LEFT = 2; + + int SAMPLEFORMAT_INT = 2; + int SAMPLEFORMAT_FP = 3; + int SAMPLEFORMAT_UNDEFINED = 4; + + int YCBCR_POSITIONING_CENTERED = 1; + int YCBCR_POSITIONING_COSITED = 2; + + /** Deprecated. For backwards compatibility only ("Old-style" JPEG). */ + int JPEG_PROC_BASELINE = 1; + /** Deprecated. For backwards compatibility only ("Old-style" JPEG). */ + int JPEG_PROC_LOSSLESS = 14; + + /** For use with Photometric: 5 (Separated), when image data is in CMYK color space. */ + int INKSET_CMYK = 1; + + /** + * For use with Photometric: 5 (Separated), when image data is in a color space other than CMYK. + * See {@link com.twelvemonkeys.imageio.metadata.exif.TIFF#TAG_INK_NAMES InkNames} field for a + * description of the inks to be used. + */ + int INKSET_NOT_CMYK = 2; + + int ORIENTATION_TOPRIGHT = 2; + int ORIENTATION_BOTRIGHT = 3; + int ORIENTATION_BOTLEFT = 4; + int ORIENTATION_LEFTTOP = 5; + int ORIENTATION_RIGHTTOP = 6; + int ORIENTATION_RIGHTBOT = 7; + int ORIENTATION_LEFTBOT = 8; + + int GROUP3OPT_2DENCODING = 1; + int GROUP3OPT_UNCOMPRESSED = 2; + int GROUP3OPT_FILLBITS = 4; + int GROUP3OPT_BYTEALIGNED = 8; + int GROUP4OPT_UNCOMPRESSED = 2; + int GROUP4OPT_BYTEALIGNED = 4; + int COMPRESSION_CCITT_MODIFIED_HUFFMAN_RLE = 2; + int FILL_LEFT_TO_RIGHT = 1; // Default +} + From 83c51fce9eee5c53446b2c56a67e1496095802e8 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Mon, 30 May 2016 19:39:47 +0000 Subject: [PATCH 0096/2182] PDFBOX-3338: add notice git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1746173 13f79535-47bb-0310-9956-ffa450edef68 --- pdfbox/src/main/appended-resources/META-INF/NOTICE | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pdfbox/src/main/appended-resources/META-INF/NOTICE b/pdfbox/src/main/appended-resources/META-INF/NOTICE index 2b3c8359d5f..d37168726be 100644 --- a/pdfbox/src/main/appended-resources/META-INF/NOTICE +++ b/pdfbox/src/main/appended-resources/META-INF/NOTICE @@ -9,3 +9,6 @@ Copyright 2002, 2010 Adobe Systems Incorporated. Includes the Bidi Mirroring Glyph Property (BidiMirroring-8.0.0.txt) Copyright 1991-2015 Unicode, Inc. + +Includes parts of TwelveMonkeys ImageIO +Copyright 2008-2016 Harald Kuhr From 7e70d990372eae3b0b897e4384be2749bcf87846 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Mon, 30 May 2016 19:40:01 +0000 Subject: [PATCH 0097/2182] PDFBOX-3338: add license git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1746174 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/appended-resources/META-INF/LICENSE | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/pdfbox/src/main/appended-resources/META-INF/LICENSE b/pdfbox/src/main/appended-resources/META-INF/LICENSE index 6558877ba46..98976a71ac1 100644 --- a/pdfbox/src/main/appended-resources/META-INF/LICENSE +++ b/pdfbox/src/main/appended-resources/META-INF/LICENSE @@ -207,3 +207,33 @@ Liberation Fonts (https://fedorahosted.org/liberation-fonts) FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. +Twelvemonkeys (https://github.com/haraldk/TwelveMonkeys/) + + Copyright (c) 2008-2016, Harald Kuhr + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + o Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + o Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + o Neither the name "TwelveMonkeys" nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file From 4b54785c33b1b638161cb03a7465303cd65fa247 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Mon, 30 May 2016 19:42:53 +0000 Subject: [PATCH 0098/2182] PDFBOX-3338: add notice git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1746176 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/appended-resources/META-INF/NOTICE | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/debugger-app/src/main/appended-resources/META-INF/NOTICE b/debugger-app/src/main/appended-resources/META-INF/NOTICE index e8fea2ebf58..a0f9eac0893 100644 --- a/debugger-app/src/main/appended-resources/META-INF/NOTICE +++ b/debugger-app/src/main/appended-resources/META-INF/NOTICE @@ -1,2 +1,14 @@ Based on source code originally developed in the PDFBox and FontBox projects. Copyright (c) 2002-2007, www.pdfbox.org + +Includes the Adobe Glyph List +Copyright 1997, 1998, 2002, 2007, 2010 Adobe Systems Incorporated. + +Includes the Zapf Dingbats Glyph List +Copyright 2002, 2010 Adobe Systems Incorporated. + +Includes the Bidi Mirroring Glyph Property (BidiMirroring-8.0.0.txt) +Copyright 1991-2015 Unicode, Inc. + +Includes parts of TwelveMonkeys ImageIO +Copyright 2008-2016 Harald Kuhr From c0c166e1b765071eb62176ea248a7fea38eea0c9 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Mon, 30 May 2016 19:43:01 +0000 Subject: [PATCH 0099/2182] PDFBOX-3338: add notice git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1746178 13f79535-47bb-0310-9956-ffa450edef68 --- app/src/main/appended-resources/META-INF/NOTICE | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/app/src/main/appended-resources/META-INF/NOTICE b/app/src/main/appended-resources/META-INF/NOTICE index e8fea2ebf58..a0f9eac0893 100644 --- a/app/src/main/appended-resources/META-INF/NOTICE +++ b/app/src/main/appended-resources/META-INF/NOTICE @@ -1,2 +1,14 @@ Based on source code originally developed in the PDFBox and FontBox projects. Copyright (c) 2002-2007, www.pdfbox.org + +Includes the Adobe Glyph List +Copyright 1997, 1998, 2002, 2007, 2010 Adobe Systems Incorporated. + +Includes the Zapf Dingbats Glyph List +Copyright 2002, 2010 Adobe Systems Incorporated. + +Includes the Bidi Mirroring Glyph Property (BidiMirroring-8.0.0.txt) +Copyright 1991-2015 Unicode, Inc. + +Includes parts of TwelveMonkeys ImageIO +Copyright 2008-2016 Harald Kuhr From d593278392318a1f8a0f86ab0d53af368ced56ac Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Mon, 30 May 2016 19:43:45 +0000 Subject: [PATCH 0100/2182] PDFBOX-3338: add license git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1746179 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/appended-resources/META-INF/LICENSE | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/app/src/main/appended-resources/META-INF/LICENSE b/app/src/main/appended-resources/META-INF/LICENSE index 57237248ea1..f581b421846 100644 --- a/app/src/main/appended-resources/META-INF/LICENSE +++ b/app/src/main/appended-resources/META-INF/LICENSE @@ -134,3 +134,33 @@ Glyphlist (http://www.adobe.com/devnet/opentype/archives/glyph.html) non-infringement of any third party rights regarding the Adobe materials. +Twelvemonkeys (https://github.com/haraldk/TwelveMonkeys/) + + Copyright (c) 2008-2016, Harald Kuhr + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + o Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + o Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + o Neither the name "TwelveMonkeys" nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file From c8359ff7689afaab7d5995f61ce210276fe58942 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Mon, 30 May 2016 19:43:51 +0000 Subject: [PATCH 0101/2182] PDFBOX-3338: add license git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1746180 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/appended-resources/META-INF/LICENSE | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/debugger-app/src/main/appended-resources/META-INF/LICENSE b/debugger-app/src/main/appended-resources/META-INF/LICENSE index 57237248ea1..f581b421846 100644 --- a/debugger-app/src/main/appended-resources/META-INF/LICENSE +++ b/debugger-app/src/main/appended-resources/META-INF/LICENSE @@ -134,3 +134,33 @@ Glyphlist (http://www.adobe.com/devnet/opentype/archives/glyph.html) non-infringement of any third party rights regarding the Adobe materials. +Twelvemonkeys (https://github.com/haraldk/TwelveMonkeys/) + + Copyright (c) 2008-2016, Harald Kuhr + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + o Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + o Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + o Neither the name "TwelveMonkeys" nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file From e8bab65f6d6f711b1be95fa430cc9a59b6ac5fb7 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Mon, 30 May 2016 20:41:04 +0000 Subject: [PATCH 0102/2182] PDFBOX-3338: remove ccitt folder git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1746203 13f79535-47bb-0310-9956-ffa450edef68 --- .../filter/ccitt/CCITTFaxConstants.java | 81 - .../ccitt/CCITTFaxG31DDecodeInputStream.java | 466 ----- .../ccitt/FillOrderChangeInputStream.java | 108 -- .../pdfbox/filter/ccitt/PackedBitArray.java | 257 --- .../pdfbox/filter/ccitt/TIFFFaxDecoder.java | 1599 ----------------- .../apache/pdfbox/filter/ccitt/package.html | 26 - .../ccitt/AbstractCCITTFaxTestCase.java | 67 - .../TestCCITTFaxG31DDecodeInputStream.java | 195 -- .../filter/ccitt/TestPackedBitArray.java | 81 - .../apache/pdfbox/filter/ccitt/package.html | 25 - 10 files changed, 2905 deletions(-) delete mode 100644 pdfbox/src/main/java/org/apache/pdfbox/filter/ccitt/CCITTFaxConstants.java delete mode 100644 pdfbox/src/main/java/org/apache/pdfbox/filter/ccitt/CCITTFaxG31DDecodeInputStream.java delete mode 100644 pdfbox/src/main/java/org/apache/pdfbox/filter/ccitt/FillOrderChangeInputStream.java delete mode 100644 pdfbox/src/main/java/org/apache/pdfbox/filter/ccitt/PackedBitArray.java delete mode 100644 pdfbox/src/main/java/org/apache/pdfbox/filter/ccitt/TIFFFaxDecoder.java delete mode 100644 pdfbox/src/main/java/org/apache/pdfbox/filter/ccitt/package.html delete mode 100644 pdfbox/src/test/java/org/apache/pdfbox/filter/ccitt/AbstractCCITTFaxTestCase.java delete mode 100644 pdfbox/src/test/java/org/apache/pdfbox/filter/ccitt/TestCCITTFaxG31DDecodeInputStream.java delete mode 100644 pdfbox/src/test/java/org/apache/pdfbox/filter/ccitt/TestPackedBitArray.java delete mode 100644 pdfbox/src/test/java/org/apache/pdfbox/filter/ccitt/package.html diff --git a/pdfbox/src/main/java/org/apache/pdfbox/filter/ccitt/CCITTFaxConstants.java b/pdfbox/src/main/java/org/apache/pdfbox/filter/ccitt/CCITTFaxConstants.java deleted file mode 100644 index 0ce02b2d45c..00000000000 --- a/pdfbox/src/main/java/org/apache/pdfbox/filter/ccitt/CCITTFaxConstants.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* $Id$ */ - -package org.apache.pdfbox.filter.ccitt; - -/** - * Constants for CCITT Fax Filter. - */ -final class CCITTFaxConstants -{ - /** A constant for group 3 1D encoding (ITU T.4). */ - final int COMPRESSION_GROUP3_1D = 0; - - /** A constant for group 3 2D encoding (ITU T.4). */ - final int COMPRESSION_GROUP3_2D = 1; - - /** A constant for group 4 2D encoding (ITU T.6). */ - final int COMPRESSION_GROUP4_2D = 2; - - //Format: First 8 bits: length of pattern, Second 8 bits: pattern - - /** The white terminating code words. */ - public static final short[] WHITE_TERMINATING = new short[] { - 0x0835, 0x0607, 0x0407, 0x0408, 0x040B, 0x040C, 0x040E, 0x040F, - 0x0513, 0x0514, 0x0507, 0x0508, 0x0608, 0x0603, 0x0634, 0x0635, - 0x062A, 0x062B, 0x0727, 0x070C, 0x0708, 0x0717, 0x0703, 0x0704, - 0x0728, 0x072B, 0x0713, 0x0724, 0x0718, 0x0802, 0x0803, 0x081A, - 0x081B, 0x0812, 0x0813, 0x0814, 0x0815, 0x0816, 0x0817, 0x0828, - 0x0829, 0x082A, 0x082B, 0x082C, 0x082D, 0x0804, 0x0805, 0x080A, - 0x080B, 0x0852, 0x0853, 0x0854, 0x0855, 0x0824, 0x0825, 0x0858, - 0x0859, 0x085A, 0x085B, 0x084A, 0x084B, 0x0832, 0x0833, 0x0834}; - - /** The black terminating code words. */ - public static final short[] BLACK_TERMINATING = new short[] { - 0x0A37, 0x0302, 0x0203, 0x0202, 0x0303, 0x0403, 0x0402, 0x0503, - 0x0605, 0x0604, 0x0704, 0x0705, 0x0707, 0x0804, 0x0807, 0x0918, - 0x0A17, 0x0A18, 0x0A08, 0x0B67, 0x0B68, 0x0B6C, 0x0B37, 0x0B28, - 0x0B17, 0x0B18, 0x0CCA, 0x0CCB, 0x0CCC, 0x0CCD, 0x0C68, 0x0C69, - 0x0C6A, 0x0C6B, 0x0CD2, 0x0CD3, 0x0CD4, 0x0CD5, 0x0CD6, 0x0CD7, - 0x0C6C, 0x0C6D, 0x0CDA, 0x0CDB, 0x0C54, 0x0C55, 0x0C56, 0x0C57, - 0x0C64, 0x0C65, 0x0C52, 0x0C53, 0x0C24, 0x0C37, 0x0C38, 0x0C27, - 0x0C28, 0x0C58, 0x0C59, 0x0C2B, 0x0C2C, 0x0C5A, 0x0C66, 0x0C67}; - - /** The white make-up code words. */ - public static final short[] WHITE_MAKE_UP = new short[] { - 0x051B, 0x0512, 0x0617, 0x0737, 0x0836, 0x0837, 0x0864, 0x0865, - 0x0868, 0x0867, 0x09CC, 0x09CD, 0x09D2, 0x09D3, 0x09D4, 0x09D5, - 0x09D6, 0x09D7, 0x09D8, 0x09D9, 0x09DA, 0x09DB, 0x0998, 0x0999, - 0x099A, 0x0618, 0x099B}; - - /** The black make-up code words. */ - public static final short[] BLACK_MAKE_UP = new short[] { - 0x0A0F, 0x0CC8, 0x0CC9, 0x0C5B, 0x0C33, 0x0C34, 0x0C35, 0x0D6C, - 0x0D6D, 0x0D4A, 0x0D4B, 0x0D4C, 0x0D4D, 0x0D72, 0x0D73, 0x0D74, - 0x0D75, 0x0D76, 0x0D77, 0x0D52, 0x0D53, 0x0D54, 0x0D55, 0x0D5A, - 0x0D5B, 0x0D64, 0x0D65}; - - /** The long make-up code words. */ - public static final short[] LONG_MAKE_UP = new short[] { - 0x0B08, 0x0B0C, 0x0B0D, 0x0C12, 0x0C13, 0x0C14, 0x0C15, 0x0C16, - 0x0C17, 0x0C1C, 0x0C1D, 0x0C1E, 0x0C1F}; - - /** The EOL code word. */ - public static final short EOL_CODE = 0x0C01; -} diff --git a/pdfbox/src/main/java/org/apache/pdfbox/filter/ccitt/CCITTFaxG31DDecodeInputStream.java b/pdfbox/src/main/java/org/apache/pdfbox/filter/ccitt/CCITTFaxG31DDecodeInputStream.java deleted file mode 100644 index 5b8f3202544..00000000000 --- a/pdfbox/src/main/java/org/apache/pdfbox/filter/ccitt/CCITTFaxG31DDecodeInputStream.java +++ /dev/null @@ -1,466 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* $Id$ */ - -package org.apache.pdfbox.filter.ccitt; - -import java.io.IOException; -import java.io.InputStream; - -/** - * This is a CCITT Group 3 1D decoder (ITU T.4). - */ -public final class CCITTFaxG31DDecodeInputStream extends InputStream -{ - private static final int CODE_WORD = 0; - private static final int SIGNAL_EOD = -1; - private static final int SIGNAL_EOL = -2; - - private InputStream source; - private int columns; - private int rows; - private boolean encodedByteAlign; - - //for reading compressed bits - private int bits; - private int bitPos = 8; - - //a single decoded line (one line decoded at a time, then read byte by byte) - private PackedBitArray decodedLine; - private int decodedWritePos; //write position in bits (used by the decoder algorithm) - private int decodedReadPos; //read position in bytes (used by the actual InputStream reading) - - //state - private int y = -1; //Current row/line - private int accumulatedRunLength; //Used for make-up codes - - private static final NonLeafLookupTreeNode WHITE_LOOKUP_TREE_ROOT; - private static final NonLeafLookupTreeNode BLACK_LOOKUP_TREE_ROOT; - - static { - WHITE_LOOKUP_TREE_ROOT = new NonLeafLookupTreeNode(); - BLACK_LOOKUP_TREE_ROOT = new NonLeafLookupTreeNode(); - buildLookupTree(); - } - - /** - * Creates a new decoder. - * - * @param source the input stream containing the compressed data. - * @param columns the number of columns - * @param rows the number of rows (0 if undefined) - * @param encodedByteAlign true if each encoded scan line is filled - * to a byte boundary, false if not - */ - public CCITTFaxG31DDecodeInputStream(InputStream source, int columns, int rows, boolean encodedByteAlign) - { - this.source = source; - this.columns = columns; - this.rows = rows; - this.decodedLine = new PackedBitArray(columns); - this.decodedReadPos = this.decodedLine.getByteCount(); - this.encodedByteAlign = encodedByteAlign; - } - - /** - * Creates a new decoder. - * - * @param source the input stream containing the compressed data. - * @param columns the number of columns - * @param encodedByteAlign true if each encoded scan line is filled - * to a byte boundary, false if not - */ - public CCITTFaxG31DDecodeInputStream(InputStream source, int columns, boolean encodedByteAlign) - { - this(source, columns, 0, encodedByteAlign); - } - - /** {@inheritDoc} */ - public boolean markSupported() - { - return false; - } - - /** {@inheritDoc} */ - public int read() throws IOException - { - if (this.decodedReadPos >= this.decodedLine.getByteCount()) - { - boolean hasLine = decodeLine(); - if (!hasLine) - { - return -1; - } - } - byte data = this.decodedLine.getData()[this.decodedReadPos++]; - - return data & 0xFF; - } - - //TODO Implement the other two read methods - - private boolean decodeLine() throws IOException - { - if (encodedByteAlign && this.bitPos != 0) - { - readByte(); - } - if (this.bits < 0) - { - //Shortcut after EOD - return false; - } - this.y++; - int x = 0; - if (this.rows > 0 && this.y >= this.rows) - { - //All rows decoded, ignore further bits - return false; - } - this.decodedLine.clear(); - this.decodedWritePos = 0; - int expectRTC = 6; - boolean white = true; - while (x < this.columns || this.accumulatedRunLength > 0) - { - CodeWord code; - LookupTreeNode root = white ? WHITE_LOOKUP_TREE_ROOT : BLACK_LOOKUP_TREE_ROOT; - code = root.getNextCodeWord(this); - if (code == null) - { - //no more code words (EOD) - if (x > 0) - { - //Have last line - this.decodedReadPos = 0; - return true; - } - else - { - return false; - } - } - else if (code.getType() == SIGNAL_EOL) - { - expectRTC--; - if (expectRTC == 0) - { - //Return to Control = End Of Data - return false; - } - if (x == 0) - { - //Ignore leading EOL - continue; - } - } - else - { - expectRTC = -1; - x += code.execute(this); - if (this.accumulatedRunLength == 0) - { - //Only switch if not using make-up codes - white = !white; - } - } - } - this.decodedReadPos = 0; - return true; - } - - private void writeRun(int bit, int length) - { - this.accumulatedRunLength += length; - - if (bit != 0) - { - this.decodedLine.setBits(this.decodedWritePos, this.accumulatedRunLength); - } - this.decodedWritePos += this.accumulatedRunLength; - this.accumulatedRunLength = 0; - } - - private void writeNonTerminating(int length) - { - this.accumulatedRunLength += length; - } - - private static final int[] BIT_POS_MASKS - = new int[] {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01}; - - private int readBit() throws IOException - { - if (this.bitPos >= 8) - { - readByte(); - if (this.bits < 0) - { - return SIGNAL_EOD; - } - } - return (this.bits & BIT_POS_MASKS[this.bitPos++]) == 0 ? 0 : 1; - } - - private void readByte() throws IOException - { - this.bits = this.source.read(); - this.bitPos = 0; - } - - private static final short EOL_STARTER = 0x0B00; - - private static void buildLookupTree() - { - buildUpTerminating(CCITTFaxConstants.WHITE_TERMINATING, WHITE_LOOKUP_TREE_ROOT, true); - buildUpTerminating(CCITTFaxConstants.BLACK_TERMINATING, BLACK_LOOKUP_TREE_ROOT, false); - buildUpMakeUp(CCITTFaxConstants.WHITE_MAKE_UP, WHITE_LOOKUP_TREE_ROOT); - buildUpMakeUp(CCITTFaxConstants.BLACK_MAKE_UP, BLACK_LOOKUP_TREE_ROOT); - buildUpMakeUpLong(CCITTFaxConstants.LONG_MAKE_UP, WHITE_LOOKUP_TREE_ROOT); - buildUpMakeUpLong(CCITTFaxConstants.LONG_MAKE_UP, BLACK_LOOKUP_TREE_ROOT); - LookupTreeNode eolNode = new EndOfLineTreeNode(); - addLookupTreeNode(EOL_STARTER, WHITE_LOOKUP_TREE_ROOT, eolNode); - addLookupTreeNode(EOL_STARTER, BLACK_LOOKUP_TREE_ROOT, eolNode); - } - - private static void buildUpTerminating(short[] codes, NonLeafLookupTreeNode root, boolean white) - { - for (int len = 0, c = codes.length; len < c; len++) - { - LookupTreeNode leaf = new RunLengthTreeNode(white ? 0 : 1, len); - addLookupTreeNode(codes[len], root, leaf); - } - } - - private static void buildUpMakeUp(short[] codes, NonLeafLookupTreeNode root) - { - for (int len = 0, c = codes.length; len < c; len++) - { - LookupTreeNode leaf = new MakeUpTreeNode((len + 1) * 64); - addLookupTreeNode(codes[len], root, leaf); - } - } - - private static void buildUpMakeUpLong(short[] codes, NonLeafLookupTreeNode root) - { - for (int len = 0, c = codes.length; len < c; len++) - { - LookupTreeNode leaf = new MakeUpTreeNode((len + 28) * 64); - addLookupTreeNode(codes[len], root, leaf); - } - } - - private static void addLookupTreeNode(short code, NonLeafLookupTreeNode root, - LookupTreeNode leaf) - { - int codeLength = code >> 8; - int pattern = code & 0xFF; - NonLeafLookupTreeNode node = root; - for (int p = codeLength - 1; p > 0; p--) - { - int bit = (pattern >> p) & 0x01; - LookupTreeNode child = node.get(bit); - if (child == null) - { - child = new NonLeafLookupTreeNode(); - node.set(bit, child); - } - if (child instanceof NonLeafLookupTreeNode) - { - node = (NonLeafLookupTreeNode)child; - } - else - { - throw new IllegalStateException("NonLeafLookupTreeNode expected, was " - + child.getClass().getName()); - } - } - int bit = pattern & 0x01; - if (node.get(bit) != null) - { - throw new IllegalStateException("Two codes conflicting in lookup tree"); - } - node.set(bit, leaf); - } - - /** Base class for all nodes in the lookup tree for code words. */ - private abstract static class LookupTreeNode - { - - public abstract CodeWord getNextCodeWord(CCITTFaxG31DDecodeInputStream decoder) - throws IOException; - - } - - /** Interface for code words. */ - private interface CodeWord - { - int getType(); - int execute(CCITTFaxG31DDecodeInputStream decoder) throws IOException; - } - - /** Non-leaf nodes that hold a child node for both the 0 and 1 cases for the lookup tree. */ - private static class NonLeafLookupTreeNode extends LookupTreeNode - { - - private LookupTreeNode zero; - private LookupTreeNode one; - - public void set(int bit, LookupTreeNode node) - { - if (bit == 0) - { - this.zero = node; - } - else - { - this.one = node; - } - } - - public LookupTreeNode get(int bit) - { - return (bit == 0) ? this.zero : this.one; - } - - public CodeWord getNextCodeWord(CCITTFaxG31DDecodeInputStream decoder) - throws IOException - { - int bit = decoder.readBit(); - if (bit < 0) - { - return null; - } - LookupTreeNode node = get(bit); - if (node != null) - { - return node.getNextCodeWord(decoder); - } - throw new IOException("Invalid code word encountered"); - } - - } - - /** This node represents a run length of either 0 or 1. */ - private static class RunLengthTreeNode extends LookupTreeNode implements CodeWord - { - - private final int bit; - private final int length; - - RunLengthTreeNode(int bit, int length) - { - this.bit = bit; - this.length = length; - } - - public CodeWord getNextCodeWord(CCITTFaxG31DDecodeInputStream decoder) throws IOException - { - return this; - } - - public int execute(CCITTFaxG31DDecodeInputStream decoder) - { - decoder.writeRun(this.bit, this.length); - return length; - } - - public int getType() - { - return CODE_WORD; - } - - public String toString() - { - return "Run Length for " + length + " bits of " + (bit == 0 ? "white" : "black"); - } - - } - - /** Represents a make-up code word. */ - private static class MakeUpTreeNode extends LookupTreeNode implements CodeWord - { - - private final int length; - - MakeUpTreeNode(int length) - { - this.length = length; - } - - public CodeWord getNextCodeWord(CCITTFaxG31DDecodeInputStream decoder) throws IOException - { - return this; - } - - public int execute(CCITTFaxG31DDecodeInputStream decoder) throws IOException - { - decoder.writeNonTerminating(length); - return length; - } - - public int getType() - { - return CODE_WORD; - } - - public String toString() - { - return "Make up code for length " + length; - } - - } - - /** Represents an EOL code word. */ - private static class EndOfLineTreeNode extends LookupTreeNode implements CodeWord - { - - public CodeWord getNextCodeWord(CCITTFaxG31DDecodeInputStream decoder) throws IOException - { - int bit; - do - { - bit = decoder.readBit(); - //bit 1 finishes the EOL, any number of bit 0 allowed as fillers - } while (bit == 0); - if (bit < 0) - { - return null; - } - return this; - } - - public int execute(CCITTFaxG31DDecodeInputStream decoder) throws IOException - { - //nop - return 0; - } - - public int getType() - { - return SIGNAL_EOL; - } - - public String toString() - { - return "EOL"; - } - - } - -} \ No newline at end of file diff --git a/pdfbox/src/main/java/org/apache/pdfbox/filter/ccitt/FillOrderChangeInputStream.java b/pdfbox/src/main/java/org/apache/pdfbox/filter/ccitt/FillOrderChangeInputStream.java deleted file mode 100644 index 95f90aee747..00000000000 --- a/pdfbox/src/main/java/org/apache/pdfbox/filter/ccitt/FillOrderChangeInputStream.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* $Id$ */ - -package org.apache.pdfbox.filter.ccitt; - -import java.io.FilterInputStream; -import java.io.IOException; -import java.io.InputStream; - -/** - * This filtering input stream does a fill order change required for certain TIFF images. - */ -public final class FillOrderChangeInputStream extends FilterInputStream -{ - /** - * Main constructor. - * @param in the underlying input stream - */ - public FillOrderChangeInputStream(InputStream in) - { - super(in); - } - - /** {@inheritDoc} */ - @Override - public int read(byte[] b, int off, int len) throws IOException - { - int result = super.read(b, off, len); - if (result > 0) - { - int endpos = off + result; - for (int i = off; i < endpos; i++) - { - b[i] = FLIP_TABLE[b[i] & 0xff]; - } - } - return result; - } - - /** {@inheritDoc} */ - @Override - public int read() throws IOException - { - int b = super.read(); - if (b < 0) - { - return b; - } - else - { - return FLIP_TABLE[b] & 0xff; - } - } - - // Table to be used when fillOrder = 2, for flipping bytes. - // Copied from the TIFFFaxDecoder class - private static final byte[] FLIP_TABLE = { - 0, -128, 64, -64, 32, -96, 96, -32, - 16, -112, 80, -48, 48, -80, 112, -16, - 8, -120, 72, -56, 40, -88, 104, -24, - 24, -104, 88, -40, 56, -72, 120, -8, - 4, -124, 68, -60, 36, -92, 100, -28, - 20, -108, 84, -44, 52, -76, 116, -12, - 12, -116, 76, -52, 44, -84, 108, -20, - 28, -100, 92, -36, 60, -68, 124, -4, - 2, -126, 66, -62, 34, -94, 98, -30, - 18, -110, 82, -46, 50, -78, 114, -14, - 10, -118, 74, -54, 42, -86, 106, -22, - 26, -102, 90, -38, 58, -70, 122, -6, - 6, -122, 70, -58, 38, -90, 102, -26, - 22, -106, 86, -42, 54, -74, 118, -10, - 14, -114, 78, -50, 46, -82, 110, -18, - 30, -98, 94, -34, 62, -66, 126, -2, - 1, -127, 65, -63, 33, -95, 97, -31, - 17, -111, 81, -47, 49, -79, 113, -15, - 9, -119, 73, -55, 41, -87, 105, -23, - 25, -103, 89, -39, 57, -71, 121, -7, - 5, -123, 69, -59, 37, -91, 101, -27, - 21, -107, 85, -43, 53, -75, 117, -11, - 13, -115, 77, -51, 45, -83, 109, -19, - 29, -99, 93, -35, 61, -67, 125, -3, - 3, -125, 67, -61, 35, -93, 99, -29, - 19, -109, 83, -45, 51, -77, 115, -13, - 11, -117, 75, -53, 43, -85, 107, -21, - 27, -101, 91, -37, 59, -69, 123, -5, - 7, -121, 71, -57, 39, -89, 103, -25, - 23, -105, 87, -41, 55, -73, 119, -9, - 15, -113, 79, -49, 47, -81, 111, -17, - 31, -97, 95, -33, 63, -65, 127, -1, - }; - // end -} \ No newline at end of file diff --git a/pdfbox/src/main/java/org/apache/pdfbox/filter/ccitt/PackedBitArray.java b/pdfbox/src/main/java/org/apache/pdfbox/filter/ccitt/PackedBitArray.java deleted file mode 100644 index ec316556a06..00000000000 --- a/pdfbox/src/main/java/org/apache/pdfbox/filter/ccitt/PackedBitArray.java +++ /dev/null @@ -1,257 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* $Id$ */ - -package org.apache.pdfbox.filter.ccitt; - -/** - * Represents an array of bits packed in a byte array of fixed size. - */ -final class PackedBitArray -{ - private int bitCount; - private byte[] data; - - /** - * Constructs a new bit array. - * @param bitCount the number of bits to maintain - */ - PackedBitArray(int bitCount) - { - this.bitCount = bitCount; - int byteCount = (bitCount + 7) / 8; - this.data = new byte[byteCount]; - } - - private int byteOffset(int offset) - { - return offset / 8; - } - - private int bitOffset(int offset) - { - return offset % 8; - } - - /** - * Sets a bit at the given offset. - * @param offset the offset - */ - public void set(int offset) - { - int byteOffset = byteOffset(offset); - this.data[byteOffset] |= 1 << bitOffset(offset); - } - - /** - * Clears a bit at the given offset. - * @param offset the offset - */ - public void clear(int offset) - { - int byteOffset = byteOffset(offset); - int bitOffset = bitOffset(offset); - this.data[byteOffset] &= ~(1 << bitOffset); - } - - /** - * Sets a run of bits at the given offset to either 1 or 0. - * @param offset the offset - * @param length the number of bits to set - * @param bit 1 to set the bit, 0 to clear it - */ - public void setBits(int offset, int length, int bit) - { - if (bit == 0) - { - clearBits(offset, length); - } - else - { - setBits(offset, length); - } - } - - /** - * Sets a run of bits at the given offset to either 1. - * @param offset the offset - * @param length the number of bits to set - */ - public void setBits(int offset, int length) - { - if (length == 0) - { - return; - } - int startBitOffset = bitOffset(offset); - int firstByte = byteOffset(offset); - int lastBitOffset = offset + length; - if (lastBitOffset > getBitCount()) - { - throw new IndexOutOfBoundsException("offset + length > bit count"); - } - int lastByte = byteOffset(lastBitOffset); - int endBitOffset = bitOffset(lastBitOffset); - - if (firstByte == lastByte) - { - //Only one byte affected - int mask = (1 << endBitOffset) - (1 << startBitOffset); - this.data[firstByte] |= mask; - } - else - { - //Bits spanning multiple bytes - this.data[firstByte] |= 0xFF << startBitOffset; - for (int i = firstByte + 1; i < lastByte; i++) - { - this.data[i] = (byte)0xFF; - } - if (endBitOffset > 0) - { - this.data[lastByte] |= 0xFF >> (8 - endBitOffset); - } - } - } - - /** - * Clears a run of bits at the given offset. - * @param offset the offset - * @param length the number of bits to clear - */ - public void clearBits(int offset, int length) - { - if (length == 0) - { - return; - } - int startBitOffset = offset % 8; - int firstByte = byteOffset(offset); - int lastBitOffset = offset + length; - int lastByte = byteOffset(lastBitOffset); - int endBitOffset = lastBitOffset % 8; - - if (firstByte == lastByte) - { - //Only one byte affected - int mask = (1 << endBitOffset) - (1 << startBitOffset); - this.data[firstByte] &= ~mask; - } - else - { - //Bits spanning multiple bytes - this.data[firstByte] &= ~(0xFF << startBitOffset); - for (int i = firstByte + 1; i < lastByte; i++) - { - this.data[i] = 0x00; - } - if (endBitOffset > 0) - { - this.data[lastByte] &= ~(0xFF >> (8 - endBitOffset)); - } - } - } - - /** - * Clear all bits in the array. - */ - public void clear() - { - clearBits(0, getBitCount()); - } - - /** - * Returns the number of bits maintained by this array. - * @return the number of bits - */ - public int getBitCount() - { - return this.bitCount; - } - - /** - * Returns the size of the byte buffer for this array. - * @return the size of the byte buffer - */ - public int getByteCount() - { - return this.data.length; - } - - /** - * Returns the underlying byte buffer. - *

- * Note: the actual buffer is returned. If it's manipulated - * the content of the bit array changes. - * @return the underlying data buffer - */ - public byte[] getData() - { - return this.data; - } - - /** {@inheritDoc} */ - public String toString() - { - return toBitString(this.data).substring(0, this.bitCount); - } - - /** - * Converts a byte to a "binary" String of 0s and 1s. - * @param data the value to convert - * @return the binary string - */ - public static String toBitString(byte data) - { - byte[] buf = new byte[] {data}; - return toBitString(buf); - } - - /** - * Converts a series of bytes to a "binary" String of 0s and 1s. - * @param data the data - * @return the binary string - */ - public static String toBitString(byte[] data) - { - return toBitString(data, 0, data.length); - } - - /** - * Converts a series of bytes to a "binary" String of 0s and 1s. - * @param data the data - * @param start the start offset - * @param len the number of bytes to convert - * @return the binary string - */ - public static String toBitString(byte[] data, int start, int len) - { - StringBuffer sb = new StringBuffer(); - for (int x = start, end = start + len; x < end; x++) - { - for (int i = 0; i < 8; i++) - { - int mask = 1 << i; - int value = data[x] & mask; - sb.append(value != 0 ? '1' : '0'); - } - } - return sb.toString(); - } - -} diff --git a/pdfbox/src/main/java/org/apache/pdfbox/filter/ccitt/TIFFFaxDecoder.java b/pdfbox/src/main/java/org/apache/pdfbox/filter/ccitt/TIFFFaxDecoder.java deleted file mode 100644 index 717fb8a8088..00000000000 --- a/pdfbox/src/main/java/org/apache/pdfbox/filter/ccitt/TIFFFaxDecoder.java +++ /dev/null @@ -1,1599 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* $Id$ */ - -package org.apache.pdfbox.filter.ccitt; - -import java.io.IOException; - -/** - * CCITT Fax decoder. - */ -public final class TIFFFaxDecoder -{ - - private int bitPointer, bytePointer; - private byte[] data; - private int w, h; - private int fillOrder; - - // Data structures needed to store changing elements for the previous - // and the current scanline - private int changingElemSize = 0; - private int[] prevChangingElems; - private int[] currChangingElems; - - // Element at which to start search in getNextChangingElement - private int lastChangingElement = 0; - - private int compression = 2; - - // Variables set by T4Options - private int uncompressedMode = 0; - private int fillBits = 0; - private int oneD; - - private static final int[] TABLE1 = { 0x00, // 0 bits are left in first byte - SHOULD NOT HAPPEN - 0x01, // 1 bits are left in first byte - 0x03, // 2 bits are left in first byte - 0x07, // 3 bits are left in first byte - 0x0f, // 4 bits are left in first byte - 0x1f, // 5 bits are left in first byte - 0x3f, // 6 bits are left in first byte - 0x7f, // 7 bits are left in first byte - 0xff // 8 bits are left in first byte - }; - - private static final int[] TABLE2 = { 0x00, // 0 - 0x80, // 1 - 0xc0, // 2 - 0xe0, // 3 - 0xf0, // 4 - 0xf8, // 5 - 0xfc, // 6 - 0xfe, // 7 - 0xff // 8 - }; - - // Table to be used when fillOrder = 2, for flipping bytes. - private static final byte[] FLIP_TABLE = { 0, -128, 64, -64, 32, -96, 96, -32, 16, -112, 80, - -48, 48, -80, 112, -16, 8, -120, 72, -56, 40, -88, 104, -24, 24, -104, 88, -40, 56, - -72, 120, -8, 4, -124, 68, -60, 36, -92, 100, -28, 20, -108, 84, -44, 52, -76, 116, - -12, 12, -116, 76, -52, 44, -84, 108, -20, 28, -100, 92, -36, 60, -68, 124, -4, 2, - -126, 66, -62, 34, -94, 98, -30, 18, -110, 82, -46, 50, -78, 114, -14, 10, -118, 74, - -54, 42, -86, 106, -22, 26, -102, 90, -38, 58, -70, 122, -6, 6, -122, 70, -58, 38, -90, - 102, -26, 22, -106, 86, -42, 54, -74, 118, -10, 14, -114, 78, -50, 46, -82, 110, -18, - 30, -98, 94, -34, 62, -66, 126, -2, 1, -127, 65, -63, 33, -95, 97, -31, 17, -111, 81, - -47, 49, -79, 113, -15, 9, -119, 73, -55, 41, -87, 105, -23, 25, -103, 89, -39, 57, - -71, 121, -7, 5, -123, 69, -59, 37, -91, 101, -27, 21, -107, 85, -43, 53, -75, 117, - -11, 13, -115, 77, -51, 45, -83, 109, -19, 29, -99, 93, -35, 61, -67, 125, -3, 3, -125, - 67, -61, 35, -93, 99, -29, 19, -109, 83, -45, 51, -77, 115, -13, 11, -117, 75, -53, 43, - -85, 107, -21, 27, -101, 91, -37, 59, -69, 123, -5, 7, -121, 71, -57, 39, -89, 103, - -25, 23, -105, 87, -41, 55, -73, 119, -9, 15, -113, 79, -49, 47, -81, 111, -17, 31, - -97, 95, -33, 63, -65, 127, -1, }; - - // The main 10 bit white runs lookup table - private static final short[] WHITE = { - // 0 - 7 - 6430, 6400, 6400, 6400, 3225, 3225, 3225, 3225, - // 8 - 15 - 944, 944, 944, 944, 976, 976, 976, 976, - // 16 - 23 - 1456, 1456, 1456, 1456, 1488, 1488, 1488, 1488, - // 24 - 31 - 718, 718, 718, 718, 718, 718, 718, 718, - // 32 - 39 - 750, 750, 750, 750, 750, 750, 750, 750, - // 40 - 47 - 1520, 1520, 1520, 1520, 1552, 1552, 1552, 1552, - // 48 - 55 - 428, 428, 428, 428, 428, 428, 428, 428, - // 56 - 63 - 428, 428, 428, 428, 428, 428, 428, 428, - // 64 - 71 - 654, 654, 654, 654, 654, 654, 654, 654, - // 72 - 79 - 1072, 1072, 1072, 1072, 1104, 1104, 1104, 1104, - // 80 - 87 - 1136, 1136, 1136, 1136, 1168, 1168, 1168, 1168, - // 88 - 95 - 1200, 1200, 1200, 1200, 1232, 1232, 1232, 1232, - // 96 - 103 - 622, 622, 622, 622, 622, 622, 622, 622, - // 104 - 111 - 1008, 1008, 1008, 1008, 1040, 1040, 1040, 1040, - // 112 - 119 - 44, 44, 44, 44, 44, 44, 44, 44, - // 120 - 127 - 44, 44, 44, 44, 44, 44, 44, 44, - // 128 - 135 - 396, 396, 396, 396, 396, 396, 396, 396, - // 136 - 143 - 396, 396, 396, 396, 396, 396, 396, 396, - // 144 - 151 - 1712, 1712, 1712, 1712, 1744, 1744, 1744, 1744, - // 152 - 159 - 846, 846, 846, 846, 846, 846, 846, 846, - // 160 - 167 - 1264, 1264, 1264, 1264, 1296, 1296, 1296, 1296, - // 168 - 175 - 1328, 1328, 1328, 1328, 1360, 1360, 1360, 1360, - // 176 - 183 - 1392, 1392, 1392, 1392, 1424, 1424, 1424, 1424, - // 184 - 191 - 686, 686, 686, 686, 686, 686, 686, 686, - // 192 - 199 - 910, 910, 910, 910, 910, 910, 910, 910, - // 200 - 207 - 1968, 1968, 1968, 1968, 2000, 2000, 2000, 2000, - // 208 - 215 - 2032, 2032, 2032, 2032, 16, 16, 16, 16, - // 216 - 223 - 10257, 10257, 10257, 10257, 12305, 12305, 12305, 12305, - // 224 - 231 - 330, 330, 330, 330, 330, 330, 330, 330, - // 232 - 239 - 330, 330, 330, 330, 330, 330, 330, 330, - // 240 - 247 - 330, 330, 330, 330, 330, 330, 330, 330, - // 248 - 255 - 330, 330, 330, 330, 330, 330, 330, 330, - // 256 - 263 - 362, 362, 362, 362, 362, 362, 362, 362, - // 264 - 271 - 362, 362, 362, 362, 362, 362, 362, 362, - // 272 - 279 - 362, 362, 362, 362, 362, 362, 362, 362, - // 280 - 287 - 362, 362, 362, 362, 362, 362, 362, 362, - // 288 - 295 - 878, 878, 878, 878, 878, 878, 878, 878, - // 296 - 303 - 1904, 1904, 1904, 1904, 1936, 1936, 1936, 1936, - // 304 - 311 - -18413, -18413, -16365, -16365, -14317, -14317, -10221, -10221, - // 312 - 319 - 590, 590, 590, 590, 590, 590, 590, 590, - // 320 - 327 - 782, 782, 782, 782, 782, 782, 782, 782, - // 328 - 335 - 1584, 1584, 1584, 1584, 1616, 1616, 1616, 1616, - // 336 - 343 - 1648, 1648, 1648, 1648, 1680, 1680, 1680, 1680, - // 344 - 351 - 814, 814, 814, 814, 814, 814, 814, 814, - // 352 - 359 - 1776, 1776, 1776, 1776, 1808, 1808, 1808, 1808, - // 360 - 367 - 1840, 1840, 1840, 1840, 1872, 1872, 1872, 1872, - // 368 - 375 - 6157, 6157, 6157, 6157, 6157, 6157, 6157, 6157, - // 376 - 383 - 6157, 6157, 6157, 6157, 6157, 6157, 6157, 6157, - // 384 - 391 - -12275, -12275, -12275, -12275, -12275, -12275, -12275, -12275, - // 392 - 399 - -12275, -12275, -12275, -12275, -12275, -12275, -12275, -12275, - // 400 - 407 - 14353, 14353, 14353, 14353, 16401, 16401, 16401, 16401, - // 408 - 415 - 22547, 22547, 24595, 24595, 20497, 20497, 20497, 20497, - // 416 - 423 - 18449, 18449, 18449, 18449, 26643, 26643, 28691, 28691, - // 424 - 431 - 30739, 30739, -32749, -32749, -30701, -30701, -28653, -28653, - // 432 - 439 - -26605, -26605, -24557, -24557, -22509, -22509, -20461, -20461, - // 440 - 447 - 8207, 8207, 8207, 8207, 8207, 8207, 8207, 8207, - // 448 - 455 - 72, 72, 72, 72, 72, 72, 72, 72, - // 456 - 463 - 72, 72, 72, 72, 72, 72, 72, 72, - // 464 - 471 - 72, 72, 72, 72, 72, 72, 72, 72, - // 472 - 479 - 72, 72, 72, 72, 72, 72, 72, 72, - // 480 - 487 - 72, 72, 72, 72, 72, 72, 72, 72, - // 488 - 495 - 72, 72, 72, 72, 72, 72, 72, 72, - // 496 - 503 - 72, 72, 72, 72, 72, 72, 72, 72, - // 504 - 511 - 72, 72, 72, 72, 72, 72, 72, 72, - // 512 - 519 - 104, 104, 104, 104, 104, 104, 104, 104, - // 520 - 527 - 104, 104, 104, 104, 104, 104, 104, 104, - // 528 - 535 - 104, 104, 104, 104, 104, 104, 104, 104, - // 536 - 543 - 104, 104, 104, 104, 104, 104, 104, 104, - // 544 - 551 - 104, 104, 104, 104, 104, 104, 104, 104, - // 552 - 559 - 104, 104, 104, 104, 104, 104, 104, 104, - // 560 - 567 - 104, 104, 104, 104, 104, 104, 104, 104, - // 568 - 575 - 104, 104, 104, 104, 104, 104, 104, 104, - // 576 - 583 - 4107, 4107, 4107, 4107, 4107, 4107, 4107, 4107, - // 584 - 591 - 4107, 4107, 4107, 4107, 4107, 4107, 4107, 4107, - // 592 - 599 - 4107, 4107, 4107, 4107, 4107, 4107, 4107, 4107, - // 600 - 607 - 4107, 4107, 4107, 4107, 4107, 4107, 4107, 4107, - // 608 - 615 - 266, 266, 266, 266, 266, 266, 266, 266, - // 616 - 623 - 266, 266, 266, 266, 266, 266, 266, 266, - // 624 - 631 - 266, 266, 266, 266, 266, 266, 266, 266, - // 632 - 639 - 266, 266, 266, 266, 266, 266, 266, 266, - // 640 - 647 - 298, 298, 298, 298, 298, 298, 298, 298, - // 648 - 655 - 298, 298, 298, 298, 298, 298, 298, 298, - // 656 - 663 - 298, 298, 298, 298, 298, 298, 298, 298, - // 664 - 671 - 298, 298, 298, 298, 298, 298, 298, 298, - // 672 - 679 - 524, 524, 524, 524, 524, 524, 524, 524, - // 680 - 687 - 524, 524, 524, 524, 524, 524, 524, 524, - // 688 - 695 - 556, 556, 556, 556, 556, 556, 556, 556, - // 696 - 703 - 556, 556, 556, 556, 556, 556, 556, 556, - // 704 - 711 - 136, 136, 136, 136, 136, 136, 136, 136, - // 712 - 719 - 136, 136, 136, 136, 136, 136, 136, 136, - // 720 - 727 - 136, 136, 136, 136, 136, 136, 136, 136, - // 728 - 735 - 136, 136, 136, 136, 136, 136, 136, 136, - // 736 - 743 - 136, 136, 136, 136, 136, 136, 136, 136, - // 744 - 751 - 136, 136, 136, 136, 136, 136, 136, 136, - // 752 - 759 - 136, 136, 136, 136, 136, 136, 136, 136, - // 760 - 767 - 136, 136, 136, 136, 136, 136, 136, 136, - // 768 - 775 - 168, 168, 168, 168, 168, 168, 168, 168, - // 776 - 783 - 168, 168, 168, 168, 168, 168, 168, 168, - // 784 - 791 - 168, 168, 168, 168, 168, 168, 168, 168, - // 792 - 799 - 168, 168, 168, 168, 168, 168, 168, 168, - // 800 - 807 - 168, 168, 168, 168, 168, 168, 168, 168, - // 808 - 815 - 168, 168, 168, 168, 168, 168, 168, 168, - // 816 - 823 - 168, 168, 168, 168, 168, 168, 168, 168, - // 824 - 831 - 168, 168, 168, 168, 168, 168, 168, 168, - // 832 - 839 - 460, 460, 460, 460, 460, 460, 460, 460, - // 840 - 847 - 460, 460, 460, 460, 460, 460, 460, 460, - // 848 - 855 - 492, 492, 492, 492, 492, 492, 492, 492, - // 856 - 863 - 492, 492, 492, 492, 492, 492, 492, 492, - // 864 - 871 - 2059, 2059, 2059, 2059, 2059, 2059, 2059, 2059, - // 872 - 879 - 2059, 2059, 2059, 2059, 2059, 2059, 2059, 2059, - // 880 - 887 - 2059, 2059, 2059, 2059, 2059, 2059, 2059, 2059, - // 888 - 895 - 2059, 2059, 2059, 2059, 2059, 2059, 2059, 2059, - // 896 - 903 - 200, 200, 200, 200, 200, 200, 200, 200, - // 904 - 911 - 200, 200, 200, 200, 200, 200, 200, 200, - // 912 - 919 - 200, 200, 200, 200, 200, 200, 200, 200, - // 920 - 927 - 200, 200, 200, 200, 200, 200, 200, 200, - // 928 - 935 - 200, 200, 200, 200, 200, 200, 200, 200, - // 936 - 943 - 200, 200, 200, 200, 200, 200, 200, 200, - // 944 - 951 - 200, 200, 200, 200, 200, 200, 200, 200, - // 952 - 959 - 200, 200, 200, 200, 200, 200, 200, 200, - // 960 - 967 - 232, 232, 232, 232, 232, 232, 232, 232, - // 968 - 975 - 232, 232, 232, 232, 232, 232, 232, 232, - // 976 - 983 - 232, 232, 232, 232, 232, 232, 232, 232, - // 984 - 991 - 232, 232, 232, 232, 232, 232, 232, 232, - // 992 - 999 - 232, 232, 232, 232, 232, 232, 232, 232, - // 1000 - 1007 - 232, 232, 232, 232, 232, 232, 232, 232, - // 1008 - 1015 - 232, 232, 232, 232, 232, 232, 232, 232, - // 1016 - 1023 - 232, 232, 232, 232, 232, 232, 232, 232, }; - - // Additional make up codes for both White and Black runs - private static final short[] ADDITIONAL_MAKEUP = { 28679, 28679, 31752, (short) 32777, - (short) 33801, (short) 34825, (short) 35849, (short) 36873, (short) 29703, - (short) 29703, (short) 30727, (short) 30727, (short) 37897, (short) 38921, - (short) 39945, (short) 40969 }; - - // Initial black run look up table, uses the first 4 bits of a code - private static final short[] INIT_BLACK = { - // 0 - 7 - 3226, 6412, 200, 168, 38, 38, 134, 134, - // 8 - 15 - 100, 100, 100, 100, 68, 68, 68, 68 }; - - // - private static final short[] TWO_BIT_BLACK = { 292, 260, 226, 226 }; // 0 - 3 - - // Main black run table, using the last 9 bits of possible 13 bit code - private static final short[] BLACK = { - // 0 - 7 - 62, 62, 30, 30, 0, 0, 0, 0, - // 8 - 15 - 0, 0, 0, 0, 0, 0, 0, 0, - // 16 - 23 - 0, 0, 0, 0, 0, 0, 0, 0, - // 24 - 31 - 0, 0, 0, 0, 0, 0, 0, 0, - // 32 - 39 - 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, - // 40 - 47 - 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, - // 48 - 55 - 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, - // 56 - 63 - 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, - // 64 - 71 - 588, 588, 588, 588, 588, 588, 588, 588, - // 72 - 79 - 1680, 1680, 20499, 22547, 24595, 26643, 1776, 1776, - // 80 - 87 - 1808, 1808, -24557, -22509, -20461, -18413, 1904, 1904, - // 88 - 95 - 1936, 1936, -16365, -14317, 782, 782, 782, 782, - // 96 - 103 - 814, 814, 814, 814, -12269, -10221, 10257, 10257, - // 104 - 111 - 12305, 12305, 14353, 14353, 16403, 18451, 1712, 1712, - // 112 - 119 - 1744, 1744, 28691, 30739, -32749, -30701, -28653, -26605, - // 120 - 127 - 2061, 2061, 2061, 2061, 2061, 2061, 2061, 2061, - // 128 - 135 - 424, 424, 424, 424, 424, 424, 424, 424, - // 136 - 143 - 424, 424, 424, 424, 424, 424, 424, 424, - // 144 - 151 - 424, 424, 424, 424, 424, 424, 424, 424, - // 152 - 159 - 424, 424, 424, 424, 424, 424, 424, 424, - // 160 - 167 - 750, 750, 750, 750, 1616, 1616, 1648, 1648, - // 168 - 175 - 1424, 1424, 1456, 1456, 1488, 1488, 1520, 1520, - // 176 - 183 - 1840, 1840, 1872, 1872, 1968, 1968, 8209, 8209, - // 184 - 191 - 524, 524, 524, 524, 524, 524, 524, 524, - // 192 - 199 - 556, 556, 556, 556, 556, 556, 556, 556, - // 200 - 207 - 1552, 1552, 1584, 1584, 2000, 2000, 2032, 2032, - // 208 - 215 - 976, 976, 1008, 1008, 1040, 1040, 1072, 1072, - // 216 - 223 - 1296, 1296, 1328, 1328, 718, 718, 718, 718, - // 224 - 231 - 456, 456, 456, 456, 456, 456, 456, 456, - // 232 - 239 - 456, 456, 456, 456, 456, 456, 456, 456, - // 240 - 247 - 456, 456, 456, 456, 456, 456, 456, 456, - // 248 - 255 - 456, 456, 456, 456, 456, 456, 456, 456, - // 256 - 263 - 326, 326, 326, 326, 326, 326, 326, 326, - // 264 - 271 - 326, 326, 326, 326, 326, 326, 326, 326, - // 272 - 279 - 326, 326, 326, 326, 326, 326, 326, 326, - // 280 - 287 - 326, 326, 326, 326, 326, 326, 326, 326, - // 288 - 295 - 326, 326, 326, 326, 326, 326, 326, 326, - // 296 - 303 - 326, 326, 326, 326, 326, 326, 326, 326, - // 304 - 311 - 326, 326, 326, 326, 326, 326, 326, 326, - // 312 - 319 - 326, 326, 326, 326, 326, 326, 326, 326, - // 320 - 327 - 358, 358, 358, 358, 358, 358, 358, 358, - // 328 - 335 - 358, 358, 358, 358, 358, 358, 358, 358, - // 336 - 343 - 358, 358, 358, 358, 358, 358, 358, 358, - // 344 - 351 - 358, 358, 358, 358, 358, 358, 358, 358, - // 352 - 359 - 358, 358, 358, 358, 358, 358, 358, 358, - // 360 - 367 - 358, 358, 358, 358, 358, 358, 358, 358, - // 368 - 375 - 358, 358, 358, 358, 358, 358, 358, 358, - // 376 - 383 - 358, 358, 358, 358, 358, 358, 358, 358, - // 384 - 391 - 490, 490, 490, 490, 490, 490, 490, 490, - // 392 - 399 - 490, 490, 490, 490, 490, 490, 490, 490, - // 400 - 407 - 4113, 4113, 6161, 6161, 848, 848, 880, 880, - // 408 - 415 - 912, 912, 944, 944, 622, 622, 622, 622, - // 416 - 423 - 654, 654, 654, 654, 1104, 1104, 1136, 1136, - // 424 - 431 - 1168, 1168, 1200, 1200, 1232, 1232, 1264, 1264, - // 432 - 439 - 686, 686, 686, 686, 1360, 1360, 1392, 1392, - // 440 - 447 - 12, 12, 12, 12, 12, 12, 12, 12, - // 448 - 455 - 390, 390, 390, 390, 390, 390, 390, 390, - // 456 - 463 - 390, 390, 390, 390, 390, 390, 390, 390, - // 464 - 471 - 390, 390, 390, 390, 390, 390, 390, 390, - // 472 - 479 - 390, 390, 390, 390, 390, 390, 390, 390, - // 480 - 487 - 390, 390, 390, 390, 390, 390, 390, 390, - // 488 - 495 - 390, 390, 390, 390, 390, 390, 390, 390, - // 496 - 503 - 390, 390, 390, 390, 390, 390, 390, 390, - // 504 - 511 - 390, 390, 390, 390, 390, 390, 390, 390, }; - - private static final byte[] TWO_DCODES = { - // 0 - 7 - 80, 88, 23, 71, 30, 30, 62, 62, - // 8 - 15 - 4, 4, 4, 4, 4, 4, 4, 4, - // 16 - 23 - 11, 11, 11, 11, 11, 11, 11, 11, - // 24 - 31 - 11, 11, 11, 11, 11, 11, 11, 11, - // 32 - 39 - 35, 35, 35, 35, 35, 35, 35, 35, - // 40 - 47 - 35, 35, 35, 35, 35, 35, 35, 35, - // 48 - 55 - 51, 51, 51, 51, 51, 51, 51, 51, - // 56 - 63 - 51, 51, 51, 51, 51, 51, 51, 51, - // 64 - 71 - 41, 41, 41, 41, 41, 41, 41, 41, - // 72 - 79 - 41, 41, 41, 41, 41, 41, 41, 41, - // 80 - 87 - 41, 41, 41, 41, 41, 41, 41, 41, - // 88 - 95 - 41, 41, 41, 41, 41, 41, 41, 41, - // 96 - 103 - 41, 41, 41, 41, 41, 41, 41, 41, - // 104 - 111 - 41, 41, 41, 41, 41, 41, 41, 41, - // 112 - 119 - 41, 41, 41, 41, 41, 41, 41, 41, - // 120 - 127 - 41, 41, 41, 41, 41, 41, 41, 41, }; - - /** - * @param fillOrderValue The fill order of the compressed data bytes. - * @param width The width of the image in pixels - * @param height The height of the image in pixels - */ - public TIFFFaxDecoder(int fillOrderValue, int width, int height) - { - fillOrder = fillOrderValue; - w = width; - h = height; - - bitPointer = 0; - bytePointer = 0; - prevChangingElems = new int[width + 1]; - currChangingElems = new int[width + 1]; - } - - // One-dimensional decoding methods - - public void decode1D(byte[] buffer, byte[] compData, int startX, int height) throws IOException - { - this.data = compData; - - int lineOffset = 0; - int scanlineStride = (w + 7) / 8; - - bitPointer = 0; - bytePointer = 0; - - for (int i = 0; i < height; i++) - { - decodeNextScanline(buffer, lineOffset, startX); - lineOffset += scanlineStride; - } - } - - public void decodeNextScanline(byte[] buffer, int lineOffset, int bitOffset) throws IOException - { - int bits = 0, code = 0, isT = 0; - int current, entry, twoBits; - boolean isWhite = true; - - // Initialize starting of the changing elements array - changingElemSize = 0; - - // While scanline not complete - while (bitOffset < w) - { - while (isWhite) - { - // White run - current = nextNBits(10); - entry = WHITE[current]; - - // Get the 3 fields from the entry - isT = entry & 0x0001; - bits = (entry >>> 1) & 0x0f; - - if (bits == 12) - { // Additional Make up code - // Get the next 2 bits - twoBits = nextLesserThan8Bits(2); - // Consolidate the 2 new bits and last 2 bits into 4 bits - current = ((current << 2) & 0x000c) | twoBits; - entry = ADDITIONAL_MAKEUP[current]; - bits = (entry >>> 1) & 0x07; // 3 bits 0000 0111 - code = (entry >>> 4) & 0x0fff; // 12 bits - bitOffset += code; // Skip white run - - updatePointer(4 - bits); - } - else if (bits == 0) - { // ERROR - throw new IOException("TIFFFaxDecoder: Invalid code encountered."); - } - else if (bits == 15) - { // EOL - throw new IOException("TIFFFaxDecoder: EOL encountered in white run."); - } - else - { - // 11 bits - 0000 0111 1111 1111 = 0x07ff - code = (entry >>> 5) & 0x07ff; - bitOffset += code; - - updatePointer(10 - bits); - if (isT == 0) - { - isWhite = false; - currChangingElems[changingElemSize++] = bitOffset; - } - } - } - - // Check whether this run completed one width, if so - // advance to next byte boundary for compression = 2. - if (bitOffset == w) - { - if (compression == 2) - { - advancePointer(); - } - break; - } - - while (!isWhite) - { - // Black run - current = nextLesserThan8Bits(4); - entry = INIT_BLACK[current]; - - // Get the 3 fields from the entry - isT = entry & 0x0001; - bits = (entry >>> 1) & 0x000f; - code = (entry >>> 5) & 0x07ff; - - if (code == 100) - { - current = nextNBits(9); - entry = BLACK[current]; - - // Get the 3 fields from the entry - isT = entry & 0x0001; - bits = (entry >>> 1) & 0x000f; - code = (entry >>> 5) & 0x07ff; - - if (bits == 12) - { - // Additional makeup codes - updatePointer(5); - current = nextLesserThan8Bits(4); - entry = ADDITIONAL_MAKEUP[current]; - bits = (entry >>> 1) & 0x07; // 3 bits 0000 0111 - code = (entry >>> 4) & 0x0fff; // 12 bits - - setToBlack(buffer, lineOffset, bitOffset, code); - bitOffset += code; - - updatePointer(4 - bits); - } - else if (bits == 15) - { - // EOL code - throw new IOException("TIFFFaxDecoder: EOL encountered in black run."); - } - else - { - setToBlack(buffer, lineOffset, bitOffset, code); - bitOffset += code; - - updatePointer(9 - bits); - if (isT == 0) - { - isWhite = true; - currChangingElems[changingElemSize++] = bitOffset; - } - } - } - else if (code == 200) - { - // Is a Terminating code - current = nextLesserThan8Bits(2); - entry = TWO_BIT_BLACK[current]; - code = (entry >>> 5) & 0x07ff; - bits = (entry >>> 1) & 0x0f; - - setToBlack(buffer, lineOffset, bitOffset, code); - bitOffset += code; - - updatePointer(2 - bits); - isWhite = true; - currChangingElems[changingElemSize++] = bitOffset; - } - else - { - // Is a Terminating code - setToBlack(buffer, lineOffset, bitOffset, code); - bitOffset += code; - - updatePointer(4 - bits); - isWhite = true; - currChangingElems[changingElemSize++] = bitOffset; - } - } - - // Check whether this run completed one width - if (bitOffset == w) - { - if (compression == 2) - { - advancePointer(); - } - break; - } - } - - currChangingElems[changingElemSize++] = bitOffset; - } - - // Two-dimensional decoding methods - - public void decode2D(byte[] buffer, byte[] compData, int startX, int height, long tiffT4Options) - throws IOException - { - this.data = compData; - compression = 3; - - bitPointer = 0; - bytePointer = 0; - - int scanlineStride = (w + 7) / 8; - - int a0, a1, b1, b2; - int[] b = new int[2]; - int entry, code, bits; - boolean isWhite; - int currIndex = 0; - int[] temp; - - // fillBits - dealt with this in readEOL - // 1D/2D encoding - dealt with this in readEOL - - // uncompressedMode - haven't dealt with this yet. - - oneD = (int) (tiffT4Options & 0x01); - uncompressedMode = (int) ((tiffT4Options & 0x02) >> 1); - fillBits = (int) ((tiffT4Options & 0x04) >> 2); - - // The data must start with an EOL code - if (readEOL() != 1) - { - throw new IOException("TIFFFaxDecoder: First scanline must be 1D encoded."); - } - - int lineOffset = 0; - int bitOffset; - - // Then the 1D encoded scanline data will occur, changing elements - // array gets set. - decodeNextScanline(buffer, lineOffset, startX); - lineOffset += scanlineStride; - - for (int lines = 1; lines < height; lines++) - { - - // Every line must begin with an EOL followed by a bit which - // indicates whether the following scanline is 1D or 2D encoded. - if (readEOL() == 0) - { - // 2D encoded scanline follows - - // Initialize previous scanlines changing elements, and - // initialize current scanline's changing elements array - temp = prevChangingElems; - prevChangingElems = currChangingElems; - currChangingElems = temp; - currIndex = 0; - - // a0 has to be set just before the start of this scanline. - a0 = -1; - isWhite = true; - bitOffset = startX; - - lastChangingElement = 0; - - while (bitOffset < w) - { - // Get the next changing element - getNextChangingElement(a0, isWhite, b); - - b1 = b[0]; - b2 = b[1]; - - // Get the next seven bits - entry = nextLesserThan8Bits(7); - - // Run these through the 2DCodes table - entry = (TWO_DCODES[entry] & 0xff); - - // Get the code and the number of bits used up - code = (entry & 0x78) >>> 3; - bits = entry & 0x07; - - if (code == 0) - { - if (!isWhite) - { - setToBlack(buffer, lineOffset, bitOffset, b2 - bitOffset); - } - bitOffset = a0 = b2; - - // Set pointer to consume the correct number of bits. - updatePointer(7 - bits); - } - else if (code == 1) - { - // Horizontal - updatePointer(7 - bits); - - // identify the next 2 codes. - int number; - if (isWhite) - { - number = decodeWhiteCodeWord(); - bitOffset += number; - currChangingElems[currIndex++] = bitOffset; - - number = decodeBlackCodeWord(); - setToBlack(buffer, lineOffset, bitOffset, number); - bitOffset += number; - currChangingElems[currIndex++] = bitOffset; - } - else - { - number = decodeBlackCodeWord(); - setToBlack(buffer, lineOffset, bitOffset, number); - bitOffset += number; - currChangingElems[currIndex++] = bitOffset; - - number = decodeWhiteCodeWord(); - bitOffset += number; - currChangingElems[currIndex++] = bitOffset; - } - - a0 = bitOffset; - } - else if (code <= 8) - { - // Vertical - a1 = b1 + (code - 5); - - currChangingElems[currIndex++] = a1; - - // We write the current color till a1 - 1 pos, - // since a1 is where the next color starts - if (!isWhite) - { - setToBlack(buffer, lineOffset, bitOffset, a1 - bitOffset); - } - bitOffset = a0 = a1; - isWhite = !isWhite; - - updatePointer(7 - bits); - } - else - { - throw new IOException( - "TIFFFaxDecoder: Invalid code encountered while decoding 2D group 3 compressed data."); - } - } - - // Add the changing element beyond the current scanline for the - // other color too - currChangingElems[currIndex++] = bitOffset; - changingElemSize = currIndex; - } - else - { - // 1D encoded scanline follows - decodeNextScanline(buffer, lineOffset, startX); - } - - lineOffset += scanlineStride; - } - } - - public synchronized void decodeT6(byte[] buffer, byte[] compData, int startX, int height, - long tiffT6Options, boolean encodedByteAlign) throws IOException - { - this.data = compData; - compression = 4; - - bitPointer = 0; - bytePointer = 0; - - int scanlineStride = (w + 7) / 8; - - int a0, a1, b1, b2; - int entry, code, bits; - boolean isWhite; - int currIndex; - int[] temp; - - // Return values from getNextChangingElement - int[] b = new int[2]; - - // uncompressedMode - have written some code for this, but this - // has not been tested due to lack of test images using this optional - - uncompressedMode = (int) ((tiffT6Options & 0x02) >> 1); - - // Local cached reference - int[] cce = currChangingElems; - - // Assume invisible preceding row of all white pixels and insert - // both black and white changing elements beyond the end of this - // imaginary scanline. - changingElemSize = 0; - cce[changingElemSize++] = w; - cce[changingElemSize++] = w; - - int lineOffset = 0; - int bitOffset; - - for (int lines = 0; lines < height; lines++) - { - if (encodedByteAlign && bitPointer != 0) - { - bitPointer = 0; - bytePointer++; - } - // a0 has to be set just before the start of the scanline. - a0 = -1; - isWhite = true; - - // Assign the changing elements of the previous scanline to - // prevChangingElems and start putting this new scanline's - // changing elements into the currChangingElems. - temp = prevChangingElems; - prevChangingElems = currChangingElems; - cce = currChangingElems = temp; - currIndex = 0; - - // Start decoding the scanline at startX in the raster - bitOffset = startX; - - // Reset search start position for getNextChangingElement - lastChangingElement = 0; - - // Till one whole scanline is decoded - while (bitOffset < w) - { - // Get the next changing element - getNextChangingElement(a0, isWhite, b); - b1 = b[0]; - b2 = b[1]; - - // Get the next seven bits - entry = nextLesserThan8Bits(7); - // Run these through the 2DCodes table - entry = (TWO_DCODES[entry] & 0xff); - - // Get the code and the number of bits used up - code = (entry & 0x78) >>> 3; - bits = entry & 0x07; - - if (code == 0) - { // Pass - // We always assume WhiteIsZero format for fax. - if (!isWhite) - { - setToBlack(buffer, lineOffset, bitOffset, b2 - bitOffset); - } - bitOffset = a0 = b2; - - // Set pointer to only consume the correct number of bits. - updatePointer(7 - bits); - } - else if (code == 1) - { // Horizontal - // Set pointer to only consume the correct number of bits. - updatePointer(7 - bits); - - // identify the next 2 alternating color codes. - int number; - if (isWhite) - { - // Following are white and black runs - number = decodeWhiteCodeWord(); - bitOffset += number; - cce[currIndex++] = bitOffset; - - number = decodeBlackCodeWord(); - setToBlack(buffer, lineOffset, bitOffset, number); - bitOffset += number; - cce[currIndex++] = bitOffset; - } - else - { - // First a black run and then a white run follows - number = decodeBlackCodeWord(); - setToBlack(buffer, lineOffset, bitOffset, number); - bitOffset += number; - cce[currIndex++] = bitOffset; - - number = decodeWhiteCodeWord(); - bitOffset += number; - cce[currIndex++] = bitOffset; - } - - a0 = bitOffset; - } - else if (code <= 8) - { // Vertical - a1 = b1 + (code - 5); - cce[currIndex++] = a1; - - // We write the current color till a1 - 1 pos, - // since a1 is where the next color starts - if (!isWhite) - { - setToBlack(buffer, lineOffset, bitOffset, a1 - bitOffset); - } - bitOffset = a0 = a1; - isWhite = !isWhite; - - updatePointer(7 - bits); - } - else if (code == 11) - { - if (nextLesserThan8Bits(3) != 7) - { - throw new IOException( - "TIFFFaxDecoder: Invalid code encountered while decoding 2D group 4 compressed data."); - } - - int zeros = 0; - boolean exit = false; - - while (!exit) - { - while (nextLesserThan8Bits(1) != 1) - { - zeros++; - } - - if (zeros > 5) - { - // Exit code - - // Zeros before exit code - zeros = zeros - 6; - - if (!isWhite && (zeros > 0)) - { - cce[currIndex++] = bitOffset; - } - - // Zeros before the exit code - bitOffset += zeros; - if (zeros > 0) - { - // Some zeros have been written - isWhite = true; - } - - // Read in the bit which specifies the color of - // the following run - if (nextLesserThan8Bits(1) == 0) - { - if (!isWhite) - { - cce[currIndex++] = bitOffset; - } - isWhite = true; - } - else - { - if (isWhite) - { - cce[currIndex++] = bitOffset; - } - isWhite = false; - } - - exit = true; - } - - if (zeros == 5) - { - if (!isWhite) - { - cce[currIndex++] = bitOffset; - } - bitOffset += zeros; - - // Last thing written was white - isWhite = true; - } - else - { - bitOffset += zeros; - - cce[currIndex++] = bitOffset; - setToBlack(buffer, lineOffset, bitOffset, 1); - ++bitOffset; - - // Last thing written was black - isWhite = false; - } - - } - } - else - { - throw new IOException( - "TIFFFaxDecoder: Invalid code encountered while decoding 2D group 4 compressed data."); - } - } - - // workaround for PDFBOX-1916, it is not clear whether the - // code in the class is to blame or if the PDF is corrupt - if (cce.length == currIndex) - { - break; - } - - // Add the changing element beyond the current scanline for the - // other color too - cce[currIndex++] = bitOffset; - - // Number of changing elements in this scanline. - changingElemSize = currIndex; - - lineOffset += scanlineStride; - } - } - - private void setToBlack(byte[] buffer, int lineOffset, int bitOffset, int numBits) - { - int bitNum = 8 * lineOffset + bitOffset; - int lastBit = bitNum + numBits; - - int byteNum = bitNum >> 3; - - // Handle bits in first byte - int shift = bitNum & 0x7; - if (shift > 0) - { - int maskVal = 1 << (7 - shift); - byte val = buffer[byteNum]; - while (maskVal > 0 && bitNum < lastBit) - { - val |= maskVal; - maskVal >>= 1; - ++bitNum; - } - buffer[byteNum] = val; - } - - // Fill in 8 bits at a time - byteNum = bitNum >> 3; - while (bitNum < lastBit - 7) - { - buffer[byteNum++] = (byte) 255; - bitNum += 8; - } - - // Fill in remaining bits - while (bitNum < lastBit) - { - byteNum = bitNum >> 3; - buffer[byteNum] |= 1 << (7 - (bitNum & 0x7)); - ++bitNum; - } - } - - // Returns run length - private int decodeWhiteCodeWord() throws IOException - { - int current, entry, bits, isT, twoBits, code = -1; - int runLength = 0; - boolean isWhite = true; - - while (isWhite) - { - current = nextNBits(10); - entry = WHITE[current]; - - // Get the 3 fields from the entry - isT = entry & 0x0001; - bits = (entry >>> 1) & 0x0f; - - if (bits == 12) - { // Additional Make up code - // Get the next 2 bits - twoBits = nextLesserThan8Bits(2); - // Consolidate the 2 new bits and last 2 bits into 4 bits - current = ((current << 2) & 0x000c) | twoBits; - entry = ADDITIONAL_MAKEUP[current]; - bits = (entry >>> 1) & 0x07; // 3 bits 0000 0111 - code = (entry >>> 4) & 0x0fff; // 12 bits - runLength += code; - updatePointer(4 - bits); - } - else if (bits == 0) - { // ERROR - throw new IOException("TIFFFaxDecoder: Invalid code encountered."); - } - else if (bits == 15) - { // EOL - throw new IOException("TIFFFaxDecoder: EOL encountered in white run."); - } - else - { - // 11 bits - 0000 0111 1111 1111 = 0x07ff - code = (entry >>> 5) & 0x07ff; - runLength += code; - updatePointer(10 - bits); - if (isT == 0) - { - isWhite = false; - } - } - } - - return runLength; - } - - // Returns run length - private int decodeBlackCodeWord() throws IOException - { - int current, entry, bits, isT, code = -1; - int runLength = 0; - boolean isWhite = false; - - while (!isWhite) - { - current = nextLesserThan8Bits(4); - entry = INIT_BLACK[current]; - - // Get the 3 fields from the entry - isT = entry & 0x0001; - bits = (entry >>> 1) & 0x000f; - code = (entry >>> 5) & 0x07ff; - - if (code == 100) - { - current = nextNBits(9); - entry = BLACK[current]; - - // Get the 3 fields from the entry - isT = entry & 0x0001; - bits = (entry >>> 1) & 0x000f; - code = (entry >>> 5) & 0x07ff; - - if (bits == 12) - { - // Additional makeup codes - updatePointer(5); - current = nextLesserThan8Bits(4); - entry = ADDITIONAL_MAKEUP[current]; - bits = (entry >>> 1) & 0x07; // 3 bits 0000 0111 - code = (entry >>> 4) & 0x0fff; // 12 bits - runLength += code; - - updatePointer(4 - bits); - } - else if (bits == 15) - { - // EOL code - throw new IOException("TIFFFaxDecoder: EOL encountered in black run."); - } - else - { - runLength += code; - updatePointer(9 - bits); - if (isT == 0) - { - isWhite = true; - } - } - } - else if (code == 200) - { - // Is a Terminating code - current = nextLesserThan8Bits(2); - entry = TWO_BIT_BLACK[current]; - code = (entry >>> 5) & 0x07ff; - runLength += code; - bits = (entry >>> 1) & 0x0f; - updatePointer(2 - bits); - isWhite = true; - } - else - { - // Is a Terminating code - runLength += code; - updatePointer(4 - bits); - isWhite = true; - } - } - - return runLength; - } - - private int readEOL() throws IOException - { - if (fillBits == 0) - { - if (nextNBits(12) != 1) - { - throw new IOException("TIFFFaxDecoder: Scanline must begin with EOL."); - } - } - else if (fillBits == 1) - { - - // First EOL code word xxxx 0000 0000 0001 will occur - // As many fill bits will be present as required to make - // the EOL code of 12 bits end on a byte boundary. - - int bitsLeft = 8 - bitPointer; - - if (nextNBits(bitsLeft) != 0) - { - throw new IOException("TIFFFaxDecoder: All fill bits preceding EOL code must be 0."); - } - - // If the number of bitsLeft is less than 8, then to have a 12 - // bit EOL sequence, two more bytes are certainly going to be - // required. The first of them has to be all zeros, so ensure - // that. - if (bitsLeft < 4) - { - if (nextNBits(8) != 0) - { - throw new IOException( - "TIFFFaxDecoder: All fill bits preceding EOL code must be 0."); - } - } - - // There might be a random number of fill bytes with 0s, so - // loop till the EOL of 0000 0001 is found, as long as all - // the bytes preceding it are 0's. - int n; - while ((n = nextNBits(8)) != 1) - { - - // If not all zeros - if (n != 0) - { - throw new IOException( - "TIFFFaxDecoder: All fill bits preceding EOL code must be 0."); - } - } - } - - // If one dimensional encoding mode, then always return 1 - if (oneD == 0) - { - return 1; - } - else - { - // Otherwise for 2D encoding mode, - // The next one bit signifies 1D/2D encoding of next line. - return nextLesserThan8Bits(1); - } - } - - private void getNextChangingElement(int a0, boolean isWhite, int[] ret) - { - // Local copies of instance variables - int[] pce = this.prevChangingElems; - int ces = this.changingElemSize; - - // If the previous match was at an odd element, we still - // have to search the preceeding element. - // int start = lastChangingElement & ~0x1; - int start = lastChangingElement > 0 ? lastChangingElement - 1 : 0; - if (isWhite) - { - start &= ~0x1; // Search even numbered elements - } - else - { - start |= 0x1; // Search odd numbered elements - } - - int i = start; - for (; i < ces; i += 2) - { - int temp = pce[i]; - if (temp > a0) - { - lastChangingElement = i; - ret[0] = temp; - break; - } - } - - if (i + 1 < ces) - { - ret[1] = pce[i + 1]; - } - } - - private int nextNBits(int bitsToGet) throws IOException - { - byte b, next, next2next; - int l = data.length - 1; - int bp = this.bytePointer; - - if (fillOrder == 1) - { - b = data[bp]; - - if (bp == l) - { - next = 0x00; - next2next = 0x00; - } - else if ((bp + 1) == l) - { - next = data[bp + 1]; - next2next = 0x00; - } - else - { - next = data[bp + 1]; - next2next = data[bp + 2]; - } - } - else if (fillOrder == 2) - { - b = FLIP_TABLE[data[bp] & 0xff]; - - if (bp == l) - { - next = 0x00; - next2next = 0x00; - } - else if ((bp + 1) == l) - { - next = FLIP_TABLE[data[bp + 1] & 0xff]; - next2next = 0x00; - } - else - { - next = FLIP_TABLE[data[bp + 1] & 0xff]; - next2next = FLIP_TABLE[data[bp + 2] & 0xff]; - } - } - else - { - throw new IOException("TIFFFaxDecoder: TIFF_FILL_ORDER tag must be either 1 or 2."); - } - - int bitsLeft = 8 - bitPointer; - int bitsFromNextByte = bitsToGet - bitsLeft; - int bitsFromNext2NextByte = 0; - if (bitsFromNextByte > 8) - { - bitsFromNext2NextByte = bitsFromNextByte - 8; - bitsFromNextByte = 8; - } - - bytePointer++; - - int i1 = (b & TABLE1[bitsLeft]) << (bitsToGet - bitsLeft); - int i2 = (next & TABLE2[bitsFromNextByte]) >>> (8 - bitsFromNextByte); - - int i3 = 0; - if (bitsFromNext2NextByte != 0) - { - i2 <<= bitsFromNext2NextByte; - i3 = (next2next & TABLE2[bitsFromNext2NextByte]) >>> (8 - bitsFromNext2NextByte); - i2 |= i3; - bytePointer++; - bitPointer = bitsFromNext2NextByte; - } - else - { - if (bitsFromNextByte == 8) - { - bitPointer = 0; - bytePointer++; - } - else - { - bitPointer = bitsFromNextByte; - } - } - - int i = i1 | i2; - return i; - } - - private int nextLesserThan8Bits(int bitsToGet) throws IOException - { - byte b, next; - int l = data.length - 1; - int bp = this.bytePointer; - - if (fillOrder == 1) - { - b = data[bp]; - if (bp == l) - { - next = 0x00; - } - else - { - next = data[bp + 1]; - } - } - else if (fillOrder == 2) - { - b = FLIP_TABLE[data[bp] & 0xff]; - if (bp == l) - { - next = 0x00; - } - else - { - next = FLIP_TABLE[data[bp + 1] & 0xff]; - } - } - else - { - throw new IOException("TIFFFaxDecoder: TIFF_FILL_ORDER tag must be either 1 or 2."); - } - - int bitsLeft = 8 - bitPointer; - int bitsFromNextByte = bitsToGet - bitsLeft; - - int shift = bitsLeft - bitsToGet; - int i1, i2; - if (shift >= 0) - { - i1 = (b & TABLE1[bitsLeft]) >>> shift; - bitPointer += bitsToGet; - if (bitPointer == 8) - { - bitPointer = 0; - bytePointer++; - } - } - else - { - i1 = (b & TABLE1[bitsLeft]) << (-shift); - i2 = (next & TABLE2[bitsFromNextByte]) >>> (8 - bitsFromNextByte); - - i1 |= i2; - bytePointer++; - bitPointer = bitsFromNextByte; - } - - return i1; - } - - // Move pointer backwards by given amount of bits - private void updatePointer(int bitsToMoveBack) - { - int i = bitPointer - bitsToMoveBack; - - if (i < 0) - { - bytePointer--; - bitPointer = 8 + i; - } - else - { - bitPointer = i; - } - } - - // Move to the next byte boundary - private boolean advancePointer() - { - if (bitPointer != 0) - { - bytePointer++; - bitPointer = 0; - } - - return true; - } -} diff --git a/pdfbox/src/main/java/org/apache/pdfbox/filter/ccitt/package.html b/pdfbox/src/main/java/org/apache/pdfbox/filter/ccitt/package.html deleted file mode 100644 index cd5971ae3e9..00000000000 --- a/pdfbox/src/main/java/org/apache/pdfbox/filter/ccitt/package.html +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - -This package contains CCITT encoders and decoders. -This refers to the ITU T.4 (Group 3 Fax) and T.6 (Group 4 Fax) specifications. - - diff --git a/pdfbox/src/test/java/org/apache/pdfbox/filter/ccitt/AbstractCCITTFaxTestCase.java b/pdfbox/src/test/java/org/apache/pdfbox/filter/ccitt/AbstractCCITTFaxTestCase.java deleted file mode 100644 index 94614f14c93..00000000000 --- a/pdfbox/src/test/java/org/apache/pdfbox/filter/ccitt/AbstractCCITTFaxTestCase.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* $Id$ */ - -package org.apache.pdfbox.filter.ccitt; - -import junit.framework.TestCase; - -/** - * Abstract base class for testing CCITT fax encoding. - */ -public abstract class AbstractCCITTFaxTestCase extends TestCase -{ - - /** - * Visualizes a packed bitmap and dumps it on System.out. - * @param data the bitmap - * @param columns the number of columns - */ - protected void dumpBitmap(byte[] data, int columns) - { - int lineBytes = columns / 8; - if (columns % 8 != 0) - { - lineBytes++; - } - int lines = data.length / lineBytes; - for (int y = 0; y < lines; y++) - { - int start = y * lineBytes; - for (int x = 0; x < columns; x++) - { - int index = start + (x / 8); - int mask = 1 << (7 - (x % 8)); - int value = data[index] & mask; - System.out.print(value != 0 ? 'X' : '_'); - } - System.out.println(); - } - } - - /** - * Converts a series of bytes to a "binary" String of 0s and 1s. - * @param data the data - * @return the binary string - */ - protected String toBitString(byte[] data) - { - return PackedBitArray.toBitString(data); - } - -} diff --git a/pdfbox/src/test/java/org/apache/pdfbox/filter/ccitt/TestCCITTFaxG31DDecodeInputStream.java b/pdfbox/src/test/java/org/apache/pdfbox/filter/ccitt/TestCCITTFaxG31DDecodeInputStream.java deleted file mode 100644 index 509084ee23b..00000000000 --- a/pdfbox/src/test/java/org/apache/pdfbox/filter/ccitt/TestCCITTFaxG31DDecodeInputStream.java +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* $Id$ */ - -package org.apache.pdfbox.filter.ccitt; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; - -import org.apache.pdfbox.io.IOUtils; - -/** - * Tests the CCITT Fax G3 1D decoder. - */ -public class TestCCITTFaxG31DDecodeInputStream extends AbstractCCITTFaxTestCase -{ - - private static final boolean DEBUG = false; - - private static final String EOL = "000000000001"; - private static final String RTC = EOL + EOL + EOL + EOL + EOL + EOL; - - /** - * Tests the decoder with naked bits (no EOL, no alignment, nothing). - * @throws IOException if an I/O error occurs - */ - public void testDecoderNaked() throws IOException - { - //Test data: 24x3 pixels encoded - byte[] data = fromBinary("10011" + "000101" + "10011" - + "00110101" + "011" + "10011" + "0000111" - + "00110101" + "010" + "000111" + "010" + "0010111" + "000000"); - assertStandardDecodingResult(data); - } - - /** - * Tests the decoder with EOLs. - * @throws IOException if an I/O error occurs - */ - public void testDecoderWithEOL() throws IOException - { - //Test data: 24x3 pixels encoded - byte[] data = fromBinary("10011" + "000101" + "10011" + EOL - + "00110101" + "011" + "10011" + "0000111" + EOL - + "00110101" + "010" + "000111" + "010" + "0010111" + "000000" + EOL); - assertStandardDecodingResult(data); - } - - /** - * Tests the decoder with RTC and byte alignment. - * @throws IOException if an I/O error occurs - */ - public void testDecoderAlignedWithRTC() throws IOException - { - //Test data: 24x3 pixels encoded - byte[] data = fromBinary("1001100010110011" + EOL - + "00110101011100110000111" + "0" + EOL - + "001101010100001110100010111000000" + "00000" + RTC); - assertStandardDecodingResult(data); - } - - /** - * Tests the decoder with an initial EOL. - * @throws IOException if an I/O error occurs - */ - public void testDecoderInitialEOL() throws IOException - { - //Test data: 24x3 pixels encoded - byte[] data = fromBinary("000" + EOL + "1001100010110011" + EOL - + "00110101011100110000111" + EOL - + "001101010100001110100010111000000"); - assertStandardDecodingResult(data); - } - - private void assertStandardDecodingResult(byte[] data) throws IOException - { - int columns = 24; - - byte[] decoded = decode(data, columns); - - if (DEBUG) - { - dumpBitmap(decoded, columns); - System.out.println(PackedBitArray.toBitString(decoded)); - } - - assertEquals(9, decoded.length); - assertEquals("000000001111111100000000" - + "111100000000111111111111" - + "101000000000000000000000", toBitString(decoded)); - } - - /** - * Tests the decoder with a restriction in the number of rows. - * @throws IOException if an I/O error occurs - */ - public void testDecoderRowsRestriction() throws IOException - { - //Test data: 24x3 pixels encoded - byte[] data = fromBinary("10011" + "000101" + "10011" - + "00110101" + "011" + "10011" + "0000111" - + "00110101" + "010" + "000111" + "010" + "0010111" + "000000"); - int columns = 24; - int rows = 2; //We actually have data for three rows. Just checking the restriction. - - CCITTFaxG31DDecodeInputStream decoder = new CCITTFaxG31DDecodeInputStream( - new ByteArrayInputStream(data), columns, rows, false); - byte[] decoded = IOUtils.toByteArray(decoder); - decoder.close(); - - if (DEBUG) - { - dumpBitmap(decoded, columns); - System.out.println(PackedBitArray.toBitString(decoded)); - } - - assertEquals(6, decoded.length); - assertEquals("000000001111111100000000" - + "111100000000111111111111", toBitString(decoded)); - } - - /** - * Tests the decoder with white lines. - * @throws IOException if an I/O error occurs - */ - public void testDecoderWhiteLines() throws IOException - { - //Test data: 1728x3 pixels encoded (all white) - byte[] data = fromBinary(EOL + "010011011" + "00110101" //EOL + w1728 (make-up) + w0 - + EOL + "010011011" + "00110101" - + EOL + "010011011" + "00110101" + RTC); - int columns = 1728; - - byte[] decoded = decode(data, columns); - - if (DEBUG) - { - dumpBitmap(decoded, columns); - } - - assertEquals(columns * 3 / 8, decoded.length); - } - - /** - * Decodes a byte buffer. - * @param data the data - * @param columns the number of columns - * @return the decoded bits/pixels - * @throws IOException if an I/O error occurs - */ - public static byte[] decode(byte[] data, int columns) throws IOException - { - CCITTFaxG31DDecodeInputStream decoder = new CCITTFaxG31DDecodeInputStream( - new ByteArrayInputStream(data), columns, false); - byte[] decoded = IOUtils.toByteArray(decoder); - decoder.close(); - return decoded; - } - - private byte[] fromBinary(String binary) - { - ByteArrayOutputStream baout = new ByteArrayOutputStream(); - int pos = 0; - while (pos < binary.length() - 8) - { - int v = Integer.parseInt(binary.substring(pos, pos + 8), 2); - baout.write(v & 0xFF); - pos += 8; - } - int rest = binary.length() - pos; - if (rest > 0) - { - String f = binary.substring(pos) + "00000000".substring(rest); - baout.write(Integer.parseInt(f, 2)); - } - return baout.toByteArray(); - } - -} diff --git a/pdfbox/src/test/java/org/apache/pdfbox/filter/ccitt/TestPackedBitArray.java b/pdfbox/src/test/java/org/apache/pdfbox/filter/ccitt/TestPackedBitArray.java deleted file mode 100644 index 5265bf67246..00000000000 --- a/pdfbox/src/test/java/org/apache/pdfbox/filter/ccitt/TestPackedBitArray.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* $Id$ */ - -package org.apache.pdfbox.filter.ccitt; - -import junit.framework.TestCase; - -/** - * This is a unit test for {@link PackedBitArray}. - */ -public class TestPackedBitArray extends TestCase -{ - - /** - * Tests the {@link PackedBitArray} class. - */ - public void testPackedBitArray() - { - PackedBitArray bits = new PackedBitArray(19); - assertEquals(19, bits.getBitCount()); - assertEquals(3, bits.getByteCount()); - assertEquals("0000000000000000000", bits.toString()); - - bits.set(1); - assertEquals("0100000000000000000", bits.toString()); - - bits.clear(1); - assertEquals("0000000000000000000", bits.toString()); - - bits.setBits(4, 4); - assertEquals("0000111100000000000", bits.toString()); - - bits.setBits(2, 1); - assertEquals("0010111100000000000", bits.toString()); - - bits.setBits(9, 9, 1); - assertEquals("0010111101111111110", bits.toString()); - - bits.clearBits(15, 2); - assertEquals("0010111101111110010", bits.toString()); - - bits.setBits(9, 9, 0); - assertEquals("0010111100000000000", bits.toString()); - - bits.clear(); - assertEquals("0000000000000000000", bits.toString()); - - bits.setBits(1, 18); - assertEquals("0111111111111111111", bits.toString()); - - bits.clearBits(3, 1); - assertEquals("0110111111111111111", bits.toString()); - - try - { - bits.setBits(1, 19); - fail("Expecting IndexOutOfBoundsException"); - } - catch (IndexOutOfBoundsException e) - { - //good - } - } - -} diff --git a/pdfbox/src/test/java/org/apache/pdfbox/filter/ccitt/package.html b/pdfbox/src/test/java/org/apache/pdfbox/filter/ccitt/package.html deleted file mode 100644 index 975173e46e1..00000000000 --- a/pdfbox/src/test/java/org/apache/pdfbox/filter/ccitt/package.html +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - -This package contains classes testing the CCITT encoders and decoders. - - From e9f444bde028751d9db72951b5185f65457fa12a Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Tue, 31 May 2016 06:43:47 +0000 Subject: [PATCH 0103/2182] PDFBOX-3369: more general workaround for certain broken floats git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1746238 13f79535-47bb-0310-9956-ffa450edef68 --- pdfbox/src/main/java/org/apache/pdfbox/cos/COSFloat.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/cos/COSFloat.java b/pdfbox/src/main/java/org/apache/pdfbox/cos/COSFloat.java index 6d696bb1c21..43cf73cfc66 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/cos/COSFloat.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/cos/COSFloat.java @@ -61,13 +61,13 @@ public COSFloat( String aFloat ) throws IOException } catch( NumberFormatException e ) { - if (aFloat.startsWith("0.00000-")) + if (aFloat.matches("^0\\.0+\\-\\d+")) { // PDFBOX-2990 has 0.00000-33917698 - // Let's wait what other floats will be coming before doing a more general workaround. + // PDFBOX-3369 has 0.00-35095424 try { - valueAsString = "-0.00000" + aFloat.substring(8); + valueAsString = "-" + valueAsString.replaceFirst("\\-", ""); value = new BigDecimal(valueAsString); checkMinMaxValues(); } From 255fa8d2cf87ba2f439add854b0b2390fc2e471f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Lehmk=C3=BChler?= Date: Mon, 6 Jun 2016 16:46:39 +0000 Subject: [PATCH 0104/2182] prepare 2.0.2 release git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1747038 13f79535-47bb-0310-9956-ffa450edef68 --- RELEASE-NOTES.txt | 51 ++++++++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt index ea785c48e8b..135df2c9b19 100644 --- a/RELEASE-NOTES.txt +++ b/RELEASE-NOTES.txt @@ -1,11 +1,11 @@ -Release Notes -- Apache PDFBox -- Version 2.0.1 +Release Notes -- Apache PDFBox -- Version 2.0.2 Introduction ------------ The Apache PDFBox library is an open source Java tool for working with PDF documents. -This is an incremental bugfix release based on the earlier 2.0.0 release. It contains +This is an incremental bugfix release based on the earlier 2.0.1 release. It contains a couple of fixes and small improvements. For more details on these changes and all the other fixes and improvements @@ -14,30 +14,35 @@ PDFBox issue tracker at https://issues.apache.org/jira/browse/PDFBOX. Bug -[PDFBOX-3272] - Loaded fonts file descriptors open after closing document -[PDFBOX-3273] - Fonts not rendered correctly -[PDFBOX-3276] - Double encryption dictionary for files with XRef stream -[PDFBOX-3279] - PDDocument.importPage creates two inputstreams -[PDFBOX-3281] - HTML output wrongly specifies UTF-16 in header -[PDFBOX-3286] - Think I found a bad constant (TTF) value and constant use in PDFBox source -[PDFBOX-3292] - Error reading stream, expected='endstream' actual='' in non-truncated files -[PDFBOX-3297] - Infinite loop -[PDFBOX-3299] - TIFF-files with FillOrder=2 can't be converted to PDF -[PDFBOX-3301] - NPE in PDAcroForm.flatten if a widget doesn't contain a /P entry -[PDFBOX-3303] - setWidgets should set connection to parent -[PDFBOX-3308] - Missing endOfName chars -[PDFBOX-3312] - NPE in saveIncremental() / fix javadoc -[PDFBOX-3317] - Merged PDF/A files no longer valid PDF/A -[PDFBOX-3319] - Chinese character overlap other chinese character +[PDFBOX-3267] - Using threads results in different images +[PDFBOX-3326] - Issue in RenderingMode.isStroke method +[PDFBOX-3327] - IndexOutOfBoundsException when retrieving kerning information +[PDFBOX-3332] - Apache PDFBox Form Fill TrueType text spacing issue +[PDFBOX-3333] - Wrong appearance generation for rotated AcroForms fields +[PDFBOX-3336] - several errors in the incremental save +[PDFBOX-3338] - CCITT Fax decoder fails +[PDFBOX-3341] - currentAccessPermission.setReadOnly() not set in StandardSecurityHandler +[PDFBOX-3346] - Create example with empty signature +[PDFBOX-3347] - COSName parsing doesn't handle ISO-8859-1 encoded bytes +[PDFBOX-3348] - NPE in Type1Parser.parseBinary +[PDFBOX-3351] - NPE when drawing annotation with empty border color array +[PDFBOX-3354] - PDCIDFont.getAverageFontWidth always returns 0 +[PDFBOX-3355] - PDPageLabels.getLabelsByPageIndices() returns Uppercase letters for style a +[PDFBOX-3360] - java.lang.IllegalArgumentException: dash lengths all zero +[PDFBOX-3362] - PageLayout.TwoColumnRight was Illegal +[PDFBOX-3363] - Leftover file in temp directory when signing +[PDFBOX-3368] - ContainsKey don't work for the Map returned by PDStructureTreeRoot.getRoleMap +[PDFBOX-3369] - Error expected floating point number actual='0.00-35095424' Improvement -[PDFBOX-3275] - Show glyph bounds in DrawPrintTextLocations -[PDFBOX-3289] - Wrong unit MM_PER_INCH in PDRectangle -[PDFBOX-3295] - Improve parsing performance of object streams -[PDFBOX-3305] - PDPageContentStream should allow drawing images at current position -[PDFBOX-3307] - Enable AES128 encryption -[PDFBOX-3323] - Cannot set destination meta data in PDFMergerUtility +[PDFBOX-3089] - Investigate why glyph path caching does not always cache glyph accesses +[PDFBOX-3316] - Add comment to PDF +[PDFBOX-3329] - Create PDFMergerUtility example with improved metadata handling +[PDFBOX-3342] - Add example to jump to a local page to AddAnnotations +[PDFBOX-3352] - Calendar values are parsed with unknown timezones +[PDFBOX-3364] - PDModel.getSignatureFields() only returns top level signature fields + Release Contents ---------------- From 01680c1d90678aed683f8ce89246c60b327f0e6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Lehmk=C3=BChler?= Date: Mon, 6 Jun 2016 17:06:30 +0000 Subject: [PATCH 0105/2182] PDFBOX-3338: add rat exception git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1747040 13f79535-47bb-0310-9956-ffa450edef68 --- pdfbox/pom.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pdfbox/pom.xml b/pdfbox/pom.xml index d05554bd036..b31a7555e56 100644 --- a/pdfbox/pom.xml +++ b/pdfbox/pom.xml @@ -154,6 +154,8 @@ src/test/resources/org/apache/pdfbox/encryption/*.pfx src/test/resources/org/apache/pdfbox/filter/*.bin src/test/resources/org/apache/pdfbox/text/*.txt + src/main/java/org/apache/pdfbox/filter/CCITTFaxDecoderStream.java + src/main/java/org/apache/pdfbox/filter/TIFFExtension.java From dadf44547ad822449de5807cc711435efa39462e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Lehmk=C3=BChler?= Date: Mon, 6 Jun 2016 17:13:49 +0000 Subject: [PATCH 0106/2182] [maven-release-plugin] prepare release 2.0.2 git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1747041 13f79535-47bb-0310-9956-ffa450edef68 --- app/pom.xml | 2 +- debugger-app/pom.xml | 2 +- debugger/pom.xml | 2 +- examples/pom.xml | 2 +- fontbox/pom.xml | 2 +- parent/pom.xml | 8 ++++---- pdfbox/pom.xml | 2 +- pom.xml | 8 ++++---- preflight-app/pom.xml | 2 +- preflight/pom.xml | 2 +- tools/pom.xml | 2 +- xmpbox/pom.xml | 2 +- 12 files changed, 18 insertions(+), 18 deletions(-) diff --git a/app/pom.xml b/app/pom.xml index dc7144c67a8..63b703b2938 100644 --- a/app/pom.xml +++ b/app/pom.xml @@ -23,7 +23,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.2-SNAPSHOT + 2.0.2 ../parent/pom.xml diff --git a/debugger-app/pom.xml b/debugger-app/pom.xml index 9e0c45cc527..e9320686590 100644 --- a/debugger-app/pom.xml +++ b/debugger-app/pom.xml @@ -23,7 +23,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.2-SNAPSHOT + 2.0.2 ../parent/pom.xml diff --git a/debugger/pom.xml b/debugger/pom.xml index 88c56defcd0..0d1f1d0ca73 100644 --- a/debugger/pom.xml +++ b/debugger/pom.xml @@ -23,7 +23,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.2-SNAPSHOT + 2.0.2 ../parent/pom.xml diff --git a/examples/pom.xml b/examples/pom.xml index 1faf4c07ff6..f901af2d6d7 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -23,7 +23,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.2-SNAPSHOT + 2.0.2 ../parent/pom.xml diff --git a/fontbox/pom.xml b/fontbox/pom.xml index f059397f8f2..b18d8d43d00 100644 --- a/fontbox/pom.xml +++ b/fontbox/pom.xml @@ -21,7 +21,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.2-SNAPSHOT + 2.0.2 ../parent/pom.xml diff --git a/parent/pom.xml b/parent/pom.xml index 54cd845d502..4028c887533 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -29,7 +29,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.2-SNAPSHOT + 2.0.2 pom PDFBox parent @@ -377,8 +377,8 @@ - scm:svn:http://svn.apache.org/repos/asf/maven/pom/branches/2.0/pdfbox-parent - scm:svn:https://svn.apache.org/repos/asf/maven/pom/branches/2.0/pdfbox-parent - http://svn.apache.org/viewvc/maven/pom/branches/2.0/pdfbox-parent + scm:svn:http://svn.apache.org/repos/asf/maven/pom/tags/2.0.2/pdfbox-parent + scm:svn:https://svn.apache.org/repos/asf/maven/pom/tags/2.0.2/pdfbox-parent + http://svn.apache.org/viewvc/maven/pom/tags/2.0.2/pdfbox-parent diff --git a/pdfbox/pom.xml b/pdfbox/pom.xml index b31a7555e56..e6233fc1bb3 100644 --- a/pdfbox/pom.xml +++ b/pdfbox/pom.xml @@ -23,7 +23,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.2-SNAPSHOT + 2.0.2 ../parent/pom.xml diff --git a/pom.xml b/pom.xml index b5ed02fdf53..e4e95cf2e61 100644 --- a/pom.xml +++ b/pom.xml @@ -23,7 +23,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.2-SNAPSHOT + 2.0.2 parent/pom.xml @@ -34,12 +34,12 @@ - scm:svn:http://svn.apache.org/repos/asf/pdfbox/branches/2.0 + scm:svn:http://svn.apache.org/repos/asf/pdfbox/tags/2.0.2 - scm:svn:https://svn.apache.org/repos/asf/pdfbox/branches/2.0 + scm:svn:https://svn.apache.org/repos/asf/pdfbox/tags/2.0.2 - http://svn.apache.org/viewvc/pdfbox/branches/2.0 + http://svn.apache.org/viewvc/pdfbox/tags/2.0.2 diff --git a/preflight-app/pom.xml b/preflight-app/pom.xml index 8afec57668e..12351432fc1 100644 --- a/preflight-app/pom.xml +++ b/preflight-app/pom.xml @@ -23,7 +23,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.2-SNAPSHOT + 2.0.2 ../parent/pom.xml diff --git a/preflight/pom.xml b/preflight/pom.xml index 9f8c4ff59df..4ed18942489 100644 --- a/preflight/pom.xml +++ b/preflight/pom.xml @@ -26,7 +26,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.2-SNAPSHOT + 2.0.2 ../parent/pom.xml diff --git a/tools/pom.xml b/tools/pom.xml index 291612a973c..f159f8f27c0 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -23,7 +23,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.2-SNAPSHOT + 2.0.2 ../parent/pom.xml diff --git a/xmpbox/pom.xml b/xmpbox/pom.xml index 84ff8d6ffd3..75e0d42213c 100644 --- a/xmpbox/pom.xml +++ b/xmpbox/pom.xml @@ -27,7 +27,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.2-SNAPSHOT + 2.0.2 ../parent/pom.xml From ed7fc0486470eedf11d63e3f41a3df7c452f6a62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Lehmk=C3=BChler?= Date: Mon, 6 Jun 2016 17:14:07 +0000 Subject: [PATCH 0107/2182] [maven-release-plugin] prepare for next development iteration git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1747043 13f79535-47bb-0310-9956-ffa450edef68 --- app/pom.xml | 2 +- debugger-app/pom.xml | 2 +- debugger/pom.xml | 2 +- examples/pom.xml | 2 +- fontbox/pom.xml | 2 +- parent/pom.xml | 8 ++++---- pdfbox/pom.xml | 2 +- pom.xml | 8 ++++---- preflight-app/pom.xml | 2 +- preflight/pom.xml | 2 +- tools/pom.xml | 2 +- xmpbox/pom.xml | 2 +- 12 files changed, 18 insertions(+), 18 deletions(-) diff --git a/app/pom.xml b/app/pom.xml index 63b703b2938..c69d9d1809b 100644 --- a/app/pom.xml +++ b/app/pom.xml @@ -23,7 +23,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.2 + 2.0.3-SNAPSHOT ../parent/pom.xml diff --git a/debugger-app/pom.xml b/debugger-app/pom.xml index e9320686590..67142bf9c53 100644 --- a/debugger-app/pom.xml +++ b/debugger-app/pom.xml @@ -23,7 +23,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.2 + 2.0.3-SNAPSHOT ../parent/pom.xml diff --git a/debugger/pom.xml b/debugger/pom.xml index 0d1f1d0ca73..09e9d92fe62 100644 --- a/debugger/pom.xml +++ b/debugger/pom.xml @@ -23,7 +23,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.2 + 2.0.3-SNAPSHOT ../parent/pom.xml diff --git a/examples/pom.xml b/examples/pom.xml index f901af2d6d7..a29b129af8a 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -23,7 +23,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.2 + 2.0.3-SNAPSHOT ../parent/pom.xml diff --git a/fontbox/pom.xml b/fontbox/pom.xml index b18d8d43d00..9d5769dc404 100644 --- a/fontbox/pom.xml +++ b/fontbox/pom.xml @@ -21,7 +21,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.2 + 2.0.3-SNAPSHOT ../parent/pom.xml diff --git a/parent/pom.xml b/parent/pom.xml index 4028c887533..569caaf3299 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -29,7 +29,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.2 + 2.0.3-SNAPSHOT pom PDFBox parent @@ -377,8 +377,8 @@ - scm:svn:http://svn.apache.org/repos/asf/maven/pom/tags/2.0.2/pdfbox-parent - scm:svn:https://svn.apache.org/repos/asf/maven/pom/tags/2.0.2/pdfbox-parent - http://svn.apache.org/viewvc/maven/pom/tags/2.0.2/pdfbox-parent + scm:svn:http://svn.apache.org/repos/asf/maven/pom/branches/2.0/pdfbox-parent + scm:svn:https://svn.apache.org/repos/asf/maven/pom/branches/2.0/pdfbox-parent + http://svn.apache.org/viewvc/maven/pom/branches/2.0/pdfbox-parent diff --git a/pdfbox/pom.xml b/pdfbox/pom.xml index e6233fc1bb3..ab15a53c810 100644 --- a/pdfbox/pom.xml +++ b/pdfbox/pom.xml @@ -23,7 +23,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.2 + 2.0.3-SNAPSHOT ../parent/pom.xml diff --git a/pom.xml b/pom.xml index e4e95cf2e61..d633a3f9168 100644 --- a/pom.xml +++ b/pom.xml @@ -23,7 +23,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.2 + 2.0.3-SNAPSHOT parent/pom.xml @@ -34,12 +34,12 @@ - scm:svn:http://svn.apache.org/repos/asf/pdfbox/tags/2.0.2 + scm:svn:http://svn.apache.org/repos/asf/pdfbox/branches/2.0 - scm:svn:https://svn.apache.org/repos/asf/pdfbox/tags/2.0.2 + scm:svn:https://svn.apache.org/repos/asf/pdfbox/branches/2.0 - http://svn.apache.org/viewvc/pdfbox/tags/2.0.2 + http://svn.apache.org/viewvc/pdfbox/branches/2.0 diff --git a/preflight-app/pom.xml b/preflight-app/pom.xml index 12351432fc1..85d481fef22 100644 --- a/preflight-app/pom.xml +++ b/preflight-app/pom.xml @@ -23,7 +23,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.2 + 2.0.3-SNAPSHOT ../parent/pom.xml diff --git a/preflight/pom.xml b/preflight/pom.xml index 4ed18942489..21261777ec8 100644 --- a/preflight/pom.xml +++ b/preflight/pom.xml @@ -26,7 +26,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.2 + 2.0.3-SNAPSHOT ../parent/pom.xml diff --git a/tools/pom.xml b/tools/pom.xml index f159f8f27c0..859438f0ba4 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -23,7 +23,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.2 + 2.0.3-SNAPSHOT ../parent/pom.xml diff --git a/xmpbox/pom.xml b/xmpbox/pom.xml index 75e0d42213c..93d5e57c3ce 100644 --- a/xmpbox/pom.xml +++ b/xmpbox/pom.xml @@ -27,7 +27,7 @@ org.apache.pdfbox pdfbox-parent - 2.0.2 + 2.0.3-SNAPSHOT ../parent/pom.xml From 55aa98ba8083627f1989c990db2df73db645082d Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Tue, 7 Jun 2016 15:50:45 +0000 Subject: [PATCH 0108/2182] PDFBOX-3017: enable verify git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1747263 13f79535-47bb-0310-9956-ffa450edef68 --- .../examples/pdmodel/TestCreateSignature.java | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/examples/src/test/java/org/apache/pdfbox/examples/pdmodel/TestCreateSignature.java b/examples/src/test/java/org/apache/pdfbox/examples/pdmodel/TestCreateSignature.java index 8be4830187c..93fcdbd8b0c 100644 --- a/examples/src/test/java/org/apache/pdfbox/examples/pdmodel/TestCreateSignature.java +++ b/examples/src/test/java/org/apache/pdfbox/examples/pdmodel/TestCreateSignature.java @@ -47,6 +47,7 @@ import org.bouncycastle.cms.CMSProcessableByteArray; import org.bouncycastle.cms.CMSSignedData; import org.bouncycastle.cms.SignerInformation; +import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder; import org.bouncycastle.operator.OperatorCreationException; import org.bouncycastle.tsp.TSPValidationException; import org.bouncycastle.util.Store; @@ -218,16 +219,15 @@ private void checkSignature(File file) assertEquals(certificate, certFromSignedData); - // code below doesn't work - maybe because the signature can indeed not be verified? - -// if (signerInformation.verify(new JcaSimpleSignerInfoVerifierBuilder().build(certFromSignedData))) -// { -// System.out.println("Signature verified"); -// } -// else -// { -// System.out.println("Signature verification failed"); -// } + // CMSVerifierCertificateNotValidException means that the keystore wasn't valid at signing time + if (signerInformation.verify(new JcaSimpleSignerInfoVerifierBuilder().build(certFromSignedData))) + { + System.out.println("Signature verified"); + } + else + { + System.out.println("Signature verification failed"); + } break; } From 942ed91ad54a1307a99ca608d41d4c7e8f7ce006 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Tue, 7 Jun 2016 15:55:35 +0000 Subject: [PATCH 0109/2182] PDFBOX-3017: replace keystore with one that is valid git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1747265 13f79535-47bb-0310-9956-ffa450edef68 --- .../pdfbox/examples/signature/keystore.p12 | Bin 2608 -> 2608 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/examples/src/test/resources/org/apache/pdfbox/examples/signature/keystore.p12 b/examples/src/test/resources/org/apache/pdfbox/examples/signature/keystore.p12 index a4d24bf59d8f397e3962e0e300d170e3440093b6..ee7d8065dc951e4ecb1826565ad7a84c44c2e538 100644 GIT binary patch delta 2447 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 N0ys(J5RU=^1OULjm}dY0 delta 2447 zcmV;A32^qX6tEPKXn%GtIu`vjs7Xz80Xyz8aSmn8>b?R31ONnr1jy@a{A=sxwm0iZ z4f@{OV>3BqsHdaxpd3)fz5J+QiKck|7vN(1T2m^5*(bd#})Q6~eoBLed_WI{`vBI!cu! z_P9EP%3WRz2o3bHbuU8BKt<(x3ZaEn0o0eiYmBTx+tErJeb$-5x7Om>k~usInbrH< z)4VBZ&ILz$!GF$TiDTqd^Se;@EP_Ho@Iy%7pIk>G8@Y`7UoV>DfHmNxE-oG)IKF%2 z{Lz16?B2bOuBRu5F?G$|MhmDZ(&+1>cxDMH0Rl&cC;`vD_yz(8V!jKfX{R2aikZN2 ztro|qrqhzdEalw)9NQ+6PqcBM!{+9x+EvzoLJf-DWPgA_6p{~a1P7tTP|`L?YVs{1 z8bmoJUbK(RgB#Ruxy$9l_+e~@8(x%#Krh*u@`n1qz(P@~qJ4p&-5FsAl`nz81sRS3FU&H*p9O()(aXg%WPGKRl-)hHvNYT*3vQiF z75K_~IWq8h4ln1@Fg4t|)9I)!U<~mF7`YVmDXp*Cp?fy*L zdrb}ZqN-eTj$dyz7e@u?lgrqUcgaUw4^afv8B_vBI3|80w zFhC2ir&hm!mqao@F9|+Q&t}GW|wtx zpJxiOajD2QDIun1G9p~oubh=W@!j>-u&i><7gOE61c5UF5?MGfqe7r(y}!o=n}0c2 zJ6s-0mjv<~r(5c7P>Jt(Qx^!WD1_@}c8>Zn&Tr5D83rD)nsR=Vf_{!nWbov#iHBhjx@v+tYoQW#$zMy{qNhKqtYn& zlLed1%BY5Pl=bi3PV&~F=Ch7Y3V)7Uorw*Uc<6_zaYwXxXi>qW==FHou1BfMF)#hZ zD-<-skBNT&^oVi~AiWt7CSq3P9@}38Zkbt>*}C%_CBDYSneeJ7ulm~k6B~1dc_(9> zfY0XhF3>Sa54RAU7IWRnQ^zwsL;=90jPXCW| z{<%#I(`EjJL!sXk=g?dnLQA2rJSCH{Yu9Ebn9P+aMSQ-v(=_GLspO>{co9@aD+Wy( z3mr;kSSl@`U(y8J$YNfiLmr9UT}#|vKn=Mc``vTV`j};qRM~%3GFXGIe}9c#qDSv} zq1np=Q@uP0bzq6qSbcvi1bbZp_`Ivc3r!NgMO)_rfhzUE50`Al6CpuIH_OJDw%-^7 zQsSg@;%4HMlZit_{B`tS&qB z)&}b`AQPB~rS5-B&GLYliC;QRe^f{^UR&p_NGA_03I)8_^v{!1keMD6Uh_T@KY`h86~)yvw#BEC0C8W@tJQ5WVa2|f zYWC}KodnL%F=Md?GCvtHSi|^}c6#dSl9E)zCOLhG>V|(xYRQ0{DIuy+eT86(TKkU% z71Y&OCydZ=|LiB)d_(5+^AmXfR|TIYT?E#8sAe|anFm+9d2x|}`qwWMTs16o@lnPYRE)pYcmRzJ zUm4HD1RH;;Vw3 zru%Zy&2h9K0z`qOe5^!ZO1V{lLU2wAGfuo!K6HQEGuA>8^>4!0_LwaSCz959?UPj5sJM7}eUY2Z~HfpNGh#zSXV9#|8b`-HZb5 zS`~ay5k&mMg*`$9iVe)tXi$~*lJ{g>|`CSJ-S@b$Ug(m-LG@2LNhCY!XTs(8a3* z^Te-4L9kemdPjN2zW9;o4gO1TRrv7@zQ+Co`0b1Hz}^-OY1{1nB+9U5X!Z{p_tJBV z$^rP|ZmN^cmD0O5bCTyIWG-Hjv2aTC@{|o0lp^)T$gguD$FMWqL6cLQ1RE7b$Z5kc zJuo3K2?hl#4g&%j1povTi~R%UVw2-Udjs+AbZFWBdQGdL1Qbq#-0IL%X*%987=Pd= NLH(cARXYL#1OO2qwsQag From c1ec0b5a863264aaa54063e87817250e8ddd4124 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Tue, 7 Jun 2016 16:33:39 +0000 Subject: [PATCH 0110/2182] PDFBOX-3017: add simple verify for adbe.pkcs7.detached signatures git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1747269 13f79535-47bb-0310-9956-ffa450edef68 --- .../examples/signature/ShowSignature.java | 162 ++++++++++++------ 1 file changed, 112 insertions(+), 50 deletions(-) diff --git a/examples/src/main/java/org/apache/pdfbox/examples/signature/ShowSignature.java b/examples/src/main/java/org/apache/pdfbox/examples/signature/ShowSignature.java index bb8efdb6b01..fa13108bbd6 100644 --- a/examples/src/main/java/org/apache/pdfbox/examples/signature/ShowSignature.java +++ b/examples/src/main/java/org/apache/pdfbox/examples/signature/ShowSignature.java @@ -19,16 +19,33 @@ import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; +import java.io.RandomAccessFile; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.SignatureException; import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.text.SimpleDateFormat; import java.util.Collection; -import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.cos.COSString; import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature; +import org.bouncycastle.cert.X509CertificateHolder; +import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; +import org.bouncycastle.cms.CMSException; +import org.bouncycastle.cms.CMSProcessable; +import org.bouncycastle.cms.CMSProcessableByteArray; +import org.bouncycastle.cms.CMSSignedData; +import org.bouncycastle.cms.SignerInformation; +import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder; +import org.bouncycastle.operator.OperatorCreationException; +import org.bouncycastle.util.Store; /** * This will read a document from the filesystem, decrypt it and do something with the signature. @@ -37,6 +54,8 @@ */ public final class ShowSignature { + private static SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.yyyy HH:mm:ss"); + private ShowSignature() { } @@ -48,14 +67,22 @@ private ShowSignature() * * @throws IOException If there is an error reading the file. * @throws CertificateException + * @throws java.security.NoSuchAlgorithmException + * @throws java.security.InvalidKeyException + * @throws java.security.NoSuchProviderException + * @throws java.security.SignatureException */ - public static void main( String[] args ) throws IOException, CertificateException + public static void main(String[] args) throws IOException, CertificateException, + NoSuchAlgorithmException, InvalidKeyException, + NoSuchProviderException, SignatureException { ShowSignature show = new ShowSignature(); show.showSignature( args ); } - private void showSignature( String[] args ) throws IOException, CertificateException + private void showSignature(String[] args) throws IOException, CertificateException, + NoSuchAlgorithmException, InvalidKeyException, + NoSuchProviderException, SignatureException { if( args.length != 2 ) { @@ -68,71 +95,106 @@ private void showSignature( String[] args ) throws IOException, CertificateExcep PDDocument document = null; try { - document = PDDocument.load( new File(infile), password ); - if( !document.isEncrypted() ) + document = PDDocument.load(new File(infile), password); + for (PDSignature sig : document.getSignatureDictionaries()) { - System.err.println( "Warning: Document is not encrypted." ); - } + COSDictionary sigDict = sig.getCOSObject(); + COSString contents = (COSString) sigDict.getDictionaryObject(COSName.CONTENTS); - COSDictionary trailer = document.getDocument().getTrailer(); - COSDictionary root = (COSDictionary)trailer.getDictionaryObject( COSName.ROOT ); - COSDictionary acroForm = (COSDictionary)root.getDictionaryObject( COSName.ACRO_FORM ); - COSArray fields = (COSArray)acroForm.getDictionaryObject( COSName.FIELDS ); - for( int i=0; i certs = factory.generateCertificates( certStream ); - System.out.println( "certs=" + certs ); - } - else if( subFilter.getName().equals( "adbe.pkcs7.sha1" ) ) - { - COSString certString = (COSString)cert.getDictionaryObject( - COSName.CONTENTS ); - byte[] certData = certString.getBytes(); - CertificateFactory factory = CertificateFactory.getInstance( "X.509" ); - ByteArrayInputStream certStream = new ByteArrayInputStream( certData ); - Collection certs = factory.generateCertificates( certStream ); - System.out.println( "certs=" + certs ); - } - else - { - System.err.println( "Unknown certificate type:" + subFilter ); - } + System.out.println("Signature verified"); } else { - throw new IOException( "Missing subfilter for cert dictionary" ); + System.out.println("Signature verification failed"); } + + //TODO check certificate chain, revocation lists, timestamp... + } + else if (subFilter.equals("adbe.x509.rsa_sha1")) + { + // PDFBOX-2693.pdf + COSString certString = (COSString) sigDict.getDictionaryObject( + COSName.getPDFName("Cert")); + byte[] certData = certString.getBytes(); + CertificateFactory factory = CertificateFactory.getInstance("X.509"); + ByteArrayInputStream certStream = new ByteArrayInputStream(certData); + Collection certs = factory.generateCertificates(certStream); + System.out.println("certs=" + certs); + + //TODO verify signature + } + else if (subFilter.equals("adbe.pkcs7.sha1")) + { + // PDFBOX-1452.pdf + COSString certString = (COSString) sigDict.getDictionaryObject( + COSName.CONTENTS); + byte[] certData = certString.getBytes(); + CertificateFactory factory = CertificateFactory.getInstance("X.509"); + ByteArrayInputStream certStream = new ByteArrayInputStream(certData); + Collection certs = factory.generateCertificates(certStream); + System.out.println("certs=" + certs); + + //TODO verify signature } else { - System.out.println( "Signature found, but no certificate" ); + System.err.println("Unknown certificate type: " + subFilter); } } + else + { + throw new IOException("Missing subfilter for cert dictionary"); + } } } + catch (CMSException ex) + { + throw new IOException(ex); + } + catch (OperatorCreationException ex) + { + throw new IOException(ex); + } finally { - if( document != null ) + if (document != null) { document.close(); } From c10435904a21110a8fe8cab612c8a485dbfa25bc Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Tue, 7 Jun 2016 17:13:02 +0000 Subject: [PATCH 0111/2182] PDFBOX-3017: check that certificate is valid before signing git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1747272 13f79535-47bb-0310-9956-ffa450edef68 --- .../examples/signature/CreateSignature.java | 16 ++++++++++++---- .../signature/CreateVisibleSignature.java | 16 ++++++++++++++-- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateSignature.java b/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateSignature.java index cc663d46ce0..5ed771a4a4e 100644 --- a/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateSignature.java +++ b/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateSignature.java @@ -31,6 +31,8 @@ import java.security.PrivateKey; import java.security.UnrecoverableKeyException; import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Calendar; import java.util.Enumeration; @@ -68,14 +70,15 @@ public class CreateSignature extends CreateSignatureBase /** * Initialize the signature creator with a keystore and certficate password. - * @param keystore the keystore containing the signing certificate + * @param keystore the pkcs12 keystore containing the signing certificate * @param password the password for recovering the key * @throws KeyStoreException if the keystore has not been initialized (loaded) * @throws NoSuchAlgorithmException if the algorithm for recovering the key cannot be found * @throws UnrecoverableKeyException if the given password is wrong + * @throws CertificateException if the certificate is not valid as signing time */ public CreateSignature(KeyStore keystore, char[] password) - throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException + throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, CertificateException { // grabs the first alias from the keystore and get the private key. An // TODO alternative method or constructor could be used for setting a specific @@ -91,8 +94,13 @@ public CreateSignature(KeyStore keystore, char[] password) throw new KeyStoreException("Keystore is empty"); } setPrivateKey((PrivateKey) keystore.getKey(alias, password)); - Certificate[] certificateChain = keystore.getCertificateChain(alias); - setCertificate(certificateChain[0]); + Certificate cert = keystore.getCertificateChain(alias)[0]; + setCertificate(cert); + if (cert instanceof X509Certificate) + { + // avoid expired certificate + ((X509Certificate) cert).checkValidity(); + } } /** diff --git a/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateVisibleSignature.java b/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateVisibleSignature.java index 3605435884a..796b8703116 100644 --- a/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateVisibleSignature.java +++ b/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateVisibleSignature.java @@ -25,7 +25,9 @@ import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.UnrecoverableKeyException; +import java.security.cert.Certificate; import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; import java.util.Calendar; import java.util.Enumeration; import org.apache.pdfbox.io.IOUtils; @@ -73,9 +75,13 @@ public void setSignatureProperties(String name, String location, String reason, * * @param keystore is a pkcs12 keystore. * @param pin is the pin for the keystore / private key + * @throws KeyStoreException if the keystore has not been initialized (loaded) + * @throws NoSuchAlgorithmException if the algorithm for recovering the key cannot be found + * @throws UnrecoverableKeyException if the given password is wrong + * @throws CertificateException if the certificate is not valid as signing time */ public CreateVisibleSignature(KeyStore keystore, char[] pin) - throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, IOException + throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, IOException, CertificateException { // grabs the first alias from the keystore and get the private key. An // alternative method or constructor could be used for setting a specific @@ -91,7 +97,13 @@ public CreateVisibleSignature(KeyStore keystore, char[] pin) throw new IOException("Could not find alias"); } setPrivateKey((PrivateKey) keystore.getKey(alias, pin)); - setCertificate(keystore.getCertificateChain(alias)[0]); + Certificate cert = keystore.getCertificateChain(alias)[0]; + setCertificate(cert); + if (cert instanceof X509Certificate) + { + // avoid expired certificate + ((X509Certificate) cert).checkValidity(); + } } /** From 2d9d4f300a42fe89e66b80878ffc96c9c246f6fb Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Tue, 7 Jun 2016 20:32:27 +0000 Subject: [PATCH 0112/2182] PDFBOX-3017: add simple verify for adbe.pkcs7.sha1 signatures git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1747316 13f79535-47bb-0310-9956-ffa450edef68 --- .../examples/signature/ShowSignature.java | 86 ++++++++++++------- 1 file changed, 54 insertions(+), 32 deletions(-) diff --git a/examples/src/main/java/org/apache/pdfbox/examples/signature/ShowSignature.java b/examples/src/main/java/org/apache/pdfbox/examples/signature/ShowSignature.java index fa13108bbd6..9c2af83baca 100644 --- a/examples/src/main/java/org/apache/pdfbox/examples/signature/ShowSignature.java +++ b/examples/src/main/java/org/apache/pdfbox/examples/signature/ShowSignature.java @@ -21,12 +21,15 @@ import java.io.IOException; import java.io.RandomAccessFile; import java.security.InvalidKeyException; +import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.SignatureException; import java.security.cert.Certificate; import java.security.cert.CertificateException; +import java.security.cert.CertificateExpiredException; import java.security.cert.CertificateFactory; +import java.security.cert.CertificateNotYetValidException; import java.security.cert.X509Certificate; import java.text.SimpleDateFormat; import java.util.Collection; @@ -46,6 +49,7 @@ import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder; import org.bouncycastle.operator.OperatorCreationException; import org.bouncycastle.util.Store; +import org.bouncycastle.util.StoreException; /** * This will read a document from the filesystem, decrypt it and do something with the signature. @@ -120,57 +124,37 @@ private void showSignature(String[] args) throws IOException, CertificateExcepti { if (subFilter.equals("adbe.pkcs7.detached")) { - CMSProcessable signedContent = new CMSProcessableByteArray(buf); - - // inspiration: - // http://stackoverflow.com/a/26702631/535646 - // http://stackoverflow.com/a/9261365/535646 - CMSSignedData signedData = new CMSSignedData(signedContent, contents.getBytes()); - Store certificatesStore = signedData.getCertificates(); - Collection signers = signedData.getSignerInfos().getSigners(); - SignerInformation signerInformation = signers.iterator().next(); - Collection matches = certificatesStore.getMatches(signerInformation.getSID()); - X509CertificateHolder certificateHolder = (X509CertificateHolder) matches.iterator().next(); - X509Certificate certFromSignedData = new JcaX509CertificateConverter().getCertificate(certificateHolder); - System.out.println("certFromSignedData: " + certFromSignedData); - certFromSignedData.checkValidity(sig.getSignDate().getTime()); - - // CMSVerifierCertificateNotValidException means that the keystore wasn't valid at signing time - if (signerInformation.verify(new JcaSimpleSignerInfoVerifierBuilder().build(certFromSignedData))) - { - System.out.println("Signature verified"); - } - else - { - System.out.println("Signature verification failed"); - } + verifyPKCS7(buf, contents, sig); //TODO check certificate chain, revocation lists, timestamp... } - else if (subFilter.equals("adbe.x509.rsa_sha1")) + else if (subFilter.equals("adbe.pkcs7.sha1")) { - // PDFBOX-2693.pdf + // example: PDFBOX-1452.pdf COSString certString = (COSString) sigDict.getDictionaryObject( - COSName.getPDFName("Cert")); + COSName.CONTENTS); byte[] certData = certString.getBytes(); CertificateFactory factory = CertificateFactory.getInstance("X.509"); ByteArrayInputStream certStream = new ByteArrayInputStream(certData); Collection certs = factory.generateCertificates(certStream); System.out.println("certs=" + certs); + + byte[] hash = MessageDigest.getInstance("SHA1").digest(buf); + verifyPKCS7(hash, contents, sig); - //TODO verify signature + //TODO check certificate chain, revocation lists, timestamp... } - else if (subFilter.equals("adbe.pkcs7.sha1")) + else if (subFilter.equals("adbe.x509.rsa_sha1")) { - // PDFBOX-1452.pdf + // example: PDFBOX-2693.pdf COSString certString = (COSString) sigDict.getDictionaryObject( - COSName.CONTENTS); + COSName.getPDFName("Cert")); byte[] certData = certString.getBytes(); CertificateFactory factory = CertificateFactory.getInstance("X.509"); ByteArrayInputStream certStream = new ByteArrayInputStream(certData); Collection certs = factory.generateCertificates(certStream); System.out.println("certs=" + certs); - + //TODO verify signature } else @@ -202,6 +186,44 @@ else if (subFilter.equals("adbe.pkcs7.sha1")) } } + /** + * Verify a PKCS7 signature. + * + * @param byteArray the byte sequence that has been signed + * @param contents the /Contents field as a COSString + * @param sig the PDF signature (the /V dictionary) + * @throws CertificateException + * @throws CMSException + * @throws StoreException + * @throws OperatorCreationException + */ + private void verifyPKCS7(byte[] byteArray, COSString contents, PDSignature sig) + throws CMSException, CertificateException, StoreException, OperatorCreationException + { + // inspiration: + // http://stackoverflow.com/a/26702631/535646 + // http://stackoverflow.com/a/9261365/535646 + CMSProcessable signedContent = new CMSProcessableByteArray(byteArray); + CMSSignedData signedData = new CMSSignedData(signedContent, contents.getBytes()); + Store certificatesStore = signedData.getCertificates(); + Collection signers = signedData.getSignerInfos().getSigners(); + SignerInformation signerInformation = signers.iterator().next(); + Collection matches = certificatesStore.getMatches(signerInformation.getSID()); + X509CertificateHolder certificateHolder = (X509CertificateHolder) matches.iterator().next(); + X509Certificate certFromSignedData = new JcaX509CertificateConverter().getCertificate(certificateHolder); + System.out.println("certFromSignedData: " + certFromSignedData); + certFromSignedData.checkValidity(sig.getSignDate().getTime()); + + if (signerInformation.verify(new JcaSimpleSignerInfoVerifierBuilder().build(certFromSignedData))) + { + System.out.println("Signature verified"); + } + else + { + System.out.println("Signature verification failed"); + } + } + /** * This will print a usage message. */ From 363e7dc9851f753cb3896973c72aaaf99bf6a7ba Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Wed, 8 Jun 2016 17:05:02 +0000 Subject: [PATCH 0113/2182] PDFBOX-3017: SonarQube fixes git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1747419 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/pdfbox/examples/signature/ShowSignature.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/examples/src/main/java/org/apache/pdfbox/examples/signature/ShowSignature.java b/examples/src/main/java/org/apache/pdfbox/examples/signature/ShowSignature.java index 9c2af83baca..dadb5030578 100644 --- a/examples/src/main/java/org/apache/pdfbox/examples/signature/ShowSignature.java +++ b/examples/src/main/java/org/apache/pdfbox/examples/signature/ShowSignature.java @@ -27,9 +27,7 @@ import java.security.SignatureException; import java.security.cert.Certificate; import java.security.cert.CertificateException; -import java.security.cert.CertificateExpiredException; import java.security.cert.CertificateFactory; -import java.security.cert.CertificateNotYetValidException; import java.security.cert.X509Certificate; import java.text.SimpleDateFormat; import java.util.Collection; @@ -58,7 +56,7 @@ */ public final class ShowSignature { - private static SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.yyyy HH:mm:ss"); + private SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.yyyy HH:mm:ss"); private ShowSignature() { From 03118a7a04699786b39ca6b60b778e782b68d4ac Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Wed, 8 Jun 2016 17:06:52 +0000 Subject: [PATCH 0114/2182] PDFBOX-3373: add signature field to acroform field list git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1747421 13f79535-47bb-0310-9956-ffa450edef68 --- .../pdfbox/examples/signature/CreateEmptySignatureForm.java | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateEmptySignatureForm.java b/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateEmptySignatureForm.java index 5ab8ec4f29a..ee30777efa8 100644 --- a/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateEmptySignatureForm.java +++ b/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateEmptySignatureForm.java @@ -76,6 +76,7 @@ public static void main(String[] args) throws IOException widget.setPage(page); page.getAnnotations().add(widget); + acroForm.getFields().add(signatureField); document.save("target/EmptySignatureForm.pdf"); document.close(); From ebe06b7b094832f8f9cc8e2a66491c4b957900be Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Thu, 9 Jun 2016 17:07:53 +0000 Subject: [PATCH 0115/2182] PDFBOX-3017: simplify code by using getSignedContent() git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1747565 13f79535-47bb-0310-9956-ffa450edef68 --- .../pdfbox/examples/signature/ShowSignature.java | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/examples/src/main/java/org/apache/pdfbox/examples/signature/ShowSignature.java b/examples/src/main/java/org/apache/pdfbox/examples/signature/ShowSignature.java index dadb5030578..1c4fa0d1fd6 100644 --- a/examples/src/main/java/org/apache/pdfbox/examples/signature/ShowSignature.java +++ b/examples/src/main/java/org/apache/pdfbox/examples/signature/ShowSignature.java @@ -18,8 +18,8 @@ import java.io.ByteArrayInputStream; import java.io.File; +import java.io.FileInputStream; import java.io.IOException; -import java.io.RandomAccessFile; import java.security.InvalidKeyException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; @@ -103,16 +103,10 @@ private void showSignature(String[] args) throws IOException, CertificateExcepti COSDictionary sigDict = sig.getCOSObject(); COSString contents = (COSString) sigDict.getDictionaryObject(COSName.CONTENTS); - // download the signed content, described in /ByteRange COSArray: - // [offset1 len1 offset2 len2] - int[] byteRange = sig.getByteRange(); - byte[] buf = new byte[byteRange[1] + byteRange[3]]; - RandomAccessFile raf = new RandomAccessFile(infile, "r"); - raf.seek(byteRange[0]); - raf.readFully(buf, byteRange[0], byteRange[1]); - raf.seek(byteRange[2]); - raf.readFully(buf, byteRange[1], byteRange[3]); - raf.close(); + // download the signed content + FileInputStream fis = new FileInputStream(infile); + byte[] buf = sig.getSignedContent(fis); + fis.close(); System.out.println("Signature found"); System.out.println("Name: " + sig.getName()); From efa8b2ea43da79f151c04f30b3a37cda280aa52f Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Thu, 9 Jun 2016 17:45:22 +0000 Subject: [PATCH 0116/2182] PDFBOX-3017: simplify code by using getSignedContent() git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1747569 13f79535-47bb-0310-9956-ffa450edef68 --- .../examples/pdmodel/TestCreateSignature.java | 86 +++++++------------ 1 file changed, 31 insertions(+), 55 deletions(-) diff --git a/examples/src/test/java/org/apache/pdfbox/examples/pdmodel/TestCreateSignature.java b/examples/src/test/java/org/apache/pdfbox/examples/pdmodel/TestCreateSignature.java index 93fcdbd8b0c..bdcd6005669 100644 --- a/examples/src/test/java/org/apache/pdfbox/examples/pdmodel/TestCreateSignature.java +++ b/examples/src/test/java/org/apache/pdfbox/examples/pdmodel/TestCreateSignature.java @@ -22,7 +22,6 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; -import java.io.RandomAccessFile; import java.net.URL; import java.security.GeneralSecurityException; import java.security.KeyStore; @@ -30,8 +29,7 @@ import java.security.cert.Certificate; import java.security.cert.X509Certificate; import java.util.Collection; -import org.apache.pdfbox.cos.COSArray; -import org.apache.pdfbox.cos.COSDictionary; +import java.util.List; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.cos.COSString; @@ -40,6 +38,7 @@ import org.apache.pdfbox.examples.signature.TSAClient; import org.apache.pdfbox.io.IOUtils; import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature; import org.apache.wink.client.MockHttpServer; import org.bouncycastle.cert.X509CertificateHolder; import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; @@ -175,66 +174,43 @@ public void testCreateVisibleSignature() checkSignature(destFile); } - //TODO expand this into a full verify (if possible) // This check fails with a file created with the code before PDFBOX-3011 was solved. private void checkSignature(File file) throws IOException, CMSException, OperatorCreationException, GeneralSecurityException { PDDocument document = PDDocument.load(file); - COSDictionary trailer = document.getDocument().getTrailer(); - COSDictionary root = (COSDictionary) trailer.getDictionaryObject(COSName.ROOT); - COSDictionary acroForm = (COSDictionary) root.getDictionaryObject(COSName.ACRO_FORM); - COSArray fields = (COSArray) acroForm.getDictionaryObject(COSName.FIELDS); - COSDictionary sig = null; - for (int i = 0; i < fields.size(); i++) + List signatureDictionaries = document.getSignatureDictionaries(); + if (signatureDictionaries.isEmpty()) { - COSDictionary field = (COSDictionary) fields.getObject(i); - if (COSName.SIG.equals(field.getCOSName(COSName.FT))) - { - sig = (COSDictionary) field.getDictionaryObject(COSName.V); - - COSString contents = (COSString) sig.getDictionaryObject(COSName.CONTENTS); - COSArray byteRange = (COSArray) sig.getDictionaryObject(COSName.BYTERANGE); - - RandomAccessFile raf = new RandomAccessFile(file, "r"); - - byte[] buf = new byte[byteRange.getInt(1) + byteRange.getInt(3)]; - raf.seek(byteRange.getInt(0)); - raf.readFully(buf, 0, byteRange.getInt(1)); - raf.seek(byteRange.getInt(2)); - raf.readFully(buf, byteRange.getInt(1), byteRange.getInt(3)); - raf.close(); - - // inspiration: - // http://stackoverflow.com/a/26702631/535646 - // http://stackoverflow.com/a/9261365/535646 - CMSSignedData signedData = new CMSSignedData(new CMSProcessableByteArray(buf), contents.getBytes()); - Store certificatesStore = signedData.getCertificates(); - Collection signers = signedData.getSignerInfos().getSigners(); - SignerInformation signerInformation = signers.iterator().next(); - - Collection matches = certificatesStore.getMatches(signerInformation.getSID()); - X509CertificateHolder certificateHolder = (X509CertificateHolder) matches.iterator().next(); - X509Certificate certFromSignedData = new JcaX509CertificateConverter().getCertificate(certificateHolder); - - assertEquals(certificate, certFromSignedData); - - // CMSVerifierCertificateNotValidException means that the keystore wasn't valid at signing time - if (signerInformation.verify(new JcaSimpleSignerInfoVerifierBuilder().build(certFromSignedData))) - { - System.out.println("Signature verified"); - } - else - { - System.out.println("Signature verification failed"); - } - - break; - } + fail("no signature found"); } - if (sig == null) + for (PDSignature sig : document.getSignatureDictionaries()) { - fail("no signature found"); + COSString contents = (COSString) sig.getCOSObject().getDictionaryObject(COSName.CONTENTS); + + FileInputStream fis = new FileInputStream(file); + byte[] buf = sig.getSignedContent(fis); + fis.close(); + + // inspiration: + // http://stackoverflow.com/a/26702631/535646 + // http://stackoverflow.com/a/9261365/535646 + CMSSignedData signedData = new CMSSignedData(new CMSProcessableByteArray(buf), contents.getBytes()); + Store certificatesStore = signedData.getCertificates(); + Collection signers = signedData.getSignerInfos().getSigners(); + SignerInformation signerInformation = signers.iterator().next(); + Collection matches = certificatesStore.getMatches(signerInformation.getSID()); + X509CertificateHolder certificateHolder = (X509CertificateHolder) matches.iterator().next(); + X509Certificate certFromSignedData = new JcaX509CertificateConverter().getCertificate(certificateHolder); + + assertEquals(certificate, certFromSignedData); + + // CMSVerifierCertificateNotValidException means that the keystore wasn't valid at signing time + if (!signerInformation.verify(new JcaSimpleSignerInfoVerifierBuilder().build(certFromSignedData))) + { + fail("Signature verification failed"); + } + break; } document.close(); } From 469485782fd3c8c3f3d8ec2b3df8cb7eed23c6dd Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Sat, 11 Jun 2016 16:34:39 +0000 Subject: [PATCH 0117/2182] PDFBOX-3379: correct handling of partially monospaced fonts, increase hmetrics only when last gid wasn't already part of the set git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1747911 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/fontbox/ttf/TTFSubsetter.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/fontbox/src/main/java/org/apache/fontbox/ttf/TTFSubsetter.java b/fontbox/src/main/java/org/apache/fontbox/ttf/TTFSubsetter.java index 895d2023d80..29d9e693951 100755 --- a/fontbox/src/main/java/org/apache/fontbox/ttf/TTFSubsetter.java +++ b/fontbox/src/main/java/org/apache/fontbox/ttf/TTFSubsetter.java @@ -250,9 +250,10 @@ private byte[] buildHheaTable() throws IOException writeSInt16(out, h.getReserved5()); writeSInt16(out, h.getMetricDataFormat()); - // is there a GID >= numberOfHMetrics ? Then keep the last entry of original hmtx table + // is there a GID >= numberOfHMetrics ? Then keep the last entry of original hmtx table, + // (add if it isn't in our set of GIDs), see also in buildHmtxTable() int hmetrics = glyphIds.subSet(0, h.getNumberOfHMetrics()).size(); - if (glyphIds.last() >= h.getNumberOfHMetrics()) + if (glyphIds.last() >= h.getNumberOfHMetrics() && !glyphIds.contains(h.getNumberOfHMetrics()-1)) { ++hmetrics; } @@ -873,12 +874,14 @@ private byte[] buildHmtxTable() throws IOException InputStream is = ttf.getOriginalData(); // is there a GID >= numberOfHMetrics ? Then keep the last entry of original hmtx table + // add it if it isn't in the set + int lastgid = h.getNumberOfHMetrics() - 1; SortedSet gidSet = glyphIds; - if (glyphIds.last() >= h.getNumberOfHMetrics()) + if (glyphIds.last() > lastgid && !glyphIds.contains(lastgid)) { - // Create a deep copy of the glyph set that has the last entry + // Create a deep copy of the glyph set and add the last entry gidSet = new TreeSet(glyphIds); - gidSet.add(ttf.getHorizontalHeader().getNumberOfHMetrics() - 1); + gidSet.add(lastgid); } try From a1a334863854cff0c2702f14f65ba61e3bc14558 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Sun, 12 Jun 2016 08:19:04 +0000 Subject: [PATCH 0118/2182] PDFBOX-3381, PDFBOX-3359: copy from trunk git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1747966 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/pdfbox/rendering/PDFRenderer.java | 41 +++++++++++-------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/rendering/PDFRenderer.java b/pdfbox/src/main/java/org/apache/pdfbox/rendering/PDFRenderer.java index 364c549a918..9b62f566b23 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/rendering/PDFRenderer.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/rendering/PDFRenderer.java @@ -135,8 +135,15 @@ public BufferedImage renderImage(int pageIndex, float scale, ImageType imageType { g.setBackground(Color.WHITE); } + g.clearRect(0, 0, image.getWidth(), image.getHeight()); + + transform(g, page, scale); - renderPage(page, g, image.getWidth(), image.getHeight(), scale, scale); + // the end-user may provide a custom PageDrawer + PageDrawerParameters parameters = new PageDrawerParameters(this, page); + PageDrawer drawer = createPageDrawer(parameters); + drawer.drawPage(g, page.getCropBox()); + g.dispose(); return image; @@ -165,22 +172,27 @@ public void renderPageToGraphics(int pageIndex, Graphics2D graphics, float scale { PDPage page = document.getPage(pageIndex); // TODO need width/wight calculations? should these be in PageDrawer? - PDRectangle adjustedCropBox = page.getCropBox(); - renderPage(page, graphics, (int)adjustedCropBox.getWidth(), (int)adjustedCropBox.getHeight(), scale, scale); + + transform(graphics, page, scale); + + PDRectangle cropBox = page.getCropBox(); + graphics.clearRect(0, 0, (int) cropBox.getWidth(), (int) cropBox.getHeight()); + + // the end-user may provide a custom PageDrawer + PageDrawerParameters parameters = new PageDrawerParameters(this, page); + PageDrawer drawer = createPageDrawer(parameters); + drawer.drawPage(graphics, cropBox); } - // renders a page to the given graphics - private void renderPage(PDPage page, Graphics2D graphics, int width, int height, float scaleX, - float scaleY) throws IOException + // scale rotate translate + private void transform(Graphics2D graphics, PDPage page, float scale) { - graphics.scale(scaleX, scaleY); - // TODO should we be passing the scale to PageDrawer rather than messing with Graphics? - - graphics.clearRect(0, 0, width, height); + graphics.scale(scale, scale); - PDRectangle cropBox = page.getCropBox(); + // TODO should we be passing the scale to PageDrawer rather than messing with Graphics? int rotationAngle = page.getRotation(); - + PDRectangle cropBox = page.getCropBox(); + if (rotationAngle != 0) { float translateX = 0; @@ -201,11 +213,6 @@ private void renderPage(PDPage page, Graphics2D graphics, int width, int height, graphics.translate(translateX, translateY); graphics.rotate((float) Math.toRadians(rotationAngle)); } - - // the end-user may provide a custom PageDrawer - PageDrawerParameters parameters = new PageDrawerParameters(this, page); - PageDrawer drawer = createPageDrawer(parameters); - drawer.drawPage(graphics, cropBox); } /** From 81efc04648527f2a1304adfd938ebf0b733da143 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Mon, 13 Jun 2016 16:07:42 +0000 Subject: [PATCH 0119/2182] PDFBOX-3379: correct handling of partially monospaced fonts: first glyphid larger than maxgid needs width of maxgid but own lsb git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1748274 13f79535-47bb-0310-9956-ffa450edef68 --- .../pdfbox/pdmodel/font/TTFSubsetter.java | 1099 +++++++++++++++++ 1 file changed, 1099 insertions(+) create mode 100755 pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/TTFSubsetter.java diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/TTFSubsetter.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/TTFSubsetter.java new file mode 100755 index 00000000000..09547a7fc8a --- /dev/null +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/TTFSubsetter.java @@ -0,0 +1,1099 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.fontbox.ttf; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.charset.Charset; +import java.util.Calendar; +import java.util.GregorianCalendar; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.SortedMap; +import java.util.SortedSet; +import java.util.TreeMap; +import java.util.TreeSet; + +/** + * Subsetter for TrueType (TTF) fonts. + * + *

Originally developed by Wolfgang Glas for + * Sketch. + * + * @author Wolfgang Glas + */ +public final class TTFSubsetter +{ + private static final byte[] PAD_BUF = new byte[] { 0, 0, 0 }; + + private final TrueTypeFont ttf; + private final CmapSubtable unicodeCmap; + private final SortedMap uniToGID; + + private final List keepTables; + private final SortedSet glyphIds; // new glyph ids + private String prefix; + private boolean hasAddedCompoundReferences; + + /** + * Creates a subsetter for the given font. + * + * @param ttf the font to be subset + */ + public TTFSubsetter(TrueTypeFont ttf) throws IOException + { + this(ttf, null); + } + + /** + * Creates a subsetter for the given font. + * + * @param ttf the font to be subset + * @param tables optional tables to keep if present + */ + public TTFSubsetter(TrueTypeFont ttf, List tables) throws IOException + { + this.ttf = ttf; + this.keepTables = tables; + + uniToGID = new TreeMap(); + glyphIds = new TreeSet(); + + // find the best Unicode cmap + this.unicodeCmap = ttf.getUnicodeCmap(); + + // always copy GID 0 + glyphIds.add(0); + } + + /** + * Sets the prefix to add to the font's PostScript name. + */ + public void setPrefix(String prefix) + { + this.prefix = prefix; + } + + /** + * Add the given character code to the subset. + * + * @param unicode character code + */ + public void add(int unicode) + { + int gid = unicodeCmap.getGlyphId(unicode); + if (gid != 0) + { + uniToGID.put(unicode, gid); + glyphIds.add(gid); + } + } + + /** + * Add the given character codes to the subset. + * + * @param unicodeSet character code set + */ + public void addAll(Set unicodeSet) + { + for (int unicode : unicodeSet) + { + add(unicode); + } + } + + /** + * Returns the map of new -> old GIDs. + */ + public Map getGIDMap() throws IOException + { + addCompoundReferences(); + + Map newToOld = new HashMap(); + int newGID = 0; + for (int oldGID : glyphIds) + { + newToOld.put(newGID, oldGID); + newGID++; + } + return newToOld; + } + + /** + * @param out The data output stream. + * @param nTables The number of table. + * @return The file offset of the first TTF table to write. + * @throws IOException Upon errors. + */ + private long writeFileHeader(DataOutputStream out, int nTables) throws IOException + { + out.writeInt(0x00010000); + out.writeShort(nTables); + + int mask = Integer.highestOneBit(nTables); + int searchRange = mask * 16; + out.writeShort(searchRange); + + int entrySelector = log2(mask); + + out.writeShort(entrySelector); + + // numTables * 16 - searchRange + int last = 16 * nTables - searchRange; + out.writeShort(last); + + return 0x00010000L + toUInt32(nTables, searchRange) + toUInt32(entrySelector, last); + } + + private long writeTableHeader(DataOutputStream out, String tag, long offset, byte[] bytes) + throws IOException + { + long checksum = 0; + for (int nup = 0, n = bytes.length; nup < n; nup++) + { + checksum += (bytes[nup] & 0xffL) << 24 - nup % 4 * 8; + } + checksum &= 0xffffffffL; + + byte[] tagbytes = tag.getBytes("US-ASCII"); + + out.write(tagbytes, 0, 4); + out.writeInt((int)checksum); + out.writeInt((int)offset); + out.writeInt(bytes.length); + + // account for the checksum twice, once for the header field, once for the content itself + return toUInt32(tagbytes) + checksum + checksum + offset + bytes.length; + } + + private void writeTableBody(OutputStream os, byte[] bytes) throws IOException + { + int n = bytes.length; + os.write(bytes); + if (n % 4 != 0) + { + os.write(PAD_BUF, 0, 4 - n % 4); + } + } + + private byte[] buildHeadTable() throws IOException + { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + DataOutputStream out = new DataOutputStream(bos); + + HeaderTable h = ttf.getHeader(); + writeFixed(out, h.getVersion()); + writeFixed(out, h.getFontRevision()); + writeUint32(out, 0); // h.getCheckSumAdjustment() + writeUint32(out, h.getMagicNumber()); + writeUint16(out, h.getFlags()); + writeUint16(out, h.getUnitsPerEm()); + writeLongDateTime(out, h.getCreated()); + writeLongDateTime(out, h.getModified()); + writeSInt16(out, h.getXMin()); + writeSInt16(out, h.getYMin()); + writeSInt16(out, h.getXMax()); + writeSInt16(out, h.getYMax()); + writeUint16(out, h.getMacStyle()); + writeUint16(out, h.getLowestRecPPEM()); + writeSInt16(out, h.getFontDirectionHint()); + // force long format of 'loca' table + writeSInt16(out, (short)1); // h.getIndexToLocFormat() + writeSInt16(out, h.getGlyphDataFormat()); + out.flush(); + + return bos.toByteArray(); + } + + private byte[] buildHheaTable() throws IOException + { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + DataOutputStream out = new DataOutputStream(bos); + + HorizontalHeaderTable h = ttf.getHorizontalHeader(); + writeFixed(out, h.getVersion()); + writeSInt16(out, h.getAscender()); + writeSInt16(out, h.getDescender()); + writeSInt16(out, h.getLineGap()); + writeUint16(out, h.getAdvanceWidthMax()); + writeSInt16(out, h.getMinLeftSideBearing()); + writeSInt16(out, h.getMinRightSideBearing()); + writeSInt16(out, h.getXMaxExtent()); + writeSInt16(out, h.getCaretSlopeRise()); + writeSInt16(out, h.getCaretSlopeRun()); + writeSInt16(out, h.getReserved1()); // caretOffset + writeSInt16(out, h.getReserved2()); + writeSInt16(out, h.getReserved3()); + writeSInt16(out, h.getReserved4()); + writeSInt16(out, h.getReserved5()); + writeSInt16(out, h.getMetricDataFormat()); + + // is there a GID >= numberOfHMetrics ? Then keep the last entry of original hmtx table, + // (add if it isn't in our set of GIDs), see also in buildHmtxTable() + int hmetrics = glyphIds.subSet(0, h.getNumberOfHMetrics()).size(); + if (glyphIds.last() >= h.getNumberOfHMetrics() && !glyphIds.contains(h.getNumberOfHMetrics()-1)) + { + ++hmetrics; + } + writeUint16(out, hmetrics); + + out.flush(); + return bos.toByteArray(); + } + + private boolean shouldCopyNameRecord(NameRecord nr) + { + return nr.getPlatformId() == NameRecord.PLATFORM_WINDOWS + && nr.getPlatformEncodingId() == NameRecord.ENCODING_WINDOWS_UNICODE_BMP + && nr.getLanguageId() == NameRecord.LANGUGAE_WINDOWS_EN_US + && nr.getNameId() >= 0 && nr.getNameId() < 7; + } + + private byte[] buildNameTable() throws IOException + { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + DataOutputStream out = new DataOutputStream(bos); + + NamingTable name = ttf.getNaming(); + if (name == null || keepTables != null && !keepTables.contains("name")) + { + return null; + } + + List nameRecords = name.getNameRecords(); + int numRecords = 0; + for (NameRecord record : nameRecords) + { + if (shouldCopyNameRecord(record)) + { + numRecords++; + } + } + writeUint16(out, 0); + writeUint16(out, numRecords); + writeUint16(out, 2*3 + 2*6 * numRecords); + + if (numRecords == 0) + { + return null; + } + + byte[][] names = new byte[numRecords][]; + int j = 0; + for (NameRecord record : nameRecords) + { + if (shouldCopyNameRecord(record)) + { + int platform = record.getPlatformId(); + int encoding = record.getPlatformEncodingId(); + String charset = "ISO-8859-1"; + + if (platform == CmapTable.PLATFORM_WINDOWS && + encoding == CmapTable.ENCODING_WIN_UNICODE_BMP) + { + charset = "UTF-16BE"; + } + else if (platform == 2) // ISO [deprecated]= + { + if (encoding == 0) // 7-bit ASCII + { + charset = "US-ASCII"; + } + else if (encoding == 1) // ISO 10646= + { + //not sure is this is correct?? + charset = "UTF16-BE"; + } + else if (encoding == 2) // ISO 8859-1 + { + charset = "ISO-8859-1"; + } + } + String value = record.getString(); + if (record.getNameId() == 6 && prefix != null) + { + value = prefix + value; + } + names[j] = value.getBytes(charset); + j++; + } + } + + int offset = 0; + j = 0; + for (NameRecord nr : nameRecords) + { + if (shouldCopyNameRecord(nr)) + { + writeUint16(out, nr.getPlatformId()); + writeUint16(out, nr.getPlatformEncodingId()); + writeUint16(out, nr.getLanguageId()); + writeUint16(out, nr.getNameId()); + writeUint16(out, names[j].length); + writeUint16(out, offset); + offset += names[j].length; + j++; + } + } + + for (int i = 0; i < numRecords; i++) + { + out.write(names[i]); + } + + out.flush(); + return bos.toByteArray(); + } + + private byte[] buildMaxpTable() throws IOException + { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + DataOutputStream out = new DataOutputStream(bos); + + MaximumProfileTable p = ttf.getMaximumProfile(); + writeFixed(out, 1.0); + writeUint16(out, glyphIds.size()); + writeUint16(out, p.getMaxPoints()); + writeUint16(out, p.getMaxContours()); + writeUint16(out, p.getMaxCompositePoints()); + writeUint16(out, p.getMaxCompositeContours()); + writeUint16(out, p.getMaxZones()); + writeUint16(out, p.getMaxTwilightPoints()); + writeUint16(out, p.getMaxStorage()); + writeUint16(out, p.getMaxFunctionDefs()); + writeUint16(out, p.getMaxInstructionDefs()); + writeUint16(out, p.getMaxStackElements()); + writeUint16(out, p.getMaxSizeOfInstructions()); + writeUint16(out, p.getMaxComponentElements()); + writeUint16(out, p.getMaxComponentDepth()); + + out.flush(); + return bos.toByteArray(); + } + + private byte[] buildOS2Table() throws IOException + { + OS2WindowsMetricsTable os2 = ttf.getOS2Windows(); + if (os2 == null || keepTables != null && !keepTables.contains("OS/2")) + { + return null; + } + + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + DataOutputStream out = new DataOutputStream(bos); + + writeUint16(out, os2.getVersion()); + writeSInt16(out, os2.getAverageCharWidth()); + writeUint16(out, os2.getWeightClass()); + writeUint16(out, os2.getWidthClass()); + + writeSInt16(out, os2.getFsType()); + + writeSInt16(out, os2.getSubscriptXSize()); + writeSInt16(out, os2.getSubscriptYSize()); + writeSInt16(out, os2.getSubscriptXOffset()); + writeSInt16(out, os2.getSubscriptYOffset()); + + writeSInt16(out, os2.getSuperscriptXSize()); + writeSInt16(out, os2.getSuperscriptYSize()); + writeSInt16(out, os2.getSuperscriptXOffset()); + writeSInt16(out, os2.getSuperscriptYOffset()); + + writeSInt16(out, os2.getStrikeoutSize()); + writeSInt16(out, os2.getStrikeoutPosition()); + writeSInt16(out, (short)os2.getFamilyClass()); + out.write(os2.getPanose()); + + writeUint32(out, 0); + writeUint32(out, 0); + writeUint32(out, 0); + writeUint32(out, 0); + + out.write(os2.getAchVendId().getBytes("US-ASCII")); + + Iterator> it = uniToGID.entrySet().iterator(); + it.next(); + Entry first = it.next(); + + writeUint16(out, os2.getFsSelection()); + writeUint16(out, first.getKey()); + writeUint16(out, uniToGID.lastKey()); + writeUint16(out, os2.getTypoAscender()); + writeUint16(out, os2.getTypoDescender()); + writeUint16(out, os2.getTypoLineGap()); + writeUint16(out, os2.getWinAscent()); + writeUint16(out, os2.getWinDescent()); + + out.flush(); + return bos.toByteArray(); + } + + private byte[] buildLocaTable(long[] newOffsets) throws IOException + { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + DataOutputStream out = new DataOutputStream(bos); + + for (long offset : newOffsets) + { + writeUint32(out, offset); + } + + out.flush(); + return bos.toByteArray(); + } + + /** + * Resolve compound glyph references. + */ + private void addCompoundReferences() throws IOException + { + if (hasAddedCompoundReferences) + { + return; + } + hasAddedCompoundReferences = true; + + boolean hasNested; + do + { + GlyphTable g = ttf.getGlyph(); + long[] offsets = ttf.getIndexToLocation().getOffsets(); + InputStream is = ttf.getOriginalData(); + Set glyphIdsToAdd = null; + try + { + is.skip(g.getOffset()); + long lastOff = 0L; + for (Integer glyphId : glyphIds) + { + long offset = offsets[glyphId]; + long len = offsets[glyphId + 1] - offset; + is.skip(offset - lastOff); + byte[] buf = new byte[(int)len]; + is.read(buf); + // rewrite glyphIds for compound glyphs + if (buf.length >= 2 && buf[0] == -1 && buf[1] == -1) + { + int off = 2*5; + int flags; + do + { + flags = (buf[off] & 0xff) << 8 | buf[off + 1] & 0xff; + off +=2; + int ogid = (buf[off] & 0xff) << 8 | buf[off + 1] & 0xff; + if (!glyphIds.contains(ogid)) + { + if (glyphIdsToAdd == null) + { + glyphIdsToAdd = new TreeSet(); + } + glyphIdsToAdd.add(ogid); + } + off += 2; + // ARG_1_AND_2_ARE_WORDS + if ((flags & 1 << 0) != 0) + { + off += 2 * 2; + } + else + { + off += 2; + } + // WE_HAVE_A_TWO_BY_TWO + if ((flags & 1 << 7) != 0) + { + off += 2 * 4; + } + // WE_HAVE_AN_X_AND_Y_SCALE + else if ((flags & 1 << 6) != 0) + { + off += 2 * 2; + } + // WE_HAVE_A_SCALE + else if ((flags & 1 << 3) != 0) + { + off += 2; + } + } + while ((flags & 1 << 5) != 0); // MORE_COMPONENTS + + } + lastOff = offsets[glyphId + 1]; + } + } + finally + { + is.close(); + } + if (glyphIdsToAdd != null) + { + glyphIds.addAll(glyphIdsToAdd); + } + hasNested = glyphIdsToAdd != null; + } while (hasNested); + } + + private byte[] buildGlyfTable(long[] newOffsets) throws IOException + { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + + GlyphTable g = ttf.getGlyph(); + long[] offsets = ttf.getIndexToLocation().getOffsets(); + InputStream is = ttf.getOriginalData(); + try + { + is.skip(g.getOffset()); + + long prevEnd = 0; // previously read glyph offset + long newOffset = 0; // new offset for the glyph in the subset font + int newGid = 0; // new GID in subset font + + // for each glyph in the subset + for (Integer gid : glyphIds) + { + long offset = offsets[gid]; + long length = offsets[gid + 1] - offset; + + newOffsets[newGid++] = newOffset; + is.skip(offset - prevEnd); + + byte[] buf = new byte[(int)length]; + is.read(buf); + + // detect glyph type + if (buf.length >= 2 && buf[0] == -1 && buf[1] == -1) + { + // compound glyph + int off = 2*5; + int flags; + do + { + // flags + flags = (buf[off] & 0xff) << 8 | buf[off + 1] & 0xff; + off += 2; + + // glyphIndex + int componentGid = (buf[off] & 0xff) << 8 | buf[off + 1] & 0xff; + if (!glyphIds.contains(componentGid)) + { + glyphIds.add(componentGid); + } + + int newComponentGid = getNewGlyphId(componentGid); + buf[off] = (byte)(newComponentGid >>> 8); + buf[off + 1] = (byte)newComponentGid; + off += 2; + + // ARG_1_AND_2_ARE_WORDS + if ((flags & 1 << 0) != 0) + { + off += 2 * 2; + } + else + { + off += 2; + } + // WE_HAVE_A_TWO_BY_TWO + if ((flags & 1 << 7) != 0) + { + off += 2 * 4; + } + // WE_HAVE_AN_X_AND_Y_SCALE + else if ((flags & 1 << 6) != 0) + { + off += 2 * 2; + } + // WE_HAVE_A_SCALE + else if ((flags & 1 << 3) != 0) + { + off += 2; + } + } + while ((flags & 1 << 5) != 0); // MORE_COMPONENTS + + // WE_HAVE_INSTRUCTIONS + if ((flags & 0x0100) == 0x0100) + { + // USHORT numInstr + int numInstr = (buf[off] & 0xff) << 8 | buf[off + 1] & 0xff; + off += 2; + + // BYTE instr[numInstr] + off += numInstr; + } + + // write the compound glyph + bos.write(buf, 0, off); + + // offset to start next glyph + newOffset += off; + } + else if (buf.length > 0) + { + // copy the entire glyph + bos.write(buf, 0, buf.length); + + // offset to start next glyph + newOffset += buf.length; + } + + // 4-byte alignment + if (newOffset % 4 != 0) + { + int len = 4 - (int)(newOffset % 4); + bos.write(PAD_BUF, 0, len); + newOffset += len; + } + + prevEnd = offset + length; + } + newOffsets[newGid++] = newOffset; + } + finally + { + is.close(); + } + + return bos.toByteArray(); + } + + private int getNewGlyphId(Integer oldGid) + { + return glyphIds.headSet(oldGid).size(); + } + + private byte[] buildCmapTable() throws IOException + { + if (ttf.getCmap() == null || keepTables != null && !keepTables.contains("cmap")) + { + return null; + } + + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + DataOutputStream out = new DataOutputStream(bos); + + // cmap header + writeUint16(out, 0); // version + writeUint16(out, 1); // numberSubtables + + // encoding record + writeUint16(out, CmapTable.PLATFORM_WINDOWS); // platformID + writeUint16(out, CmapTable.ENCODING_WIN_UNICODE_BMP); // platformSpecificID + writeUint32(out, 4 * 2 + 4); // offset + + // build Format 4 subtable (Unicode BMP) + Iterator> it = uniToGID.entrySet().iterator(); + it.next(); + Entry lastChar = it.next(); + Entry prevChar = lastChar; + int lastGid = getNewGlyphId(lastChar.getValue()); + + int[] startCode = new int[uniToGID.size()]; + int[] endCode = new int[uniToGID.size()]; + int[] idDelta = new int[uniToGID.size()]; + int segCount = 0; + while(it.hasNext()) + { + Entry curChar2Gid = it.next(); + int curGid = getNewGlyphId(curChar2Gid.getValue()); + + // todo: need format Format 12 for non-BMP + if (curChar2Gid.getKey() > 0xFFFF) + { + throw new UnsupportedOperationException("non-BMP Unicode character"); + } + + if (curChar2Gid.getKey() != prevChar.getKey()+1 || + curGid - lastGid != curChar2Gid.getKey() - lastChar.getKey()) + { + if (lastGid != 0) + { + // don't emit ranges, which map to GID 0, the + // undef glyph is emitted a the very last segment + startCode[segCount] = lastChar.getKey(); + endCode[segCount] = prevChar.getKey(); + idDelta[segCount] = lastGid - lastChar.getKey(); + segCount++; + } + else if (!lastChar.getKey().equals(prevChar.getKey())) + { + // shorten ranges which start with GID 0 by one + startCode[segCount] = lastChar.getKey() + 1; + endCode[segCount] = prevChar.getKey(); + idDelta[segCount] = lastGid - lastChar.getKey(); + segCount++; + } + lastGid = curGid; + lastChar = curChar2Gid; + } + prevChar = curChar2Gid; + } + + // trailing segment + startCode[segCount] = lastChar.getKey(); + endCode[segCount] = prevChar.getKey(); + idDelta[segCount] = lastGid -lastChar.getKey(); + segCount++; + + // GID 0 + startCode[segCount] = 0xffff; + endCode[segCount] = 0xffff; + idDelta[segCount] = 1; + segCount++; + + // write format 4 subtable + int searchRange = 2 * (int)Math.pow(2, Math.floor(log2(segCount))); + writeUint16(out, 4); // format + writeUint16(out, 8 * 2 + segCount * 4*2); // length + writeUint16(out, 0); // language + writeUint16(out, segCount * 2); // segCountX2 + writeUint16(out, searchRange); // searchRange + writeUint16(out, log2(searchRange / 2)); // entrySelector + writeUint16(out, 2 * segCount - searchRange); // rangeShift + + // endCode[segCount] + for (int i = 0; i < segCount; i++) + { + writeUint16(out, endCode[i]); + } + + // reservedPad + writeUint16(out, 0); + + // startCode[segCount] + for (int i = 0; i < segCount; i++) + { + writeUint16(out, startCode[i]); + } + + // idDelta[segCount] + for (int i = 0; i < segCount; i++) + { + writeUint16(out, idDelta[i]); + } + + for (int i = 0; i < segCount; i++) + { + writeUint16(out, 0); + } + + return bos.toByteArray(); + } + + private byte[] buildPostTable() throws IOException + { + PostScriptTable post = ttf.getPostScript(); + if (post == null || keepTables != null && !keepTables.contains("post")) + { + return null; + } + + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + DataOutputStream out = new DataOutputStream(bos); + + writeFixed(out, 2.0); // version + writeFixed(out, post.getItalicAngle()); + writeSInt16(out, post.getUnderlinePosition()); + writeSInt16(out, post.getUnderlineThickness()); + writeUint32(out, post.getIsFixedPitch()); + writeUint32(out, post.getMinMemType42()); + writeUint32(out, post.getMaxMemType42()); + writeUint32(out, post.getMinMemType1()); + writeUint32(out, post.getMaxMemType1()); + + // version 2.0 + + // numberOfGlyphs + writeUint16(out, glyphIds.size()); + + // glyphNameIndex[numGlyphs] + Map names = new TreeMap(); + for (int gid : glyphIds) + { + String name = post.getName(gid); + Integer macId = WGL4Names.MAC_GLYPH_NAMES_INDICES.get(name); + if (macId != null) + { + // the name is implicit, as it's from MacRoman + writeUint16(out, macId); + } + else + { + // the name will be written explicitly + Integer ordinal = names.get(name); + if (ordinal == null) + { + ordinal = names.size(); + names.put(name, ordinal); + } + writeUint16(out, 258 + ordinal); + } + } + + // names[numberNewGlyphs] + for (String name : names.keySet()) + { + byte[] buf = name.getBytes(Charset.forName("US-ASCII")); + writeUint8(out, buf.length); + out.write(buf); + } + + out.flush(); + return bos.toByteArray(); + } + + private byte[] buildHmtxTable() throws IOException + { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + + HorizontalHeaderTable h = ttf.getHorizontalHeader(); + HorizontalMetricsTable hm = ttf.getHorizontalMetrics(); + InputStream is = ttf.getOriginalData(); + + // more info: https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6hmtx.html + int lastgid = h.getNumberOfHMetrics() - 1; + // true if lastgid is not in the set: we'll need its width (but not its left side bearing) later + boolean needLastGidWidth = false; + if (glyphIds.last() > lastgid && !glyphIds.contains(lastgid)) + { + needLastGidWidth = true; + } + + try + { + is.skip(hm.getOffset()); + long lastOffset = 0; + for (Integer glyphId : glyphIds) + { + // offset in original file + long offset; + if (glyphId <= lastgid) + { + // copy width and lsb + offset = glyphId * 4; + lastOffset = copyBytes(is, bos, offset, lastOffset, 4); + } + else + { + if (needLastGidWidth) + { + // one time only: copy width from lastgid, whose width applies + // to all later glyphs + needLastGidWidth = false; + offset = lastgid * 4; + lastOffset = copyBytes(is, bos, offset, lastOffset, 2); + + // then go on with lsb from actual glyph (lsb are individual even in monotype fonts) + } + + // copy lsb only, as we are beyond numOfHMetrics + offset = h.getNumberOfHMetrics() * 4 + (glyphId - h.getNumberOfHMetrics()) * 2; + lastOffset = copyBytes(is, bos, offset, lastOffset, 2); + } + } + + return bos.toByteArray(); + } + finally + { + is.close(); + } + } + + private long copyBytes(InputStream is, OutputStream os, long newOffset, long lastOffset, int count) + throws IOException + { + // skip over from last original offset + long nskip = newOffset - lastOffset; + if (nskip != is.skip(nskip)) + { + throw new EOFException("Unexpected EOF exception parsing glyphId of hmtx table."); + } + byte[] buf = new byte[count]; + if (count != is.read(buf, 0, count)) + { + throw new EOFException("Unexpected EOF exception parsing glyphId of hmtx table."); + } + os.write(buf, 0, count); + return newOffset + count; + } + + /** + * Write the subfont to the given output stream. + * + * @param os the stream used for writing + * @throws IOException if something went wrong. + * @throws IllegalStateException if the subset is empty. + */ + public void writeToStream(OutputStream os) throws IOException + { + if (glyphIds.isEmpty() || uniToGID.isEmpty()) + { + throw new IllegalStateException("subset is empty"); + } + + addCompoundReferences(); + + DataOutputStream out = new DataOutputStream(os); + try + { + long[] newLoca = new long[glyphIds.size() + 1]; + + // generate tables in dependency order + byte[] head = buildHeadTable(); + byte[] hhea = buildHheaTable(); + byte[] maxp = buildMaxpTable(); + byte[] name = buildNameTable(); + byte[] os2 = buildOS2Table(); + byte[] glyf = buildGlyfTable(newLoca); + byte[] loca = buildLocaTable(newLoca); + byte[] cmap = buildCmapTable(); + byte[] hmtx = buildHmtxTable(); + byte[] post = buildPostTable(); + + // save to TTF in optimized order + Map tables = new TreeMap(); + if (os2 != null) + { + tables.put("OS/2", os2); + } + if (cmap != null) + { + tables.put("cmap", cmap); + } + if (glyf != null) + { + tables.put("glyf", glyf); + } + tables.put("head", head); + tables.put("hhea", hhea); + tables.put("hmtx", hmtx); + if (loca != null) + { + tables.put("loca", loca); + } + tables.put("maxp", maxp); + if (name != null) + { + tables.put("name", name); + } + if (post != null) + { + tables.put("post", post); + } + + // copy all other tables + for (Map.Entry entry : ttf.getTableMap().entrySet()) + { + String tag = entry.getKey(); + TTFTable table = entry.getValue(); + + if (!tables.containsKey(tag) && (keepTables == null || keepTables.contains(tag))) + { + tables.put(tag, ttf.getTableBytes(table)); + } + } + + // calculate checksum + long checksum = writeFileHeader(out, tables.size()); + long offset = 12L + 16L * tables.size(); + for (Map.Entry entry : tables.entrySet()) + { + checksum += writeTableHeader(out, entry.getKey(), offset, entry.getValue()); + offset += (entry.getValue().length + 3) / 4 * 4; + } + checksum = 0xB1B0AFBAL - (checksum & 0xffffffffL); + + // update checksumAdjustment in 'head' table + head[8] = (byte)(checksum >>> 24); + head[9] = (byte)(checksum >>> 16); + head[10] = (byte)(checksum >>> 8); + head[11] = (byte)checksum; + for (byte[] bytes : tables.values()) + { + writeTableBody(out, bytes); + } + } + finally + { + out.close(); + } + } + + private void writeFixed(DataOutputStream out, double f) throws IOException + { + double ip = Math.floor(f); + double fp = (f-ip) * 65536.0; + out.writeShort((int)ip); + out.writeShort((int)fp); + } + + private void writeUint32(DataOutputStream out, long l) throws IOException + { + out.writeInt((int)l); + } + + private void writeUint16(DataOutputStream out, int i) throws IOException + { + out.writeShort(i); + } + + private void writeSInt16(DataOutputStream out, short i) throws IOException + { + out.writeShort(i); + } + + private void writeUint8(DataOutputStream out, int i) throws IOException + { + out.writeByte(i); + } + + private void writeLongDateTime(DataOutputStream out, Calendar calendar) throws IOException + { + // inverse operation of TTFDataStream.readInternationalDate() + GregorianCalendar cal = new GregorianCalendar( 1904, 0, 1 ); + long millisFor1904 = cal.getTimeInMillis(); + long secondsSince1904 = (calendar.getTimeInMillis() - millisFor1904) / 1000L; + out.writeLong(secondsSince1904); + } + + private long toUInt32(int high, int low) + { + return (high & 0xffffL) << 16 | low & 0xffffL; + } + + private long toUInt32(byte[] bytes) + { + return (bytes[0] & 0xffL) << 24 + | (bytes[1] & 0xffL) << 16 + | (bytes[2] & 0xffL) << 8 + | bytes[3] & 0xffL; + } + + private int log2(int num) + { + return (int)Math.round(Math.log(num) / Math.log(2)); + } +} From 61c0cec54e8707cebf59c08ae4649c45bceb1f78 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Mon, 13 Jun 2016 16:09:39 +0000 Subject: [PATCH 0120/2182] PDFBOX-3379: remove file form wrong package git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1748275 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/pdfbox/pdmodel/font/Subsetter.java | 40 ------------------- 1 file changed, 40 deletions(-) delete mode 100644 pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/Subsetter.java diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/Subsetter.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/Subsetter.java deleted file mode 100644 index be4e48d70bf..00000000000 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/Subsetter.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.pdfbox.pdmodel.font; - -import java.io.IOException; - -/** - * Interface for a font subsetter. - */ -interface Subsetter -{ - /** - * Adds the given Unicode code point to this subset. - * - * @param codePoint Unicode code point - */ - void addToSubset(int codePoint); - - /** - * Subset this font now. - * - * @throws IOException if the font could not be read - */ - void subset() throws IOException; -} From 49fca187e99101e22ecace770b20e73422263a75 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Mon, 13 Jun 2016 16:13:42 +0000 Subject: [PATCH 0121/2182] PDFBOX-3379: oops, restore git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1748277 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/pdfbox/pdmodel/font/Subsetter.java | 40 + .../pdfbox/pdmodel/font/TTFSubsetter.java | 1099 ----------------- 2 files changed, 40 insertions(+), 1099 deletions(-) create mode 100644 pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/Subsetter.java delete mode 100755 pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/TTFSubsetter.java diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/Subsetter.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/Subsetter.java new file mode 100644 index 00000000000..be4e48d70bf --- /dev/null +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/Subsetter.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.pdfbox.pdmodel.font; + +import java.io.IOException; + +/** + * Interface for a font subsetter. + */ +interface Subsetter +{ + /** + * Adds the given Unicode code point to this subset. + * + * @param codePoint Unicode code point + */ + void addToSubset(int codePoint); + + /** + * Subset this font now. + * + * @throws IOException if the font could not be read + */ + void subset() throws IOException; +} diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/TTFSubsetter.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/TTFSubsetter.java deleted file mode 100755 index 09547a7fc8a..00000000000 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/TTFSubsetter.java +++ /dev/null @@ -1,1099 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.fontbox.ttf; - -import java.io.ByteArrayOutputStream; -import java.io.DataOutputStream; -import java.io.EOFException; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.charset.Charset; -import java.util.Calendar; -import java.util.GregorianCalendar; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; -import java.util.SortedMap; -import java.util.SortedSet; -import java.util.TreeMap; -import java.util.TreeSet; - -/** - * Subsetter for TrueType (TTF) fonts. - * - *

Originally developed by Wolfgang Glas for - * Sketch. - * - * @author Wolfgang Glas - */ -public final class TTFSubsetter -{ - private static final byte[] PAD_BUF = new byte[] { 0, 0, 0 }; - - private final TrueTypeFont ttf; - private final CmapSubtable unicodeCmap; - private final SortedMap uniToGID; - - private final List keepTables; - private final SortedSet glyphIds; // new glyph ids - private String prefix; - private boolean hasAddedCompoundReferences; - - /** - * Creates a subsetter for the given font. - * - * @param ttf the font to be subset - */ - public TTFSubsetter(TrueTypeFont ttf) throws IOException - { - this(ttf, null); - } - - /** - * Creates a subsetter for the given font. - * - * @param ttf the font to be subset - * @param tables optional tables to keep if present - */ - public TTFSubsetter(TrueTypeFont ttf, List tables) throws IOException - { - this.ttf = ttf; - this.keepTables = tables; - - uniToGID = new TreeMap(); - glyphIds = new TreeSet(); - - // find the best Unicode cmap - this.unicodeCmap = ttf.getUnicodeCmap(); - - // always copy GID 0 - glyphIds.add(0); - } - - /** - * Sets the prefix to add to the font's PostScript name. - */ - public void setPrefix(String prefix) - { - this.prefix = prefix; - } - - /** - * Add the given character code to the subset. - * - * @param unicode character code - */ - public void add(int unicode) - { - int gid = unicodeCmap.getGlyphId(unicode); - if (gid != 0) - { - uniToGID.put(unicode, gid); - glyphIds.add(gid); - } - } - - /** - * Add the given character codes to the subset. - * - * @param unicodeSet character code set - */ - public void addAll(Set unicodeSet) - { - for (int unicode : unicodeSet) - { - add(unicode); - } - } - - /** - * Returns the map of new -> old GIDs. - */ - public Map getGIDMap() throws IOException - { - addCompoundReferences(); - - Map newToOld = new HashMap(); - int newGID = 0; - for (int oldGID : glyphIds) - { - newToOld.put(newGID, oldGID); - newGID++; - } - return newToOld; - } - - /** - * @param out The data output stream. - * @param nTables The number of table. - * @return The file offset of the first TTF table to write. - * @throws IOException Upon errors. - */ - private long writeFileHeader(DataOutputStream out, int nTables) throws IOException - { - out.writeInt(0x00010000); - out.writeShort(nTables); - - int mask = Integer.highestOneBit(nTables); - int searchRange = mask * 16; - out.writeShort(searchRange); - - int entrySelector = log2(mask); - - out.writeShort(entrySelector); - - // numTables * 16 - searchRange - int last = 16 * nTables - searchRange; - out.writeShort(last); - - return 0x00010000L + toUInt32(nTables, searchRange) + toUInt32(entrySelector, last); - } - - private long writeTableHeader(DataOutputStream out, String tag, long offset, byte[] bytes) - throws IOException - { - long checksum = 0; - for (int nup = 0, n = bytes.length; nup < n; nup++) - { - checksum += (bytes[nup] & 0xffL) << 24 - nup % 4 * 8; - } - checksum &= 0xffffffffL; - - byte[] tagbytes = tag.getBytes("US-ASCII"); - - out.write(tagbytes, 0, 4); - out.writeInt((int)checksum); - out.writeInt((int)offset); - out.writeInt(bytes.length); - - // account for the checksum twice, once for the header field, once for the content itself - return toUInt32(tagbytes) + checksum + checksum + offset + bytes.length; - } - - private void writeTableBody(OutputStream os, byte[] bytes) throws IOException - { - int n = bytes.length; - os.write(bytes); - if (n % 4 != 0) - { - os.write(PAD_BUF, 0, 4 - n % 4); - } - } - - private byte[] buildHeadTable() throws IOException - { - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - DataOutputStream out = new DataOutputStream(bos); - - HeaderTable h = ttf.getHeader(); - writeFixed(out, h.getVersion()); - writeFixed(out, h.getFontRevision()); - writeUint32(out, 0); // h.getCheckSumAdjustment() - writeUint32(out, h.getMagicNumber()); - writeUint16(out, h.getFlags()); - writeUint16(out, h.getUnitsPerEm()); - writeLongDateTime(out, h.getCreated()); - writeLongDateTime(out, h.getModified()); - writeSInt16(out, h.getXMin()); - writeSInt16(out, h.getYMin()); - writeSInt16(out, h.getXMax()); - writeSInt16(out, h.getYMax()); - writeUint16(out, h.getMacStyle()); - writeUint16(out, h.getLowestRecPPEM()); - writeSInt16(out, h.getFontDirectionHint()); - // force long format of 'loca' table - writeSInt16(out, (short)1); // h.getIndexToLocFormat() - writeSInt16(out, h.getGlyphDataFormat()); - out.flush(); - - return bos.toByteArray(); - } - - private byte[] buildHheaTable() throws IOException - { - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - DataOutputStream out = new DataOutputStream(bos); - - HorizontalHeaderTable h = ttf.getHorizontalHeader(); - writeFixed(out, h.getVersion()); - writeSInt16(out, h.getAscender()); - writeSInt16(out, h.getDescender()); - writeSInt16(out, h.getLineGap()); - writeUint16(out, h.getAdvanceWidthMax()); - writeSInt16(out, h.getMinLeftSideBearing()); - writeSInt16(out, h.getMinRightSideBearing()); - writeSInt16(out, h.getXMaxExtent()); - writeSInt16(out, h.getCaretSlopeRise()); - writeSInt16(out, h.getCaretSlopeRun()); - writeSInt16(out, h.getReserved1()); // caretOffset - writeSInt16(out, h.getReserved2()); - writeSInt16(out, h.getReserved3()); - writeSInt16(out, h.getReserved4()); - writeSInt16(out, h.getReserved5()); - writeSInt16(out, h.getMetricDataFormat()); - - // is there a GID >= numberOfHMetrics ? Then keep the last entry of original hmtx table, - // (add if it isn't in our set of GIDs), see also in buildHmtxTable() - int hmetrics = glyphIds.subSet(0, h.getNumberOfHMetrics()).size(); - if (glyphIds.last() >= h.getNumberOfHMetrics() && !glyphIds.contains(h.getNumberOfHMetrics()-1)) - { - ++hmetrics; - } - writeUint16(out, hmetrics); - - out.flush(); - return bos.toByteArray(); - } - - private boolean shouldCopyNameRecord(NameRecord nr) - { - return nr.getPlatformId() == NameRecord.PLATFORM_WINDOWS - && nr.getPlatformEncodingId() == NameRecord.ENCODING_WINDOWS_UNICODE_BMP - && nr.getLanguageId() == NameRecord.LANGUGAE_WINDOWS_EN_US - && nr.getNameId() >= 0 && nr.getNameId() < 7; - } - - private byte[] buildNameTable() throws IOException - { - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - DataOutputStream out = new DataOutputStream(bos); - - NamingTable name = ttf.getNaming(); - if (name == null || keepTables != null && !keepTables.contains("name")) - { - return null; - } - - List nameRecords = name.getNameRecords(); - int numRecords = 0; - for (NameRecord record : nameRecords) - { - if (shouldCopyNameRecord(record)) - { - numRecords++; - } - } - writeUint16(out, 0); - writeUint16(out, numRecords); - writeUint16(out, 2*3 + 2*6 * numRecords); - - if (numRecords == 0) - { - return null; - } - - byte[][] names = new byte[numRecords][]; - int j = 0; - for (NameRecord record : nameRecords) - { - if (shouldCopyNameRecord(record)) - { - int platform = record.getPlatformId(); - int encoding = record.getPlatformEncodingId(); - String charset = "ISO-8859-1"; - - if (platform == CmapTable.PLATFORM_WINDOWS && - encoding == CmapTable.ENCODING_WIN_UNICODE_BMP) - { - charset = "UTF-16BE"; - } - else if (platform == 2) // ISO [deprecated]= - { - if (encoding == 0) // 7-bit ASCII - { - charset = "US-ASCII"; - } - else if (encoding == 1) // ISO 10646= - { - //not sure is this is correct?? - charset = "UTF16-BE"; - } - else if (encoding == 2) // ISO 8859-1 - { - charset = "ISO-8859-1"; - } - } - String value = record.getString(); - if (record.getNameId() == 6 && prefix != null) - { - value = prefix + value; - } - names[j] = value.getBytes(charset); - j++; - } - } - - int offset = 0; - j = 0; - for (NameRecord nr : nameRecords) - { - if (shouldCopyNameRecord(nr)) - { - writeUint16(out, nr.getPlatformId()); - writeUint16(out, nr.getPlatformEncodingId()); - writeUint16(out, nr.getLanguageId()); - writeUint16(out, nr.getNameId()); - writeUint16(out, names[j].length); - writeUint16(out, offset); - offset += names[j].length; - j++; - } - } - - for (int i = 0; i < numRecords; i++) - { - out.write(names[i]); - } - - out.flush(); - return bos.toByteArray(); - } - - private byte[] buildMaxpTable() throws IOException - { - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - DataOutputStream out = new DataOutputStream(bos); - - MaximumProfileTable p = ttf.getMaximumProfile(); - writeFixed(out, 1.0); - writeUint16(out, glyphIds.size()); - writeUint16(out, p.getMaxPoints()); - writeUint16(out, p.getMaxContours()); - writeUint16(out, p.getMaxCompositePoints()); - writeUint16(out, p.getMaxCompositeContours()); - writeUint16(out, p.getMaxZones()); - writeUint16(out, p.getMaxTwilightPoints()); - writeUint16(out, p.getMaxStorage()); - writeUint16(out, p.getMaxFunctionDefs()); - writeUint16(out, p.getMaxInstructionDefs()); - writeUint16(out, p.getMaxStackElements()); - writeUint16(out, p.getMaxSizeOfInstructions()); - writeUint16(out, p.getMaxComponentElements()); - writeUint16(out, p.getMaxComponentDepth()); - - out.flush(); - return bos.toByteArray(); - } - - private byte[] buildOS2Table() throws IOException - { - OS2WindowsMetricsTable os2 = ttf.getOS2Windows(); - if (os2 == null || keepTables != null && !keepTables.contains("OS/2")) - { - return null; - } - - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - DataOutputStream out = new DataOutputStream(bos); - - writeUint16(out, os2.getVersion()); - writeSInt16(out, os2.getAverageCharWidth()); - writeUint16(out, os2.getWeightClass()); - writeUint16(out, os2.getWidthClass()); - - writeSInt16(out, os2.getFsType()); - - writeSInt16(out, os2.getSubscriptXSize()); - writeSInt16(out, os2.getSubscriptYSize()); - writeSInt16(out, os2.getSubscriptXOffset()); - writeSInt16(out, os2.getSubscriptYOffset()); - - writeSInt16(out, os2.getSuperscriptXSize()); - writeSInt16(out, os2.getSuperscriptYSize()); - writeSInt16(out, os2.getSuperscriptXOffset()); - writeSInt16(out, os2.getSuperscriptYOffset()); - - writeSInt16(out, os2.getStrikeoutSize()); - writeSInt16(out, os2.getStrikeoutPosition()); - writeSInt16(out, (short)os2.getFamilyClass()); - out.write(os2.getPanose()); - - writeUint32(out, 0); - writeUint32(out, 0); - writeUint32(out, 0); - writeUint32(out, 0); - - out.write(os2.getAchVendId().getBytes("US-ASCII")); - - Iterator> it = uniToGID.entrySet().iterator(); - it.next(); - Entry first = it.next(); - - writeUint16(out, os2.getFsSelection()); - writeUint16(out, first.getKey()); - writeUint16(out, uniToGID.lastKey()); - writeUint16(out, os2.getTypoAscender()); - writeUint16(out, os2.getTypoDescender()); - writeUint16(out, os2.getTypoLineGap()); - writeUint16(out, os2.getWinAscent()); - writeUint16(out, os2.getWinDescent()); - - out.flush(); - return bos.toByteArray(); - } - - private byte[] buildLocaTable(long[] newOffsets) throws IOException - { - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - DataOutputStream out = new DataOutputStream(bos); - - for (long offset : newOffsets) - { - writeUint32(out, offset); - } - - out.flush(); - return bos.toByteArray(); - } - - /** - * Resolve compound glyph references. - */ - private void addCompoundReferences() throws IOException - { - if (hasAddedCompoundReferences) - { - return; - } - hasAddedCompoundReferences = true; - - boolean hasNested; - do - { - GlyphTable g = ttf.getGlyph(); - long[] offsets = ttf.getIndexToLocation().getOffsets(); - InputStream is = ttf.getOriginalData(); - Set glyphIdsToAdd = null; - try - { - is.skip(g.getOffset()); - long lastOff = 0L; - for (Integer glyphId : glyphIds) - { - long offset = offsets[glyphId]; - long len = offsets[glyphId + 1] - offset; - is.skip(offset - lastOff); - byte[] buf = new byte[(int)len]; - is.read(buf); - // rewrite glyphIds for compound glyphs - if (buf.length >= 2 && buf[0] == -1 && buf[1] == -1) - { - int off = 2*5; - int flags; - do - { - flags = (buf[off] & 0xff) << 8 | buf[off + 1] & 0xff; - off +=2; - int ogid = (buf[off] & 0xff) << 8 | buf[off + 1] & 0xff; - if (!glyphIds.contains(ogid)) - { - if (glyphIdsToAdd == null) - { - glyphIdsToAdd = new TreeSet(); - } - glyphIdsToAdd.add(ogid); - } - off += 2; - // ARG_1_AND_2_ARE_WORDS - if ((flags & 1 << 0) != 0) - { - off += 2 * 2; - } - else - { - off += 2; - } - // WE_HAVE_A_TWO_BY_TWO - if ((flags & 1 << 7) != 0) - { - off += 2 * 4; - } - // WE_HAVE_AN_X_AND_Y_SCALE - else if ((flags & 1 << 6) != 0) - { - off += 2 * 2; - } - // WE_HAVE_A_SCALE - else if ((flags & 1 << 3) != 0) - { - off += 2; - } - } - while ((flags & 1 << 5) != 0); // MORE_COMPONENTS - - } - lastOff = offsets[glyphId + 1]; - } - } - finally - { - is.close(); - } - if (glyphIdsToAdd != null) - { - glyphIds.addAll(glyphIdsToAdd); - } - hasNested = glyphIdsToAdd != null; - } while (hasNested); - } - - private byte[] buildGlyfTable(long[] newOffsets) throws IOException - { - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - - GlyphTable g = ttf.getGlyph(); - long[] offsets = ttf.getIndexToLocation().getOffsets(); - InputStream is = ttf.getOriginalData(); - try - { - is.skip(g.getOffset()); - - long prevEnd = 0; // previously read glyph offset - long newOffset = 0; // new offset for the glyph in the subset font - int newGid = 0; // new GID in subset font - - // for each glyph in the subset - for (Integer gid : glyphIds) - { - long offset = offsets[gid]; - long length = offsets[gid + 1] - offset; - - newOffsets[newGid++] = newOffset; - is.skip(offset - prevEnd); - - byte[] buf = new byte[(int)length]; - is.read(buf); - - // detect glyph type - if (buf.length >= 2 && buf[0] == -1 && buf[1] == -1) - { - // compound glyph - int off = 2*5; - int flags; - do - { - // flags - flags = (buf[off] & 0xff) << 8 | buf[off + 1] & 0xff; - off += 2; - - // glyphIndex - int componentGid = (buf[off] & 0xff) << 8 | buf[off + 1] & 0xff; - if (!glyphIds.contains(componentGid)) - { - glyphIds.add(componentGid); - } - - int newComponentGid = getNewGlyphId(componentGid); - buf[off] = (byte)(newComponentGid >>> 8); - buf[off + 1] = (byte)newComponentGid; - off += 2; - - // ARG_1_AND_2_ARE_WORDS - if ((flags & 1 << 0) != 0) - { - off += 2 * 2; - } - else - { - off += 2; - } - // WE_HAVE_A_TWO_BY_TWO - if ((flags & 1 << 7) != 0) - { - off += 2 * 4; - } - // WE_HAVE_AN_X_AND_Y_SCALE - else if ((flags & 1 << 6) != 0) - { - off += 2 * 2; - } - // WE_HAVE_A_SCALE - else if ((flags & 1 << 3) != 0) - { - off += 2; - } - } - while ((flags & 1 << 5) != 0); // MORE_COMPONENTS - - // WE_HAVE_INSTRUCTIONS - if ((flags & 0x0100) == 0x0100) - { - // USHORT numInstr - int numInstr = (buf[off] & 0xff) << 8 | buf[off + 1] & 0xff; - off += 2; - - // BYTE instr[numInstr] - off += numInstr; - } - - // write the compound glyph - bos.write(buf, 0, off); - - // offset to start next glyph - newOffset += off; - } - else if (buf.length > 0) - { - // copy the entire glyph - bos.write(buf, 0, buf.length); - - // offset to start next glyph - newOffset += buf.length; - } - - // 4-byte alignment - if (newOffset % 4 != 0) - { - int len = 4 - (int)(newOffset % 4); - bos.write(PAD_BUF, 0, len); - newOffset += len; - } - - prevEnd = offset + length; - } - newOffsets[newGid++] = newOffset; - } - finally - { - is.close(); - } - - return bos.toByteArray(); - } - - private int getNewGlyphId(Integer oldGid) - { - return glyphIds.headSet(oldGid).size(); - } - - private byte[] buildCmapTable() throws IOException - { - if (ttf.getCmap() == null || keepTables != null && !keepTables.contains("cmap")) - { - return null; - } - - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - DataOutputStream out = new DataOutputStream(bos); - - // cmap header - writeUint16(out, 0); // version - writeUint16(out, 1); // numberSubtables - - // encoding record - writeUint16(out, CmapTable.PLATFORM_WINDOWS); // platformID - writeUint16(out, CmapTable.ENCODING_WIN_UNICODE_BMP); // platformSpecificID - writeUint32(out, 4 * 2 + 4); // offset - - // build Format 4 subtable (Unicode BMP) - Iterator> it = uniToGID.entrySet().iterator(); - it.next(); - Entry lastChar = it.next(); - Entry prevChar = lastChar; - int lastGid = getNewGlyphId(lastChar.getValue()); - - int[] startCode = new int[uniToGID.size()]; - int[] endCode = new int[uniToGID.size()]; - int[] idDelta = new int[uniToGID.size()]; - int segCount = 0; - while(it.hasNext()) - { - Entry curChar2Gid = it.next(); - int curGid = getNewGlyphId(curChar2Gid.getValue()); - - // todo: need format Format 12 for non-BMP - if (curChar2Gid.getKey() > 0xFFFF) - { - throw new UnsupportedOperationException("non-BMP Unicode character"); - } - - if (curChar2Gid.getKey() != prevChar.getKey()+1 || - curGid - lastGid != curChar2Gid.getKey() - lastChar.getKey()) - { - if (lastGid != 0) - { - // don't emit ranges, which map to GID 0, the - // undef glyph is emitted a the very last segment - startCode[segCount] = lastChar.getKey(); - endCode[segCount] = prevChar.getKey(); - idDelta[segCount] = lastGid - lastChar.getKey(); - segCount++; - } - else if (!lastChar.getKey().equals(prevChar.getKey())) - { - // shorten ranges which start with GID 0 by one - startCode[segCount] = lastChar.getKey() + 1; - endCode[segCount] = prevChar.getKey(); - idDelta[segCount] = lastGid - lastChar.getKey(); - segCount++; - } - lastGid = curGid; - lastChar = curChar2Gid; - } - prevChar = curChar2Gid; - } - - // trailing segment - startCode[segCount] = lastChar.getKey(); - endCode[segCount] = prevChar.getKey(); - idDelta[segCount] = lastGid -lastChar.getKey(); - segCount++; - - // GID 0 - startCode[segCount] = 0xffff; - endCode[segCount] = 0xffff; - idDelta[segCount] = 1; - segCount++; - - // write format 4 subtable - int searchRange = 2 * (int)Math.pow(2, Math.floor(log2(segCount))); - writeUint16(out, 4); // format - writeUint16(out, 8 * 2 + segCount * 4*2); // length - writeUint16(out, 0); // language - writeUint16(out, segCount * 2); // segCountX2 - writeUint16(out, searchRange); // searchRange - writeUint16(out, log2(searchRange / 2)); // entrySelector - writeUint16(out, 2 * segCount - searchRange); // rangeShift - - // endCode[segCount] - for (int i = 0; i < segCount; i++) - { - writeUint16(out, endCode[i]); - } - - // reservedPad - writeUint16(out, 0); - - // startCode[segCount] - for (int i = 0; i < segCount; i++) - { - writeUint16(out, startCode[i]); - } - - // idDelta[segCount] - for (int i = 0; i < segCount; i++) - { - writeUint16(out, idDelta[i]); - } - - for (int i = 0; i < segCount; i++) - { - writeUint16(out, 0); - } - - return bos.toByteArray(); - } - - private byte[] buildPostTable() throws IOException - { - PostScriptTable post = ttf.getPostScript(); - if (post == null || keepTables != null && !keepTables.contains("post")) - { - return null; - } - - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - DataOutputStream out = new DataOutputStream(bos); - - writeFixed(out, 2.0); // version - writeFixed(out, post.getItalicAngle()); - writeSInt16(out, post.getUnderlinePosition()); - writeSInt16(out, post.getUnderlineThickness()); - writeUint32(out, post.getIsFixedPitch()); - writeUint32(out, post.getMinMemType42()); - writeUint32(out, post.getMaxMemType42()); - writeUint32(out, post.getMinMemType1()); - writeUint32(out, post.getMaxMemType1()); - - // version 2.0 - - // numberOfGlyphs - writeUint16(out, glyphIds.size()); - - // glyphNameIndex[numGlyphs] - Map names = new TreeMap(); - for (int gid : glyphIds) - { - String name = post.getName(gid); - Integer macId = WGL4Names.MAC_GLYPH_NAMES_INDICES.get(name); - if (macId != null) - { - // the name is implicit, as it's from MacRoman - writeUint16(out, macId); - } - else - { - // the name will be written explicitly - Integer ordinal = names.get(name); - if (ordinal == null) - { - ordinal = names.size(); - names.put(name, ordinal); - } - writeUint16(out, 258 + ordinal); - } - } - - // names[numberNewGlyphs] - for (String name : names.keySet()) - { - byte[] buf = name.getBytes(Charset.forName("US-ASCII")); - writeUint8(out, buf.length); - out.write(buf); - } - - out.flush(); - return bos.toByteArray(); - } - - private byte[] buildHmtxTable() throws IOException - { - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - - HorizontalHeaderTable h = ttf.getHorizontalHeader(); - HorizontalMetricsTable hm = ttf.getHorizontalMetrics(); - InputStream is = ttf.getOriginalData(); - - // more info: https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6hmtx.html - int lastgid = h.getNumberOfHMetrics() - 1; - // true if lastgid is not in the set: we'll need its width (but not its left side bearing) later - boolean needLastGidWidth = false; - if (glyphIds.last() > lastgid && !glyphIds.contains(lastgid)) - { - needLastGidWidth = true; - } - - try - { - is.skip(hm.getOffset()); - long lastOffset = 0; - for (Integer glyphId : glyphIds) - { - // offset in original file - long offset; - if (glyphId <= lastgid) - { - // copy width and lsb - offset = glyphId * 4; - lastOffset = copyBytes(is, bos, offset, lastOffset, 4); - } - else - { - if (needLastGidWidth) - { - // one time only: copy width from lastgid, whose width applies - // to all later glyphs - needLastGidWidth = false; - offset = lastgid * 4; - lastOffset = copyBytes(is, bos, offset, lastOffset, 2); - - // then go on with lsb from actual glyph (lsb are individual even in monotype fonts) - } - - // copy lsb only, as we are beyond numOfHMetrics - offset = h.getNumberOfHMetrics() * 4 + (glyphId - h.getNumberOfHMetrics()) * 2; - lastOffset = copyBytes(is, bos, offset, lastOffset, 2); - } - } - - return bos.toByteArray(); - } - finally - { - is.close(); - } - } - - private long copyBytes(InputStream is, OutputStream os, long newOffset, long lastOffset, int count) - throws IOException - { - // skip over from last original offset - long nskip = newOffset - lastOffset; - if (nskip != is.skip(nskip)) - { - throw new EOFException("Unexpected EOF exception parsing glyphId of hmtx table."); - } - byte[] buf = new byte[count]; - if (count != is.read(buf, 0, count)) - { - throw new EOFException("Unexpected EOF exception parsing glyphId of hmtx table."); - } - os.write(buf, 0, count); - return newOffset + count; - } - - /** - * Write the subfont to the given output stream. - * - * @param os the stream used for writing - * @throws IOException if something went wrong. - * @throws IllegalStateException if the subset is empty. - */ - public void writeToStream(OutputStream os) throws IOException - { - if (glyphIds.isEmpty() || uniToGID.isEmpty()) - { - throw new IllegalStateException("subset is empty"); - } - - addCompoundReferences(); - - DataOutputStream out = new DataOutputStream(os); - try - { - long[] newLoca = new long[glyphIds.size() + 1]; - - // generate tables in dependency order - byte[] head = buildHeadTable(); - byte[] hhea = buildHheaTable(); - byte[] maxp = buildMaxpTable(); - byte[] name = buildNameTable(); - byte[] os2 = buildOS2Table(); - byte[] glyf = buildGlyfTable(newLoca); - byte[] loca = buildLocaTable(newLoca); - byte[] cmap = buildCmapTable(); - byte[] hmtx = buildHmtxTable(); - byte[] post = buildPostTable(); - - // save to TTF in optimized order - Map tables = new TreeMap(); - if (os2 != null) - { - tables.put("OS/2", os2); - } - if (cmap != null) - { - tables.put("cmap", cmap); - } - if (glyf != null) - { - tables.put("glyf", glyf); - } - tables.put("head", head); - tables.put("hhea", hhea); - tables.put("hmtx", hmtx); - if (loca != null) - { - tables.put("loca", loca); - } - tables.put("maxp", maxp); - if (name != null) - { - tables.put("name", name); - } - if (post != null) - { - tables.put("post", post); - } - - // copy all other tables - for (Map.Entry entry : ttf.getTableMap().entrySet()) - { - String tag = entry.getKey(); - TTFTable table = entry.getValue(); - - if (!tables.containsKey(tag) && (keepTables == null || keepTables.contains(tag))) - { - tables.put(tag, ttf.getTableBytes(table)); - } - } - - // calculate checksum - long checksum = writeFileHeader(out, tables.size()); - long offset = 12L + 16L * tables.size(); - for (Map.Entry entry : tables.entrySet()) - { - checksum += writeTableHeader(out, entry.getKey(), offset, entry.getValue()); - offset += (entry.getValue().length + 3) / 4 * 4; - } - checksum = 0xB1B0AFBAL - (checksum & 0xffffffffL); - - // update checksumAdjustment in 'head' table - head[8] = (byte)(checksum >>> 24); - head[9] = (byte)(checksum >>> 16); - head[10] = (byte)(checksum >>> 8); - head[11] = (byte)checksum; - for (byte[] bytes : tables.values()) - { - writeTableBody(out, bytes); - } - } - finally - { - out.close(); - } - } - - private void writeFixed(DataOutputStream out, double f) throws IOException - { - double ip = Math.floor(f); - double fp = (f-ip) * 65536.0; - out.writeShort((int)ip); - out.writeShort((int)fp); - } - - private void writeUint32(DataOutputStream out, long l) throws IOException - { - out.writeInt((int)l); - } - - private void writeUint16(DataOutputStream out, int i) throws IOException - { - out.writeShort(i); - } - - private void writeSInt16(DataOutputStream out, short i) throws IOException - { - out.writeShort(i); - } - - private void writeUint8(DataOutputStream out, int i) throws IOException - { - out.writeByte(i); - } - - private void writeLongDateTime(DataOutputStream out, Calendar calendar) throws IOException - { - // inverse operation of TTFDataStream.readInternationalDate() - GregorianCalendar cal = new GregorianCalendar( 1904, 0, 1 ); - long millisFor1904 = cal.getTimeInMillis(); - long secondsSince1904 = (calendar.getTimeInMillis() - millisFor1904) / 1000L; - out.writeLong(secondsSince1904); - } - - private long toUInt32(int high, int low) - { - return (high & 0xffffL) << 16 | low & 0xffffL; - } - - private long toUInt32(byte[] bytes) - { - return (bytes[0] & 0xffL) << 24 - | (bytes[1] & 0xffL) << 16 - | (bytes[2] & 0xffL) << 8 - | bytes[3] & 0xffL; - } - - private int log2(int num) - { - return (int)Math.round(Math.log(num) / Math.log(2)); - } -} From 1f7f613b7912431522233fbd8d92d7cf5226c3df Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Mon, 13 Jun 2016 16:15:16 +0000 Subject: [PATCH 0122/2182] PDFBOX-3379: correct handling of partially monospaced fonts: first glyphid larger than maxgid needs width of maxgid but own lsb git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1748278 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/fontbox/ttf/TTFSubsetter.java | 73 +++++++++++-------- 1 file changed, 43 insertions(+), 30 deletions(-) diff --git a/fontbox/src/main/java/org/apache/fontbox/ttf/TTFSubsetter.java b/fontbox/src/main/java/org/apache/fontbox/ttf/TTFSubsetter.java index 29d9e693951..09547a7fc8a 100755 --- a/fontbox/src/main/java/org/apache/fontbox/ttf/TTFSubsetter.java +++ b/fontbox/src/main/java/org/apache/fontbox/ttf/TTFSubsetter.java @@ -870,53 +870,48 @@ private byte[] buildHmtxTable() throws IOException HorizontalHeaderTable h = ttf.getHorizontalHeader(); HorizontalMetricsTable hm = ttf.getHorizontalMetrics(); - byte [] buf = new byte[4]; InputStream is = ttf.getOriginalData(); - // is there a GID >= numberOfHMetrics ? Then keep the last entry of original hmtx table - // add it if it isn't in the set + // more info: https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6hmtx.html int lastgid = h.getNumberOfHMetrics() - 1; - SortedSet gidSet = glyphIds; + // true if lastgid is not in the set: we'll need its width (but not its left side bearing) later + boolean needLastGidWidth = false; if (glyphIds.last() > lastgid && !glyphIds.contains(lastgid)) { - // Create a deep copy of the glyph set and add the last entry - gidSet = new TreeSet(glyphIds); - gidSet.add(lastgid); + needLastGidWidth = true; } - + try { is.skip(hm.getOffset()); - long lastOff = 0; - for (Integer glyphId : gidSet) + long lastOffset = 0; + for (Integer glyphId : glyphIds) { // offset in original file - long off; - if (glyphId < h.getNumberOfHMetrics()) - { - off = glyphId * 4; - } - else + long offset; + if (glyphId <= lastgid) { - off = h.getNumberOfHMetrics() * 4 + (glyphId - h.getNumberOfHMetrics()) * 2; + // copy width and lsb + offset = glyphId * 4; + lastOffset = copyBytes(is, bos, offset, lastOffset, 4); } - // skip over from last original offset - if (off != lastOff) + else { - long nskip = off-lastOff; - if (nskip != is.skip(nskip)) + if (needLastGidWidth) { - throw new EOFException("Unexpected EOF exception parsing glyphId of hmtx table."); + // one time only: copy width from lastgid, whose width applies + // to all later glyphs + needLastGidWidth = false; + offset = lastgid * 4; + lastOffset = copyBytes(is, bos, offset, lastOffset, 2); + + // then go on with lsb from actual glyph (lsb are individual even in monotype fonts) } + + // copy lsb only, as we are beyond numOfHMetrics + offset = h.getNumberOfHMetrics() * 4 + (glyphId - h.getNumberOfHMetrics()) * 2; + lastOffset = copyBytes(is, bos, offset, lastOffset, 2); } - // read left side bearings only, if we are beyond numOfHMetrics - int n = glyphId < h.getNumberOfHMetrics() ? 4 : 2; - if (n != is.read(buf, 0, n)) - { - throw new EOFException("Unexpected EOF exception parsing glyphId of hmtx table."); - } - bos.write(buf, 0, n); - lastOff = off + n; } return bos.toByteArray(); @@ -927,6 +922,24 @@ private byte[] buildHmtxTable() throws IOException } } + private long copyBytes(InputStream is, OutputStream os, long newOffset, long lastOffset, int count) + throws IOException + { + // skip over from last original offset + long nskip = newOffset - lastOffset; + if (nskip != is.skip(nskip)) + { + throw new EOFException("Unexpected EOF exception parsing glyphId of hmtx table."); + } + byte[] buf = new byte[count]; + if (count != is.read(buf, 0, count)) + { + throw new EOFException("Unexpected EOF exception parsing glyphId of hmtx table."); + } + os.write(buf, 0, count); + return newOffset + count; + } + /** * Write the subfont to the given output stream. * From 5d8ce1a22b80f82c89eadbee70c7b811ac97d211 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Tue, 14 Jun 2016 16:33:07 +0000 Subject: [PATCH 0123/2182] PDFBOX-2854: modify for missing .notdef entry git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1748440 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/fontbox/ttf/TTFSubsetter.java | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/fontbox/src/main/java/org/apache/fontbox/ttf/TTFSubsetter.java b/fontbox/src/main/java/org/apache/fontbox/ttf/TTFSubsetter.java index 09547a7fc8a..68cc88518ca 100755 --- a/fontbox/src/main/java/org/apache/fontbox/ttf/TTFSubsetter.java +++ b/fontbox/src/main/java/org/apache/fontbox/ttf/TTFSubsetter.java @@ -433,12 +433,8 @@ private byte[] buildOS2Table() throws IOException out.write(os2.getAchVendId().getBytes("US-ASCII")); - Iterator> it = uniToGID.entrySet().iterator(); - it.next(); - Entry first = it.next(); - writeUint16(out, os2.getFsSelection()); - writeUint16(out, first.getKey()); + writeUint16(out, uniToGID.firstKey()); writeUint16(out, uniToGID.lastKey()); writeUint16(out, os2.getTypoAscender()); writeUint16(out, os2.getTypoDescender()); @@ -705,14 +701,14 @@ private byte[] buildCmapTable() throws IOException // build Format 4 subtable (Unicode BMP) Iterator> it = uniToGID.entrySet().iterator(); - it.next(); Entry lastChar = it.next(); Entry prevChar = lastChar; int lastGid = getNewGlyphId(lastChar.getValue()); - int[] startCode = new int[uniToGID.size()]; - int[] endCode = new int[uniToGID.size()]; - int[] idDelta = new int[uniToGID.size()]; + // +1 because .notdef is missing in uniToGID + int[] startCode = new int[uniToGID.size()+1]; + int[] endCode = new int[uniToGID.size()+1]; + int[] idDelta = new int[uniToGID.size()+1]; int segCount = 0; while(it.hasNext()) { From a5c7ed37d664b2c75ecd220469551a8b3a1e72ba Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Tue, 14 Jun 2016 16:33:56 +0000 Subject: [PATCH 0124/2182] PDFBOX-2854, PDFBOX-3379: add test git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1748441 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/fontbox/ttf/TTFSubsetterTest.java | 153 +++++++++++++++++- 1 file changed, 146 insertions(+), 7 deletions(-) diff --git a/fontbox/src/test/java/org/apache/fontbox/ttf/TTFSubsetterTest.java b/fontbox/src/test/java/org/apache/fontbox/ttf/TTFSubsetterTest.java index 87ee77c5ffe..6d0c00c6afa 100644 --- a/fontbox/src/test/java/org/apache/fontbox/ttf/TTFSubsetterTest.java +++ b/fontbox/src/test/java/org/apache/fontbox/ttf/TTFSubsetterTest.java @@ -15,9 +15,20 @@ */ package org.apache.fontbox.ttf; +import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; +import java.util.Map.Entry; +import org.apache.fontbox.util.autodetect.FontFileFinder; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import static org.junit.Assert.fail; import org.junit.Test; @@ -29,7 +40,9 @@ public class TTFSubsetterTest { /** - * Test of PDFBOX-2854. + * Test of PDFBOX-2854: empty subset. + * + * @throws java.io.IOException */ @Test public void testEmptySubset() throws IOException @@ -49,17 +62,143 @@ public void testEmptySubset() throws IOException } /** - * Test of PDFBOX-2854. + * Test of PDFBOX-2854: subset with one glyph. + * + * @throws java.io.IOException */ - //@Test - // enable when fixed + @Test public void testNonEmptySubset() throws IOException { final File testFile = new File("src/test/resources/ttf/LiberationSans-Regular.ttf"); - TrueTypeFont x = new TTFParser().parse(testFile); - TTFSubsetter ttfSubsetter = new TTFSubsetter(x); + TrueTypeFont full = new TTFParser().parse(testFile); + TTFSubsetter ttfSubsetter = new TTFSubsetter(full); ttfSubsetter.add('a'); - ttfSubsetter.writeToStream(new ByteArrayOutputStream()); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ttfSubsetter.writeToStream(baos); + TrueTypeFont subset = new TTFParser(true).parse(new ByteArrayInputStream(baos.toByteArray())); + assertEquals(2, subset.getNumberOfGlyphs()); + assertEquals(0, subset.nameToGID(".notdef")); + assertEquals(1, subset.nameToGID("a")); + assertNotNull(subset.getGlyph().getGlyph(0)); + assertNotNull(subset.getGlyph().getGlyph(1)); + assertNull(subset.getGlyph().getGlyph(2)); + assertEquals(full.getAdvanceWidth(full.nameToGID("a")), + subset.getAdvanceWidth(subset.nameToGID("a"))); + assertEquals(full.getHorizontalMetrics().getLeftSideBearing(full.nameToGID("a")), + subset.getHorizontalMetrics().getLeftSideBearing(subset.nameToGID("a"))); + subset.close(); } + /** + * Test of PDFBOX-3319: check that widths and left side bearings in partially monospaced font + * are kept. + * + * @throws java.io.IOException + */ + @Test + public void testPDFBox3319() throws IOException + { + System.out.println("Searching for SimHei font..."); + FontFileFinder fontFileFinder = new FontFileFinder(); + List files = fontFileFinder.find(); + File simhei = null; + for (URI uri : files) + { + if (uri.getPath() != null && uri.getPath().toLowerCase().endsWith("simhei.ttf")) + { + simhei = new File(uri); + } + } + if (simhei == null) + { + System.err.println("SimHei font not available on this machine, test skipped"); + return; + } + System.out.println("SimHei font found!"); + TrueTypeFont full = new TTFParser().parse(simhei); + + // List copied from TrueTypeEmbedder.java + // Without it, the test would fail because of missing post table in source font + List tables = new ArrayList(); + tables.add("head"); + tables.add("hhea"); + tables.add("loca"); + tables.add("maxp"); + tables.add("cvt "); + tables.add("prep"); + tables.add("glyf"); + tables.add("hmtx"); + tables.add("fpgm"); + tables.add("gasp"); + + TTFSubsetter ttfSubsetter = new TTFSubsetter(full, tables); + + String chinese = "中国你好!"; + for (int offset = 0; offset < chinese.length();) + { + int codePoint = chinese.codePointAt(offset); + ttfSubsetter.add(codePoint); + offset += Character.charCount(codePoint); + } + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ttfSubsetter.writeToStream(baos); + TrueTypeFont subset = new TTFParser(true).parse(new ByteArrayInputStream(baos.toByteArray())); + assertEquals(6, subset.getNumberOfGlyphs()); + + for (Entry entry : ttfSubsetter.getGIDMap().entrySet()) + { + Integer newGID = entry.getKey(); + Integer oldGID = entry.getValue(); + assertEquals(full.getAdvanceWidth(oldGID), subset.getAdvanceWidth(newGID)); + assertEquals(full.getHorizontalMetrics().getLeftSideBearing(oldGID), + subset.getHorizontalMetrics().getLeftSideBearing(newGID)); + } + subset.close(); + } + + /** + * Test of PDFBOX-3379: check that left side bearings in partially monospaced font are kept. + * + * @throws java.io.IOException + */ + @Test + public void testPDFBox3379() throws IOException + { + InputStream is; + try + { + // don't want to include this font into source download (300KB) + System.out.println("Downloading DejaVuSansMono font..."); + is = new URL("https://issues.apache.org/jira/secure/attachment/12809395/DejaVuSansMono.ttf").openStream(); + System.out.println("Download finished!"); + } + catch (IOException ex) + { + System.err.println("DejaVuSansMono font could not be downloaded, test skipped"); + return; + } + TrueTypeFont full = new TTFParser().parse(is); + TTFSubsetter ttfSubsetter = new TTFSubsetter(full); + ttfSubsetter.add('A'); + ttfSubsetter.add(' '); + ttfSubsetter.add('B'); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ttfSubsetter.writeToStream(baos); + TrueTypeFont subset = new TTFParser().parse(new ByteArrayInputStream(baos.toByteArray())); + assertEquals(4, subset.getNumberOfGlyphs()); + assertEquals(0, subset.nameToGID(".notdef")); + assertEquals(1, subset.nameToGID("space")); + assertEquals(2, subset.nameToGID("A")); + assertEquals(3, subset.nameToGID("B")); + String [] names = new String[]{"A","B","space"}; + for (String name : names) + { + assertEquals(full.getAdvanceWidth(full.nameToGID(name)), + subset.getAdvanceWidth(subset.nameToGID(name))); + assertEquals(full.getHorizontalMetrics().getLeftSideBearing(full.nameToGID(name)), + subset.getHorizontalMetrics().getLeftSideBearing(subset.nameToGID(name))); + } + subset.close(); + } } From c29a009d7fd601e076a5277c2b8f6455e93db61f Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Wed, 15 Jun 2016 20:36:50 +0000 Subject: [PATCH 0125/2182] PDFBOX-3383: refactor to allow tsa timestamping for visible signatures, some renaming for clarity git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1748633 13f79535-47bb-0310-9956-ffa450edef68 --- .../examples/signature/CreateSignature.java | 78 +-------------- .../signature/CreateSignatureBase.java | 66 ++++++++++++- .../signature/CreateVisibleSignature.java | 99 +++++++++++++------ 3 files changed, 133 insertions(+), 110 deletions(-) diff --git a/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateSignature.java b/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateSignature.java index 5ed771a4a4e..04df26551f3 100644 --- a/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateSignature.java +++ b/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateSignature.java @@ -33,26 +33,12 @@ import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; -import java.util.ArrayList; import java.util.Calendar; import java.util.Enumeration; -import java.util.List; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature; -import org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.ASN1Primitive; -import org.bouncycastle.asn1.DERSet; -import org.bouncycastle.asn1.cms.Attribute; -import org.bouncycastle.asn1.cms.AttributeTable; -import org.bouncycastle.asn1.cms.Attributes; -import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; -import org.bouncycastle.cms.CMSSignedData; -import org.bouncycastle.cms.SignerInformation; -import org.bouncycastle.cms.SignerInformationStore; -import org.bouncycastle.tsp.TSPException; +import org.apache.pdfbox.pdmodel.interactive.digitalsignature.SignatureOptions; /** * An example for singing a PDF with bouncy castle. @@ -164,70 +150,14 @@ public void signDetached(PDDocument document, OutputStream output, TSAClient tsa signature.setSignDate(Calendar.getInstance()); // register signature dictionary and sign interface - document.addSignature(signature, this); + SignatureOptions signatureOptions = new SignatureOptions(); + signatureOptions.setPage(1); // 0-based + document.addSignature(signature, this, signatureOptions); // write incremental (only for signing purpose) document.saveIncremental(output); } - /** - * We just extend CMS signed Data - * - * @param signedData -Generated CMS signed data - * @return CMSSignedData - Extended CMS signed data - */ - @Override - protected CMSSignedData signTimeStamps(CMSSignedData signedData) - throws IOException, TSPException - { - SignerInformationStore signerStore = signedData.getSignerInfos(); - List newSigners = new ArrayList(); - - for (SignerInformation signer : signerStore.getSigners()) - { - newSigners.add(signTimeStamp(signer)); - } - - // TODO do we have to return a new store? - return CMSSignedData.replaceSigners(signedData, new SignerInformationStore(newSigners)); - } - - /** - * We are extending CMS Signature - * - * @param signer information about signer - * @return information about SignerInformation - */ - private SignerInformation signTimeStamp(SignerInformation signer) - throws IOException, TSPException - { - AttributeTable unsignedAttributes = signer.getUnsignedAttributes(); - - ASN1EncodableVector vector = new ASN1EncodableVector(); - if (unsignedAttributes != null) - { - vector = unsignedAttributes.toASN1EncodableVector(); - } - - byte[] token = getTsaClient().getTimeStampToken(signer.getSignature()); - ASN1ObjectIdentifier oid = PKCSObjectIdentifiers.id_aa_signatureTimeStampToken; - ASN1Encodable signatureTimeStamp = new Attribute(oid, new DERSet(ASN1Primitive.fromByteArray(token))); - - vector.add(signatureTimeStamp); - Attributes signedAttributes = new Attributes(vector); - - SignerInformation newSigner = SignerInformation.replaceUnsignedAttributes( - signer, new AttributeTable(signedAttributes)); - - // TODO can this actually happen? - if (newSigner == null) - { - return signer; - } - - return newSigner; - } - public static void main(String[] args) throws IOException, GeneralSecurityException { if (args.length < 3) diff --git a/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateSignatureBase.java b/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateSignatureBase.java index 415728478a2..c0e0783a2d2 100644 --- a/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateSignatureBase.java +++ b/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateSignatureBase.java @@ -24,12 +24,22 @@ import java.util.ArrayList; import java.util.List; import org.apache.pdfbox.pdmodel.interactive.digitalsignature.SignatureInterface; +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.DERSet; +import org.bouncycastle.asn1.cms.Attribute; +import org.bouncycastle.asn1.cms.AttributeTable; +import org.bouncycastle.asn1.cms.Attributes; +import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import org.bouncycastle.cert.X509CertificateHolder; import org.bouncycastle.cert.jcajce.JcaCertStore; import org.bouncycastle.cms.CMSException; import org.bouncycastle.cms.CMSSignedData; import org.bouncycastle.cms.CMSSignedDataGenerator; +import org.bouncycastle.cms.SignerInformation; +import org.bouncycastle.cms.SignerInformationStore; import org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder; import org.bouncycastle.operator.ContentSigner; import org.bouncycastle.operator.OperatorCreationException; @@ -65,14 +75,62 @@ public TSAClient getTsaClient() } /** - * Does nothing. Override this if needed. + * We just extend CMS signed Data * - * @param signedData Generated CMS signed data + * @param signedData ´Generated CMS signed data * @return CMSSignedData Extended CMS signed data + * @throws IOException + * @throws org.bouncycastle.tsp.TSPException */ - protected CMSSignedData signTimeStamps(CMSSignedData signedData) throws IOException, TSPException + private CMSSignedData signTimeStamps(CMSSignedData signedData) + throws IOException, TSPException { - return signedData; + SignerInformationStore signerStore = signedData.getSignerInfos(); + List newSigners = new ArrayList(); + + for (SignerInformation signer : signerStore.getSigners()) + { + newSigners.add(signTimeStamp(signer)); + } + + // TODO do we have to return a new store? + return CMSSignedData.replaceSigners(signedData, new SignerInformationStore(newSigners)); + } + + /** + * We are extending CMS Signature + * + * @param signer information about signer + * @return information about SignerInformation + */ + private SignerInformation signTimeStamp(SignerInformation signer) + throws IOException, TSPException + { + AttributeTable unsignedAttributes = signer.getUnsignedAttributes(); + + ASN1EncodableVector vector = new ASN1EncodableVector(); + if (unsignedAttributes != null) + { + vector = unsignedAttributes.toASN1EncodableVector(); + } + + byte[] token = getTsaClient().getTimeStampToken(signer.getSignature()); + ASN1ObjectIdentifier oid = PKCSObjectIdentifiers.id_aa_signatureTimeStampToken; + ASN1Encodable signatureTimeStamp = new Attribute(oid, new DERSet(ASN1Primitive.fromByteArray(token))); + + vector.add(signatureTimeStamp); + Attributes signedAttributes = new Attributes(vector); + + SignerInformation newSigner = SignerInformation.replaceUnsignedAttributes( + signer, new AttributeTable(signedAttributes)); + + // TODO can this actually happen? + if (newSigner == null) + { + return signer; + } + + return newSigner; } /** diff --git a/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateVisibleSignature.java b/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateVisibleSignature.java index 796b8703116..df176a46b7b 100644 --- a/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateVisibleSignature.java +++ b/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateVisibleSignature.java @@ -20,8 +20,10 @@ import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; +import java.net.URL; import java.security.KeyStore; import java.security.KeyStoreException; +import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.UnrecoverableKeyException; @@ -49,11 +51,11 @@ public class CreateVisibleSignature extends CreateSignatureBase { private static final BouncyCastleProvider BCPROVIDER = new BouncyCastleProvider(); - private SignatureOptions options; + private SignatureOptions signatureOptions; private PDVisibleSignDesigner visibleSignDesigner; private final PDVisibleSigProperties visibleSignatureProperties = new PDVisibleSigProperties(); - public void setVisibleSignatureProperties(String filename, int x, int y, int zoomPercent, + public void setvisibleSignDesigner(String filename, int x, int y, int zoomPercent, FileInputStream image, int page) throws IOException { @@ -61,7 +63,7 @@ public void setVisibleSignatureProperties(String filename, int x, int y, int zoo visibleSignDesigner.xAxis(x).yAxis(y).zoom(zoomPercent).signatureFieldName("signature"); } - public void setSignatureProperties(String name, String location, String reason, int preferredSize, + public void setVisibleSignatureProperties(String name, String location, String reason, int preferredSize, int page, boolean visualSignEnabled) throws IOException { visibleSignatureProperties.signerName(name).signerLocation(location).signatureReason(reason). @@ -111,10 +113,13 @@ public CreateVisibleSignature(KeyStore keystore, char[] pin) * * @param inputFile The source pdf document file. * @param signedFile The file to be signed. + * @param tsaClient optional TSA client * @throws IOException */ - public void signPDF(File inputFile, File signedFile) throws IOException + public void signPDF(File inputFile, File signedFile, TSAClient tsaClient) throws IOException { + setTsaClient(tsaClient); + if (inputFile == null || !inputFile.exists()) { throw new IOException("Document for signing does not exist"); @@ -141,10 +146,10 @@ public void signPDF(File inputFile, File signedFile) throws IOException // register signature dictionary and sign interface if (visibleSignatureProperties != null && visibleSignatureProperties.isVisualSignEnabled()) { - options = new SignatureOptions(); - options.setVisualSignature(visibleSignatureProperties); - options.setPage(visibleSignatureProperties.getPage() - 1); - doc.addSignature(signature, this, options); + signatureOptions = new SignatureOptions(); + signatureOptions.setVisualSignature(visibleSignatureProperties); + signatureOptions.setPage(visibleSignatureProperties.getPage() - 1); + doc.addSignature(signature, this, signatureOptions); } else { @@ -157,7 +162,7 @@ public void signPDF(File inputFile, File signedFile) throws IOException // do not close options before saving, because some COSStream objects within options // are transferred to the signed document. - IOUtils.closeQuietly(options); + IOUtils.closeQuietly(signatureOptions); } /** @@ -166,38 +171,66 @@ public void signPDF(File inputFile, File signedFile) throws IOException * [1] pin * [2] document that will be signed * [3] image of visible signature + * @param args + * @throws java.security.KeyStoreException + * @throws java.security.cert.CertificateException + * @throws java.io.IOException + * @throws java.security.NoSuchAlgorithmException + * @throws java.security.UnrecoverableKeyException */ public static void main(String[] args) throws KeyStoreException, CertificateException, IOException, NoSuchAlgorithmException, UnrecoverableKeyException { - if (args.length != 4) + // generate with + // keytool -storepass 123456 -storetype PKCS12 -keystore file.p12 -genkey -alias client -keyalg RSA + if (args.length < 4) { usage(); System.exit(1); } - else + + String tsaUrl = null; + for(int i = 0; i < args.length; i++) + { + if (args[i].equals("-tsa")) + { + i++; + if (i >= args.length) + { + usage(); + } + tsaUrl = args[i]; + } + } + + File ksFile = new File(args[0]); + KeyStore keystore = KeyStore.getInstance("PKCS12", BCPROVIDER); + char[] pin = args[1].toCharArray(); + keystore.load(new FileInputStream(ksFile), pin); + + // TSA client + TSAClient tsaClient = null; + if (tsaUrl != null) { - File ksFile = new File(args[0]); - KeyStore keystore = KeyStore.getInstance("PKCS12", BCPROVIDER); - char[] pin = args[1].toCharArray(); - keystore.load(new FileInputStream(ksFile), pin); - - File documentFile = new File(args[2]); - - CreateVisibleSignature signing = new CreateVisibleSignature(keystore, pin.clone()); - - FileInputStream image = new FileInputStream(args[3]); - - String name = documentFile.getName(); - String substring = name.substring(0, name.lastIndexOf('.')); - File signedDocumentFile = new File(documentFile.getParent(), substring + "_signed.pdf"); - - // page is 1-based here - int page = 1; - signing.setVisibleSignatureProperties (args[2], 0, 0, -50, image, page); - signing.setSignatureProperties ("name", "location", "Security", 0, page, true); - signing.signPDF(documentFile, signedDocumentFile); + MessageDigest digest = MessageDigest.getInstance("SHA-256"); + tsaClient = new TSAClient(new URL(tsaUrl), null, null, digest); } + + File documentFile = new File(args[2]); + + CreateVisibleSignature signing = new CreateVisibleSignature(keystore, pin.clone()); + + FileInputStream image = new FileInputStream(args[3]); + + String name = documentFile.getName(); + String substring = name.substring(0, name.lastIndexOf('.')); + File signedDocumentFile = new File(documentFile.getParent(), substring + "_signed.pdf"); + + // page is 1-based here + int page = 1; + signing.setvisibleSignDesigner (args[2], 0, 0, -50, image, page); + signing.setVisibleSignatureProperties ("name", "location", "Security", 0, page, true); + signing.signPDF(documentFile, signedDocumentFile, tsaClient); } /** @@ -206,6 +239,8 @@ public static void main(String[] args) throws KeyStoreException, CertificateExce private static void usage() { System.err.println("Usage: java " + CreateVisibleSignature.class.getName() - + " "); + + " \n" + "" + + "options:\n" + + " -tsa sign timestamp using the given TSA server"); } } From aacfe18784f44cb525e6ace20277e9e1d506b3fc Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Wed, 15 Jun 2016 20:39:14 +0000 Subject: [PATCH 0126/2182] PDFBOX-3383: adjust test git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1748635 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/pdfbox/examples/pdmodel/TestCreateSignature.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/src/test/java/org/apache/pdfbox/examples/pdmodel/TestCreateSignature.java b/examples/src/test/java/org/apache/pdfbox/examples/pdmodel/TestCreateSignature.java index bdcd6005669..9da41449eff 100644 --- a/examples/src/test/java/org/apache/pdfbox/examples/pdmodel/TestCreateSignature.java +++ b/examples/src/test/java/org/apache/pdfbox/examples/pdmodel/TestCreateSignature.java @@ -166,10 +166,10 @@ public void testCreateVisibleSignature() String inPath = inDir + "sign_me.pdf"; FileInputStream fis = new FileInputStream(jpegPath); CreateVisibleSignature signing = new CreateVisibleSignature(keystore, password.toCharArray()); - signing.setVisibleSignatureProperties(inPath, 0, 0, -50, fis, 1); - signing.setSignatureProperties("name", "location", "Security", 0, 1, true); + signing.setvisibleSignDesigner(inPath, 0, 0, -50, fis, 1); + signing.setVisibleSignatureProperties("name", "location", "Security", 0, 1, true); File destFile = new File(outDir + "signed_visible.pdf"); - signing.signPDF(new File(inPath), destFile); + signing.signPDF(new File(inPath), destFile, null); checkSignature(destFile); } From 1072c5d82fe73c4c8d163ec2a695b54765e68b63 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Thu, 16 Jun 2016 16:12:51 +0000 Subject: [PATCH 0127/2182] PDFBOX-3383: revert code change that doesn't make sense for invisible signatures git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1748752 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/pdfbox/examples/signature/CreateSignature.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateSignature.java b/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateSignature.java index 04df26551f3..a091da8f649 100644 --- a/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateSignature.java +++ b/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateSignature.java @@ -38,7 +38,6 @@ import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature; -import org.apache.pdfbox.pdmodel.interactive.digitalsignature.SignatureOptions; /** * An example for singing a PDF with bouncy castle. @@ -150,9 +149,7 @@ public void signDetached(PDDocument document, OutputStream output, TSAClient tsa signature.setSignDate(Calendar.getInstance()); // register signature dictionary and sign interface - SignatureOptions signatureOptions = new SignatureOptions(); - signatureOptions.setPage(1); // 0-based - document.addSignature(signature, this, signatureOptions); + document.addSignature(signature, this); // write incremental (only for signing purpose) document.saveIncremental(output); From bf98fd1616f50043ac3e68cab62a2cb1990bed57 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Thu, 16 Jun 2016 16:14:23 +0000 Subject: [PATCH 0128/2182] PDFBOX-3017: assign name/location/reason the values set in visibleSignatureProperties; don't use signatureOptions.setVisualSignature(visibleSignatureProperties) as this is misleading git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1748754 13f79535-47bb-0310-9956-ffa450edef68 --- .../signature/CreateVisibleSignature.java | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateVisibleSignature.java b/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateVisibleSignature.java index df176a46b7b..62d2934fd61 100644 --- a/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateVisibleSignature.java +++ b/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateVisibleSignature.java @@ -133,12 +133,19 @@ public void signPDF(File inputFile, File signedFile, TSAClient tsaClient) throws // create signature dictionary PDSignature signature = new PDSignature(); - signature.setFilter(PDSignature.FILTER_ADOBE_PPKLITE); // default filter + + // default filter + signature.setFilter(PDSignature.FILTER_ADOBE_PPKLITE); + // subfilter for basic and PAdES Part 2 signatures signature.setSubFilter(PDSignature.SUBFILTER_ADBE_PKCS7_DETACHED); - signature.setName("signer name"); - signature.setLocation("signer location"); - signature.setReason("reason for signature"); + + if (visibleSignatureProperties != null) + { + signature.setName(visibleSignatureProperties.getSignerName()); + signature.setLocation(visibleSignatureProperties.getSignerLocation()); + signature.setReason(visibleSignatureProperties.getSignatureReason()); + } // the signing date, needed for valid signature signature.setSignDate(Calendar.getInstance()); @@ -147,7 +154,7 @@ public void signPDF(File inputFile, File signedFile, TSAClient tsaClient) throws if (visibleSignatureProperties != null && visibleSignatureProperties.isVisualSignEnabled()) { signatureOptions = new SignatureOptions(); - signatureOptions.setVisualSignature(visibleSignatureProperties); + signatureOptions.setVisualSignature(visibleSignatureProperties.getVisibleSignature()); signatureOptions.setPage(visibleSignatureProperties.getPage() - 1); doc.addSignature(signature, this, signatureOptions); } From 367a8898da2817161b2d09080ec07633a9e1b847 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Sat, 18 Jun 2016 11:01:41 +0000 Subject: [PATCH 0129/2182] PDFBOX-3017: SonarQube fix git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1748962 13f79535-47bb-0310-9956-ffa450edef68 --- .../pdfbox/examples/signature/ShowSignature.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/examples/src/main/java/org/apache/pdfbox/examples/signature/ShowSignature.java b/examples/src/main/java/org/apache/pdfbox/examples/signature/ShowSignature.java index 1c4fa0d1fd6..907f0fbd09a 100644 --- a/examples/src/main/java/org/apache/pdfbox/examples/signature/ShowSignature.java +++ b/examples/src/main/java/org/apache/pdfbox/examples/signature/ShowSignature.java @@ -105,8 +105,15 @@ private void showSignature(String[] args) throws IOException, CertificateExcepti // download the signed content FileInputStream fis = new FileInputStream(infile); - byte[] buf = sig.getSignedContent(fis); - fis.close(); + byte[] buf = null; + try + { + buf = sig.getSignedContent(fis); + } + finally + { + fis.close(); + } System.out.println("Signature found"); System.out.println("Name: " + sig.getName()); From 25f2437521be8db945c2c40fa4145d36e3733d4e Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Sat, 18 Jun 2016 14:02:46 +0000 Subject: [PATCH 0130/2182] PDFBOX-3382: speed up encoding git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1749037 13f79535-47bb-0310-9956-ffa450edef68 --- .../pdfbox/pdmodel/font/PDType1Font.java | 27 ++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1Font.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1Font.java index feb3ca390a7..5069d108c31 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1Font.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1Font.java @@ -88,14 +88,27 @@ public class PDType1Font extends PDSimpleFont public static final PDType1Font SYMBOL = new PDType1Font("Symbol"); public static final PDType1Font ZAPF_DINGBATS = new PDType1Font("ZapfDingbats"); - private final Type1Font type1font; // embedded font - private final FontBoxFont genericFont; // embedded or system font for rendering + /** + * embedded font. + */ + private final Type1Font type1font; + + /** + * embedded or system font for rendering. + */ + private final FontBoxFont genericFont; + private final boolean isEmbedded; private final boolean isDamaged; private Matrix fontMatrix; private final AffineTransform fontMatrixTransform; private BoundingBox fontBBox; + /** + * to improve encoding speed. + */ + final private Map codeToBytesMap = new HashMap(); + /** * Creates a Type 1 standard 14 font for embedding. * @@ -339,6 +352,12 @@ public float getHeight(int code) throws IOException @Override protected byte[] encode(int unicode) throws IOException { + byte[] bytes = codeToBytesMap.get(unicode); + if (bytes != null) + { + return bytes; + } + String name = getGlyphList().codePointToName(unicode); if (!encoding.contains(name)) { @@ -357,7 +376,9 @@ protected byte[] encode(int unicode) throws IOException } int code = inverted.get(name); - return new byte[] { (byte)code }; + bytes = new byte[] { (byte)code }; + codeToBytesMap.put(code, bytes); + return bytes; } @Override From 5fba8f6821a6e81bcd13400006ba920697987fa9 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Sat, 18 Jun 2016 14:11:43 +0000 Subject: [PATCH 0131/2182] PDFBOX-3382: speed up hex writing, don't check for hex if it is already forced git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1749055 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/pdfbox/pdfwriter/COSWriter.java | 35 ++++++++++++------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdfwriter/COSWriter.java b/pdfbox/src/main/java/org/apache/pdfbox/pdfwriter/COSWriter.java index 6a356e019d9..fe186fcffa2 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdfwriter/COSWriter.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdfwriter/COSWriter.java @@ -67,7 +67,6 @@ import org.apache.pdfbox.pdmodel.fdf.FDFDocument; import org.apache.pdfbox.pdmodel.interactive.digitalsignature.SignatureInterface; import org.apache.pdfbox.util.Charsets; -import org.apache.pdfbox.util.Hex; /** * This class acts on a in-memory representation of a PDF document. @@ -159,6 +158,11 @@ public class COSWriter implements ICOSVisitor, Closeable */ public static final byte[] ENDSTREAM = "endstream".getBytes(Charsets.US_ASCII); + /** + * for hex conversion. + */ + private static final byte[] HEXES = "0123456789ABCDEF".getBytes(Charsets.US_ASCII); + private final NumberFormat formatXrefOffset = new DecimalFormat("0000000000"); // the decimal format for the xref object generation number data @@ -1380,19 +1384,22 @@ private static void writeString(byte[] bytes, boolean forceHex, OutputStream out { // check for non-ASCII characters boolean isASCII = true; - for (byte b : bytes) + if (!forceHex) { - // if the byte is negative then it is an eight bit byte and is outside the ASCII range - if (b < 0) - { - isASCII = false; - break; - } - // PDFBOX-3107 EOL markers within a string are troublesome - if (b == 0x0d || b == 0x0a) + for (byte b : bytes) { - isASCII = false; - break; + // if the byte is negative then it is an eight bit byte and is outside the ASCII range + if (b < 0) + { + isASCII = false; + break; + } + // PDFBOX-3107 EOL markers within a string are troublesome + if (b == 0x0d || b == 0x0a) + { + isASCII = false; + break; + } } } @@ -1422,7 +1429,9 @@ private static void writeString(byte[] bytes, boolean forceHex, OutputStream out output.write('<'); for (byte b : bytes) { - output.write(Hex.getBytes(b)); + // https://stackoverflow.com/questions/2817752/java-code-to-convert-byte-to-hexadecimal + output.write(HEXES[(b & 0xF0) >> 4]); + output.write(HEXES[b & 0x0F]); } output.write('>'); } From ef603a4851b5d8df09a80ea80fb4809c7701b0e5 Mon Sep 17 00:00:00 2001 From: John Hewson Date: Sun, 19 Jun 2016 07:31:56 +0000 Subject: [PATCH 0132/2182] PDFBOX-3337: Don't clear data when closing an in-memory TTF stream git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1749136 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/fontbox/ttf/MemoryTTFDataStream.java | 1 - 1 file changed, 1 deletion(-) diff --git a/fontbox/src/main/java/org/apache/fontbox/ttf/MemoryTTFDataStream.java b/fontbox/src/main/java/org/apache/fontbox/ttf/MemoryTTFDataStream.java index 45ffdebf569..11d1d8d6d48 100644 --- a/fontbox/src/main/java/org/apache/fontbox/ttf/MemoryTTFDataStream.java +++ b/fontbox/src/main/java/org/apache/fontbox/ttf/MemoryTTFDataStream.java @@ -146,7 +146,6 @@ public short readSignedShort() throws IOException */ public void close() throws IOException { - data = null; } /** From 6753a8709a3f5201dfd404d864a887bd03512953 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Sun, 19 Jun 2016 10:04:57 +0000 Subject: [PATCH 0133/2182] PDFBOX-3382: reorder modifier according to JLS suggestions git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1749143 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/pdfbox/pdmodel/font/PDType1Font.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1Font.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1Font.java index 5069d108c31..044f65af945 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1Font.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1Font.java @@ -107,7 +107,7 @@ public class PDType1Font extends PDSimpleFont /** * to improve encoding speed. */ - final private Map codeToBytesMap = new HashMap(); + private final Map codeToBytesMap = new HashMap(); /** * Creates a Type 1 standard 14 font for embedding. From 1617bd39c76ff67565b759d568097483a130400a Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Sun, 19 Jun 2016 10:21:07 +0000 Subject: [PATCH 0134/2182] PDFBOX-3337: added test code from Philip Helger git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1749146 13f79535-47bb-0310-9956-ffa450edef68 --- .../pdfbox/pdmodel/font/PDFontTest.java | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/font/PDFontTest.java b/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/font/PDFontTest.java index e78dfc86175..4f8dbe545e7 100644 --- a/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/font/PDFontTest.java +++ b/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/font/PDFontTest.java @@ -19,8 +19,14 @@ package org.apache.pdfbox.pdmodel.font; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; import junit.framework.TestCase; import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.pdmodel.PDPage; +import org.apache.pdfbox.pdmodel.PDPageContentStream; +import org.apache.pdfbox.pdmodel.common.PDRectangle; import org.apache.pdfbox.rendering.PDFRenderer; /** @@ -51,4 +57,34 @@ public void testPDFBox988() throws Exception } } } + + /** + * PDFBOX-3337: Test ability to reuse a TrueTypeFont for several PDFs to avoid parsing it over + * and over again. + * + * @throws java.io.IOException + */ + public void testPDFBox3337() throws IOException + { + InputStream ttfStream = PDFontTest.class.getClassLoader().getResourceAsStream( + "org/apache/pdfbox/ttf/LiberationSans-Regular.ttf"); + + for (int i = 0; i < 2; ++i) + { + PDDocument doc = new PDDocument(); + + final PDPage page = new PDPage(PDRectangle.A4); + doc.addPage(page); + + PDPageContentStream cs = new PDPageContentStream(doc, page); + PDFont font = PDType0Font.load(doc, ttfStream); + cs.setFont(font, 10); + cs.beginText(); + cs.showText("PDFBOX"); + cs.endText(); + cs.close(); + doc.save(new ByteArrayOutputStream()); + doc.close(); + } + } } From 90cd63e65a5acf9ca4a8d2c4fa238a676d093fe1 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Sun, 19 Jun 2016 11:27:38 +0000 Subject: [PATCH 0135/2182] PDFBOX-3337: added test code from Philip Helger git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1749152 13f79535-47bb-0310-9956-ffa450edef68 --- .../test/java/org/apache/pdfbox/pdmodel/font/PDFontTest.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/font/PDFontTest.java b/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/font/PDFontTest.java index 4f8dbe545e7..fdf4967fa4b 100644 --- a/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/font/PDFontTest.java +++ b/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/font/PDFontTest.java @@ -23,6 +23,8 @@ import java.io.IOException; import java.io.InputStream; import junit.framework.TestCase; +import org.apache.fontbox.ttf.TTFParser; +import org.apache.fontbox.ttf.TrueTypeFont; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.PDPageContentStream; @@ -68,6 +70,7 @@ public void testPDFBox3337() throws IOException { InputStream ttfStream = PDFontTest.class.getClassLoader().getResourceAsStream( "org/apache/pdfbox/ttf/LiberationSans-Regular.ttf"); + final TrueTypeFont ttf = new TTFParser ().parse (ttfStream); for (int i = 0; i < 2; ++i) { @@ -77,7 +80,7 @@ public void testPDFBox3337() throws IOException doc.addPage(page); PDPageContentStream cs = new PDPageContentStream(doc, page); - PDFont font = PDType0Font.load(doc, ttfStream); + PDFont font = PDType0Font.load(doc, ttf, true); cs.setFont(font, 10); cs.beginText(); cs.showText("PDFBOX"); From bd31f1ee784b368a62ceb13eb109679d73ad7bb6 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Sun, 19 Jun 2016 11:57:27 +0000 Subject: [PATCH 0136/2182] PDFBOX-3280: revert 1741294 because it resulted in split creating huge files git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1749157 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/pdfbox/pdmodel/PDDocument.java | 33 +++++++++++-------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java index 23d2a5efdd1..2aee7e88773 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java @@ -42,7 +42,6 @@ import org.apache.pdfbox.io.RandomAccessBufferedFileInputStream; import org.apache.pdfbox.io.RandomAccessRead; import org.apache.pdfbox.io.ScratchFile; -import org.apache.pdfbox.multipdf.PDFCloneUtility; import org.apache.pdfbox.pdfparser.PDFParser; import org.apache.pdfbox.pdfwriter.COSWriter; import org.apache.pdfbox.pdmodel.common.COSArrayList; @@ -505,26 +504,34 @@ public void removePage(int pageNumber) * document and want to copy the contents to this document's scratch file then use this method otherwise just use * the {@link #addPage} method. * - * Unlike {@link #addPage}, this method does a deep clone. This will be slower and have a larger - * memory footprint. However the deep clone is important to avoid resources getting lost if the - * source document is closed when the destination document is saved. - * - * If your page has annotations, and if these link to pages not in the target document, then the - * target document might become huge. What you need to do is to delete page references of such - * annotations. See + * Unlike {@link #addPage}, this method does a deep copy. If your page has annotations, and if + * these link to pages not in the target document, then the target document might become huge. + * What you need to do is to delete page references of such annotations. See * here for how to do this. * * @param page The page to import. * @return The page that was imported. - * + * * @throws IOException If there is an error copying the page. */ public PDPage importPage(PDPage page) throws IOException { - PDFCloneUtility cloner = new PDFCloneUtility(this); - COSBase pageBase = cloner.cloneForNewDocument(page.getCOSObject()); - PDPage importedPage = new PDPage((COSDictionary) pageBase, resourceCache); - addPage(importedPage); + PDPage importedPage = new PDPage(new COSDictionary(page.getCOSObject()), resourceCache); + InputStream in = null; + try + { + in = page.getContents(); + if (in != null) + { + PDStream dest = new PDStream(this, in, COSName.FLATE_DECODE); + importedPage.setContents(dest); + } + addPage(importedPage); + } + catch (IOException e) + { + IOUtils.closeQuietly(in); + } return importedPage; } From c449d81e1379e862fddcdb6b3e25e94224301ca4 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Sun, 19 Jun 2016 11:59:13 +0000 Subject: [PATCH 0137/2182] PDFBOX-3280: remove test due to revert of 1741294 git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1749158 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/pdfbox/pdmodel/TestPDDocument.java | 54 ------------------- 1 file changed, 54 deletions(-) diff --git a/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/TestPDDocument.java b/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/TestPDDocument.java index 40cf3ccf733..e203c1d86cc 100644 --- a/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/TestPDDocument.java +++ b/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/TestPDDocument.java @@ -16,10 +16,6 @@ */ package org.apache.pdfbox.pdmodel; -import java.awt.Color; -import java.awt.Font; -import java.awt.Graphics; -import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; @@ -37,11 +33,6 @@ import static junit.framework.TestCase.assertNull; import static junit.framework.TestCase.assertTrue; import static junit.framework.TestCase.fail; -import org.apache.pdfbox.pdmodel.font.PDType1Font; -import org.apache.pdfbox.pdmodel.graphics.image.LosslessFactory; -import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject; -import org.apache.pdfbox.rendering.PDFRenderer; -import org.junit.Assert; /** * Testcase introduced with PDFBOX-1581. @@ -259,49 +250,4 @@ public void testDeleteGoodFile() throws IOException boolean deleted = f.delete(); assertTrue("delete good file failed after successful load() and close()", deleted); } - - /** - * Test whether importPage does a deep copy (if not, the save would fail, see PDFBOX-3328) - * - * @throws java.io.IOException - */ - public void testImportPage() throws IOException - { - PDDocument doc1 = new PDDocument(); - PDPage page = new PDPage(); - PDPageContentStream pageContentStream = new PDPageContentStream(doc1, page); - BufferedImage bim = new BufferedImage(100, 50, BufferedImage.TYPE_INT_RGB); - Graphics g = bim.getGraphics(); - Font font = new Font("Dialog", Font.PLAIN, 20); - g.setFont(font); - g.drawString("PDFBox", 10, 30); - g.dispose(); - PDImageXObject img = LosslessFactory.createFromImage(doc1, bim); - pageContentStream.drawImage(img, 200, 500); - pageContentStream.setFont(PDType1Font.HELVETICA, 20); - pageContentStream.beginText(); - pageContentStream.setNonStrokingColor(Color.blue); - pageContentStream.newLineAtOffset(200, 600); - pageContentStream.showText("PDFBox"); - pageContentStream.endText(); - pageContentStream.close(); - doc1.addPage(page); - BufferedImage bim1 = new PDFRenderer(doc1).renderImage(0); - - PDDocument doc2 = new PDDocument(); - doc2.importPage(doc1.getPage(0)); - doc1.close(); - BufferedImage bim2 = new PDFRenderer(doc2).renderImage(0); - doc2.save(new ByteArrayOutputStream()); - doc2.close(); - - assertEquals(bim1.getWidth(), bim2.getWidth()); - assertEquals(bim1.getHeight(), bim2.getHeight()); - int w = bim1.getWidth(); - int h = bim1.getHeight(); - int[] pixels1 = bim1.getRaster().getPixels(0, 0, w, h, (int[]) null); - int[] pixels2 = bim2.getRaster().getPixels(0, 0, w, h, (int[]) null); - assertEquals(w * h * 3, pixels1.length); - Assert.assertArrayEquals(pixels1, pixels2); - } } From eb5e1cd0f90ae14535e684083a9df11c277cefa1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Lehmk=C3=BChler?= Date: Sun, 19 Jun 2016 13:11:57 +0000 Subject: [PATCH 0138/2182] PDFBOX-3386: downgrade maven-bundle-plugin due to jdk6 compatibility git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1749164 13f79535-47bb-0310-9956-ffa450edef68 --- parent/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parent/pom.xml b/parent/pom.xml index 569caaf3299..e1215aa1912 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -240,7 +240,7 @@ org.apache.felix maven-bundle-plugin - 3.0.1 + 2.5.4 From cf0b37633515d094e9842c9bcf5d8b97d4a75e9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Lehmk=C3=BChler?= Date: Sun, 19 Jun 2016 13:18:46 +0000 Subject: [PATCH 0139/2182] PDFBOX-3386: added a comment on using an outdated plugin version git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1749166 13f79535-47bb-0310-9956-ffa450edef68 --- parent/pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/parent/pom.xml b/parent/pom.xml index e1215aa1912..d5948a3e553 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -240,6 +240,7 @@ org.apache.felix maven-bundle-plugin + 2.5.4 From 4137bf5271c559a6ab7523766dab14b520d2fdec Mon Sep 17 00:00:00 2001 From: Maruan Sahyoun Date: Mon, 20 Jun 2016 14:57:46 +0000 Subject: [PATCH 0140/2182] PDFBOX-3387: make sure the fields widget is printable git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1749351 13f79535-47bb-0310-9956-ffa450edef68 --- .../pdfbox/examples/interactive/form/CreateSimpleForm.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/src/main/java/org/apache/pdfbox/examples/interactive/form/CreateSimpleForm.java b/examples/src/main/java/org/apache/pdfbox/examples/interactive/form/CreateSimpleForm.java index 0cca6556c59..451050aa03e 100644 --- a/examples/src/main/java/org/apache/pdfbox/examples/interactive/form/CreateSimpleForm.java +++ b/examples/src/main/java/org/apache/pdfbox/examples/interactive/form/CreateSimpleForm.java @@ -84,6 +84,9 @@ public static void main(String[] args) throws IOException PDRectangle rect = new PDRectangle(50, 750, 200, 50); widget.setRectangle(rect); widget.setPage(page); + + // make sure the annotation is visible on screen and paper + widget.setPrinted(true); // Add the annotation to the page page.getAnnotations().add(widget); From b5fb08a9a6add254536fa0aa7da05e9ac917b3ef Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Mon, 20 Jun 2016 16:05:13 +0000 Subject: [PATCH 0141/2182] PDFBOX-3382: speed up getWidth() git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1749353 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/pdfbox/pdmodel/font/PDFont.java | 31 ++++++++++++++++--- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDFont.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDFont.java index d2d17ccc0d1..eb4e4bb76b0 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDFont.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDFont.java @@ -21,7 +21,9 @@ import java.io.IOException; import java.io.InputStream; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.fontbox.afm.FontMetrics; @@ -52,12 +54,17 @@ public abstract class PDFont implements COSObjectable, PDFontLike protected final COSDictionary dict; private final CMap toUnicodeCMap; - private final FontMetrics afmStandard14; // AFM for standard 14 fonts + + /** + * AFM for standard 14 fonts + */ + private final FontMetrics afmStandard14; private PDFontDescriptor fontDescriptor; private List widths; private float avgFontWidth; private float fontWidthOfSpace = -1f; + private final Map codeToWidthMap = new HashMap(); /** * Constructor for embedding. @@ -215,6 +222,12 @@ public Vector getDisplacement(int code) throws IOException @Override public float getWidth(int code) throws IOException { + Float width = codeToWidthMap.get(code); + if (width != null) + { + return width; + } + // Acrobat overrides the widths in the font program on the conforming reader's system with // the widths specified in the font dictionary." (Adobe Supplement to the ISO 32000) // @@ -230,25 +243,33 @@ public float getWidth(int code) throws IOException int idx = code - firstChar; if (siz > 0 && code >= firstChar && code <= lastChar && idx < siz) { - return getWidths().get(idx); + width = getWidths().get(idx); + codeToWidthMap.put(code, width); + return width; } PDFontDescriptor fd = getFontDescriptor(); if (fd != null && fd.hasMissingWidth()) { // get entry from /MissingWidth entry - return fd.getMissingWidth(); + width = fd.getMissingWidth(); + codeToWidthMap.put(code, width); + return width; } } // standard 14 font widths are specified by an AFM if (isStandard14()) { - return getStandard14Width(code); + width = getStandard14Width(code); + codeToWidthMap.put(code, width); + return width; } // if there's nothing to override with, then obviously we fall back to the font - return getWidthFromFont(code); + width = getWidthFromFont(code); + codeToWidthMap.put(code, width); + return width; } /** From bf91a064517fae9cc4a1267ea6fbf1b11852e37c Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Mon, 20 Jun 2016 16:11:29 +0000 Subject: [PATCH 0142/2182] PDFBOX-2852: remove tests that are duplicate due to removal of non sequential parser git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1749354 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/pdfbox/pdmodel/TestPDDocument.java | 57 ------------------- 1 file changed, 57 deletions(-) diff --git a/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/TestPDDocument.java b/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/TestPDDocument.java index e203c1d86cc..9160589bec0 100644 --- a/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/TestPDDocument.java +++ b/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/TestPDDocument.java @@ -106,63 +106,6 @@ public void testSaveLoadFile() throws IOException loadDoc.close(); } - /** - * Test document save/loadNonSeq using a stream. - * @throws IOException if something went wrong - */ - public void testSaveLoadNonSeqStream() throws IOException - { - // Create PDF with one blank page - PDDocument document = new PDDocument(); - document.addPage(new PDPage()); - - // Save - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - document.save(baos); - document.close(); - - // Verify content - byte[] pdf = baos.toByteArray(); - assertTrue(pdf.length > 200); - assertEquals("%PDF-1.4", new String(Arrays.copyOfRange(pdf, 0, 8), "UTF-8")); - assertEquals("%%EOF\n", new String(Arrays.copyOfRange(pdf, pdf.length - 6, pdf.length), "UTF-8")); - - // Load - PDDocument loadDoc = PDDocument.load(new ByteArrayInputStream(pdf)); - assertEquals(1, loadDoc.getNumberOfPages()); - loadDoc.close(); - } - - /** - * Test document save/loadNonSeq using a file. - * @throws IOException if something went wrong - */ - public void testSaveLoadNonSeqFile() throws IOException - { - // Create PDF with one blank page - PDDocument document = new PDDocument(); - document.addPage(new PDPage()); - - // Save - File targetFile = new File(testResultsDir, "pddocument-saveloadnonseqfile.pdf"); - document.save(targetFile); - document.close(); - - // Verify content - assertTrue(targetFile.length() > 200); - InputStream in = new FileInputStream(targetFile); - byte[] pdf = IOUtils.toByteArray(in); - in.close(); - assertTrue(pdf.length > 200); - assertEquals("%PDF-1.4", new String(Arrays.copyOfRange(pdf, 0, 8), "UTF-8")); - assertEquals("%%EOF\n", new String(Arrays.copyOfRange(pdf, pdf.length - 6, pdf.length), "UTF-8")); - - // Load - PDDocument loadDoc = PDDocument.load(targetFile); - assertEquals(1, loadDoc.getNumberOfPages()); - loadDoc.close(); - } - /** * Test get/setVersion. * @throws IOException if something went wrong From a6eb493812f1b32981d5fbfbb221d144501e45bd Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Mon, 20 Jun 2016 16:19:23 +0000 Subject: [PATCH 0143/2182] PDFBOX-2852: fix javadoc git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1749356 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/pdfbox/pdmodel/PDPageContentStream.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPageContentStream.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPageContentStream.java index 9827b92e5a1..f89c16291cf 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPageContentStream.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPageContentStream.java @@ -2215,7 +2215,7 @@ public void addComment(String comment) throws IOException } /** - * Writes a real real to the content stream. + * Writes a real number to the content stream. */ private void writeOperand(float real) throws IOException { @@ -2224,7 +2224,7 @@ private void writeOperand(float real) throws IOException } /** - * Writes a real number to the content stream. + * Writes an integer number to the content stream. */ private void writeOperand(int integer) throws IOException { From 6299435bff1144fedb66afdaca2472b675b107a7 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Mon, 20 Jun 2016 16:21:06 +0000 Subject: [PATCH 0144/2182] PDFBOX-2852: fix javadoc git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1749357 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/pdfbox/pdmodel/PDPageContentStream.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPageContentStream.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPageContentStream.java index f89c16291cf..d9bffa173a3 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPageContentStream.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPageContentStream.java @@ -2259,7 +2259,7 @@ private void write(String text) throws IOException } /** - * Writes a string to the content stream as ASCII. + * Writes a newline to the content stream as ASCII. */ private void writeLine() throws IOException { From 431cd2eaab7bbafa29a661476745ced492c2c030 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Lehmk=C3=BChler?= Date: Tue, 21 Jun 2016 06:20:41 +0000 Subject: [PATCH 0145/2182] PDFBOX-3382: move optimized hex encoding code to utility class, optimize remaining methods as well based on Tilmans changes git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1749439 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/pdfbox/cos/COSString.java | 7 +- .../apache/pdfbox/filter/ASCIIHexFilter.java | 2 +- .../apache/pdfbox/pdfwriter/COSWriter.java | 19 +--- .../main/java/org/apache/pdfbox/util/Hex.java | 93 ++++++++++++++++++- 4 files changed, 97 insertions(+), 24 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/cos/COSString.java b/pdfbox/src/main/java/org/apache/pdfbox/cos/COSString.java index e51139dd7c8..d430d457512 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/cos/COSString.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/cos/COSString.java @@ -227,12 +227,7 @@ public byte[] getBytes() */ public String toHexString() { - StringBuilder sb = new StringBuilder(bytes.length * 2); - for (byte b : bytes) - { - sb.append(Hex.getString(b)); - } - return sb.toString(); + return Hex.getString(bytes); } /** diff --git a/pdfbox/src/main/java/org/apache/pdfbox/filter/ASCIIHexFilter.java b/pdfbox/src/main/java/org/apache/pdfbox/filter/ASCIIHexFilter.java index c9c52f57596..f86d2120202 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/filter/ASCIIHexFilter.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/filter/ASCIIHexFilter.java @@ -116,7 +116,7 @@ public void encode(InputStream input, OutputStream encoded, COSDictionary parame int byteRead; while ((byteRead = input.read()) != -1) { - encoded.write(Hex.getBytes((byte)byteRead)); + Hex.writeHexByte((byte)byteRead, encoded); } encoded.flush(); } diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdfwriter/COSWriter.java b/pdfbox/src/main/java/org/apache/pdfbox/pdfwriter/COSWriter.java index fe186fcffa2..832fc4e7977 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdfwriter/COSWriter.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdfwriter/COSWriter.java @@ -67,6 +67,7 @@ import org.apache.pdfbox.pdmodel.fdf.FDFDocument; import org.apache.pdfbox.pdmodel.interactive.digitalsignature.SignatureInterface; import org.apache.pdfbox.util.Charsets; +import org.apache.pdfbox.util.Hex; /** * This class acts on a in-memory representation of a PDF document. @@ -158,11 +159,6 @@ public class COSWriter implements ICOSVisitor, Closeable */ public static final byte[] ENDSTREAM = "endstream".getBytes(Charsets.US_ASCII); - /** - * for hex conversion. - */ - private static final byte[] HEXES = "0123456789ABCDEF".getBytes(Charsets.US_ASCII); - private final NumberFormat formatXrefOffset = new DecimalFormat("0000000000"); // the decimal format for the xref object generation number data @@ -772,16 +768,14 @@ private void doWriteSignature() throws IOException new ByteArrayInputStream(signBuffer)); // sign the bytes - byte[] sign = signatureInterface.sign(signStream); - String signature = new COSString(sign).toHexString(); + byte[] signatureBytes = Hex.getBytes(signatureInterface.sign(signStream)); // substract 2 bytes because of the enclosing "<>" - if (signature.length() > signatureLength - 2) + if (signatureBytes.length > signatureLength - 2) { throw new IOException("Can't write signature, not enough space"); } // overwrite the signature Contents in the buffer - byte[] signatureBytes = signature.getBytes(Charsets.ISO_8859_1); System.arraycopy(signatureBytes, 0, buffer, bufSignatureOffset + 1, signatureBytes.length); // write the data to the incremental output stream @@ -1427,12 +1421,7 @@ private static void writeString(byte[] bytes, boolean forceHex, OutputStream out { // write hex string output.write('<'); - for (byte b : bytes) - { - // https://stackoverflow.com/questions/2817752/java-code-to-convert-byte-to-hexadecimal - output.write(HEXES[(b & 0xF0) >> 4]); - output.write(HEXES[b & 0x0F]); - } + Hex.writeHexBytes(bytes, output); output.write('>'); } } diff --git a/pdfbox/src/main/java/org/apache/pdfbox/util/Hex.java b/pdfbox/src/main/java/org/apache/pdfbox/util/Hex.java index 238c28d38b5..a46cf189df5 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/util/Hex.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/util/Hex.java @@ -17,6 +17,9 @@ package org.apache.pdfbox.util; +import java.io.IOException; +import java.io.OutputStream; + /** * Utility functions for hex encoding. * @@ -24,6 +27,16 @@ */ public final class Hex { + /** + * for hex conversion. + * + * https://stackoverflow.com/questions/2817752/java-code-to-convert-byte-to-hexadecimal + * + */ + private static final String HEXES_STRING = "0123456789ABCDEF"; + + private static final byte[] HEXES = HEXES_STRING.getBytes(Charsets.US_ASCII); + private Hex() {} /** @@ -31,7 +44,21 @@ private Hex() {} */ public static String getString(byte b) { - return Integer.toHexString(0x100 | b & 0xff).substring(1).toUpperCase(); + char[] chars = new char[]{HEXES_STRING.charAt(getHighNibble(b)), HEXES_STRING.charAt(getLowNibble(b))}; + return new String(chars); + } + + /** + * Returns a hex string of the given byte array. + */ + public static String getString(byte[] bytes) + { + StringBuilder string = new StringBuilder(bytes.length * 2); + for (byte b : bytes) + { + string.append(HEXES_STRING.charAt(getHighNibble(b))).append(HEXES_STRING.charAt(getLowNibble(b))); + } + return string.toString(); } /** @@ -39,6 +66,68 @@ public static String getString(byte b) */ public static byte[] getBytes(byte b) { - return getString(b).getBytes(Charsets.US_ASCII); + return new byte[]{HEXES[getHighNibble(b)], HEXES[getLowNibble(b)]}; + } + + /** + * Returns the bytes corresponding to the ASCII hex encoding of the given bytes. + */ + public static byte[] getBytes(byte[] bytes) + { + byte[] asciiBytes = new byte[bytes.length*2]; + for(int i=0; i< bytes.length; i++) + { + asciiBytes[i*2] = HEXES[getHighNibble(bytes[i])]; + asciiBytes[i*2+1] = HEXES[getLowNibble(bytes[i])]; + } + return asciiBytes; + } + + /** + * Writes the given byte as hex value to the given output stream. + * @param b the byte to be written + * @param output the output stream to be written to + * @throws IOException exception if anything went wrong + */ + public static void writeHexByte(byte b, OutputStream output) throws IOException + { + output.write(HEXES[getHighNibble(b)]); + output.write(HEXES[getLowNibble(b)]); + } + + /** + * Writes the given byte array as hex value to the given output stream. + * @param b the byte array to be written + * @param output the output stream to be written to + * @throws IOException exception if anything went wrong + */ + public static void writeHexBytes(byte[] bytes, OutputStream output) throws IOException + { + for (byte b : bytes) + { + writeHexByte(b, output); + } + } + + /** + * Get the high nibble of the given byte. + * + * @param b the given byte + * @return the high nibble + */ + private static int getHighNibble(byte b) + { + return (b & 0xF0) >> 4; + } + + /** + * Get the low nibble of the given byte. + * + * @param b the given byte + * @return the low nibble + */ + private static int getLowNibble(byte b) + { + return b & 0x0F; } } From b009b6703e8bce558cda398ccb5164ada664e99c Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Tue, 21 Jun 2016 16:25:28 +0000 Subject: [PATCH 0146/2182] PDFBOX-2852: fix javadoc git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1749566 13f79535-47bb-0310-9956-ffa450edef68 --- pdfbox/src/main/java/org/apache/pdfbox/util/Hex.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/util/Hex.java b/pdfbox/src/main/java/org/apache/pdfbox/util/Hex.java index a46cf189df5..36aef19ede6 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/util/Hex.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/util/Hex.java @@ -97,7 +97,7 @@ public static void writeHexByte(byte b, OutputStream output) throws IOException /** * Writes the given byte array as hex value to the given output stream. - * @param b the byte array to be written + * @param bytes the byte array to be written * @param output the output stream to be written to * @throws IOException exception if anything went wrong */ From 909f72c3cff7d5ed509098e730b7b12675ac42fd Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Tue, 21 Jun 2016 16:35:23 +0000 Subject: [PATCH 0147/2182] PDFBOX-2852: fix javadoc git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1749568 13f79535-47bb-0310-9956-ffa450edef68 --- .../pdfbox/pdmodel/graphics/form/PDFormXObject.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/form/PDFormXObject.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/form/PDFormXObject.java index 2d5f079ae5f..ac7a3973c7e 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/form/PDFormXObject.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/form/PDFormXObject.java @@ -145,10 +145,10 @@ public InputStream getContents() throws IOException } /** - * This will get the resources at this page and not look up the hierarchy. - * This attribute is inheritable, and findResources() should probably used. - * This will return null if no resources are available at this level. - * @return The resources at this level in the hierarchy. + * This will get the resources for this Form XObject. + * This will return null if no resources are available. + * + * @return The resources for this Form XObject. */ @Override public PDResources getResources() From 9183a17b93695763062ffe0bc116aa2e63ef767e Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Thu, 23 Jun 2016 16:41:07 +0000 Subject: [PATCH 0148/2182] PDFBOX-3069: add CCITT G4 (T6) encoding from BufferedImage with encoder from twelvemonkeys; add check for orientation git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1749939 13f79535-47bb-0310-9956-ffa450edef68 --- .../pdfbox/filter/CCITTFaxEncoderStream.java | 323 ++++++++++++++++++ .../apache/pdfbox/filter/CCITTFaxFilter.java | 12 +- .../pdmodel/graphics/image/CCITTFactory.java | 84 ++++- .../graphics/image/CCITTFactoryTest.java | 61 +++- 4 files changed, 474 insertions(+), 6 deletions(-) create mode 100644 pdfbox/src/main/java/org/apache/pdfbox/filter/CCITTFaxEncoderStream.java diff --git a/pdfbox/src/main/java/org/apache/pdfbox/filter/CCITTFaxEncoderStream.java b/pdfbox/src/main/java/org/apache/pdfbox/filter/CCITTFaxEncoderStream.java new file mode 100644 index 00000000000..96d3b3124ef --- /dev/null +++ b/pdfbox/src/main/java/org/apache/pdfbox/filter/CCITTFaxEncoderStream.java @@ -0,0 +1,323 @@ +/* + * Copyright (c) 2013, Harald Kuhr + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name "TwelveMonkeys" nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.apache.pdfbox.filter; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * CCITT Modified Group 4 (T6) fax compression. + * + * @author Oliver Schmidtmer + * + * Taken from commit 047884e3d9e1b30516c79b147ead763303dc9bcb of 21.4.2016 from + * twelvemonkeys/imageio/plugins/tiff/CCITTFaxEncoderStream.java + * + * Initial changes for PDFBox: + * - removed Validate + * - G4 compression only + * - removed options + */ +final class CCITTFaxEncoderStream extends OutputStream { + + private int currentBufferLength = 0; + private final byte[] inputBuffer; + private final int inputBufferLength; + private final int columns; + private final int rows; + + private int[] changesCurrentRow; + private int[] changesReferenceRow; + private int currentRow = 0; + private int changesCurrentRowLength = 0; + private int changesReferenceRowLength = 0; + private byte outputBuffer = 0; + private byte outputBufferBitLength = 0; + private final int fillOrder; + private final OutputStream stream; + + CCITTFaxEncoderStream(final OutputStream stream, final int columns, final int rows, final int fillOrder) { + + this.stream = stream; + this.columns = columns; + this.rows = rows; + this.fillOrder = fillOrder; + + this.changesReferenceRow = new int[columns]; + this.changesCurrentRow = new int[columns]; + + inputBufferLength = (columns + 7) / 8; + inputBuffer = new byte[inputBufferLength]; + } + + @Override + public void write(int b) throws IOException { + inputBuffer[currentBufferLength] = (byte) b; + currentBufferLength++; + + if (currentBufferLength == inputBufferLength) { + encodeRow(); + currentBufferLength = 0; + } + } + + @Override + public void flush() throws IOException { + stream.flush(); + } + + @Override + public void close() throws IOException { + stream.close(); + } + + private void encodeRow() throws IOException { + currentRow++; + int[] tmp = changesReferenceRow; + changesReferenceRow = changesCurrentRow; + changesCurrentRow = tmp; + changesReferenceRowLength = changesCurrentRowLength; + changesCurrentRowLength = 0; + + int index = 0; + boolean white = true; + while (index < columns) { + int byteIndex = index / 8; + int bit = index % 8; + if ((((inputBuffer[byteIndex] >> (7 - bit)) & 1) == 1) == (white)) { + changesCurrentRow[changesCurrentRowLength] = index; + changesCurrentRowLength++; + white = !white; + } + index++; + } + + encodeRowType6(); + + if (currentRow == rows) { + writeEOL(); + writeEOL(); + fill(); + } + } + + + private void encodeRowType6() throws IOException { + encode2D(); + } + + private int[] getNextChanges(int pos, boolean white) { + int[] result = new int[] {columns, columns}; + for (int i = 0; i < changesCurrentRowLength; i++) { + if (pos < changesCurrentRow[i] || (pos == 0 && white)) { + result[0] = changesCurrentRow[i]; + if ((i + 1) < changesCurrentRowLength) { + result[1] = changesCurrentRow[i + 1]; + } + break; + } + } + + return result; + } + + private void writeRun(int runLength, boolean white) throws IOException { + int nonterm = runLength / 64; + Code[] codes = white ? WHITE_NONTERMINATING_CODES : BLACK_NONTERMINATING_CODES; + while (nonterm > 0) { + if (nonterm >= codes.length) { + write(codes[codes.length - 1].code, codes[codes.length - 1].length); + nonterm -= codes.length; + } + else { + write(codes[nonterm - 1].code, codes[nonterm - 1].length); + nonterm = 0; + } + } + + Code c = white ? WHITE_TERMINATING_CODES[runLength % 64] : BLACK_TERMINATING_CODES[runLength % 64]; + write(c.code, c.length); + } + + private void encode2D() throws IOException { + boolean white = true; + int index = 0; // a0 + while (index < columns) { + int[] nextChanges = getNextChanges(index, white); // a1, a2 + + int[] nextRefs = getNextRefChanges(index, white); // b1, b2 + + int difference = nextChanges[0] - nextRefs[0]; + if (nextChanges[0] > nextRefs[1]) { + // PMODE + write(1, 4); + index = nextRefs[1]; + } + else if (difference > 3 || difference < -3) { + // HMODE + write(1, 3); + writeRun(nextChanges[0] - index, white); + writeRun(nextChanges[1] - nextChanges[0], !white); + index = nextChanges[1]; + + } + else { + // VMODE + switch (difference) { + case 0: + write(1, 1); + break; + case 1: + write(3, 3); + break; + case 2: + write(3, 6); + break; + case 3: + write(3, 7); + break; + case -1: + write(2, 3); + break; + case -2: + write(2, 6); + break; + case -3: + write(2, 7); + break; + } + white = !white; + index = nextRefs[0] + difference; + } + } + } + + private int[] getNextRefChanges(int a0, boolean white) { + int[] result = new int[] {columns, columns}; + for (int i = (white ? 0 : 1); i < changesReferenceRowLength; i += 2) { + if (changesReferenceRow[i] > a0 || (a0 == 0 && i == 0)) { + result[0] = changesReferenceRow[i]; + if ((i + 1) < changesReferenceRowLength) { + result[1] = changesReferenceRow[i + 1]; + } + break; + } + } + return result; + } + + private void write(int code, int codeLength) throws IOException { + + for (int i = 0; i < codeLength; i++) { + boolean codeBit = ((code >> (codeLength - i - 1)) & 1) == 1; + if (fillOrder == TIFFExtension.FILL_LEFT_TO_RIGHT) { + outputBuffer |= (codeBit ? 1 << (7 - ((outputBufferBitLength) % 8)) : 0); + } + else { + outputBuffer |= (codeBit ? 1 << (((outputBufferBitLength) % 8)) : 0); + } + outputBufferBitLength++; + + if (outputBufferBitLength == 8) { + stream.write(outputBuffer); + clearOutputBuffer(); + } + } + } + + private void writeEOL() throws IOException { + write(1, 12); + } + + private void fill() throws IOException { + if (outputBufferBitLength != 0) { + stream.write(outputBuffer); + } + clearOutputBuffer(); + } + + private void clearOutputBuffer() { + outputBuffer = 0; + outputBufferBitLength = 0; + } + + public static class Code { + private Code(int code, int length) { + this.code = code; + this.length = length; + } + + final int code; + final int length; + } + + public static final Code[] WHITE_TERMINATING_CODES; + + public static final Code[] WHITE_NONTERMINATING_CODES; + + public static final Code[] BLACK_TERMINATING_CODES; + + public static final Code[] BLACK_NONTERMINATING_CODES; + + static { + // Setup HUFFMAN Codes + WHITE_TERMINATING_CODES = new Code[64]; + WHITE_NONTERMINATING_CODES = new Code[40]; + for (int i = 0; i < CCITTFaxDecoderStream.WHITE_CODES.length; i++) { + int bitLength = i + 4; + for (int j = 0; j < CCITTFaxDecoderStream.WHITE_CODES[i].length; j++) { + int value = CCITTFaxDecoderStream.WHITE_RUN_LENGTHS[i][j]; + int code = CCITTFaxDecoderStream.WHITE_CODES[i][j]; + + if (value < 64) { + WHITE_TERMINATING_CODES[value] = new Code(code, bitLength); + } + else { + WHITE_NONTERMINATING_CODES[(value / 64) - 1] = new Code(code, bitLength); + } + } + } + + BLACK_TERMINATING_CODES = new Code[64]; + BLACK_NONTERMINATING_CODES = new Code[40]; + for (int i = 0; i < CCITTFaxDecoderStream.BLACK_CODES.length; i++) { + int bitLength = i + 2; + for (int j = 0; j < CCITTFaxDecoderStream.BLACK_CODES[i].length; j++) { + int value = CCITTFaxDecoderStream.BLACK_RUN_LENGTHS[i][j]; + int code = CCITTFaxDecoderStream.BLACK_CODES[i][j]; + + if (value < 64) { + BLACK_TERMINATING_CODES[value] = new Code(code, bitLength); + } + else { + BLACK_NONTERMINATING_CODES[(value / 64) - 1] = new Code(code, bitLength); + } + } + } + } +} diff --git a/pdfbox/src/main/java/org/apache/pdfbox/filter/CCITTFaxFilter.java b/pdfbox/src/main/java/org/apache/pdfbox/filter/CCITTFaxFilter.java index 4ca7e122d44..365b024f924 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/filter/CCITTFaxFilter.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/filter/CCITTFaxFilter.java @@ -21,10 +21,11 @@ import java.io.OutputStream; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; +import org.apache.pdfbox.io.IOUtils; /** * Decodes image data that has been encoded using either Group 3 or Group 4 - * CCITT facsimile (fax) encoding. + * CCITT facsimile (fax) encoding, and encodes image data to Group 4. * * @author Ben Litchfield * @author Marcel Kammer @@ -110,7 +111,7 @@ public DecodeResult decode(InputStream encoded, OutputStream decoded, return new DecodeResult(parameters); } - public void readFromDecoderStream(CCITTFaxDecoderStream decoderStream, byte[] result) + void readFromDecoderStream(CCITTFaxDecoderStream decoderStream, byte[] result) throws IOException { int pos = 0; @@ -138,6 +139,11 @@ private void invertBitmap(byte[] bufferData) protected void encode(InputStream input, OutputStream encoded, COSDictionary parameters) throws IOException { - throw new UnsupportedOperationException("CCITTFaxFilter encoding not implemented, use the CCITTFactory methods instead"); + int cols = parameters.getInt(COSName.COLUMNS); + int rows = parameters.getInt(COSName.ROWS); + CCITTFaxEncoderStream ccittFaxEncoderStream = + new CCITTFaxEncoderStream(encoded, cols, rows, TIFFExtension.FILL_LEFT_TO_RIGHT); + IOUtils.copy(input, ccittFaxEncoderStream); + input.close(); } } diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/CCITTFactory.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/CCITTFactory.java index 0601cdd0b9f..0c88030c70d 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/CCITTFactory.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/CCITTFactory.java @@ -16,16 +16,21 @@ */ package org.apache.pdfbox.pdmodel.graphics.image; +import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.OutputStream; +import javax.imageio.stream.MemoryCacheImageOutputStream; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; +import org.apache.pdfbox.filter.Filter; +import org.apache.pdfbox.filter.FilterFactory; import org.apache.pdfbox.io.RandomAccess; import org.apache.pdfbox.io.RandomAccessFile; import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.pdmodel.graphics.color.PDColorSpace; import org.apache.pdfbox.pdmodel.graphics.color.PDDeviceGray; /** @@ -40,6 +45,69 @@ private CCITTFactory() { } + /** + * Creates a new CCITT group 4 (T6) compressed image XObject from a b/w BufferedImage. This + * compression technique usually results in smaller images than those produced by {@link LosslessFactory#createFromImage(PDDocument, BufferedImage) + * }. + * + * @param document the document to create the image as part of. + * @param image the image. + * @return a new image XObject. + * @throws IOException if there is an error creating the image. + * @throws IllegalArgumentException if the BufferedImage is not a b/w image. + */ + public static PDImageXObject createFromImage(PDDocument document, BufferedImage image) + throws IOException + { + if (image.getType() != BufferedImage.TYPE_BYTE_BINARY && image.getColorModel().getPixelSize() != 1) + { + throw new IllegalArgumentException("Only 1-bit b/w images supported"); + } + + int height = image.getHeight(); + int width = image.getWidth(); + + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + MemoryCacheImageOutputStream mcios = new MemoryCacheImageOutputStream(bos); + + for (int y = 0; y < height; ++y) + { + for (int x = 0; x < width; ++x) + { + // flip bit to avoid having to set /BlackIs1 + mcios.writeBits(~(image.getRGB(x, y) & 1), 1); + } + while (mcios.getBitOffset() != 0) + { + mcios.writeBit(0); + } + } + mcios.flush(); + mcios.close(); + + return prepareImageXObject(document, bos.toByteArray(), width, height, PDDeviceGray.INSTANCE); + } + + private static PDImageXObject prepareImageXObject(PDDocument document, + byte[] byteArray, int width, int height, + PDColorSpace initColorSpace) throws IOException + { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + Filter filter = FilterFactory.INSTANCE.getFilter(COSName.CCITTFAX_DECODE); + COSDictionary dict = new COSDictionary(); + dict.setInt(COSName.COLUMNS, width); + dict.setInt(COSName.ROWS, height); + filter.encode(new ByteArrayInputStream(byteArray), baos, dict, 0); + + ByteArrayInputStream encodedByteStream = new ByteArrayInputStream(baos.toByteArray()); + PDImageXObject image = new PDImageXObject(document, encodedByteStream, COSName.CCITTFAX_DECODE, + width, height, 1, initColorSpace); + dict.setInt(COSName.K, -1); + image.getCOSObject().setItem(COSName.DECODE_PARMS, dict); + return image; + } + /** * Creates a new CCITT Fax compressed image XObject from the first image of a TIFF file. * @@ -82,6 +150,7 @@ public static PDImageXObject createFromRandomAccess(PDDocument document, RandomA * single-strip CCITT T4 or T6 compressed TIFF files are supported. If you're not sure what TIFF * files you have, use * {@link LosslessFactory#createFromImage(org.apache.pdfbox.pdmodel.PDDocument, java.awt.image.BufferedImage)} + * or {@link CCITTFactory#createFromImage(PDDocument, BufferedImage) } * instead. * * @param document the document to create the image as part of. @@ -99,7 +168,8 @@ public static PDImageXObject createFromFile(PDDocument document, File file) * Creates a new CCITT Fax compressed image XObject from a specific image of a TIFF file. Only * single-strip CCITT T4 or T6 compressed TIFF files are supported. If you're not sure what TIFF * files you have, use - * {@link LosslessFactory#createFromImage(org.apache.pdfbox.pdmodel.PDDocument, java.awt.image.BufferedImage)} + * {@link LosslessFactory#createFromImage(PDDocument, BufferedImage) } + * or {@link CCITTFactory#createFromImage(PDDocument, BufferedImage) } * instead. * * @param document the document to create the image as part of. @@ -298,6 +368,15 @@ private static void extractFromTiff(RandomAccess reader, OutputStream os, } break; } + case 274: + { + // http://www.awaresystems.be/imaging/tiff/tifftags/orientation.html + if (val != 1) + { + throw new IOException("Orientation " + val + " is not supported"); + } + break; + } case 279: { if (count == 1) @@ -310,7 +389,8 @@ private static void extractFromTiff(RandomAccess reader, OutputStream os, { if ((val & 1) != 0) { - k = 50; // T4 2D - arbitary positive K value + // T4 2D - arbitary positive K value + k = 50; } // http://www.awaresystems.be/imaging/tiff/tifftags/t4options.html if ((val & 4) != 0) diff --git a/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/graphics/image/CCITTFactoryTest.java b/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/graphics/image/CCITTFactoryTest.java index 9052f9a1542..04c70608e7e 100644 --- a/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/graphics/image/CCITTFactoryTest.java +++ b/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/graphics/image/CCITTFactoryTest.java @@ -81,7 +81,7 @@ public void testCreateFromRandomAccessSingle() throws IOException document.save(testResultsDir + "/singletiff.pdf"); document.close(); - document = PDDocument.load(new File(testResultsDir, "singletiff.pdf"), (String)null); + document = PDDocument.load(new File(testResultsDir, "singletiff.pdf")); assertEquals(2, document.getNumberOfPages()); document.close(); @@ -136,4 +136,63 @@ public void testCreateFromRandomAccessMulti() throws IOException document.close(); imageReader.dispose(); } + + public void testCreateFromBufferedImage() throws IOException + { + String tiffG4Path = "src/test/resources/org/apache/pdfbox/pdmodel/graphics/image/ccittg4.tif"; + + PDDocument document = new PDDocument(); + BufferedImage bim = ImageIO.read(new File(tiffG4Path)); + PDImageXObject ximage3 = CCITTFactory.createFromImage(document, bim); + validate(ximage3, 1, 344, 287, "tiff", PDDeviceGray.INSTANCE.getName()); + checkIdent(bim, ximage3.getOpaqueImage()); + + PDPage page = new PDPage(PDRectangle.A4); + document.addPage(page); + PDPageContentStream contentStream = new PDPageContentStream(document, page, AppendMode.APPEND, false); + contentStream.drawImage(ximage3, 0, 0, ximage3.getWidth(), ximage3.getHeight()); + contentStream.close(); + + document.save(testResultsDir + "/singletifffrombi.pdf"); + document.close(); + + document = PDDocument.load(new File(testResultsDir, "singletifffrombi.pdf")); + assertEquals(1, document.getNumberOfPages()); + + document.close(); + } + + public void testCreateFromBufferedChessImage() throws IOException + { + PDDocument document = new PDDocument(); + BufferedImage bim = new BufferedImage(343, 287, BufferedImage.TYPE_BYTE_BINARY); + assertTrue((bim.getWidth() / 8) * 8 != bim.getWidth()); // not mult of 8 + int col = 0; + for (int x = 0; x < bim.getWidth(); ++x) + { + for (int y = 0; y < bim.getHeight(); ++y) + { + bim.setRGB(x, y, col & 0xFFFFFF); + col = ~col; + } + } + + PDImageXObject ximage3 = CCITTFactory.createFromImage(document, bim); + validate(ximage3, 1, 343, 287, "tiff", PDDeviceGray.INSTANCE.getName()); + checkIdent(bim, ximage3.getOpaqueImage()); + + PDPage page = new PDPage(PDRectangle.A4); + document.addPage(page); + PDPageContentStream contentStream = new PDPageContentStream(document, page, AppendMode.APPEND, false); + contentStream.drawImage(ximage3, 0, 0, ximage3.getWidth(), ximage3.getHeight()); + contentStream.close(); + + document.save(testResultsDir + "/singletifffromchessbi.pdf"); + document.close(); + + document = PDDocument.load(new File(testResultsDir, "singletifffromchessbi.pdf")); + assertEquals(1, document.getNumberOfPages()); + + document.close(); + } } From 644bcd951a499c149bed8611f27a053d40b4b2ec Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Thu, 23 Jun 2016 16:41:51 +0000 Subject: [PATCH 0149/2182] PDFBOX-3069: add rat exception git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1749940 13f79535-47bb-0310-9956-ffa450edef68 --- pdfbox/pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/pdfbox/pom.xml b/pdfbox/pom.xml index ab15a53c810..4b34a23a716 100644 --- a/pdfbox/pom.xml +++ b/pdfbox/pom.xml @@ -155,6 +155,7 @@ src/test/resources/org/apache/pdfbox/filter/*.bin src/test/resources/org/apache/pdfbox/text/*.txt src/main/java/org/apache/pdfbox/filter/CCITTFaxDecoderStream.java + src/main/java/org/apache/pdfbox/filter/CCITTFaxEncoderStream.java src/main/java/org/apache/pdfbox/filter/TIFFExtension.java From cf5d4dbc821249a53f8c26216a37cd7e9e962227 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Thu, 23 Jun 2016 18:32:37 +0000 Subject: [PATCH 0150/2182] PDFBOX-2852: fix javadoc git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1749961 13f79535-47bb-0310-9956-ffa450edef68 --- fontbox/src/main/java/org/apache/fontbox/ttf/TTFSubsetter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fontbox/src/main/java/org/apache/fontbox/ttf/TTFSubsetter.java b/fontbox/src/main/java/org/apache/fontbox/ttf/TTFSubsetter.java index 68cc88518ca..33046fcaae9 100755 --- a/fontbox/src/main/java/org/apache/fontbox/ttf/TTFSubsetter.java +++ b/fontbox/src/main/java/org/apache/fontbox/ttf/TTFSubsetter.java @@ -125,7 +125,7 @@ public void addAll(Set unicodeSet) } /** - * Returns the map of new -> old GIDs. + * Returns the map of new -> old GIDs. */ public Map getGIDMap() throws IOException { From b951a6c2e935b5cadcde1a1668e29cc3646e276b Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Thu, 23 Jun 2016 18:44:45 +0000 Subject: [PATCH 0151/2182] PDFBOX-2852: fix javadoc git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1749964 13f79535-47bb-0310-9956-ffa450edef68 --- fontbox/src/main/java/org/apache/fontbox/cmap/CMap.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fontbox/src/main/java/org/apache/fontbox/cmap/CMap.java b/fontbox/src/main/java/org/apache/fontbox/cmap/CMap.java index f08a4b97ee6..da0eb24afab 100644 --- a/fontbox/src/main/java/org/apache/fontbox/cmap/CMap.java +++ b/fontbox/src/main/java/org/apache/fontbox/cmap/CMap.java @@ -95,7 +95,7 @@ public String toUnicode(int code) /** * Reads a character code from a string in the content stream. - *

>See "CMap Mapping" and "Handling Undefined Characters" in PDF32000 for more details. + *

See "CMap Mapping" and "Handling Undefined Characters" in PDF32000 for more details. * * @param in string stream * @return character code From 1d2cd20b99f4f182c51f0e7cdd7468acaced7b30 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Thu, 23 Jun 2016 18:46:01 +0000 Subject: [PATCH 0152/2182] PDFBOX-2852: fix javadoc git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1749966 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/fontbox/ttf/OS2WindowsMetricsTable.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fontbox/src/main/java/org/apache/fontbox/ttf/OS2WindowsMetricsTable.java b/fontbox/src/main/java/org/apache/fontbox/ttf/OS2WindowsMetricsTable.java index 70899c5962b..7865c6dda81 100644 --- a/fontbox/src/main/java/org/apache/fontbox/ttf/OS2WindowsMetricsTable.java +++ b/fontbox/src/main/java/org/apache/fontbox/ttf/OS2WindowsMetricsTable.java @@ -155,7 +155,7 @@ public class OS2WindowsMetricsTable extends TTFTable public static final short FSTYPE_RESTRICTED = 0x0001; /** - * Preview & Print embedding: the font may be embedded, and temporarily loaded on the + * Preview and Print embedding: the font may be embedded, and temporarily loaded on the * remote system. No edits can be applied to the document. */ public static final short FSTYPE_PREVIEW_AND_PRINT = 0x0004; From ceed464b9949ff9692e2374f32e1adb817637bf2 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Thu, 23 Jun 2016 19:18:06 +0000 Subject: [PATCH 0153/2182] PDFBOX-2852: fix javadoc git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1749979 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/pdfbox/multipdf/PDFCloneUtility.java | 2 +- .../apache/pdfbox/pdmodel/encryption/PDEncryption.java | 6 +++--- .../main/java/org/apache/pdfbox/pdmodel/fdf/FDFField.java | 6 +++--- .../pdfbox/pdmodel/interactive/form/PDAcroForm.java | 6 +++--- .../apache/pdfbox/pdmodel/interactive/form/PDChoice.java | 6 +++--- .../pdfbox/pdmodel/interactive/form/PDRadioButton.java | 4 ++-- .../pdfbox/pdmodel/interactive/form/PDVariableText.java | 8 ++++---- .../main/java/org/apache/pdfbox/text/PDFTextStripper.java | 6 +++--- tools/src/main/java/org/apache/pdfbox/tools/Encrypt.java | 2 +- xmpbox/src/main/java/org/apache/xmpbox/XMPMetadata.java | 8 ++++---- 10 files changed, 27 insertions(+), 27 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/multipdf/PDFCloneUtility.java b/pdfbox/src/main/java/org/apache/pdfbox/multipdf/PDFCloneUtility.java index f529819a357..0b5cb7c67cf 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/multipdf/PDFCloneUtility.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/multipdf/PDFCloneUtility.java @@ -149,7 +149,7 @@ else if( base instanceof COSDictionary ) /** * Merges two objects of the same type by deep-cloning its members. - *
+ *
* Base and target must be instances of the same class. * @param base the base object to be cloned * @param target the merge target diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/PDEncryption.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/PDEncryption.java index 67422cd735e..18edd868d02 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/PDEncryption.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/PDEncryption.java @@ -180,8 +180,8 @@ public void setSubFilter(String subfilter) } /** - * This will set the V entry of the encryption dictionary.

- * See PDF Reference 1.4 Table 3.13.

+ * This will set the V entry of the encryption dictionary.

+ * See PDF Reference 1.4 Table 3.13.

* Note: This value is used to decrypt the pdf document. If you change this when * the document is encrypted then decryption will fail!. * @@ -193,7 +193,7 @@ public void setVersion(int version) } /** - * This will return the V entry of the encryption dictionary.

+ * This will return the V entry of the encryption dictionary.

* See PDF Reference 1.4 Table 3.13. * * @return The encryption version to use. diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/fdf/FDFField.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/fdf/FDFField.java index 2dd1d163832..fba435c756f 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/fdf/FDFField.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/fdf/FDFField.java @@ -187,9 +187,9 @@ public void setKids(List kids) /** * This will get the "T" entry in the field dictionary. A partial field name. Where the fully qualified field name - * is a concatenation of the parent's fully qualified field name and "." as a separator. For example
- * Address.State
- * Address.City
+ * is a concatenation of the parent's fully qualified field name and "." as a separator. For example
+ * Address.State
+ * Address.City
* * @return The partial field name. */ diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDAcroForm.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDAcroForm.java index 0d7e051d298..6dc0045b4af 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDAcroForm.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDAcroForm.java @@ -566,9 +566,9 @@ public void setXFA(PDXFAResource xfa) /** * This will get the 'quadding' or justification of the text to be displayed. - * 0 - Left(default)
- * 1 - Centered
- * 2 - Right
+ * 0 - Left(default)
+ * 1 - Centered
+ * 2 - Right
* Please see the QUADDING_CONSTANTS. * * @return The justification of the text strings. diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDChoice.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDChoice.java index f8db5ac365e..47de629ef6d 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDChoice.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDChoice.java @@ -73,7 +73,7 @@ public PDChoice(PDAcroForm acroForm) * *

* For a choice field the options array can either be an array - * of text strings or an array of a two-element arrays.
+ * of text strings or an array of a two-element arrays.
* The method always only returns either the text strings or, * in case of two-element arrays, an array of the first element of * the two-element arrays @@ -180,7 +180,7 @@ public void setOptions(List exportValues, List displayValues) * *

* For options with an array of text strings the display value and export value - * are the same.
+ * are the same.
* For options with an array of two-element arrays the display value is the * second entry in the two-element array. *

@@ -198,7 +198,7 @@ public List getOptionsDisplayValues() * *

* For options with an array of text strings the display value and export value - * are the same.
+ * are the same.
* For options with an array of two-element arrays the export value is the * first entry in the two-element array. *

diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDRadioButton.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDRadioButton.java index 402c59e4140..382fd8a2b0c 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDRadioButton.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDRadioButton.java @@ -60,7 +60,7 @@ public PDRadioButton(PDAcroForm acroForm) } /** - * From the PDF Spec
+ * From the PDF Spec
* If set, a group of radio buttons within a radio button field that use the same value for the on state will turn * on and off in unison; that is if one is checked, they are all checked. If clear, the buttons are mutually * exclusive (the same behavior as HTML radio buttons). @@ -86,7 +86,7 @@ public boolean isRadiosInUnison() *

* A RadioButton might have an export value to allow field values * which can not be encoded as PDFDocEncoding or for the same export value - * being assigned to multiple RadioButtons in a group.
+ * being assigned to multiple RadioButtons in a group.
* To define an export value the RadioButton must define options {@link #setExportValues(List)} * which correspond to the individual items within the RadioButton.

*

diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDVariableText.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDVariableText.java index 248f4b93a1a..5131081c9d3 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDVariableText.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDVariableText.java @@ -146,9 +146,9 @@ public void setDefaultStyleString(String defaultStyleString) * * This is an inheritable attribute. * - * 0 - Left(default)
- * 1 - Centered
- * 2 - Right
+ * 0 - Left(default)
+ * 1 - Centered
+ * 2 - Right
* Please see the QUADDING_CONSTANTS. * * @return The justification of the text strings. @@ -193,7 +193,7 @@ public String getRichTextValue() throws IOException *

* Setting the rich text value will not generate the appearance * for the field. - *
+ *
* You can set {@link PDAcroForm#setNeedAppearances(Boolean)} to * signal a conforming reader to generate the appearance stream. *

diff --git a/pdfbox/src/main/java/org/apache/pdfbox/text/PDFTextStripper.java b/pdfbox/src/main/java/org/apache/pdfbox/text/PDFTextStripper.java index 8727edc80fd..a2cc219b756 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/text/PDFTextStripper.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/text/PDFTextStripper.java @@ -1199,9 +1199,9 @@ public boolean getSortByPosition() /** * The order of the text tokens in a PDF file may not be in the same as they appear visually on the screen. For * example, a PDF writer may write out all text by font, so all bold or larger text, then make a second pass and - * write out the normal text.
- * The default is to not sort by position.
- *
+ * write out the normal text.
+ * The default is to not sort by position.
+ *
* A PDF writer could choose to write each character in a different order. By default PDFBox does not sort * the text tokens before processing them due to performance reasons. * diff --git a/tools/src/main/java/org/apache/pdfbox/tools/Encrypt.java b/tools/src/main/java/org/apache/pdfbox/tools/Encrypt.java index 14f119e10cb..b3d700ec9ee 100644 --- a/tools/src/main/java/org/apache/pdfbox/tools/Encrypt.java +++ b/tools/src/main/java/org/apache/pdfbox/tools/Encrypt.java @@ -32,7 +32,7 @@ /** * This will read a document from the filesystem, encrypt it and and then write - * the results to the filesystem.

+ * the results to the filesystem. * * @author Ben Litchfield */ diff --git a/xmpbox/src/main/java/org/apache/xmpbox/XMPMetadata.java b/xmpbox/src/main/java/org/apache/xmpbox/XMPMetadata.java index 238b370044f..9f057307e65 100644 --- a/xmpbox/src/main/java/org/apache/xmpbox/XMPMetadata.java +++ b/xmpbox/src/main/java/org/apache/xmpbox/XMPMetadata.java @@ -207,10 +207,10 @@ public String getEndXPacket() /** * Get the XMPSchema for the specified namespace. * - * Return the schema corresponding to this nsURI
+ * Return the schema corresponding to this nsURI
* BE CAREFUL: typically, Metadata should contain one schema for each type. * This method returns the first schema encountered - * corresponding to this NSURI.
+ * corresponding to this NSURI.
* Return null if unknown * * @param nsURI The namespace URI corresponding to the schema wanted @@ -234,10 +234,10 @@ public XMPSchema getSchema(String nsURI) /** * Get the XMPSchema for the specified Class. * - * Return the schema corresponding to this Class
+ * Return the schema corresponding to this Class
* BE CAREFUL: typically, Metadata should contain one schema for each type. * This method returns the first schema encountered - * corresponding to this Class.
+ * corresponding to this Class.
* Return null if unknown * * @param clz The Class corresponding to the schema wanted From 97008df75c3a44d5842fbd542fd152dd7dd80d29 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Thu, 23 Jun 2016 19:25:26 +0000 Subject: [PATCH 0154/2182] PDFBOX-2852: fix javadoc git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1749982 13f79535-47bb-0310-9956-ffa450edef68 --- xmpbox/src/main/java/org/apache/xmpbox/type/AbstractField.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xmpbox/src/main/java/org/apache/xmpbox/type/AbstractField.java b/xmpbox/src/main/java/org/apache/xmpbox/type/AbstractField.java index 7185b9fbd28..c9b60708c85 100644 --- a/xmpbox/src/main/java/org/apache/xmpbox/type/AbstractField.java +++ b/xmpbox/src/main/java/org/apache/xmpbox/type/AbstractField.java @@ -29,7 +29,7 @@ import org.apache.xmpbox.XMPMetadata; /** - * Astract Object representation of a XMP 'field' (-> Properties and specific Schemas) + * Astract Object representation of a XMP 'field' (-> Properties and specific Schemas) * * @author a183132 * From 54c29a35d0285e99448ba154c6a02c059a391542 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Thu, 23 Jun 2016 19:42:08 +0000 Subject: [PATCH 0155/2182] PDFBOX-2852: fix javadoc git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1749990 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/pdfbox/pdmodel/font/encoding/Encoding.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/Encoding.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/Encoding.java index ea7dce2bcdb..bd245d05247 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/Encoding.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/Encoding.java @@ -72,10 +72,10 @@ public Map getCodeToNameMap() } /** - * Returns an unmodifiable view of the name -> code mapping. More than one name may map to + * Returns an unmodifiable view of the name -> code mapping. More than one name may map to * the same code. * - * @return the name -> code map + * @return the name -> code map */ public Map getNameToCodeMap() { From f3a71d60f1405ee9bf5124177c4c0c0c6d4affe3 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Thu, 23 Jun 2016 19:52:26 +0000 Subject: [PATCH 0156/2182] PDFBOX-2852: fix javadoc git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1749993 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/pdfbox/pdmodel/font/PDTrueTypeFont.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDTrueTypeFont.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDTrueTypeFont.java index 2f450cc06b2..cf86ff62ed1 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDTrueTypeFont.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDTrueTypeFont.java @@ -411,7 +411,7 @@ protected byte[] encode(int unicode) throws IOException } /** - * Inverts the font's code -> GID mapping. Any duplicate (GID -> code) mappings will be lost. + * Inverts the font's code -> GID mapping. Any duplicate (GID -> code) mappings will be lost. */ protected Map getGIDToCode() throws IOException { From 8cf3b9cae8a72110ba0fc368413fa8337f80415c Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Thu, 23 Jun 2016 19:55:57 +0000 Subject: [PATCH 0157/2182] PDFBOX-2852: fix javadoc git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1749996 13f79535-47bb-0310-9956-ffa450edef68 --- .../digitalsignature/visible/PDFTemplateStructure.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDFTemplateStructure.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDFTemplateStructure.java index 1a54b233148..cb172387624 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDFTemplateStructure.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDFTemplateStructure.java @@ -181,7 +181,7 @@ public COSDictionary getAcroFormDictionary() /** * Acroform have its Dictionary, so we here set * the Dictionary which is in this location: - * AcroForm/DR + * AcroForm/DR * @param acroFormDictionary */ public void setAcroFormDictionary(COSDictionary acroFormDictionary) From acf80413fa1aae20247cac4cbe43201e13ecbe64 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Thu, 23 Jun 2016 20:04:09 +0000 Subject: [PATCH 0158/2182] PDFBOX-2852: fix javadoc git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1749999 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/pdfbox/pdmodel/font/PDFontLike.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDFontLike.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDFontLike.java index ad92a668b43..504e0ecf4e0 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDFontLike.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDFontLike.java @@ -61,17 +61,17 @@ public interface PDFontLike /** * Returns the height of the given character, in glyph space. This can be expensive to - * calculate. Results are only approximate.

+ * calculate. Results are only approximate.

* * Warning: This method is deprecated in PDFBox 2.0 because there is no meaningful value - * which it can return. The {@link #getWidth} method returns the advance width of a glyph, + * which it can return. The {@link #getWidth(int)} method returns the advance width of a glyph, * but there is no corresponding advance height. The logical height of a character is the same * for every character in a font, so if you want that, retrieve the font bbox's height. * Otherwise if you want the visual bounds of the glyph then call getPath(..) on the appropriate * PDFont subclass to retrieve the glyph outline as a GeneralPath. * * @param code character code - * @deprecated Use {@link #getBoundingBox().#getHeight(int)} instead. + * @deprecated Use {@link #getBoundingBox()#getHeight(int) } instead. */ @Deprecated float getHeight(int code) throws IOException; From c4b19ce3071b6bb0cb3e8680b650c9517d4d003d Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Thu, 23 Jun 2016 20:10:54 +0000 Subject: [PATCH 0159/2182] PDFBOX-2852: fix javadoc git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1750005 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/pdfbox/pdmodel/font/FontMapper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontMapper.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontMapper.java index 54df09b1c5e..8cf5139115a 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontMapper.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontMapper.java @@ -21,7 +21,7 @@ /** * Font mapper, locates non-embedded fonts. If you implement this then you're responsible for - * caching the fonts. SoftReference is recommended. + * caching the fonts. SoftReference<FontBoxFont> is recommended. * * @author John Hewson */ From 16751722f6bffe2c1e13371c4a8d3e6fda426126 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Thu, 23 Jun 2016 20:13:01 +0000 Subject: [PATCH 0160/2182] PDFBOX-2852: fix javadoc git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1750008 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/pdfbox/pdmodel/fdf/FDFDictionary.java | 1 - 1 file changed, 1 deletion(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/fdf/FDFDictionary.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/fdf/FDFDictionary.java index fa6c89aec27..ef5adb9f08b 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/fdf/FDFDictionary.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/fdf/FDFDictionary.java @@ -70,7 +70,6 @@ public FDFDictionary(COSDictionary fdfDictionary) * This will create an FDF dictionary from an XFDF XML document. * * @param fdfXML The XML document that contains the XFDF data. - * @throws IOException If there is an error reading from the dom. */ public FDFDictionary(Element fdfXML) { From 080c8b11ae69dcecd9a3d86cb1865a6717d943f9 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Fri, 24 Jun 2016 16:40:36 +0000 Subject: [PATCH 0161/2182] PDFBOX-2852: fix javadoc git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1750131 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/pdfbox/pdmodel/font/encoding/Encoding.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/Encoding.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/Encoding.java index bd245d05247..95dfa19fde6 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/Encoding.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/Encoding.java @@ -62,9 +62,9 @@ else if (COSName.MAC_ROMAN_ENCODING.equals(name)) private Set names; /** - * Returns an unmodifiable view of the code -> name mapping. + * Returns an unmodifiable view of the code -> name mapping. * - * @return the code -> name map + * @return the code -> name map */ public Map getCodeToNameMap() { From bc12acdd458a2d98fc4d286fb816f41f2790c99b Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Fri, 24 Jun 2016 16:42:54 +0000 Subject: [PATCH 0162/2182] PDFBOX-2852: fix javadoc git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1750133 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/pdfbox/pdmodel/font/PDFontLike.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDFontLike.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDFontLike.java index 504e0ecf4e0..0140b554b0f 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDFontLike.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDFontLike.java @@ -71,13 +71,15 @@ public interface PDFontLike * PDFont subclass to retrieve the glyph outline as a GeneralPath. * * @param code character code - * @deprecated Use {@link #getBoundingBox()#getHeight(int) } instead. + * @deprecated Use + * {@link #getBoundingBox() getBoundingBox()}.{@link BoundingBox#getHeight() getHeight()} + * instead. */ @Deprecated float getHeight(int code) throws IOException; /** - * Returns the advance width of the given character, in glyph space.

+ * Returns the advance width of the given character, in glyph space.

* * If you want the visual bounds of the glyph then call getPath(..) on the appropriate * PDFont subclass to retrieve the glyph outline as a GeneralPath instead. From 0dfb4a178e06e5950c75260ca25e369dc362539a Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Fri, 24 Jun 2016 17:30:51 +0000 Subject: [PATCH 0163/2182] PDFBOX-2852: fix javadoc git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1750140 13f79535-47bb-0310-9956-ffa450edef68 --- .../pdfbox/cos/UnmodifiableCOSDictionary.java | 58 +++++++++---------- .../pdmodel/graphics/color/PDDeviceRGB.java | 2 +- .../interactive/form/PDNonTerminalField.java | 6 +- 3 files changed, 33 insertions(+), 33 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/cos/UnmodifiableCOSDictionary.java b/pdfbox/src/main/java/org/apache/pdfbox/cos/UnmodifiableCOSDictionary.java index c483eb0c864..9a562dac8d3 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/cos/UnmodifiableCOSDictionary.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/cos/UnmodifiableCOSDictionary.java @@ -28,7 +28,7 @@ final class UnmodifiableCOSDictionary extends COSDictionary { /** - * @inheritDoc + * {@inheritDoc} */ UnmodifiableCOSDictionary(COSDictionary dict) { @@ -37,7 +37,7 @@ final class UnmodifiableCOSDictionary extends COSDictionary } /** - * @inheritDoc + * {@inheritDoc} */ @Override public void clear() @@ -46,7 +46,7 @@ public void clear() } /** - * @inheritDoc + * {@inheritDoc} */ @Override public void setItem(COSName key, COSBase value) @@ -55,7 +55,7 @@ public void setItem(COSName key, COSBase value) } /** - * @inheritDoc + * {@inheritDoc} */ @Override public void setItem(COSName key, COSObjectable value) @@ -64,7 +64,7 @@ public void setItem(COSName key, COSObjectable value) } /** - * @inheritDoc + * {@inheritDoc} */ @Override public void setItem(String key, COSObjectable value) @@ -73,7 +73,7 @@ public void setItem(String key, COSObjectable value) } /** - * @inheritDoc + * {@inheritDoc} */ @Override public void setBoolean(String key, boolean value) @@ -82,7 +82,7 @@ public void setBoolean(String key, boolean value) } /** - * @inheritDoc + * {@inheritDoc} */ @Override public void setBoolean(COSName key, boolean value) @@ -91,7 +91,7 @@ public void setBoolean(COSName key, boolean value) } /** - * @inheritDoc + * {@inheritDoc} */ @Override public void setItem(String key, COSBase value) @@ -100,7 +100,7 @@ public void setItem(String key, COSBase value) } /** - * @inheritDoc + * {@inheritDoc} */ @Override public void setName(String key, String value) @@ -109,7 +109,7 @@ public void setName(String key, String value) } /** - * @inheritDoc + * {@inheritDoc} */ @Override public void setName(COSName key, String value) @@ -118,7 +118,7 @@ public void setName(COSName key, String value) } /** - * @inheritDoc + * {@inheritDoc} */ @Override public void setDate(String key, Calendar date) @@ -127,7 +127,7 @@ public void setDate(String key, Calendar date) } /** - * @inheritDoc + * {@inheritDoc} */ @Override public void setDate(COSName key, Calendar date) @@ -136,7 +136,7 @@ public void setDate(COSName key, Calendar date) } /** - * @inheritDoc + * {@inheritDoc} */ @Override public void setEmbeddedDate(String embedded, String key, Calendar date) @@ -145,7 +145,7 @@ public void setEmbeddedDate(String embedded, String key, Calendar date) } /** - * @inheritDoc + * {@inheritDoc} */ @Override public void setEmbeddedDate(String embedded, COSName key, Calendar date) @@ -154,7 +154,7 @@ public void setEmbeddedDate(String embedded, COSName key, Calendar date) } /** - * @inheritDoc + * {@inheritDoc} */ @Override public void setString(String key, String value) @@ -163,7 +163,7 @@ public void setString(String key, String value) } /** - * @inheritDoc + * {@inheritDoc} */ @Override public void setString(COSName key, String value) @@ -172,7 +172,7 @@ public void setString(COSName key, String value) } /** - * @inheritDoc + * {@inheritDoc} */ @Override public void setEmbeddedString(String embedded, String key, String value) @@ -181,7 +181,7 @@ public void setEmbeddedString(String embedded, String key, String value) } /** - * @inheritDoc + * {@inheritDoc} */ @Override public void setEmbeddedString(String embedded, COSName key, String value) @@ -190,7 +190,7 @@ public void setEmbeddedString(String embedded, COSName key, String value) } /** - * @inheritDoc + * {@inheritDoc} */ @Override public void setInt(String key, int value) @@ -199,7 +199,7 @@ public void setInt(String key, int value) } /** - * @inheritDoc + * {@inheritDoc} */ @Override public void setInt(COSName key, int value) @@ -208,7 +208,7 @@ public void setInt(COSName key, int value) } /** - * @inheritDoc + * {@inheritDoc} */ @Override public void setLong(String key, long value) @@ -217,7 +217,7 @@ public void setLong(String key, long value) } /** - * @inheritDoc + * {@inheritDoc} */ @Override public void setLong(COSName key, long value) @@ -226,7 +226,7 @@ public void setLong(COSName key, long value) } /** - * @inheritDoc + * {@inheritDoc} */ @Override public void setEmbeddedInt(String embeddedDictionary, String key, int value) @@ -235,7 +235,7 @@ public void setEmbeddedInt(String embeddedDictionary, String key, int value) } /** - * @inheritDoc + * {@inheritDoc} */ @Override public void setEmbeddedInt(String embeddedDictionary, COSName key, int value) @@ -244,7 +244,7 @@ public void setEmbeddedInt(String embeddedDictionary, COSName key, int value) } /** - * @inheritDoc + * {@inheritDoc} */ @Override public void setFloat(String key, float value) @@ -253,7 +253,7 @@ public void setFloat(String key, float value) } /** - * @inheritDoc + * {@inheritDoc} */ @Override public void setFloat(COSName key, float value) @@ -262,7 +262,7 @@ public void setFloat(COSName key, float value) } /** - * @inheritDoc + * {@inheritDoc} */ @Override public void removeItem(COSName key) @@ -271,7 +271,7 @@ public void removeItem(COSName key) } /** - * @inheritDoc + * {@inheritDoc} */ @Override public void addAll(COSDictionary dic) @@ -280,7 +280,7 @@ public void addAll(COSDictionary dic) } /** - * @inheritDoc + * {@inheritDoc} */ @Override public void mergeInto(COSDictionary dic) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDDeviceRGB.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDDeviceRGB.java index 54c8fe057b2..46403de3734 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDDeviceRGB.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDDeviceRGB.java @@ -77,7 +77,7 @@ public String getName() } /** - * @inheritDoc + * {@inheritDoc} */ @Override public int getNumberOfComponents() diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDNonTerminalField.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDNonTerminalField.java index 342b8a92b95..9a20aa55b1b 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDNonTerminalField.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDNonTerminalField.java @@ -152,7 +152,7 @@ public void setChildren(List children) } /** - * @inheritDoc + * {@inheritDoc} * *

Note: while non-terminal fields do inherit field values, this method returns * the local value, without inheritance. @@ -164,7 +164,7 @@ public String getFieldType() } /** - * @inheritDoc + * {@inheritDoc} * *

Note: while non-terminal fields do inherit field values, this method returns * the local value, without inheritance. @@ -175,7 +175,7 @@ public COSBase getValue() } /** - * @inheritDoc + * {@inheritDoc} * *

Note: while non-terminal fields do inherit field values, this method returns * the local value, without inheritance. From 3ee1eb70aec4c93078ba79e0d6a07d7d3cc42c0c Mon Sep 17 00:00:00 2001 From: Maruan Sahyoun Date: Fri, 24 Jun 2016 18:14:59 +0000 Subject: [PATCH 0164/2182] improve setting the fields value if an /Opts entry is defined git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1750155 13f79535-47bb-0310-9956-ffa450edef68 --- .../pdmodel/interactive/form/PDButton.java | 113 +++++++++++++----- 1 file changed, 84 insertions(+), 29 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDButton.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDButton.java index 54ac013c127..cc6c4e3837d 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDButton.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDButton.java @@ -150,21 +150,20 @@ public String getValue() @Override public void setValue(String value) throws IOException { - checkValue(value); - getCOSObject().setName(COSName.V, value); - // update the appearance state (AS) - for (PDAnnotationWidget widget : getWidgets()) + checkValue(value); + + // if there are export values/an Opt entry there is a different + // approach to setting the value + boolean hasExportValues = getExportValues().size() > 0; + + if (hasExportValues) { + updateByOption(value); + } + else { - PDAppearanceEntry appearanceEntry = widget.getAppearance().getNormalAppearance(); - if (((COSDictionary) appearanceEntry.getCOSObject()).containsKey(value)) - { - widget.getCOSObject().setName(COSName.AS, value); - } - else - { - widget.getCOSObject().setItem(COSName.AS, COSName.Off); - } + updateByValue(value); } + applyChange(); } @@ -227,6 +226,7 @@ public String getValueAsString() public List getExportValues() { COSBase value = getInheritableAttribute(COSName.OPT); + if (value instanceof COSString) { List array = new ArrayList(); @@ -263,28 +263,28 @@ public void setExportValues(List values) @Override void constructAppearances() throws IOException { - for (PDAnnotationWidget widget : getWidgets()) + List exportValues = getExportValues(); + if (exportValues.size() > 0) { - PDAppearanceDictionary appearance = widget.getAppearance(); - if (appearance == null || appearance.getNormalAppearance() == null) + // the value is the index value of the option. So we need to get that + // and use it to set the value + try { - // TODO: implement appearance generation for radio buttons - throw new UnsupportedOperationException("Appearance generation is not implemented yet, see PDFBOX-2849"); - } - else - { - PDAppearanceEntry appearanceEntry = widget.getAppearance().getNormalAppearance(); - String value = getValue(); - if (((COSDictionary) appearanceEntry.getCOSObject()).containsKey(value)) - { - widget.getCOSObject().setName(COSName.AS, value); - } - else + int optionsIndex = Integer.parseInt(getValue()); + if (optionsIndex < exportValues.size()) { - widget.getCOSObject().setItem(COSName.AS, COSName.Off); + updateByOption(exportValues.get(optionsIndex)); } + } catch (NumberFormatException e) + { + // silently ignore that + // and don't update the appearance } } + else + { + updateByValue(getValue()); + } } /** @@ -302,6 +302,12 @@ public Set getOnValues() // we need a set as the field can appear multiple times Set onValues = new HashSet(); + if (getExportValues().size() > 0) + { + onValues.addAll(getExportValues()); + return onValues; + } + List widgets = this.getWidgets(); for (PDAnnotationWidget widget : widgets) { @@ -341,4 +347,53 @@ void checkValue(String value) throws IllegalArgumentException + ", valid values are: " + onValues + " and " + COSName.Off.getName()); } } + + private void updateByValue(String value) throws IOException + { + getCOSObject().setName(COSName.V, value); + // update the appearance state (AS) + for (PDAnnotationWidget widget : getWidgets()) + { + PDAppearanceEntry appearanceEntry = widget.getAppearance().getNormalAppearance(); + if (((COSDictionary) appearanceEntry.getCOSObject()).containsKey(value)) + { + widget.getCOSObject().setName(COSName.AS, value); + } + else + { + widget.getCOSObject().setItem(COSName.AS, COSName.Off); + } + } + } + + private void updateByOption(String value) throws IOException + { + List widgets = getWidgets(); + List options = getExportValues(); + + if (widgets.size() != options.size()) + { + throw new IllegalArgumentException("The number of options doesn't match the number of widgets"); + } + + // the value is the index of the matching option + int optionsIndex = options.indexOf(value); + getCOSObject().setName(COSName.V, String.valueOf(optionsIndex)); + + + // update the appearance state (AS) + for (int i = 0; i < widgets.size(); i++) + { + PDAnnotationWidget widget = widgets.get(i); + if (value.compareTo(options.get(i)) == 0) + { + widget.getCOSObject().setName(COSName.AS, String.valueOf(i)); + } + else + { + widget.getCOSObject().setItem(COSName.AS, COSName.Off); + } + } + } + } From 386be5a8749c0d36d7606739d4a5137ce8ecd2e3 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Fri, 24 Jun 2016 19:39:01 +0000 Subject: [PATCH 0165/2182] PDFBOX-2852: fix javadoc git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1750160 13f79535-47bb-0310-9956-ffa450edef68 --- .../pdfbox/examples/interactive/form/PrintFields.java | 2 +- .../apache/pdfbox/examples/interactive/form/SetField.java | 2 +- .../org/apache/pdfbox/examples/pdmodel/AddImageToPDF.java | 2 +- .../pdfbox/examples/pdmodel/AddMessageToEachPage.java | 2 +- .../org/apache/pdfbox/examples/pdmodel/EmbeddedFiles.java | 2 +- .../org/apache/pdfbox/examples/pdmodel/PrintURLs.java | 2 +- .../org/apache/pdfbox/examples/pdmodel/ReplaceURLs.java | 2 +- .../org/apache/pdfbox/pdmodel/common/PDRectangle.java | 4 ++-- .../pdmodel/encryption/PDCryptFilterDictionary.java | 2 +- .../apache/pdfbox/pdmodel/encryption/PDEncryption.java | 8 ++++---- .../main/java/org/apache/pdfbox/pdmodel/fdf/FDFField.java | 4 ++-- .../java/org/apache/pdfbox/pdmodel/fdf/FDFIconFit.java | 2 +- .../main/java/org/apache/pdfbox/text/PDFTextStripper.java | 2 +- .../src/main/java/org/apache/pdfbox/tools/ExportFDF.java | 2 +- .../src/main/java/org/apache/pdfbox/tools/ExportXFDF.java | 2 +- .../src/main/java/org/apache/pdfbox/tools/ImportFDF.java | 2 +- .../src/main/java/org/apache/pdfbox/tools/ImportXFDF.java | 2 +- .../src/main/java/org/apache/pdfbox/tools/TextToPDF.java | 2 +- .../java/org/apache/pdfbox/tools/WriteDecodedDoc.java | 2 +- 19 files changed, 24 insertions(+), 24 deletions(-) diff --git a/examples/src/main/java/org/apache/pdfbox/examples/interactive/form/PrintFields.java b/examples/src/main/java/org/apache/pdfbox/examples/interactive/form/PrintFields.java index 65e151bd4ec..7704f836f75 100644 --- a/examples/src/main/java/org/apache/pdfbox/examples/interactive/form/PrintFields.java +++ b/examples/src/main/java/org/apache/pdfbox/examples/interactive/form/PrintFields.java @@ -91,7 +91,7 @@ private void processField(PDField field, String sLevel, String sParent) throws I } /** - * This will read a PDF file and print out the form elements.
+ * This will read a PDF file and print out the form elements.
* see usage() for commandline * * @param args command line arguments diff --git a/examples/src/main/java/org/apache/pdfbox/examples/interactive/form/SetField.java b/examples/src/main/java/org/apache/pdfbox/examples/interactive/form/SetField.java index 08a2e809b5b..371f62febd5 100644 --- a/examples/src/main/java/org/apache/pdfbox/examples/interactive/form/SetField.java +++ b/examples/src/main/java/org/apache/pdfbox/examples/interactive/form/SetField.java @@ -81,7 +81,7 @@ else if (field instanceof PDTextField) /** * This will read a PDF file and set a field and then write it the pdf out - * again.
+ * again.
* see usage() for commandline * * @param args command line arguments diff --git a/examples/src/main/java/org/apache/pdfbox/examples/pdmodel/AddImageToPDF.java b/examples/src/main/java/org/apache/pdfbox/examples/pdmodel/AddImageToPDF.java index e6ca5b1f637..26479ad7c88 100644 --- a/examples/src/main/java/org/apache/pdfbox/examples/pdmodel/AddImageToPDF.java +++ b/examples/src/main/java/org/apache/pdfbox/examples/pdmodel/AddImageToPDF.java @@ -80,7 +80,7 @@ public void createPDFFromImage( String inputFile, String imagePath, String outpu /** * This will load a PDF document and add a single image on it. - *
+ *
* see usage() for commandline * * @param args Command line arguments. diff --git a/examples/src/main/java/org/apache/pdfbox/examples/pdmodel/AddMessageToEachPage.java b/examples/src/main/java/org/apache/pdfbox/examples/pdmodel/AddMessageToEachPage.java index 56d3fc79583..f01a5609179 100644 --- a/examples/src/main/java/org/apache/pdfbox/examples/pdmodel/AddMessageToEachPage.java +++ b/examples/src/main/java/org/apache/pdfbox/examples/pdmodel/AddMessageToEachPage.java @@ -109,7 +109,7 @@ public void doIt( String file, String message, String outfile ) throws IOExcept /** * This will create a hello world PDF document. - *
+ *
* see usage() for commandline * * @param args Command line arguments. diff --git a/examples/src/main/java/org/apache/pdfbox/examples/pdmodel/EmbeddedFiles.java b/examples/src/main/java/org/apache/pdfbox/examples/pdmodel/EmbeddedFiles.java index b8d5162857c..08deb416e69 100644 --- a/examples/src/main/java/org/apache/pdfbox/examples/pdmodel/EmbeddedFiles.java +++ b/examples/src/main/java/org/apache/pdfbox/examples/pdmodel/EmbeddedFiles.java @@ -120,7 +120,7 @@ public void doIt( String file) throws IOException /** * This will create a hello world PDF document with an embedded file. - *
+ *
* see usage() for commandline * * @param args Command line arguments. diff --git a/examples/src/main/java/org/apache/pdfbox/examples/pdmodel/PrintURLs.java b/examples/src/main/java/org/apache/pdfbox/examples/pdmodel/PrintURLs.java index a245cc8fc40..a60b66ea042 100644 --- a/examples/src/main/java/org/apache/pdfbox/examples/pdmodel/PrintURLs.java +++ b/examples/src/main/java/org/apache/pdfbox/examples/pdmodel/PrintURLs.java @@ -48,7 +48,7 @@ private PrintURLs() /** * This will create a hello world PDF document. - *
+ *
* see usage() for commandline * * @param args Command line arguments. diff --git a/examples/src/main/java/org/apache/pdfbox/examples/pdmodel/ReplaceURLs.java b/examples/src/main/java/org/apache/pdfbox/examples/pdmodel/ReplaceURLs.java index b17e8e36a38..682cae7e869 100644 --- a/examples/src/main/java/org/apache/pdfbox/examples/pdmodel/ReplaceURLs.java +++ b/examples/src/main/java/org/apache/pdfbox/examples/pdmodel/ReplaceURLs.java @@ -48,7 +48,7 @@ private ReplaceURLs() /** * This will read in a document and replace all of the urls with * http://pdfbox.apache.org. - *
+ *
* see usage() for commandline * * @param args Command line arguments. diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/PDRectangle.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/PDRectangle.java index de2a5e91a41..49c80429066 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/PDRectangle.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/PDRectangle.java @@ -156,8 +156,8 @@ public boolean contains( float x, float y ) /** * This will create a translated rectangle based off of this rectangle, such * that the new rectangle retains the same dimensions(height/width), but the - * lower left x,y values are zero.
- * 100, 100, 400, 400 (llx, lly, urx, ury )
+ * lower left x,y values are zero.
+ * 100, 100, 400, 400 (llx, lly, urx, ury )
* will be translated to 0,0,300,300 * * @return A new rectangle that has been translated back to the origin. diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/PDCryptFilterDictionary.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/PDCryptFilterDictionary.java index d82ad663f0d..d5b06ea763b 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/PDCryptFilterDictionary.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/PDCryptFilterDictionary.java @@ -72,7 +72,7 @@ public void setLength(int length) } /** - * This will return the Length entry of the crypt filter dictionary.

+ * This will return the Length entry of the crypt filter dictionary.

* The length in bits for the crypt filter algorithm. This will return a multiple of 8. * * @return The length in bits for the encryption algorithm diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/PDEncryption.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/PDEncryption.java index 18edd868d02..0c9f81794d6 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/PDEncryption.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/PDEncryption.java @@ -214,7 +214,7 @@ public void setLength(int length) } /** - * This will return the Length entry of the encryption dictionary.

+ * This will return the Length entry of the encryption dictionary.

* The length in bits for the encryption algorithm. This will return a multiple of 8. * * @return The length in bits for the encryption algorithm @@ -225,8 +225,8 @@ public int getLength() } /** - * This will set the R entry of the encryption dictionary.

- * See PDF Reference 1.4 Table 3.14.

+ * This will set the R entry of the encryption dictionary.

+ * See PDF Reference 1.4 Table 3.14.

* * Note: This value is used to decrypt the pdf document. If you change this when * the document is encrypted then decryption will fail!. @@ -239,7 +239,7 @@ public void setRevision(int revision) } /** - * This will return the R entry of the encryption dictionary.

+ * This will return the R entry of the encryption dictionary.

* See PDF Reference 1.4 Table 3.14. * * @return The encryption revision to use. diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/fdf/FDFField.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/fdf/FDFField.java index fba435c756f..aaf5bf85915 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/fdf/FDFField.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/fdf/FDFField.java @@ -209,8 +209,8 @@ public void setPartialFieldName(String partial) } /** - * This will get the value for the field. This will return type will either be
- * String : Checkboxes, Radio Button
+ * This will get the value for the field. This will return type will either be
+ * String : Checkboxes, Radio Button
* java.util.List of strings: Choice Field PDTextStream: Textfields * * @return The value of the field. diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/fdf/FDFIconFit.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/fdf/FDFIconFit.java index 0b60b868c24..b7b5954ce20 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/fdf/FDFIconFit.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/fdf/FDFIconFit.java @@ -139,7 +139,7 @@ public void setScaleType(String scale) } /** - * This is guaranteed to never return null.
+ * This is guaranteed to never return null.
* * To quote the PDF Spec "An array of two numbers between 0.0 and 1.0 indicating the fraction of leftover space to * allocate at the left and bottom of the icon. A value of [0.0 0.0] positions the icon at the bottom-left corner of diff --git a/pdfbox/src/main/java/org/apache/pdfbox/text/PDFTextStripper.java b/pdfbox/src/main/java/org/apache/pdfbox/text/PDFTextStripper.java index a2cc219b756..1b1b1338c61 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/text/PDFTextStripper.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/text/PDFTextStripper.java @@ -214,7 +214,7 @@ public PDFTextStripper() throws IOException } /** - * This will return the text of a document. See writeText.
+ * This will return the text of a document. See writeText.
* NOTE: The document must not be encrypted when coming into this method. * * @param doc The document to get the text from. diff --git a/tools/src/main/java/org/apache/pdfbox/tools/ExportFDF.java b/tools/src/main/java/org/apache/pdfbox/tools/ExportFDF.java index ef4c3b28f99..48e3259dc95 100644 --- a/tools/src/main/java/org/apache/pdfbox/tools/ExportFDF.java +++ b/tools/src/main/java/org/apache/pdfbox/tools/ExportFDF.java @@ -40,7 +40,7 @@ public ExportFDF() /** * This will import an fdf document and write out another pdf. - *
+ *
* see usage() for commandline * * @param args command line arguments diff --git a/tools/src/main/java/org/apache/pdfbox/tools/ExportXFDF.java b/tools/src/main/java/org/apache/pdfbox/tools/ExportXFDF.java index b5b876bef3b..cb00382f688 100644 --- a/tools/src/main/java/org/apache/pdfbox/tools/ExportXFDF.java +++ b/tools/src/main/java/org/apache/pdfbox/tools/ExportXFDF.java @@ -40,7 +40,7 @@ public ExportXFDF() /** * This will import an fdf document and write out another pdf. - *
+ *
* see usage() for commandline * * @param args command line arguments diff --git a/tools/src/main/java/org/apache/pdfbox/tools/ImportFDF.java b/tools/src/main/java/org/apache/pdfbox/tools/ImportFDF.java index 25ad367da72..a8200c73346 100644 --- a/tools/src/main/java/org/apache/pdfbox/tools/ImportFDF.java +++ b/tools/src/main/java/org/apache/pdfbox/tools/ImportFDF.java @@ -65,7 +65,7 @@ public void importFDF( PDDocument pdfDocument, FDFDocument fdfDocument ) throws /** * This will import an fdf document and write out another pdf. - *
+ *
* see usage() for commandline * * @param args command line arguments diff --git a/tools/src/main/java/org/apache/pdfbox/tools/ImportXFDF.java b/tools/src/main/java/org/apache/pdfbox/tools/ImportXFDF.java index 63dd0040a98..acb8b852549 100644 --- a/tools/src/main/java/org/apache/pdfbox/tools/ImportXFDF.java +++ b/tools/src/main/java/org/apache/pdfbox/tools/ImportXFDF.java @@ -59,7 +59,7 @@ public void importFDF( PDDocument pdfDocument, FDFDocument fdfDocument ) throws /** * This will import an fdf document and write out another pdf. - *
+ *
* see usage() for commandline * * @param args command line arguments diff --git a/tools/src/main/java/org/apache/pdfbox/tools/TextToPDF.java b/tools/src/main/java/org/apache/pdfbox/tools/TextToPDF.java index 594864f6ce3..a63f47dd1f4 100644 --- a/tools/src/main/java/org/apache/pdfbox/tools/TextToPDF.java +++ b/tools/src/main/java/org/apache/pdfbox/tools/TextToPDF.java @@ -210,7 +210,7 @@ public void createPDFFromText( PDDocument doc, Reader text ) throws IOException /** * This will create a PDF document with some text in it. - *
+ *
* see usage() for commandline * * @param args Command line arguments. diff --git a/tools/src/main/java/org/apache/pdfbox/tools/WriteDecodedDoc.java b/tools/src/main/java/org/apache/pdfbox/tools/WriteDecodedDoc.java index 15c03bde26f..aa0a77de89b 100644 --- a/tools/src/main/java/org/apache/pdfbox/tools/WriteDecodedDoc.java +++ b/tools/src/main/java/org/apache/pdfbox/tools/WriteDecodedDoc.java @@ -89,7 +89,7 @@ public void doIt(String in, String out, String password) /** * This will write a PDF document with completely decoded streams. - *
+ *
* see usage() for commandline * * @param args command line arguments From 8ca8e2c5d6f463e5cfc9bfc17a369d4933860e86 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Mon, 27 Jun 2016 15:42:15 +0000 Subject: [PATCH 0166/2182] PDFBOX-3401: call PDXObject.createXObject() only if parameter is a COSStream git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1750363 13f79535-47bb-0310-9956-ffa450edef68 --- .../logicalstructure/PDObjectReference.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/documentinterchange/logicalstructure/PDObjectReference.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/documentinterchange/logicalstructure/PDObjectReference.java index 19862bff9c6..40a57859229 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/documentinterchange/logicalstructure/PDObjectReference.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/documentinterchange/logicalstructure/PDObjectReference.java @@ -21,6 +21,7 @@ import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; +import org.apache.pdfbox.cos.COSStream; import org.apache.pdfbox.pdmodel.common.COSObjectable; import org.apache.pdfbox.pdmodel.graphics.PDXObject; import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotation; @@ -88,10 +89,13 @@ public COSObjectable getReferencedObject() } try { - PDXObject xobject = PDXObject.createXObject(obj, null); // <-- TODO: valid? - if (xobject != null) + if (obj instanceof COSStream) { - return xobject; + PDXObject xobject = PDXObject.createXObject(obj, null); // <-- TODO: valid? + if (xobject != null) + { + return xobject; + } } COSDictionary objDictionary = (COSDictionary)obj; PDAnnotation annotation = PDAnnotation.createAnnotation(obj); From 7f9f5f0f1e91137d64b389b8e5dfde65d7a686da Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Mon, 27 Jun 2016 15:50:54 +0000 Subject: [PATCH 0167/2182] PDFBOX-2852: fix javadoc git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1750365 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/pdfbox/pdmodel/font/PDPanoseClassification.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDPanoseClassification.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDPanoseClassification.java index bfd3823c828..089fed559d0 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDPanoseClassification.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDPanoseClassification.java @@ -18,9 +18,8 @@ package org.apache.pdfbox.pdmodel.font; /** - * Represents a 10-byte PANOSE classification. + * Represents a 10-byte PANOSE classification. * - * @link http://www.monotype.com/services/pan2 * @author John Hewson */ public class PDPanoseClassification From 36accff47924647b7a0cbbf1dd8484f8900a198b Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Mon, 27 Jun 2016 15:53:21 +0000 Subject: [PATCH 0168/2182] PDFBOX-2852: fix javadoc git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1750367 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/pdfbox/pdmodel/graphics/blend/BlendComposite.java | 2 +- .../org/apache/pdfbox/pdmodel/graphics/blend/BlendMode.java | 2 +- .../pdfbox/pdmodel/graphics/blend/NonSeparableBlendMode.java | 2 +- .../pdfbox/pdmodel/graphics/blend/SeparableBlendMode.java | 2 +- .../org/apache/pdfbox/pdmodel/graphics/blend/SoftMaskPaint.java | 2 +- .../pdmodel/graphics/form/PDTransparencyGroupAttributes.java | 2 +- .../org/apache/pdfbox/pdmodel/graphics/state/PDSoftMask.java | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/blend/BlendComposite.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/blend/BlendComposite.java index e8d33c60b0c..f20bee8c593 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/blend/BlendComposite.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/blend/BlendComposite.java @@ -30,7 +30,7 @@ /** * AWT composite for blend modes. * - * @author Kühn & Weyh Software, GmbH + * @author Kühn & Weyh Software GmbH */ public final class BlendComposite implements Composite { diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/blend/BlendMode.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/blend/BlendMode.java index c36d2b18e85..0aee8e831a2 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/blend/BlendMode.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/blend/BlendMode.java @@ -26,7 +26,7 @@ /** * Blend mode. * - * @author Kühn & Weyh Software, GmbH + * @author Kühn & Weyh Software GmbH */ public abstract class BlendMode { diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/blend/NonSeparableBlendMode.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/blend/NonSeparableBlendMode.java index 7ab7262dfdd..1e40abcaaa3 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/blend/NonSeparableBlendMode.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/blend/NonSeparableBlendMode.java @@ -19,7 +19,7 @@ /** * Non-separable blend mode (supports blend function). * - * @author Kühn & Weyh Software, GmbH + * @author Kühn & Weyh Software GmbH */ public abstract class NonSeparableBlendMode extends BlendMode { diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/blend/SeparableBlendMode.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/blend/SeparableBlendMode.java index 0fdaf02a95e..c525fb79c9b 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/blend/SeparableBlendMode.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/blend/SeparableBlendMode.java @@ -19,7 +19,7 @@ /** * Separable blend mode (support blendChannel) * - * @author Kühn & Weyh Software, GmbH + * @author Kühn & Weyh Software GmbH */ public abstract class SeparableBlendMode extends BlendMode { diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/blend/SoftMaskPaint.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/blend/SoftMaskPaint.java index af874148b3e..212180aa646 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/blend/SoftMaskPaint.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/blend/SoftMaskPaint.java @@ -38,7 +38,7 @@ * AWT Paint that adds a soft mask to the alpha channel of the existing parent paint. If the parent * paint does not have an alpha channel, a new raster is created. * - * @author Kühn & Weyh Software, GmbH + * @author Kühn & Weyh Software GmbH */ public final class SoftMaskPaint implements Paint { diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/form/PDTransparencyGroupAttributes.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/form/PDTransparencyGroupAttributes.java index b30eebb41ca..68e20f887aa 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/form/PDTransparencyGroupAttributes.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/form/PDTransparencyGroupAttributes.java @@ -26,7 +26,7 @@ /** * Transparency group attributes. * - * @author Kühn & Weyh Software, GmbH + * @author Kühn & Weyh Software GmbH */ public final class PDTransparencyGroupAttributes implements COSObjectable { diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/state/PDSoftMask.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/state/PDSoftMask.java index 3e3a3d2884b..6d68e6c3009 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/state/PDSoftMask.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/state/PDSoftMask.java @@ -32,7 +32,7 @@ /** * Soft mask. * - * @author Kühn & Weyh Software, GmbH + * @author Kühn & Weyh Software GmbH */ public final class PDSoftMask implements COSObjectable { From a651fb2958308ec20f5f7399ce5e4dfa57b026fa Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Mon, 27 Jun 2016 15:58:23 +0000 Subject: [PATCH 0169/2182] PDFBOX-2852: fix javadoc git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1750371 13f79535-47bb-0310-9956-ffa450edef68 --- .../pdfbox/pdmodel/interactive/form/PDSignatureField.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDSignatureField.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDSignatureField.java index 17a91e97ce7..58e1889a37c 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDSignatureField.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDSignatureField.java @@ -125,7 +125,7 @@ public void setValue(PDSignature value) throws IOException * Sets the value of this field. * * This will throw an UnsupportedOperationException if used as the signature fields - * value can't be set using a String + * value can't be set using a String * * @param value the plain text value. * From a275b2163fdc3f22e5d95b383bc174c165713548 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Mon, 27 Jun 2016 16:00:10 +0000 Subject: [PATCH 0170/2182] PDFBOX-2852: fix javadoc git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1750373 13f79535-47bb-0310-9956-ffa450edef68 --- .../pdfbox/preflight/content/PreflightContentStream.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/preflight/src/main/java/org/apache/pdfbox/preflight/content/PreflightContentStream.java b/preflight/src/main/java/org/apache/pdfbox/preflight/content/PreflightContentStream.java index a1f00feb87c..44b8cf76f2c 100644 --- a/preflight/src/main/java/org/apache/pdfbox/preflight/content/PreflightContentStream.java +++ b/preflight/src/main/java/org/apache/pdfbox/preflight/content/PreflightContentStream.java @@ -164,10 +164,9 @@ protected void unsupportedOperator(Operator operator, List arguments) } /** - * Process Text Validation. According to the operator one of the both method will be called. - * (validStringDefinition(PDFOperator operator, List arguments) / validStringArray(PDFOperator operator, List - * arguments)) - * + * Process Text Validation. Depending on the operator parameter, this will either call + * validateStringDefinition or validateStringArray. + * * @param operator * @param arguments * @throws IOException From b4782c6d674af2490f657fa726bfaf984d3c3c95 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Mon, 27 Jun 2016 16:43:38 +0000 Subject: [PATCH 0171/2182] PDFBOX-2852: fix javadoc git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1750380 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/pdfbox/pdmodel/interactive/form/PDButton.java | 1 - 1 file changed, 1 deletion(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDButton.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDButton.java index cc6c4e3837d..3e5b4b4bdf5 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDButton.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDButton.java @@ -219,7 +219,6 @@ public String getValueAsString() *

  • allow radio buttons having the same export value to be handled independently *
  • * - *

    * * @return List containing all possible export values. If there is no Opt entry an empty list will be returned. */ From 0acb49a7700301a97a56c87c468a7b119bd21f41 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Mon, 27 Jun 2016 16:44:58 +0000 Subject: [PATCH 0172/2182] PDFBOX-2852: fix javadoc git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1750382 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/pdfbox/pdmodel/interactive/form/PDChoice.java | 1 - 1 file changed, 1 deletion(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDChoice.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDChoice.java index 47de629ef6d..fe08f805d0d 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDChoice.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDChoice.java @@ -242,7 +242,6 @@ public List getSelectedOptionsIndex() *

    *

    * Setting the index will set the value too. - *

    * * @param values List containing the indices of all selected options. */ From f737f1cb098eee2041b0f07ffc08e017047503cc Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Mon, 27 Jun 2016 16:47:03 +0000 Subject: [PATCH 0173/2182] PDFBOX-2852: fix javadoc git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1750385 13f79535-47bb-0310-9956-ffa450edef68 --- pdfbox/src/main/java/org/apache/pdfbox/util/Matrix.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/util/Matrix.java b/pdfbox/src/main/java/org/apache/pdfbox/util/Matrix.java index a1d5669d087..6a6232257fd 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/util/Matrix.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/util/Matrix.java @@ -274,7 +274,7 @@ public Matrix multiply( Matrix b ) * This method multiplies this Matrix with the specified other Matrix, storing the product in the specified * result Matrix. By reusing Matrix instances like this, multiplication chains can be executed without having * to create many temporary Matrix objects. - *

    + *

    * It is allowed to have (other == this) or (result == this) or indeed (other == result) but if this is done, * the backing float[] matrix values may be copied in order to ensure a correct product. * @@ -389,7 +389,7 @@ public Point2D.Float transformPoint(float x, float y) /** * Transforms the given point by this matrix. * - * @param vector @2D vector + * @param vector 2D vector */ public Vector transform(Vector vector) { From 00c38629402ef23f49932e2e22880203f478b294 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Mon, 27 Jun 2016 16:51:21 +0000 Subject: [PATCH 0174/2182] PDFBOX-2852: fix javadoc git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1750388 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/pdfbox/debugger/ui/PDFTreeModel.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debugger/src/main/java/org/apache/pdfbox/debugger/ui/PDFTreeModel.java b/debugger/src/main/java/org/apache/pdfbox/debugger/ui/PDFTreeModel.java index 7a577373ae8..7d2d1c4739b 100644 --- a/debugger/src/main/java/org/apache/pdfbox/debugger/ui/PDFTreeModel.java +++ b/debugger/src/main/java/org/apache/pdfbox/debugger/ui/PDFTreeModel.java @@ -92,7 +92,7 @@ public void addTreeModelListener(TreeModelListener l) * Returns the child of parent at index index in the parent's child * array. parent must be a node previously obtained from this data source. This * should not return null if index is a valid index for - * parent (that is index >= 0 && + * parent (that is index >= 0 && * index < getChildCount(parent)). * * @param parent a node in the tree, obtained from this data source From 7bbd82f90441645dff82b67a07abf647a0c0b213 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Mon, 27 Jun 2016 17:59:21 +0000 Subject: [PATCH 0175/2182] PDFBOX-2852: fix javadoc git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1750396 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/pdfbox/debugger/PDFDebugger.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/debugger/src/main/java/org/apache/pdfbox/debugger/PDFDebugger.java b/debugger/src/main/java/org/apache/pdfbox/debugger/PDFDebugger.java index 34e4361a574..de613def59d 100644 --- a/debugger/src/main/java/org/apache/pdfbox/debugger/PDFDebugger.java +++ b/debugger/src/main/java/org/apache/pdfbox/debugger/PDFDebugger.java @@ -508,7 +508,7 @@ public JMenu getFindMenu() } /** - * Returns the Edit > Find > Find menu item. + * Returns the Edit > Find > Find menu item. */ public JMenuItem getFindMenuItem() { @@ -516,7 +516,7 @@ public JMenuItem getFindMenuItem() } /** - * Returns the Edit > Find > Find Next menu item. + * Returns the Edit > Find > Find Next menu item. */ public JMenuItem getFindNextMenuItem() { @@ -524,7 +524,7 @@ public JMenuItem getFindNextMenuItem() } /** - * Returns the Edit > Find > Find Previous menu item. + * Returns the Edit > Find > Find Previous menu item. */ public JMenuItem getFindPreviousMenuItem() { From d7e5d20a084b14e4ef77ca5bde01368c02bac2fb Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Tue, 28 Jun 2016 15:36:00 +0000 Subject: [PATCH 0176/2182] PDFBOX-2852: fix javadoc git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1750539 13f79535-47bb-0310-9956-ffa450edef68 --- .../pdfbox/examples/lucene/LucenePDFDocument.java | 1 + .../examples/signature/CreateSignatureBase.java | 3 ++- .../org/apache/pdfbox/tools/imageio/TIFFUtil.java | 14 ++++++++------ 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/examples/src/main/java/org/apache/pdfbox/examples/lucene/LucenePDFDocument.java b/examples/src/main/java/org/apache/pdfbox/examples/lucene/LucenePDFDocument.java index 55b4db254ba..0fddefa8a74 100644 --- a/examples/src/main/java/org/apache/pdfbox/examples/lucene/LucenePDFDocument.java +++ b/examples/src/main/java/org/apache/pdfbox/examples/lucene/LucenePDFDocument.java @@ -43,6 +43,7 @@ * This class is used to create a document for the lucene search engine. This should easily plug into the IndexPDFFiles * that comes with the lucene project. This class will populate the following fields. * + * * * * diff --git a/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateSignatureBase.java b/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateSignatureBase.java index c0e0783a2d2..665c69f602c 100644 --- a/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateSignatureBase.java +++ b/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateSignatureBase.java @@ -139,13 +139,14 @@ private SignerInformation signTimeStamp(SignerInformation signer) * This method will be called from inside of the pdfbox and create the PKCS #7 signature. * The given InputStream contains the bytes that are given by the byte range. * - * This method is for internal use only. <-- TODO this method should be private + * This method is for internal use only. * * Use your favorite cryptographic library to implement PKCS #7 signature creation. */ @Override public byte[] sign(InputStream content) throws IOException { + //TODO this method should be private try { List certList = new ArrayList(); diff --git a/tools/src/main/java/org/apache/pdfbox/tools/imageio/TIFFUtil.java b/tools/src/main/java/org/apache/pdfbox/tools/imageio/TIFFUtil.java index 3753f9aa5fd..fc233f23bed 100644 --- a/tools/src/main/java/org/apache/pdfbox/tools/imageio/TIFFUtil.java +++ b/tools/src/main/java/org/apache/pdfbox/tools/imageio/TIFFUtil.java @@ -76,12 +76,14 @@ public static void setCompressionType(ImageWriteParam param, BufferedImage image } /** - * Updates the given ImageIO metadata with Sun's custom TIFF tags. - * {@see https://svn.apache.org/repos/asf/xmlgraphics/commons/tags/commons-1_3_1/src/java/org/ - * apache/xmlgraphics/image/writer/imageio/ImageIOTIFFImageWriter.java} - * {@see http://download.java.net/media/jai-imageio/javadoc/1.0_01/com/sun/media/imageio/ - * plugins/tiff/package-summary.html} - * {@see http://partners.adobe.com/public/developer/tiff/index.html} + * Updates the given ImageIO metadata with Sun's custom TIFF tags, as described in + * the org.apache.xmlgraphics.image.writer.imageio.ImageIOTIFFImageWriter + * sources, + * the com.sun.media.imageio.plugins.tiff + * package javadoc + * and the TIFF + * specification. + * * @param image buffered image which will be written * @param metadata ImageIO metadata * @param dpi image dots per inch From 89c7b3078ede376970ecce51d43ca8d6cc2ee312 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Tue, 28 Jun 2016 15:42:51 +0000 Subject: [PATCH 0177/2182] PDFBOX-3403: add MacExpertEncoding git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1750541 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/pdfbox/cos/COSName.java | 1 + .../pdmodel/font/encoding/Encoding.java | 4 + .../font/encoding/MacExpertEncoding.java | 229 ++++++++++++++++++ 3 files changed, 234 insertions(+) create mode 100644 pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/MacExpertEncoding.java diff --git a/pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java b/pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java index 91ccbc68370..f5b5d0472b6 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java @@ -328,6 +328,7 @@ public final class COSName extends COSBase implements Comparable // M public static final COSName M = new COSName("M"); public static final COSName MAC = new COSName("Mac"); + public static final COSName MAC_EXPERT_ENCODING = new COSName("MacExpertEncoding"); public static final COSName MAC_ROMAN_ENCODING = new COSName("MacRomanEncoding"); public static final COSName MARK_INFO = new COSName("MarkInfo"); public static final COSName MASK = new COSName("Mask"); diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/Encoding.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/Encoding.java index 95dfa19fde6..b99ab837dd0 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/Encoding.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/Encoding.java @@ -51,6 +51,10 @@ else if (COSName.MAC_ROMAN_ENCODING.equals(name)) { return MacRomanEncoding.INSTANCE; } + else if (COSName.MAC_EXPERT_ENCODING.equals(name)) + { + return MacExpertEncoding.INSTANCE; + } else { return null; diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/MacExpertEncoding.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/MacExpertEncoding.java new file mode 100644 index 00000000000..1fa76f05a46 --- /dev/null +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/MacExpertEncoding.java @@ -0,0 +1,229 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.pdfbox.pdmodel.font.encoding; + +import org.apache.pdfbox.cos.COSBase; +import org.apache.pdfbox.cos.COSName; + +/** + * This is an interface to a text encoder. + */ +public class MacExpertEncoding extends Encoding +{ + + private static final int CHAR_CODE = 0; + private static final int CHAR_NAME = 1; + + /** + * Table of octal character codes and their corresponding names. + */ + private static final Object[][] MAC_EXPERT_ENCODING_TABLE = { + {0276, "AEsmall"}, + {0207, "Aacutesmall"}, + {0211, "Acircumflexsmall"}, + {047, "Acutesmall"}, + {0212, "Adieresissmall"}, + {0210, "Agravesmall"}, + {0214, "Aringsmall"}, + {0141, "Asmall"}, + {0213, "Atildesmall"}, + {0363, "Brevesmall"}, + {0142, "Bsmall"}, + {0256, "Caronsmall"}, + {0215, "Ccedillasmall"}, + {0311, "Cedillasmall"}, + {0136, "Circumflexsmall"}, + {0143, "Csmall"}, + {0254, "Dieresissmall"}, + {0372, "Dotaccentsmall"}, + {0144, "Dsmall"}, + {0216, "Eacutesmall"}, + {0220, "Ecircumflexsmall"}, + {0221, "Edieresissmall"}, + {0217, "Egravesmall"}, + {0145, "Esmall"}, + {0104, "Ethsmall"}, + {0146, "Fsmall"}, + {0140, "Gravesmall"}, + {0147, "Gsmall"}, + {0150, "Hsmall"}, + {042, "Hungarumlautsmall"}, + {0222, "Iacutesmall"}, + {0224, "Icircumflexsmall"}, + {0225, "Idieresissmall"}, + {0223, "Igravesmall"}, + {0151, "Ismall"}, + {0152, "Jsmall"}, + {0153, "Ksmall"}, + {0302, "Lslashsmall"}, + {0154, "Lsmall"}, + {0364, "Macronsmall"}, + {0155, "Msmall"}, + {0156, "Nsmall"}, + {0226, "Ntildesmall"}, + {0317, "OEsmall"}, + {0227, "Oacutesmall"}, + {0231, "Ocircumflexsmall"}, + {0232, "Odieresissmall"}, + {0362, "Ogoneksmall"}, + {0230, "Ogravesmall"}, + {0277, "Oslashsmall"}, + {0157, "Osmall"}, + {0233, "Otildesmall"}, + {0160, "Psmall"}, + {0161, "Qsmall"}, + {0373, "Ringsmall"}, + {0162, "Rsmall"}, + {0247, "Scaronsmall"}, + {0163, "Ssmall"}, + {0271, "Thornsmall"}, + {0176, "Tildesmall"}, + {0164, "Tsmall"}, + {0234, "Uacutesmall"}, + {0236, "Ucircumflexsmall"}, + {0237, "Udieresissmall"}, + {0235, "Ugravesmall"}, + {0165, "Usmall"}, + {0166, "Vsmall"}, + {0167, "Wsmall"}, + {0170, "Xsmall"}, + {0264, "Yacutesmall"}, + {0330, "Ydieresissmall"}, + {0171, "Ysmall"}, + {0275, "Zcaronsmall"}, + {0172, "Zsmall"}, + {046, "ampersandsmall"}, + {0201, "asuperior"}, + {0365, "bsuperior"}, + {0251, "centinferior"}, + {043, "centoldstyle"}, + {0202, "centsuperior"}, + {072, "colon"}, + {0173, "colonmonetary"}, + {054, "comma"}, + {0262, "commainferior"}, + {0370, "commasuperior"}, + {0266, "dollarinferior"}, + {044, "dollaroldstyle"}, + {045, "dollarsuperior"}, + {0353, "dsuperior"}, + {0245, "eightinferior"}, + {070, "eightoldstyle"}, + {0241, "eightsuperior"}, + {0344, "esuperior"}, + {0326, "exclamdownsmall"}, + {041, "exclamsmall"}, + {0126, "ff"}, + {0131, "ffi"}, + {0132, "ffl"}, + {0127, "fi"}, + {0320, "figuredash"}, + {0114, "fiveeighths"}, + {0260, "fiveinferior"}, + {065, "fiveoldstyle"}, + {0336, "fivesuperior"}, + {0130, "fl"}, + {0242, "fourinferior"}, + {064, "fouroldstyle"}, + {0335, "foursuperior"}, + {057, "fraction"}, + {055, "hyphen"}, + {0137, "hypheninferior"}, + {0321, "hyphensuperior"}, + {0351, "isuperior"}, + {0361, "lsuperior"}, + {0367, "msuperior"}, + {0273, "nineinferior"}, + {071, "nineoldstyle"}, + {0341, "ninesuperior"}, + {0366, "nsuperior"}, + {053, "onedotenleader"}, + {0112, "oneeighth"}, + {0174, "onefitted"}, + {0110, "onehalf"}, + {0301, "oneinferior"}, + {061, "oneoldstyle"}, + {0107, "onequarter"}, + {0332, "onesuperior"}, + {0116, "onethird"}, + {0257, "osuperior"}, + {0133, "parenleftinferior"}, + {050, "parenleftsuperior"}, + {0135, "parenrightinferior"}, + {051, "parenrightsuperior"}, + {056, "period"}, + {0263, "periodinferior"}, + {0371, "periodsuperior"}, + {0300, "questiondownsmall"}, + {077, "questionsmall"}, + {0345, "rsuperior"}, + {0175, "rupiah"}, + {073, "semicolon"}, + {0115, "seveneighths"}, + {0246, "seveninferior"}, + {067, "sevenoldstyle"}, + {0340, "sevensuperior"}, + {0244, "sixinferior"}, + {066, "sixoldstyle"}, + {0337, "sixsuperior"}, + {040, "space"}, + {0352, "ssuperior"}, + {0113, "threeeighths"}, + {0243, "threeinferior"}, + {063, "threeoldstyle"}, + {0111, "threequarters"}, + {075, "threequartersemdash"}, + {0334, "threesuperior"}, + {0346, "tsuperior"}, + {052, "twodotenleader"}, + {0252, "twoinferior"}, + {062, "twooldstyle"}, + {0333, "twosuperior"}, + {0117, "twothirds"}, + {0274, "zeroinferior"}, + {060, "zerooldstyle"}, + {0342, "zerosuperior"} + }; + + /** + * Singleton instance of this class. + */ + public static final MacExpertEncoding INSTANCE = new MacExpertEncoding(); + + /** + * Constructor. + */ + public MacExpertEncoding() + { + for (Object[] encodingEntry : MAC_EXPERT_ENCODING_TABLE) + { + add((Integer) encodingEntry[CHAR_CODE], encodingEntry[CHAR_NAME].toString()); + } + } + + @Override + public COSBase getCOSObject() + { + return COSName.MAC_EXPERT_ENCODING; + } + + @Override + public String getEncodingName() + { + return "MacExpertEncoding"; + } +} From 5055c4ef6a96b87b71046b3685623dd5ee06306c Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Tue, 28 Jun 2016 16:34:36 +0000 Subject: [PATCH 0178/2182] PDFBOX-3404: use concurrent HashSet git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1750547 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/pdfbox/pdmodel/font/encoding/Encoding.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/Encoding.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/Encoding.java index b99ab837dd0..825178714e9 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/Encoding.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/Encoding.java @@ -18,9 +18,9 @@ import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; import java.util.Map; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.pdmodel.common.COSObjectable; @@ -109,7 +109,7 @@ public boolean contains(String name) // otherwise /Differences won't be accounted for if (names == null) { - names = new HashSet(codeToName.size()); + names = Collections.newSetFromMap(new ConcurrentHashMap()); names.addAll(codeToName.values()); } return names.contains(name); From 87caee55b8f5a26810c97148f6880a2c5f22b2fb Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Tue, 28 Jun 2016 19:25:55 +0000 Subject: [PATCH 0179/2182] PDFBOX-3403: don't throw exception if encoding is missing but use /differences table, as suggested by Michael Klink git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1750562 13f79535-47bb-0310-9956-ffa450edef68 --- .../pdfbox/pdmodel/font/PDSimpleFont.java | 4 ++ .../font/encoding/DictionaryEncoding.java | 40 +++++++++++++------ 2 files changed, 32 insertions(+), 12 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDSimpleFont.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDSimpleFont.java index d2a1368ba21..18b6d40f63c 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDSimpleFont.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDSimpleFont.java @@ -369,6 +369,10 @@ public boolean isStandard14() // we also require that the differences are actually different, see PDFBOX-1900 with // the file from PDFBOX-2192 on Windows Encoding baseEncoding = dictionary.getBaseEncoding(); + if (baseEncoding == null) + { + return false; + } for (Map.Entry entry : dictionary.getDifferences().entrySet()) { if (!entry.getValue().equals(baseEncoding.getName(entry.getKey()))) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/DictionaryEncoding.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/DictionaryEncoding.java index f2fbe22afd7..835d263fa5b 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/DictionaryEncoding.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/DictionaryEncoding.java @@ -19,6 +19,8 @@ import java.util.HashMap; import java.util.Map; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; @@ -32,12 +34,16 @@ */ public class DictionaryEncoding extends Encoding { + private static final Log LOG = LogFactory.getLog(DictionaryEncoding.class); private final COSDictionary encoding; private final Encoding baseEncoding; private final Map differences = new HashMap(); /** * Creates a new DictionaryEncoding for embedding. + * + * @param baseEncoding + * @param differences */ public DictionaryEncoding(COSName baseEncoding, COSArray differences) { @@ -56,11 +62,14 @@ public DictionaryEncoding(COSName baseEncoding, COSArray differences) if (this.baseEncoding == null) { - throw new IllegalArgumentException("Invalid encoding: " + baseEncoding); + LOG.error("Invalid encoding: " + baseEncoding); } - codeToName.putAll(this.baseEncoding.codeToName); - inverted.putAll(this.baseEncoding.inverted); + if (this.baseEncoding != null) + { + codeToName.putAll(this.baseEncoding.codeToName); + inverted.putAll(this.baseEncoding.inverted); + } applyDifferences(); } @@ -91,7 +100,7 @@ public DictionaryEncoding(COSDictionary fontEncoding, boolean isNonSymbolic, Enc if (encoding.containsKey(COSName.BASE_ENCODING)) { COSName name = encoding.getCOSName(COSName.BASE_ENCODING); - base = Encoding.getInstance(name); // may be null + base = Encoding.getInstance(name); } if (base == null) @@ -110,26 +119,33 @@ public DictionaryEncoding(COSDictionary fontEncoding, boolean isNonSymbolic, Enc } else { - throw new IllegalArgumentException("Symbolic fonts must have a built-in " + - "encoding"); + LOG.error("Symbolic fonts must have a built-in encoding"); } } } baseEncoding = base; - codeToName.putAll(baseEncoding.codeToName); - inverted.putAll(baseEncoding.inverted); + if (baseEncoding != null) + { + codeToName.putAll(baseEncoding.codeToName); + inverted.putAll(baseEncoding.inverted); + } applyDifferences(); } private void applyDifferences() { // now replace with the differences - COSArray differences = (COSArray)encoding.getDictionaryObject( COSName.DIFFERENCES ); + COSBase base = encoding.getDictionaryObject(COSName.DIFFERENCES); + if (!(base instanceof COSArray)) + { + return; + } + COSArray diffArray = (COSArray) base; int currentIndex = -1; - for( int i=0; differences != null && i Date: Tue, 28 Jun 2016 20:04:00 +0000 Subject: [PATCH 0180/2182] PDFBOX-3382, PDFBOX-3404: use concurrentHashMap for standard 14 fonts; remove double WinAnsiEncoding assignment and use it as a singleton; remove unused field git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1750577 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/pdfbox/pdmodel/font/PDFont.java | 7 ++++++- .../org/apache/pdfbox/pdmodel/font/PDSimpleFont.java | 5 +---- .../org/apache/pdfbox/pdmodel/font/PDType1Font.java | 12 +++++++++--- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDFont.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDFont.java index eb4e4bb76b0..c0ff535db65 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDFont.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDFont.java @@ -24,6 +24,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.fontbox.afm.FontMetrics; @@ -64,7 +65,7 @@ public abstract class PDFont implements COSObjectable, PDFontLike private List widths; private float avgFontWidth; private float fontWidthOfSpace = -1f; - private final Map codeToWidthMap = new HashMap(); + private final Map codeToWidthMap; /** * Constructor for embedding. @@ -76,6 +77,7 @@ public abstract class PDFont implements COSObjectable, PDFontLike toUnicodeCMap = null; fontDescriptor = null; afmStandard14 = null; + codeToWidthMap = new HashMap(); } /** @@ -92,6 +94,8 @@ public abstract class PDFont implements COSObjectable, PDFontLike throw new IllegalArgumentException("No AFM for font " + baseFont); } fontDescriptor = PDType1FontEmbedder.buildFontDescriptor(afmStandard14); + // standard 14 fonts may be accessed concurrently, as they are singletons + codeToWidthMap = new ConcurrentHashMap(); } /** @@ -102,6 +106,7 @@ public abstract class PDFont implements COSObjectable, PDFontLike protected PDFont(COSDictionary fontDictionary) throws IOException { dict = fontDictionary; + codeToWidthMap = new HashMap(); // standard 14 fonts use an AFM afmStandard14 = Standard14Fonts.getAFM(getName()); // may be null (it usually is) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDSimpleFont.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDSimpleFont.java index 18b6d40f63c..9ddae0a5aa9 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDSimpleFont.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDSimpleFont.java @@ -47,8 +47,7 @@ public abstract class PDSimpleFont extends PDFont protected GlyphList glyphList; private Boolean isSymbolic; private final Set noUnicode = new HashSet(); // for logging - private Map invertedEncoding; // for writing - + /** * Constructor for embedding. */ @@ -64,8 +63,6 @@ public abstract class PDSimpleFont extends PDFont { super(baseFont); - this.encoding = WinAnsiEncoding.INSTANCE; - // assign the glyph list based on the font if ("ZapfDingbats".equals(baseFont)) { diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1Font.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1Font.java index 044f65af945..1db70a26923 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1Font.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1Font.java @@ -25,6 +25,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.fontbox.EncodedFont; @@ -41,11 +42,11 @@ import org.apache.pdfbox.pdmodel.font.encoding.Encoding; import org.apache.pdfbox.pdmodel.font.encoding.StandardEncoding; import org.apache.pdfbox.pdmodel.font.encoding.Type1Encoding; -import org.apache.pdfbox.pdmodel.font.encoding.WinAnsiEncoding; import org.apache.pdfbox.util.Matrix; import static org.apache.pdfbox.pdmodel.font.UniUtil.getUniNameOfCodePoint; +import org.apache.pdfbox.pdmodel.font.encoding.WinAnsiEncoding; /** * A PostScript Type 1 Font. @@ -107,7 +108,7 @@ public class PDType1Font extends PDSimpleFont /** * to improve encoding speed. */ - private final Map codeToBytesMap = new HashMap(); + private final Map codeToBytesMap; /** * Creates a Type 1 standard 14 font for embedding. @@ -120,8 +121,10 @@ private PDType1Font(String baseFont) dict.setItem(COSName.SUBTYPE, COSName.TYPE1); dict.setName(COSName.BASE_FONT, baseFont); - encoding = new WinAnsiEncoding(); + encoding = WinAnsiEncoding.INSTANCE; dict.setItem(COSName.ENCODING, COSName.WIN_ANSI_ENCODING); + // standard 14 fonts may be accessed concurrently, as they are singletons + codeToBytesMap = new ConcurrentHashMap(); // todo: could load the PFB font here if we wanted to support Standard 14 embedding type1font = null; @@ -165,6 +168,7 @@ public PDType1Font(PDDocument doc, InputStream pfbIn) throws IOException isEmbedded = true; isDamaged = false; fontMatrixTransform = new AffineTransform(); + codeToBytesMap = new HashMap(); } /** @@ -185,6 +189,7 @@ public PDType1Font(PDDocument doc, InputStream pfbIn, Encoding encoding) throws isEmbedded = true; isDamaged = false; fontMatrixTransform = new AffineTransform(); + codeToBytesMap = new HashMap(); } /** @@ -197,6 +202,7 @@ public PDType1Font(PDDocument doc, InputStream pfbIn, Encoding encoding) throws public PDType1Font(COSDictionary fontDictionary) throws IOException { super(fontDictionary); + codeToBytesMap = new HashMap(); PDFontDescriptor fd = getFontDescriptor(); Type1Font t1 = null; From a1832958978fea648211bec7b99f7ec6766f4ded Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Tue, 28 Jun 2016 20:29:57 +0000 Subject: [PATCH 0181/2182] PDFBOX-3344: Handle the case where CFF/OTF fonts are embedded where TTF is expected + correct detection of OTF fonts via OTTO header, as done by John Hewson in the trunk git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1750580 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/fontbox/ttf/OpenTypeFont.java | 2 +- .../org/apache/fontbox/ttf/TTFParser.java | 26 +++++---- .../pdfbox/pdmodel/font/PDCIDFontType2.java | 53 ++++++++----------- 3 files changed, 38 insertions(+), 43 deletions(-) diff --git a/fontbox/src/main/java/org/apache/fontbox/ttf/OpenTypeFont.java b/fontbox/src/main/java/org/apache/fontbox/ttf/OpenTypeFont.java index bfb3e4820b1..8b9afc4b117 100644 --- a/fontbox/src/main/java/org/apache/fontbox/ttf/OpenTypeFont.java +++ b/fontbox/src/main/java/org/apache/fontbox/ttf/OpenTypeFont.java @@ -40,7 +40,7 @@ public class OpenTypeFont extends TrueTypeFont @Override void setVersion(float versionValue) { - isPostScript = versionValue != 1.0; + isPostScript = Float.floatToIntBits(versionValue) == 0x469EA8A9; // OTTO super.setVersion(versionValue); } diff --git a/fontbox/src/main/java/org/apache/fontbox/ttf/TTFParser.java b/fontbox/src/main/java/org/apache/fontbox/ttf/TTFParser.java index 022f2f9792b..1d636394694 100644 --- a/fontbox/src/main/java/org/apache/fontbox/ttf/TTFParser.java +++ b/fontbox/src/main/java/org/apache/fontbox/ttf/TTFParser.java @@ -175,6 +175,8 @@ private void parseTables(TrueTypeFont font, TTFDataStream raf) throws IOExceptio } } + boolean isPostScript = font.tables.containsKey(CFFTable.TAG); + HeaderTable head = font.getHeader(); if (head == null) { @@ -200,26 +202,30 @@ private void parseTables(TrueTypeFont font, TTFDataStream raf) throws IOExceptio throw new IOException("post is mandatory"); } - IndexToLocationTable loc = font.getIndexToLocation(); - if (loc == null) - { - throw new IOException("loca is mandatory"); - } - // check other mandatory tables - if (font.getGlyph() == null) + if (!isPostScript) { - throw new IOException("glyf is mandatory"); + IndexToLocationTable loc = font.getIndexToLocation(); + if (loc == null) + { + throw new IOException("loca is mandatory"); + } + + if (font.getGlyph() == null) + { + throw new IOException("glyf is mandatory"); + } } + if (font.getNaming() == null && !isEmbedded) { throw new IOException("name is mandatory"); } + if (font.getHorizontalMetrics() == null) { throw new IOException("hmtx is mandatory"); } - - // check others mandatory tables + if (!isEmbedded && font.getCmap() == null) { throw new IOException("cmap is mandatory"); diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType2.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType2.java index aec43290c85..0957ceaedc6 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType2.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType2.java @@ -29,7 +29,6 @@ import org.apache.fontbox.ttf.GlyphData; import org.apache.fontbox.ttf.OTFParser; import org.apache.fontbox.ttf.OpenTypeFont; -import org.apache.fontbox.ttf.TTFParser; import org.apache.fontbox.ttf.TrueTypeFont; import org.apache.fontbox.util.BoundingBox; import org.apache.pdfbox.cos.COSBase; @@ -93,48 +92,36 @@ public PDCIDFontType2(COSDictionary fontDictionary, PDType0Font parent, TrueType { boolean fontIsDamaged = false; TrueTypeFont ttfFont = null; - PDStream ff2Stream = fd.getFontFile2(); - PDStream ff3Stream = fd.getFontFile3(); - - // Acrobat looks in FontFile too, even though it is not in the spec, see PDFBOX-2599 - if (ff2Stream == null && ff3Stream == null) + + PDStream stream; + if (fd.getFontFile2() != null) { - ff2Stream = fd.getFontFile(); + stream = fd.getFontFile2(); } - - if (ff2Stream != null) + else if (fd.getFontFile3() != null) { - try - { - // embedded - TTFParser ttfParser = new TTFParser(true); - ttfFont = ttfParser.parse(ff2Stream.createInputStream()); - } - catch (NullPointerException e) // TTF parser is buggy - { - LOG.warn("Could not read embedded TTF for font " + getBaseFont(), e); - fontIsDamaged = true; - } - catch (IOException e) - { - LOG.warn("Could not read embedded TTF for font " + getBaseFont(), e); - fontIsDamaged = true; - } + stream = fd.getFontFile3(); } - else if (ff3Stream != null) + else + { + // Acrobat looks in FontFile too, even though it is not in the spec, see PDFBOX-2599 + stream = fd.getFontFile(); + } + + if (stream != null) { try { - // embedded + // embedded OTF or TTF OTFParser otfParser = new OTFParser(true); - OpenTypeFont otf = otfParser.parse(ff3Stream.createInputStream()); + OpenTypeFont otf = otfParser.parse(stream.createInputStream()); ttfFont = otf; if (otf.isPostScript()) { - // todo: we need more abstraction to support CFF fonts here - throw new IOException("Not implemented: OpenType font with CFF table " + - getBaseFont()); + // PDFBOX-3344 contains PostScript outlines instead of TrueType + fontIsDamaged = true; + LOG.warn("Found CFF/OTF but expected embedded TTF font " + fd.getFontName()); } if (otf.hasLayoutTables()) @@ -442,7 +429,9 @@ public GeneralPath getPath(int code) throws IOException { if (ttf instanceof OpenTypeFont && ((OpenTypeFont)ttf).isPostScript()) { - int cid = codeToCID(code); + // we're not supposed to have CFF fonts inside PDCIDFontType2, but if we do, + // then we treat their CIDs as GIDs, see PDFBOX-3344 + int cid = codeToGID(code); Type2CharString charstring = ((OpenTypeFont)ttf).getCFF().getFont().getType2CharString(cid); return charstring.getPath(); } From 1f5b42c4c4ca61f4bdcdd1d483f6c7ebe6d61ce1 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Wed, 29 Jun 2016 19:20:14 +0000 Subject: [PATCH 0182/2182] PDFBOX-2854: skip os2 and cmap tables if subset is empty git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1750696 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/fontbox/ttf/TTFSubsetter.java | 10 ++-- .../apache/fontbox/ttf/TTFSubsetterTest.java | 53 +++++++++++++++---- 2 files changed, 49 insertions(+), 14 deletions(-) diff --git a/fontbox/src/main/java/org/apache/fontbox/ttf/TTFSubsetter.java b/fontbox/src/main/java/org/apache/fontbox/ttf/TTFSubsetter.java index 33046fcaae9..657f08389f9 100755 --- a/fontbox/src/main/java/org/apache/fontbox/ttf/TTFSubsetter.java +++ b/fontbox/src/main/java/org/apache/fontbox/ttf/TTFSubsetter.java @@ -35,6 +35,8 @@ import java.util.SortedSet; import java.util.TreeMap; import java.util.TreeSet; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; /** * Subsetter for TrueType (TTF) fonts. @@ -46,6 +48,8 @@ */ public final class TTFSubsetter { + private static final Log LOG = LogFactory.getLog(TTFSubsetter.class); + private static final byte[] PAD_BUF = new byte[] { 0, 0, 0 }; private final TrueTypeFont ttf; @@ -396,7 +400,7 @@ private byte[] buildMaxpTable() throws IOException private byte[] buildOS2Table() throws IOException { OS2WindowsMetricsTable os2 = ttf.getOS2Windows(); - if (os2 == null || keepTables != null && !keepTables.contains("OS/2")) + if (os2 == null || uniToGID.isEmpty() || keepTables != null && !keepTables.contains("OS/2")) { return null; } @@ -682,7 +686,7 @@ private int getNewGlyphId(Integer oldGid) private byte[] buildCmapTable() throws IOException { - if (ttf.getCmap() == null || keepTables != null && !keepTables.contains("cmap")) + if (ttf.getCmap() == null || uniToGID.isEmpty() || keepTables != null && !keepTables.contains("cmap")) { return null; } @@ -947,7 +951,7 @@ public void writeToStream(OutputStream os) throws IOException { if (glyphIds.isEmpty() || uniToGID.isEmpty()) { - throw new IllegalStateException("subset is empty"); + LOG.info("font subset is empty"); } addCompoundReferences(); diff --git a/fontbox/src/test/java/org/apache/fontbox/ttf/TTFSubsetterTest.java b/fontbox/src/test/java/org/apache/fontbox/ttf/TTFSubsetterTest.java index 6d0c00c6afa..7e970445c2d 100644 --- a/fontbox/src/test/java/org/apache/fontbox/ttf/TTFSubsetterTest.java +++ b/fontbox/src/test/java/org/apache/fontbox/ttf/TTFSubsetterTest.java @@ -29,7 +29,6 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; -import static org.junit.Assert.fail; import org.junit.Test; /** @@ -40,7 +39,7 @@ public class TTFSubsetterTest { /** - * Test of PDFBOX-2854: empty subset. + * Test of PDFBOX-2854: empty subset with all tables. * * @throws java.io.IOException */ @@ -50,15 +49,47 @@ public void testEmptySubset() throws IOException final File testFile = new File("src/test/resources/ttf/LiberationSans-Regular.ttf"); TrueTypeFont x = new TTFParser().parse(testFile); TTFSubsetter ttfSubsetter = new TTFSubsetter(x); - try - { - ttfSubsetter.writeToStream(new ByteArrayOutputStream()); - fail("IllegalStateException should be thrown"); - } - catch (IllegalStateException e) - { - // ok - } + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ttfSubsetter.writeToStream(baos); + TrueTypeFont subset = new TTFParser(true).parse(new ByteArrayInputStream(baos.toByteArray())); + assertEquals(1, subset.getNumberOfGlyphs()); + assertEquals(0, subset.nameToGID(".notdef")); + assertNotNull(subset.getGlyph().getGlyph(0)); + subset.close(); + } + + /** + * Test of PDFBOX-2854: empty subset with selected tables. + * + * @throws java.io.IOException + */ + @Test + public void testEmptySubset2() throws IOException + { + final File testFile = new File("src/test/resources/ttf/LiberationSans-Regular.ttf"); + TrueTypeFont x = new TTFParser().parse(testFile); + // List copied from TrueTypeEmbedder.java + List tables = new ArrayList(); + tables.add("head"); + tables.add("hhea"); + tables.add("loca"); + tables.add("maxp"); + tables.add("cvt "); + tables.add("prep"); + tables.add("glyf"); + tables.add("hmtx"); + tables.add("fpgm"); + tables.add("gasp"); + TTFSubsetter ttfSubsetter = new TTFSubsetter(x, tables); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ttfSubsetter.writeToStream(baos); + TrueTypeFont subset = new TTFParser(true).parse(new ByteArrayInputStream(baos.toByteArray())); + assertEquals(1, subset.getNumberOfGlyphs()); + assertEquals(0, subset.nameToGID(".notdef")); + assertNotNull(subset.getGlyph().getGlyph(0)); + subset.close(); } /** From ce0cea1b8bc9fd195b695342de7b942602a62744 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Wed, 29 Jun 2016 21:21:51 +0000 Subject: [PATCH 0183/2182] PDFBOX-2854: avoid NPE for missing post table git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1750729 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/fontbox/ttf/TrueTypeFont.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/fontbox/src/main/java/org/apache/fontbox/ttf/TrueTypeFont.java b/fontbox/src/main/java/org/apache/fontbox/ttf/TrueTypeFont.java index 01349a6e17f..f8cc3966812 100644 --- a/fontbox/src/main/java/org/apache/fontbox/ttf/TrueTypeFont.java +++ b/fontbox/src/main/java/org/apache/fontbox/ttf/TrueTypeFont.java @@ -577,10 +577,13 @@ public int nameToGID(String name) throws IOException { // look up in 'post' table readPostScriptNames(); - Integer gid = postScriptNames.get(name); - if (gid != null && gid > 0 && gid < getMaximumProfile().getNumGlyphs()) + if (postScriptNames != null) { - return gid; + Integer gid = postScriptNames.get(name); + if (gid != null && gid > 0 && gid < getMaximumProfile().getNumGlyphs()) + { + return gid; + } } // look up in 'cmap' From 1236cbf0a6ee0ad49ac83fc2b7c83ef3f81d2962 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Thu, 30 Jun 2016 16:36:58 +0000 Subject: [PATCH 0184/2182] PDFBOX-2852: fix javadoc git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1750830 13f79535-47bb-0310-9956-ffa450edef68 --- fontbox/src/main/java/org/apache/fontbox/ttf/TrueTypeFont.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fontbox/src/main/java/org/apache/fontbox/ttf/TrueTypeFont.java b/fontbox/src/main/java/org/apache/fontbox/ttf/TrueTypeFont.java index f8cc3966812..037657f1806 100644 --- a/fontbox/src/main/java/org/apache/fontbox/ttf/TrueTypeFont.java +++ b/fontbox/src/main/java/org/apache/fontbox/ttf/TrueTypeFont.java @@ -106,7 +106,7 @@ public Map getTableMap() } /** - * Returns the war bytes of the given table. + * Returns the raw bytes of the given table. * @param table the table to read. * @throws IOException if there was an error accessing the table. */ From 6093c61957214b2bb5b7bbf930a96639ba86493f Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Thu, 30 Jun 2016 16:38:08 +0000 Subject: [PATCH 0185/2182] PDFBOX-2852: fix javadoc git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1750832 13f79535-47bb-0310-9956-ffa450edef68 --- fontbox/src/main/java/org/apache/fontbox/ttf/TrueTypeFont.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fontbox/src/main/java/org/apache/fontbox/ttf/TrueTypeFont.java b/fontbox/src/main/java/org/apache/fontbox/ttf/TrueTypeFont.java index 037657f1806..ab56196454a 100644 --- a/fontbox/src/main/java/org/apache/fontbox/ttf/TrueTypeFont.java +++ b/fontbox/src/main/java/org/apache/fontbox/ttf/TrueTypeFont.java @@ -380,7 +380,7 @@ void readTable(TTFTable table) throws IOException } /** - * Returns the number of glyphs (MaximuProfile.numGlyphs). + * Returns the number of glyphs (MaximumProfile.numGlyphs). * * @return the number of glyphs * @throws IOException if there was an error reading the table. From 7ec796e8e7f40fd1f4336f9838f76ea22e29d162 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Fri, 1 Jul 2016 05:15:33 +0000 Subject: [PATCH 0186/2182] PDFBOX-3405: clarify javadoc git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1750877 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/pdfbox/text/TextPosition.java | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/text/TextPosition.java b/pdfbox/src/main/java/org/apache/pdfbox/text/TextPosition.java index 5296304a2ba..ed19b428834 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/text/TextPosition.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/text/TextPosition.java @@ -110,7 +110,7 @@ private static Map createDiacritics() * @param pageRotation rotation of the page that the text is located in * @param pageWidth rotation of the page that the text is located in * @param pageHeight rotation of the page that the text is located in - * @param textMatrix TextMatrix for start of text (in display units) + * @param textMatrix text rendering matrix for start of text (in display units) * @param endX x coordinate of the end position * @param endY y coordinate of the end position * @param maxHeight Maximum height of text (in display units) @@ -179,7 +179,10 @@ public int[] getCharacterCodes() } /** - * Return the text matrix stored in this object. + * The matrix containing the starting text position and scaling. Despite the name, it is not the + * text matrix set by the "Tm" operator, it is really the effective text rendering matrix (which + * is dependent on the current transformation matrix, the text matrix, the font size and the + * page cropbox). * * @return The Matrix containing the starting text position */ @@ -403,7 +406,9 @@ public float getHeightDir() } /** - * This will get the font size that this object is suppose to be drawn at. + * This will get the font size that has been set with the "Tf" operator (Set text font and + * size). When the text is rendered, it may appear bigger or smaller depending on the current + * transformation matrix and the text matrix. * * @return The font size. */ @@ -413,8 +418,12 @@ public float getFontSize() } /** - * This will get the font size in pt. To get this size we have to multiply the pdf-fontsize - * and the scaling from the textmatrix + * This will get the font size in pt. To get this size we have to multiply the font size from + * {@link #getFontSize() getFontSize()} with the text matrix (set by the "Tm" operator) + * horizontal scaling factor and truncate the result to integer. The actual rendering may appear + * bigger or smaller depending on the current transformation matrix (set by the "cm" operator). + * To get the size in rendering, use + * {@link #getTextMatrix() getTextMatrix()}.{@link Matrix#getScalingFactorX() getScalingFactorX()}. * * @return The font size in pt. */ From 5ed78d87da7c6efca7632fec9ae7da2d0737bea0 Mon Sep 17 00:00:00 2001 From: Maruan Sahyoun Date: Fri, 1 Jul 2016 20:06:10 +0000 Subject: [PATCH 0187/2182] PDFBOX-3397: use UTF-8 when reading XML Metadata instead of ISO-8859-1 git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1751002 13f79535-47bb-0310-9956-ffa450edef68 --- .../pdfbox/debugger/streampane/Stream.java | 18 ++++++++++++++++++ .../pdfbox/debugger/streampane/StreamPane.java | 17 +++++++++++------ 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/debugger/src/main/java/org/apache/pdfbox/debugger/streampane/Stream.java b/debugger/src/main/java/org/apache/pdfbox/debugger/streampane/Stream.java index c6a295a21f7..e762c895970 100644 --- a/debugger/src/main/java/org/apache/pdfbox/debugger/streampane/Stream.java +++ b/debugger/src/main/java/org/apache/pdfbox/debugger/streampane/Stream.java @@ -45,6 +45,8 @@ public class Stream private final COSStream stream; private final boolean isThumb; private final boolean isImage; + private final boolean isXmlMetadata; + private final Map> filters; /** @@ -58,6 +60,7 @@ public class Stream this.stream = cosStream; this.isThumb = isThumb; this.isImage = isImageStream(cosStream, isThumb); + this.isXmlMetadata = isXmlMetadataStream(cosStream); filters = createFilterList(cosStream); } @@ -71,6 +74,16 @@ public boolean isImage() { return isImage; } + + /** + * Return if this is stream is an Metadata stream. + * + * @return true if this a metadata stream and false otherwise. + */ + public boolean isXmlMetadata() + { + return isXmlMetadata; + } /** * Return the available filter list. Only "Unfiltered" is returned if there is no filter and in @@ -229,4 +242,9 @@ private boolean isImageStream(COSDictionary dic, boolean isThumb) } return dic.containsKey(COSName.SUBTYPE) && dic.getCOSName(COSName.SUBTYPE).equals(COSName.IMAGE); } + + private boolean isXmlMetadataStream(COSDictionary dic) + { + return dic.containsKey(COSName.SUBTYPE) && dic.getCOSName(COSName.SUBTYPE).equals(COSName.getPDFName("XML")); + } } diff --git a/debugger/src/main/java/org/apache/pdfbox/debugger/streampane/StreamPane.java b/debugger/src/main/java/org/apache/pdfbox/debugger/streampane/StreamPane.java index fa2c0cf1edf..e92bc30bc16 100644 --- a/debugger/src/main/java/org/apache/pdfbox/debugger/streampane/StreamPane.java +++ b/debugger/src/main/java/org/apache/pdfbox/debugger/streampane/StreamPane.java @@ -250,8 +250,13 @@ private DocumentCreator(String filterKey) @Override protected StyledDocument doInBackground() { + // default encoding to use when reading text base content + String encoding = "ISO-8859-1"; synchronized (stream) { + if (stream.isXmlMetadata()) { + encoding = "UTF-8"; + } InputStream inputStream = stream.getStream(filterKey); if (isContentStream && Stream.UNFILTERED.equals(filterKey)) { @@ -260,9 +265,9 @@ protected StyledDocument doInBackground() { return document; } - return getDocument(stream.getStream(filterKey)); + return getDocument(stream.getStream(filterKey), encoding); } - return getDocument(inputStream); + return getDocument(inputStream, encoding); } } @@ -283,7 +288,7 @@ protected void done() } } - private String getStringOfStream(InputStream ioStream) + private String getStringOfStream(InputStream ioStream, String encoding) { ByteArrayOutputStream byteArray = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; @@ -301,7 +306,7 @@ private String getStringOfStream(InputStream ioStream) } try { - return byteArray.toString("ISO-8859-1"); + return byteArray.toString(encoding); } catch (UnsupportedEncodingException e) { @@ -310,12 +315,12 @@ private String getStringOfStream(InputStream ioStream) } } - private StyledDocument getDocument(InputStream inputStream) + private StyledDocument getDocument(InputStream inputStream, String encoding) { StyledDocument docu = new DefaultStyledDocument(); if (inputStream != null) { - String data = getStringOfStream(inputStream); + String data = getStringOfStream(inputStream, encoding); try { docu.insertString(0, data, null); From cbddfded1620bad0fd39835d62cbb8f130fccb56 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Sun, 3 Jul 2016 09:40:39 +0000 Subject: [PATCH 0188/2182] PDFBOX-3405: clarify javadoc git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1751135 13f79535-47bb-0310-9956-ffa450edef68 --- pdfbox/src/main/java/org/apache/pdfbox/text/TextPosition.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/text/TextPosition.java b/pdfbox/src/main/java/org/apache/pdfbox/text/TextPosition.java index ed19b428834..0a031f57d35 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/text/TextPosition.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/text/TextPosition.java @@ -422,8 +422,7 @@ public float getFontSize() * {@link #getFontSize() getFontSize()} with the text matrix (set by the "Tm" operator) * horizontal scaling factor and truncate the result to integer. The actual rendering may appear * bigger or smaller depending on the current transformation matrix (set by the "cm" operator). - * To get the size in rendering, use - * {@link #getTextMatrix() getTextMatrix()}.{@link Matrix#getScalingFactorX() getScalingFactorX()}. + * To get the size in rendering, use {@link #getXScale() getXScale()}. * * @return The font size in pt. */ From 2a1476cc8613e316701d8a0a08d5cf7092141083 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Sun, 3 Jul 2016 10:01:52 +0000 Subject: [PATCH 0189/2182] PDFBOX-3405: clarify javadoc git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1751143 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/pdfbox/text/TextPosition.java | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/text/TextPosition.java b/pdfbox/src/main/java/org/apache/pdfbox/text/TextPosition.java index 0a031f57d35..6831009f173 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/text/TextPosition.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/text/TextPosition.java @@ -120,7 +120,7 @@ private static Map createDiacritics() * @param charCodes An array of the internal PDF character codes for the glyphs in this text. * @param font The current font for this text position. * @param fontSize The new font size. - * @param fontSizeInPt The font size in pt units. + * @param fontSizeInPt The font size in pt units (see {@link #getFontSizeInPt()} for details). */ public TextPosition(int pageRotation, float pageWidth, float pageHeight, Matrix textMatrix, float endX, float endY, float maxHeight, float individualWidth, @@ -181,8 +181,8 @@ public int[] getCharacterCodes() /** * The matrix containing the starting text position and scaling. Despite the name, it is not the * text matrix set by the "Tm" operator, it is really the effective text rendering matrix (which - * is dependent on the current transformation matrix, the text matrix, the font size and the - * page cropbox). + * is dependent on the current transformation matrix (set by the "cm" operator), the text matrix + * (set by the "Tm" operator), the font size (set by the "Tf" operator) and the page cropbox). * * @return The Matrix containing the starting text position */ @@ -408,7 +408,8 @@ public float getHeightDir() /** * This will get the font size that has been set with the "Tf" operator (Set text font and * size). When the text is rendered, it may appear bigger or smaller depending on the current - * transformation matrix and the text matrix. + * transformation matrix (set by the "cm" operator) and the text matrix (set by the "Tm" + * operator). * * @return The font size. */ @@ -453,7 +454,11 @@ public float getWidthOfSpace() } /** - * @return Returns the xScale. + * This will get the X scaling factor. This is dependent on the current transformation matrix + * (set by the "cm" operator), the text matrix (set by the "Tm" operator) and the font size (set + * by the "Tf" operator). + * + * @return The X scaling factor. */ public float getXScale() { @@ -461,7 +466,11 @@ public float getXScale() } /** - * @return Returns the yScale. + * This will get the Y scaling factor. This is dependent on the current transformation matrix + * (set by the "cm" operator), the text matrix (set by the "Tm" operator) and the font size (set + * by the "Tf" operator). + * + * @return The Y scaling factor. */ public float getYScale() { From 1f669f0980992575f8582079a5a9fda64ca77c38 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Sun, 3 Jul 2016 10:42:18 +0000 Subject: [PATCH 0190/2182] PDFBOX-2852: remove option that doesn't exist in 2.* git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1751144 13f79535-47bb-0310-9956-ffa450edef68 --- tools/src/main/java/org/apache/pdfbox/tools/PDFToImage.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/src/main/java/org/apache/pdfbox/tools/PDFToImage.java b/tools/src/main/java/org/apache/pdfbox/tools/PDFToImage.java index 17533a493b1..4d111343d1a 100644 --- a/tools/src/main/java/org/apache/pdfbox/tools/PDFToImage.java +++ b/tools/src/main/java/org/apache/pdfbox/tools/PDFToImage.java @@ -278,7 +278,7 @@ private static void usage() + " -page : The only page to extract (1-based)\n" + " -startPage : The first page to start extraction (1-based)\n" + " -endPage : The last page to extract(inclusive)\n" - + " -color : The color depth (valid: bilevel, indexed, gray, rgb, rgba)\n" + + " -color : The color depth (valid: bilevel, gray, rgb, rgba)\n" + " -dpi : The DPI of the output image\n" + " -cropbox : The page area to export\n" + " -time : Prints timing information to stdout\n" From 4ffc592b879aecf82b244d3b351b7c4299773e11 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Sun, 3 Jul 2016 12:27:50 +0000 Subject: [PATCH 0191/2182] PDFBOX-3408: Correct validation of Btn widget annotations for PDF/A-1 git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1751153 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/pdfbox/cos/COSName.java | 1 + .../annotation/AnnotationValidator.java | 61 +++++++++++++++---- .../src/test/resources/expected_errors.txt | 4 +- 3 files changed, 54 insertions(+), 12 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java b/pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java index f5b5d0472b6..765e9e3c930 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java @@ -539,6 +539,7 @@ public final class COSName extends COSBase implements Comparable public static final COSName W = new COSName("W"); public static final COSName W2 = new COSName("W2"); public static final COSName WHITE_POINT = new COSName("WhitePoint"); + public static final COSName WIDGET = new COSName("Widget"); public static final COSName WIDTH = new COSName("Width"); public static final COSName WIDTHS = new COSName("Widths"); public static final COSName WIN_ANSI_ENCODING = new COSName("WinAnsiEncoding"); diff --git a/preflight/src/main/java/org/apache/pdfbox/preflight/annotation/AnnotationValidator.java b/preflight/src/main/java/org/apache/pdfbox/preflight/annotation/AnnotationValidator.java index f3363373321..b4152a307dd 100644 --- a/preflight/src/main/java/org/apache/pdfbox/preflight/annotation/AnnotationValidator.java +++ b/preflight/src/main/java/org/apache/pdfbox/preflight/annotation/AnnotationValidator.java @@ -126,6 +126,7 @@ protected boolean checkCA() * DestOutputProfile of the OutputIntent dictionary. * * @return true if the C field is present and the RGB profile is used. + * @throws org.apache.pdfbox.preflight.exception.ValidationException */ protected boolean checkColors() throws ValidationException { @@ -142,6 +143,7 @@ protected boolean checkColors() throws ValidationException * Search the RGB Profile in OutputIntents dictionaries * * @return true if a rgb profile is found, false otherwise. + * @throws org.apache.pdfbox.preflight.exception.ValidationException */ protected boolean searchRGBProfile() throws ValidationException { @@ -162,6 +164,7 @@ protected boolean searchRGBProfile() throws ValidationException * If the AP content isn't valid, this method return false and updates the errors list. * * @return the validation state of the AP content. + * @throws org.apache.pdfbox.preflight.exception.ValidationException */ protected boolean checkAP() throws ValidationException { @@ -185,21 +188,57 @@ else if (apDict.getItem(COSName.N) == null) } else { - // the N entry must be a Stream (Dictionaries are forbidden) COSBase apn = apDict.getItem(COSName.N); - if (!COSUtils.isStream(apn, cosDocument)) + COSBase subtype = annotDictionary.getItem(COSName.SUBTYPE); + COSBase ft = annotDictionary.getItem(COSName.FT); + if (COSName.WIDGET.equals(subtype) && COSName.BTN.equals(ft)) { - ctx.addValidationError(new ValidationError(ERROR_ANNOT_INVALID_AP_CONTENT, - "The N Appearance must be a Stream")); - return false; + // TECHNICAL CORRIGENDUM 2 for ISO 19005-1:2005 (PDF/A-1) + // added a clause for Widget Annotations: + // the value of the N key shall be an appearance subdictionary + if (COSUtils.isStream(apn, cosDocument)) + { + ctx.addValidationError(new ValidationError(ERROR_ANNOT_INVALID_AP_CONTENT, + "The N Appearance of a Btn widget must not be a stream, but an appearance subdictionary")); + // But validate it anyway, for isartor-6-3-4-t01-fail-f.pdf + // Appearance stream is a XObjectForm, check it. + ContextHelper.validateElement(ctx, new PDFormXObject( + COSUtils.getAsStream(apn, cosDocument)), + GRAPHIC_PROCESS); + return false; + } + if (!COSUtils.isDictionary(apn, cosDocument)) + { + ctx.addValidationError(new ValidationError(ERROR_ANNOT_INVALID_AP_CONTENT, + "The N Appearance must be an appearance subdictionary")); + return false; + } + COSDictionary apnDict = COSUtils.getAsDictionary(apn, cosDocument); + for (COSBase val : apnDict.getValues()) + { + // Appearance stream is a XObjectForm, check it. + ContextHelper.validateElement(ctx, new PDFormXObject( + COSUtils.getAsStream(val, cosDocument)), + GRAPHIC_PROCESS); + } + } + else + { + // the N entry must be a stream (Dictionaries are forbidden) + if (!COSUtils.isStream(apn, cosDocument)) + { + ctx.addValidationError(new ValidationError(ERROR_ANNOT_INVALID_AP_CONTENT, + "The N Appearance must be a Stream")); + return false; + } + // Appearance stream is a XObjectForm, check it. + ContextHelper.validateElement(ctx, new PDFormXObject( + COSUtils.getAsStream(apn, cosDocument)), + GRAPHIC_PROCESS); } - - // Appearance stream is a XObjectForm, check it. - ContextHelper.validateElement(ctx, new PDFormXObject( - COSUtils.getAsStream(apn, cosDocument)), - GRAPHIC_PROCESS); } - } // else ok, nothing to check,this field is optional + } + // else ok, nothing to check, this field is optional return true; } diff --git a/preflight/src/test/resources/expected_errors.txt b/preflight/src/test/resources/expected_errors.txt index eabb69eac1f..6023742e852 100644 --- a/preflight/src/test/resources/expected_errors.txt +++ b/preflight/src/test/resources/expected_errors.txt @@ -110,7 +110,9 @@ isartor-6-3-4-t01-fail-b.pdf=3.1.3 isartor-6-3-4-t01-fail-c.pdf=3.1.3 isartor-6-3-4-t01-fail-d.pdf=3.1.3 isartor-6-3-4-t01-fail-e.pdf=3.1.3 -isartor-6-3-4-t01-fail-f.pdf=3.1.3 +# 5.3.1 check is not part of isartor, but N Appearance of a Btn widget must not be a stream, but an appearance subdictionary, see PDFBOX-3408 +# PDFTools validator agrees: "The appearance must have state dictionaries (subdictionaries to 'N')" +isartor-6-3-4-t01-fail-f.pdf=3.1.3,5.3.1 isartor-6-3-4-t01-fail-g.pdf=3.2.4 // Type3 Damage because the Type1 used as Resource isn't embedded isartor-6-3-4-t01-fail-h.pdf=3.1.3 isartor-6-3-5-t01-fail-a.pdf=3.3.1 From 50a08c40b98a41478738c1f26c2467ff6cfd7af4 Mon Sep 17 00:00:00 2001 From: Maruan Sahyoun Date: Mon, 4 Jul 2016 06:36:16 +0000 Subject: [PATCH 0192/2182] PDFBOX-3396: don't add a transformation if there is a XObject git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1751214 13f79535-47bb-0310-9956-ffa450edef68 --- .../pdmodel/interactive/form/PDAcroForm.java | 38 +++++++++++++++++-- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDAcroForm.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDAcroForm.java index 6dc0045b4af..d29a3803212 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDAcroForm.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDAcroForm.java @@ -45,6 +45,7 @@ import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject; import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotation; import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationWidget; +import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceStream; import org.apache.pdfbox.util.Matrix; /** @@ -248,7 +249,7 @@ public void flatten(List fields, boolean refreshAppearances) throws IOE if (!isContentStreamWrapped) { - contentStream = new PDPageContentStream(document, page, AppendMode.APPEND, true, true); + contentStream = new PDPageContentStream(document, page, AppendMode.APPEND, true); isContentStreamWrapped = true; } else @@ -256,11 +257,22 @@ public void flatten(List fields, boolean refreshAppearances) throws IOE contentStream = new PDPageContentStream(document, page, AppendMode.APPEND, true); } - PDFormXObject fieldObject = new PDFormXObject(widget.getNormalAppearanceStream().getCOSObject()); + PDAppearanceStream appearanceStream = widget.getNormalAppearanceStream(); + + PDFormXObject fieldObject = new PDFormXObject(appearanceStream.getCOSObject()); - Matrix translationMatrix = Matrix.getTranslateInstance(widget.getRectangle().getLowerLeftX(), widget.getRectangle().getLowerLeftY()); contentStream.saveGraphicsState(); - contentStream.transform(translationMatrix); + + // translate the appearance stream to the widget location if there is + // not already a transformation in place + boolean needsTransformation = isNeedsTransformation(appearanceStream); + if (needsTransformation) + { + Matrix translationMatrix = Matrix.getTranslateInstance(widget.getRectangle().getLowerLeftX(), + widget.getRectangle().getLowerLeftY()); + contentStream.transform(translationMatrix); + } + contentStream.drawForm(fieldObject); contentStream.restoreGraphicsState(); contentStream.close(); @@ -652,4 +664,22 @@ private Map buildAnnotationToPageRef() { } return annotationToPageRef; } + + /** + * Check if there is a transformation needed to place the annotations content. + * + * @param appearanceStream + * @return the need for a transformation. + */ + private boolean isNeedsTransformation(PDAppearanceStream appearanceStream) + { + // Check if there is a XObject defined as this is an indication that there should already be a transformation + // in place. + // TODO: A more reliable approach might be to parse the content stream + if (appearanceStream.getResources() != null && appearanceStream.getResources().getXObjectNames().iterator().hasNext()) + { + return false; + } + return true; + } } From cf30435b36c7c9ffc17d166ef562bc8d0fd64b1c Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Mon, 4 Jul 2016 16:04:21 +0000 Subject: [PATCH 0193/2182] PDFBOX-3408: Go up the hierarchy to get the type git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1751328 13f79535-47bb-0310-9956-ffa450edef68 --- .../annotation/AnnotationValidator.java | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/preflight/src/main/java/org/apache/pdfbox/preflight/annotation/AnnotationValidator.java b/preflight/src/main/java/org/apache/pdfbox/preflight/annotation/AnnotationValidator.java index b4152a307dd..3e1cf8fe7fe 100644 --- a/preflight/src/main/java/org/apache/pdfbox/preflight/annotation/AnnotationValidator.java +++ b/preflight/src/main/java/org/apache/pdfbox/preflight/annotation/AnnotationValidator.java @@ -190,7 +190,7 @@ else if (apDict.getItem(COSName.N) == null) { COSBase apn = apDict.getItem(COSName.N); COSBase subtype = annotDictionary.getItem(COSName.SUBTYPE); - COSBase ft = annotDictionary.getItem(COSName.FT); + COSBase ft = getFieldType(); if (COSName.WIDGET.equals(subtype) && COSName.BTN.equals(ft)) { // TECHNICAL CORRIGENDUM 2 for ISO 19005-1:2005 (PDF/A-1) @@ -339,4 +339,25 @@ public final void setFactory(AnnotationValidatorFactory fact) { this.annotFact = fact; } + + private COSBase getFieldType() + { + COSBase ft = annotDictionary.getDictionaryObject(COSName.FT); + COSDictionary parent = annotDictionary; + while (ft == null) + { + // /FT could be in parent, so look upwards + COSBase parentBase = parent.getDictionaryObject(COSName.PARENT); + if (parentBase instanceof COSDictionary) + { + parent = (COSDictionary) parentBase; + ft = parent.getDictionaryObject(COSName.FT); + } + else + { + break; + } + } + return ft; + } } From f0a2615d396559014075372023c27866b5b95772 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Mon, 4 Jul 2016 16:46:34 +0000 Subject: [PATCH 0194/2182] PDFBOX-3410: added landscape option, as wished by Marc Stuart PDFBOX-3409: don't drop leading spaces, and handle formfeed as wished by Marc Stuart git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1751339 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/pdfbox/tools/TextToPDF.java | 101 ++++++++++++++++-- 1 file changed, 93 insertions(+), 8 deletions(-) diff --git a/tools/src/main/java/org/apache/pdfbox/tools/TextToPDF.java b/tools/src/main/java/org/apache/pdfbox/tools/TextToPDF.java index a63f47dd1f4..df3dcef2c03 100644 --- a/tools/src/main/java/org/apache/pdfbox/tools/TextToPDF.java +++ b/tools/src/main/java/org/apache/pdfbox/tools/TextToPDF.java @@ -28,6 +28,7 @@ import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.PDPageContentStream; +import org.apache.pdfbox.pdmodel.common.PDRectangle; import org.apache.pdfbox.pdmodel.font.PDFont; import org.apache.pdfbox.pdmodel.font.PDType0Font; import org.apache.pdfbox.pdmodel.font.PDType1Font; @@ -60,6 +61,7 @@ public class TextToPDF private static final float LINE_HEIGHT_FACTOR = 1.05f; private int fontSize = DEFAULT_FONT_SIZE; + private boolean landscape = false; private PDFont font = DEFAULT_FONT; private static final Map STANDARD_14 = new HashMap(); @@ -111,12 +113,17 @@ public void createPDFFromText( PDDocument doc, Reader text ) throws IOException final int margin = 40; float height = font.getBoundingBox().getHeight() / FONTSCALE; + PDRectangle mediaBox = PDRectangle.LETTER; + if (landscape) + { + mediaBox = new PDRectangle(mediaBox.getHeight(), mediaBox.getWidth()); + } //calculate font height and increase by a factor. height = height*fontSize*LINE_HEIGHT_FACTOR; BufferedReader data = new BufferedReader( text ); String nextLine = null; - PDPage page = new PDPage(); + PDPage page = new PDPage(mediaBox); PDPageContentStream contentStream = null; float y = -1; float maxStringLength = page.getMediaBox().getWidth() - 2*margin; @@ -132,20 +139,61 @@ public void createPDFFromText( PDDocument doc, Reader text ) throws IOException // the text. textIsEmpty = false; - String[] lineWords = nextLine.trim().split( " " ); + String[] lineWords = nextLine.replaceAll("[\\n\\r]+$", "").split(" "); int lineIndex = 0; while( lineIndex < lineWords.length ) { StringBuilder nextLineToDraw = new StringBuilder(); float lengthIfUsingNextWord = 0; + boolean ff = false; do { - nextLineToDraw.append( lineWords[lineIndex] ); - nextLineToDraw.append( " " ); - lineIndex++; + String word1, word2 = ""; + int indexFF = lineWords[lineIndex].indexOf('\f'); + if (indexFF == -1) + { + word1 = lineWords[lineIndex]; + } + else + { + ff = true; + word1 = lineWords[lineIndex].substring(0, indexFF); + if (indexFF < lineWords[lineIndex].length()) + { + word2 = lineWords[lineIndex].substring(indexFF + 1); + } + } + // word1 is the part before ff, word2 after + // both can be empty + // word1 can also be empty without ff, if a line has many spaces + if (word1.length() > 0 || !ff) + { + nextLineToDraw.append(word1); + nextLineToDraw.append(" "); + } + if (!ff || word2.length() == 0) + { + lineIndex++; + } + else + { + lineWords[lineIndex] = word2; + } + if (ff) + { + break; + } if( lineIndex < lineWords.length ) { - String lineWithNextWord = nextLineToDraw.toString() + lineWords[lineIndex]; + // need cut off at \f in next word to avoid IllegalArgumentException + String nextWord = lineWords[lineIndex]; + indexFF = nextWord.indexOf('\f'); + if (indexFF != -1) + { + nextWord = nextWord.substring(0, indexFF); + } + + String lineWithNextWord = nextLineToDraw.toString() + " " + nextWord; lengthIfUsingNextWord = (font.getStringWidth( lineWithNextWord )/FONTSCALE) * fontSize; } @@ -156,7 +204,7 @@ public void createPDFFromText( PDDocument doc, Reader text ) throws IOException { // We have crossed the end-of-page boundary and need to extend the // document by another page. - page = new PDPage(); + page = new PDPage(mediaBox); doc.addPage( page ); if( contentStream != null ) { @@ -179,6 +227,18 @@ public void createPDFFromText( PDDocument doc, Reader text ) throws IOException contentStream.newLineAtOffset(0, -height); y -= height; contentStream.showText(nextLineToDraw.toString()); + if (ff) + { + page = new PDPage(mediaBox); + doc.addPage(page); + contentStream.endText(); + contentStream.close(); + contentStream = new PDPageContentStream(doc, page); + contentStream.setFont(font, fontSize); + contentStream.beginText(); + y = page.getMediaBox().getHeight() - margin + height; + contentStream.newLineAtOffset(margin, y); + } } @@ -251,6 +311,10 @@ else if( args[i].equals( "-fontSize" )) i++; app.setFontSize( Integer.parseInt( args[i] ) ); } + else if( args[i].equals( "-landscape" )) + { + app.setLandscape(true); + } else { throw new IOException( "Unknown argument:" + args[i] ); @@ -278,13 +342,14 @@ private void usage() message.append("Usage: jar -jar pdfbox-app-x.y.z.jar TextToPDF [options] \n"); message.append("\nOptions:\n"); message.append(" -standardFont : " + DEFAULT_FONT.getBaseFont() + " (default)\n"); - + for (String std14String : std14) { message.append(" " + std14String + "\n"); } message.append(" -ttf : The TTF font to use.\n"); message.append(" -fontSize : default: " + DEFAULT_FONT_SIZE ); + message.append(" -landscape : sets orientation to landscape" ); System.err.println(message.toString()); System.exit(1); @@ -342,4 +407,24 @@ public void setFontSize(int aFontSize) { this.fontSize = aFontSize; } + + /** + * Tells the paper orientation. + * + * @return + */ + public boolean isLandscape() + { + return landscape; + } + + /** + * Sets paper orientation. + * + * @param landscape + */ + public void setLandscape(boolean landscape) + { + this.landscape = landscape; + } } From a1c3fc894936e751a168e4a109605eb16acf5395 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Mon, 4 Jul 2016 17:58:26 +0000 Subject: [PATCH 0195/2182] PDFBOX-3377: exclude fonts.alias.ttf git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1751358 13f79535-47bb-0310-9956-ffa450edef68 --- .../fontbox/util/autodetect/FontFileFinder.java | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/fontbox/src/main/java/org/apache/fontbox/util/autodetect/FontFileFinder.java b/fontbox/src/main/java/org/apache/fontbox/util/autodetect/FontFileFinder.java index de92a571683..765e93cd42e 100644 --- a/fontbox/src/main/java/org/apache/fontbox/util/autodetect/FontFileFinder.java +++ b/fontbox/src/main/java/org/apache/fontbox/util/autodetect/FontFileFinder.java @@ -20,6 +20,8 @@ import java.io.File; import java.net.URI; import java.util.List; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; /** * Helps to autodetect/locate available operating system fonts. This class is based on a class provided by Apache FOP. @@ -27,6 +29,7 @@ */ public class FontFileFinder { + private static final Log LOG = LogFactory.getLog(FontFileFinder.class); private FontDirFinder fontDirFinder = null; @@ -123,8 +126,16 @@ private void walk(File directory, List results) } else { + if (LOG.isDebugEnabled()) + { + LOG.debug("checkFontfile check " + file); + } if (checkFontfile(file)) { + if (LOG.isDebugEnabled()) + { + LOG.debug("checkFontfile found " + file); + } results.add(file.toURI()); } } @@ -142,6 +153,8 @@ private void walk(File directory, List results) private boolean checkFontfile(File file) { String name = file.getName().toLowerCase(); - return name.endsWith(".ttf") || name.endsWith(".otf") || name.endsWith(".pfb") || name.endsWith(".ttc"); + return (name.endsWith(".ttf") || name.endsWith(".otf") || name.endsWith(".pfb") || name.endsWith(".ttc")) + // PDFBOX-3377 exclude weird file in AIX + && !name.equals("fonts.alias.ttf"); } } From af7e75893bf438a9d16b9c1cdb8b7c4344921d39 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Mon, 4 Jul 2016 18:14:31 +0000 Subject: [PATCH 0196/2182] PDFBOX-3377: exclude fonts.* git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1751365 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/fontbox/util/autodetect/FontFileFinder.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fontbox/src/main/java/org/apache/fontbox/util/autodetect/FontFileFinder.java b/fontbox/src/main/java/org/apache/fontbox/util/autodetect/FontFileFinder.java index 765e93cd42e..9d39ea480cf 100644 --- a/fontbox/src/main/java/org/apache/fontbox/util/autodetect/FontFileFinder.java +++ b/fontbox/src/main/java/org/apache/fontbox/util/autodetect/FontFileFinder.java @@ -154,7 +154,7 @@ private boolean checkFontfile(File file) { String name = file.getName().toLowerCase(); return (name.endsWith(".ttf") || name.endsWith(".otf") || name.endsWith(".pfb") || name.endsWith(".ttc")) - // PDFBOX-3377 exclude weird file in AIX - && !name.equals("fonts.alias.ttf"); + // PDFBOX-3377 exclude weird files in AIX + && !name.startsWith("fonts."); } } From a0bd54481692ddb3a8221e08d5bb6d10dc25f57c Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Tue, 5 Jul 2016 19:22:03 +0000 Subject: [PATCH 0197/2182] PDFBOX-3411: fix embedding of non subsetted font git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1751540 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/pdfbox/pdmodel/font/TrueTypeEmbedder.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/TrueTypeEmbedder.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/TrueTypeEmbedder.java index 9a12abe3983..1fd2a92bbf7 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/TrueTypeEmbedder.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/TrueTypeEmbedder.java @@ -87,6 +87,10 @@ abstract class TrueTypeEmbedder implements Subsetter this.ttf = ttf; fontDescriptor = createFontDescriptor(ttf); + PDStream stream = new PDStream(document, ttf.getOriginalData(), COSName.FLATE_DECODE); + stream.getCOSObject().setInt(COSName.LENGTH1, stream.toByteArray().length); + fontDescriptor.setFontFile2(stream); + dict.setName(COSName.BASE_FONT, ttf.getName()); // choose a Unicode "cmap" From 7ba8bc63d6fd5ec14bf8f52698e393d40c44295b Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Wed, 6 Jul 2016 05:45:04 +0000 Subject: [PATCH 0198/2182] PDFBOX-3403: revert 1750562 for lack of consensus git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1751602 13f79535-47bb-0310-9956-ffa450edef68 --- .../pdfbox/pdmodel/font/PDSimpleFont.java | 4 -- .../font/encoding/DictionaryEncoding.java | 37 ++++++------------- 2 files changed, 12 insertions(+), 29 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDSimpleFont.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDSimpleFont.java index 9ddae0a5aa9..72ff98ce325 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDSimpleFont.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDSimpleFont.java @@ -366,10 +366,6 @@ public boolean isStandard14() // we also require that the differences are actually different, see PDFBOX-1900 with // the file from PDFBOX-2192 on Windows Encoding baseEncoding = dictionary.getBaseEncoding(); - if (baseEncoding == null) - { - return false; - } for (Map.Entry entry : dictionary.getDifferences().entrySet()) { if (!entry.getValue().equals(baseEncoding.getName(entry.getKey()))) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/DictionaryEncoding.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/DictionaryEncoding.java index 835d263fa5b..1f3d54c84d8 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/DictionaryEncoding.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/DictionaryEncoding.java @@ -19,8 +19,6 @@ import java.util.HashMap; import java.util.Map; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; @@ -34,7 +32,6 @@ */ public class DictionaryEncoding extends Encoding { - private static final Log LOG = LogFactory.getLog(DictionaryEncoding.class); private final COSDictionary encoding; private final Encoding baseEncoding; private final Map differences = new HashMap(); @@ -62,14 +59,11 @@ public DictionaryEncoding(COSName baseEncoding, COSArray differences) if (this.baseEncoding == null) { - LOG.error("Invalid encoding: " + baseEncoding); + throw new IllegalArgumentException("Invalid encoding: " + baseEncoding); } - if (this.baseEncoding != null) - { - codeToName.putAll(this.baseEncoding.codeToName); - inverted.putAll(this.baseEncoding.inverted); - } + codeToName.putAll(this.baseEncoding.codeToName); + inverted.putAll(this.baseEncoding.inverted); applyDifferences(); } @@ -100,7 +94,7 @@ public DictionaryEncoding(COSDictionary fontEncoding, boolean isNonSymbolic, Enc if (encoding.containsKey(COSName.BASE_ENCODING)) { COSName name = encoding.getCOSName(COSName.BASE_ENCODING); - base = Encoding.getInstance(name); + base = Encoding.getInstance(name); // may be null } if (base == null) @@ -119,33 +113,26 @@ public DictionaryEncoding(COSDictionary fontEncoding, boolean isNonSymbolic, Enc } else { - LOG.error("Symbolic fonts must have a built-in encoding"); + throw new IllegalArgumentException("Symbolic fonts must have a built-in " + + "encoding"); } } } baseEncoding = base; - if (baseEncoding != null) - { - codeToName.putAll(baseEncoding.codeToName); - inverted.putAll(baseEncoding.inverted); - } + codeToName.putAll(baseEncoding.codeToName); + inverted.putAll(baseEncoding.inverted); applyDifferences(); } private void applyDifferences() { // now replace with the differences - COSBase base = encoding.getDictionaryObject(COSName.DIFFERENCES); - if (!(base instanceof COSArray)) - { - return; - } - COSArray diffArray = (COSArray) base; + COSArray differences = (COSArray)encoding.getDictionaryObject( COSName.DIFFERENCES ); int currentIndex = -1; - for (int i = 0; i < diffArray.size(); i++) + for( int i=0; differences != null && i Date: Wed, 6 Jul 2016 17:52:44 +0000 Subject: [PATCH 0199/2182] PDFBOX-3403: Sonar fixes git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1751718 13f79535-47bb-0310-9956-ffa450edef68 --- .../pdmodel/font/encoding/DictionaryEncoding.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/DictionaryEncoding.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/DictionaryEncoding.java index 1f3d54c84d8..2c1ecf8ecc1 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/DictionaryEncoding.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/DictionaryEncoding.java @@ -128,11 +128,16 @@ public DictionaryEncoding(COSDictionary fontEncoding, boolean isNonSymbolic, Enc private void applyDifferences() { // now replace with the differences - COSArray differences = (COSArray)encoding.getDictionaryObject( COSName.DIFFERENCES ); + COSBase base = encoding.getDictionaryObject(COSName.DIFFERENCES); + if (!(base instanceof COSArray)) + { + return; + } + COSArray diffArray = (COSArray) base; int currentIndex = -1; - for( int i=0; differences != null && i Date: Thu, 7 Jul 2016 18:29:20 +0000 Subject: [PATCH 0200/2182] PDFBOX-3404: drop concurrent HashSet, synchronize initialization instead git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1751824 13f79535-47bb-0310-9956-ffa450edef68 --- .../pdfbox/pdmodel/font/encoding/Encoding.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/Encoding.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/Encoding.java index 825178714e9..ef027503aa9 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/Encoding.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/Encoding.java @@ -18,9 +18,9 @@ import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.pdmodel.common.COSObjectable; @@ -109,8 +109,15 @@ public boolean contains(String name) // otherwise /Differences won't be accounted for if (names == null) { - names = Collections.newSetFromMap(new ConcurrentHashMap()); - names.addAll(codeToName.values()); + synchronized(this) + { + // PDFBOX-3404: avoid possibility that one thread ends up with newly created empty map from other thread + Set tmpSet = new HashSet(codeToName.values()); + // make sure that assignment is done after initialisation is complete + names = tmpSet; + // note that it might still happen that 'names' is initialized twice, but this is harmless + } + // at this point, names will never be null. } return names.contains(name); } From 045ca5b2be44f4e9fb9d31753fdf7f153cc788e3 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Thu, 7 Jul 2016 21:24:51 +0000 Subject: [PATCH 0201/2182] PDFBOX-3298: added encoding for ZapfDingbats git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1751834 13f79535-47bb-0310-9956-ffa450edef68 --- .../pdfbox/pdmodel/font/PDType1Font.java | 13 +- .../font/encoding/ZapfDingbatsEncoding.java | 252 ++++++++++++++++++ 2 files changed, 263 insertions(+), 2 deletions(-) create mode 100644 pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/ZapfDingbatsEncoding.java diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1Font.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1Font.java index 1db70a26923..fac4022e22c 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1Font.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1Font.java @@ -47,6 +47,7 @@ import static org.apache.pdfbox.pdmodel.font.UniUtil.getUniNameOfCodePoint; import org.apache.pdfbox.pdmodel.font.encoding.WinAnsiEncoding; +import org.apache.pdfbox.pdmodel.font.encoding.ZapfDingbatsEncoding; /** * A PostScript Type 1 Font. @@ -121,8 +122,16 @@ private PDType1Font(String baseFont) dict.setItem(COSName.SUBTYPE, COSName.TYPE1); dict.setName(COSName.BASE_FONT, baseFont); - encoding = WinAnsiEncoding.INSTANCE; - dict.setItem(COSName.ENCODING, COSName.WIN_ANSI_ENCODING); + if ("ZapfDingbats".equals(baseFont)) + { + encoding = ZapfDingbatsEncoding.INSTANCE; + } + else + { + encoding = WinAnsiEncoding.INSTANCE; + dict.setItem(COSName.ENCODING, COSName.WIN_ANSI_ENCODING); + } + // standard 14 fonts may be accessed concurrently, as they are singletons codeToBytesMap = new ConcurrentHashMap(); diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/ZapfDingbatsEncoding.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/ZapfDingbatsEncoding.java new file mode 100644 index 00000000000..d7ec2953a4b --- /dev/null +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/ZapfDingbatsEncoding.java @@ -0,0 +1,252 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.pdfbox.pdmodel.font.encoding; + +import org.apache.pdfbox.cos.COSBase; +import org.apache.pdfbox.cos.COSName; + +/** + * This is an interface to a text encoder. + */ +public class ZapfDingbatsEncoding extends Encoding +{ + + private static final int CHAR_CODE = 0; + private static final int CHAR_NAME = 1; + + /** + * Table of octal character codes and their corresponding names. + */ + private static final Object[][] ZAPFDINGBATS_ENCODING_TABLE = { + {040, "space"}, + {041, "a1"}, + {042, "a2"}, + {043, "a202"}, + {044, "a3"}, + {045, "a4"}, + {046, "a5"}, + {047, "a119"}, + {050, "a118"}, + {051, "a117"}, + {052, "a11"}, + {053, "a12"}, + {054, "a13"}, + {055, "a14"}, + {056, "a15"}, + {057, "a16"}, + {060, "a105"}, + {061, "a17"}, + {062, "a18"}, + {063, "a19"}, + {064, "a20"}, + {065, "a21"}, + {066, "a22"}, + {067, "a23"}, + {070, "a24"}, + {071, "a25"}, + {072, "a26"}, + {073, "a27"}, + {074, "a28"}, + {075, "a6"}, + {076, "a7"}, + {077, "a8"}, + {0100, "a9"}, + {0101, "a10"}, + {0102, "a29"}, + {0103, "a30"}, + {0104, "a31"}, + {0105, "a32"}, + {0106, "a33"}, + {0107, "a34"}, + {0110, "a35"}, + {0111, "a36"}, + {0112, "a37"}, + {0113, "a38"}, + {0114, "a39"}, + {0115, "a40"}, + {0116, "a41"}, + {0117, "a42"}, + {0120, "a43"}, + {0121, "a44"}, + {0122, "a45"}, + {0123, "a46"}, + {0124, "a47"}, + {0125, "a48"}, + {0126, "a49"}, + {0127, "a50"}, + {0130, "a51"}, + {0131, "a52"}, + {0132, "a53"}, + {0133, "a54"}, + {0134, "a55"}, + {0135, "a56"}, + {0136, "a57"}, + {0137, "a58"}, + {0140, "a59"}, + {0141, "a60"}, + {0142, "a61"}, + {0143, "a62"}, + {0144, "a63"}, + {0145, "a64"}, + {0146, "a65"}, + {0147, "a66"}, + {0150, "a67"}, + {0151, "a68"}, + {0152, "a69"}, + {0153, "a70"}, + {0154, "a71"}, + {0155, "a72"}, + {0156, "a73"}, + {0157, "a74"}, + {0160, "a203"}, + {0161, "a75"}, + {0162, "a204"}, + {0163, "a76"}, + {0164, "a77"}, + {0165, "a78"}, + {0166, "a79"}, + {0167, "a81"}, + {0170, "a82"}, + {0171, "a83"}, + {0172, "a84"}, + {0173, "a97"}, + {0174, "a98"}, + {0175, "a99"}, + {0176, "a100"}, + {0241, "a101"}, + {0242, "a102"}, + {0243, "a103"}, + {0244, "a104"}, + {0245, "a106"}, + {0246, "a107"}, + {0247, "a108"}, + {0250, "a112"}, + {0251, "a111"}, + {0252, "a110"}, + {0253, "a109"}, + {0254, "a120"}, + {0255, "a121"}, + {0256, "a122"}, + {0257, "a123"}, + {0260, "a124"}, + {0261, "a125"}, + {0262, "a126"}, + {0263, "a127"}, + {0264, "a128"}, + {0265, "a129"}, + {0266, "a130"}, + {0267, "a131"}, + {0270, "a132"}, + {0271, "a133"}, + {0272, "a134"}, + {0273, "a135"}, + {0274, "a136"}, + {0275, "a137"}, + {0276, "a138"}, + {0277, "a139"}, + {0300, "a140"}, + {0301, "a141"}, + {0302, "a142"}, + {0303, "a143"}, + {0304, "a144"}, + {0305, "a145"}, + {0306, "a146"}, + {0307, "a147"}, + {0310, "a148"}, + {0311, "a149"}, + {0312, "a150"}, + {0313, "a151"}, + {0314, "a152"}, + {0315, "a153"}, + {0316, "a154"}, + {0317, "a155"}, + {0320, "a156"}, + {0321, "a157"}, + {0322, "a158"}, + {0323, "a159"}, + {0324, "a160"}, + {0325, "a161"}, + {0326, "a163"}, + {0327, "a164"}, + {0330, "a196"}, + {0331, "a165"}, + {0332, "a192"}, + {0333, "a166"}, + {0334, "a167"}, + {0335, "a168"}, + {0336, "a169"}, + {0337, "a170"}, + {0340, "a171"}, + {0341, "a172"}, + {0342, "a173"}, + {0343, "a162"}, + {0344, "a174"}, + {0345, "a175"}, + {0346, "a176"}, + {0347, "a177"}, + {0350, "a178"}, + {0351, "a179"}, + {0352, "a193"}, + {0353, "a180"}, + {0354, "a199"}, + {0355, "a181"}, + {0356, "a200"}, + {0357, "a182"}, + {0361, "a201"}, + {0362, "a183"}, + {0363, "a184"}, + {0364, "a197"}, + {0365, "a185"}, + {0366, "a194"}, + {0367, "a198"}, + {0370, "a186"}, + {0371, "a195"}, + {0372, "a187"}, + {0373, "a188"}, + {0374, "a189"}, + {0375, "a190"}, + {0376, "a191"} + }; + + /** + * Singleton instance of this class. + */ + public static final ZapfDingbatsEncoding INSTANCE = new ZapfDingbatsEncoding(); + + /** + * Constructor. + */ + public ZapfDingbatsEncoding() + { + for (Object[] encodingEntry : ZAPFDINGBATS_ENCODING_TABLE) + { + add((Integer) encodingEntry[CHAR_CODE], encodingEntry[CHAR_NAME].toString()); + } + } + + @Override + public COSBase getCOSObject() + { + return COSName.getPDFName("ZapfDingbatsEncoding"); + } + + @Override + public String getEncodingName() + { + return "ZapfDingbatsEncoding"; + } +} From ca64d08ade933249236b93f9e1161a494240b4ab Mon Sep 17 00:00:00 2001 From: John Hewson Date: Fri, 8 Jul 2016 16:41:05 +0000 Subject: [PATCH 0202/2182] PDFBOX-3403: Handle invalid BaseEncoding names git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1751942 13f79535-47bb-0310-9956-ffa450edef68 --- .../font/encoding/DictionaryEncoding.java | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/DictionaryEncoding.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/DictionaryEncoding.java index 2c1ecf8ecc1..bbbcae88cb0 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/DictionaryEncoding.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/DictionaryEncoding.java @@ -19,6 +19,8 @@ import java.util.HashMap; import java.util.Map; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; @@ -32,6 +34,8 @@ */ public class DictionaryEncoding extends Encoding { + private static final Log LOG = LogFactory.getLog(DictionaryEncoding.class); + private final COSDictionary encoding; private final Encoding baseEncoding; private final Map differences = new HashMap(); @@ -91,7 +95,8 @@ public DictionaryEncoding(COSDictionary fontEncoding, boolean isNonSymbolic, Enc encoding = fontEncoding; Encoding base = null; - if (encoding.containsKey(COSName.BASE_ENCODING)) + boolean hasBaseEncoding = encoding.containsKey(COSName.BASE_ENCODING); + if (hasBaseEncoding) { COSName name = encoding.getCOSName(COSName.BASE_ENCODING); base = Encoding.getInstance(name); // may be null @@ -111,8 +116,18 @@ public DictionaryEncoding(COSDictionary fontEncoding, boolean isNonSymbolic, Enc { base = builtIn; } + else if (hasBaseEncoding) + { + String name = encoding.getCOSName(COSName.BASE_ENCODING).getName(); + LOG.warn("Invalid BaseEncoding: " + name + ", using StandardEncoding instead"); + + // fallback to standard encoding (not in PDF spec, see PDFBOX-3403) + base = StandardEncoding.INSTANCE; + } else { + // triggering this error indicates a bug in PDFBox. Every font should always have + // a built-in encoding, if not, we parsed it incorrectly. throw new IllegalArgumentException("Symbolic fonts must have a built-in " + "encoding"); } From 33f3e3dc3b0c47bc5c65879bdecb711d10cf245e Mon Sep 17 00:00:00 2001 From: John Hewson Date: Fri, 8 Jul 2016 16:54:01 +0000 Subject: [PATCH 0203/2182] PDFBOX-3403: Ignore invalid BaseEncoding names git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1751943 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/pdfbox/pdmodel/font/PDSimpleFont.java | 10 ++++++++-- .../pdmodel/font/encoding/DictionaryEncoding.java | 10 +--------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDSimpleFont.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDSimpleFont.java index 72ff98ce325..3d1689d5dd8 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDSimpleFont.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDSimpleFont.java @@ -111,7 +111,13 @@ else if (encoding instanceof COSDictionary) Encoding builtIn = null; Boolean symbolic = getSymbolicFlag(); boolean isFlaggedAsSymbolic = symbolic != null && symbolic; - if (!encodingDict.containsKey(COSName.BASE_ENCODING) && isFlaggedAsSymbolic) + + COSName baseEncoding = encodingDict.getCOSName(COSName.BASE_ENCODING); + + boolean hasValidBaseEncoding = baseEncoding != null && + Encoding.getInstance(baseEncoding) != null; + + if (!hasValidBaseEncoding && isFlaggedAsSymbolic) { builtIn = readEncodingFromFont(); } @@ -142,7 +148,7 @@ else if (encoding instanceof COSDictionary) glyphList = GlyphList.getAdobeGlyphList(); } } - + /** * Called by readEncoding() if the encoding needs to be extracted from the font file. * diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/DictionaryEncoding.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/DictionaryEncoding.java index bbbcae88cb0..56f82a0b92d 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/DictionaryEncoding.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/DictionaryEncoding.java @@ -99,7 +99,7 @@ public DictionaryEncoding(COSDictionary fontEncoding, boolean isNonSymbolic, Enc if (hasBaseEncoding) { COSName name = encoding.getCOSName(COSName.BASE_ENCODING); - base = Encoding.getInstance(name); // may be null + base = Encoding.getInstance(name); // null when the name is invalid } if (base == null) @@ -116,14 +116,6 @@ public DictionaryEncoding(COSDictionary fontEncoding, boolean isNonSymbolic, Enc { base = builtIn; } - else if (hasBaseEncoding) - { - String name = encoding.getCOSName(COSName.BASE_ENCODING).getName(); - LOG.warn("Invalid BaseEncoding: " + name + ", using StandardEncoding instead"); - - // fallback to standard encoding (not in PDF spec, see PDFBOX-3403) - base = StandardEncoding.INSTANCE; - } else { // triggering this error indicates a bug in PDFBox. Every font should always have From 0cf8ad880e21c4cdb8745a017bd515c669e18f14 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Fri, 8 Jul 2016 20:25:27 +0000 Subject: [PATCH 0204/2182] PDFBOX-3414: Add orientation parameter and improve usage dialog (secret option -printerName wasn't mentioned) git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1751965 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/pdfbox/tools/PrintPDF.java | 32 ++++++++++++++++--- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/tools/src/main/java/org/apache/pdfbox/tools/PrintPDF.java b/tools/src/main/java/org/apache/pdfbox/tools/PrintPDF.java index 86952bf8063..228b3f742de 100644 --- a/tools/src/main/java/org/apache/pdfbox/tools/PrintPDF.java +++ b/tools/src/main/java/org/apache/pdfbox/tools/PrintPDF.java @@ -20,9 +20,12 @@ import java.awt.print.PrinterJob; import java.io.File; import java.io.IOException; - +import java.util.HashMap; +import java.util.Map; import javax.print.PrintService; + import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.printing.Orientation; import org.apache.pdfbox.printing.PDFPageable; /** @@ -35,6 +38,7 @@ public final class PrintPDF private static final String PASSWORD = "-password"; private static final String SILENT = "-silentPrint"; private static final String PRINTER_NAME = "-printerName"; + private static final String ORIENTATION = "-orientation"; /** * private constructor. @@ -60,6 +64,11 @@ public static void main(String[] args) throws PrinterException, IOException String pdfFile = null; boolean silentPrint = false; String printerName = null; + Orientation orientation = Orientation.AUTO; + Map orientationMap = new HashMap(); + orientationMap.put("auto", Orientation.AUTO); + orientationMap.put("landscape", Orientation.LANDSCAPE); + orientationMap.put("portrait", Orientation.PORTRAIT); for (int i = 0; i < args.length; i++) { if (args[i].equals(PASSWORD)) @@ -84,6 +93,19 @@ else if (args[i].equals(SILENT)) { silentPrint = true; } + else if (args[i].equals(ORIENTATION)) + { + i++; + if (i >= args.length) + { + usage(); + } + orientation = orientationMap.get(args[i]); + if (orientation == null) + { + usage(); + } + } else { pdfFile = args[i]; @@ -116,7 +138,7 @@ else if (args[i].equals(SILENT)) } } } - printJob.setPageable(new PDFPageable(document)); + printJob.setPageable(new PDFPageable(document, orientation)); if (silentPrint || printJob.printDialog()) { @@ -139,8 +161,10 @@ private static void usage() { String message = "Usage: java -jar pdfbox-app-x.y.z.jar PrintPDF [options] \n" + "\nOptions:\n" - + " -password : Password to decrypt document\n" - + " -silentPrint : Print without prompting for printer info\n"; + + " -password : Password to decrypt document\n" + + " -printerName : Print to specific printer\n" + + " -orientation auto|portrait|landscape : Print using orientation (default: auto)\n" + + " -silentPrint : Print without printer dialog box\n"; System.err.println(message); System.exit(1); From 30e97ace6cf2fa3701ec000a764f830d50bd421d Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Sat, 9 Jul 2016 13:59:05 +0000 Subject: [PATCH 0205/2182] PDFBOX-3324: add /Sound git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1752006 13f79535-47bb-0310-9956-ffa450edef68 --- pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java | 1 + 1 file changed, 1 insertion(+) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java b/pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java index 765e9e3c930..30569873d9b 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java @@ -466,6 +466,7 @@ public final class COSName extends COSBase implements Comparable public static final COSName SM = new COSName("SM"); public static final COSName SMASK = new COSName("SMask"); public static final COSName SOFT_LIGHT = new COSName("SoftLight"); + public static final COSName SOUND = new COSName("Sound"); public static final COSName SS = new COSName("SS"); public static final COSName ST = new COSName("St"); public static final COSName STANDARD_ENCODING = new COSName("StandardEncoding"); From c425115616dbfd364192408f397a3469c9169529 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Sat, 9 Jul 2016 15:02:15 +0000 Subject: [PATCH 0206/2182] PDFBOX-3324: add entries specific to a sound action; deprecate or delete /S git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1752011 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/pdfbox/cos/COSName.java | 4 + .../interactive/action/PDActionSound.java | 153 ++++++++++++++++++ 2 files changed, 157 insertions(+) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java b/pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java index 30569873d9b..d7030225db5 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java @@ -340,6 +340,7 @@ public final class COSName extends COSBase implements Comparable public static final COSName MEDIA_BOX = new COSName("MediaBox"); public static final COSName METADATA = new COSName("Metadata"); public static final COSName MISSING_WIDTH = new COSName("MissingWidth"); + public static final COSName MIX = new COSName("Mix"); public static final COSName MK = new COSName("MK"); public static final COSName ML = new COSName("ML"); public static final COSName MM_TYPE1 = new COSName("MMType1"); @@ -435,6 +436,7 @@ public final class COSName extends COSBase implements Comparable public static final COSName RD = new COSName("RD"); public static final COSName REASON = new COSName("Reason"); public static final COSName REASONS = new COSName("Reasons"); + public static final COSName REPEAT = new COSName("Repeat"); public static final COSName RECIPIENTS = new COSName("Recipients"); public static final COSName RECT = new COSName("Rect"); public static final COSName REGISTRY = new COSName("Registry"); @@ -490,6 +492,7 @@ public final class COSName extends COSBase implements Comparable public static final COSName SV = new COSName("SV"); public static final COSName SW = new COSName("SW"); public static final COSName SY = new COSName("Sy"); + public static final COSName SYNCHRONOUS = new COSName("Synchronous"); // T public static final COSName T = new COSName("T"); public static final COSName TARGET = new COSName("Target"); @@ -536,6 +539,7 @@ public final class COSName extends COSBase implements Comparable public static final COSName VIEW_AREA = new COSName("ViewArea"); public static final COSName VIEW_CLIP = new COSName("ViewClip"); public static final COSName VIEWER_PREFERENCES = new COSName("ViewerPreferences"); + public static final COSName VOLUME = new COSName("Volume"); // W public static final COSName W = new COSName("W"); public static final COSName W2 = new COSName("W2"); diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/action/PDActionSound.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/action/PDActionSound.java index 33af5392a0f..a10c564f3c9 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/action/PDActionSound.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/action/PDActionSound.java @@ -17,8 +17,12 @@ package org.apache.pdfbox.pdmodel.interactive.action; +import org.apache.pdfbox.cos.COSBase; +import org.apache.pdfbox.cos.COSBoolean; import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; +import org.apache.pdfbox.cos.COSNumber; +import org.apache.pdfbox.cos.COSStream; /** * This represents a Sound action that can be executed in a PDF document @@ -57,7 +61,9 @@ public PDActionSound(COSDictionary a) * a Sound action. * * @return The S entry of the specific Sound action dictionary. + * @deprecated use {@link #getSubType() }. */ + @Deprecated public String getS() { return action.getNameAsString(COSName.S); @@ -68,10 +74,157 @@ public String getS() * a Sound action. * * @param s The Sound action. + * @deprecated use {@link #setSubType(java.lang.String) }. */ + @Deprecated public void setS(String s) { action.setName(COSName.S, s); } + /** + * Sets the sound object. + * + * @param sound the sound object defining the sound that shall be played. + */ + public void setSound(COSStream sound) + { + action.setItem(COSName.SOUND, sound); + } + + /** + * Gets the sound object. + * + * @return The sound object defining the sound that shall be played. + */ + public COSStream getSound() + { + COSBase base = action.getDictionaryObject(COSName.SOUND); + if (base instanceof COSStream) + { + return (COSStream) base; + } + return null; + } + + /** + * Gets the volume at which to play the sound, in the range −1.0 to 1.0. + * + * @param volume The volume at which to play the sound, in the range −1.0 to 1.0. + * + * @throws IllegalArgumentException if the volume parameter is outside of the range −1.0 to 1.0. + */ + public void setVolume(float volume) + { + if (volume < -1 || volume > 1) + { + throw new IllegalArgumentException("volume outside of the range −1.0 to 1.0"); + } + action.setFloat(COSName.VOLUME, volume); + } + + /** + * Sets the volume. + * + * @return The volume at which to play the sound, in the range −1.0 to 1.0. Default value: 1.0. + */ + public float getVolume() + { + COSBase base = action.getDictionaryObject(COSName.VOLUME); + if (base instanceof COSNumber) + { + float volume = ((COSNumber) base).floatValue(); + if (volume < -1 || volume > 1) + { + volume = 1; + } + return volume; + } + return 1; + } + + /** + * A flag specifying whether to play the sound synchronously or asynchronously. When true, the + * reader allows no further user interaction other than canceling the sound until the sound has + * been completely played. + * + * @param synchronous Whether to play the sound synchronously (true) or asynchronously (false). + */ + public void setSynchronous(boolean synchronous) + { + action.setBoolean(COSName.SYNCHRONOUS, synchronous); + } + + /** + * Gets the synchronous flag. It specifyes whether to play the sound synchronously or + * asynchronously. When true, the reader allows no further user interaction other than canceling + * the sound until the sound has been completely played. + * + * @return Whether to play the sound synchronously (true) or asynchronously (false, also the + * default). + */ + public boolean getSynchronous() + { + COSBase base = action.getDictionaryObject(COSName.SYNCHRONOUS); + if (base instanceof COSBoolean) + { + return ((COSBoolean) base).getValue(); + } + return false; + } + + /** + * A flag specifying whether to repeat the sound indefinitely. + * + * @param repeat Whether to repeat the sound indefinitely. + */ + public void setRepeat(boolean repeat) + { + action.setBoolean(COSName.REPEAT, repeat); + } + + /** + * Gets whether to repeat the sound indefinitely. + * + * @return Whether to repeat the sound indefinitely (default: false). + */ + public boolean getRepeat() + { + COSBase base = action.getDictionaryObject(COSName.REPEAT); + if (base instanceof COSBoolean) + { + return ((COSBoolean) base).getValue(); + } + return false; + } + + /** + * The flag specifying whether to mix this sound with any other sound already playing. If this + * flag is false, any previously playing sound shall be stopped before starting this sound; this + * can be used to stop a repeating sound (see Repeat). Default value: false. + * + * @param mix whether to mix this sound with any other sound already playing. (false). + */ + public void setMix(boolean mix) + { + action.setBoolean(COSName.MIX, mix); + } + + /** + * Gets the flag specifying whether to mix this sound with any other sound already playing. If + * this flag is false, any previously playing sound shall be stopped before starting this sound; + * this can be used to stop a repeating sound (see Repeat). + * + * @return whether to mix this sound with any other sound already playing (default: false). + */ + public boolean getMix() + { + COSBase base = action.getDictionaryObject(COSName.MIX); + if (base instanceof COSBoolean) + { + return ((COSBoolean) base).getValue(); + } + return false; + } + } From 6cb6643a00ef14a58348baa0aa518c50d4a4c516 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Sat, 9 Jul 2016 15:04:56 +0000 Subject: [PATCH 0207/2182] PDFBOX-3324: correct misleading javadoc git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1752012 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/pdfbox/pdmodel/interactive/action/PDAction.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/action/PDAction.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/action/PDAction.java index 645fbf34d70..6ad55c40f31 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/action/PDAction.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/action/PDAction.java @@ -98,7 +98,6 @@ public final void setType( String type ) /** * This will get the type of action that the actions dictionary describes. - * If present, must be Action for an action dictionary. * * @return The S entry of actions dictionary. */ @@ -109,7 +108,6 @@ public String getSubType() /** * This will set the type of action that the actions dictionary describes. - * If present, must be Action for an action dictionary. * * @param s The new type of action. */ From ccf58d2551a2dd624b4e67725b250cb468f5d669 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Sat, 9 Jul 2016 15:26:03 +0000 Subject: [PATCH 0208/2182] PDFBOX-3324: deprecate or delete /S git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1752014 13f79535-47bb-0310-9956-ffa450edef68 --- .../pdfbox/pdmodel/interactive/action/PDActionMovie.java | 4 ++++ .../pdfbox/pdmodel/interactive/action/PDActionRemoteGoTo.java | 4 ++++ .../apache/pdfbox/pdmodel/interactive/action/PDActionURI.java | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/action/PDActionMovie.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/action/PDActionMovie.java index 932e0578f0c..9577e47cfc8 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/action/PDActionMovie.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/action/PDActionMovie.java @@ -55,7 +55,9 @@ public PDActionMovie(COSDictionary a) * a Movie action. * * @return The S entry of the specific Movie action dictionary. + * @deprecated use {@link #getSubType() }. */ + @Deprecated public String getS() { return action.getNameAsString(COSName.S); @@ -66,7 +68,9 @@ public String getS() * a Movie action. * * @param s The Movie action. + * @deprecated use {@link #setSubType(java.lang.String) }. */ + @Deprecated public void setS(String s) { action.setName(COSName.S, s); diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/action/PDActionRemoteGoTo.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/action/PDActionRemoteGoTo.java index 973cb7823df..b615245c2e6 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/action/PDActionRemoteGoTo.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/action/PDActionRemoteGoTo.java @@ -61,7 +61,9 @@ public PDActionRemoteGoTo( COSDictionary a ) * It must be GoToR for a remote go-to action. * * @return The S entry of the specific remote go-to action dictionary. + * @deprecated use {@link #getSubType() }. */ + @Deprecated public String getS() { return action.getNameAsString( COSName.S ); @@ -72,7 +74,9 @@ public String getS() * It must be GoToR for a remote go-to action. * * @param s The remote go-to action. + * @deprecated use {@link #setSubType(java.lang.String) }. */ + @Deprecated public void setS( String s ) { action.setName( COSName.S, s ); diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/action/PDActionURI.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/action/PDActionURI.java index abc3c3f6e05..272b4d3f383 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/action/PDActionURI.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/action/PDActionURI.java @@ -56,7 +56,9 @@ public PDActionURI(COSDictionary a) * It must be URI for a URI action. * * @return The S entry of the specific URI action dictionary. + * @deprecated use {@link #getSubType() }. */ + @Deprecated public String getS() { return action.getNameAsString(COSName.S); @@ -67,7 +69,9 @@ public String getS() * It must be URI for a URI action. * * @param s The URI action. + * @deprecated use {@link #setSubType(java.lang.String) }. */ + @Deprecated public void setS(String s) { action.setName(COSName.S, s); From 7d25f70128846fc72000d378d401c7b522fd2405 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Mon, 11 Jul 2016 15:56:58 +0000 Subject: [PATCH 0209/2182] PDFBOX-3298: improve Exception message git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1752182 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/pdfbox/pdmodel/font/PDType1Font.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1Font.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1Font.java index fac4022e22c..097ea7e5ca0 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1Font.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1Font.java @@ -377,8 +377,8 @@ protected byte[] encode(int unicode) throws IOException if (!encoding.contains(name)) { throw new IllegalArgumentException( - String.format("U+%04X ('%s') is not available in this font's encoding: %s", - unicode, name, encoding.getEncodingName())); + String.format("U+%04X ('%s') is not available in this font %s (generic: %s) encoding: %s", + unicode, name, getName(), genericFont.getName(), encoding.getEncodingName())); } String nameInFont = getNameInFont(name); @@ -387,7 +387,7 @@ protected byte[] encode(int unicode) throws IOException if (nameInFont.equals(".notdef") || !genericFont.hasGlyph(nameInFont)) { throw new IllegalArgumentException( - String.format("No glyph for U+%04X in font %s", unicode, getName())); + String.format("No glyph for U+%04X in font %s (generic: %s)", unicode, getName(), genericFont.getName())); } int code = inverted.get(name); From 3c50a7db4f8a2141b36832227cc3a433f9f4368c Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Mon, 11 Jul 2016 18:43:18 +0000 Subject: [PATCH 0210/2182] PDFBOX-3416: avoid NullPointerException as suggested by Vittal Aithal; refactor double code git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1752193 13f79535-47bb-0310-9956-ffa450edef68 --- .../examples/signature/CreateSignature.java | 29 ++-------- .../signature/CreateSignatureBase.java | 57 ++++++++++++++++++- .../signature/CreateVisibleSignature.java | 23 +------- 3 files changed, 62 insertions(+), 47 deletions(-) diff --git a/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateSignature.java b/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateSignature.java index a091da8f649..f71e4a88708 100644 --- a/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateSignature.java +++ b/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateSignature.java @@ -56,36 +56,17 @@ public class CreateSignature extends CreateSignatureBase /** * Initialize the signature creator with a keystore and certficate password. * @param keystore the pkcs12 keystore containing the signing certificate - * @param password the password for recovering the key + * @param pin the password for recovering the key * @throws KeyStoreException if the keystore has not been initialized (loaded) * @throws NoSuchAlgorithmException if the algorithm for recovering the key cannot be found * @throws UnrecoverableKeyException if the given password is wrong * @throws CertificateException if the certificate is not valid as signing time + * @throws IOException if no certificate could be found */ - public CreateSignature(KeyStore keystore, char[] password) - throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, CertificateException + public CreateSignature(KeyStore keystore, char[] pin) + throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, CertificateException, IOException { - // grabs the first alias from the keystore and get the private key. An - // TODO alternative method or constructor could be used for setting a specific - // alias that should be used. - Enumeration aliases = keystore.aliases(); - String alias; - if (aliases.hasMoreElements()) - { - alias = aliases.nextElement(); - } - else - { - throw new KeyStoreException("Keystore is empty"); - } - setPrivateKey((PrivateKey) keystore.getKey(alias, password)); - Certificate cert = keystore.getCertificateChain(alias)[0]; - setCertificate(cert); - if (cert instanceof X509Certificate) - { - // avoid expired certificate - ((X509Certificate) cert).checkValidity(); - } + super(keystore, pin); } /** diff --git a/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateSignatureBase.java b/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateSignatureBase.java index 665c69f602c..8026d4323c4 100644 --- a/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateSignatureBase.java +++ b/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateSignatureBase.java @@ -19,9 +19,16 @@ import java.io.IOException; import java.io.InputStream; import java.security.GeneralSecurityException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; +import java.security.UnrecoverableKeyException; import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; import java.util.ArrayList; +import java.util.Enumeration; import java.util.List; import org.apache.pdfbox.pdmodel.interactive.digitalsignature.SignatureInterface; import org.bouncycastle.asn1.ASN1Encodable; @@ -54,12 +61,58 @@ public abstract class CreateSignatureBase implements SignatureInterface private Certificate certificate; private TSAClient tsaClient; - public void setPrivateKey(PrivateKey privateKey) + /** + * Initialize the signature creator with a keystore (pkcs12) and pin that should be used for the + * signature. + * + * @param keystore is a pkcs12 keystore. + * @param pin is the pin for the keystore / private key + * @throws KeyStoreException if the keystore has not been initialized (loaded) + * @throws NoSuchAlgorithmException if the algorithm for recovering the key cannot be found + * @throws UnrecoverableKeyException if the given password is wrong + * @throws CertificateException if the certificate is not valid as signing time + * @throws IOException if no certificate could be found + */ + public CreateSignatureBase(KeyStore keystore, char[] pin) + throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, IOException, CertificateException + { + // grabs the first alias from the keystore and get the private key. An + // alternative method or constructor could be used for setting a specific + // alias that should be used. + Enumeration aliases = keystore.aliases(); + String alias; + Certificate cert = null; + while (aliases.hasMoreElements()) + { + alias = aliases.nextElement(); + setPrivateKey((PrivateKey) keystore.getKey(alias, pin)); + Certificate[] certChain = keystore.getCertificateChain(alias); + if (certChain == null) + { + continue; + } + cert = certChain[0]; + setCertificate(cert); + if (cert instanceof X509Certificate) + { + // avoid expired certificate + ((X509Certificate) cert).checkValidity(); + } + break; + } + + if (cert == null) + { + throw new IOException("Could not find certificate"); + } + } + + public final void setPrivateKey(PrivateKey privateKey) { this.privateKey = privateKey; } - public void setCertificate(Certificate certificate) + public final void setCertificate(Certificate certificate) { this.certificate = certificate; } diff --git a/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateVisibleSignature.java b/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateVisibleSignature.java index 62d2934fd61..7c4e7f48690 100644 --- a/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateVisibleSignature.java +++ b/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateVisibleSignature.java @@ -81,31 +81,12 @@ public void setVisibleSignatureProperties(String name, String location, String r * @throws NoSuchAlgorithmException if the algorithm for recovering the key cannot be found * @throws UnrecoverableKeyException if the given password is wrong * @throws CertificateException if the certificate is not valid as signing time + * @throws IOException if no certificate could be found */ public CreateVisibleSignature(KeyStore keystore, char[] pin) throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, IOException, CertificateException { - // grabs the first alias from the keystore and get the private key. An - // alternative method or constructor could be used for setting a specific - // alias that should be used. - Enumeration aliases = keystore.aliases(); - String alias = null; - if (aliases.hasMoreElements()) - { - alias = aliases.nextElement(); - } - else - { - throw new IOException("Could not find alias"); - } - setPrivateKey((PrivateKey) keystore.getKey(alias, pin)); - Certificate cert = keystore.getCertificateChain(alias)[0]; - setCertificate(cert); - if (cert instanceof X509Certificate) - { - // avoid expired certificate - ((X509Certificate) cert).checkValidity(); - } + super(keystore, pin); } /** From 502900f46a78cdf0bc1006a62a5e60cc8bbb0164 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Tue, 12 Jul 2016 15:41:31 +0000 Subject: [PATCH 0211/2182] PDFBOX-3416: fix imports git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1752306 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/pdfbox/examples/signature/CreateSignature.java | 4 ---- .../pdfbox/examples/signature/CreateVisibleSignature.java | 4 ---- 2 files changed, 8 deletions(-) diff --git a/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateSignature.java b/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateSignature.java index f71e4a88708..82736ddf702 100644 --- a/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateSignature.java +++ b/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateSignature.java @@ -28,13 +28,9 @@ import java.security.KeyStoreException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; import java.security.UnrecoverableKeyException; -import java.security.cert.Certificate; import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; import java.util.Calendar; -import java.util.Enumeration; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature; diff --git a/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateVisibleSignature.java b/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateVisibleSignature.java index 7c4e7f48690..2ee845cbb4a 100644 --- a/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateVisibleSignature.java +++ b/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateVisibleSignature.java @@ -25,13 +25,9 @@ import java.security.KeyStoreException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; import java.security.UnrecoverableKeyException; -import java.security.cert.Certificate; import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; import java.util.Calendar; -import java.util.Enumeration; import org.apache.pdfbox.io.IOUtils; import org.apache.pdfbox.pdmodel.PDDocument; From ad719d19c4add3a8eb211beb3b5423a71261f03d Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Tue, 12 Jul 2016 19:24:20 +0000 Subject: [PATCH 0212/2182] PDFBOX-3418: optimize string to hex conversion, as suggested by Michael Doswald git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1752336 13f79535-47bb-0310-9956-ffa450edef68 --- .../pdfbox/pdmodel/font/ToUnicodeWriter.java | 25 ++---- .../main/java/org/apache/pdfbox/util/Hex.java | 63 +++++++++++--- .../org/apache/pdfbox/util/TestHexUtil.java | 87 +++++++++++++++++++ 3 files changed, 145 insertions(+), 30 deletions(-) create mode 100644 pdfbox/src/test/java/org/apache/pdfbox/util/TestHexUtil.java diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/ToUnicodeWriter.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/ToUnicodeWriter.java index a7df741a2e9..92b61f2d156 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/ToUnicodeWriter.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/ToUnicodeWriter.java @@ -26,6 +26,7 @@ import java.util.Map; import java.util.TreeMap; import org.apache.pdfbox.util.Charsets; +import org.apache.pdfbox.util.Hex; /** * Writes ToUnicode Mapping Files. @@ -154,15 +155,15 @@ public void writeTo(OutputStream out) throws IOException { int index = batch * 100 + j; writer.write('<'); - writer.write(toHex(srcFrom.get(index))); + writer.write(Hex.getChars(srcFrom.get(index).shortValue())); writer.write("> "); writer.write('<'); - writer.write(toHex(srcTo.get(index))); + writer.write(Hex.getChars(srcTo.get(index).shortValue())); writer.write("> "); - writer.write("<"); - writer.write(stringToHex(dstString.get(index))); + writer.write('<'); + writer.write(Hex.getCharsUTF16BE(dstString.get(index))); writer.write(">\n"); } writeLine(writer, "endbfrange\n"); @@ -182,20 +183,4 @@ private void writeLine(BufferedWriter writer, String text) throws IOException writer.write(text); writer.write('\n'); } - - private String toHex(int num) - { - return String.format("%04X", num); - } - - private String stringToHex(String text) - { - // use of non-BMP code points requires PDF 1.5 or later, otherwise we're limited to UCS-2 - StringBuilder sb = new StringBuilder(); - for (byte b : text.getBytes(Charsets.UTF_16BE)) - { - sb.append(String.format("%02X", b)); - } - return sb.toString(); - } } diff --git a/pdfbox/src/main/java/org/apache/pdfbox/util/Hex.java b/pdfbox/src/main/java/org/apache/pdfbox/util/Hex.java index 36aef19ede6..d4ff4491495 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/util/Hex.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/util/Hex.java @@ -33,9 +33,8 @@ public final class Hex * https://stackoverflow.com/questions/2817752/java-code-to-convert-byte-to-hexadecimal * */ - private static final String HEXES_STRING = "0123456789ABCDEF"; - - private static final byte[] HEXES = HEXES_STRING.getBytes(Charsets.US_ASCII); + private static final byte[] HEX_BYTES = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; + private static final char[] HEX_CHARS = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; private Hex() {} @@ -44,7 +43,7 @@ private Hex() {} */ public static String getString(byte b) { - char[] chars = new char[]{HEXES_STRING.charAt(getHighNibble(b)), HEXES_STRING.charAt(getLowNibble(b))}; + char[] chars = new char[]{HEX_CHARS[getHighNibble(b)], HEX_CHARS[getLowNibble(b)]}; return new String(chars); } @@ -56,7 +55,7 @@ public static String getString(byte[] bytes) StringBuilder string = new StringBuilder(bytes.length * 2); for (byte b : bytes) { - string.append(HEXES_STRING.charAt(getHighNibble(b))).append(HEXES_STRING.charAt(getLowNibble(b))); + string.append(HEX_CHARS[getHighNibble(b)]).append(HEX_CHARS[getLowNibble(b)]); } return string.toString(); } @@ -66,7 +65,7 @@ public static String getString(byte[] bytes) */ public static byte[] getBytes(byte b) { - return new byte[]{HEXES[getHighNibble(b)], HEXES[getLowNibble(b)]}; + return new byte[]{HEX_BYTES[getHighNibble(b)], HEX_BYTES[getLowNibble(b)]}; } /** @@ -77,13 +76,57 @@ public static byte[] getBytes(byte[] bytes) byte[] asciiBytes = new byte[bytes.length*2]; for(int i=0; i< bytes.length; i++) { - asciiBytes[i*2] = HEXES[getHighNibble(bytes[i])]; - asciiBytes[i*2+1] = HEXES[getLowNibble(bytes[i])]; + asciiBytes[i*2] = HEX_BYTES[getHighNibble(bytes[i])]; + asciiBytes[i*2+1] = HEX_BYTES[getLowNibble(bytes[i])]; } return asciiBytes; } /** + * Returns the characters corresponding to the ASCII hex encoding of the given short. + */ + public static char[] getChars(short num) + { + char[] hex = new char[4]; + hex[0] = HEX_CHARS[(num >> 12) & 0x0F]; + hex[1] = HEX_CHARS[(num >> 8) & 0x0F]; + hex[2] = HEX_CHARS[(num >> 4) & 0x0F]; + hex[3] = HEX_CHARS[num & 0x0F]; + return hex; + } + + /** + * Takes the characters in the given string, convert it to bytes in UTF16-BE format + * and build a char array that corresponds to the ASCII hex encoding of the resulting + * bytes. + * + * Example: + *
    +     *   getCharsUTF16BE("ab") == new char[]{'0','0','6','1','0','0','6','2'}
    +     * 
    + * + * @param text The string to convert + * @return The string converted to hex + */ + public static char[] getCharsUTF16BE(String text) + { + // Note that the internal representation of string in Java is already UTF-16. Therefore + // we do not need to use an encoder to convert the string to its byte representation. + char[] hex = new char[text.length()*4]; + + for (int stringIdx = 0, charIdx = 0; stringIdx < text.length(); stringIdx++) + { + char c = text.charAt(stringIdx); + hex[charIdx++] = HEX_CHARS[(c >> 12) & 0x0F]; + hex[charIdx++] = HEX_CHARS[(c >> 8) & 0x0F]; + hex[charIdx++] = HEX_CHARS[(c >> 4) & 0x0F]; + hex[charIdx++] = HEX_CHARS[c & 0x0F]; + } + + return hex; + } + + /** * Writes the given byte as hex value to the given output stream. * @param b the byte to be written * @param output the output stream to be written to @@ -91,8 +134,8 @@ public static byte[] getBytes(byte[] bytes) */ public static void writeHexByte(byte b, OutputStream output) throws IOException { - output.write(HEXES[getHighNibble(b)]); - output.write(HEXES[getLowNibble(b)]); + output.write(HEX_BYTES[getHighNibble(b)]); + output.write(HEX_BYTES[getLowNibble(b)]); } /** diff --git a/pdfbox/src/test/java/org/apache/pdfbox/util/TestHexUtil.java b/pdfbox/src/test/java/org/apache/pdfbox/util/TestHexUtil.java new file mode 100644 index 00000000000..fe286d90931 --- /dev/null +++ b/pdfbox/src/test/java/org/apache/pdfbox/util/TestHexUtil.java @@ -0,0 +1,87 @@ +/* + * Copyright 2016 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.pdfbox.util; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +/** + * + * @author Michael Doswald + */ +public class TestHexUtil extends TestCase +{ + + /** + * Test conversion from short to char[] + */ + public void testGetCharsFromShortWithoutPassingInABuffer() + { + assertArrayEquals(new char[]{'0','0','0','0'}, Hex.getChars((short)0x0000)); + assertArrayEquals(new char[]{'0','0','0','F'}, Hex.getChars((short)0x000F)); + assertArrayEquals(new char[]{'A','B','C','D'}, Hex.getChars((short)0xABCD)); + assertArrayEquals(new char[]{'B','A','B','E'}, Hex.getChars((short)0xCAFEBABE)); + } + + /** + * Check conversion from String to a char[] which contains the UTF16-BE encoded + * bytes of the string as hex digits + * + */ + public void testGetCharsUTF16BE() + { + assertArrayEquals(new char[]{'0','0','6','1','0','0','6','2'}, Hex.getCharsUTF16BE("ab")); + assertArrayEquals(new char[]{'5','E','2','E','5','2','A','9'}, Hex.getCharsUTF16BE("帮助")); + } + + private void assertArrayEquals(char[] expected, char[] actual) + { + assertEquals("Length of char array not equal", expected.length, actual.length); + for (int idx = 0; idx < expected.length; idx++) + { + if (expected[idx] != actual[idx]) + { + fail(String.format("Character at index %d not equal. Expected '%c' but got '%c'", + idx, expected[idx], actual[idx])); + } + } + } + + /** + * Set the tests in the suite for this test class. + * + * @return the Suite. + */ + public static Test suite() + { + return new TestSuite(TestHexUtil.class); + } + + /** + * Command line execution. + * + * @param args Command line arguments. + */ + public static void main(String[] args) + { + String[] arg = + { + TestHexUtil.class.getName() + }; + junit.textui.TestRunner.main(arg); + } +} From a113a6ab1082b6ad80f6117fbad60c4eb8f07263 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Wed, 13 Jul 2016 16:44:35 +0000 Subject: [PATCH 0213/2182] PDFBOX-3419: pass type to parseLiElement from above instead of assuming text git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1752453 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/xmpbox/xml/DomXmpParser.java | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/xmpbox/src/main/java/org/apache/xmpbox/xml/DomXmpParser.java b/xmpbox/src/main/java/org/apache/xmpbox/xml/DomXmpParser.java index ebb6dec816a..8bd5e44024e 100644 --- a/xmpbox/src/main/java/org/apache/xmpbox/xml/DomXmpParser.java +++ b/xmpbox/src/main/java/org/apache/xmpbox/xml/DomXmpParser.java @@ -92,7 +92,6 @@ public DomXmpParser() throws XmpParsingException { throw new XmpParsingException(ErrorType.Configuration, "Failed to initilalize", e); } - } public boolean isStrictParsing() @@ -462,7 +461,7 @@ private void manageArray(XMPMetadata xmp, Element property, PropertyType type, C for (Element element : lis) { QName propertyQName = new QName(element.getLocalName()); - AbstractField ast = parseLiElement(xmp, propertyQName, element); + AbstractField ast = parseLiElement(xmp, propertyQName, element, type.type()); if (ast != null) { array.addProperty(ast); @@ -499,7 +498,7 @@ private void parseDescriptionInner(XMPMetadata xmp, Element description, Complex } } - private AbstractField parseLiElement(XMPMetadata xmp, QName descriptor, Element liElement) + private AbstractField parseLiElement(XMPMetadata xmp, QName descriptor, Element liElement, Types type) throws XmpParsingException { if (DomHelper.isParseTypeResource(liElement)) @@ -515,11 +514,11 @@ private AbstractField parseLiElement(XMPMetadata xmp, QName descriptor, Element } else { - // no child, so consider as simple text + // no child String text = liElement.getTextContent(); TypeMapping tm = xmp.getTypeMapping(); AbstractSimpleProperty sp = tm.instanciateSimpleProperty(descriptor.getNamespaceURI(), - descriptor.getPrefix(), descriptor.getLocalPart(), text, Types.Text); + descriptor.getPrefix(), descriptor.getLocalPart(), text, type); loadAttributes(sp, liElement); return sp; } @@ -600,7 +599,7 @@ else if (type.card().isArray()) List lis = DomHelper.getElementChildren(bagOrSeq); for (Element element2 : lis) { - AbstractField ast2 = parseLiElement(xmp, descriptor, element2); + AbstractField ast2 = parseLiElement(xmp, descriptor, element2, type.type()); if (ast2 != null) { array.addProperty(ast2); From cf3d0ffad5e955c85b63449478129109030b118d Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Wed, 13 Jul 2016 17:05:12 +0000 Subject: [PATCH 0214/2182] PDFBOX-3395: allow missing glyf table git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1752459 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/fontbox/ttf/TTFParser.java | 5 ----- .../org/apache/fontbox/ttf/TTFSubsetter.java | 8 +++++++ .../pdfbox/pdmodel/font/PDCIDFontType2.java | 8 ++++++- .../pdfbox/pdmodel/font/PDTrueTypeFont.java | 22 ++++++++++++++++--- 4 files changed, 34 insertions(+), 9 deletions(-) diff --git a/fontbox/src/main/java/org/apache/fontbox/ttf/TTFParser.java b/fontbox/src/main/java/org/apache/fontbox/ttf/TTFParser.java index 1d636394694..68449d20833 100644 --- a/fontbox/src/main/java/org/apache/fontbox/ttf/TTFParser.java +++ b/fontbox/src/main/java/org/apache/fontbox/ttf/TTFParser.java @@ -209,11 +209,6 @@ private void parseTables(TrueTypeFont font, TTFDataStream raf) throws IOExceptio { throw new IOException("loca is mandatory"); } - - if (font.getGlyph() == null) - { - throw new IOException("glyf is mandatory"); - } } if (font.getNaming() == null && !isEmbedded) diff --git a/fontbox/src/main/java/org/apache/fontbox/ttf/TTFSubsetter.java b/fontbox/src/main/java/org/apache/fontbox/ttf/TTFSubsetter.java index 657f08389f9..d71591629b6 100755 --- a/fontbox/src/main/java/org/apache/fontbox/ttf/TTFSubsetter.java +++ b/fontbox/src/main/java/org/apache/fontbox/ttf/TTFSubsetter.java @@ -479,6 +479,10 @@ private void addCompoundReferences() throws IOException do { GlyphTable g = ttf.getGlyph(); + if (g == null) + { + throw new IOException("source font " + ttf.getName() + " must have a glyf table"); + } long[] offsets = ttf.getIndexToLocation().getOffsets(); InputStream is = ttf.getOriginalData(); Set glyphIdsToAdd = null; @@ -560,6 +564,10 @@ private byte[] buildGlyfTable(long[] newOffsets) throws IOException ByteArrayOutputStream bos = new ByteArrayOutputStream(); GlyphTable g = ttf.getGlyph(); + if (g == null) + { + throw new IOException("source font " + ttf.getName() + " must have a glyf table"); + } long[] offsets = ttf.getIndexToLocation().getOffsets(); InputStream is = ttf.getOriginalData(); try diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType2.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType2.java index 0957ceaedc6..0edf8f32c85 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType2.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType2.java @@ -27,6 +27,7 @@ import org.apache.fontbox.cmap.CMap; import org.apache.fontbox.ttf.CmapSubtable; import org.apache.fontbox.ttf.GlyphData; +import org.apache.fontbox.ttf.GlyphTable; import org.apache.fontbox.ttf.OTFParser; import org.apache.fontbox.ttf.OpenTypeFont; import org.apache.fontbox.ttf.TrueTypeFont; @@ -438,7 +439,12 @@ public GeneralPath getPath(int code) throws IOException else { int gid = codeToGID(code); - GlyphData glyph = ttf.getGlyph().getGlyph(gid); + GlyphTable glyphTable = ttf.getGlyph(); + if (glyphTable == null) + { + return new GeneralPath(); + } + GlyphData glyph = glyphTable.getGlyph(gid); if (glyph != null) { return glyph.getPath(); diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDTrueTypeFont.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDTrueTypeFont.java index cf86ff62ed1..066fb518d4f 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDTrueTypeFont.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDTrueTypeFont.java @@ -29,6 +29,7 @@ import org.apache.fontbox.ttf.CmapSubtable; import org.apache.fontbox.ttf.CmapTable; import org.apache.fontbox.ttf.GlyphData; +import org.apache.fontbox.ttf.GlyphTable; import org.apache.fontbox.ttf.PostScriptTable; import org.apache.fontbox.ttf.TTFParser; import org.apache.fontbox.ttf.TrueTypeFont; @@ -350,7 +351,12 @@ public float getWidthFromFont(int code) throws IOException public float getHeight(int code) throws IOException { int gid = codeToGID(code); - GlyphData glyph = ttf.getGlyph().getGlyph(gid); + GlyphTable glyphTable = ttf.getGlyph(); + if (glyphTable == null) + { + return 0; + } + GlyphData glyph = glyphTable.getGlyph(gid); if (glyph != null) { return glyph.getBoundingBox().getHeight(); @@ -442,7 +448,12 @@ public boolean isEmbedded() public GeneralPath getPath(int code) throws IOException { int gid = codeToGID(code); - GlyphData glyph = ttf.getGlyph().getGlyph(gid); + GlyphTable glyphTable = ttf.getGlyph(); + if (glyphTable == null) + { + return new GeneralPath(); + } + GlyphData glyph = glyphTable.getGlyph(gid); // some glyphs have no outlines (e.g. space, table, newline) if (glyph == null) @@ -482,7 +493,12 @@ public GeneralPath getPath(String name) throws IOException return new GeneralPath(); } - GlyphData glyph = ttf.getGlyph().getGlyph(gid); + GlyphTable glyphTable = ttf.getGlyph(); + if (glyphTable == null) + { + return new GeneralPath(); + } + GlyphData glyph = glyphTable.getGlyph(gid); if (glyph != null) { return glyph.getPath(); From c785755d435540afde48a29c893400c4f74b5cd4 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Wed, 13 Jul 2016 17:20:05 +0000 Subject: [PATCH 0215/2182] PDFBOX-2852: make fields private that aren't used outside git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1752461 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/pdfbox/filter/CCITTFaxEncoderStream.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/filter/CCITTFaxEncoderStream.java b/pdfbox/src/main/java/org/apache/pdfbox/filter/CCITTFaxEncoderStream.java index 96d3b3124ef..e597cd2c2e3 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/filter/CCITTFaxEncoderStream.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/filter/CCITTFaxEncoderStream.java @@ -266,7 +266,7 @@ private void clearOutputBuffer() { outputBufferBitLength = 0; } - public static class Code { + private static class Code { private Code(int code, int length) { this.code = code; this.length = length; @@ -276,13 +276,13 @@ private Code(int code, int length) { final int length; } - public static final Code[] WHITE_TERMINATING_CODES; + private static final Code[] WHITE_TERMINATING_CODES; - public static final Code[] WHITE_NONTERMINATING_CODES; + private static final Code[] WHITE_NONTERMINATING_CODES; - public static final Code[] BLACK_TERMINATING_CODES; + private static final Code[] BLACK_TERMINATING_CODES; - public static final Code[] BLACK_NONTERMINATING_CODES; + private static final Code[] BLACK_NONTERMINATING_CODES; static { // Setup HUFFMAN Codes From d7794acd13a205df4d0ddc10f1a1b5727b1ef4de Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Wed, 13 Jul 2016 17:50:45 +0000 Subject: [PATCH 0216/2182] PDFBOX-3395: revert last change and allow empty glyf table instead git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1752475 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/fontbox/ttf/TTFParser.java | 9 ++++++-- .../org/apache/fontbox/ttf/TTFSubsetter.java | 8 ------- .../pdfbox/pdmodel/font/PDCIDFontType2.java | 8 +------ .../pdfbox/pdmodel/font/PDTrueTypeFont.java | 22 +++---------------- 4 files changed, 11 insertions(+), 36 deletions(-) diff --git a/fontbox/src/main/java/org/apache/fontbox/ttf/TTFParser.java b/fontbox/src/main/java/org/apache/fontbox/ttf/TTFParser.java index 68449d20833..f7dba200b8c 100644 --- a/fontbox/src/main/java/org/apache/fontbox/ttf/TTFParser.java +++ b/fontbox/src/main/java/org/apache/fontbox/ttf/TTFParser.java @@ -209,6 +209,11 @@ private void parseTables(TrueTypeFont font, TTFDataStream raf) throws IOExceptio { throw new IOException("loca is mandatory"); } + + if (font.getGlyph() == null) + { + throw new IOException("glyf is mandatory"); + } } if (font.getNaming() == null && !isEmbedded) @@ -300,8 +305,8 @@ else if (tag.equals(VerticalOriginTable.TAG)) table.setOffset(raf.readUnsignedInt()); table.setLength(raf.readUnsignedInt()); - // skip tables with zero length - if (table.getLength() == 0) + // skip tables with zero length (except glyf) + if (table.getLength() == 0 && !tag.equals(GlyphTable.TAG)) { return null; } diff --git a/fontbox/src/main/java/org/apache/fontbox/ttf/TTFSubsetter.java b/fontbox/src/main/java/org/apache/fontbox/ttf/TTFSubsetter.java index d71591629b6..657f08389f9 100755 --- a/fontbox/src/main/java/org/apache/fontbox/ttf/TTFSubsetter.java +++ b/fontbox/src/main/java/org/apache/fontbox/ttf/TTFSubsetter.java @@ -479,10 +479,6 @@ private void addCompoundReferences() throws IOException do { GlyphTable g = ttf.getGlyph(); - if (g == null) - { - throw new IOException("source font " + ttf.getName() + " must have a glyf table"); - } long[] offsets = ttf.getIndexToLocation().getOffsets(); InputStream is = ttf.getOriginalData(); Set glyphIdsToAdd = null; @@ -564,10 +560,6 @@ private byte[] buildGlyfTable(long[] newOffsets) throws IOException ByteArrayOutputStream bos = new ByteArrayOutputStream(); GlyphTable g = ttf.getGlyph(); - if (g == null) - { - throw new IOException("source font " + ttf.getName() + " must have a glyf table"); - } long[] offsets = ttf.getIndexToLocation().getOffsets(); InputStream is = ttf.getOriginalData(); try diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType2.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType2.java index 0edf8f32c85..0957ceaedc6 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType2.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType2.java @@ -27,7 +27,6 @@ import org.apache.fontbox.cmap.CMap; import org.apache.fontbox.ttf.CmapSubtable; import org.apache.fontbox.ttf.GlyphData; -import org.apache.fontbox.ttf.GlyphTable; import org.apache.fontbox.ttf.OTFParser; import org.apache.fontbox.ttf.OpenTypeFont; import org.apache.fontbox.ttf.TrueTypeFont; @@ -439,12 +438,7 @@ public GeneralPath getPath(int code) throws IOException else { int gid = codeToGID(code); - GlyphTable glyphTable = ttf.getGlyph(); - if (glyphTable == null) - { - return new GeneralPath(); - } - GlyphData glyph = glyphTable.getGlyph(gid); + GlyphData glyph = ttf.getGlyph().getGlyph(gid); if (glyph != null) { return glyph.getPath(); diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDTrueTypeFont.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDTrueTypeFont.java index 066fb518d4f..cf86ff62ed1 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDTrueTypeFont.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDTrueTypeFont.java @@ -29,7 +29,6 @@ import org.apache.fontbox.ttf.CmapSubtable; import org.apache.fontbox.ttf.CmapTable; import org.apache.fontbox.ttf.GlyphData; -import org.apache.fontbox.ttf.GlyphTable; import org.apache.fontbox.ttf.PostScriptTable; import org.apache.fontbox.ttf.TTFParser; import org.apache.fontbox.ttf.TrueTypeFont; @@ -351,12 +350,7 @@ public float getWidthFromFont(int code) throws IOException public float getHeight(int code) throws IOException { int gid = codeToGID(code); - GlyphTable glyphTable = ttf.getGlyph(); - if (glyphTable == null) - { - return 0; - } - GlyphData glyph = glyphTable.getGlyph(gid); + GlyphData glyph = ttf.getGlyph().getGlyph(gid); if (glyph != null) { return glyph.getBoundingBox().getHeight(); @@ -448,12 +442,7 @@ public boolean isEmbedded() public GeneralPath getPath(int code) throws IOException { int gid = codeToGID(code); - GlyphTable glyphTable = ttf.getGlyph(); - if (glyphTable == null) - { - return new GeneralPath(); - } - GlyphData glyph = glyphTable.getGlyph(gid); + GlyphData glyph = ttf.getGlyph().getGlyph(gid); // some glyphs have no outlines (e.g. space, table, newline) if (glyph == null) @@ -493,12 +482,7 @@ public GeneralPath getPath(String name) throws IOException return new GeneralPath(); } - GlyphTable glyphTable = ttf.getGlyph(); - if (glyphTable == null) - { - return new GeneralPath(); - } - GlyphData glyph = glyphTable.getGlyph(gid); + GlyphData glyph = ttf.getGlyph().getGlyph(gid); if (glyph != null) { return glyph.getPath(); From 3599f05c670616621f3cbb6896f23defa0b35115 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Fri, 15 Jul 2016 17:34:41 +0000 Subject: [PATCH 0217/2182] PDFBOX-3017: cache visual signature stream as RandomAccessBuffer instead of RandomAccessBufferedFileInputStream to avoid disk access git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1752857 13f79535-47bb-0310-9956-ffa450edef68 --- .../pdmodel/interactive/digitalsignature/SignatureOptions.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/SignatureOptions.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/SignatureOptions.java index 7229e256758..df9681e8245 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/SignatureOptions.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/SignatureOptions.java @@ -22,6 +22,7 @@ import java.io.InputStream; import org.apache.pdfbox.cos.COSDocument; +import org.apache.pdfbox.io.RandomAccessBuffer; import org.apache.pdfbox.io.RandomAccessBufferedFileInputStream; import org.apache.pdfbox.io.RandomAccessRead; import org.apache.pdfbox.pdfparser.PDFParser; @@ -92,7 +93,7 @@ public void setVisualSignature(File file) throws IOException */ public void setVisualSignature(InputStream is) throws IOException { - pdfSource = new RandomAccessBufferedFileInputStream(is); + pdfSource = new RandomAccessBuffer(is); PDFParser parser = new PDFParser(pdfSource); parser.parse(); visualSignature = parser.getDocument(); From 1d05f26374eee387e291f2beee2d2e41df8570dd Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Fri, 15 Jul 2016 19:49:29 +0000 Subject: [PATCH 0218/2182] PDFBOX-3017: DRY refactoring git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1752876 13f79535-47bb-0310-9956-ffa450edef68 --- .../digitalsignature/SignatureOptions.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/SignatureOptions.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/SignatureOptions.java index df9681e8245..0dd82bad0ac 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/SignatureOptions.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/SignatureOptions.java @@ -79,10 +79,7 @@ public int getPage() */ public void setVisualSignature(File file) throws IOException { - pdfSource = new RandomAccessBufferedFileInputStream(file); - PDFParser parser = new PDFParser(pdfSource); - parser.parse(); - visualSignature = parser.getDocument(); + initFromRandomAccessRead(new RandomAccessBufferedFileInputStream(file)); } /** @@ -93,7 +90,12 @@ public void setVisualSignature(File file) throws IOException */ public void setVisualSignature(InputStream is) throws IOException { - pdfSource = new RandomAccessBuffer(is); + initFromRandomAccessRead(new RandomAccessBuffer(is)); + } + + private void initFromRandomAccessRead(RandomAccessRead rar) throws IOException + { + pdfSource = rar; PDFParser parser = new PDFParser(pdfSource); parser.parse(); visualSignature = parser.getDocument(); From 3af999e2d889853e6600c6aa044ef0b579b3bbe5 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Sat, 16 Jul 2016 12:12:57 +0000 Subject: [PATCH 0219/2182] PDFBOX-3017: move constructor to top git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1752937 13f79535-47bb-0310-9956-ffa450edef68 --- .../visible/PDVisibleSigBuilder.java | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDVisibleSigBuilder.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDVisibleSigBuilder.java index c279190b76d..69cb13cb468 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDVisibleSigBuilder.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDVisibleSigBuilder.java @@ -53,6 +53,15 @@ public class PDVisibleSigBuilder implements PDFTemplateBuilder private final PDFTemplateStructure pdfStructure; private static final Log log = LogFactory.getLog(PDVisibleSigBuilder.class); + /** + * Constructor. + */ + public PDVisibleSigBuilder() + { + pdfStructure = new PDFTemplateStructure(); + log.info("PDF Structure has been created"); + } + @Override public void createPage(PDVisibleSignDesigner properties) { @@ -70,12 +79,6 @@ public void createTemplate(PDPage page) throws IOException pdfStructure.setTemplate(template); } - public PDVisibleSigBuilder() - { - pdfStructure = new PDFTemplateStructure(); - log.info("PDF Structure has been created"); - } - @Override public void createAcroForm(PDDocument template) { From a01c3838ba267ecc45be057b89e39b612f1430bb Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Sat, 16 Jul 2016 14:15:39 +0000 Subject: [PATCH 0220/2182] PDFBOX-2852: remove redundant if git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1752971 13f79535-47bb-0310-9956-ffa450edef68 --- xmpbox/src/main/java/org/apache/xmpbox/xml/DomHelper.java | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/xmpbox/src/main/java/org/apache/xmpbox/xml/DomHelper.java b/xmpbox/src/main/java/org/apache/xmpbox/xml/DomHelper.java index 48b57879a46..d9b17482fae 100644 --- a/xmpbox/src/main/java/org/apache/xmpbox/xml/DomHelper.java +++ b/xmpbox/src/main/java/org/apache/xmpbox/xml/DomHelper.java @@ -109,13 +109,7 @@ public static boolean isRdfDescription(Element element) public static boolean isParseTypeResource(Element element) { Attr parseType = element.getAttributeNodeNS(XmpConstants.RDF_NAMESPACE, XmpConstants.PARSE_TYPE); - if (parseType != null && XmpConstants.RESOURCE_NAME.equals(parseType.getValue())) - { - // parseType resourc - return true; - } - // else - return false; + return parseType != null && XmpConstants.RESOURCE_NAME.equals(parseType.getValue()); } } From c06252499589f910c32c60d92e702dfcd092f443 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Sat, 16 Jul 2016 14:26:46 +0000 Subject: [PATCH 0221/2182] PDFBOX-2852: add break git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1752973 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/pdfbox/multipdf/LayerUtility.java | 1 + 1 file changed, 1 insertion(+) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/multipdf/LayerUtility.java b/pdfbox/src/main/java/org/apache/pdfbox/multipdf/LayerUtility.java index 8ed5b7d67c4..1b7217bd089 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/multipdf/LayerUtility.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/multipdf/LayerUtility.java @@ -187,6 +187,7 @@ public PDFormXObject importPageAsForm(PDDocument sourceDoc, PDPage page) throws at.scale(viewBox.getWidth() / viewBox.getHeight(), viewBox.getHeight() / viewBox.getWidth()); at.translate(viewBox.getHeight(), 0); at.rotate(-Math.PI * 1.5); + break; default: //no additional transformations necessary } From 2a8ec2a62c2f5c431dbd78799ee027ec2f2499f3 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Sat, 16 Jul 2016 14:28:33 +0000 Subject: [PATCH 0222/2182] PDFBOX-2852: add break git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1752976 13f79535-47bb-0310-9956-ffa450edef68 --- pdfbox/src/main/java/org/apache/pdfbox/pdfwriter/COSWriter.java | 1 + 1 file changed, 1 insertion(+) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdfwriter/COSWriter.java b/pdfbox/src/main/java/org/apache/pdfbox/pdfwriter/COSWriter.java index 832fc4e7977..4f0196cb33f 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdfwriter/COSWriter.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdfwriter/COSWriter.java @@ -1413,6 +1413,7 @@ private static void writeString(byte[] bytes, boolean forceHex, OutputStream out break; default: output.write(b); + break; } } output.write(')'); From dddc322c84f41d3806eabccdd21a87776bb3a6f7 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Sat, 16 Jul 2016 14:46:58 +0000 Subject: [PATCH 0223/2182] PDFBOX-2852: Avoid using a branching statement as the last in a loop; git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1752978 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/fontbox/cff/Type2CharStringParser.java | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/fontbox/src/main/java/org/apache/fontbox/cff/Type2CharStringParser.java b/fontbox/src/main/java/org/apache/fontbox/cff/Type2CharStringParser.java index f2331f2dbec..83a41b07fdf 100644 --- a/fontbox/src/main/java/org/apache/fontbox/cff/Type2CharStringParser.java +++ b/fontbox/src/main/java/org/apache/fontbox/cff/Type2CharStringParser.java @@ -121,7 +121,7 @@ else if (b0 == 29 && globalSubroutineIndexProvided) { // process globalsubr command Integer operand=(Integer)sequence.remove(sequence.size()-1); //get subrbias - int bias = 0; + int bias; int nSubrs = globalSubrIndex.length; if (nSubrs < 1240) @@ -249,7 +249,7 @@ else if (b0 == 255) private int getMaskLength() { int hintCount = hstemCount + vstemCount; - int length = (int)(hintCount / 8); + int length = hintCount / 8; if (hintCount % 8 > 0) { length++; @@ -264,12 +264,11 @@ private List peekNumbers() { Object object = sequence.get(i); - if (object instanceof Number) + if (!(object instanceof Number)) { - numbers.add(0, (Number) object); - continue; + return numbers; } - return numbers; + numbers.add(0, (Number) object); } return numbers; } From 64ebab31e0a5d8512e655f78d404e418946e4a5c Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Mon, 18 Jul 2016 19:02:26 +0000 Subject: [PATCH 0224/2182] PDFBOX-3417: remove useless code git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1753303 13f79535-47bb-0310-9956-ffa450edef68 --- .../digitalsignature/visible/PDVisibleSignDesigner.java | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDVisibleSignDesigner.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDVisibleSignDesigner.java index cf082c3b221..428bb35bd98 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDVisibleSignDesigner.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDVisibleSignDesigner.java @@ -30,7 +30,7 @@ /** * Builder for visible signature design. - * Uses use param() instead of setParam() + * Setters use param() instead of setParam() to allow chaining. * * @author Vakhtang Koroghlishvili */ @@ -188,12 +188,7 @@ private void calculatePageSize(PDDocument document, int page) PDRectangle mediaBox = firstPage.getMediaBox(); pageHeight(mediaBox.getHeight()); pageWidth = mediaBox.getWidth(); - - float x = pageWidth; - float y = 0; - pageWidth += y; - float tPercent = (100 * y / (x + y)); - imageSizeInPercents = 100 - tPercent; + imageSizeInPercents = 100; } /** From 89f675cf361bff7fb8830078bd6aefdfcee6c5e2 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Mon, 18 Jul 2016 19:17:52 +0000 Subject: [PATCH 0225/2182] PDFBOX-3017: remove setting of placeholder items, this is done in PDDocument.addSignature since 2011 git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1753304 13f79535-47bb-0310-9956-ffa450edef68 --- .../digitalsignature/visible/PDVisibleSigBuilder.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDVisibleSigBuilder.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDVisibleSigBuilder.java index 69cb13cb468..628d7127702 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDVisibleSigBuilder.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDVisibleSigBuilder.java @@ -112,8 +112,6 @@ public void createSignature(PDSignatureField pdSignatureField, PDPage page, widget.setPage(page); page.getAnnotations().add(widget); pdSignature.setName(signatureName); - pdSignature.setByteRange(new int[] { 0, 0, 0, 0 }); - pdSignature.setContents(new byte[4096]); pdfStructure.setPdSignature(pdSignature); log.info("PDSignature has been created"); } From 1248234d7a038fd749d7439de85f09ca72561cf4 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Mon, 18 Jul 2016 20:06:18 +0000 Subject: [PATCH 0226/2182] PDFBOX-3421: Optimize float to string conversion, as done by Michael Doswald git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1753313 13f79535-47bb-0310-9956-ffa450edef68 --- .../pdfbox/pdmodel/PDPageContentStream.java | 18 +- .../apache/pdfbox/util/NumberFormatUtil.java | 171 +++++++++++++++ .../pdfbox/util/TestNumberFormatUtil.java | 201 ++++++++++++++++++ 3 files changed, 387 insertions(+), 3 deletions(-) create mode 100644 pdfbox/src/main/java/org/apache/pdfbox/util/NumberFormatUtil.java create mode 100644 pdfbox/src/test/java/org/apache/pdfbox/util/TestNumberFormatUtil.java diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPageContentStream.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPageContentStream.java index d9bffa173a3..27dc6eb632f 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPageContentStream.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPageContentStream.java @@ -53,6 +53,7 @@ import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceStream; import org.apache.pdfbox.util.Charsets; import org.apache.pdfbox.util.Matrix; +import org.apache.pdfbox.util.NumberFormatUtil; /** * Provides the ability to write to a page content stream. @@ -105,6 +106,7 @@ public boolean isPrepend() // number format private final NumberFormat formatDecimal = NumberFormat.getNumberInstance(Locale.US); + private final byte[] formatBuffer = new byte[32]; /** * Create a new PDPage content stream. @@ -266,7 +268,7 @@ public PDPageContentStream(PDDocument document, PDPage sourcePage, AppendMode ap } // configure NumberFormat - formatDecimal.setMaximumFractionDigits(10); + formatDecimal.setMaximumFractionDigits(5); formatDecimal.setGroupingUsed(false); } @@ -2217,9 +2219,19 @@ public void addComment(String comment) throws IOException /** * Writes a real number to the content stream. */ - private void writeOperand(float real) throws IOException + protected void writeOperand(float real) throws IOException { - write(formatDecimal.format(real)); + int byteCount = NumberFormatUtil.formatFloatFast(real, formatDecimal.getMaximumFractionDigits(), formatBuffer); + + if (byteCount == -1) + { + //Fast formatting failed + write(formatDecimal.format(real)); + } + else + { + output.write(formatBuffer, 0, byteCount); + } output.write(' '); } diff --git a/pdfbox/src/main/java/org/apache/pdfbox/util/NumberFormatUtil.java b/pdfbox/src/main/java/org/apache/pdfbox/util/NumberFormatUtil.java new file mode 100644 index 00000000000..32482fe1ab3 --- /dev/null +++ b/pdfbox/src/main/java/org/apache/pdfbox/util/NumberFormatUtil.java @@ -0,0 +1,171 @@ +/* + * Copyright 2016 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.pdfbox.util; + +/** + * This class contains methods to format numbers. + * + * @author Michael Doswald + */ +public class NumberFormatUtil +{ + + /** + * Maximum number of fraction digits supported by the format methods + */ + private static final int MAX_FRACTION_DIGITS = 5; + + /** + * Contains the power of ten values for fast lookup in the format methods + */ + private static final long[] POWER_OF_TENS; + private static final int[] POWER_OF_TENS_INT; + + static + { + POWER_OF_TENS = new long[19]; + POWER_OF_TENS[0] = 1; + + for (int exp = 1; exp < POWER_OF_TENS.length; exp++) + { + POWER_OF_TENS[exp] = POWER_OF_TENS[exp - 1] * 10; + } + + POWER_OF_TENS_INT = new int[10]; + POWER_OF_TENS_INT[0] = 1; + + for (int exp = 1; exp < POWER_OF_TENS_INT.length; exp++) + { + POWER_OF_TENS_INT[exp] = POWER_OF_TENS_INT[exp - 1] * 10; + } + } + + /** + * Fast variant to format a floating point value to a ASCII-string. The format will fail if the + * value is greater than {@link Long#MAX_VALUE}, smaller or equal to {@link Long#MIN_VALUE}, is + * {@link Float#NaN}, infinite or the number of requested fraction digits is greater than + * {@link #MAX_FRACTION_DIGITS}. + * + * When the number contains more fractional digits than {@code maxFractionDigits} the value will + * be rounded. Rounding is done to the nearest possible value, with the tie breaking rule of + * rounding away from zero. + * + * @param value The float value to format + * @param maxFractionDigits The maximum number of fraction digits used + * @param asciiBuffer The output buffer to write the formatted value to + * + * @return The number of bytes used in the buffer or {@code -1} if formatting failed + */ + public static int formatFloatFast(float value, int maxFractionDigits, byte[] asciiBuffer) + { + if (Float.isNaN(value) || + Float.isInfinite(value) || + value > Long.MAX_VALUE || + value <= Long.MIN_VALUE || + maxFractionDigits > MAX_FRACTION_DIGITS) + { + return -1; + } + + int offset = 0; + long integerPart = (long) value; + + //handle sign + if (value < 0) + { + asciiBuffer[offset++] = '-'; + integerPart = -integerPart; + } + + //extract fraction part + long fractionPart = (long) ((Math.abs((double)value) - integerPart) * POWER_OF_TENS[maxFractionDigits] + 0.5d); + + //Check for rounding to next integer + if (fractionPart >= POWER_OF_TENS[maxFractionDigits]) { + integerPart++; + fractionPart -= POWER_OF_TENS[maxFractionDigits]; + } + + //format integer part + offset = formatPositiveNumber(integerPart, getExponent(integerPart), false, asciiBuffer, offset); + + if (fractionPart > 0 && maxFractionDigits > 0) + { + asciiBuffer[offset++] = '.'; + offset = formatPositiveNumber(fractionPart, maxFractionDigits - 1, true, asciiBuffer, offset); + } + + return offset; + } + + /** + * Formats a positive integer number starting with the digit at {@code 10^exp}. + * + * @param number The number to format + * @param exp The start digit + * @param omitTrailingZeros Whether the formatting should stop if only trailing zeros are left. + * This is needed e.g. when formatting fractions of a number. + * @param asciiBuffer The buffer to write the ASCII digits to + * @param startOffset The start offset into the buffer to start writing + * + * @return The offset into the buffer which contains the first byte that was not filled by the + * method + */ + private static int formatPositiveNumber(long number, int exp, boolean omitTrailingZeros, byte[] asciiBuffer, int startOffset) + { + int offset = startOffset; + long remaining = number; + + while (remaining > Integer.MAX_VALUE && (!omitTrailingZeros || remaining > 0)) + { + long digit = remaining / POWER_OF_TENS[exp]; + remaining -= (digit * POWER_OF_TENS[exp]); + + asciiBuffer[offset++] = (byte) ('0' + digit); + exp--; + } + + //If the remaining fits into an integer, use int arithmetic as it is faster + int remainingInt = (int) remaining; + while (exp >= 0 && (!omitTrailingZeros || remainingInt > 0)) + { + int digit = remainingInt / POWER_OF_TENS_INT[exp]; + remainingInt -= (digit * POWER_OF_TENS_INT[exp]); + + asciiBuffer[offset++] = (byte) ('0' + digit); + exp--; + } + + return offset; + } + + /** + * Returns the highest exponent of 10 where {@code 10^exp < number} for numbers > 0 + */ + private static int getExponent(long number) + { + for (int exp = 0; exp < (POWER_OF_TENS.length - 1); exp++) + { + if (number < POWER_OF_TENS[exp + 1]) + { + return exp; + } + } + + return POWER_OF_TENS.length - 1; + } + +} diff --git a/pdfbox/src/test/java/org/apache/pdfbox/util/TestNumberFormatUtil.java b/pdfbox/src/test/java/org/apache/pdfbox/util/TestNumberFormatUtil.java new file mode 100644 index 00000000000..76bc3f582a8 --- /dev/null +++ b/pdfbox/src/test/java/org/apache/pdfbox/util/TestNumberFormatUtil.java @@ -0,0 +1,201 @@ +/* + * Copyright 2016 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.pdfbox.util; + +import java.math.BigDecimal; +import java.math.MathContext; +import java.math.RoundingMode; +import java.util.Arrays; +import java.util.regex.Pattern; +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +/** + * + * @author Michael Doswald + */ +public class TestNumberFormatUtil extends TestCase +{ + + private final byte[] buffer = new byte[64]; + + public void testFormatOfIntegerValues() + { + assertEquals(2, NumberFormatUtil.formatFloatFast(51, 5, buffer)); + assertArrayEquals(new byte[]{'5', '1'}, Arrays.copyOfRange(buffer, 0, 2)); + + assertEquals(3, NumberFormatUtil.formatFloatFast(-51, 5, buffer)); + assertArrayEquals(new byte[]{'-', '5', '1'}, Arrays.copyOfRange(buffer, 0, 3)); + + assertEquals(1, NumberFormatUtil.formatFloatFast(0, 5, buffer)); + assertArrayEquals(new byte[]{'0'}, Arrays.copyOfRange(buffer, 0, 1)); + + assertEquals(19, NumberFormatUtil.formatFloatFast(Long.MAX_VALUE, 5, buffer)); + assertArrayEquals(new byte[]{'9', '2', '2', '3', '3', '7', '2', '0', '3', '6', '8', '5', + '4', '7', '7', '5', '8', '0', '7'}, + Arrays.copyOfRange(buffer, 0, 19)); + + //Note: Integer.MAX_VALUE would be 2147483647, but when converting to float, we have + // precision errors. NumberFormat.getIntegerInstance() does also print 2147483648 for + // such a float + assertEquals(10, NumberFormatUtil.formatFloatFast(Integer.MAX_VALUE, 5, buffer)); + assertArrayEquals(new byte[]{'2', '1', '4', '7', '4', '8', '3', '6', '4', '8'}, + Arrays.copyOfRange(buffer, 0, 10)); + + assertEquals(11, NumberFormatUtil.formatFloatFast(Integer.MIN_VALUE, 5, buffer)); + assertArrayEquals(new byte[]{'-', '2', '1', '4', '7', '4', '8', '3', '6', '4', '8'}, + Arrays.copyOfRange(buffer, 0, 11)); + } + + public void testFormatOfRealValues() + { + assertEquals(3, NumberFormatUtil.formatFloatFast(0.7f, 5, buffer)); + assertArrayEquals(new byte[]{'0', '.', '7'}, Arrays.copyOfRange(buffer, 0, 3)); + + assertEquals(4, NumberFormatUtil.formatFloatFast(-0.7f, 5, buffer)); + assertArrayEquals(new byte[]{'-', '0', '.', '7'}, Arrays.copyOfRange(buffer, 0, 4)); + + assertEquals(5, NumberFormatUtil.formatFloatFast(0.003f, 5, buffer)); + assertArrayEquals(new byte[]{'0', '.', '0', '0', '3'}, Arrays.copyOfRange(buffer, 0, 5)); + + assertEquals(6, NumberFormatUtil.formatFloatFast(-0.003f, 5, buffer)); + assertArrayEquals(new byte[]{'-', '0', '.', '0', '0', '3'}, + Arrays.copyOfRange(buffer, 0, 6)); + } + + public void testFormatOfRealValuesReturnsMinusOneIfItCannotBeFormatted() + { + assertEquals("NaN should not be formattable", -1, + NumberFormatUtil.formatFloatFast(Float.NaN, 5, buffer)); + assertEquals("+Infinity should not be formattable", -1, + NumberFormatUtil.formatFloatFast(Float.POSITIVE_INFINITY, 5, buffer)); + assertEquals("-Infinity should not be formattable", -1, + NumberFormatUtil.formatFloatFast(Float.NEGATIVE_INFINITY, 5, buffer)); + + assertEquals("Too big number should not be formattable", -1, + NumberFormatUtil.formatFloatFast(((float) Long.MAX_VALUE) + 1000000000000f, 5, buffer)); + assertEquals("Too big negative number should not be formattable", -1, + NumberFormatUtil.formatFloatFast(Long.MIN_VALUE, 5, buffer)); + } + + public void testRoundingUp() + { + assertEquals(1, NumberFormatUtil.formatFloatFast(0.999999f, 5, buffer)); + assertArrayEquals(new byte[]{'1'}, Arrays.copyOfRange(buffer, 0, 1)); + + assertEquals(4, NumberFormatUtil.formatFloatFast(0.125f, 2, buffer)); + assertArrayEquals(new byte[]{'0','.','1','3'}, Arrays.copyOfRange(buffer, 0, 4)); + + assertEquals(2, NumberFormatUtil.formatFloatFast(-0.999999f, 5, buffer)); + assertArrayEquals(new byte[]{'-','1'}, Arrays.copyOfRange(buffer, 0, 2)); + } + + public void testRoundingDown() + { + assertEquals(4, NumberFormatUtil.formatFloatFast(0.994f, 2, buffer)); + assertArrayEquals(new byte[]{'0','.','9','9'}, Arrays.copyOfRange(buffer, 0, 4)); + } + + /** + * Formats all floats in a defined range, parses them back with the BigDecimal constructor and + * compares them to the expected result. The test only tests a small range for performance + * reasons. It works for ranges up to at least A0 size: + * + *
      + *
    • PDF uses 72 dpi resolution
    • + *
    • A0 size is 841mm x 1189mm, this equals to about 2472 x 3495 in dot resolution
    • + *
    + */ + public void testFormattingInRange() + { + //Define a range to test + BigDecimal minVal = new BigDecimal("-10"); + BigDecimal maxVal = new BigDecimal("10"); + BigDecimal maxDelta = BigDecimal.ZERO; + + Pattern pattern = Pattern.compile("^\\-?\\d+(\\.\\d+)?$"); + + byte[] formatBuffer = new byte[32]; + + for (int maxFractionDigits = 0; maxFractionDigits <= 5; maxFractionDigits++) + { + BigDecimal increment = new BigDecimal(10).pow(-maxFractionDigits, MathContext.DECIMAL128); + + for (BigDecimal value = minVal; value.compareTo(maxVal) < 0; value = value.add(increment)) + { + //format with the formatFloatFast method and parse back + int byteCount = NumberFormatUtil.formatFloatFast(value.floatValue(), maxFractionDigits, formatBuffer); + assertFalse(byteCount == -1); + String newStringResult = new String(formatBuffer, 0, byteCount, Charsets.US_ASCII); + BigDecimal formattedDecimal = new BigDecimal(newStringResult); + + //create new BigDecimal with float representation. This is needed because the float + //may not represent the 'value' BigDecimal precisely, in which case the formatFloatFast + //would get a different result. + BigDecimal expectedDecimal = new BigDecimal(value.floatValue()); + expectedDecimal = expectedDecimal.setScale(maxFractionDigits, RoundingMode.HALF_UP); + + BigDecimal diff = formattedDecimal.subtract(expectedDecimal).abs(); + + assertTrue(pattern.matcher(newStringResult).matches()); + + //Fail if diff is greater than maxDelta. + if (diff.compareTo(maxDelta) > 0) + { + fail("Expected: " + expectedDecimal + ", actual: " + newStringResult + ", diff: " + diff); + } + } + } + } + + private void assertArrayEquals(byte[] expected, byte[] actual) + { + assertEquals("Length of byte array not equal", expected.length, actual.length); + for (int idx = 0; idx < expected.length; idx++) + { + if (expected[idx] != actual[idx]) + { + fail(String.format("Byte at index %d not equal. Expected '%02X' but got '%02X'", + idx, expected[idx], actual[idx])); + } + } + } + + /** + * Set the tests in the suite for this test class. + * + * @return the Suite. + */ + public static Test suite() + { + return new TestSuite(TestNumberFormatUtil.class); + } + + /** + * Command line execution. + * + * @param args Command line arguments. + */ + public static void main(String[] args) + { + String[] arg = + { + TestNumberFormatUtil.class.getName() + }; + junit.textui.TestRunner.main(arg); + } +} From 159ae67fc27d2671ab9a41942ba3856331c1344d Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Wed, 20 Jul 2016 16:23:06 +0000 Subject: [PATCH 0227/2182] PDFBOX-3017: improve javadoc git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1753544 13f79535-47bb-0310-9956-ffa450edef68 --- .../digitalsignature/PDSignature.java | 27 ++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/PDSignature.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/PDSignature.java index 0d62663eaff..580cbbda80e 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/PDSignature.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/PDSignature.java @@ -102,6 +102,7 @@ public PDSignature(COSDictionary dict) * * @return The COS dictionary that matches this Java object. */ + @Override public COSDictionary getCOSObject() { return dictionary; @@ -138,7 +139,10 @@ public void setSubFilter(COSName subfilter) } /** - * Sets the name. + * Sets the name of the person or authority signing the document. According to the PDF + * specification, this value should be used only when it is not possible to extract the name + * from the signature. + * * @param name the name to be used */ public void setName(String name) @@ -147,7 +151,8 @@ public void setName(String name) } /** - * Sets the location. + * Sets the CPU host name or physical location of the signing. + * * @param location the location to be used */ public void setLocation(String location) @@ -156,7 +161,7 @@ public void setLocation(String location) } /** - * Sets the reason. + * Sets the reason for the signing, such as (I agree...). * * @param reason the reason to be used */ @@ -166,7 +171,8 @@ public void setReason(String reason) } /** - * Sets the contact info. + * Sets the contact info provided by the signer to enable a recipient to contact the signer to + * verify the signature, e.g. a phone number. * * @param contactInfo the contact info to be used */ @@ -205,7 +211,9 @@ public String getSubFilter() } /** - * Returns the name. + * Returns the name of the person or authority signing the document. According to the PDF + * specification, this value should be used only when it is not possible to extract the name + * from the signature. * * @return the name */ @@ -215,7 +223,7 @@ public String getName() } /** - * Returns the location. + * Returns the CPU host name or physical location of the signing. * * @return the location */ @@ -225,7 +233,7 @@ public String getLocation() } /** - * Returns the reason. + * Returns the reason for the signing, such as (I agree...). * * @return the reason */ @@ -235,9 +243,10 @@ public String getReason() } /** - * Returns the contact info. + * Returns the contact info provided by the signer to enable a recipient to contact the signer + * to verify the signature, e.g. a phone number. * - * @return teh contact info + * @return the contact info */ public String getContactInfo() { From 62fcaf1fb484d7d7ae98a60c4a5413823d1c73fc Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Wed, 20 Jul 2016 16:38:50 +0000 Subject: [PATCH 0228/2182] PDFBOX-3017: buffer and close inputStream, fix javadoc git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1753549 13f79535-47bb-0310-9956-ffa450edef68 --- .../visible/PDVisibleSignDesigner.java | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDVisibleSignDesigner.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDVisibleSignDesigner.java index 428bb35bd98..af0bc120d24 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDVisibleSignDesigner.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDVisibleSignDesigner.java @@ -17,6 +17,8 @@ package org.apache.pdfbox.pdmodel.interactive.digitalsignature.visible; import java.awt.image.BufferedImage; + +import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; @@ -24,13 +26,14 @@ import javax.imageio.ImageIO; +import org.apache.pdfbox.io.IOUtils; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.common.PDRectangle; /** - * Builder for visible signature design. - * Setters use param() instead of setParam() to allow chaining. + * Class for visible signature design properties. Setters use param() instead of setParam() to allow + * chaining. * * @author Vakhtang Koroghlishvili */ @@ -193,15 +196,23 @@ private void calculatePageSize(PDDocument document, int page) /** * Set the image for the signature. - * - * @param path of image location - * @return image Stream + * + * @param path Path of the image file. + * @return Visible Signature Configuration Object * @throws IOException */ public PDVisibleSignDesigner signatureImage(String path) throws IOException { - InputStream fin = new FileInputStream(path); - readImageStream(fin); + InputStream in = null; + try + { + in = new BufferedInputStream(new FileInputStream(path)); + readImageStream(in); + } + finally + { + IOUtils.closeQuietly(in); + } return this; } From 23abb47b93a1072f34d7de71caf8d7ddb4bb5d6c Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Wed, 20 Jul 2016 16:45:23 +0000 Subject: [PATCH 0229/2182] PDFBOX-3017: improve javadoc, correct local variables names git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1753550 13f79535-47bb-0310-9956-ffa450edef68 --- .../visible/PDVisibleSigBuilder.java | 27 +++++++++---------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDVisibleSigBuilder.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDVisibleSigBuilder.java index 628d7127702..18801474776 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDVisibleSigBuilder.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDVisibleSigBuilder.java @@ -44,8 +44,8 @@ import org.apache.pdfbox.pdmodel.interactive.form.PDSignatureField; /** - * Implementation of PDFTemplateBuilder. - * @see PDFTemplateBuilder + * Implementation of {@link PDFTemplateBuilder}. + * * @author Vakhtang Koroghlishvili */ public class PDVisibleSigBuilder implements PDFTemplateBuilder @@ -240,8 +240,8 @@ public void createAppearanceDictionary(PDFormXObject holderForml, @Override public void createInnerFormStream(PDDocument template) { - PDStream innterFormStream = new PDStream(template); - pdfStructure.setInnterFormStream(innterFormStream); + PDStream innerFormStream = new PDStream(template); + pdfStructure.setInnterFormStream(innerFormStream); log.info("Stream of another form (inner form - it will be inside holder form) " + "has been created"); } @@ -334,18 +334,15 @@ public void injectAppearanceStreams(PDStream holderFormStream, PDStream innterFo { // 100 means that document width is 100% via the rectangle. if rectangle // is 500px, images 100% is 500px. - // String imgFormComment = "q "+imageWidthSize+ " 0 0 50 0 0 cm /" + + // String imgFormContent = "q "+imageWidthSize+ " 0 0 50 0 0 cm /" + // imageName + " Do Q\n" + builder.toString(); - String imgFormComment = "q " + 100 + " 0 0 50 0 0 cm /" + imageName.getName() + " Do Q\n"; - String holderFormComment = "q 1 0 0 1 0 0 cm /" + innerFormName.getName() + " Do Q \n"; - String innerFormComment = "q 1 0 0 1 0 0 cm /" + imageObjectName.getName() + " Do Q\n"; - - appendRawCommands(pdfStructure.getHolderFormStream().createOutputStream(), - holderFormComment); - appendRawCommands(pdfStructure.getInnerFormStream().createOutputStream(), - innerFormComment); - appendRawCommands(pdfStructure.getImageFormStream().createOutputStream(), - imgFormComment); + String imgFormContent = "q " + 100 + " 0 0 50 0 0 cm /" + imageName.getName() + " Do Q\n"; + String holderFormContent = "q 1 0 0 1 0 0 cm /" + innerFormName.getName() + " Do Q\n"; + String innerFormContent = "q 1 0 0 1 0 0 cm /" + imageObjectName.getName() + " Do Q\n"; + + appendRawCommands(pdfStructure.getHolderFormStream().createOutputStream(), holderFormContent); + appendRawCommands(pdfStructure.getInnerFormStream().createOutputStream(), innerFormContent); + appendRawCommands(pdfStructure.getImageFormStream().createOutputStream(), imgFormContent); log.info("Injected appearance stream to pdf"); } From 6b898b49e3169df46558eb260cc05d5bc8406218 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Wed, 20 Jul 2016 16:51:56 +0000 Subject: [PATCH 0230/2182] PDFBOX-3017: correct variables names git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1753552 13f79535-47bb-0310-9956-ffa450edef68 --- .../digitalsignature/visible/PDFTemplateBuilder.java | 2 +- .../digitalsignature/visible/PDFTemplateStructure.java | 6 +++--- .../digitalsignature/visible/PDVisibleSigBuilder.java | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDFTemplateBuilder.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDFTemplateBuilder.java index 4bee05f6ab5..029a637c703 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDFTemplateBuilder.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDFTemplateBuilder.java @@ -235,7 +235,7 @@ void injectProcSetArray(PDFormXObject innerForm, PDPage page, * @param properties * @throws IOException */ - void injectAppearanceStreams(PDStream holderFormStream, PDStream innterFormStream, + void injectAppearanceStreams(PDStream holderFormStream, PDStream innerFormStream, PDStream imageFormStream, COSName imageObjectName, COSName imageName, COSName innerFormName, PDVisibleSignDesigner properties) throws IOException; diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDFTemplateStructure.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDFTemplateStructure.java index cb172387624..aa42423befa 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDFTemplateStructure.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDFTemplateStructure.java @@ -367,11 +367,11 @@ public PDStream getInnerFormStream() /** * Sets inner form stream - * @param innterFormStream + * @param innerFormStream */ - public void setInnterFormStream(PDStream innterFormStream) + public void setInnterFormStream(PDStream innerFormStream) { - this.innterFormStream = innterFormStream; + this.innterFormStream = innerFormStream; } /** diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDVisibleSigBuilder.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDVisibleSigBuilder.java index 18801474776..87018dad256 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDVisibleSigBuilder.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDVisibleSigBuilder.java @@ -327,7 +327,7 @@ public void injectProcSetArray(PDFormXObject innerForm, PDPage page, } @Override - public void injectAppearanceStreams(PDStream holderFormStream, PDStream innterFormStream, + public void injectAppearanceStreams(PDStream holderFormStream, PDStream innerFormStream, PDStream imageFormStream, COSName imageObjectName, COSName imageName, COSName innerFormName, PDVisibleSignDesigner properties) throws IOException From a7127de995d72f017e9ad43e1d12be0b5f09534d Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Wed, 20 Jul 2016 17:02:26 +0000 Subject: [PATCH 0231/2182] PDFBOX-3017: close image stream, clarify variable names git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1753568 13f79535-47bb-0310-9956-ffa450edef68 --- .../examples/signature/CreateVisibleSignature.java | 9 +++++---- .../pdfbox/examples/pdmodel/TestCreateSignature.java | 7 +++++++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateVisibleSignature.java b/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateVisibleSignature.java index 2ee845cbb4a..0965973da4e 100644 --- a/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateVisibleSignature.java +++ b/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateVisibleSignature.java @@ -52,10 +52,10 @@ public class CreateVisibleSignature extends CreateSignatureBase private final PDVisibleSigProperties visibleSignatureProperties = new PDVisibleSigProperties(); public void setvisibleSignDesigner(String filename, int x, int y, int zoomPercent, - FileInputStream image, int page) + FileInputStream imageStream, int page) throws IOException { - visibleSignDesigner = new PDVisibleSignDesigner(filename, image, page); + visibleSignDesigner = new PDVisibleSignDesigner(filename, imageStream, page); visibleSignDesigner.xAxis(x).yAxis(y).zoom(zoomPercent).signatureFieldName("signature"); } @@ -204,7 +204,7 @@ public static void main(String[] args) throws KeyStoreException, CertificateExce CreateVisibleSignature signing = new CreateVisibleSignature(keystore, pin.clone()); - FileInputStream image = new FileInputStream(args[3]); + FileInputStream imageStream = new FileInputStream(args[3]); String name = documentFile.getName(); String substring = name.substring(0, name.lastIndexOf('.')); @@ -212,7 +212,8 @@ public static void main(String[] args) throws KeyStoreException, CertificateExce // page is 1-based here int page = 1; - signing.setvisibleSignDesigner (args[2], 0, 0, -50, image, page); + signing.setvisibleSignDesigner (args[2], 0, 0, -50, imageStream, page); + imageStream.close(); signing.setVisibleSignatureProperties ("name", "location", "Security", 0, page, true); signing.signPDF(documentFile, signedDocumentFile, tsaClient); } diff --git a/examples/src/test/java/org/apache/pdfbox/examples/pdmodel/TestCreateSignature.java b/examples/src/test/java/org/apache/pdfbox/examples/pdmodel/TestCreateSignature.java index 9da41449eff..0953291781a 100644 --- a/examples/src/test/java/org/apache/pdfbox/examples/pdmodel/TestCreateSignature.java +++ b/examples/src/test/java/org/apache/pdfbox/examples/pdmodel/TestCreateSignature.java @@ -79,6 +79,8 @@ protected void setUp() throws Exception * * @throws IOException * @throws GeneralSecurityException + * @throws CMSException + * @throws OperatorCreationException */ public void testDetachedSHA256() throws IOException, CMSException, OperatorCreationException, GeneralSecurityException @@ -105,6 +107,8 @@ public void testDetachedSHA256() * * @throws IOException * @throws GeneralSecurityException + * @throws CMSException + * @throws OperatorCreationException */ public void testDetachedSHA256WithTSA() throws IOException, CMSException, OperatorCreationException, GeneralSecurityException @@ -153,6 +157,8 @@ public void testDetachedSHA256WithTSA() * Test creating visual signature. * * @throws IOException + * @throws CMSException + * @throws OperatorCreationException * @throws GeneralSecurityException */ public void testCreateVisibleSignature() @@ -170,6 +176,7 @@ public void testCreateVisibleSignature() signing.setVisibleSignatureProperties("name", "location", "Security", 0, 1, true); File destFile = new File(outDir + "signed_visible.pdf"); signing.signPDF(new File(inPath), destFile, null); + fis.close(); checkSignature(destFile); } From 4ccd846f666072f312cb4f7b1b60817c26231ad5 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Wed, 20 Jul 2016 17:08:47 +0000 Subject: [PATCH 0232/2182] PDFBOX-3017: improve javadoc, rename parameter names git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1753571 13f79535-47bb-0310-9956-ffa450edef68 --- .../visible/PDFTemplateBuilder.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDFTemplateBuilder.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDFTemplateBuilder.java index 029a637c703..7da3a734f30 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDFTemplateBuilder.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDFTemplateBuilder.java @@ -75,14 +75,17 @@ public interface PDFTemplateBuilder void createSignatureField(PDAcroForm acroForm) throws IOException; /** - * Creates PDSignatureField. - * + * Creates the signature with the given name and assign it to the signature field parameter and + * assign the page parameter to the widget. + * * @param pdSignatureField * @param page - * @param signatureName + * @param signerName the name of the person or authority signing the document. According to the + * PDF specification, this value should be used only when it is not possible to extract the name + * from the signature. * @throws IOException */ - void createSignature(PDSignatureField pdSignatureField, PDPage page, String signatureName) + void createSignature(PDSignatureField pdSignatureField, PDPage page, String signerName) throws IOException; /** @@ -227,7 +230,7 @@ void injectProcSetArray(PDFormXObject innerForm, PDPage page, * injects appearance streams * * @param holderFormStream - * @param innterFormStream + * @param innerFormStream * @param imageFormStream * @param imageObjectName * @param imageName From f5946f1db46db67b9d958aa5f659193f774856c3 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Wed, 20 Jul 2016 17:15:23 +0000 Subject: [PATCH 0233/2182] PDFBOX-3017: improve javadoc, rename parameter names git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1753573 13f79535-47bb-0310-9956-ffa450edef68 --- .../visible/PDFTemplateCreator.java | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDFTemplateCreator.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDFTemplateCreator.java index 1d4ae5b82d0..fc39eeb54cb 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDFTemplateCreator.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDFTemplateCreator.java @@ -34,28 +34,29 @@ import org.apache.pdfbox.pdmodel.interactive.form.PDSignatureField; /** - * Using that class, we build pdf template. + * Class to build PDF template. + * * @author Vakhtang Koroghlishvili */ public class PDFTemplateCreator { - PDFTemplateBuilder pdfBuilder; + private final PDFTemplateBuilder pdfBuilder; private static final Log logger = LogFactory.getLog(PDFTemplateCreator.class); /** - * sets PDFBuilder + * Constructor. * - * @param bookBuilder + * @param templateBuilder */ - public PDFTemplateCreator(PDFTemplateBuilder bookBuilder) + public PDFTemplateCreator(PDFTemplateBuilder templateBuilder) { - pdfBuilder = bookBuilder; + pdfBuilder = templateBuilder; } /** - * that method returns object of PDFStructure + * Returns the PDFTemplateStructure object. * - * @return PDFStructure + * @return */ public PDFTemplateStructure getPdfStructure() { @@ -63,7 +64,8 @@ public PDFTemplateStructure getPdfStructure() } /** - * this method builds pdf step by step, and finally it returns stream of visible signature + * Build a PDF with a visible signature step by step, and return it as a stream. + * * @param properties * @return InputStream * @throws IOException From 6ede1926785121212b3edf150ab1e5a108f839a9 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Wed, 20 Jul 2016 17:23:52 +0000 Subject: [PATCH 0234/2182] PDFBOX-3017: deprecate / remove poorly named method "getTemplateAppearanceStream" git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1753579 13f79535-47bb-0310-9956-ffa450edef68 --- .../visible/PDFTemplateCreator.java | 14 +++++++- .../visible/PDFTemplateStructure.java | 33 ++++++++++++++----- 2 files changed, 37 insertions(+), 10 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDFTemplateCreator.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDFTemplateCreator.java index fc39eeb54cb..95bc44a4227 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDFTemplateCreator.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDFTemplateCreator.java @@ -18,12 +18,15 @@ import java.awt.geom.AffineTransform; import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.apache.pdfbox.cos.COSDocument; import org.apache.pdfbox.cos.COSName; +import org.apache.pdfbox.pdfwriter.COSWriter; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.PDResources; @@ -152,7 +155,7 @@ public InputStream buildPDF(PDVisibleSignDesigner properties) throws IOException pdfBuilder.createVisualSignature(template); pdfBuilder.createWidgetDictionary(pdSignatureField, holderFormResources); - ByteArrayInputStream in = pdfStructure.getTemplateAppearanceStream(); + InputStream in = getVisualSignatureAsStream(pdfStructure.getVisualSignature()); logger.info("stream returning started, size= " + in.available()); // we must close the document @@ -161,4 +164,13 @@ public InputStream buildPDF(PDVisibleSignDesigner properties) throws IOException // return result of the stream return in; } + + private InputStream getVisualSignatureAsStream(COSDocument visualSignature) throws IOException + { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + COSWriter writer = new COSWriter(baos); + writer.write(visualSignature); + writer.close(); + return new ByteArrayInputStream(baos.toByteArray()); + } } diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDFTemplateStructure.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDFTemplateStructure.java index aa42423befa..7be3ad5c5f4 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDFTemplateStructure.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDFTemplateStructure.java @@ -61,7 +61,7 @@ public class PDFTemplateStructure private PDResources holderFormResources; private PDFormXObject holderForm; private PDAppearanceDictionary appearanceDictionary; - private PDStream innterFormStream; + private PDStream innerFormStream; private PDResources innerFormResources; private PDFormXObject innerForm; private PDStream imageFormStream; @@ -362,7 +362,7 @@ public void setAppearanceDictionary(PDAppearanceDictionary appearanceDictionary) */ public PDStream getInnerFormStream() { - return innterFormStream; + return innerFormStream; } /** @@ -371,7 +371,7 @@ public PDStream getInnerFormStream() */ public void setInnterFormStream(PDStream innerFormStream) { - this.innterFormStream = innerFormStream; + this.innerFormStream = innerFormStream; } /** @@ -567,12 +567,27 @@ public void setAcroFormFields(List acroFormFields) { this.acroFormFields = acroFormFields; } - - /** - * Gets AP of the created template - * @return the templates Appearance Stream - * @throws IOException - */ + + /** + * Returns the visual signature COSDocument as a stream and closes the template field + * PDDocument. + * + * @return the visual signature COSDocument as a stream + * @throws IOException + * @deprecated This will be removed in 2.1 because the method name is misleading and confusing, + * and the work done rather belongs into the calling class: + *
    +     * {@code
    +     * COSDocument visualSignature = structure.getVisualSignature();
    +     *  ByteArrayOutputStream baos = new ByteArrayOutputStream();
    +     *  COSWriter writer = new COSWriter(baos);
    +     *  writer.write(visualSignature);
    +     *  writer.close();
    +     *  structure.getTemplate().close();
    +     *  ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
    +     * } 
    + */ + @Deprecated public ByteArrayInputStream getTemplateAppearanceStream() throws IOException { COSDocument visualSignature = getVisualSignature(); From 3fd1a56d71a2144a4c0e69e6e4c65b0b2747b5af Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Wed, 20 Jul 2016 18:07:23 +0000 Subject: [PATCH 0235/2182] PDFBOX-3017: rename parameter names; improve javadoc git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1753588 13f79535-47bb-0310-9956-ffa450edef68 --- .../visible/PDVisibleSigBuilder.java | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDVisibleSigBuilder.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDVisibleSigBuilder.java index 87018dad256..13ccb84c4a7 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDVisibleSigBuilder.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDVisibleSigBuilder.java @@ -44,7 +44,8 @@ import org.apache.pdfbox.pdmodel.interactive.form.PDSignatureField; /** - * Implementation of {@link PDFTemplateBuilder}. + * Implementation of {@link PDFTemplateBuilder}. This builds the signature PDF but doesn't keep the + * elements, these are kept in its PDF template structure. * * @author Vakhtang Koroghlishvili */ @@ -54,7 +55,7 @@ public class PDVisibleSigBuilder implements PDFTemplateBuilder private static final Log log = LogFactory.getLog(PDVisibleSigBuilder.class); /** - * Constructor. + * Constructor, creates PDF template structure. */ public PDVisibleSigBuilder() { @@ -71,6 +72,13 @@ public void createPage(PDVisibleSignDesigner properties) log.info("PDF page has been created"); } + /** + * Creates a PDDocument and adds the page parameter to it and keeps this as a template in the + * PDF template Structure. + * + * @param page + * @throws IOException + */ @Override public void createTemplate(PDPage page) throws IOException { @@ -103,15 +111,15 @@ public void createSignatureField(PDAcroForm acroForm) throws IOException } @Override - public void createSignature(PDSignatureField pdSignatureField, PDPage page, - String signatureName) throws IOException + public void createSignature(PDSignatureField pdSignatureField, PDPage page, String signerName) + throws IOException { PDSignature pdSignature = new PDSignature(); PDAnnotationWidget widget = pdSignatureField.getWidgets().get(0); pdSignatureField.setValue(pdSignature); widget.setPage(page); page.getAnnotations().add(widget); - pdSignature.setName(signatureName); + pdSignature.setName(signerName); pdfStructure.setPdSignature(pdSignature); log.info("PDSignature has been created"); } From 0f6bb58d53aba3dec7b164dc727fb289211fc70f Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Wed, 20 Jul 2016 20:54:28 +0000 Subject: [PATCH 0236/2182] PDFBOX-3017: remove call that has no effect, add a TODO for later git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1753609 13f79535-47bb-0310-9956-ffa450edef68 --- .../pdfbox/examples/signature/CreateVisibleSignature.java | 2 +- .../digitalsignature/visible/PDFTemplateCreator.java | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateVisibleSignature.java b/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateVisibleSignature.java index 0965973da4e..2022c6e1ded 100644 --- a/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateVisibleSignature.java +++ b/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateVisibleSignature.java @@ -56,7 +56,7 @@ public void setvisibleSignDesigner(String filename, int x, int y, int zoomPercen throws IOException { visibleSignDesigner = new PDVisibleSignDesigner(filename, imageStream, page); - visibleSignDesigner.xAxis(x).yAxis(y).zoom(zoomPercent).signatureFieldName("signature"); + visibleSignDesigner.xAxis(x).yAxis(y).zoom(zoomPercent); } public void setVisibleSignatureProperties(String name, String location, String reason, int preferredSize, diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDFTemplateCreator.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDFTemplateCreator.java index 95bc44a4227..22826e0433c 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDFTemplateCreator.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDFTemplateCreator.java @@ -98,6 +98,10 @@ public InputStream buildPDF(PDVisibleSignDesigner properties) throws IOException PDSignatureField pdSignatureField = pdfStructure.getSignatureField(); // create signature + //TODO + // The line below has no effect with the CreateVisibleSignature example. + // The signature field is needed as a "holder" for the /AP tree, + // but the /P and /V PDSignatureField entries are ignored by PDDocument.addSignature pdfBuilder.createSignature(pdSignatureField, page, properties.getSignatureFieldName()); // that is /AcroForm/DR entry From 2a4fe26df41d69c442f242829b49e1f81daab706 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Wed, 20 Jul 2016 21:25:48 +0000 Subject: [PATCH 0237/2182] PDFBOX-2852: clarify javadoc git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1753612 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/pdfbox/text/TextPosition.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/text/TextPosition.java b/pdfbox/src/main/java/org/apache/pdfbox/text/TextPosition.java index 6831009f173..bd4778034de 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/text/TextPosition.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/text/TextPosition.java @@ -159,7 +159,9 @@ public TextPosition(int pageRotation, float pageWidth, float pageHeight, Matrix } /** - * Return the string of characters stored in this object. + * Return the string of characters stored in this object. The length can be different than the + * CharacterCodes length e.g. if ligatures are used ("fi", "fl", "ffl") where one glyph + * represents several unicode characters. * * @return The string on the screen. */ @@ -480,7 +482,7 @@ public float getYScale() /** * Get the widths of each individual character. * - * @return An array that is the same length as the length of the string. + * @return An array that has the same length as the CharacterCodes array. */ public float[] getIndividualWidths() { From e8b5ef7f895af8b4c338d2aebfe834b8d0065bd1 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Thu, 21 Jul 2016 16:09:57 +0000 Subject: [PATCH 0238/2182] PDFBOX-3433: add optimizations by Michael Doswald git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1753707 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/pdfbox/cos/COSStream.java | 13 ++++++- .../graphics/image/LosslessFactory.java | 39 ++++++++++++------- 2 files changed, 36 insertions(+), 16 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/cos/COSStream.java b/pdfbox/src/main/java/org/apache/pdfbox/cos/COSStream.java index d0aca00b878..eaeb9b5c987 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/cos/COSStream.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/cos/COSStream.java @@ -24,7 +24,6 @@ import java.io.OutputStream; import java.util.ArrayList; import java.util.List; - import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.pdfbox.filter.Filter; @@ -212,6 +211,12 @@ public OutputStream createOutputStream(COSBase filters) throws IOException isWriting = true; return new FilterOutputStream(cosOut) { + @Override + public void write(byte[] b, int off, int len) throws IOException + { + this.out.write(b, off, len); + } + @Override public void close() throws IOException { @@ -255,6 +260,12 @@ public OutputStream createRawOutputStream() throws IOException isWriting = true; return new FilterOutputStream(out) { + @Override + public void write(byte[] b, int off, int len) throws IOException + { + this.out.write(b, off, len); + } + @Override public void close() throws IOException { diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/LosslessFactory.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/LosslessFactory.java index b2a60a73eb5..daf0e135f7c 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/LosslessFactory.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/LosslessFactory.java @@ -15,7 +15,6 @@ */ package org.apache.pdfbox.pdmodel.graphics.image; -import java.awt.Color; import java.awt.Transparency; import java.awt.image.BufferedImage; import java.awt.image.WritableRaster; @@ -58,50 +57,59 @@ public static PDImageXObject createFromImage(PDDocument document, BufferedImage int bpc; PDDeviceColorSpace deviceColorSpace; - ByteArrayOutputStream bos = new ByteArrayOutputStream(); int height = image.getHeight(); int width = image.getWidth(); + int[] rgbLineBuffer = new int[width]; + byte[] imageData; if ((image.getType() == BufferedImage.TYPE_BYTE_GRAY && image.getColorModel().getPixelSize() <= 8) || (image.getType() == BufferedImage.TYPE_BYTE_BINARY && image.getColorModel().getPixelSize() == 1)) { - MemoryCacheImageOutputStream mcios = new MemoryCacheImageOutputStream(bos); - // grayscale images need one color per sample bpc = image.getColorModel().getPixelSize(); deviceColorSpace = PDDeviceGray.INSTANCE; + + ByteArrayOutputStream bos = new ByteArrayOutputStream((width*bpc/8)+(width*bpc%8 != 0 ? 1:0)*height); + MemoryCacheImageOutputStream mcios = new MemoryCacheImageOutputStream(bos); + for (int y = 0; y < height; ++y) { - for (int x = 0; x < width; ++x) + for (int pixel : image.getRGB(0, y, width, 1, rgbLineBuffer, 0, width)) { - mcios.writeBits(image.getRGB(x, y) & 0xFF, bpc); + mcios.writeBits(pixel & 0xFF, bpc); } - while (mcios.getBitOffset() != 0) + + int bitOffset = mcios.getBitOffset(); + if (bitOffset != 0) { - mcios.writeBit(0); + mcios.writeBits(0, 8-bitOffset); } } mcios.flush(); mcios.close(); + + imageData = bos.toByteArray(); } else { // RGB bpc = 8; deviceColorSpace = PDDeviceRGB.INSTANCE; + imageData = new byte[width*height*3]; + int byteIdx = 0; + for (int y = 0; y < height; ++y) { - for (int x = 0; x < width; ++x) + for (int pixel : image.getRGB(0, y, width, 1, rgbLineBuffer, 0, width)) { - Color color = new Color(image.getRGB(x, y)); - bos.write(color.getRed()); - bos.write(color.getGreen()); - bos.write(color.getBlue()); + imageData[byteIdx++] = (byte)((pixel >> 16) & 0xFF); + imageData[byteIdx++] = (byte)((pixel >> 8) & 0xFF); + imageData[byteIdx++] = (byte)(pixel & 0xFF); } } } - PDImageXObject pdImage = prepareImageXObject(document, bos.toByteArray(), + PDImageXObject pdImage = prepareImageXObject(document, imageData, image.getWidth(), image.getHeight(), bpc, deviceColorSpace); // alpha -> soft mask @@ -248,7 +256,8 @@ private static PDImageXObject prepareImageXObject(PDDocument document, byte [] byteArray, int width, int height, int bitsPerComponent, PDColorSpace initColorSpace) throws IOException { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); + //pre-size the output stream to half of the input + ByteArrayOutputStream baos = new ByteArrayOutputStream(byteArray.length/2); Filter filter = FilterFactory.INSTANCE.getFilter(COSName.FLATE_DECODE); filter.encode(new ByteArrayInputStream(byteArray), baos, new COSDictionary(), 0); From 15a116b7342523da53d5455f163c10e6f6e2f72b Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Thu, 21 Jul 2016 18:09:14 +0000 Subject: [PATCH 0239/2182] PDFBOX-3432: use bit arithmetic instead of modulo, by Michael Doswald git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1753718 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/fontbox/ttf/CmapSubtable.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/fontbox/src/main/java/org/apache/fontbox/ttf/CmapSubtable.java b/fontbox/src/main/java/org/apache/fontbox/ttf/CmapSubtable.java index 3eadfd68a85..2d086cd6efb 100644 --- a/fontbox/src/main/java/org/apache/fontbox/ttf/CmapSubtable.java +++ b/fontbox/src/main/java/org/apache/fontbox/ttf/CmapSubtable.java @@ -354,7 +354,7 @@ protected void processSubtype6(TTFDataStream data, int numGlyphs) throws IOExcep for (int i = 0; i < entryCount; i++) { tmpGlyphToChar.put(glyphIdArray[i], firstCode + i); - characterCodeToGlyphId.put((firstCode + i), glyphIdArray[i]); + characterCodeToGlyphId.put(firstCode + i, glyphIdArray[i]); } glyphIdToCharacterCode = newGlyphIdToCharacterCode(Collections.max(tmpGlyphToChar.keySet()) + 1); for (Entry entry : tmpGlyphToChar.entrySet()) @@ -401,7 +401,7 @@ protected void processSubtype4(TTFDataStream data, int numGlyphs) throws IOExcep { if (rangeOffset == 0) { - int glyphid = (j + delta) % 65536; + int glyphid = (j + delta) & 0xFFFF; tmpGlyphToChar.put(glyphid, j); characterCodeToGlyphId.put(j, glyphid); } @@ -414,8 +414,7 @@ protected void processSubtype4(TTFDataStream data, int numGlyphs) throws IOExcep int glyphIndex = data.readUnsignedShort(); if (glyphIndex != 0) { - glyphIndex += delta; - glyphIndex %= 65536; + glyphIndex = (glyphIndex + delta) & 0xFFFF; if (!tmpGlyphToChar.containsKey(glyphIndex)) { tmpGlyphToChar.put(glyphIndex, j); From 0b26f8f27b70dd39c0852b30d0b59f740e839e62 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Thu, 21 Jul 2016 18:13:51 +0000 Subject: [PATCH 0240/2182] PDFBOX-3432: optimize by avoiding calling Collections.max() + DRY refactoring, by Michael Doswald git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1753720 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/fontbox/ttf/CmapSubtable.java | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/fontbox/src/main/java/org/apache/fontbox/ttf/CmapSubtable.java b/fontbox/src/main/java/org/apache/fontbox/ttf/CmapSubtable.java index 2d086cd6efb..d309757e0ed 100644 --- a/fontbox/src/main/java/org/apache/fontbox/ttf/CmapSubtable.java +++ b/fontbox/src/main/java/org/apache/fontbox/ttf/CmapSubtable.java @@ -18,7 +18,6 @@ import java.io.IOException; import java.util.Arrays; -import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; @@ -351,17 +350,14 @@ protected void processSubtype6(TTFDataStream data, int numGlyphs) throws IOExcep Map tmpGlyphToChar = new HashMap(numGlyphs); characterCodeToGlyphId = new HashMap(numGlyphs); int[] glyphIdArray = data.readUnsignedShortArray(entryCount); + int maxGlyphId = 0; for (int i = 0; i < entryCount; i++) { + maxGlyphId = Math.max(maxGlyphId, glyphIdArray[i]); tmpGlyphToChar.put(glyphIdArray[i], firstCode + i); characterCodeToGlyphId.put(firstCode + i, glyphIdArray[i]); } - glyphIdToCharacterCode = newGlyphIdToCharacterCode(Collections.max(tmpGlyphToChar.keySet()) + 1); - for (Entry entry : tmpGlyphToChar.entrySet()) - { - // link the glyphId with the right character code - glyphIdToCharacterCode[entry.getKey()] = entry.getValue(); - } + buildGlyphIdToCharacterCodeLookup(tmpGlyphToChar, maxGlyphId); } /** @@ -386,6 +382,7 @@ protected void processSubtype4(TTFDataStream data, int numGlyphs) throws IOExcep Map tmpGlyphToChar = new HashMap(numGlyphs); characterCodeToGlyphId = new HashMap(numGlyphs); + int maxGlyphId = 0; long currentPosition = data.getCurrentPosition(); @@ -402,6 +399,7 @@ protected void processSubtype4(TTFDataStream data, int numGlyphs) throws IOExcep if (rangeOffset == 0) { int glyphid = (j + delta) & 0xFFFF; + maxGlyphId = Math.max(glyphid, maxGlyphId); tmpGlyphToChar.put(glyphid, j); characterCodeToGlyphId.put(j, glyphid); } @@ -417,6 +415,7 @@ protected void processSubtype4(TTFDataStream data, int numGlyphs) throws IOExcep glyphIndex = (glyphIndex + delta) & 0xFFFF; if (!tmpGlyphToChar.containsKey(glyphIndex)) { + maxGlyphId = Math.max(glyphIndex, maxGlyphId); tmpGlyphToChar.put(glyphIndex, j); characterCodeToGlyphId.put(j, glyphIndex); } @@ -435,7 +434,12 @@ protected void processSubtype4(TTFDataStream data, int numGlyphs) throws IOExcep LOG.warn("cmap format 4 subtable is empty"); return; } - glyphIdToCharacterCode = newGlyphIdToCharacterCode(Collections.max(tmpGlyphToChar.keySet()) + 1); + buildGlyphIdToCharacterCodeLookup(tmpGlyphToChar, maxGlyphId); + } + + private void buildGlyphIdToCharacterCodeLookup(Map tmpGlyphToChar, int maxGlyphId) + { + glyphIdToCharacterCode = newGlyphIdToCharacterCode(maxGlyphId + 1); for (Entry entry : tmpGlyphToChar.entrySet()) { // link the glyphId with the right character code From f719af023b5589fbe140c8573e4ed0f41a8f7493 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Thu, 21 Jul 2016 19:38:01 +0000 Subject: [PATCH 0241/2182] PDFBOX-2852: clarify javadoc git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1753726 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/fontbox/ttf/RAFDataStream.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/fontbox/src/main/java/org/apache/fontbox/ttf/RAFDataStream.java b/fontbox/src/main/java/org/apache/fontbox/ttf/RAFDataStream.java index aa7287ec1e2..b224ab9d2d5 100644 --- a/fontbox/src/main/java/org/apache/fontbox/ttf/RAFDataStream.java +++ b/fontbox/src/main/java/org/apache/fontbox/ttf/RAFDataStream.java @@ -65,10 +65,11 @@ class RAFDataStream extends TTFDataStream } /** - * Read an signed short. + * Read a signed short. * * @return An signed short. * @throws IOException If there is an error reading the data. + * @see RandomAccessFile#readShort() */ @Override public short readSignedShort() throws IOException @@ -103,6 +104,7 @@ public void close() throws IOException * Read an unsigned byte. * @return An unsigned byte. * @throws IOException If there is an error reading the data. + * @see RandomAccessFile#read() */ @Override public int read() throws IOException @@ -115,6 +117,7 @@ public int read() throws IOException * * @return An unsigned short. * @throws IOException If there is an error reading the data. + * @see RandomAccessFile#readUnsignedShort() */ @Override public int readUnsignedShort() throws IOException @@ -123,9 +126,11 @@ public int readUnsignedShort() throws IOException } /** - * Read an unsigned byte. - * @return An unsigned byte. + * Read a signed 64-bit integer. + * + * @return eight bytes interpreted as a long. * @throws IOException If there is an error reading the data. + * @see RandomAccessFile#readLong() */ @Override public long readLong() throws IOException From 6f3cfa3a2aa20e8e73c9da2058d956f9135429d3 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Fri, 22 Jul 2016 18:15:22 +0000 Subject: [PATCH 0242/2182] PDFBOX-2941: add status bar git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1753826 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/pdfbox/debugger/PDFDebugger.java | 9 ++++++++- .../org/apache/pdfbox/debugger/pagepane/PagePane.java | 10 ++++++++-- .../apache/pdfbox/debugger/ui/ReaderBottomPanel.java | 2 +- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/debugger/src/main/java/org/apache/pdfbox/debugger/PDFDebugger.java b/debugger/src/main/java/org/apache/pdfbox/debugger/PDFDebugger.java index de613def59d..748b487c59e 100644 --- a/debugger/src/main/java/org/apache/pdfbox/debugger/PDFDebugger.java +++ b/debugger/src/main/java/org/apache/pdfbox/debugger/PDFDebugger.java @@ -95,6 +95,7 @@ import org.apache.pdfbox.debugger.ui.PDFTreeCellRenderer; import org.apache.pdfbox.debugger.ui.PDFTreeModel; import org.apache.pdfbox.debugger.ui.PageEntry; +import org.apache.pdfbox.debugger.ui.ReaderBottomPanel; import org.apache.pdfbox.debugger.ui.RecentFiles; import org.apache.pdfbox.debugger.ui.RotationMenu; import org.apache.pdfbox.debugger.ui.Tree; @@ -139,6 +140,7 @@ public class PDFDebugger extends JFrame private JScrollPane jScrollPane2; private javax.swing.JSplitPane jSplitPane1; private javax.swing.JTextPane jTextPane1; + private ReaderBottomPanel statusBar; private Tree tree; private final JPanel documentPanel = new JPanel(); @@ -237,6 +239,9 @@ public void valueChanged(TreeSelectionEvent evt) getContentPane().add(jSplitPane1, BorderLayout.CENTER); + statusBar = new ReaderBottomPanel(); + getContentPane().add(statusBar, BorderLayout.SOUTH); + // create menus JMenuBar menuBar = new JMenuBar(); menuBar.add(createFileMenu()); @@ -603,6 +608,8 @@ private void jTree1ValueChanged(TreeSelectionEvent evt) { Object selectedNode = path.getLastPathComponent(); + statusBar.getStatusLabel().setText(""); + if (isPage(selectedNode)) { showPage(selectedNode); @@ -826,7 +833,7 @@ private void showPage(Object selectedNode) COSBase typeItem = page.getItem(COSName.TYPE); if (COSName.PAGE.equals(typeItem)) { - PagePane pagePane = new PagePane(document, page); + PagePane pagePane = new PagePane(document, page, statusBar.getStatusLabel()); replaceRightComponent(new JScrollPane(pagePane.getPanel())); } } diff --git a/debugger/src/main/java/org/apache/pdfbox/debugger/pagepane/PagePane.java b/debugger/src/main/java/org/apache/pdfbox/debugger/pagepane/PagePane.java index 94300c215b9..7df280d6e80 100644 --- a/debugger/src/main/java/org/apache/pdfbox/debugger/pagepane/PagePane.java +++ b/debugger/src/main/java/org/apache/pdfbox/debugger/pagepane/PagePane.java @@ -53,12 +53,14 @@ public class PagePane implements ActionListener, AncestorListener private JLabel label; private ZoomMenu zoomMenu; private RotationMenu rotationMenu; + private final JLabel statuslabel; - public PagePane(PDDocument document, COSDictionary page) + public PagePane(PDDocument document, COSDictionary page, JLabel statuslabel) { PDPage pdPage = new PDPage(page); pageIndex = document.getPages().indexOf(pdPage); this.document = document; + this.statuslabel = statuslabel; initUI(); } @@ -151,9 +153,13 @@ private RenderWorker(float scale, int rotation) protected BufferedImage doInBackground() throws IOException { label.setIcon(null); - label.setText("Loading..."); + label.setText("Rendering..."); PDFRenderer renderer = new PDFRenderer(document); + long t0 = System.currentTimeMillis(); + statuslabel.setText("Rendering..."); BufferedImage bim = renderer.renderImage(pageIndex, scale); + float t = ((System.currentTimeMillis() - t0) / 1000f); + statuslabel.setText("Rendered in " + t + " second" + (t > 1 ? "s" : "")); return ImageUtil.getRotatedImage(bim, rotation); } diff --git a/debugger/src/main/java/org/apache/pdfbox/debugger/ui/ReaderBottomPanel.java b/debugger/src/main/java/org/apache/pdfbox/debugger/ui/ReaderBottomPanel.java index d5f6f774d67..553b30e16d4 100644 --- a/debugger/src/main/java/org/apache/pdfbox/debugger/ui/ReaderBottomPanel.java +++ b/debugger/src/main/java/org/apache/pdfbox/debugger/ui/ReaderBottomPanel.java @@ -40,7 +40,7 @@ public ReaderBottomPanel() FlowLayout flowLayout = new FlowLayout(); this.setLayout(flowLayout); this.setComponentOrientation(java.awt.ComponentOrientation.LEFT_TO_RIGHT); - this.setPreferredSize(new Dimension(1000, 20)); + this.setPreferredSize(new Dimension(1000, 24)); flowLayout.setAlignment(FlowLayout.LEFT); statusLabel = new JLabel(); statusLabel.setText("Ready"); From 2a38e944c5da47df6140d63ca2a71148bf071864 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Sat, 23 Jul 2016 14:36:24 +0000 Subject: [PATCH 0243/2182] PDFBOX-2941: show PDF coordinates git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1753875 13f79535-47bb-0310-9956-ffa450edef68 --- .../pdfbox/debugger/pagepane/PagePane.java | 78 ++++++++++++++++++- 1 file changed, 76 insertions(+), 2 deletions(-) diff --git a/debugger/src/main/java/org/apache/pdfbox/debugger/pagepane/PagePane.java b/debugger/src/main/java/org/apache/pdfbox/debugger/pagepane/PagePane.java index 7df280d6e80..152ac7ea85e 100644 --- a/debugger/src/main/java/org/apache/pdfbox/debugger/pagepane/PagePane.java +++ b/debugger/src/main/java/org/apache/pdfbox/debugger/pagepane/PagePane.java @@ -21,6 +21,9 @@ import java.awt.Font; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionListener; import java.awt.image.BufferedImage; import java.io.IOException; import java.util.concurrent.ExecutionException; @@ -45,7 +48,7 @@ * @author Tilman Hausherr * @author John Hewson */ -public class PagePane implements ActionListener, AncestorListener +public class PagePane implements ActionListener, AncestorListener, MouseMotionListener, MouseListener { private JPanel panel; private int pageIndex = -1; @@ -54,11 +57,14 @@ public class PagePane implements ActionListener, AncestorListener private ZoomMenu zoomMenu; private RotationMenu rotationMenu; private final JLabel statuslabel; + private final float height, width; public PagePane(PDDocument document, COSDictionary page, JLabel statuslabel) { PDPage pdPage = new PDPage(page); pageIndex = document.getPages().indexOf(pdPage); + height = pdPage.getCropBox().getHeight(); + width = pdPage.getCropBox().getWidth(); this.document = document; this.statuslabel = statuslabel; initUI(); @@ -78,6 +84,8 @@ private void initUI() panel.add(pageLabel); label = new JLabel(); + label.addMouseMotionListener(this); + label.addMouseListener(this); label.setBackground(panel.getBackground()); label.setAlignmentX(Component.CENTER_ALIGNMENT); panel.add(label); @@ -135,6 +143,72 @@ public void ancestorMoved(AncestorEvent ancestorEvent) { } + @Override + public void mouseDragged(MouseEvent e) + { + } + + /** + * Catch mouse event to display cursor position in PDF coordinates in the status bar. + * + * @param e mouse event with position + */ + @Override + public void mouseMoved(MouseEvent e) + { + float zoomScale = zoomMenu.getPageZoomScale(); + float x = e.getX() / zoomScale; + float y = e.getY() / zoomScale; + int x1, y1; + switch (RotationMenu.getRotationDegrees()) + { + case 0: + default: + x1 = (int) x; + y1 = (int) (height - y); + break; + case 90: + x1 = (int) y; + y1 = (int) x; + break; + case 180: + x1 = (int) (width - x); + y1 = (int) y; + break; + case 270: + x1 = (int) (width - y); + y1 = (int) (height - x); + break; + } + statuslabel.setText(x1 + "," + y1); + } + + @Override + public void mouseClicked(MouseEvent e) + { + } + + @Override + public void mousePressed(MouseEvent e) + { + } + + @Override + public void mouseReleased(MouseEvent e) + { + } + + @Override + public void mouseEntered(MouseEvent e) + { + } + + @Override + public void mouseExited(MouseEvent e) + { + statuslabel.setText(""); + } + /** * Note that PDDocument is not officially thread safe, caution advised. */ @@ -158,7 +232,7 @@ protected BufferedImage doInBackground() throws IOException long t0 = System.currentTimeMillis(); statuslabel.setText("Rendering..."); BufferedImage bim = renderer.renderImage(pageIndex, scale); - float t = ((System.currentTimeMillis() - t0) / 1000f); + float t = (System.currentTimeMillis() - t0) / 1000f; statuslabel.setText("Rendered in " + t + " second" + (t > 1 ? "s" : "")); return ImageUtil.getRotatedImage(bim, rotation); } From 2671d379614b97fd011957248d9fa3ad348e80f7 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Mon, 25 Jul 2016 16:00:33 +0000 Subject: [PATCH 0244/2182] PDFBOX-2941: include cropbox and /Rotate value to PDF coordinate calculation git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1754032 13f79535-47bb-0310-9956-ffa450edef68 --- .../pdfbox/debugger/pagepane/PagePane.java | 38 ++++++++++--------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/debugger/src/main/java/org/apache/pdfbox/debugger/pagepane/PagePane.java b/debugger/src/main/java/org/apache/pdfbox/debugger/pagepane/PagePane.java index 152ac7ea85e..71950e24072 100644 --- a/debugger/src/main/java/org/apache/pdfbox/debugger/pagepane/PagePane.java +++ b/debugger/src/main/java/org/apache/pdfbox/debugger/pagepane/PagePane.java @@ -57,14 +57,12 @@ public class PagePane implements ActionListener, AncestorListener, MouseMotionLi private ZoomMenu zoomMenu; private RotationMenu rotationMenu; private final JLabel statuslabel; - private final float height, width; + private final PDPage page; - public PagePane(PDDocument document, COSDictionary page, JLabel statuslabel) + public PagePane(PDDocument document, COSDictionary pageDict, JLabel statuslabel) { - PDPage pdPage = new PDPage(page); - pageIndex = document.getPages().indexOf(pdPage); - height = pdPage.getCropBox().getHeight(); - width = pdPage.getCropBox().getWidth(); + page = new PDPage(pageDict); + pageIndex = document.getPages().indexOf(page); this.document = document; this.statuslabel = statuslabel; initUI(); @@ -156,28 +154,32 @@ public void mouseDragged(MouseEvent e) @Override public void mouseMoved(MouseEvent e) { + float height = page.getCropBox().getHeight(); + float width = page.getCropBox().getWidth(); + float offsetX = page.getCropBox().getLowerLeftX(); + float offsetY = page.getCropBox().getLowerLeftY(); float zoomScale = zoomMenu.getPageZoomScale(); float x = e.getX() / zoomScale; float y = e.getY() / zoomScale; int x1, y1; - switch (RotationMenu.getRotationDegrees()) + switch ((RotationMenu.getRotationDegrees() + page.getRotation()) % 360) { - case 0: - default: - x1 = (int) x; - y1 = (int) (height - y); - break; case 90: - x1 = (int) y; - y1 = (int) x; + x1 = (int) (y + offsetX); + y1 = (int) (x + offsetY); break; case 180: - x1 = (int) (width - x); - y1 = (int) y; + x1 = (int) (width - x + offsetX); + y1 = (int) (y - offsetY); break; case 270: - x1 = (int) (width - y); - y1 = (int) (height - x); + x1 = (int) (width - y + offsetX); + y1 = (int) (height - x + offsetY); + break; + case 0: + default: + x1 = (int) (x + offsetX); + y1 = (int) (height - y + offsetY); break; } statuslabel.setText(x1 + "," + y1); From 4c20ad301aa372b1c03457120d88b0042c5587cc Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Wed, 27 Jul 2016 20:11:03 +0000 Subject: [PATCH 0245/2182] PDFBOX-3439: avoid another exception if seconds are missing, which is valid ISO8601 but not xsd:datetime; improve error message git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1754339 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/xmpbox/DateConverter.java | 21 +++++++++++-------- .../org/apache/xmpbox/type/TypeMapping.java | 18 ++++++++-------- .../org/apache/xmpbox/DateConverterTest.java | 2 ++ 3 files changed, 23 insertions(+), 18 deletions(-) diff --git a/xmpbox/src/main/java/org/apache/xmpbox/DateConverter.java b/xmpbox/src/main/java/org/apache/xmpbox/DateConverter.java index 9b5b50c3968..7e9a4cbd687 100644 --- a/xmpbox/src/main/java/org/apache/xmpbox/DateConverter.java +++ b/xmpbox/src/main/java/org/apache/xmpbox/DateConverter.java @@ -365,20 +365,23 @@ private static Calendar fromISO8601(String dateString) if (timeZoneString != null) { - - Calendar cal = javax.xml.bind.DatatypeConverter.parseDateTime( - dateString.substring(0, dateString.indexOf(timeZoneString)) - ); - + // can't use parseDateTime immediately, first do handling for time that has no seconds + int teeIndex = dateString.indexOf('T'); + int tzIndex = dateString.indexOf(timeZoneString); + String toParse = dateString.substring(0, tzIndex); + if (tzIndex - teeIndex == 6) + { + toParse = dateString.substring(0, tzIndex) + ":00"; + } + Calendar cal = javax.xml.bind.DatatypeConverter.parseDateTime(toParse); + TimeZone z = TimeZone.getTimeZone(timeZoneString); - cal.setTimeZone(z); - + cal.setTimeZone(z); return cal; } else { - // can't use parseDateTime immediately, - // first do handling for time that has no seconds + // can't use parseDateTime immediately, first do handling for time that has no seconds int teeIndex = dateString.indexOf('T'); if (teeIndex == -1) { diff --git a/xmpbox/src/main/java/org/apache/xmpbox/type/TypeMapping.java b/xmpbox/src/main/java/org/apache/xmpbox/type/TypeMapping.java index 15e16579a08..e71818ac409 100644 --- a/xmpbox/src/main/java/org/apache/xmpbox/type/TypeMapping.java +++ b/xmpbox/src/main/java/org/apache/xmpbox/type/TypeMapping.java @@ -176,40 +176,40 @@ public AbstractSimpleProperty instanciateSimpleProperty(String nsuri, String pre // constructor parameters Object[] params = new Object[] { metadata, nsuri, prefix, name, value }; // type + Class clz = + type.getImplementingClass().asSubclass(AbstractSimpleProperty.class); try { - Class clz = type.getImplementingClass().asSubclass( - AbstractSimpleProperty.class); Constructor cons = clz.getConstructor(SIMPLEPROPERTYCONSTPARAMS); return cons.newInstance(params); } catch (NoSuchMethodError e) { - throw new IllegalArgumentException("Failed to instanciate property", e); + throw new IllegalArgumentException("Failed to instanciate " + clz.getSimpleName() + " property with value " + value, e); } catch (IllegalArgumentException e) { - throw new IllegalArgumentException("Failed to instanciate property", e); + throw new IllegalArgumentException("Failed to instanciate " + clz.getSimpleName() + " property with value " + value, e); } catch (InstantiationException e) { - throw new IllegalArgumentException("Failed to instanciate property", e); + throw new IllegalArgumentException("Failed to instanciate " + clz.getSimpleName() + " property with value " + value, e); } catch (IllegalAccessException e) { - throw new IllegalArgumentException("Failed to instanciate property", e); + throw new IllegalArgumentException("Failed to instanciate " + clz.getSimpleName() + " property with value " + value, e); } catch (InvocationTargetException e) { - throw new IllegalArgumentException("Failed to instanciate property", e); + throw new IllegalArgumentException("Failed to instanciate " + clz.getSimpleName() + " property with value " + value, e); } catch (SecurityException e) { - throw new IllegalArgumentException("Failed to instanciate property", e); + throw new IllegalArgumentException("Failed to instanciate " + clz.getSimpleName() + " property with value " + value, e); } catch (NoSuchMethodException e) { - throw new IllegalArgumentException("Failed to instanciate property", e); + throw new IllegalArgumentException("Failed to instanciate " + clz.getSimpleName() + " property with value " + value, e); } } diff --git a/xmpbox/src/test/java/org/apache/xmpbox/DateConverterTest.java b/xmpbox/src/test/java/org/apache/xmpbox/DateConverterTest.java index a63ec8712fb..ec7c8a01398 100644 --- a/xmpbox/src/test/java/org/apache/xmpbox/DateConverterTest.java +++ b/xmpbox/src/test/java/org/apache/xmpbox/DateConverterTest.java @@ -57,6 +57,8 @@ public void testDateConversion() throws Exception //Test missing seconds assertEquals(DateConverter.toCalendar("2015-12-08T12:07:00-05:00"), DateConverter.toCalendar("2015-12-08T12:07-05:00")); + assertEquals(DateConverter.toCalendar("2011-11-20T10:09:00Z"), + DateConverter.toCalendar("2011-11-20T10:09Z")); // Test some time zone offsets jaxbCal = javax.xml.bind.DatatypeConverter.parseDateTime("2015-02-02T16:37:19.192Z"); From 502a6c12e0ee4dbd9e959ea823653402faf14c29 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Thu, 28 Jul 2016 16:35:20 +0000 Subject: [PATCH 0246/2182] PDFBOX-3441: use long instead of int to handle huge files, as suggested by Michael Doswald git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1754431 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/pdfbox/pdfparser/COSParser.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/COSParser.java b/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/COSParser.java index 51ad3267ecd..0905e5e4a8a 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/COSParser.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/COSParser.java @@ -324,7 +324,7 @@ private long parseXrefObjStream(long objByteOffset, boolean isStandalone) throws COSDictionary dict = parseCOSDictionary(); COSStream xrefStream = parseCOSStream(dict); - parseXrefStream(xrefStream, (int) objByteOffset, isStandalone); + parseXrefStream(xrefStream, objByteOffset, isStandalone); xrefStream.close(); return dict.getLong(COSName.PREV); @@ -2002,7 +2002,7 @@ protected boolean parseXrefTable(long startByteOffset) throws IOException { try { - int currOffset = Integer.parseInt(splitString[0]); + long currOffset = Long.parseLong(splitString[0]); int currGenID = Integer.parseInt(splitString[1]); COSObjectKey objKey = new COSObjectKey(currObjID, currGenID); xrefTrailerResolver.setXRef(objKey, currOffset); From e479ce312620a6a1bbab12c77f3578543ea13123 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Mon, 1 Aug 2016 17:05:00 +0000 Subject: [PATCH 0247/2182] PDFBOX-3428: avoid inherited rotation, mediabox and cropbox from getting lost git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1754777 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/pdfbox/pdmodel/PDDocument.java | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java index 2aee7e88773..ab4824a9fa6 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java @@ -501,13 +501,17 @@ public void removePage(int pageNumber) /** * This will import and copy the contents from another location. Currently the content stream is stored in a scratch * file. The scratch file is associated with the document. If you are adding a page to this document from another - * document and want to copy the contents to this document's scratch file then use this method otherwise just use - * the {@link #addPage} method. - * - * Unlike {@link #addPage}, this method does a deep copy. If your page has annotations, and if - * these link to pages not in the target document, then the target document might become huge. - * What you need to do is to delete page references of such annotations. See + * document and want to copy the contents to this + * document's scratch file then use this method otherwise just use the {@link #addPage addPage} + * method. + *

    + * Unlike {@link #addPage addPage}, this method creates a new PDPage object. If your page has + * annotations, and if these link to pages not in the target document, then the target document + * might become huge. What you need to do is to delete page references of such annotations. See * here for how to do this. + *

    + * Inherited (global) resources are ignored. If you need them, call + * importedPage.setRotation(page.getRotation()); * * @param page The page to import. * @return The page that was imported. @@ -532,6 +536,14 @@ public PDPage importPage(PDPage page) throws IOException { IOUtils.closeQuietly(in); } + importedPage.setCropBox(page.getCropBox()); + importedPage.setMediaBox(page.getMediaBox()); + importedPage.setRotation(page.getRotation()); + if (page.getResources() != null && !page.getCOSObject().containsKey(COSName.RESOURCES)) + { + LOG.warn("inherited resources of source document are not imported to destination page"); + LOG.warn("call importedPage.setResources(page.getResources()) to do this"); + } return importedPage; } From b8c0cbde9f80ae02e4bcb63b5937c348de3f6b5a Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Mon, 1 Aug 2016 17:06:16 +0000 Subject: [PATCH 0248/2182] PDFBOX-3428: remove calls that are now done in importPage git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1754780 13f79535-47bb-0310-9956-ffa450edef68 --- pdfbox/src/main/java/org/apache/pdfbox/multipdf/Splitter.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/multipdf/Splitter.java b/pdfbox/src/main/java/org/apache/pdfbox/multipdf/Splitter.java index 2187d20a5b9..130b63c8c3a 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/multipdf/Splitter.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/multipdf/Splitter.java @@ -204,11 +204,7 @@ protected void processPage(PDPage page) throws IOException createNewDocumentIfNecessary(); PDPage imported = getDestinationDocument().importPage(page); - imported.setCropBox(page.getCropBox()); - imported.setMediaBox(page.getMediaBox()); - // only the resources of the page will be copied imported.setResources(page.getResources()); - imported.setRotation(page.getRotation()); // remove page links to avoid copying not needed resources processAnnotations(imported); } From c07966450bd177c2526fa9ba881f150075e2da8a Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Mon, 1 Aug 2016 20:18:03 +0000 Subject: [PATCH 0249/2182] PDFBOX-3446: avoid /Prev loop git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1754795 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/pdfbox/pdfparser/COSParser.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/COSParser.java b/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/COSParser.java index 0905e5e4a8a..4bd06110a81 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/COSParser.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/COSParser.java @@ -208,8 +208,10 @@ protected COSDictionary parseXref(long startXRefOffset) throws IOException document.setStartXref(startXrefOffset); long prev = startXrefOffset; // ---- parse whole chain of xref tables/object streams using PREV reference - while (prev > 0) + long lastPrev = -1; + while (prev > 0 && prev != lastPrev) { + lastPrev = prev; // seek to xref table source.seek(prev); @@ -298,6 +300,11 @@ protected COSDictionary parseXref(long startXRefOffset) throws IOException } } } + if (prev == lastPrev) + { + //TODO better idea needed? PDFBOX-3446 + throw new IOException("/Prev loop at offset " + prev); + } // ---- build valid xrefs out of the xref chain xrefTrailerResolver.setStartxref(startXrefOffset); COSDictionary trailer = xrefTrailerResolver.getTrailer(); @@ -745,7 +752,7 @@ private void parseFileObject(Long offsetOrObjstmObNr, final COSObjectKey objKey, { throw new IOException("XREF for " + objKey.getNumber() + ":" + objKey.getGeneration() + " points to wrong object: " + readObjNr - + ":" + readObjGen); + + ":" + readObjGen + " at offset " + offsetOrObjstmObNr); } skipSpaces(); @@ -1204,7 +1211,7 @@ private long checkXRefStreamOffset(long startXRefOffset, boolean checkOnly) thro // seek to offset-1 source.seek(startXRefOffset-1); int nextValue = source.read(); - // the first character has to be whitespace(s), and then a digit + // the first character has to be a whitespace, and then a digit if (isWhitespace(nextValue)) { skipSpaces(); From 66dd2e4c973df8ddf441eddac8327ecfabd5c429 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Tue, 2 Aug 2016 15:43:19 +0000 Subject: [PATCH 0250/2182] PDFBOX-3450: avoid ArrayIndexOutOfBoundsException if token is empty git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1754962 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/fontbox/cmap/CMapParser.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/fontbox/src/main/java/org/apache/fontbox/cmap/CMapParser.java b/fontbox/src/main/java/org/apache/fontbox/cmap/CMapParser.java index c79455effc2..010f9d09752 100644 --- a/fontbox/src/main/java/org/apache/fontbox/cmap/CMapParser.java +++ b/fontbox/src/main/java/org/apache/fontbox/cmap/CMapParser.java @@ -375,6 +375,11 @@ private void parseBeginbfrange(Object previousToken, PushbackInputStream cmapStr { tokenBytes = (byte[]) nextToken; } + if (tokenBytes.length == 0) + { + // PDFBOX-3450: ignore <> + continue; + } boolean done = false; int arrayIndex = 0; From 4425afd766d25b5275ee3a0698009c65fade3e0c Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Tue, 2 Aug 2016 16:07:26 +0000 Subject: [PATCH 0251/2182] PDFBOX-3448: avoid NullPointerException for null elements git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1754968 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/pdfbox/pdmodel/common/COSArrayList.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/COSArrayList.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/COSArrayList.java index 73c1aa5785c..7623d42994b 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/COSArrayList.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/COSArrayList.java @@ -291,10 +291,18 @@ public static List convertFloatCOSArrayToList( COSArray floatArray ) List retval = null; if( floatArray != null ) { - List numbers = new ArrayList(); + List numbers = new ArrayList(floatArray.size()); for( int i=0; i( numbers, floatArray ); } From a29b137e88fd90d9b5dea508e4fd61274b620ea5 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Tue, 2 Aug 2016 16:12:12 +0000 Subject: [PATCH 0252/2182] PDFBOX-3448: convert null elements of /WIDTHS array to 0 git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1754971 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/pdfbox/pdmodel/font/PDFont.java | 4 ++++ .../main/java/org/apache/pdfbox/pdmodel/font/PDType3Font.java | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDFont.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDFont.java index c0ff535db65..b3c47e35562 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDFont.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDFont.java @@ -249,6 +249,10 @@ public float getWidth(int code) throws IOException if (siz > 0 && code >= firstChar && code <= lastChar && idx < siz) { width = getWidths().get(idx); + if (width == null) + { + width = 0f; + } codeToWidthMap.put(code, width); return width; } diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType3Font.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType3Font.java index 2a9bf0eb31f..5c50b66d247 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType3Font.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType3Font.java @@ -118,7 +118,8 @@ public float getWidth(int code) throws IOException int lastChar = dict.getInt(COSName.LAST_CHAR, -1); if (getWidths().size() > 0 && code >= firstChar && code <= lastChar) { - return getWidths().get(code - firstChar); + Float w = getWidths().get(code - firstChar); + return w == null ? 0 : w; } else { From 6c1064002ede5206998e8db7bb02fbe367237c0c Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Tue, 2 Aug 2016 16:38:29 +0000 Subject: [PATCH 0253/2182] PDFBOX-3447: avoid XStep / YStep >= 32767 git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1754977 13f79535-47bb-0310-9956-ffa450edef68 --- .../pdfbox/pdmodel/graphics/pattern/PDTilingPattern.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/pattern/PDTilingPattern.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/pattern/PDTilingPattern.java index ce866f8c8fc..abf75a52595 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/pattern/PDTilingPattern.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/pattern/PDTilingPattern.java @@ -126,7 +126,7 @@ public float getXStep() { // ignores invalid values, see PDFBOX-1094-065514-XStep32767.pdf float xStep = getCOSObject().getFloat( COSName.X_STEP, 0 ); - return xStep == Short.MAX_VALUE ? 0 : xStep; + return xStep >= Short.MAX_VALUE ? 0 : xStep; } /** @@ -146,7 +146,7 @@ public float getYStep() { // ignores invalid values, see PDFBOX-1094-065514-XStep32767.pdf float yStep = getCOSObject().getFloat( COSName.Y_STEP, 0 ); - return yStep == Short.MAX_VALUE ? 0 : yStep; + return yStep >= Short.MAX_VALUE ? 0 : yStep; } public PDStream getContentStream() From 3dc04c873d4d55c96e4070a3ed8238b9b6a72cc7 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Wed, 3 Aug 2016 16:05:16 +0000 Subject: [PATCH 0254/2182] PDFBOX-3306: only stretch to fit when enabled git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1755093 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/pdfbox/printing/PDFPrintable.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/printing/PDFPrintable.java b/pdfbox/src/main/java/org/apache/pdfbox/printing/PDFPrintable.java index f9480ed0744..d77f29155c4 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/printing/PDFPrintable.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/printing/PDFPrintable.java @@ -148,6 +148,12 @@ public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) { scale = 1; } + + // only stretch to fit when enabled + if (scale < 1 && scaling == Scaling.STRETCH_TO_FIT) + { + scale = 1; + } } // set the graphics origin to the origin of the imageable area (i.e the margins) From 1af5fc9a2f408424f6f8772536c497660273266a Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Wed, 3 Aug 2016 16:07:48 +0000 Subject: [PATCH 0255/2182] PDFBOX-3306: apply scale on temp image size git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1755095 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/pdfbox/printing/PDFPrintable.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/printing/PDFPrintable.java b/pdfbox/src/main/java/org/apache/pdfbox/printing/PDFPrintable.java index d77f29155c4..c4a8f710d1e 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/printing/PDFPrintable.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/printing/PDFPrintable.java @@ -172,8 +172,8 @@ public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) if (dpi > 0) { float dpiScale = dpi / 72; - image = new BufferedImage((int)(imageableWidth * dpiScale), - (int)(imageableHeight * dpiScale), + image = new BufferedImage((int)(imageableWidth * dpiScale / scale), + (int)(imageableHeight * dpiScale / scale), BufferedImage.TYPE_INT_ARGB); printerGraphics = graphics2D; From a54764b5dbe246bcd2789b7bfa5c4667362bdbb1 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Wed, 3 Aug 2016 18:38:23 +0000 Subject: [PATCH 0256/2182] PDFBOX-2852: avoid unchecked exceptions git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1755103 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/fontbox/cff/CFFParser.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/fontbox/src/main/java/org/apache/fontbox/cff/CFFParser.java b/fontbox/src/main/java/org/apache/fontbox/cff/CFFParser.java index e579e8f0ecc..94b12becddd 100644 --- a/fontbox/src/main/java/org/apache/fontbox/cff/CFFParser.java +++ b/fontbox/src/main/java/org/apache/fontbox/cff/CFFParser.java @@ -217,6 +217,12 @@ private static String[] readStringIndexData(CFFDataInput input) throws IOExcepti for (int i = 0; i < count; i++) { int length = offsets[i + 1] - offsets[i]; + if (length < 0) + { + throw new IOException("Negative index data length + " + length + " at " + + i + ": offsets[" + (i + 1) + "]=" + offsets[i + 1] + + ", offsets[" + i + "]=" + offsets[i]); + } indexDataValues[i] = new String(input.readBytes(length), Charsets.ISO_8859_1); } return indexDataValues; @@ -1113,19 +1119,19 @@ public Entry getEntry(String name) public Boolean getBoolean(String name, boolean defaultValue) { Entry entry = getEntry(name); - return entry != null ? entry.getBoolean(0) : defaultValue; + return entry != null && entry.getArray().size() > 0 ? entry.getBoolean(0) : defaultValue; } public List getArray(String name, List defaultValue) { Entry entry = getEntry(name); - return entry != null ? entry.getArray() : defaultValue; + return entry != null && entry.getArray().size() > 0 ? entry.getArray() : defaultValue; } public Number getNumber(String name, Number defaultValue) { Entry entry = getEntry(name); - return entry != null ? entry.getNumber(0) : defaultValue; + return entry != null && entry.getArray().size() > 0 ? entry.getNumber(0) : defaultValue; } /** From 7c3ad00e87dcc7f70a194866318deab40a5dd6fa Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Wed, 3 Aug 2016 18:57:25 +0000 Subject: [PATCH 0257/2182] PDFBOX-2852: simplify code git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1755107 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/fontbox/cff/Type2CharString.java | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/fontbox/src/main/java/org/apache/fontbox/cff/Type2CharString.java b/fontbox/src/main/java/org/apache/fontbox/cff/Type2CharString.java index 8dbc63a1b9f..b8c5e6f8d7c 100644 --- a/fontbox/src/main/java/org/apache/fontbox/cff/Type2CharString.java +++ b/fontbox/src/main/java/org/apache/fontbox/cff/Type2CharString.java @@ -256,14 +256,14 @@ private List clearStack(List numbers, boolean flag) { if (flag) { - addCommand(asNumberList(0f, numbers.get(0).floatValue() + nominalWidthX), + addCommand(Arrays.asList((Number) 0f, numbers.get(0).floatValue() + nominalWidthX), new CharStringCommand(13)); numbers = numbers.subList(1, numbers.size()); - } + } else { - addCommand(asNumberList(0f, defWidthX), - new CharStringCommand(13)); + addCommand(Arrays.asList((Number) 0f, defWidthX), + new CharStringCommand(13)); } } return numbers; @@ -374,16 +374,6 @@ private void addCommand(List numbers, CharStringCommand command) type1Sequence.add(command); } - private List asNumberList(Float... a) - { - List list = new ArrayList(a.length); - for(int i = 0; i < a.length; i++) - { - list.add(a[i]); - } - return list; - } - private static List> split(List list, int size) { List> result = new ArrayList>(); From d136a47ace948f341daa8f56d2305c22fac36b8b Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Thu, 4 Aug 2016 16:17:56 +0000 Subject: [PATCH 0258/2182] PDFBOX-3435: use CapHeight when glyphHeight is 0 git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1755202 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/pdfbox/text/PDFTextStreamEngine.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/text/PDFTextStreamEngine.java b/pdfbox/src/main/java/org/apache/pdfbox/text/PDFTextStreamEngine.java index ac4135238c6..4583e8ccd55 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/text/PDFTextStreamEngine.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/text/PDFTextStreamEngine.java @@ -168,7 +168,7 @@ protected void showGlyph(Matrix textRenderingMatrix, PDFont font, int code, Stri if (fontDescriptor != null) { float capHeight = fontDescriptor.getCapHeight(); - if (capHeight != 0 && capHeight < glyphHeight) + if (capHeight != 0 && (capHeight < glyphHeight || glyphHeight == 0)) { glyphHeight = capHeight; } From 9cd2f0f0ff2b6e2cf27febc9f69d8bacd12407da Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Thu, 4 Aug 2016 16:48:48 +0000 Subject: [PATCH 0259/2182] PDFBOX-3426: avoid ArrayIndexOutOfBoundsException if cmapTable.getCmaps() is empty git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1755212 13f79535-47bb-0310-9956-ffa450edef68 --- fontbox/src/main/java/org/apache/fontbox/ttf/TrueTypeFont.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fontbox/src/main/java/org/apache/fontbox/ttf/TrueTypeFont.java b/fontbox/src/main/java/org/apache/fontbox/ttf/TrueTypeFont.java index ab56196454a..92a444076c6 100644 --- a/fontbox/src/main/java/org/apache/fontbox/ttf/TrueTypeFont.java +++ b/fontbox/src/main/java/org/apache/fontbox/ttf/TrueTypeFont.java @@ -560,7 +560,7 @@ public CmapSubtable getUnicodeCmap(boolean isStrict) throws IOException { throw new IOException("The TrueType font does not contain a Unicode cmap"); } - else + else if (cmapTable.getCmaps().length > 0) { // fallback to the first cmap (may not be Unicode, so may produce poor results) cmap = cmapTable.getCmaps()[0]; From fee3304cf068ee30dee37bc9f90040abcdb4f7c7 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Sat, 6 Aug 2016 13:11:33 +0000 Subject: [PATCH 0260/2182] PDFBOX-3442: cache direct fonts git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1755395 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/pdfbox/pdmodel/PDResources.java | 34 ++++++++++++++++--- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDResources.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDResources.java index 4a66c7dc946..3b01da27d91 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDResources.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDResources.java @@ -17,7 +17,10 @@ package org.apache.pdfbox.pdmodel; import java.io.IOException; +import java.lang.ref.SoftReference; import java.util.Collections; +import java.util.HashMap; +import java.util.Map; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; @@ -48,6 +51,11 @@ public final class PDResources implements COSObjectable { private final COSDictionary resources; private final ResourceCache cache; + + // PDFBOX-3442 cache fonts that are not indirect objects, as these aren't cached in ResourceCache + // and this would result in huge memory footprint in text extraction + private final Map > directFontCache = + new HashMap>(); /** * Constructor for embedding. @@ -102,7 +110,7 @@ public COSDictionary getCOSObject() * Returns the font resource with the given name, or null if none exists. * * @param name Name of the font resource. - * @throws java.io.IOException if something went wrong. + * @throws IOException if something went wrong. */ public PDFont getFont(COSName name) throws IOException { @@ -115,6 +123,18 @@ public PDFont getFont(COSName name) throws IOException return cached; } } + else if (indirect == null) + { + SoftReference ref = directFontCache.get(name); + if (ref != null) + { + PDFont cached = ref.get(); + if (cached != null) + { + return cached; + } + } + } PDFont font = null; COSDictionary dict = (COSDictionary)get(COSName.FONT, name); @@ -123,10 +143,14 @@ public PDFont getFont(COSName name) throws IOException font = PDFontFactory.createFont(dict); } - if (cache != null) + if (cache != null && indirect != null) { cache.put(indirect, font); } + else if (indirect == null) + { + directFontCache.put(name, new SoftReference(font)); + } return font; } @@ -231,7 +255,7 @@ public PDExtendedGraphicsState getExtGState(COSName name) * Returns the shading resource with the given name, or null if none exists. * * @param name Name of the shading resource. - * @throws java.io.IOException if something went wrong. + * @throws IOException if something went wrong. */ public PDShading getShading(COSName name) throws IOException { @@ -264,7 +288,7 @@ public PDShading getShading(COSName name) throws IOException * Returns the pattern resource with the given name, or null if none exists. * * @param name Name of the pattern resource. - * @throws java.io.IOException if something went wrong. + * @throws IOException if something went wrong. */ public PDAbstractPattern getPattern(COSName name) throws IOException { @@ -355,7 +379,7 @@ else if (value instanceof COSObject) * Returns the XObject resource with the given name, or null if none exists. * * @param name Name of the XObject resource. - * @throws java.io.IOException if something went wrong. + * @throws IOException if something went wrong. */ public PDXObject getXObject(COSName name) throws IOException { From 85c05f2ebd94458af8f2cc869f59b649cc1b8062 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Lehmk=C3=BChler?= Date: Sun, 7 Aug 2016 12:04:52 +0000 Subject: [PATCH 0261/2182] PDFBOX-2852: DRY-refactoring to improve readability of synchronized code git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1755436 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/fontbox/ttf/OpenTypeFont.java | 11 +- .../org/apache/fontbox/ttf/TrueTypeFont.java | 151 ++++++------------ 2 files changed, 52 insertions(+), 110 deletions(-) diff --git a/fontbox/src/main/java/org/apache/fontbox/ttf/OpenTypeFont.java b/fontbox/src/main/java/org/apache/fontbox/ttf/OpenTypeFont.java index 8b9afc4b117..39c6ee82797 100644 --- a/fontbox/src/main/java/org/apache/fontbox/ttf/OpenTypeFont.java +++ b/fontbox/src/main/java/org/apache/fontbox/ttf/OpenTypeFont.java @@ -49,22 +49,17 @@ void setVersion(float versionValue) * * @return The "CFF" table. */ - public synchronized CFFTable getCFF() throws IOException + public CFFTable getCFF() throws IOException { if (!isPostScript) { throw new UnsupportedOperationException("TTF fonts do not have a CFF table"); } - CFFTable cff = (CFFTable)tables.get(CFFTable.TAG); - if (cff != null && !cff.getInitialized()) - { - readTable(cff); - } - return cff; + return (CFFTable) getTable(CFFTable.TAG); } @Override - public synchronized GlyphTable getGlyph() throws IOException + public GlyphTable getGlyph() throws IOException { if (isPostScript) { diff --git a/fontbox/src/main/java/org/apache/fontbox/ttf/TrueTypeFont.java b/fontbox/src/main/java/org/apache/fontbox/ttf/TrueTypeFont.java index 92a444076c6..e326e6db046 100644 --- a/fontbox/src/main/java/org/apache/fontbox/ttf/TrueTypeFont.java +++ b/fontbox/src/main/java/org/apache/fontbox/ttf/TrueTypeFont.java @@ -123,21 +123,33 @@ public synchronized byte[] getTableBytes(TTFTable table) throws IOException data.seek(currentPosition); return bytes; } - + /** - * This will get the naming table for the true type font. + * This will get the table for the given tag. * - * @return The naming table. + * @param tag the name of the table to be returned + * @return The table with the given tag. * @throws IOException if there was an error reading the table. */ - public synchronized NamingTable getNaming() throws IOException + protected synchronized TTFTable getTable(String tag) throws IOException { - NamingTable naming = (NamingTable)tables.get( NamingTable.TAG ); - if (naming != null && !naming.getInitialized()) + TTFTable ttfTable = tables.get(tag); + if (ttfTable != null && !ttfTable.getInitialized()) { - readTable(naming); + readTable(ttfTable); } - return naming; + return ttfTable; + } + + /** + * This will get the naming table for the true type font. + * + * @return The naming table. + * @throws IOException if there was an error reading the table. + */ + public NamingTable getNaming() throws IOException + { + return (NamingTable) getTable(NamingTable.TAG); } /** @@ -146,14 +158,9 @@ public synchronized NamingTable getNaming() throws IOException * @return The postscript table. * @throws IOException if there was an error reading the table. */ - public synchronized PostScriptTable getPostScript() throws IOException + public PostScriptTable getPostScript() throws IOException { - PostScriptTable postscript = (PostScriptTable)tables.get( PostScriptTable.TAG ); - if (postscript != null && !postscript.getInitialized()) - { - readTable(postscript); - } - return postscript; + return (PostScriptTable) getTable(PostScriptTable.TAG); } /** @@ -162,30 +169,20 @@ public synchronized PostScriptTable getPostScript() throws IOException * @return The OS/2 table. * @throws IOException if there was an error reading the table. */ - public synchronized OS2WindowsMetricsTable getOS2Windows() throws IOException + public OS2WindowsMetricsTable getOS2Windows() throws IOException { - OS2WindowsMetricsTable os2WindowsMetrics = (OS2WindowsMetricsTable)tables.get( OS2WindowsMetricsTable.TAG ); - if (os2WindowsMetrics != null && !os2WindowsMetrics.getInitialized()) - { - readTable(os2WindowsMetrics); - } - return os2WindowsMetrics; + return (OS2WindowsMetricsTable) getTable(OS2WindowsMetricsTable.TAG); } - + /** * Get the maxp table for this TTF. * * @return The maxp table. * @throws IOException if there was an error reading the table. */ - public synchronized MaximumProfileTable getMaximumProfile() throws IOException + public MaximumProfileTable getMaximumProfile() throws IOException { - MaximumProfileTable maximumProfile = (MaximumProfileTable)tables.get( MaximumProfileTable.TAG ); - if (maximumProfile != null && !maximumProfile.getInitialized()) - { - readTable(maximumProfile); - } - return maximumProfile; + return (MaximumProfileTable) getTable(MaximumProfileTable.TAG); } /** @@ -194,14 +191,9 @@ public synchronized MaximumProfileTable getMaximumProfile() throws IOException * @return The head table. * @throws IOException if there was an error reading the table. */ - public synchronized HeaderTable getHeader() throws IOException + public HeaderTable getHeader() throws IOException { - HeaderTable header = (HeaderTable)tables.get( HeaderTable.TAG ); - if (header != null && !header.getInitialized()) - { - readTable(header); - } - return header; + return (HeaderTable) getTable(HeaderTable.TAG); } /** @@ -210,14 +202,9 @@ public synchronized HeaderTable getHeader() throws IOException * @return The hhea table. * @throws IOException if there was an error reading the table. */ - public synchronized HorizontalHeaderTable getHorizontalHeader() throws IOException + public HorizontalHeaderTable getHorizontalHeader() throws IOException { - HorizontalHeaderTable horizontalHeader = (HorizontalHeaderTable)tables.get( HorizontalHeaderTable.TAG ); - if (horizontalHeader != null && !horizontalHeader.getInitialized()) - { - readTable(horizontalHeader); - } - return horizontalHeader; + return (HorizontalHeaderTable) getTable(HorizontalHeaderTable.TAG); } /** @@ -226,14 +213,9 @@ public synchronized HorizontalHeaderTable getHorizontalHeader() throws IOExcepti * @return The hmtx table. * @throws IOException if there was an error reading the table. */ - public synchronized HorizontalMetricsTable getHorizontalMetrics() throws IOException + public HorizontalMetricsTable getHorizontalMetrics() throws IOException { - HorizontalMetricsTable horizontalMetrics = (HorizontalMetricsTable)tables.get( HorizontalMetricsTable.TAG ); - if (horizontalMetrics != null && !horizontalMetrics.getInitialized()) - { - readTable(horizontalMetrics); - } - return horizontalMetrics; + return (HorizontalMetricsTable) getTable(HorizontalMetricsTable.TAG); } /** @@ -242,14 +224,9 @@ public synchronized HorizontalMetricsTable getHorizontalMetrics() throws IOExcep * @return The loca table. * @throws IOException if there was an error reading the table. */ - public synchronized IndexToLocationTable getIndexToLocation() throws IOException + public IndexToLocationTable getIndexToLocation() throws IOException { - IndexToLocationTable indexToLocation = (IndexToLocationTable)tables.get( IndexToLocationTable.TAG ); - if (indexToLocation != null && !indexToLocation.getInitialized()) - { - readTable(indexToLocation); - } - return indexToLocation; + return (IndexToLocationTable) getTable(IndexToLocationTable.TAG); } /** @@ -258,30 +235,20 @@ public synchronized IndexToLocationTable getIndexToLocation() throws IOException * @return The glyf table. * @throws IOException if there was an error reading the table. */ - public synchronized GlyphTable getGlyph() throws IOException + public GlyphTable getGlyph() throws IOException { - GlyphTable glyph = (GlyphTable)tables.get( GlyphTable.TAG ); - if (glyph != null && !glyph.getInitialized()) - { - readTable(glyph); - } - return glyph; + return (GlyphTable) getTable(GlyphTable.TAG); } /** * Get the "cmap" table for this TTF. * * @return The "cmap" table. - * @throws IOException if there was an error reading the table. - */ - public synchronized CmapTable getCmap() throws IOException + * @throws IOException if there was an error reading the table. + */ + public CmapTable getCmap() throws IOException { - CmapTable cmap = (CmapTable)tables.get( CmapTable.TAG ); - if (cmap != null && !cmap.getInitialized()) - { - readTable(cmap); - } - return cmap; + return (CmapTable) getTable(CmapTable.TAG); } /** @@ -290,14 +257,9 @@ public synchronized CmapTable getCmap() throws IOException * @return The vhea table. * @throws IOException if there was an error reading the table. */ - public synchronized VerticalHeaderTable getVerticalHeader() throws IOException + public VerticalHeaderTable getVerticalHeader() throws IOException { - VerticalHeaderTable verticalHeader = (VerticalHeaderTable)tables.get( VerticalHeaderTable.TAG ); - if (verticalHeader != null && !verticalHeader.getInitialized()) - { - readTable(verticalHeader); - } - return verticalHeader; + return (VerticalHeaderTable) getTable(VerticalHeaderTable.TAG); } /** @@ -306,14 +268,9 @@ public synchronized VerticalHeaderTable getVerticalHeader() throws IOException * @return The vmtx table. * @throws IOException if there was an error reading the table. */ - public synchronized VerticalMetricsTable getVerticalMetrics() throws IOException + public VerticalMetricsTable getVerticalMetrics() throws IOException { - VerticalMetricsTable verticalMetrics = (VerticalMetricsTable)tables.get( VerticalMetricsTable.TAG ); - if (verticalMetrics != null && !verticalMetrics.getInitialized()) - { - readTable(verticalMetrics); - } - return verticalMetrics; + return (VerticalMetricsTable) getTable(VerticalMetricsTable.TAG); } /** @@ -322,14 +279,9 @@ public synchronized VerticalMetricsTable getVerticalMetrics() throws IOException * @return The VORG table. * @throws IOException if there was an error reading the table. */ - public synchronized VerticalOriginTable getVerticalOrigin() throws IOException + public VerticalOriginTable getVerticalOrigin() throws IOException { - VerticalOriginTable verticalOrigin = (VerticalOriginTable)tables.get( VerticalOriginTable.TAG ); - if (verticalOrigin != null && !verticalOrigin.getInitialized()) - { - readTable(verticalOrigin); - } - return verticalOrigin; + return (VerticalOriginTable) getTable(VerticalOriginTable.TAG); } /** @@ -338,14 +290,9 @@ public synchronized VerticalOriginTable getVerticalOrigin() throws IOException * @return The "kern" table. * @throws IOException if there was an error reading the table. */ - public synchronized KerningTable getKerning() throws IOException + public KerningTable getKerning() throws IOException { - KerningTable kerning = (KerningTable)tables.get( KerningTable.TAG ); - if (kerning != null && !kerning.getInitialized()) - { - readTable(kerning); - } - return kerning; + return (KerningTable) getTable(KerningTable.TAG); } /** From 64f95cbfe8d8a6398f12992e742590fb5ccdd1dd Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Tue, 9 Aug 2016 15:25:13 +0000 Subject: [PATCH 0262/2182] PDFBOX-2919: throw IOException instead of IllegalArgumentException git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1755619 13f79535-47bb-0310-9956-ffa450edef68 --- fontbox/src/main/java/org/apache/fontbox/cff/CFFParser.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fontbox/src/main/java/org/apache/fontbox/cff/CFFParser.java b/fontbox/src/main/java/org/apache/fontbox/cff/CFFParser.java index 94b12becddd..249f81e0296 100644 --- a/fontbox/src/main/java/org/apache/fontbox/cff/CFFParser.java +++ b/fontbox/src/main/java/org/apache/fontbox/cff/CFFParser.java @@ -275,7 +275,7 @@ else if (b0 >= 32 && b0 <= 254) } else { - throw new IllegalArgumentException(); + throw new IOException("invalid DICT data b0 byte: " + b0); } } return entry; From 7aa6d77af9a67dff72268dfb66485495e4040a2e Mon Sep 17 00:00:00 2001 From: tilman Date: Tue, 9 Aug 2016 15:30:01 +0000 Subject: [PATCH 0263/2182] PDFBOX-3315: prevent corner case 12:00 to be interpreted as 00:00, fixed + added tests git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1755623 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/pdfbox/util/DateConverter.java | 6 +++++- .../java/org/apache/pdfbox/util/TestDateUtil.java | 11 +++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/util/DateConverter.java b/pdfbox/src/main/java/org/apache/pdfbox/util/DateConverter.java index ee5c342d134..5e3a0b830a3 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/util/DateConverter.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/util/DateConverter.java @@ -197,12 +197,16 @@ public static String toISO8601(Calendar cal) } /* - * Constrain a timezone offset to the range [-11:59 thru +11:59]. + * Constrain a timezone offset to the range [-11:59 thru +12:00]. * by adding or subtracting multiples of a full day. */ private static int restrainTZoffset(long proposedOffset) { proposedOffset = ((proposedOffset + HALF_DAY) % DAY + DAY) % DAY; + if (proposedOffset == 0) + { + return HALF_DAY; + } // 0 <= proposedOffset < DAY proposedOffset = (proposedOffset - HALF_DAY) % HALF_DAY; // -HALF_DAY < proposedOffset < HALF_DAY diff --git a/pdfbox/src/test/java/org/apache/pdfbox/util/TestDateUtil.java b/pdfbox/src/test/java/org/apache/pdfbox/util/TestDateUtil.java index 7311aba7c35..045cf5b35ca 100644 --- a/pdfbox/src/test/java/org/apache/pdfbox/util/TestDateUtil.java +++ b/pdfbox/src/test/java/org/apache/pdfbox/util/TestDateUtil.java @@ -295,6 +295,8 @@ public void testDateConverter() throws Exception // ambiguous big-endian date checkParse(2073,12,25, 0, 8, 0, 0, 0, "2073 12 25:08"); + // PDFBOX-3315 GMT+12 + checkParse(2016, 4,11,16,01,15, 12, 0, "D:20160411160115+12'00'"); } private static void checkToString(int yr, int mon, int day, @@ -370,6 +372,7 @@ private static void checkParseTZ(int expect, String src) */ public void testParseTZ() { + // 1st parameter is what to expect checkParseTZ(0*HRS+0*MINS, "+00:00"); checkParseTZ(0*HRS+0*MINS, "-0000"); checkParseTZ(1*HRS+0*MINS, "+1:00"); @@ -391,6 +394,9 @@ public void testParseTZ() checkParseTZ((5*HRS+0*MINS), "+0500"); checkParseTZ((11*HRS+0*MINS), "+11'00'"); checkParseTZ(0, "Z"); + // PDFBOX-3315 + checkParseTZ(12*HRS+0*MINS, "+12:00"); + checkParseTZ(12*HRS+0*MINS, "-12:00"); } private static void checkFormatOffset(double off, String expect) @@ -405,6 +411,7 @@ private static void checkFormatOffset(double off, String expect) */ public void testFormatTZoffset() { + // 2nd parameter is what to expect checkFormatOffset(-12.1, "+11:54"); checkFormatOffset(12.1, "-11:54"); checkFormatOffset(0, "+00:00"); @@ -413,8 +420,8 @@ public void testFormatTZoffset() checkFormatOffset(-0.5, "-00:30"); checkFormatOffset(.1, "+00:06"); checkFormatOffset(-0.1, "-00:06"); - checkFormatOffset(-12, "+00:00"); - checkFormatOffset(12, "+00:00"); + checkFormatOffset(-12, "+12:00"); + checkFormatOffset(12, "+12:00"); checkFormatOffset(-11.5, "-11:30"); checkFormatOffset(11.5, "+11:30"); checkFormatOffset(11.9, "+11:54"); From 6f50c6cb48db2ebce198955fd910b57dba182e75 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Tue, 9 Aug 2016 15:43:37 +0000 Subject: [PATCH 0264/2182] PDFBOX-2852: removed unused field git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1755626 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/pdfbox/pdmodel/font/encoding/DictionaryEncoding.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/DictionaryEncoding.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/DictionaryEncoding.java index 56f82a0b92d..5bb8e9fd903 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/DictionaryEncoding.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/DictionaryEncoding.java @@ -34,8 +34,6 @@ */ public class DictionaryEncoding extends Encoding { - private static final Log LOG = LogFactory.getLog(DictionaryEncoding.class); - private final COSDictionary encoding; private final Encoding baseEncoding; private final Map differences = new HashMap(); From db934b48559a9f68c2b94d132c51de7dd1f444d1 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Tue, 9 Aug 2016 18:53:50 +0000 Subject: [PATCH 0265/2182] PDFBOX-2941: show field name in tree git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1755642 13f79535-47bb-0310-9956-ffa450edef68 --- .../pdfbox/debugger/ui/PDFTreeCellRenderer.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/debugger/src/main/java/org/apache/pdfbox/debugger/ui/PDFTreeCellRenderer.java b/debugger/src/main/java/org/apache/pdfbox/debugger/ui/PDFTreeCellRenderer.java index 3dd0ff29312..88d12ea073c 100644 --- a/debugger/src/main/java/org/apache/pdfbox/debugger/ui/PDFTreeCellRenderer.java +++ b/debugger/src/main/java/org/apache/pdfbox/debugger/ui/PDFTreeCellRenderer.java @@ -188,6 +188,20 @@ private String toTreePostfix(Object nodeValue) StringBuilder sb = new StringBuilder(); COSDictionary dict = (COSDictionary)nodeValue; + + if (COSName.ANNOT.equals(dict.getCOSName(COSName.TYPE)) + && COSName.WIDGET.equals(dict.getCOSName(COSName.SUBTYPE)) || + dict.containsKey(COSName.T) && dict.containsKey(COSName.KIDS)) + { + String name = dict.getString(COSName.T); + if (name != null) + { + sb.append(" Name: "); + sb.append(name); + sb.append(' '); + } + } + if (dict.containsKey(COSName.TYPE)) { COSName type = dict.getCOSName(COSName.TYPE); From 88afe4c93e8ecc37b2bac41bd48f323668bbc7f7 Mon Sep 17 00:00:00 2001 From: John Hewson Date: Wed, 10 Aug 2016 05:23:33 +0000 Subject: [PATCH 0266/2182] PDFBOX-2941: infer file extensions for streams for easy "save as" and "open" git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1755670 13f79535-47bb-0310-9956-ffa450edef68 --- .../debugger/ui/FileOpenSaveDialog.java | 12 +- .../org/apache/pdfbox/debugger/ui/Tree.java | 189 +++++++++++++++--- 2 files changed, 168 insertions(+), 33 deletions(-) diff --git a/debugger/src/main/java/org/apache/pdfbox/debugger/ui/FileOpenSaveDialog.java b/debugger/src/main/java/org/apache/pdfbox/debugger/ui/FileOpenSaveDialog.java index 5f9a49e5a9c..b5f886bae5a 100644 --- a/debugger/src/main/java/org/apache/pdfbox/debugger/ui/FileOpenSaveDialog.java +++ b/debugger/src/main/java/org/apache/pdfbox/debugger/ui/FileOpenSaveDialog.java @@ -64,6 +64,7 @@ public void approveSelection() public FileOpenSaveDialog(Component parentUI, FileFilter fileFilter) { mainUI = parentUI; + fileChooser.resetChoosableFileFilters(); fileChooser.setFileFilter(fileFilter); } @@ -74,16 +75,21 @@ public FileOpenSaveDialog(Component parentUI, FileFilter fileFilter) * @return true if the file is saved successfully or false if failed. * @throws IOException if there is an error in creation of the file. */ - public boolean saveFile(byte[] bytes) throws IOException + public boolean saveFile(byte[] bytes, String extension) throws IOException { int result = fileChooser.showSaveDialog(mainUI); if (result == JFileChooser.APPROVE_OPTION) { - File selectedFile = fileChooser.getSelectedFile(); + String filename = fileChooser.getSelectedFile().getAbsolutePath(); + if (extension != null && !filename.endsWith(extension)) + { + filename += "." + extension; + } + FileOutputStream outputStream = null; try { - outputStream = new FileOutputStream(selectedFile); + outputStream = new FileOutputStream(filename); outputStream.write(bytes); } finally diff --git a/debugger/src/main/java/org/apache/pdfbox/debugger/ui/Tree.java b/debugger/src/main/java/org/apache/pdfbox/debugger/ui/Tree.java index 14982202df4..134f16e8f3a 100644 --- a/debugger/src/main/java/org/apache/pdfbox/debugger/ui/Tree.java +++ b/debugger/src/main/java/org/apache/pdfbox/debugger/ui/Tree.java @@ -18,6 +18,7 @@ package org.apache.pdfbox.debugger.ui; import java.awt.Component; +import java.awt.Desktop; import java.awt.Point; import java.awt.Toolkit; import java.awt.datatransfer.Clipboard; @@ -25,6 +26,8 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseEvent; +import java.io.File; +import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; @@ -32,6 +35,8 @@ import javax.swing.JMenuItem; import javax.swing.JPopupMenu; import javax.swing.JTree; +import javax.swing.filechooser.FileFilter; +import javax.swing.filechooser.FileNameExtensionFilter; import javax.swing.tree.TreePath; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; @@ -72,10 +77,7 @@ public Point getPopupLocation(MouseEvent event) TreePath path = getClosestPathForLocation(event.getX(), event.getY()); setSelectionPath(path); treePopupMenu.removeAll(); - for (JMenuItem menuItem : getPopupMenuItems(path)) - { - treePopupMenu.add(menuItem); - } + addPopupMenuItems(path); return event.getPoint(); } return null; @@ -86,12 +88,11 @@ public Point getPopupLocation(MouseEvent event) * @param nodePath is instance of TreePath of the specified Node. * @return the JMenuItem list for the node */ - private List getPopupMenuItems(TreePath nodePath) + private void addPopupMenuItems(TreePath nodePath) { Object obj = nodePath.getLastPathComponent(); - List menuItems = new ArrayList(); - menuItems.add(getTreePathMenuItem(nodePath)); + treePopupMenu.add(getTreePathMenuItem(nodePath)); if (obj instanceof MapEntry) { @@ -104,22 +105,30 @@ else if (obj instanceof ArrayEntry) if (obj instanceof COSStream) { + treePopupMenu.addSeparator(); + COSStream stream = (COSStream) obj; - menuItems.add(getUnFilteredStreamSaveMenu(stream)); + treePopupMenu.add(getStreamSaveMenu(stream, nodePath)); + if (stream.getFilters() != null) { if (stream.getFilters() instanceof COSArray && ((COSArray) stream.getFilters()).size() >= 2) { - for (JMenuItem menuItem : getPartiallyFilteredStreamSaveMenu(stream)) + for (JMenuItem menuItem : getPartiallyDecodedStreamSaveMenu(stream)) { - menuItems.add(menuItem); + treePopupMenu.add(menuItem); } } - menuItems.add(getFilteredStreamSaveMenu(stream)); + treePopupMenu.add(getRawStreamSaveMenu(stream)); + } + + JMenuItem open = getFileOpenMenu(stream, nodePath); + if (open != null) + { + treePopupMenu.addSeparator(); + treePopupMenu.add(open); } } - - return menuItems; } /** @@ -143,13 +152,13 @@ public void actionPerformed(ActionEvent actionEvent) } /** - * Produce JMenuItem that saves filtered stream + * Produce JMenuItem that saves the raw stream * @param cosStream stream to save - * @return JMenuItem for saving filtered stream + * @return JMenuItem for saving the raw stream */ - private JMenuItem getFilteredStreamSaveMenu(final COSStream cosStream) + private JMenuItem getRawStreamSaveMenu(final COSStream cosStream) { - JMenuItem saveMenuItem = new JMenuItem("Save Filtered Stream (" + getFilters(cosStream) + ")..."); + JMenuItem saveMenuItem = new JMenuItem("Save Raw Stream (" + getFilters(cosStream) + ") As..."); saveMenuItem.addActionListener(new ActionListener() { @Override @@ -158,7 +167,7 @@ public void actionPerformed(ActionEvent actionEvent) try { byte[] bytes = IOUtils.toByteArray(cosStream.createRawInputStream()); - saveStream(bytes); + saveStream(bytes, null, null); } catch (IOException e) { @@ -199,13 +208,55 @@ else if (filters instanceof COSArray) } /** - * Produce JMenuItem that saves unfiltered stream + * Produce JMenuItem that saves the stream * @param cosStream stream to save - * @return JMenuItem for saving unfiltered stream + * @return JMenuItem for saving stream */ - private JMenuItem getUnFilteredStreamSaveMenu(final COSStream cosStream) + private JMenuItem getStreamSaveMenu(final COSStream cosStream, final TreePath nodePath) { - JMenuItem saveMenuItem = new JMenuItem("Save Unfiltered Stream..."); + // set file extension based on stream type + final String extension = getFileExtensionForStream(cosStream, nodePath); + final FileFilter fileFilter; + + if (extension != null) + { + if (extension.equals("pdb")) + { + fileFilter = new FileNameExtensionFilter("Type 1 Font (*.pfb)", "pfb"); + } + else if (extension.equals("ttf")) + { + fileFilter = new FileNameExtensionFilter("TrueType Font (*.ttf)", "ttf"); + } + else if (extension.equals("cff")) + { + fileFilter = new FileNameExtensionFilter("Compact Font Format (*.cff)", "cff"); + } + else if (extension.equals("otf")) + { + fileFilter = new FileNameExtensionFilter("OpenType Font (*.otf)", "otf"); + } + else + { + fileFilter = null; + } + } + else + { + fileFilter = null; + } + + String format; + if (extension != null) + { + format = " " + extension.toUpperCase(); + } + else + { + format = ""; + } + + JMenuItem saveMenuItem = new JMenuItem("Save Stream As" + format + "..."); saveMenuItem.addActionListener(new ActionListener() { @Override @@ -214,7 +265,7 @@ public void actionPerformed(ActionEvent actionEvent) try { byte[] bytes = IOUtils.toByteArray(cosStream.createInputStream()); - saveStream(bytes); + saveStream(bytes, fileFilter, extension); } catch (IOException e) { @@ -226,11 +277,88 @@ public void actionPerformed(ActionEvent actionEvent) } /** - * produce possible partially filtered stream saving menu items + * Returns the recommended file extension for the given cos stream. + */ + private String getFileExtensionForStream(final COSStream cosStream, final TreePath nodePath) + { + String name = nodePath.getLastPathComponent().toString(); + if (name.equals("FontFile")) + { + return "pfb"; + } + else if (name.equals("FontFile2")) + { + return "ttf"; + } + else if (name.equals("FontFile3")) + { + if (cosStream.getCOSName(COSName.SUBTYPE) == COSName.OPEN_TYPE) + { + return "otf"; + } + else + { + return "cff"; + } + } + return null; + } + + /** + * Produce JMenuItem that opens the stream with the system's default app. + */ + private JMenuItem getFileOpenMenu(final COSStream cosStream, final TreePath nodePath) + { + // if we know the file type, create a system open menu + final String extension = getFileExtensionForStream(cosStream, nodePath); + if (extension == null) + { + return null; + } + + JMenuItem openMenuItem = new JMenuItem("Open with Default Application"); + openMenuItem.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent actionEvent) + { + try + { + byte[] bytes = IOUtils.toByteArray(cosStream.createInputStream()); + File temp = File.createTempFile("pdfbox", "." + extension); + temp.deleteOnExit(); + + FileOutputStream outputStream = null; + try + { + outputStream = new FileOutputStream(temp); + outputStream.write(bytes); + + Desktop.getDesktop().open(temp); + } + finally + { + if (outputStream != null) + { + outputStream.close(); + } + } + } + catch (IOException e) + { + e.printStackTrace(); + } + } + }); + return openMenuItem; + } + + /** + * produce possible partially decoded stream saving menu items * @param cosStream stream to save - * @return JMenuItems for saving partially filtered streams + * @return JMenuItems for saving partially decoded streams */ - private List getPartiallyFilteredStreamSaveMenu(final COSStream cosStream) + private List getPartiallyDecodedStreamSaveMenu(final COSStream cosStream) { List menuItems = new ArrayList(); PDStream stream = new PDStream(cosStream); @@ -267,7 +395,7 @@ public void actionPerformed(ActionEvent actionEvent) try { InputStream data = stream.createInputStream(stopFilters); - saveStream(IOUtils.toByteArray(data)); + saveStream(IOUtils.toByteArray(data), null, null); } catch (IOException e) { @@ -281,11 +409,12 @@ public void actionPerformed(ActionEvent actionEvent) /** * Save the stream. * @param bytes byte array of the stream. + * @param filter an optional FileFilter * @throws IOException if there is an error in creation of the file. */ - private void saveStream(byte[] bytes) throws IOException + private void saveStream(byte[] bytes, FileFilter filter, String extension) throws IOException { - FileOpenSaveDialog saveDialog = new FileOpenSaveDialog(parent, null); - saveDialog.saveFile(bytes); + FileOpenSaveDialog saveDialog = new FileOpenSaveDialog(parent, filter); + saveDialog.saveFile(bytes, extension); } } From 6fc7d7bd3ee5b3cf1ce766fa697b447c992dd090 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Wed, 10 Aug 2016 16:10:17 +0000 Subject: [PATCH 0267/2182] PDFBOX-3458: add method to set text rendering mode git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1755775 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/pdfbox/pdmodel/PDPageContentStream.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPageContentStream.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPageContentStream.java index 27dc6eb632f..d245b58efad 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPageContentStream.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPageContentStream.java @@ -50,6 +50,7 @@ import org.apache.pdfbox.pdmodel.graphics.image.PDInlineImage; import org.apache.pdfbox.pdmodel.graphics.shading.PDShading; import org.apache.pdfbox.pdmodel.graphics.state.PDExtendedGraphicsState; +import org.apache.pdfbox.pdmodel.graphics.state.RenderingMode; import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceStream; import org.apache.pdfbox.util.Charsets; import org.apache.pdfbox.util.Matrix; @@ -2343,4 +2344,17 @@ private void setNonStrokingColorSpaceStack(PDColorSpace colorSpace) nonStrokingColorSpaceStack.setElementAt(colorSpace, nonStrokingColorSpaceStack.size() - 1); } } + + /** + * Set the text rendering mode. This determines whether showing text shall cause glyph outlines + * to be stroked, filled, used as a clipping boundary, or some combination of the three. + * + * @param rm The text rendering mode. + * @throws IOException If the content stream could not be written. + */ + public void setRenderingMode(RenderingMode rm) throws IOException + { + writeOperand(rm.intValue()); + writeOperator("Tr"); + } } From 5464f2d97db9976c3584deba8e75ca3badd228f3 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Wed, 10 Aug 2016 16:14:27 +0000 Subject: [PATCH 0268/2182] PDFBOX-2852: fix imports git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1755780 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/pdfbox/pdmodel/font/encoding/DictionaryEncoding.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/DictionaryEncoding.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/DictionaryEncoding.java index 5bb8e9fd903..3ae666d59d0 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/DictionaryEncoding.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/encoding/DictionaryEncoding.java @@ -19,8 +19,6 @@ import java.util.HashMap; import java.util.Map; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSDictionary; From ef8fce30e2fcc305e6b2415c7743e75e3dd097a3 Mon Sep 17 00:00:00 2001 From: John Hewson Date: Wed, 10 Aug 2016 20:03:08 +0000 Subject: [PATCH 0269/2182] PDFBOX-3460: warn users not to use legacy code git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1755826 13f79535-47bb-0310-9956-ffa450edef68 --- ...Engine.java => LegacyPDFStreamEngine.java} | 36 +++++++++++++------ .../text/PDFMarkedContentExtractor.java | 2 +- .../apache/pdfbox/text/PDFTextStripper.java | 2 +- 3 files changed, 27 insertions(+), 13 deletions(-) rename pdfbox/src/main/java/org/apache/pdfbox/text/{PDFTextStreamEngine.java => LegacyPDFStreamEngine.java} (91%) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/text/PDFTextStreamEngine.java b/pdfbox/src/main/java/org/apache/pdfbox/text/LegacyPDFStreamEngine.java similarity index 91% rename from pdfbox/src/main/java/org/apache/pdfbox/text/PDFTextStreamEngine.java rename to pdfbox/src/main/java/org/apache/pdfbox/text/LegacyPDFStreamEngine.java index 4583e8ccd55..ab1fd85d60a 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/text/PDFTextStreamEngine.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/text/LegacyPDFStreamEngine.java @@ -63,15 +63,18 @@ import org.apache.pdfbox.pdmodel.font.PDFontDescriptor; /** - * PDFStreamEngine subclass for advanced processing of text via TextPosition. + * LEGACY text calculations which are known to be incorrect but are depended on by PDFTextStripper. * - * @see org.apache.pdfbox.text.TextPosition - * @author Ben Litchfield - * @author John Hewson + * This class exists only so that we don't break the code of users who have their own subclasses + * of PDFTextStripper. It replaces the good implementation of showGlyph in PDFStreamEngine, with + * a bad implementation which is backwards compatible. + * + * DO NOT USE THIS CODE UNLESS YOU ARE WORKING WITH PDFTextStripper. + * THIS CODE IS DELIBERATELY INCORRECT, USE PDFStreamEngine INSTEAD. */ -class PDFTextStreamEngine extends PDFStreamEngine +class LegacyPDFStreamEngine extends PDFStreamEngine { - private static final Log LOG = LogFactory.getLog(PDFTextStreamEngine.class); + private static final Log LOG = LogFactory.getLog(LegacyPDFStreamEngine.class); private int pageRotation; private PDRectangle pageSize; @@ -81,7 +84,7 @@ class PDFTextStreamEngine extends PDFStreamEngine /** * Constructor. */ - PDFTextStreamEngine() throws IOException + LegacyPDFStreamEngine() throws IOException { addOperator(new BeginText()); addOperator(new Concatenate()); @@ -123,7 +126,7 @@ public void processPage(PDPage page) throws IOException { this.pageRotation = page.getRotation(); this.pageSize = page.getCropBox(); - + if (pageSize.getLowerLeftX() == 0 && pageSize.getLowerLeftY() == 0) { translateMatrix = null; @@ -132,7 +135,7 @@ public void processPage(PDPage page) throws IOException { // translation matrix for cropbox translateMatrix = Matrix.getTranslateInstance(-pageSize.getLowerLeftX(), -pageSize.getLowerLeftY()); - } + } super.processPage(page); } @@ -146,6 +149,9 @@ protected void showGlyph(Matrix textRenderingMatrix, PDFont font, int code, Stri // // legacy calculations which were previously in PDFStreamEngine // + // DO NOT USE THIS CODE UNLESS YOU ARE WORKING WITH PDFTextStripper. + // THIS CODE IS DELIBERATELY INCORRECT + // PDGraphicsState state = getGraphicsState(); Matrix ctm = state.getCurrentTransformationMatrix(); @@ -162,7 +168,7 @@ protected void showGlyph(Matrix textRenderingMatrix, PDFont font, int code, Stri } // 1/2 the bbox is used as the height todo: why? float glyphHeight = bbox.getHeight() / 2; - + // sometimes the bbox has very high values, but CapHeight is OK PDFontDescriptor fontDescriptor = font.getFontDescriptor(); if (fontDescriptor != null) @@ -196,7 +202,7 @@ protected void showGlyph(Matrix textRenderingMatrix, PDFont font, int code, Stri TrueTypeFont ttf = null; if (font instanceof PDTrueTypeFont) { - ttf = ((PDTrueTypeFont)font).getTrueTypeFont(); + ttf = ((PDTrueTypeFont)font).getTrueTypeFont(); } else if (font instanceof PDType0Font) { @@ -211,6 +217,14 @@ else if (font instanceof PDType0Font) displacementX *= 1000f / ttf.getUnitsPerEm(); } } + + // + // legacy calculations which were previously in PDFStreamEngine + // + // DO NOT USE THIS CODE UNLESS YOU ARE WORKING WITH PDFTextStripper. + // THIS CODE IS DELIBERATELY INCORRECT + // + // (modified) combined displacement, this is calculated *without* taking the character // spacing and word spacing into account, due to legacy code in TextStripper float tx = displacementX * fontSize * horizontalScaling; diff --git a/pdfbox/src/main/java/org/apache/pdfbox/text/PDFMarkedContentExtractor.java b/pdfbox/src/main/java/org/apache/pdfbox/text/PDFMarkedContentExtractor.java index dfcdb8cff31..a59f15350e7 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/text/PDFMarkedContentExtractor.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/text/PDFMarkedContentExtractor.java @@ -37,7 +37,7 @@ * * @author Johannes Koch */ -public class PDFMarkedContentExtractor extends PDFTextStreamEngine +public class PDFMarkedContentExtractor extends LegacyPDFStreamEngine { private final boolean suppressDuplicateOverlappingText = true; private final List markedContents = new ArrayList(); diff --git a/pdfbox/src/main/java/org/apache/pdfbox/text/PDFTextStripper.java b/pdfbox/src/main/java/org/apache/pdfbox/text/PDFTextStripper.java index 1b1b1338c61..a726390e320 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/text/PDFTextStripper.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/text/PDFTextStripper.java @@ -58,7 +58,7 @@ * * @author Ben Litchfield */ -public class PDFTextStripper extends PDFTextStreamEngine +public class PDFTextStripper extends LegacyPDFStreamEngine { private static float defaultIndentThreshold = 2.0f; private static float defaultDropThreshold = 2.5f; From 597287e1ba3739bc5f3b5651f38d26be20a21794 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Thu, 11 Aug 2016 16:40:13 +0000 Subject: [PATCH 0270/2182] PDFBOX-2420: keep timezones -14:00 thru +14:00, adjust tests git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1756010 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/pdfbox/util/DateConverter.java | 9 ++++++++- .../org/apache/pdfbox/util/TestDateUtil.java | 16 +++++++++------- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/util/DateConverter.java b/pdfbox/src/main/java/org/apache/pdfbox/util/DateConverter.java index 5e3a0b830a3..897fd4e4255 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/util/DateConverter.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/util/DateConverter.java @@ -197,11 +197,18 @@ public static String toISO8601(Calendar cal) } /* - * Constrain a timezone offset to the range [-11:59 thru +12:00]. + * Constrain a timezone offset to the range [-14:00 thru +14:00]. * by adding or subtracting multiples of a full day. */ private static int restrainTZoffset(long proposedOffset) { + if (proposedOffset <= 14 * MILLIS_PER_HOUR && proposedOffset >= -14 * MILLIS_PER_HOUR) + { + // https://www.w3.org/TR/xmlschema-2/#dateTime-timezones + // Timezones between 14:00 and -14:00 are valid + return (int) proposedOffset; + } + // Constrain a timezone offset to the range [-11:59 thru +12:00]. proposedOffset = ((proposedOffset + HALF_DAY) % DAY + DAY) % DAY; if (proposedOffset == 0) { diff --git a/pdfbox/src/test/java/org/apache/pdfbox/util/TestDateUtil.java b/pdfbox/src/test/java/org/apache/pdfbox/util/TestDateUtil.java index 045cf5b35ca..8686dcc6519 100644 --- a/pdfbox/src/test/java/org/apache/pdfbox/util/TestDateUtil.java +++ b/pdfbox/src/test/java/org/apache/pdfbox/util/TestDateUtil.java @@ -379,8 +379,8 @@ public void testParseTZ() checkParseTZ(-(1*HRS+0*MINS), "-1:00"); checkParseTZ(-(1*HRS+30*MINS), "-0130"); checkParseTZ(11*HRS+59*MINS, "1159"); - checkParseTZ(-(11*HRS+30*MINS), "1230"); - checkParseTZ(11*HRS+30*MINS, "-12:30"); + checkParseTZ(12*HRS+30*MINS, "1230"); + checkParseTZ(-(12*HRS+30*MINS), "-12:30"); checkParseTZ(0*HRS+0*MINS, "Z"); checkParseTZ(-(8*HRS+0*MINS), "PST"); checkParseTZ(0*HRS+0*MINS, "EDT"); // EDT does not parse @@ -394,9 +394,11 @@ public void testParseTZ() checkParseTZ((5*HRS+0*MINS), "+0500"); checkParseTZ((11*HRS+0*MINS), "+11'00'"); checkParseTZ(0, "Z"); - // PDFBOX-3315 + // PDFBOX-3315, PDFBOX-2420 checkParseTZ(12*HRS+0*MINS, "+12:00"); - checkParseTZ(12*HRS+0*MINS, "-12:00"); + checkParseTZ(-(12*HRS+0*MINS), "-12:00"); + checkParseTZ(14*HRS+0*MINS, "1400"); + checkParseTZ(-(14*HRS+0*MINS), "-1400"); } private static void checkFormatOffset(double off, String expect) @@ -412,15 +414,15 @@ private static void checkFormatOffset(double off, String expect) public void testFormatTZoffset() { // 2nd parameter is what to expect - checkFormatOffset(-12.1, "+11:54"); - checkFormatOffset(12.1, "-11:54"); + checkFormatOffset(-12.1, "-12:06"); + checkFormatOffset(12.1, "+12:06"); checkFormatOffset(0, "+00:00"); checkFormatOffset(-1, "-01:00"); checkFormatOffset(.5, "+00:30"); checkFormatOffset(-0.5, "-00:30"); checkFormatOffset(.1, "+00:06"); checkFormatOffset(-0.1, "-00:06"); - checkFormatOffset(-12, "+12:00"); + checkFormatOffset(-12, "-12:00"); checkFormatOffset(12, "+12:00"); checkFormatOffset(-11.5, "-11:30"); checkFormatOffset(11.5, "+11:30"); From f6524b0ec6fe060259be47d0ffa23769f1f0cbb4 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Sat, 13 Aug 2016 12:10:48 +0000 Subject: [PATCH 0271/2182] PDFBOX-3462: improve exception text for NoSuchAlgorithmException git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1756252 13f79535-47bb-0310-9956-ffa450edef68 --- .../pdfbox/pdmodel/encryption/PublicKeySecurityHandler.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/PublicKeySecurityHandler.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/PublicKeySecurityHandler.java index 2fdf56aeb03..dcb333d67bb 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/PublicKeySecurityHandler.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/PublicKeySecurityHandler.java @@ -415,8 +415,9 @@ private ASN1Primitive createDERForRecipient(byte[] in, X509Certificate cert) } catch (NoSuchAlgorithmException e) { - // should never happen, if this happens throw IOException instead - throw new RuntimeException("Could not find a suitable javax.crypto provider", e); + // happens when using the command line app .jar file + throw new IOException("Could not find a suitable javax.crypto provider for algorithm " + + algorithm + "; possible reason: using an unsigned .jar file", e); } catch (NoSuchPaddingException e) { From 7491cdfb7fb93761134f7f10c5bbf436b678af6e Mon Sep 17 00:00:00 2001 From: Maruan Sahyoun Date: Mon, 15 Aug 2016 15:03:58 +0000 Subject: [PATCH 0272/2182] PDFBOX-3461: add additional characters and combinations to force paragraph breaks git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1756392 13f79535-47bb-0310-9956-ffa450edef68 --- .../pdmodel/interactive/form/PlainText.java | 2 +- .../form/ControlCharacterTest.java | 127 ++++++++++++++++++ .../interactive/form/ControlCharacters.pdf | Bin 0 -> 12969 bytes 3 files changed, 128 insertions(+), 1 deletion(-) create mode 100644 pdfbox/src/test/java/org/apache/pdfbox/pdmodel/interactive/form/ControlCharacterTest.java create mode 100644 pdfbox/src/test/resources/org/apache/pdfbox/pdmodel/interactive/form/ControlCharacters.pdf diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PlainText.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PlainText.java index 08315969a3b..f8089df9f26 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PlainText.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PlainText.java @@ -51,7 +51,7 @@ class PlainText */ PlainText(String textValue) { - List parts = Arrays.asList(textValue.split("\\n")); + List parts = Arrays.asList(textValue.split("\\r\\n|\\n|\\r|\\u2028|\\u2029")); paragraphs = new ArrayList(); for (String part : parts) { diff --git a/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/interactive/form/ControlCharacterTest.java b/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/interactive/form/ControlCharacterTest.java new file mode 100644 index 00000000000..4c9c89a1d04 --- /dev/null +++ b/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/interactive/form/ControlCharacterTest.java @@ -0,0 +1,127 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.pdfbox.pdmodel.interactive.form; + +import java.io.File; +import java.io.IOException; + +import org.apache.pdfbox.pdmodel.PDDocument; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +/** + * Test handling some special characters when setting a fields value. + * + * Compare the results of setting the values using PDFBox with setting the values + * via Acrobat using JavaScript and manual input. + * + * The JavaScript used for acrobat is + * + *

    + * {@code
    + * this.getField("acrobat-nul").value = "NUL\0NUL";
    + * this.getField("acrobat-tab").value = "TAB\tTAB";
    + * this.getField("acrobat-space").value = "SPACE SPACE";
    + * this.getField("acrobat-cr").value = "CR\rCR";
    + * this.getField("acrobat-lf").value = "LF\nLF";
    + * this.getField("acrobat-crlf").value = "CRLF\r\nCRLF";
    + * this.getField("acrobat-lfcr").value = "LFCR\n\rLFCR";
    + * this.getField("acrobat-linebreak").value = "linebreak\u2028linebreak";
    + * this.getField("acrobat-paragraphbreak").value = "paragraphbreak\u2029paragraphbreak";
    + * }
    + * 
    + * + * @see https://issues.apache.org/jira/browse/PDFBOX-3461 + * + */ +public class ControlCharacterTest { + private static final File IN_DIR = new File("src/test/resources/org/apache/pdfbox/pdmodel/interactive/form"); + private static final String NAME_OF_PDF = "ControlCharacters.pdf"; + + private PDDocument document; + private PDAcroForm acroForm; + + @Before + public void setUp() throws IOException + { + document = PDDocument.load(new File(IN_DIR, NAME_OF_PDF)); + acroForm = document.getDocumentCatalog().getAcroForm(); + } + + @Test(expected=IllegalArgumentException.class) + public void characterNUL() throws IOException + { + acroForm.getField("pdfbox-nul").setValue("NUL\0NUL"); + } + + @Test(expected=IllegalArgumentException.class) + public void characterTAB() throws IOException + { + acroForm.getField("pdfbox-tab").setValue("TAB\tTAB"); + } + + @Test + public void characterSPACE() throws IOException + { + acroForm.getField("pdfbox-space").setValue("SPACE SPACE"); + } + + @Test + public void characterCR() throws IOException + { + acroForm.getField("pdfbox-cr").setValue("CR\rCR"); + } + + @Test + public void characterLF() throws IOException + { + acroForm.getField("pdfbox-lf").setValue("LF\nLF"); + } + + @Test + public void characterCRLF() throws IOException + { + acroForm.getField("pdfbox-crlf").setValue("CRLF\r\nCRLF"); + } + + @Test + public void characterLFCR() throws IOException + { + acroForm.getField("pdfbox-lfcr").setValue("LFCR\r\nLFCR"); + } + + @Test + public void characterUnicodeLinebreak() throws IOException + { + acroForm.getField("pdfbox-linebreak").setValue("linebreak\u2028linebreak"); + + } + + @Test + public void characterUnicodeParagraphbreak() throws IOException + { + acroForm.getField("pdfbox-paragraphbreak").setValue("paragraphbreak\u2029paragraphbreak"); + + } + + @After + public void tearDown() throws IOException + { + document.close(); + } +} diff --git a/pdfbox/src/test/resources/org/apache/pdfbox/pdmodel/interactive/form/ControlCharacters.pdf b/pdfbox/src/test/resources/org/apache/pdfbox/pdmodel/interactive/form/ControlCharacters.pdf new file mode 100644 index 0000000000000000000000000000000000000000..094347627dbd21ec7dae8324f37e4c582832a731 GIT binary patch literal 12969 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 Date: Mon, 15 Aug 2016 19:31:58 +0000 Subject: [PATCH 0273/2182] PDFBOX-3461: add handling for empty paragraphs; enhance unit tests; compare streams git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1756416 13f79535-47bb-0310-9956-ffa450edef68 --- .../pdmodel/interactive/form/PlainText.java | 5 ++ .../form/ControlCharacterTest.java | 89 +++++++++++++++++-- .../interactive/form/PlainTextTest.java | 72 +++++++++++++++ 3 files changed, 159 insertions(+), 7 deletions(-) create mode 100644 pdfbox/src/test/java/org/apache/pdfbox/pdmodel/interactive/form/PlainTextTest.java diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PlainText.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PlainText.java index f8089df9f26..f5774a64e25 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PlainText.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PlainText.java @@ -55,6 +55,11 @@ class PlainText paragraphs = new ArrayList(); for (String part : parts) { + // Acrobat prints a space for an empty paragraph + if (part.length() == 0) + { + part = " "; + } paragraphs.add(new Paragraph(part)); } } diff --git a/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/interactive/form/ControlCharacterTest.java b/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/interactive/form/ControlCharacterTest.java index 4c9c89a1d04..54853a07f24 100644 --- a/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/interactive/form/ControlCharacterTest.java +++ b/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/interactive/form/ControlCharacterTest.java @@ -16,10 +16,22 @@ */ package org.apache.pdfbox.pdmodel.interactive.form; +import static org.junit.Assert.assertEquals; + import java.io.File; import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Deque; +import java.util.List; +import org.apache.pdfbox.cos.COSString; +import org.apache.pdfbox.pdfparser.PDFStreamParser; import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationWidget; +import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceStream; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -78,45 +90,85 @@ public void characterTAB() throws IOException @Test public void characterSPACE() throws IOException { - acroForm.getField("pdfbox-space").setValue("SPACE SPACE"); + PDField field = acroForm.getField("pdfbox-space"); + field.setValue("SPACE SPACE"); + + List pdfboxValues = getStringsFromStream(field); + List acrobatValues = getStringsFromStream(acroForm.getField("acrobat-space")); + + assertEquals(pdfboxValues, acrobatValues); } @Test public void characterCR() throws IOException { - acroForm.getField("pdfbox-cr").setValue("CR\rCR"); + PDField field = acroForm.getField("pdfbox-cr"); + field.setValue("CR\rCR"); + + List pdfboxValues = getStringsFromStream(field); + List acrobatValues = getStringsFromStream(acroForm.getField("acrobat-cr")); + + assertEquals(pdfboxValues, acrobatValues); } @Test public void characterLF() throws IOException { - acroForm.getField("pdfbox-lf").setValue("LF\nLF"); + PDField field = acroForm.getField("pdfbox-lf"); + field.setValue("LF\nLF"); + + List pdfboxValues = getStringsFromStream(field); + List acrobatValues = getStringsFromStream(acroForm.getField("acrobat-lf")); + + assertEquals(pdfboxValues, acrobatValues); } @Test public void characterCRLF() throws IOException { - acroForm.getField("pdfbox-crlf").setValue("CRLF\r\nCRLF"); + PDField field = acroForm.getField("pdfbox-crlf"); + field.setValue("CRLF\r\nCRLF"); + + List pdfboxValues = getStringsFromStream(field); + List acrobatValues = getStringsFromStream(acroForm.getField("acrobat-crlf")); + + assertEquals(pdfboxValues, acrobatValues); } @Test public void characterLFCR() throws IOException { - acroForm.getField("pdfbox-lfcr").setValue("LFCR\r\nLFCR"); + PDField field = acroForm.getField("pdfbox-lfcr"); + field.setValue("LFCR\n\rLFCR"); + + List pdfboxValues = getStringsFromStream(field); + List acrobatValues = getStringsFromStream(acroForm.getField("acrobat-lfcr")); + + assertEquals(pdfboxValues, acrobatValues); } @Test public void characterUnicodeLinebreak() throws IOException { - acroForm.getField("pdfbox-linebreak").setValue("linebreak\u2028linebreak"); + PDField field = acroForm.getField("pdfbox-linebreak"); + field.setValue("linebreak\u2028linebreak"); + List pdfboxValues = getStringsFromStream(field); + List acrobatValues = getStringsFromStream(acroForm.getField("acrobat-linebreak")); + + assertEquals(pdfboxValues, acrobatValues); } @Test public void characterUnicodeParagraphbreak() throws IOException { - acroForm.getField("pdfbox-paragraphbreak").setValue("paragraphbreak\u2029paragraphbreak"); + PDField field = acroForm.getField("pdfbox-paragraphbreak"); + field.setValue("paragraphbreak\u2029paragraphbreak"); + List pdfboxValues = getStringsFromStream(field); + List acrobatValues = getStringsFromStream(acroForm.getField("acrobat-paragraphbreak")); + + assertEquals(pdfboxValues, acrobatValues); } @After @@ -124,4 +176,27 @@ public void tearDown() throws IOException { document.close(); } + + private List getStringsFromStream(PDField field) throws IOException + { + PDAnnotationWidget widget = field.getWidgets().get(0); + PDFStreamParser parser = new PDFStreamParser(widget.getNormalAppearanceStream()); + + Object token = parser.parseNextToken(); + + List stringValues = new ArrayList(); + + while (token != null) + { + if (token instanceof COSString) + { + // TODO: improve the string output to better match + // trimming as Acrobat adds spaces to strings + // where we don't + stringValues.add(((COSString) token).getString().trim()); + } + token = parser.parseNextToken(); + } + return stringValues; + } } diff --git a/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/interactive/form/PlainTextTest.java b/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/interactive/form/PlainTextTest.java new file mode 100644 index 00000000000..f750ce89b21 --- /dev/null +++ b/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/interactive/form/PlainTextTest.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.pdfbox.pdmodel.interactive.form; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +/** + * Test if a sequence of linebreak/paragraph characters produces the same + * number of paragraphs as Adobe Acrobat produces when setting the value + * via JavaScript. + * + */ +public class PlainTextTest { + @Test + public void characterCR() + { + PlainText text = new PlainText("CR\rCR"); + assertEquals(2,text.getParagraphs().size()); + } + + @Test + public void characterLF() + { + PlainText text = new PlainText("LF\nLF"); + assertEquals(2,text.getParagraphs().size()); + } + + @Test + public void characterCRLF() + { + PlainText text = new PlainText("CRLF\r\nCRLF"); + assertEquals(2,text.getParagraphs().size()); + } + + @Test + public void characterLFCR() + { + PlainText text = new PlainText("LFCR\n\rLFCR"); + assertEquals(3,text.getParagraphs().size()); + } + + @Test + public void characterUnicodeLinebreak() + { + PlainText text = new PlainText("linebreak\u2028linebreak"); + assertEquals(2,text.getParagraphs().size()); + } + + @Test + public void characterUnicodeParagraphbreak() + { + PlainText text = new PlainText("paragraphbreak\u2029paragraphbreak"); + assertEquals(2,text.getParagraphs().size()); + } + +} From 89f3e8925b78379d81f6cc471e392bde1bdda6db Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Tue, 16 Aug 2016 16:15:28 +0000 Subject: [PATCH 0274/2182] PDFBOX-2852: clarify javadoc git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1756529 13f79535-47bb-0310-9956-ffa450edef68 --- .../logicalstructure/PDStructureElement.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/documentinterchange/logicalstructure/PDStructureElement.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/documentinterchange/logicalstructure/PDStructureElement.java index c7e0a1ab055..2dd98ffc918 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/documentinterchange/logicalstructure/PDStructureElement.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/documentinterchange/logicalstructure/PDStructureElement.java @@ -159,7 +159,7 @@ public void setPage(PDPage page) /** * Returns the attributes together with their revision numbers (A). * - * @return the attributes + * @return the attributes as a list, never null. */ public Revisions getAttributes() { @@ -326,7 +326,7 @@ public void attributeChanged(PDAttributeObject attributeObject) /** * Returns the class names together with their revision numbers (C). * - * @return the class names + * @return the class names as a list, never null. */ public Revisions getClassNames() { From 632561a2e383632b3c31a59b66c0e44da6dfe7eb Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Wed, 17 Aug 2016 17:25:03 +0000 Subject: [PATCH 0275/2182] PDFBOX-3466: modify calls to methods deprecated in JDK9 git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1756666 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/fontbox/cmap/CMapParser.java | 2 +- .../org/apache/pdfbox/preflight/TestPreflightPath.java | 2 +- .../org/apache/xmpbox/parser/DeserializationTest.java | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/fontbox/src/main/java/org/apache/fontbox/cmap/CMapParser.java b/fontbox/src/main/java/org/apache/fontbox/cmap/CMapParser.java index 010f9d09752..0b1b8d19705 100644 --- a/fontbox/src/main/java/org/apache/fontbox/cmap/CMapParser.java +++ b/fontbox/src/main/java/org/apache/fontbox/cmap/CMapParser.java @@ -603,7 +603,7 @@ else if (isWhitespaceOrEOF(theNextByte)) String value = buffer.toString(); if (value.indexOf('.') >= 0) { - retval = new Double(value); + retval = Double.valueOf(value); } else { diff --git a/preflight/src/test/java/org/apache/pdfbox/preflight/TestPreflightPath.java b/preflight/src/test/java/org/apache/pdfbox/preflight/TestPreflightPath.java index 61423177d8d..1c4c9258111 100644 --- a/preflight/src/test/java/org/apache/pdfbox/preflight/TestPreflightPath.java +++ b/preflight/src/test/java/org/apache/pdfbox/preflight/TestPreflightPath.java @@ -63,7 +63,7 @@ public void test() assertEquals(1, position); Integer i = path.getPathElement(position, Integer.class); - assertEquals(new Integer(6), i); + assertEquals(Integer.valueOf(6), i); Object str = path.peek(); assertEquals(3, path.size()); diff --git a/xmpbox/src/test/java/org/apache/xmpbox/parser/DeserializationTest.java b/xmpbox/src/test/java/org/apache/xmpbox/parser/DeserializationTest.java index 1042a60fa85..cc0e6a482e4 100644 --- a/xmpbox/src/test/java/org/apache/xmpbox/parser/DeserializationTest.java +++ b/xmpbox/src/test/java/org/apache/xmpbox/parser/DeserializationTest.java @@ -143,14 +143,14 @@ public void testIsartorStyleWithThumbs() throws Exception Assert.assertEquals(2, thumbs.size()); ThumbnailType thumb = thumbs.get(0); - Assert.assertEquals(new Integer(162), thumb.getHeight()); - Assert.assertEquals(new Integer(216), thumb.getWidth()); + Assert.assertEquals(Integer.valueOf(162), thumb.getHeight()); + Assert.assertEquals(Integer.valueOf(216), thumb.getWidth()); Assert.assertEquals("JPEG", thumb.getFormat()); Assert.assertEquals("/9j/4AAQSkZJRgABAgEASABIAAD", thumb.getImage()); thumb = thumbs.get(1); - Assert.assertEquals(new Integer(162), thumb.getHeight()); - Assert.assertEquals(new Integer(216), thumb.getWidth()); + Assert.assertEquals(Integer.valueOf(162), thumb.getHeight()); + Assert.assertEquals(Integer.valueOf(216), thumb.getWidth()); Assert.assertEquals("JPEG", thumb.getFormat()); Assert.assertEquals("/9j/4AAQSkZJRgABAgEASABIAAD", thumb.getImage()); From 49c4ff5b429820f256ef93a8d7c6a61f41bb3966 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Wed, 17 Aug 2016 17:46:28 +0000 Subject: [PATCH 0276/2182] PDFBOX-2852: clarify javadoc git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1756669 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/pdfbox/pdmodel/PDPageContentStream.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPageContentStream.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPageContentStream.java index d245b58efad..a08d9be7c7c 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPageContentStream.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPageContentStream.java @@ -1566,7 +1566,8 @@ public void lineTo(float x, float y) throws IOException * @param yEnd The end y coordinate. * @throws IOException If there is an error while adding the line. * @throws IllegalStateException If the method was called within a text block. - * @deprecated Use {@link #moveTo} followed by {@link #lineTo}. + * @deprecated Use {@link #moveTo moveto(xStart,yStart)} followed by + * {@link #lineTo lineTo(xEnd,yEnd)}. */ @Deprecated public void addLine(float xStart, float yStart, float xEnd, float yEnd) throws IOException @@ -1588,7 +1589,8 @@ public void addLine(float xStart, float yStart, float xEnd, float yEnd) throws I * @param yEnd The end y coordinate. * @throws IOException If there is an error while drawing on the screen. * @throws IllegalStateException If the method was called within a text block. - * @deprecated Use {@link #moveTo} followed by {@link #lineTo} followed by {@link #stroke}. + * @deprecated Use {@link #moveTo moveto(xStart,yStart)} followed by + * {@link #lineTo lineTo(xEnd,yEnd)} followed by {@link #stroke stroke()}. */ @Deprecated public void drawLine(float xStart, float yStart, float xEnd, float yEnd) throws IOException From 2918b3904366951f5c3007389c4bb8abf92d8189 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Thu, 18 Aug 2016 16:50:43 +0000 Subject: [PATCH 0277/2182] PDFBOX-2963: remove BouncyCastle dependency that isn't needed here git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1756833 13f79535-47bb-0310-9956-ffa450edef68 --- .../pdfbox/examples/signature/CreateVisibleSignature.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateVisibleSignature.java b/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateVisibleSignature.java index 2022c6e1ded..2bb50db1bbb 100644 --- a/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateVisibleSignature.java +++ b/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateVisibleSignature.java @@ -35,18 +35,15 @@ import org.apache.pdfbox.pdmodel.interactive.digitalsignature.SignatureOptions; import org.apache.pdfbox.pdmodel.interactive.digitalsignature.visible.PDVisibleSigProperties; import org.apache.pdfbox.pdmodel.interactive.digitalsignature.visible.PDVisibleSignDesigner; -import org.bouncycastle.jce.provider.BouncyCastleProvider; /** - * This is an example for visual signing a pdf with bouncy castle. + * This is an example for visual signing a pdf. * @see CreateSignature * @author Vakhtang Koroghlishvili */ public class CreateVisibleSignature extends CreateSignatureBase { - private static final BouncyCastleProvider BCPROVIDER = new BouncyCastleProvider(); - private SignatureOptions signatureOptions; private PDVisibleSignDesigner visibleSignDesigner; private final PDVisibleSigProperties visibleSignatureProperties = new PDVisibleSigProperties(); @@ -188,7 +185,7 @@ public static void main(String[] args) throws KeyStoreException, CertificateExce } File ksFile = new File(args[0]); - KeyStore keystore = KeyStore.getInstance("PKCS12", BCPROVIDER); + KeyStore keystore = KeyStore.getInstance("PKCS12"); char[] pin = args[1].toCharArray(); keystore.load(new FileInputStream(ksFile), pin); From 9d8ee0f668d43b68865be446d3ec42ba5cb4d6d5 Mon Sep 17 00:00:00 2001 From: John Hewson Date: Thu, 18 Aug 2016 17:04:51 +0000 Subject: [PATCH 0278/2182] PDFBOX-3467: don't modify during getAnnotations git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1756835 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/pdfbox/pdmodel/PDPage.java | 4 +--- .../pdfbox/pdmodel/common/COSArrayList.java | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPage.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPage.java index 44a4e116bfd..d2f4db87c7d 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPage.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPage.java @@ -647,9 +647,7 @@ public List getAnnotations() throws IOException COSArray annots = (COSArray) page.getDictionaryObject(COSName.ANNOTS); if (annots == null) { - annots = new COSArray(); - page.setItem(COSName.ANNOTS, annots); - retval = new COSArrayList(new ArrayList(), annots); + return new COSArrayList(page, COSName.ANNOTS); } else { diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/COSArrayList.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/COSArrayList.java index 7623d42994b..6acc3301b1b 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/COSArrayList.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/COSArrayList.java @@ -67,6 +67,22 @@ public COSArrayList( List actualList, COSArray cosArray ) array = cosArray; } + /** + * This constructor is to be used if the array doesn't exist, but is to be created and added to + * the parent dictionary as soon as the first element is added to the array. + * + * @param dictionary The dictionary that holds the item, and will hold the array if an item is + * added. + * @param dictionaryKey The key into the dictionary to set the item. + */ + public COSArrayList(COSDictionary dictionary, COSName dictionaryKey) + { + array = new COSArray(); + actual = new ArrayList(); + parentDict = dictionary; + dictKey = dictionaryKey; + } + /** * This is a really special constructor. Sometimes the PDF spec says * that a dictionary entry can either be a single item or an array of those From ef740b963c2ef432f481090cd6dd0077ef757106 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Fri, 19 Aug 2016 20:03:22 +0000 Subject: [PATCH 0279/2182] PDFBOX-2852: remove redundant variables, as suggested by Lorenz Pahl git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1756961 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/xmpbox/schema/XMPSchema.java | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/xmpbox/src/main/java/org/apache/xmpbox/schema/XMPSchema.java b/xmpbox/src/main/java/org/apache/xmpbox/schema/XMPSchema.java index 73efb44b5cc..69f46b3081a 100644 --- a/xmpbox/src/main/java/org/apache/xmpbox/schema/XMPSchema.java +++ b/xmpbox/src/main/java/org/apache/xmpbox/schema/XMPSchema.java @@ -746,8 +746,7 @@ public void removeUnqualifiedSequenceValue(String qualifiedSeqName, String seqVa */ public void removeUnqualifiedArrayValue(String arrayName, AbstractField fieldValue) { - String qualifiedArrayName = arrayName; - ArrayProperty array = (ArrayProperty) getAbstractProperty(qualifiedArrayName); + ArrayProperty array = (ArrayProperty) getAbstractProperty(arrayName); if (array != null) { List toDelete = new ArrayList(); @@ -791,8 +790,7 @@ public void removeUnqualifiedSequenceValue(String qualifiedSeqName, AbstractFiel */ public void addUnqualifiedSequenceValue(String simpleSeqName, String seqValue) { - String qualifiedSeqName = simpleSeqName; - ArrayProperty seq = (ArrayProperty) getAbstractProperty(qualifiedSeqName); + ArrayProperty seq = (ArrayProperty) getAbstractProperty(simpleSeqName); TextType li = createTextType(XmpConstants.LIST_NAME, seqValue); if (seq != null) { @@ -839,8 +837,7 @@ public void addBagValue(String qualifiedSeqName, AbstractField seqValue) */ public void addUnqualifiedSequenceValue(String seqName, AbstractField seqValue) { - String qualifiedSeqName = seqName; - ArrayProperty seq = (ArrayProperty) getAbstractProperty(qualifiedSeqName); + ArrayProperty seq = (ArrayProperty) getAbstractProperty(seqName); if (seq != null) { seq.getContainer().addProperty(seqValue); @@ -884,8 +881,7 @@ public List getUnqualifiedSequenceValueList(String seqName) */ public void removeUnqualifiedSequenceDateValue(String seqName, Calendar date) { - String qualifiedSeqName = seqName; - ArrayProperty seq = (ArrayProperty) getAbstractProperty(qualifiedSeqName); + ArrayProperty seq = (ArrayProperty) getAbstractProperty(seqName); if (seq != null) { List toDelete = new ArrayList(); @@ -946,9 +942,8 @@ public void addUnqualifiedSequenceDateValue(String seqName, Calendar date) */ public List getUnqualifiedSequenceDateValueList(String seqName) { - String qualifiedSeqName = seqName; List retval = null; - ArrayProperty seq = (ArrayProperty) getAbstractProperty(qualifiedSeqName); + ArrayProperty seq = (ArrayProperty) getAbstractProperty(seqName); if (seq != null) { retval = new ArrayList(); @@ -1026,12 +1021,11 @@ public void reorganizeAltOrder(ComplexPropertyContainer alt) */ public void setUnqualifiedLanguagePropertyValue(String name, String language, String value) { - String qualifiedName = name; if (language == null || language.isEmpty()) { language = XmpConstants.X_DEFAULT; } - AbstractField property = getAbstractProperty(qualifiedName); + AbstractField property = getAbstractProperty(name); ArrayProperty arrayProp; if (property != null) { From 22d7abf6d1563a9e4ebfb0411bde7b1fa4ef45da Mon Sep 17 00:00:00 2001 From: Maruan Sahyoun Date: Mon, 22 Aug 2016 13:48:48 +0000 Subject: [PATCH 0280/2182] PDFBOX-3461: add new template with more control character samples; remove unused imports git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1757169 13f79535-47bb-0310-9956-ffa450edef68 --- .../form/ControlCharacterTest.java | 5 ----- .../interactive/form/ControlCharacters.pdf | Bin 12969 -> 43916 bytes 2 files changed, 5 deletions(-) diff --git a/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/interactive/form/ControlCharacterTest.java b/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/interactive/form/ControlCharacterTest.java index 54853a07f24..b15aa03d5e8 100644 --- a/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/interactive/form/ControlCharacterTest.java +++ b/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/interactive/form/ControlCharacterTest.java @@ -20,18 +20,13 @@ import java.io.File; import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayDeque; import java.util.ArrayList; -import java.util.Arrays; -import java.util.Deque; import java.util.List; import org.apache.pdfbox.cos.COSString; import org.apache.pdfbox.pdfparser.PDFStreamParser; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationWidget; -import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceStream; import org.junit.After; import org.junit.Before; import org.junit.Test; diff --git a/pdfbox/src/test/resources/org/apache/pdfbox/pdmodel/interactive/form/ControlCharacters.pdf b/pdfbox/src/test/resources/org/apache/pdfbox/pdmodel/interactive/form/ControlCharacters.pdf index 094347627dbd21ec7dae8324f37e4c582832a731..09ae7ccf26fa3686bdadea9f5400fe3c1c1d510b 100644 GIT binary patch literal 43916 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 A4FCWD delta 3934 zcmcJSdpy(oAIE2AGB(6!oG!~Hx$N@&Zu@Ri$^Di@ja;*2n9C?C>33R^SW@&oazskb z>B7-TBIQv+MHhusM{**$)=7>_NcnBk=^Q!zPUnx`pL>7akN5NadSAA^_diCS;is7} z0FVQ5sH;f;lWI$1gKQ4fg#=K!BmjgU8r6a1Lt=s;2?Rhtb8{?T7#JB4iiH8B1`3Oz zvtX}+FtQB;WV2Z|038G&CIev8tT;3)z}l7tLDn=n$J~$VC=BGs`T%qilLo8G;Yn;J z)pav}tBe6q*F;9fkN^gWMp{E%D~RKhAQ)Gu>lUcS;|1`{6!nQ4<5AYsviYk0zrAbqv9#&`|FV? zBEp$JcQd?6NdqP#S4c94Kp4=PFLIQqW>cN{!r+(?5&+1`K!d1jNenjCLy{e6ZXO-8 znZF?diwXHPfX7qY$m2N$BamK9H1`_jx~a-M6XH1}uq24r%Wn_jX}X1~_s)%Jit2KB zA?`EE32r7tx!7^?kH78wz&MSwL!-ynΈCOL~p)C7-D>Wy2N-oAGEd0pemEJ_OD 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 Date: Mon, 22 Aug 2016 15:18:14 +0000 Subject: [PATCH 0281/2182] PDFBOX-3470: improve example with non standard text, border and background color git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1757199 13f79535-47bb-0310-9956-ffa450edef68 --- .../interactive/form/CreateSimpleForm.java | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/examples/src/main/java/org/apache/pdfbox/examples/interactive/form/CreateSimpleForm.java b/examples/src/main/java/org/apache/pdfbox/examples/interactive/form/CreateSimpleForm.java index 451050aa03e..f1f5516e3b0 100644 --- a/examples/src/main/java/org/apache/pdfbox/examples/interactive/form/CreateSimpleForm.java +++ b/examples/src/main/java/org/apache/pdfbox/examples/interactive/form/CreateSimpleForm.java @@ -18,6 +18,7 @@ package org.apache.pdfbox.examples.interactive.form; import java.io.IOException; +import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPage; @@ -25,7 +26,10 @@ import org.apache.pdfbox.pdmodel.common.PDRectangle; import org.apache.pdfbox.pdmodel.font.PDFont; import org.apache.pdfbox.pdmodel.font.PDType1Font; +import org.apache.pdfbox.pdmodel.graphics.color.PDColor; +import org.apache.pdfbox.pdmodel.graphics.color.PDDeviceRGB; import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationWidget; +import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceCharacteristicsDictionary; import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm; import org.apache.pdfbox.pdmodel.interactive.form.PDTextField; @@ -72,8 +76,10 @@ public static void main(String[] args) throws IOException textBox.setPartialName("SampleField"); // Acrobat sets the font size to 12 as default // This is done by setting the font size to '12' on the - // field level. - defaultAppearanceString = "/Helv 12 Tf 0 g"; + // field level. + // The text color is set to blue in this example. + // To use black, replace "0 0 1 rg" with "0 0 0 rg" or "0 g". + defaultAppearanceString = "/Helv 12 Tf 0 0 1 rg"; textBox.setDefaultAppearance(defaultAppearanceString); // add the field to the acroform @@ -85,6 +91,14 @@ public static void main(String[] args) throws IOException widget.setRectangle(rect); widget.setPage(page); + // set green border and yellow background + // if you prefer defaults, just delete this code block + PDAppearanceCharacteristicsDictionary fieldAppearance + = new PDAppearanceCharacteristicsDictionary(new COSDictionary()); + fieldAppearance.setBorderColour(new PDColor(new float[]{0,1,0}, PDDeviceRGB.INSTANCE)); + fieldAppearance.setBackground(new PDColor(new float[]{1,1,0}, PDDeviceRGB.INSTANCE)); + widget.setAppearanceCharacteristics(fieldAppearance); + // make sure the annotation is visible on screen and paper widget.setPrinted(true); From 4f0463d6b195b0cbdc446e065ac87b8f2fd66e14 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Mon, 22 Aug 2016 15:18:57 +0000 Subject: [PATCH 0282/2182] PDFBOX-3470: set background, fix bug in border color, don't set width 1 git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1757205 13f79535-47bb-0310-9956-ffa450edef68 --- .../form/AppearanceGeneratorHelper.java | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/AppearanceGeneratorHelper.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/AppearanceGeneratorHelper.java index ea25cb61d44..74dfb15416a 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/AppearanceGeneratorHelper.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/AppearanceGeneratorHelper.java @@ -192,14 +192,23 @@ private void initializeAppearanceContent(PDAnnotationWidget widget, PDAppearance appearanceStream, output); PDAppearanceCharacteristicsDictionary appearanceCharacteristics = widget.getAppearanceCharacteristics(); - // TODO: support more entries like patterns, background color etc. + // TODO: support more entries like patterns, etc. if (appearanceCharacteristics != null) { + PDColor backgroundColour = appearanceCharacteristics.getBackground(); + if (backgroundColour != null) + { + contents.setNonStrokingColor(backgroundColour); + PDRectangle bbox = resolveBoundingBox(widget, appearanceStream); + contents.addRect(bbox.getLowerLeftX(),bbox.getLowerLeftY(),bbox.getWidth(), bbox.getHeight()); + contents.fill(); + } + float lineWidth = 0f; PDColor borderColour = appearanceCharacteristics.getBorderColour(); if (borderColour != null) { - contents.setNonStrokingColor(borderColour); + contents.setStrokingColor(borderColour); lineWidth = 1f; } PDBorderStyleDictionary borderStyle = widget.getBorderStyle(); @@ -210,7 +219,10 @@ private void initializeAppearanceContent(PDAnnotationWidget widget, PDAppearance if (lineWidth > 0) { - contents.setLineWidth(lineWidth); + if (lineWidth != 1) + { + contents.setLineWidth(lineWidth); + } PDRectangle bbox = resolveBoundingBox(widget, appearanceStream); PDRectangle clipRect = applyPadding(bbox, Math.max(DEFAULT_PADDING, lineWidth/2)); contents.addRect(clipRect.getLowerLeftX(),clipRect.getLowerLeftY(),clipRect.getWidth(), clipRect.getHeight()); From fc4afe218b0c1c9a29a1ee7fee816594053ee093 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Mon, 22 Aug 2016 15:31:14 +0000 Subject: [PATCH 0283/2182] PDFBOX-3468: downgrade dash error log to warning git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1757213 13f79535-47bb-0310-9956-ffa450edef68 --- .../contentstream/operator/state/SetLineDashPattern.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/contentstream/operator/state/SetLineDashPattern.java b/pdfbox/src/main/java/org/apache/pdfbox/contentstream/operator/state/SetLineDashPattern.java index e9a1ce0743a..d9378a5a09e 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/contentstream/operator/state/SetLineDashPattern.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/contentstream/operator/state/SetLineDashPattern.java @@ -71,14 +71,14 @@ public void process(Operator operator, List arguments) throws MissingOp } else { - LOG.error("dash array has non number element " + base + ", ignored"); + LOG.warn("dash array has non number element " + base + ", ignored"); dashArray = new COSArray(); break; } } if (dashArray.size() > 0 && allZero) { - LOG.error("dash lengths all zero, ignored"); + LOG.warn("dash lengths all zero, ignored"); dashArray = new COSArray(); } context.setLineDashPattern(dashArray, dashPhase); From 81027165fdeeba60411cfd8bdf6f38074bc2cfaa Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Tue, 23 Aug 2016 16:22:27 +0000 Subject: [PATCH 0284/2182] PDFBOX-3468: downgrade dash error log to warning git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1757403 13f79535-47bb-0310-9956-ffa450edef68 --- pdfbox/src/main/java/org/apache/pdfbox/cos/COSArray.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/cos/COSArray.java b/pdfbox/src/main/java/org/apache/pdfbox/cos/COSArray.java index 246886c3086..d8fb5303c39 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/cos/COSArray.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/cos/COSArray.java @@ -561,7 +561,7 @@ public void setFloatArray( float[] value ) * * @return the COSArray as List */ - public List toList() + public List toList() { List retList = new ArrayList(size()); for (int i = 0; i < size(); i++) From bddd42c2e7eb60a9110c64d552ef3d2eb4be32f1 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Tue, 23 Aug 2016 16:37:19 +0000 Subject: [PATCH 0285/2182] PDFBOX-2852: add generic type argument to uses of PDNameTreeNode, as suggested by Lorenz Pahl git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1757404 13f79535-47bb-0310-9956-ffa450edef68 --- .../pdfbox/pdmodel/PDDestinationNameTreeNode.java | 2 +- .../pdfbox/pdmodel/PDEmbeddedFilesNameTreeNode.java | 2 +- .../pdfbox/pdmodel/PDJavascriptNameTreeNode.java | 2 +- .../pdmodel/PDStructureElementNameTreeNode.java | 2 +- .../apache/pdfbox/pdmodel/common/PDNameTreeNode.java | 12 ++++++------ .../logicalstructure/PDStructureTreeRoot.java | 4 ++-- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDestinationNameTreeNode.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDestinationNameTreeNode.java index 30aeaa0cc17..9544ed726be 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDestinationNameTreeNode.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDestinationNameTreeNode.java @@ -64,7 +64,7 @@ protected PDPageDestination convertCOSToPD( COSBase base ) throws IOException } @Override - protected PDNameTreeNode createChildNode( COSDictionary dic ) + protected PDNameTreeNode createChildNode( COSDictionary dic ) { return new PDDestinationNameTreeNode(dic); } diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDEmbeddedFilesNameTreeNode.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDEmbeddedFilesNameTreeNode.java index ae179705f58..a7463c0bf68 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDEmbeddedFilesNameTreeNode.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDEmbeddedFilesNameTreeNode.java @@ -54,7 +54,7 @@ protected PDComplexFileSpecification convertCOSToPD( COSBase base ) throws IOExc } @Override - protected PDNameTreeNode createChildNode( COSDictionary dic ) + protected PDNameTreeNode createChildNode( COSDictionary dic ) { return new PDEmbeddedFilesNameTreeNode(dic); } diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDJavascriptNameTreeNode.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDJavascriptNameTreeNode.java index 7c4ebf39c0f..c6870ce0296 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDJavascriptNameTreeNode.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDJavascriptNameTreeNode.java @@ -59,7 +59,7 @@ protected PDActionJavaScript convertCOSToPD( COSBase base ) throws IOException } @Override - protected PDNameTreeNode createChildNode( COSDictionary dic ) + protected PDNameTreeNode createChildNode( COSDictionary dic ) { return new PDJavascriptNameTreeNode(dic); } diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDStructureElementNameTreeNode.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDStructureElementNameTreeNode.java index 427aaad6b0b..18bd54d635b 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDStructureElementNameTreeNode.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDStructureElementNameTreeNode.java @@ -55,7 +55,7 @@ protected PDStructureElement convertCOSToPD( COSBase base ) throws IOException } @Override - protected PDNameTreeNode createChildNode( COSDictionary dic ) + protected PDNameTreeNode createChildNode( COSDictionary dic ) { return new PDStructureElementNameTreeNode(dic); } diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/PDNameTreeNode.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/PDNameTreeNode.java index 0d463f30927..df1cf34ce5b 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/PDNameTreeNode.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/PDNameTreeNode.java @@ -42,7 +42,7 @@ public abstract class PDNameTreeNode implements COSObje private static final Log LOG = LogFactory.getLog(PDNameTreeNode.class); private final COSDictionary node; - private PDNameTreeNode parent; + private PDNameTreeNode parent; /** * Constructor. @@ -78,7 +78,7 @@ public COSDictionary getCOSObject() * * @return parent node */ - public PDNameTreeNode getParent() + public PDNameTreeNode getParent() { return parent; } @@ -88,7 +88,7 @@ public PDNameTreeNode getParent() * * @param parentNode the node to be set as parent */ - public void setParent(PDNameTreeNode parentNode) + public void setParent(PDNameTreeNode parentNode) { parent = parentNode; calculateLimits(); @@ -135,7 +135,7 @@ public void setKids( List> kids ) { if (kids != null && kids.size() > 0) { - for (PDNameTreeNode kidsNode : kids) + for (PDNameTreeNode kidsNode : kids) { kidsNode.setParent(this); } @@ -167,8 +167,8 @@ private void calculateLimits() List> kids = getKids(); if (kids != null && kids.size() > 0) { - PDNameTreeNode firstKid = kids.get(0); - PDNameTreeNode lastKid = kids.get(kids.size() - 1); + PDNameTreeNode firstKid = kids.get(0); + PDNameTreeNode lastKid = kids.get(kids.size() - 1); String lowerLimit = firstKid.getLowerLimit(); setLowerLimit(lowerLimit); String upperLimit = lastKid.getUpperLimit(); diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/documentinterchange/logicalstructure/PDStructureTreeRoot.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/documentinterchange/logicalstructure/PDStructureTreeRoot.java index ae76591bf71..e997e400835 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/documentinterchange/logicalstructure/PDStructureTreeRoot.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/documentinterchange/logicalstructure/PDStructureTreeRoot.java @@ -118,7 +118,7 @@ public void setK(COSBase k) * * @return the ID tree */ - public PDNameTreeNode getIDTree() + public PDNameTreeNode getIDTree() { COSDictionary idTreeDic = (COSDictionary) this.getCOSObject().getDictionaryObject(COSName.ID_TREE); if (idTreeDic != null) @@ -133,7 +133,7 @@ public PDNameTreeNode getIDTree() * * @param idTree the ID tree */ - public void setIDTree(PDNameTreeNode idTree) + public void setIDTree(PDNameTreeNode idTree) { this.getCOSObject().setItem(COSName.ID_TREE, idTree); } From ba6c5953cdf4fa3c868a1fd10a47d327d125b776 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Tue, 23 Aug 2016 17:48:58 +0000 Subject: [PATCH 0286/2182] PDFBOX-3472: avoid NPE as proposed by Petras; improve javadoc git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1757414 13f79535-47bb-0310-9956-ffa450edef68 --- .../pdfbox/preflight/metadata/PDFAIdentificationValidation.java | 2 +- .../java/org/apache/xmpbox/schema/PDFAIdentificationSchema.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/preflight/src/main/java/org/apache/pdfbox/preflight/metadata/PDFAIdentificationValidation.java b/preflight/src/main/java/org/apache/pdfbox/preflight/metadata/PDFAIdentificationValidation.java index 07d7e32cff2..1d4fbe99b2c 100644 --- a/preflight/src/main/java/org/apache/pdfbox/preflight/metadata/PDFAIdentificationValidation.java +++ b/preflight/src/main/java/org/apache/pdfbox/preflight/metadata/PDFAIdentificationValidation.java @@ -82,7 +82,7 @@ public List validatePDFAIdentifer(XMPMetadata metadata) throws } } checkConformanceLevel(ve, id.getConformance()); - checkPartNumber(ve, id.getPart()); + checkPartNumber(ve, id.getPart() == null ? -1 : id.getPart()); return ve; } diff --git a/xmpbox/src/main/java/org/apache/xmpbox/schema/PDFAIdentificationSchema.java b/xmpbox/src/main/java/org/apache/xmpbox/schema/PDFAIdentificationSchema.java index 2cea8b62f1d..8a50676dea5 100644 --- a/xmpbox/src/main/java/org/apache/xmpbox/schema/PDFAIdentificationSchema.java +++ b/xmpbox/src/main/java/org/apache/xmpbox/schema/PDFAIdentificationSchema.java @@ -190,7 +190,7 @@ public void setConformanceProperty(TextType conf) throws BadFieldValueException /** * Give the PDFAVersionId (as an integer) * - * @return Part value (Integer) + * @return Part value (Integer) or null if it is missing */ public Integer getPart() { From 3a619a1b0db32a075993ec7c37e9a5e969c7e689 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Wed, 24 Aug 2016 18:46:58 +0000 Subject: [PATCH 0287/2182] PDFBOX-3473: avoid exception is resources are missing in a page git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1757567 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/pdfbox/multipdf/PDFMergerUtility.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/multipdf/PDFMergerUtility.java b/pdfbox/src/main/java/org/apache/pdfbox/multipdf/PDFMergerUtility.java index 78ff4fadc3d..daa12f5ba35 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/multipdf/PDFMergerUtility.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/multipdf/PDFMergerUtility.java @@ -555,8 +555,16 @@ public void appendDocument(PDDocument destination, PDDocument source) throws IOE newPage.setCropBox(page.getCropBox()); newPage.setMediaBox(page.getMediaBox()); newPage.setRotation(page.getRotation()); - // this is smart enough to just create references for resources that are used on multiple pages - newPage.setResources(new PDResources((COSDictionary) cloner.cloneForNewDocument(page.getResources()))); + PDResources resources = page.getResources(); + if (resources != null) + { + // this is smart enough to just create references for resources that are used on multiple pages + newPage.setResources(new PDResources((COSDictionary) cloner.cloneForNewDocument(resources))); + } + else + { + newPage.setResources(new PDResources()); + } if (mergeStructTree) { updateStructParentEntries(newPage, destParentTreeNextKey); From c48839153961bcb1395cd02d081149e7784d3bdc Mon Sep 17 00:00:00 2001 From: Maruan Sahyoun Date: Thu, 25 Aug 2016 05:17:37 +0000 Subject: [PATCH 0288/2182] PDFBOX-3471: ensure that all nodes are visited when removing; ignore comments git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1757605 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/xmpbox/xml/DomXmpParser.java | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/xmpbox/src/main/java/org/apache/xmpbox/xml/DomXmpParser.java b/xmpbox/src/main/java/org/apache/xmpbox/xml/DomXmpParser.java index 8bd5e44024e..74974cd5bd8 100644 --- a/xmpbox/src/main/java/org/apache/xmpbox/xml/DomXmpParser.java +++ b/xmpbox/src/main/java/org/apache/xmpbox/xml/DomXmpParser.java @@ -789,25 +789,32 @@ else if ((ln != null) && !(ln.equals(element.getLocalName()))) */ private void removeComments(Node root) { - if (root.getChildNodes().getLength()<=1) + // will hold the nodes which are to be deleted + List forDeletion = new ArrayList(); + + NodeList nl = root.getChildNodes(); + + if (nl.getLength()<=1) { // There is only one node so we do not remove it return; } - NodeList nl = root.getChildNodes(); - for (int i=0; i < nl.getLength(); i++) + + for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (node instanceof Comment) { - // remove the comment - root.removeChild(node); + // comments to be deleted + forDeletion.add(node); } else if (node instanceof Text) { if (node.getTextContent().trim().isEmpty()) { - root.removeChild(node); + // TODO: verify why this is necessary + // empty text nodes to be deleted + forDeletion.add(node); } } else if (node instanceof Element) @@ -816,6 +823,12 @@ else if (node instanceof Element) removeComments(node); } // else do nothing } + + // now remove the child nodes + for (Node node : forDeletion) + { + root.removeChild(node); + } } private AbstractStructuredType instanciateStructured(TypeMapping tm, Types type, String name, From 49e82f0ad026e3977b69ae4f2ad1b74cb3fe0e44 Mon Sep 17 00:00:00 2001 From: Maruan Sahyoun Date: Thu, 25 Aug 2016 14:37:32 +0000 Subject: [PATCH 0289/2182] PDFBOX-3471: set to ignore comments with DocumentBuilderFactory git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1757694 13f79535-47bb-0310-9956-ffa450edef68 --- xmpbox/src/main/java/org/apache/xmpbox/xml/DomXmpParser.java | 1 + 1 file changed, 1 insertion(+) diff --git a/xmpbox/src/main/java/org/apache/xmpbox/xml/DomXmpParser.java b/xmpbox/src/main/java/org/apache/xmpbox/xml/DomXmpParser.java index 74974cd5bd8..061d9acd5c0 100644 --- a/xmpbox/src/main/java/org/apache/xmpbox/xml/DomXmpParser.java +++ b/xmpbox/src/main/java/org/apache/xmpbox/xml/DomXmpParser.java @@ -84,6 +84,7 @@ public DomXmpParser() throws XmpParsingException dbFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); dbFactory.setXIncludeAware(false); dbFactory.setExpandEntityReferences(false); + dbFactory.setIgnoringComments(true); dbFactory.setNamespaceAware(true); dBuilder = dbFactory.newDocumentBuilder(); nsFinder = new NamespaceFinder(); From 740d2ba73f4fdb2de24eba190b709c5f87165eb8 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Fri, 26 Aug 2016 17:22:29 +0000 Subject: [PATCH 0290/2182] PDFBOX-3475: repair /Length2 git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1757897 13f79535-47bb-0310-9956-ffa450edef68 --- .../pdfbox/pdmodel/font/PDType1Font.java | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1Font.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1Font.java index 097ea7e5ca0..b2a72de4219 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1Font.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1Font.java @@ -235,9 +235,10 @@ public PDType1Font(COSDictionary fontDictionary) throws IOException int length1 = stream.getInt(COSName.LENGTH1); int length2 = stream.getInt(COSName.LENGTH2); - // repair Length1 if necessary + // repair Length1 and Length2 if necessary byte[] bytes = fontFile.toByteArray(); length1 = repairLength1(bytes, length1); + length2 = repairLength2(bytes, length1, length2); if (bytes.length > 0 && (bytes[0] & 0xff) == PFB_START_MARKER) { @@ -340,6 +341,27 @@ private int repairLength1(byte[] bytes, int length1) return length1; } + /** + * Some Type 1 fonts have an invalid Length2, see PDFBOX-3475. A negative /Length2 brings an + * IllegalArgumentException in Arrays.copyOfRange(), a huge value eats up memory because of + * padding. + * + * @param bytes Type 1 stream bytes + * @param length1 Length1 from the Type 1 stream + * @param length2 Length2 from the Type 1 stream + * @return repaired Length2 value + */ + private int repairLength2(byte[] bytes, int length1, int length2) + { + // repair Length2 if necessary + if (length2 < 0 || length2 > bytes.length - length1) + { + LOG.warn("Ignored invalid Length2 " + length2 + " for Type 1 font " + getName()); + length2 = bytes.length - length1; + } + return length2; + } + /** * Returns the PostScript name of the font. */ From 96794bf381438cae898a693cccf23d487246c06b Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Sat, 27 Aug 2016 10:56:29 +0000 Subject: [PATCH 0291/2182] PDFBOX-3475: sonarQube fix git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1757988 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/pdfbox/pdmodel/font/PDType1Font.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1Font.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1Font.java index b2a72de4219..53f3ab99528 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1Font.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1Font.java @@ -357,7 +357,7 @@ private int repairLength2(byte[] bytes, int length1, int length2) if (length2 < 0 || length2 > bytes.length - length1) { LOG.warn("Ignored invalid Length2 " + length2 + " for Type 1 font " + getName()); - length2 = bytes.length - length1; + return bytes.length - length1; } return length2; } From 0dad19d3397485c79b8a836bfd59f300327cbf09 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Sat, 27 Aug 2016 13:14:41 +0000 Subject: [PATCH 0292/2182] PDFBOX-2984: avoid negative height and space width git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1758027 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/org/apache/pdfbox/text/LegacyPDFStreamEngine.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/text/LegacyPDFStreamEngine.java b/pdfbox/src/main/java/org/apache/pdfbox/text/LegacyPDFStreamEngine.java index ab1fd85d60a..085d6d5a45c 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/text/LegacyPDFStreamEngine.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/text/LegacyPDFStreamEngine.java @@ -319,8 +319,8 @@ else if (font instanceof PDType0Font) processTextPosition(new TextPosition(pageRotation, pageSize.getWidth(), pageSize.getHeight(), translatedTextRenderingMatrix, nextX, nextY, - dyDisplay, dxDisplay, - spaceWidthDisplay, unicode, new int[] { code } , font, fontSize, + Math.abs(dyDisplay), dxDisplay, + Math.abs(spaceWidthDisplay), unicode, new int[] { code } , font, fontSize, (int)(fontSize * textMatrix.getScalingFactorX()))); } From dbfdedc6a72bb30a5ebaadfe4c460f7ddad29c70 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Sat, 27 Aug 2016 13:24:44 +0000 Subject: [PATCH 0293/2182] PDFBOX-2984: add test files git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1758029 13f79535-47bb-0310-9956-ffa450edef68 --- .../resources/input/PDFBOX-2984-180\302\260.pdf" | Bin 0 -> 1374 bytes .../PDFBOX-2984-180\302\260.pdf-sorted.txt" | 4 ++++ .../input/PDFBOX-2984-180\302\260.pdf.txt" | 4 ++++ 3 files changed, 8 insertions(+) create mode 100644 "pdfbox/src/test/resources/input/PDFBOX-2984-180\302\260.pdf" create mode 100644 "pdfbox/src/test/resources/input/PDFBOX-2984-180\302\260.pdf-sorted.txt" create mode 100644 "pdfbox/src/test/resources/input/PDFBOX-2984-180\302\260.pdf.txt" diff --git "a/pdfbox/src/test/resources/input/PDFBOX-2984-180\302\260.pdf" "b/pdfbox/src/test/resources/input/PDFBOX-2984-180\302\260.pdf" new file mode 100644 index 0000000000000000000000000000000000000000..a693e31cd127fddaedb33053c6e2b23ffa9a76c4 GIT binary patch literal 1374 zcmcIkTSyd97^a)(u|?m?!Z;L5LAi6;nVs2^)m?WNMN3&DqeW_TkL%brBQv9|`cR;~ zNQB^vL?x9{5C}q~fng|NNP$+678pW7P!Zy#2a`Hy&2^m(d+NXpobUYq`M>YK9BY}^ zpTpQVU|st7^8;WY4b`eTkedsrlTGyqQU#JBMbt2$P9aT~RRvPSnktjRNQW#o4*-`7 zASFcH$bO@H%nne+a!7|kJ28hG`Bws}Ky6SA$R@ax^JI5G9Y-Nq@~BZ5q-``LAMfOC ztiU_$P~;e!C^|)aVL&w`13^Zl2|o>y+es`EN-^+Ohy3b3fONG%tHuf(F<@N*A@_eN z2xbbRi2~ucM!_#f45UHIAHmAJs9FsnK$RdRY}7)Ap-Jv^LqpO93y9vxzRG~n{GHod zo_HFbMtffuf!zfqU&niAI`((`8koy!l(MF#+m8;OxSlcF@8Z&0?;YND`BU9WEt57F zonPqtOxuOU1A)1B6@A~oWoBP%o_N)RMpJxUKc3T9hAT%rD_Kovm+s_^4D1=Rkdm*4 zUMoIHWt=xoICPqX5#@1%&4kghrbrMrehjqbXSU4_l}`4<;7Zr6G;e*`UCVMx`rg!; zyu~ex2cHR`b*yD%$GOMLH{Wyuad=_6yL-O0v)EU7`r)DWtrs)iPMt45^8Q8B(3yov z=R~OL<;3mO2m8JhKk7-(xxeeuUj&iD#Q73I3~s&+{Z16dEf`!8(|OEcQ-kDz^W#W> zDsQMVV)I9)kO7oO(h)g>!W=Bls0kCCxRFel zXiv5i9m#P;XMzqxljI1}VsBYMRdM-Z)uD>KFqkW_jNeQ1qTS1LZjSb_b_Xqp9=F@e kF+Q4QUGU!~_{k}koAHD5r(Gq@h-KU9v;(WvSLz490UxoD9{>OV literal 0 HcmV?d00001 diff --git "a/pdfbox/src/test/resources/input/PDFBOX-2984-180\302\260.pdf-sorted.txt" "b/pdfbox/src/test/resources/input/PDFBOX-2984-180\302\260.pdf-sorted.txt" new file mode 100644 index 00000000000..f0db698dbe5 --- /dev/null +++ "b/pdfbox/src/test/resources/input/PDFBOX-2984-180\302\260.pdf-sorted.txt" @@ -0,0 +1,4 @@ +Apache PDFBox ® +180° text matrix +Apache PDFBox ® +180° ctm diff --git "a/pdfbox/src/test/resources/input/PDFBOX-2984-180\302\260.pdf.txt" "b/pdfbox/src/test/resources/input/PDFBOX-2984-180\302\260.pdf.txt" new file mode 100644 index 00000000000..f0db698dbe5 --- /dev/null +++ "b/pdfbox/src/test/resources/input/PDFBOX-2984-180\302\260.pdf.txt" @@ -0,0 +1,4 @@ +Apache PDFBox ® +180° text matrix +Apache PDFBox ® +180° ctm From 6b3b153ba640d4bb0c2f8acc8b3089f37eec2a58 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Sat, 27 Aug 2016 14:54:08 +0000 Subject: [PATCH 0294/2182] =?UTF-8?q?PDFBOX-2984:=20add=2090=C2=B0=20ad=20?= =?UTF-8?q?270=C2=B0=20to=20test=20files?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1758047 13f79535-47bb-0310-9956-ffa450edef68 --- .../resources/input/PDFBOX-2984-180\302\260.pdf" | Bin 1374 -> 0 bytes .../PDFBOX-2984-180\302\260.pdf-sorted.txt" | 4 ---- .../input/PDFBOX-2984-180\302\260.pdf.txt" | 4 ---- .../resources/input/PDFBOX-2984-rotations.pdf | Bin 0 -> 3244 bytes .../input/PDFBOX-2984-rotations.pdf-sorted.txt | 12 ++++++++++++ .../input/PDFBOX-2984-rotations.pdf.txt | 12 ++++++++++++ 6 files changed, 24 insertions(+), 8 deletions(-) delete mode 100644 "pdfbox/src/test/resources/input/PDFBOX-2984-180\302\260.pdf" delete mode 100644 "pdfbox/src/test/resources/input/PDFBOX-2984-180\302\260.pdf-sorted.txt" delete mode 100644 "pdfbox/src/test/resources/input/PDFBOX-2984-180\302\260.pdf.txt" create mode 100644 pdfbox/src/test/resources/input/PDFBOX-2984-rotations.pdf create mode 100644 pdfbox/src/test/resources/input/PDFBOX-2984-rotations.pdf-sorted.txt create mode 100644 pdfbox/src/test/resources/input/PDFBOX-2984-rotations.pdf.txt diff --git "a/pdfbox/src/test/resources/input/PDFBOX-2984-180\302\260.pdf" "b/pdfbox/src/test/resources/input/PDFBOX-2984-180\302\260.pdf" deleted file mode 100644 index a693e31cd127fddaedb33053c6e2b23ffa9a76c4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1374 zcmcIkTSyd97^a)(u|?m?!Z;L5LAi6;nVs2^)m?WNMN3&DqeW_TkL%brBQv9|`cR;~ zNQB^vL?x9{5C}q~fng|NNP$+678pW7P!Zy#2a`Hy&2^m(d+NXpobUYq`M>YK9BY}^ zpTpQVU|st7^8;WY4b`eTkedsrlTGyqQU#JBMbt2$P9aT~RRvPSnktjRNQW#o4*-`7 zASFcH$bO@H%nne+a!7|kJ28hG`Bws}Ky6SA$R@ax^JI5G9Y-Nq@~BZ5q-``LAMfOC ztiU_$P~;e!C^|)aVL&w`13^Zl2|o>y+es`EN-^+Ohy3b3fONG%tHuf(F<@N*A@_eN z2xbbRi2~ucM!_#f45UHIAHmAJs9FsnK$RdRY}7)Ap-Jv^LqpO93y9vxzRG~n{GHod zo_HFbMtffuf!zfqU&niAI`((`8koy!l(MF#+m8;OxSlcF@8Z&0?;YND`BU9WEt57F zonPqtOxuOU1A)1B6@A~oWoBP%o_N)RMpJxUKc3T9hAT%rD_Kovm+s_^4D1=Rkdm*4 zUMoIHWt=xoICPqX5#@1%&4kghrbrMrehjqbXSU4_l}`4<;7Zr6G;e*`UCVMx`rg!; zyu~ex2cHR`b*yD%$GOMLH{Wyuad=_6yL-O0v)EU7`r)DWtrs)iPMt45^8Q8B(3yov z=R~OL<;3mO2m8JhKk7-(xxeeuUj&iD#Q73I3~s&+{Z16dEf`!8(|OEcQ-kDz^W#W> zDsQMVV)I9)kO7oO(h)g>!W=Bls0kCCxRFel zXiv5i9m#P;XMzqxljI1}VsBYMRdM-Z)uD>KFqkW_jNeQ1qTS1LZjSb_b_Xqp9=F@e kF+Q4QUGU!~_{k}koAHD5r(Gq@h-KU9v;(WvSLz490UxoD9{>OV diff --git "a/pdfbox/src/test/resources/input/PDFBOX-2984-180\302\260.pdf-sorted.txt" "b/pdfbox/src/test/resources/input/PDFBOX-2984-180\302\260.pdf-sorted.txt" deleted file mode 100644 index f0db698dbe5..00000000000 --- "a/pdfbox/src/test/resources/input/PDFBOX-2984-180\302\260.pdf-sorted.txt" +++ /dev/null @@ -1,4 +0,0 @@ -Apache PDFBox ® -180° text matrix -Apache PDFBox ® -180° ctm diff --git "a/pdfbox/src/test/resources/input/PDFBOX-2984-180\302\260.pdf.txt" "b/pdfbox/src/test/resources/input/PDFBOX-2984-180\302\260.pdf.txt" deleted file mode 100644 index f0db698dbe5..00000000000 --- "a/pdfbox/src/test/resources/input/PDFBOX-2984-180\302\260.pdf.txt" +++ /dev/null @@ -1,4 +0,0 @@ -Apache PDFBox ® -180° text matrix -Apache PDFBox ® -180° ctm diff --git a/pdfbox/src/test/resources/input/PDFBOX-2984-rotations.pdf b/pdfbox/src/test/resources/input/PDFBOX-2984-rotations.pdf new file mode 100644 index 0000000000000000000000000000000000000000..5ccc1e807a02635e6b93deb7532511c26606916f GIT binary patch literal 3244 zcmcIn2}~4M7)})rhFy=Q0YO$LT5MB=nfG>f4n>Y-cLVi+LW34Ub#X@=-R|Pfpa?x| z#Izx5j5I_m7K<2ch(;RgQ4cJJYEdgFMX9YyZEdw4A%I%IwllL4=h#vc<0Si%dHLS| zzVH42|Gn9$G@BzD#1Kf-{a^d9A^^ovZ|+hgHWtC&T$RtFSdvq4y1jV_mdW~f&g(%j z35}&W^H?5*B0L?5i$hqCOIjwqtC!0-1e?XVcr@EA!BIjUE%HdpBPEZtH0B^!lDEJk zprj(Kv`!xu!RD|o&S~`)qS<&1j!HiZV~K&3g*2ly0b*#Hp~ZmdUco7_D1%G1eXJPV z&s*HdBZ#j&%1B#_K$iCw_!f!6fEZ4tOd|bUDFEr{)f}{^D;?Rha{%;zp97FHq&f&W zTZ&vr8GFto=8 zABs8LV!7McMP3(+V6$0Ip0GqLXiB2a3qIEQju9!Wh*}3mH6$2&ASN49O6xL|z5aHC`n{(T?Ygxp;Nti>io zp}+c{IEma21CT+4Fn2hVWFAESI3jpW&D5c*e_Q%!2?#z|*www~58O=kOiu6oao(PL zcgC1D6g8i(W={;aZ+>tJUt6EkV0{$6YQg=g_=W=!Cj)6y`kr5#-y#&5QrgnsB?vXz znr0v+31dn+j-=ZPupSa8y+%#wcyiyMY5Jk+?}$I_qk!^L_Hx6uzt6I5jf-HUlHyZGq?i zI<-7!|EBoH;E1zK2W6LL;PHL+P!3|++189;xZ=iYP{?gtDvV9Cd01Ex?{X{fW^=Ke~@*Beu z2%zeOKmb)A1Olk)E)YOjb^fm}DTN4@QIIRhA7j!aKrpM5XXWH#$*g+?D{zaP2xj+) zhR=EOP;4ION%ZjC;|ax;Rp?_EBRC3a1Rr=%(qb`N(8b1qIUp*L9@O(>juHz?GY3dL z4l<%h4UT~NwH8t|d<~9d#3RQC)!$I7v!$BzBd+K-)5;`3a>i30apyLP4gf2(Wtj{GR0_;l= z3Vwpm$+=md{Kp{O>lIM{g^i`y(Cpa6M2DTQQV`m0v=uNQ(SZYNB5ox~ie{_~j6?q) fB7Uc5a7CHM53bXsSe~{GEuz) literal 0 HcmV?d00001 diff --git a/pdfbox/src/test/resources/input/PDFBOX-2984-rotations.pdf-sorted.txt b/pdfbox/src/test/resources/input/PDFBOX-2984-rotations.pdf-sorted.txt new file mode 100644 index 00000000000..c477aafc78a --- /dev/null +++ b/pdfbox/src/test/resources/input/PDFBOX-2984-rotations.pdf-sorted.txt @@ -0,0 +1,12 @@ +Apache PDFBox ® +90° text matrix +Apache PDFBox ® +90° ctm +Apache PDFBox ® +180° text matrix +Apache PDFBox ® +180° ctm +Apache PDFBox ® +270° text matrix +Apache PDFBox ® +270° ctm diff --git a/pdfbox/src/test/resources/input/PDFBOX-2984-rotations.pdf.txt b/pdfbox/src/test/resources/input/PDFBOX-2984-rotations.pdf.txt new file mode 100644 index 00000000000..c477aafc78a --- /dev/null +++ b/pdfbox/src/test/resources/input/PDFBOX-2984-rotations.pdf.txt @@ -0,0 +1,12 @@ +Apache PDFBox ® +90° text matrix +Apache PDFBox ® +90° ctm +Apache PDFBox ® +180° text matrix +Apache PDFBox ® +180° ctm +Apache PDFBox ® +270° text matrix +Apache PDFBox ® +270° ctm From 1b4cec144bcfe3c2e279791f7fb8a77d5c21a363 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Wed, 31 Aug 2016 18:46:01 +0000 Subject: [PATCH 0295/2182] PDFBOX-3477: always clip alpha to 0..1 git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1758664 13f79535-47bb-0310-9956-ffa450edef68 --- .../graphics/blend/BlendComposite.java | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/blend/BlendComposite.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/blend/BlendComposite.java index f20bee8c593..739904626c4 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/blend/BlendComposite.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/blend/BlendComposite.java @@ -45,21 +45,22 @@ public final class BlendComposite implements Composite * @param blendMode Desired blend mode * @param constantAlpha Constant alpha, must be in the inclusive range * [0.0...1.0] or it will be clipped. + * @return a blend composite. */ public static Composite getInstance(BlendMode blendMode, float constantAlpha) { + if (constantAlpha < 0) + { + LOG.warn("using 0 instead of incorrect Alpha " + constantAlpha); + constantAlpha = 0; + } + else if (constantAlpha > 1) + { + LOG.warn("using 1 instead of incorrect Alpha " + constantAlpha); + constantAlpha = 1; + } if (blendMode == BlendMode.NORMAL) { - if (constantAlpha < 0) - { - LOG.warn("using 0 instead of incorrect Alpha " + constantAlpha); - constantAlpha = 0; - } - else if (constantAlpha > 1) - { - LOG.warn("using 1 instead of incorrect Alpha " + constantAlpha); - constantAlpha = 1; - } return AlphaComposite.getInstance(AlphaComposite.SRC_OVER, constantAlpha); } else From 34f9c4128d045161b56ec072eef49328ee827bda Mon Sep 17 00:00:00 2001 From: Maruan Sahyoun Date: Thu, 1 Sep 2016 17:38:50 +0000 Subject: [PATCH 0296/2182] PDFBOX-3165: replace Tab character with space. Proper handling to follow in PDFBOX-3469 git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1758818 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/pdfbox/pdmodel/interactive/form/PlainText.java | 2 +- .../pdfbox/pdmodel/interactive/form/ControlCharacterTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PlainText.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PlainText.java index f5774a64e25..af66d6282fc 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PlainText.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PlainText.java @@ -51,7 +51,7 @@ class PlainText */ PlainText(String textValue) { - List parts = Arrays.asList(textValue.split("\\r\\n|\\n|\\r|\\u2028|\\u2029")); + List parts = Arrays.asList(textValue.replaceAll("\t", " ").split("\\r\\n|\\n|\\r|\\u2028|\\u2029")); paragraphs = new ArrayList(); for (String part : parts) { diff --git a/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/interactive/form/ControlCharacterTest.java b/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/interactive/form/ControlCharacterTest.java index b15aa03d5e8..f3f8888a0df 100644 --- a/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/interactive/form/ControlCharacterTest.java +++ b/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/interactive/form/ControlCharacterTest.java @@ -76,7 +76,7 @@ public void characterNUL() throws IOException acroForm.getField("pdfbox-nul").setValue("NUL\0NUL"); } - @Test(expected=IllegalArgumentException.class) + @Test public void characterTAB() throws IOException { acroForm.getField("pdfbox-tab").setValue("TAB\tTAB"); From 6a686144d5c40960fae2cfc385b655bb5264eb1d Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Thu, 1 Sep 2016 17:41:01 +0000 Subject: [PATCH 0297/2182] PDFBOX-3479: avoid NPE if no rectangle in widget git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1758820 13f79535-47bb-0310-9956-ffa450edef68 --- .../pdmodel/interactive/form/AppearanceGeneratorHelper.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/AppearanceGeneratorHelper.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/AppearanceGeneratorHelper.java index 74dfb15416a..313370c01f8 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/AppearanceGeneratorHelper.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/AppearanceGeneratorHelper.java @@ -129,6 +129,10 @@ public void setAppearanceValue(String apValue) throws IOException appearanceStream = new PDAppearanceStream(field.getAcroForm().getDocument()); PDRectangle rect = widget.getRectangle(); + if (rect == null) + { + throw new IOException("widget of field " + field.getFullyQualifiedName() + " has no rectangle"); + } // Calculate the entries for the bounding box and the transformation matrix // settings for the appearance stream From 9afc50ac1d0b988aaec062ee3053a497850c400c Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Thu, 1 Sep 2016 17:59:47 +0000 Subject: [PATCH 0298/2182] PDFBOX-3479: don't throw exception if no rectangle in widget git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1758824 13f79535-47bb-0310-9956-ffa450edef68 --- .../interactive/form/AppearanceGeneratorHelper.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/AppearanceGeneratorHelper.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/AppearanceGeneratorHelper.java index 313370c01f8..ff26c71a1b3 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/AppearanceGeneratorHelper.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/AppearanceGeneratorHelper.java @@ -22,6 +22,8 @@ import java.io.IOException; import java.io.OutputStream; import java.util.List; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.apache.pdfbox.contentstream.operator.Operator; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.pdfparser.PDFStreamParser; @@ -47,6 +49,8 @@ */ class AppearanceGeneratorHelper { + private static final Log LOG = LogFactory.getLog(AppearanceGeneratorHelper.class); + private static final Operator BMC = Operator.getOperator("BMC"); private static final Operator EMC = Operator.getOperator("EMC"); @@ -126,14 +130,15 @@ public void setAppearanceValue(String apValue) throws IOException } else { - appearanceStream = new PDAppearanceStream(field.getAcroForm().getDocument()); - PDRectangle rect = widget.getRectangle(); if (rect == null) { - throw new IOException("widget of field " + field.getFullyQualifiedName() + " has no rectangle"); + LOG.warn("widget of field " + field.getFullyQualifiedName() + " has no rectangle, no appearance stream created"); + continue; } + appearanceStream = new PDAppearanceStream(field.getAcroForm().getDocument()); + // Calculate the entries for the bounding box and the transformation matrix // settings for the appearance stream int rotation = resolveRotation(widget); From d3c81fe14f646c1593a575814908159a7f0674a6 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Fri, 2 Sep 2016 15:24:24 +0000 Subject: [PATCH 0299/2182] PDFBOX-3000: add no parameter constructor git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1758974 13f79535-47bb-0310-9956-ffa450edef68 --- .../graphics/form/PDTransparencyGroupAttributes.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/form/PDTransparencyGroupAttributes.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/form/PDTransparencyGroupAttributes.java index 68e20f887aa..5e1fed7fb88 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/form/PDTransparencyGroupAttributes.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/form/PDTransparencyGroupAttributes.java @@ -33,6 +33,15 @@ public final class PDTransparencyGroupAttributes implements COSObjectable private final COSDictionary dictionary; private PDColorSpace colorSpace; + /** + * Creates a group object with /Transparency subtype entry. + */ + public PDTransparencyGroupAttributes() + { + dictionary = new COSDictionary(); + dictionary.setItem(COSName.S, COSName.TRANSPARENCY); + } + /** * Creates a group object from a given dictionary * @param dic {@link COSDictionary} object From 3dd6c4151f18f85a551a2d7378c97c5327fbd968 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Fri, 2 Sep 2016 15:27:57 +0000 Subject: [PATCH 0300/2182] PDFBOX-2852: clarify javadoc git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1758976 13f79535-47bb-0310-9956-ffa450edef68 --- .../pdmodel/graphics/state/PDExtendedGraphicsState.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/state/PDExtendedGraphicsState.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/state/PDExtendedGraphicsState.java index 0c435ea9a82..c6ccbaae241 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/state/PDExtendedGraphicsState.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/state/PDExtendedGraphicsState.java @@ -498,7 +498,9 @@ public void setNonStrokingAlphaConstant( Float alpha ) } /** - * This will get the alpha source flag. + * This will get the alpha source flag (“alpha is shapeâ€), that specifies whether the current + * soft mask and alpha constant shall be interpreted as shape values (true) or opacity values + * (false). * * @return The alpha source flag. */ @@ -508,7 +510,9 @@ public boolean getAlphaSourceFlag() } /** - * This will get the alpha source flag. + * This will get the alpha source flag (“alpha is shapeâ€), that specifies whether the current + * soft mask and alpha constant shall be interpreted as shape values (true) or opacity values + * (false). * * @param alpha The alpha source flag. */ From dfc26b0cb6e108155b999cdabf76ea16c7c2716b Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Mon, 5 Sep 2016 16:10:50 +0000 Subject: [PATCH 0301/2182] PDFBOX-3481: avoid arab digits if Arab numbering is default git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1759320 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/pdfbox/pdfwriter/COSWriter.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdfwriter/COSWriter.java b/pdfbox/src/main/java/org/apache/pdfbox/pdfwriter/COSWriter.java index 4f0196cb33f..cce36aebc08 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdfwriter/COSWriter.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdfwriter/COSWriter.java @@ -26,6 +26,7 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; import java.text.NumberFormat; import java.util.ArrayList; import java.util.Collections; @@ -159,10 +160,12 @@ public class COSWriter implements ICOSVisitor, Closeable */ public static final byte[] ENDSTREAM = "endstream".getBytes(Charsets.US_ASCII); - private final NumberFormat formatXrefOffset = new DecimalFormat("0000000000"); + private final NumberFormat formatXrefOffset = new DecimalFormat("0000000000", + DecimalFormatSymbols.getInstance(Locale.US)); // the decimal format for the xref object generation number data - private final NumberFormat formatXrefGeneration = new DecimalFormat("00000"); + private final NumberFormat formatXrefGeneration = new DecimalFormat("00000", + DecimalFormatSymbols.getInstance(Locale.US)); private final NumberFormat formatDecimal = NumberFormat.getNumberInstance( Locale.US ); From 92a9b40bb397f186a4903d3e6b88de1797ac5a5a Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Mon, 5 Sep 2016 16:11:49 +0000 Subject: [PATCH 0302/2182] PDFBOX-3481: add test git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1759322 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/pdfbox/pdmodel/TestPDDocument.java | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/TestPDDocument.java b/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/TestPDDocument.java index 9160589bec0..47243743668 100644 --- a/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/TestPDDocument.java +++ b/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/TestPDDocument.java @@ -26,6 +26,7 @@ import java.io.InputStream; import java.io.PrintWriter; import java.util.Arrays; +import java.util.Locale; import org.apache.pdfbox.io.IOUtils; @@ -193,4 +194,26 @@ public void testDeleteGoodFile() throws IOException boolean deleted = f.delete(); assertTrue("delete good file failed after successful load() and close()", deleted); } + + /** + * PDFBOX-3481: Test whether XRef generation results in unusable PDFs if Arab numbering is + * default. + */ + public void testSaveArabicLocale() throws IOException + { + Locale defaultLocale = Locale.getDefault(); + Locale arabicLocale = new Locale.Builder().setLanguageTag("ar-EG-u-nu-arab").build(); + Locale.setDefault(arabicLocale); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + PDDocument doc = new PDDocument(); + doc.addPage(new PDPage()); + doc.save(baos); + doc.close(); + + PDDocument.load(new ByteArrayInputStream(baos.toByteArray())).close(); + + Locale.setDefault(defaultLocale); + } } From 8337279b356a6e4b4d075eea5bb29b047a83b4cd Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Mon, 5 Sep 2016 16:13:07 +0000 Subject: [PATCH 0303/2182] PDFBOX-3481: avoid arab digits if Arab numbering is default git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1759326 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/pdfbox/util/DateConverter.java | 8 ++++---- .../org/apache/pdfbox/util/TestDateUtil.java | 8 ++++---- .../java/org/apache/xmpbox/DateConverter.java | 17 +++++++++-------- 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/util/DateConverter.java b/pdfbox/src/main/java/org/apache/pdfbox/util/DateConverter.java index 897fd4e4255..f7aef0490fe 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/util/DateConverter.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/util/DateConverter.java @@ -165,7 +165,7 @@ public static String toString(Calendar cal) } String offset = formatTZoffset(cal.get(Calendar.ZONE_OFFSET) + cal.get(Calendar.DST_OFFSET), "'"); - return String.format("D:" + return String.format(Locale.US, "D:" + "%1$4tY%1$2tm%1$2td" // yyyyMMdd + "%1$2tH%1$2tM%1$2tS" // HHmmss + "%2$s" // time zone @@ -186,7 +186,7 @@ public static String toISO8601(Calendar cal) { String offset = formatTZoffset(cal.get(Calendar.ZONE_OFFSET) + cal.get(Calendar.DST_OFFSET), ":"); - return String.format( + return String.format(Locale.US, "%1$4tY" // yyyy + "-%1$2tm" // -mm (%tm adds one to cal month value) + "-%1$2td" // -dd (%tm adds one to cal month value) @@ -491,11 +491,11 @@ private static void updateZoneId(TimeZone tz) } else if (pm == '+' && hh <= 12) { - tz.setID(String.format("GMT+%02d:%02d", hh, mm)); + tz.setID(String.format(Locale.US, "GMT+%02d:%02d", hh, mm)); } else if (pm == '-' && hh <= 14) { - tz.setID(String.format("GMT-%02d:%02d", hh, mm)); + tz.setID(String.format(Locale.US, "GMT-%02d:%02d", hh, mm)); } else { diff --git a/pdfbox/src/test/java/org/apache/pdfbox/util/TestDateUtil.java b/pdfbox/src/test/java/org/apache/pdfbox/util/TestDateUtil.java index 8686dcc6519..90a5ed336b3 100644 --- a/pdfbox/src/test/java/org/apache/pdfbox/util/TestDateUtil.java +++ b/pdfbox/src/test/java/org/apache/pdfbox/util/TestDateUtil.java @@ -129,9 +129,9 @@ private static void checkParse(int yr, int mon, int day, int hr, int min, int sec, int offsetHours, int offsetMinutes, String orig) throws Exception { - String pdfDate = String.format("D:%04d%02d%02d%02d%02d%02d%+03d'%02d'", + String pdfDate = String.format(Locale.US, "D:%04d%02d%02d%02d%02d%02d%+03d'%02d'", yr,mon,day,hr,min,sec,offsetHours,offsetMinutes); - String iso8601Date = String.format("%04d-%02d-%02d" + String iso8601Date = String.format(Locale.US, "%04d-%02d-%02d" + "T%02d:%02d:%02d%+03d:%02d", yr,mon,day,hr,min,sec,offsetHours,offsetMinutes); Calendar cal = DateConverter.toCalendar(orig); @@ -307,9 +307,9 @@ private static void checkToString(int yr, int mon, int day, GregorianCalendar cal = new GregorianCalendar(tz, Locale.ENGLISH); cal.set(yr, mon-1, day, hr, min, sec); // create expected strings - String pdfDate = String.format("D:%04d%02d%02d%02d%02d%02d%+03d'%02d'", + String pdfDate = String.format(Locale.US, "D:%04d%02d%02d%02d%02d%02d%+03d'%02d'", yr,mon,day,hr,min,sec,offsetHours, offsetMinutes); - String iso8601Date = String.format("%04d-%02d-%02d" + String iso8601Date = String.format(Locale.US, "%04d-%02d-%02d" + "T%02d:%02d:%02d%+03d:%02d", yr,mon,day,hr,min,sec,offsetHours, offsetMinutes); // compare outputs from toString and toISO8601 with expected values diff --git a/xmpbox/src/main/java/org/apache/xmpbox/DateConverter.java b/xmpbox/src/main/java/org/apache/xmpbox/DateConverter.java index 7e9a4cbd687..79ad82a6abb 100644 --- a/xmpbox/src/main/java/org/apache/xmpbox/DateConverter.java +++ b/xmpbox/src/main/java/org/apache/xmpbox/DateConverter.java @@ -27,6 +27,7 @@ import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; +import java.util.Locale; import java.util.SimpleTimeZone; import java.util.TimeZone; import java.util.regex.Matcher; @@ -255,11 +256,11 @@ private static void updateZoneId(TimeZone tz) } else if (pm == '+' && hh <= 12) { - tz.setID(String.format("GMT+%02d:%02d", hh, mm)); + tz.setID(String.format(Locale.US, "GMT+%02d:%02d", hh, mm)); } else if (pm == '-' && hh <= 14) { - tz.setID(String.format("GMT-%02d:%02d", hh, mm)); + tz.setID(String.format(Locale.US, "GMT-%02d:%02d", hh, mm)); } else { @@ -292,20 +293,20 @@ public static String toISO8601(Calendar cal, boolean printMillis) retval.append(cal.get(Calendar.YEAR)); retval.append("-"); - retval.append(String.format("%02d", cal.get(Calendar.MONTH) + 1)); + retval.append(String.format(Locale.US, "%02d", cal.get(Calendar.MONTH) + 1)); retval.append("-"); - retval.append(String.format("%02d", cal.get(Calendar.DAY_OF_MONTH))); + retval.append(String.format(Locale.US, "%02d", cal.get(Calendar.DAY_OF_MONTH))); retval.append("T"); - retval.append(String.format("%02d", cal.get(Calendar.HOUR_OF_DAY))); + retval.append(String.format(Locale.US, "%02d", cal.get(Calendar.HOUR_OF_DAY))); retval.append(":"); - retval.append(String.format("%02d", cal.get(Calendar.MINUTE))); + retval.append(String.format(Locale.US, "%02d", cal.get(Calendar.MINUTE))); retval.append(":"); - retval.append(String.format("%02d", cal.get(Calendar.SECOND))); + retval.append(String.format(Locale.US, "%02d", cal.get(Calendar.SECOND))); if (printMillis) { retval.append("."); - retval.append(String.format("%03d", cal.get(Calendar.MILLISECOND))); + retval.append(String.format(Locale.US, "%03d", cal.get(Calendar.MILLISECOND))); } int timeZone = cal.get(Calendar.ZONE_OFFSET) + cal.get(Calendar.DST_OFFSET); From 403b2df54cdf4f4ea516875d15d34b1f0d3a23b3 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Mon, 5 Sep 2016 16:13:29 +0000 Subject: [PATCH 0304/2182] PDFBOX-3481: avoid arab digits if Arab numbering is default git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1759328 13f79535-47bb-0310-9956-ffa450edef68 --- pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java b/pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java index d7030225db5..373e9d9777a 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java @@ -23,6 +23,7 @@ import java.util.concurrent.ConcurrentHashMap; import org.apache.pdfbox.util.Charsets; +import org.apache.pdfbox.util.Hex; /** * A PDF Name object. @@ -703,7 +704,7 @@ public void writePDF(OutputStream output) throws IOException else { output.write('#'); - output.write(String.format("%02X", current).getBytes(Charsets.US_ASCII)); + Hex.writeHexByte(b, output); } } } From a0c447b246e9e89ac737d6a44980a16d1fa2934e Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Mon, 5 Sep 2016 19:39:21 +0000 Subject: [PATCH 0305/2182] PDFBOX-2852: clarify javadoc git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1759349 13f79535-47bb-0310-9956-ffa450edef68 --- .../pdfbox/pdmodel/interactive/form/PDField.java | 5 ++++- .../pdmodel/interactive/form/PDNonTerminalField.java | 11 +++++++++-- .../pdmodel/interactive/form/PDTerminalField.java | 7 +++++-- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDField.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDField.java index 972a3550bfa..9a9a217ff76 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDField.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDField.java @@ -131,7 +131,10 @@ else if (parent != null) * For {@link PDNonTerminalField} the list will be empty as non terminal fields * have no visual representation in the form. * - * @return a List of {@link PDAnnotationWidget} annotations. + * @return a List of {@link PDAnnotationWidget} annotations. Be aware that this list is + * not backed by the actual widget collection of the field, so adding or deleting has no + * effect on the PDF document until you call {@link #setWidgets(java.util.List) setWidgets()} + * with the modified list. */ public abstract List getWidgets(); diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDNonTerminalField.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDNonTerminalField.java index 9a20aa55b1b..1ee4cba2d14 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDNonTerminalField.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDNonTerminalField.java @@ -122,8 +122,10 @@ FDFField exportFDF() throws IOException /** * Returns this field's children. These may be either terminal or non-terminal fields. - * - * @return he list of child fields. + * + * @return the list of child fields. Be aware that this list is not backed by the + * children of the field, so adding or deleting has no effect on the PDF document until you call + * {@link #setChildren(java.util.List) setChildren()} with the modified list. */ public List getChildren() { @@ -193,6 +195,8 @@ public String getValueAsString() * *

    Note: while non-terminal fields do inherit field values, this method returns * the local value, without inheritance. + * @param object + * @throws java.io.IOException */ public void setValue(COSBase object) throws IOException { @@ -207,6 +211,7 @@ public void setValue(COSBase object) throws IOException * @param value Plain text * @throws IOException if the value could not be set */ + @Override public void setValue(String value) throws IOException { getCOSObject().setString(COSName.V, value); @@ -232,6 +237,7 @@ public COSBase getDefaultValue() * *

    Note: while non-terminal fields do inherit field values, this method returns * the local value, without inheritance. + * @param value */ public void setDefaultValue(COSBase value) { @@ -241,6 +247,7 @@ public void setDefaultValue(COSBase value) @Override public List getWidgets() { + //TODO shouldn't we return a non modifiable list? return Collections.emptyList(); } } diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDTerminalField.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDTerminalField.java index 4fce12807b9..f2986e9350a 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDTerminalField.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDTerminalField.java @@ -155,8 +155,11 @@ FDFField exportFDF() throws IOException /** * Returns the widget annotations associated with this field. - * - * @return The list of widget annotations. + * + * @return The list of widget annotations. Be aware that this list is not backed by the + * actual widget collection of the field, so adding or deleting has no effect on the PDF + * document until you call {@link #setWidgets(java.util.List) setWidgets()} with the modified + * list. */ @Override public List getWidgets() From 324a0a034b1cd25ee2412c26446e9c308ed83b5a Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Tue, 6 Sep 2016 19:41:01 +0000 Subject: [PATCH 0306/2182] PDFBOX-2852: fix javadoc git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1759487 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/pdfbox/pdmodel/interactive/form/PDField.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDField.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDField.java index 9a9a217ff76..a106db6f50c 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDField.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDField.java @@ -133,8 +133,8 @@ else if (parent != null) * * @return a List of {@link PDAnnotationWidget} annotations. Be aware that this list is * not backed by the actual widget collection of the field, so adding or deleting has no - * effect on the PDF document until you call {@link #setWidgets(java.util.List) setWidgets()} - * with the modified list. + * effect on the PDF document. For {@link PDTerminalField} you'd have to call + * {@link PDTerminalField#setWidgets(java.util.List) setWidgets()} with the modified list. */ public abstract List getWidgets(); From 68d0dd0238d081daa58b5b0c7a1628a01b5a2f35 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Tue, 6 Sep 2016 19:54:05 +0000 Subject: [PATCH 0307/2182] PDFBOX-2852: clarify javadoc git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1759489 13f79535-47bb-0310-9956-ffa450edef68 --- pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPage.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPage.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPage.java index d2f4db87c7d..442a8922236 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPage.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPage.java @@ -636,9 +636,11 @@ public void setTransition(PDTransition transition, float duration) } /** - * This will return a list of the Annotations for this page. + * This will return a list of the annotations for this page. + * + * @return List of the PDAnnotation objects, never null. The returned list is backed by the + * annotations COSArray, so any adding or deleting in this list will change the document too. * - * @return List of the PDAnnotation objects, never null. * @throws IOException If there is an error while creating the annotation list. */ public List getAnnotations() throws IOException From fe3e542a7018e7b8fdacf8fef419e666efb5e124 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Tue, 6 Sep 2016 19:59:02 +0000 Subject: [PATCH 0308/2182] PDFBOX-2852: clarify javadoc git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1759495 13f79535-47bb-0310-9956-ffa450edef68 --- .../pdfbox/pdmodel/interactive/annotation/PDAnnotation.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/PDAnnotation.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/PDAnnotation.java index 9e96690f8c1..5dfcf4d3d53 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/PDAnnotation.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/PDAnnotation.java @@ -89,10 +89,11 @@ public abstract class PDAnnotation implements COSObjectable /** * Create the correct annotation from the base COS object. - * + * * @param base The COS object that is the annotation. * @return The correctly typed annotation object. - * @throws IOException If there is an error while creating the annotation. + * + * @throws IOException If the annotation type is unknown. */ public static PDAnnotation createAnnotation(COSBase base) throws IOException { From 2937624762e522ba7514d843ff22cf5023b9e800 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Tue, 6 Sep 2016 20:01:24 +0000 Subject: [PATCH 0309/2182] PDFBOX-2852: clarify javadoc git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1759497 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/pdfbox/pdmodel/PDPage.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPage.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPage.java index 442a8922236..38b0c4b47ef 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPage.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPage.java @@ -514,10 +514,11 @@ public void setContents(List contents) } /** - * This will get a list of PDThreadBead objects, which are article threads in the document. - * This will return an empty list if there are no thread beads. - * - * @return A list of article threads on this page. + * This will get a list of PDThreadBead objects, which are article threads in the document. This + * will return an empty list if there are no thread beads. + * + * @return A list of article threads on this page, never null. The returned list is backed by + * the beads COSArray, so any adding or deleting in this list will change the document too. */ public List getThreadBeads() { @@ -539,7 +540,6 @@ public List getThreadBeads() pdObjects.add(bead); } return new COSArrayList(pdObjects, beads); - } /** From eac1fe89c6d9777b61ee7c1e5a174e3a4a708bed Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Wed, 7 Sep 2016 16:40:00 +0000 Subject: [PATCH 0310/2182] PDFBOX-3481: remove test that doesn't work before JDK7, as pointed out by Petras git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1759637 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/pdfbox/pdmodel/TestPDDocument.java | 22 ------------------- 1 file changed, 22 deletions(-) diff --git a/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/TestPDDocument.java b/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/TestPDDocument.java index 47243743668..fbb3dad31b2 100644 --- a/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/TestPDDocument.java +++ b/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/TestPDDocument.java @@ -194,26 +194,4 @@ public void testDeleteGoodFile() throws IOException boolean deleted = f.delete(); assertTrue("delete good file failed after successful load() and close()", deleted); } - - /** - * PDFBOX-3481: Test whether XRef generation results in unusable PDFs if Arab numbering is - * default. - */ - public void testSaveArabicLocale() throws IOException - { - Locale defaultLocale = Locale.getDefault(); - Locale arabicLocale = new Locale.Builder().setLanguageTag("ar-EG-u-nu-arab").build(); - Locale.setDefault(arabicLocale); - - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - - PDDocument doc = new PDDocument(); - doc.addPage(new PDPage()); - doc.save(baos); - doc.close(); - - PDDocument.load(new ByteArrayInputStream(baos.toByteArray())).close(); - - Locale.setDefault(defaultLocale); - } } From 2bf48eed0223118c22b19c53cff20a2c5ba5fb95 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Wed, 7 Sep 2016 16:53:46 +0000 Subject: [PATCH 0311/2182] PDFBOX-3065: enable external signing, as done by Petras Petkus git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1759639 13f79535-47bb-0310-9956-ffa450edef68 --- .../examples/signature/CreateSignature.java | 43 +++++++-- .../apache/pdfbox/pdfwriter/COSWriter.java | 92 +++++++++++++++---- .../org/apache/pdfbox/pdmodel/PDDocument.java | 92 ++++++++++++++++++- .../ExternalSigningSupport.java | 30 ++++++ .../digitalsignature/SigningSupport.java | 50 ++++++++++ 5 files changed, 279 insertions(+), 28 deletions(-) create mode 100644 pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/ExternalSigningSupport.java create mode 100644 pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/SigningSupport.java diff --git a/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateSignature.java b/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateSignature.java index 82736ddf702..a44e663111a 100644 --- a/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateSignature.java +++ b/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateSignature.java @@ -33,6 +33,7 @@ import java.util.Calendar; import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.pdmodel.interactive.digitalsignature.ExternalSigningSupport; import org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature; /** @@ -49,8 +50,12 @@ public class CreateSignature extends CreateSignatureBase { + private boolean externalSignature; + private ExternalSigningSupport externalSigning; + /** * Initialize the signature creator with a keystore and certficate password. + * * @param keystore the pkcs12 keystore containing the signing certificate * @param pin the password for recovering the key * @throws KeyStoreException if the keystore has not been initialized (loaded) @@ -125,11 +130,24 @@ public void signDetached(PDDocument document, OutputStream output, TSAClient tsa // the signing date, needed for valid signature signature.setSignDate(Calendar.getInstance()); - // register signature dictionary and sign interface - document.addSignature(signature, this); + if (externalSignature) + { + System.out.println("Sign externally..."); + document.addSignature(signature); + externalSigning = document.saveIncrementalForExternalSigning(output); + // invoke external signature service + byte[] cmsSignature = sign(externalSigning.getContent()); + // set signature bytes received from the service + externalSigning.setSignature(cmsSignature); + } + else + { + // register signature dictionary and sign interface + document.addSignature(signature, this); - // write incremental (only for signing purpose) - document.saveIncremental(output); + // write incremental (only for signing purpose) + document.saveIncremental(output); + } } public static void main(String[] args) throws IOException, GeneralSecurityException @@ -141,7 +159,8 @@ public static void main(String[] args) throws IOException, GeneralSecurityExcept } String tsaUrl = null; - for(int i = 0; i < args.length; i++) + boolean externalSig = false; + for (int i = 0; i < args.length; i++) { if (args[i].equals("-tsa")) { @@ -149,9 +168,14 @@ public static void main(String[] args) throws IOException, GeneralSecurityExcept if (i >= args.length) { usage(); + System.exit(1); } tsaUrl = args[i]; } + if (args[i].equals("-e")) + { + externalSig = true; + } } // load the keystore @@ -170,6 +194,7 @@ public static void main(String[] args) throws IOException, GeneralSecurityExcept // sign PDF CreateSignature signing = new CreateSignature(keystore, password); + signing.setExternalSignature(externalSig); File inFile = new File(args[2]); String name = inFile.getName(); @@ -184,6 +209,12 @@ private static void usage() System.err.println("usage: java " + CreateSignature.class.getName() + " " + " \n" + "" + "options:\n" + - " -tsa sign timestamp using the given TSA server"); + " -tsa sign timestamp using the given TSA server\n" + + " -e sign using external signature creation scenario"); + } + + public void setExternalSignature(boolean externalSignature) + { + this.externalSignature = externalSignature; } } diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdfwriter/COSWriter.java b/pdfbox/src/main/java/org/apache/pdfbox/pdfwriter/COSWriter.java index cce36aebc08..1b4cb0957b2 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdfwriter/COSWriter.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdfwriter/COSWriter.java @@ -66,6 +66,7 @@ import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.encryption.SecurityHandler; import org.apache.pdfbox.pdmodel.fdf.FDFDocument; +import org.apache.pdfbox.pdmodel.interactive.digitalsignature.COSFilterInputStream; import org.apache.pdfbox.pdmodel.interactive.digitalsignature.SignatureInterface; import org.apache.pdfbox.util.Charsets; import org.apache.pdfbox.util.Hex; @@ -220,6 +221,7 @@ public class COSWriter implements ICOSVisitor, Closeable private RandomAccessRead tempIncInput; private OutputStream incrementalOutput; private SignatureInterface signatureInterface; + private byte[] incrementPart; /** * COSWriter constructor comment. @@ -744,7 +746,7 @@ private void doWriteSignature() throws IOException // copy the new incremental data into a buffer (e.g. signature dict, trailer) ByteArrayOutputStream byteOut = (ByteArrayOutputStream) output; byteOut.flush(); - byte[] buffer = byteOut.toByteArray(); + incrementPart = byteOut.toByteArray(); // overwrite the ByteRange in the buffer byte[] byteRangeBytes = byteRange.getBytes(Charsets.ISO_8859_1); @@ -752,26 +754,71 @@ private void doWriteSignature() throws IOException { if (i >= byteRangeBytes.length) { - buffer[(int)(byteRangeOffset + i - inLength)] = 0x20; // SPACE + incrementPart[(int) (byteRangeOffset + i - inLength)] = 0x20; // SPACE } else { - buffer[(int)(byteRangeOffset + i - inLength)] = byteRangeBytes[i]; + incrementPart[(int) (byteRangeOffset + i - inLength)] = byteRangeBytes[i]; } } - // get only the incremental bytes to be signed (includes /ByteRange but not /Contents) - byte[] signBuffer = new byte[buffer.length - (int)signatureLength]; - int bufSignatureOffset = (int)(signatureOffset - inLength); - System.arraycopy(buffer, 0, signBuffer, 0, bufSignatureOffset); - System.arraycopy(buffer, bufSignatureOffset + (int)signatureLength, - signBuffer, bufSignatureOffset, buffer.length - bufSignatureOffset - (int)signatureLength); + if(signatureInterface != null) + { + // data to be signed + final InputStream dataToSign = getDataToSign(); - SequenceInputStream signStream = new SequenceInputStream(new RandomAccessInputStream(incrementalInput), - new ByteArrayInputStream(signBuffer)); + // sign the bytes + byte[] signatureBytes = signatureInterface.sign(dataToSign); + writeExternalSignature(signatureBytes); + } + // else signature should created externally and set via writeSignature() + } + + /** + * Return the stream of PDF data to be signed. Clients should use this method only to create + * signatures externally. {@link #write(PDDocument)} method should have been called prior. + * The created signature should be set using {@link #writeExternalSignature(byte[])}. + *

    + * When {@link SignatureInterface} instance is used, COSWriter obtains and writes the signature itsef. + *

    + * Note that caller must close the obtained stream. + * + * @return data stream to be signed + * @throws IllegalStateException if PDF is not prepared for external signing + * @throws IOException if input data is closed + */ + public InputStream getDataToSign() throws IOException + { + if (incrementPart == null || incrementalInput == null) + { + throw new IllegalStateException("PDF not prepared for signing"); + } + // range of incremental bytes to be signed (includes /ByteRange but not /Contents) + int incPartSigOffset = (int) (signatureOffset - incrementalInput.length()); + int afterSigOffset = incPartSigOffset + (int) signatureLength; + int[] range = {0, incPartSigOffset, + afterSigOffset, incrementPart.length - afterSigOffset}; + + return new SequenceInputStream( + new RandomAccessInputStream(incrementalInput), + new COSFilterInputStream(incrementPart, range)); + } + + /** + * Write externally created signature of PDF data obtained via {@link #getDataToSign()} method. + * + * @param cmsSignature CMS signature byte array + * @throws IllegalStateException if PDF is not prepared for external signing + * @throws IOException if source data stream is closed + */ + public void writeExternalSignature(byte[] cmsSignature) throws IOException { + + if (incrementPart == null || incrementalInput == null) + { + throw new IllegalStateException("PDF not prepared for setting signature"); + } + byte[] signatureBytes = Hex.getBytes(cmsSignature); - // sign the bytes - byte[] signatureBytes = Hex.getBytes(signatureInterface.sign(signStream)); // substract 2 bytes because of the enclosing "<>" if (signatureBytes.length > signatureLength - 2) { @@ -779,11 +826,15 @@ private void doWriteSignature() throws IOException } // overwrite the signature Contents in the buffer - System.arraycopy(signatureBytes, 0, buffer, bufSignatureOffset + 1, signatureBytes.length); + int incPartSigOffset = (int) (signatureOffset - incrementalInput.length()); + System.arraycopy(signatureBytes, 0, incrementPart, incPartSigOffset + 1, signatureBytes.length); // write the data to the incremental output stream IOUtils.copy(new RandomAccessInputStream(incrementalInput), incrementalOutput); - incrementalOutput.write(buffer); + incrementalOutput.write(incrementPart); + + // prevent further use + incrementPart = null; } private void writeXrefRange(long x, long y) throws IOException @@ -1219,7 +1270,9 @@ public void write(COSDocument doc) throws IOException } /** - * This will write the pdf document. + * This will write the pdf document. If signature should be created externally, + * {@link #writeExternalSignature(byte[])} should be invoked to set signature after calling this + * method. * * @param doc The document to write. * @@ -1231,10 +1284,13 @@ public void write(PDDocument doc) throws IOException } /** - * This will write the pdf document. + * This will write the pdf document. If signature should be created externally, + * {@link #writeExternalSignature(byte[])} should be invoked to set signature after calling this + * method. * * @param doc The document to write. - * @param signInterface class to be used for signing + * @param signInterface class to be used for signing; {@code null} if external signing would be + * performed or there will be no signing at all * * @throws IOException If an error occurs while generating the data. * @throws IllegalStateException If the document has an encryption dictionary but no protection diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java index ab4824a9fa6..0f432b8e196 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java @@ -55,9 +55,11 @@ import org.apache.pdfbox.pdmodel.font.PDFont; import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotation; import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceDictionary; +import org.apache.pdfbox.pdmodel.interactive.digitalsignature.ExternalSigningSupport; import org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature; import org.apache.pdfbox.pdmodel.interactive.digitalsignature.SignatureInterface; import org.apache.pdfbox.pdmodel.interactive.digitalsignature.SignatureOptions; +import org.apache.pdfbox.pdmodel.interactive.digitalsignature.SigningSupport; import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm; import org.apache.pdfbox.pdmodel.interactive.form.PDField; import org.apache.pdfbox.pdmodel.interactive.form.PDSignatureField; @@ -97,13 +99,16 @@ public class PDDocument implements Closeable // fonts to subset before saving private final Set fontsToSubset = new HashSet(); - + // Signature interface private SignatureInterface signInterface; - + + // helper class used to create external signature + private SigningSupport signingSupport; + // document-wide cached resources private ResourceCache resourceCache = new DefaultResourceCache(); - + /** * Creates an empty PDF document. * You need to add at least one page for the document to be valid. @@ -171,7 +176,34 @@ public void addPage(PDPage page) } /** - * Add a signature. + * Add parameters of signature to be created externally using default signature options. See + * {@link #saveIncrementalForExternalSigning(OutputStream)} method description on external + * signature creation scenario details. + * + * @param sigObject is the PDSignatureField model + * @throws IOException if there is an error creating required fields + */ + public void addSignature(PDSignature sigObject) throws IOException + { + addSignature(sigObject, new SignatureOptions()); + } + + /** + * Add parameters of signature to be created externally. See + * {@link #saveIncrementalForExternalSigning(OutputStream)} method description on external + * signature creation scenario details. + * + * @param sigObject is the PDSignatureField model + * @param options signature options + * @throws IOException if there is an error creating required fields + */ + public void addSignature(PDSignature sigObject, SignatureOptions options) throws IOException + { + addSignature(sigObject, null, options); + } + + /** + * Add a signature to be created using the instance of given interface. * * @param sigObject is the PDSignatureField model * @param signatureInterface is an interface which provides signing capabilities @@ -1150,6 +1182,52 @@ public void saveIncremental(OutputStream output) throws IOException } } + /** + * Save PDF incrementally without closing for external signature creation scenario. The general + * sequence is: + *
    +     *    PDDocument pdDocument = ...;
    +     *    OutputStream outputStream = ...;
    +     *    SignatureOptions signatureOptions = ...; // options to specify fine tuned signature options or null for defaults
    +     *    PDSignature pdSignature = ...;
    +     *
    +     *    // add signature parameters to be used when creating signature dictionary
    +     *    pdDocument.addSignature(pdSignature, signatureOptions);
    +     *    // prepare PDF for signing and obtain helper class to be used
    +     *    ExternalSigningSupport externalSigningSupport = pdDocument.saveIncrementalForExternalSigning(outputStream);
    +     *    // get data to be signed
    +     *    InputStream dataToBeSigned = externalSigningSupport.getContent();
    +     *    // invoke signature service
    +     *    byte[] signature = sign(dataToBeSigned);
    +     *    // set resulted CMS signature
    +     *    externalSigningSupport.setSignature(signature);
    +     *
    +     *    // last step is to close the document
    +     *    pdDocument.close();
    +     * 
    + *

    + * Note that after calling this method, only {@code close()} method may invoked for + * {@code PDDocument} instance and only AFTER {@link ExternalSigningSupport} instance is used. + *

    + * + * @param output stream to write final PDF + * @return instance to be used for external signing and setting CMS signature + * @throws IOException if the output could not be written + * @throws IllegalStateException if the document was not loaded from a file or a stream or + * signature optionss were not set. + */ + public ExternalSigningSupport saveIncrementalForExternalSigning(OutputStream output) throws IOException + { + if (pdfSource == null) + { + throw new IllegalStateException("document was not loaded from a file or a stream"); + } + COSWriter writer = new COSWriter(output, pdfSource); + writer.write(this); + signingSupport = new SigningSupport(writer); + return signingSupport; + } + /** * Returns the page at the given index. * @@ -1191,6 +1269,12 @@ public void close() throws IOException { if (!document.isClosed()) { + // close resources and COSWriter + if (signingSupport != null) + { + signingSupport.close(); + } + // close all intermediate I/O streams document.close(); diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/ExternalSigningSupport.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/ExternalSigningSupport.java new file mode 100644 index 00000000000..be4d9690ad2 --- /dev/null +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/ExternalSigningSupport.java @@ -0,0 +1,30 @@ +package org.apache.pdfbox.pdmodel.interactive.digitalsignature; + +import java.io.IOException; +import java.io.InputStream; + +/** + * Interface for external signature creation scenarios. It contains method for retrieving PDF data + * to be sign and setting created CMS signature to the PDF. + * + */ +public interface ExternalSigningSupport +{ + /** + * Get PDF content to be signed. Obtained InputStream must be closed after use. + * + * @return content stream + * + * @throws java.io.IOException + */ + InputStream getContent() throws IOException; + + /** + * Set CMS signature bytes to PDF. + * + * @param signature CMS signature as byte array + * + * @throws IOException if exception occured during PDF writing + */ + void setSignature(byte[] signature) throws IOException; +} diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/SigningSupport.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/SigningSupport.java new file mode 100644 index 00000000000..e47d5ebe289 --- /dev/null +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/SigningSupport.java @@ -0,0 +1,50 @@ +package org.apache.pdfbox.pdmodel.interactive.digitalsignature; + +import org.apache.pdfbox.pdfwriter.COSWriter; + +import java.io.Closeable; +import java.io.IOException; +import java.io.InputStream; + +/** + * Class to be used when creating PDF signatures externally. COSWriter is used to obtain data to be + * signed and set the resulted CMS signature. + * + */ +public class SigningSupport implements ExternalSigningSupport, Closeable +{ + private COSWriter cosWriter; + + public SigningSupport(COSWriter cosWriter) + { + this.cosWriter = cosWriter; + } + + @Override + public InputStream getContent() throws IOException + { + return cosWriter.getDataToSign(); + } + + @Override + public void setSignature(byte[] signature) throws IOException + { + cosWriter.writeExternalSignature(signature); + } + + @Override + public void close() throws IOException + { + if (cosWriter != null) + { + try + { + cosWriter.close(); + } + finally + { + cosWriter = null; + } + } + } +} From 3cadf6b7c65ca63640ada0b62b7e1c0a808d80c6 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Wed, 7 Sep 2016 17:10:50 +0000 Subject: [PATCH 0312/2182] PDFBOX-3482: don't fill() if height or width is 0 git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1759647 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/pdfbox/rendering/PageDrawer.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/rendering/PageDrawer.java b/pdfbox/src/main/java/org/apache/pdfbox/rendering/PageDrawer.java index bfa5a6beec6..596f693a3a7 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/rendering/PageDrawer.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/rendering/PageDrawer.java @@ -623,7 +623,10 @@ public void fillPath(int windingRule) throws IOException } else { - graphics.fill(linePath); + if (linePath.getBounds2D().getWidth() > 0 && linePath.getBounds2D().getHeight() > 0) + { + graphics.fill(linePath); + } } linePath.reset(); From 875394576b205b1b3eda42fcb2c4d26492fbc3c1 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Wed, 7 Sep 2016 18:37:49 +0000 Subject: [PATCH 0313/2182] PDFBOX-2852: remove ";" as suggested by Simon Steiner git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1759658 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/pdfbox/multipdf/Overlay.java | 2 +- .../pdfbox/pdfparser/XrefTrailerResolver.java | 668 +++++++++--------- .../pagenavigation/PDTransitionDimension.java | 2 +- .../pagenavigation/PDTransitionMotion.java | 2 +- .../pagenavigation/PDTransitionStyle.java | 2 +- .../apache/pdfbox/text/PDFTextStripper.java | 2 +- .../java/org/apache/xmpbox/DateConverter.java | 2 +- 7 files changed, 340 insertions(+), 340 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/multipdf/Overlay.java b/pdfbox/src/main/java/org/apache/pdfbox/multipdf/Overlay.java index 08d50787188..216c629866f 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/multipdf/Overlay.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/multipdf/Overlay.java @@ -52,7 +52,7 @@ public class Overlay public enum Position { FOREGROUND, BACKGROUND - }; + } private LayoutPage defaultOverlayPage; private LayoutPage firstPageOverlayPage; diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/XrefTrailerResolver.java b/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/XrefTrailerResolver.java index cd804379830..af4279988f1 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/XrefTrailerResolver.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/XrefTrailerResolver.java @@ -1,334 +1,334 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.pdfbox.pdfparser; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.Map.Entry; -import java.util.SortedSet; -import java.util.TreeSet; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.pdfbox.cos.COSDictionary; -import org.apache.pdfbox.cos.COSName; -import org.apache.pdfbox.cos.COSObjectKey; - -/** - * This class will collect all XRef/trailer objects and creates correct - * xref/trailer information after all objects are read using startxref - * and 'Prev' information (unused XRef/trailer objects are discarded). - * - * In case of missing startxref or wrong startxref pointer all - * XRef/trailer objects are used to create xref table / trailer dictionary - * in order they occur. - * - * For each new xref object/XRef stream method {@link #nextXrefObj(long, XRefType)} - * must be called with start byte position. All following calls to - * {@link #setXRef(COSObjectKey, long)} or {@link #setTrailer(COSDictionary)} - * will add the data for this byte position. - * - * After all objects are parsed the startxref position must be provided - * using {@link #setStartxref(long)}. This is used to build the chain of - * active xref/trailer objects used for creating document trailer and xref table. - * - * @author Timo Böhme - */ -public class XrefTrailerResolver -{ - - /** - * A class which represents a xref/trailer object. - */ - private class XrefTrailerObj - { - protected COSDictionary trailer = null; - - private XRefType xrefType; - - private final Map xrefTable = new HashMap(); - - /** - * Default constructor. - */ - private XrefTrailerObj() - { - xrefType = XRefType.TABLE; - } - } - - /** - * The XRefType of a trailer. - */ - public enum XRefType - { - /** - * XRef table type. - */ - TABLE, - /** - * XRef stream type. - */ - STREAM; - } - - private final Map bytePosToXrefMap = new HashMap(); - private XrefTrailerObj curXrefTrailerObj = null; - private XrefTrailerObj resolvedXrefTrailer = null; - - /** Log instance. */ - private static final Log LOG = LogFactory.getLog( XrefTrailerResolver.class ); - - /** - * Returns the first trailer if at least one exists. - * - * @return the first trailer or null - */ - public final COSDictionary getFirstTrailer() - { - if (bytePosToXrefMap.isEmpty()) - { - return null; - } - Set offsets = bytePosToXrefMap.keySet(); - SortedSet sortedOffset = new TreeSet(offsets); - return bytePosToXrefMap.get(sortedOffset.first()).trailer; - } - - /** - * Returns the last trailer if at least one exists. - * - * @return the last trailer ir null - */ - public final COSDictionary getLastTrailer() - { - if (bytePosToXrefMap.isEmpty()) - { - return null; - } - Set offsets = bytePosToXrefMap.keySet(); - SortedSet sortedOffset = new TreeSet(offsets); - return bytePosToXrefMap.get(sortedOffset.last()).trailer; - } - - /** - * Signals that a new XRef object (table or stream) starts. - * @param startBytePos the offset to start at - * @param type the type of the Xref object - */ - public void nextXrefObj( final long startBytePos, XRefType type ) - { - bytePosToXrefMap.put( startBytePos, curXrefTrailerObj = new XrefTrailerObj() ); - curXrefTrailerObj.xrefType = type; - } - - /** - * Returns the XRefTxpe of the resolved trailer. - * - * @return the XRefType or null. - */ - public XRefType getXrefType() - { - return ( resolvedXrefTrailer == null ) ? null : resolvedXrefTrailer.xrefType; - } - - /** - * Populate XRef HashMap of current XRef object. - * Will add an Xreftable entry that maps ObjectKeys to byte offsets in the file. - * @param objKey The objkey, with id and gen numbers - * @param offset The byte offset in this file - */ - public void setXRef( COSObjectKey objKey, long offset ) - { - if ( curXrefTrailerObj == null ) - { - // should not happen... - LOG.warn( "Cannot add XRef entry for '" + objKey.getNumber() + "' because XRef start was not signalled." ); - return; - } - curXrefTrailerObj.xrefTable.put( objKey, offset ); - } - - /** - * Adds trailer information for current XRef object. - * - * @param trailer the current document trailer dictionary - */ - public void setTrailer( COSDictionary trailer ) - { - if ( curXrefTrailerObj == null ) - { - // should not happen... - LOG.warn( "Cannot add trailer because XRef start was not signalled." ); - return; - } - curXrefTrailerObj.trailer = trailer; - } - - /** - * Returns the trailer last set by {@link #setTrailer(COSDictionary)}. - * - * @return the current trailer. - * - */ - public COSDictionary getCurrentTrailer() - { - return curXrefTrailerObj.trailer; - } - - /** - * Sets the byte position of the first XRef - * (has to be called after very last startxref was read). - * This is used to resolve chain of active XRef/trailer. - * - * In case startxref position is not found we output a - * warning and use all XRef/trailer objects combined - * in byte position order. - * Thus for incomplete PDF documents with missing - * startxref one could call this method with parameter value -1. - * - * @param startxrefBytePosValue starting position of the first XRef - * - */ - public void setStartxref( long startxrefBytePosValue ) - { - if ( resolvedXrefTrailer != null ) - { - LOG.warn( "Method must be called only ones with last startxref value." ); - return; - } - - resolvedXrefTrailer = new XrefTrailerObj(); - resolvedXrefTrailer.trailer = new COSDictionary(); - - XrefTrailerObj curObj = bytePosToXrefMap.get( startxrefBytePosValue ); - List xrefSeqBytePos = new ArrayList(); - - if ( curObj == null ) - { - // no XRef at given position - LOG.warn( "Did not found XRef object at specified startxref position " + startxrefBytePosValue ); - - // use all objects in byte position order (last entries overwrite previous ones) - xrefSeqBytePos.addAll( bytePosToXrefMap.keySet() ); - Collections.sort( xrefSeqBytePos ); - } - else - { - // copy xref type - resolvedXrefTrailer.xrefType = curObj.xrefType; - // found starting Xref object - // add this and follow chain defined by 'Prev' keys - xrefSeqBytePos.add( startxrefBytePosValue ); - while ( curObj.trailer != null ) - { - long prevBytePos = curObj.trailer.getLong( COSName.PREV, -1L ); - if ( prevBytePos == -1 ) - { - break; - } - - curObj = bytePosToXrefMap.get( prevBytePos ); - if ( curObj == null ) - { - LOG.warn( "Did not found XRef object pointed to by 'Prev' key at position " + prevBytePos ); - break; - } - xrefSeqBytePos.add( prevBytePos ); - - // sanity check to prevent infinite loops - if ( xrefSeqBytePos.size() >= bytePosToXrefMap.size() ) - { - break; - } - } - // have to reverse order so that later XRefs will overwrite previous ones - Collections.reverse( xrefSeqBytePos ); - } - - // merge used and sorted XRef/trailer - for ( Long bPos : xrefSeqBytePos ) - { - curObj = bytePosToXrefMap.get( bPos ); - if ( curObj.trailer != null ) - { - resolvedXrefTrailer.trailer.addAll( curObj.trailer ); - } - resolvedXrefTrailer.xrefTable.putAll( curObj.xrefTable ); - } - - } - - /** - * Gets the resolved trailer. Might return null in case - * {@link #setStartxref(long)} was not called before. - * - * @return the trailer if available - */ - public COSDictionary getTrailer() - { - return ( resolvedXrefTrailer == null ) ? null : resolvedXrefTrailer.trailer; - } - - /** - * Gets the resolved xref table. Might return null in case - * {@link #setStartxref(long)} was not called before. - * - * @return the xrefTable if available - */ - public Map getXrefTable() - { - return ( resolvedXrefTrailer == null ) ? null : resolvedXrefTrailer.xrefTable; - } - - /** Returns object numbers which are referenced as contained - * in object stream with specified object number. - * - * This will scan resolved xref table for all entries having negated - * stream object number as value. - * - * @param objstmObjNr object number of object stream for which contained object numbers - * should be returned - * - * @return set of object numbers referenced for given object stream - * or null if {@link #setStartxref(long)} was not - * called before so that no resolved xref table exists - */ - public Set getContainedObjectNumbers( final int objstmObjNr ) - { - if ( resolvedXrefTrailer == null ) - { - return null; - } - final Set refObjNrs = new HashSet(); - final long cmpVal = - objstmObjNr; - - for ( Entry xrefEntry : resolvedXrefTrailer.xrefTable.entrySet() ) - { - if ( xrefEntry.getValue() == cmpVal ) - { - refObjNrs.add( xrefEntry.getKey().getNumber() ); - } - } - return refObjNrs; - } -} +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.pdfbox.pdfparser; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Map.Entry; +import java.util.SortedSet; +import java.util.TreeSet; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.pdfbox.cos.COSDictionary; +import org.apache.pdfbox.cos.COSName; +import org.apache.pdfbox.cos.COSObjectKey; + +/** + * This class will collect all XRef/trailer objects and creates correct + * xref/trailer information after all objects are read using startxref + * and 'Prev' information (unused XRef/trailer objects are discarded). + * + * In case of missing startxref or wrong startxref pointer all + * XRef/trailer objects are used to create xref table / trailer dictionary + * in order they occur. + * + * For each new xref object/XRef stream method {@link #nextXrefObj(long, XRefType)} + * must be called with start byte position. All following calls to + * {@link #setXRef(COSObjectKey, long)} or {@link #setTrailer(COSDictionary)} + * will add the data for this byte position. + * + * After all objects are parsed the startxref position must be provided + * using {@link #setStartxref(long)}. This is used to build the chain of + * active xref/trailer objects used for creating document trailer and xref table. + * + * @author Timo Böhme + */ +public class XrefTrailerResolver +{ + + /** + * A class which represents a xref/trailer object. + */ + private class XrefTrailerObj + { + protected COSDictionary trailer = null; + + private XRefType xrefType; + + private final Map xrefTable = new HashMap(); + + /** + * Default constructor. + */ + private XrefTrailerObj() + { + xrefType = XRefType.TABLE; + } + } + + /** + * The XRefType of a trailer. + */ + public enum XRefType + { + /** + * XRef table type. + */ + TABLE, + /** + * XRef stream type. + */ + STREAM + } + + private final Map bytePosToXrefMap = new HashMap(); + private XrefTrailerObj curXrefTrailerObj = null; + private XrefTrailerObj resolvedXrefTrailer = null; + + /** Log instance. */ + private static final Log LOG = LogFactory.getLog( XrefTrailerResolver.class ); + + /** + * Returns the first trailer if at least one exists. + * + * @return the first trailer or null + */ + public final COSDictionary getFirstTrailer() + { + if (bytePosToXrefMap.isEmpty()) + { + return null; + } + Set offsets = bytePosToXrefMap.keySet(); + SortedSet sortedOffset = new TreeSet(offsets); + return bytePosToXrefMap.get(sortedOffset.first()).trailer; + } + + /** + * Returns the last trailer if at least one exists. + * + * @return the last trailer ir null + */ + public final COSDictionary getLastTrailer() + { + if (bytePosToXrefMap.isEmpty()) + { + return null; + } + Set offsets = bytePosToXrefMap.keySet(); + SortedSet sortedOffset = new TreeSet(offsets); + return bytePosToXrefMap.get(sortedOffset.last()).trailer; + } + + /** + * Signals that a new XRef object (table or stream) starts. + * @param startBytePos the offset to start at + * @param type the type of the Xref object + */ + public void nextXrefObj( final long startBytePos, XRefType type ) + { + bytePosToXrefMap.put( startBytePos, curXrefTrailerObj = new XrefTrailerObj() ); + curXrefTrailerObj.xrefType = type; + } + + /** + * Returns the XRefTxpe of the resolved trailer. + * + * @return the XRefType or null. + */ + public XRefType getXrefType() + { + return ( resolvedXrefTrailer == null ) ? null : resolvedXrefTrailer.xrefType; + } + + /** + * Populate XRef HashMap of current XRef object. + * Will add an Xreftable entry that maps ObjectKeys to byte offsets in the file. + * @param objKey The objkey, with id and gen numbers + * @param offset The byte offset in this file + */ + public void setXRef( COSObjectKey objKey, long offset ) + { + if ( curXrefTrailerObj == null ) + { + // should not happen... + LOG.warn( "Cannot add XRef entry for '" + objKey.getNumber() + "' because XRef start was not signalled." ); + return; + } + curXrefTrailerObj.xrefTable.put( objKey, offset ); + } + + /** + * Adds trailer information for current XRef object. + * + * @param trailer the current document trailer dictionary + */ + public void setTrailer( COSDictionary trailer ) + { + if ( curXrefTrailerObj == null ) + { + // should not happen... + LOG.warn( "Cannot add trailer because XRef start was not signalled." ); + return; + } + curXrefTrailerObj.trailer = trailer; + } + + /** + * Returns the trailer last set by {@link #setTrailer(COSDictionary)}. + * + * @return the current trailer. + * + */ + public COSDictionary getCurrentTrailer() + { + return curXrefTrailerObj.trailer; + } + + /** + * Sets the byte position of the first XRef + * (has to be called after very last startxref was read). + * This is used to resolve chain of active XRef/trailer. + * + * In case startxref position is not found we output a + * warning and use all XRef/trailer objects combined + * in byte position order. + * Thus for incomplete PDF documents with missing + * startxref one could call this method with parameter value -1. + * + * @param startxrefBytePosValue starting position of the first XRef + * + */ + public void setStartxref( long startxrefBytePosValue ) + { + if ( resolvedXrefTrailer != null ) + { + LOG.warn( "Method must be called only ones with last startxref value." ); + return; + } + + resolvedXrefTrailer = new XrefTrailerObj(); + resolvedXrefTrailer.trailer = new COSDictionary(); + + XrefTrailerObj curObj = bytePosToXrefMap.get( startxrefBytePosValue ); + List xrefSeqBytePos = new ArrayList(); + + if ( curObj == null ) + { + // no XRef at given position + LOG.warn( "Did not found XRef object at specified startxref position " + startxrefBytePosValue ); + + // use all objects in byte position order (last entries overwrite previous ones) + xrefSeqBytePos.addAll( bytePosToXrefMap.keySet() ); + Collections.sort( xrefSeqBytePos ); + } + else + { + // copy xref type + resolvedXrefTrailer.xrefType = curObj.xrefType; + // found starting Xref object + // add this and follow chain defined by 'Prev' keys + xrefSeqBytePos.add( startxrefBytePosValue ); + while ( curObj.trailer != null ) + { + long prevBytePos = curObj.trailer.getLong( COSName.PREV, -1L ); + if ( prevBytePos == -1 ) + { + break; + } + + curObj = bytePosToXrefMap.get( prevBytePos ); + if ( curObj == null ) + { + LOG.warn( "Did not found XRef object pointed to by 'Prev' key at position " + prevBytePos ); + break; + } + xrefSeqBytePos.add( prevBytePos ); + + // sanity check to prevent infinite loops + if ( xrefSeqBytePos.size() >= bytePosToXrefMap.size() ) + { + break; + } + } + // have to reverse order so that later XRefs will overwrite previous ones + Collections.reverse( xrefSeqBytePos ); + } + + // merge used and sorted XRef/trailer + for ( Long bPos : xrefSeqBytePos ) + { + curObj = bytePosToXrefMap.get( bPos ); + if ( curObj.trailer != null ) + { + resolvedXrefTrailer.trailer.addAll( curObj.trailer ); + } + resolvedXrefTrailer.xrefTable.putAll( curObj.xrefTable ); + } + + } + + /** + * Gets the resolved trailer. Might return null in case + * {@link #setStartxref(long)} was not called before. + * + * @return the trailer if available + */ + public COSDictionary getTrailer() + { + return ( resolvedXrefTrailer == null ) ? null : resolvedXrefTrailer.trailer; + } + + /** + * Gets the resolved xref table. Might return null in case + * {@link #setStartxref(long)} was not called before. + * + * @return the xrefTable if available + */ + public Map getXrefTable() + { + return ( resolvedXrefTrailer == null ) ? null : resolvedXrefTrailer.xrefTable; + } + + /** Returns object numbers which are referenced as contained + * in object stream with specified object number. + * + * This will scan resolved xref table for all entries having negated + * stream object number as value. + * + * @param objstmObjNr object number of object stream for which contained object numbers + * should be returned + * + * @return set of object numbers referenced for given object stream + * or null if {@link #setStartxref(long)} was not + * called before so that no resolved xref table exists + */ + public Set getContainedObjectNumbers( final int objstmObjNr ) + { + if ( resolvedXrefTrailer == null ) + { + return null; + } + final Set refObjNrs = new HashSet(); + final long cmpVal = - objstmObjNr; + + for ( Entry xrefEntry : resolvedXrefTrailer.xrefTable.entrySet() ) + { + if ( xrefEntry.getValue() == cmpVal ) + { + refObjNrs.add( xrefEntry.getKey().getNumber() ); + } + } + return refObjNrs; + } +} diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/pagenavigation/PDTransitionDimension.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/pagenavigation/PDTransitionDimension.java index 4024a252922..fdc597a5c6e 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/pagenavigation/PDTransitionDimension.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/pagenavigation/PDTransitionDimension.java @@ -32,6 +32,6 @@ public enum PDTransitionDimension /** * Vertical */ - V; + V } diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/pagenavigation/PDTransitionMotion.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/pagenavigation/PDTransitionMotion.java index 7de02b65ffa..5a53402df2b 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/pagenavigation/PDTransitionMotion.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/pagenavigation/PDTransitionMotion.java @@ -32,5 +32,5 @@ public enum PDTransitionMotion /** * Outward from the center of the page */ - O; + O } diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/pagenavigation/PDTransitionStyle.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/pagenavigation/PDTransitionStyle.java index 283e1540411..a9d8d9b3239 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/pagenavigation/PDTransitionStyle.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/pagenavigation/PDTransitionStyle.java @@ -25,5 +25,5 @@ */ public enum PDTransitionStyle { - Split, Blinds, Box, Wipe, Dissolve, Glitter, R, Fly, Push, Cover, Uncover, Fade; + Split, Blinds, Box, Wipe, Dissolve, Glitter, R, Fly, Push, Cover, Uncover, Fade } diff --git a/pdfbox/src/main/java/org/apache/pdfbox/text/PDFTextStripper.java b/pdfbox/src/main/java/org/apache/pdfbox/text/PDFTextStripper.java index a726390e320..92de7768d60 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/text/PDFTextStripper.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/text/PDFTextStripper.java @@ -1870,7 +1870,7 @@ private String handleDirection(String word) LOG.error("Could not close BidiMirroring.txt ", e); } } - }; + } /** * This method parses the bidi file provided as inputstream. diff --git a/xmpbox/src/main/java/org/apache/xmpbox/DateConverter.java b/xmpbox/src/main/java/org/apache/xmpbox/DateConverter.java index 79ad82a6abb..558f7507105 100644 --- a/xmpbox/src/main/java/org/apache/xmpbox/DateConverter.java +++ b/xmpbox/src/main/java/org/apache/xmpbox/DateConverter.java @@ -67,7 +67,7 @@ public final class DateConverter */ private DateConverter() { - }; + } /** * This will convert a string to a calendar. From 836015b57bd6da684702c1c7a691a2702091facd Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Wed, 7 Sep 2016 18:59:15 +0000 Subject: [PATCH 0314/2182] PDFBOX-2852: remove unneeded boxing / unboxing git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1759660 13f79535-47bb-0310-9956-ffa450edef68 --- .../main/java/org/apache/pdfbox/debugger/ui/OSXAdapter.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/debugger/src/main/java/org/apache/pdfbox/debugger/ui/OSXAdapter.java b/debugger/src/main/java/org/apache/pdfbox/debugger/ui/OSXAdapter.java index 8736fb9f92c..ae5548173dc 100644 --- a/debugger/src/main/java/org/apache/pdfbox/debugger/ui/OSXAdapter.java +++ b/debugger/src/main/java/org/apache/pdfbox/debugger/ui/OSXAdapter.java @@ -123,7 +123,7 @@ public static void setPreferencesHandler(Object target, Method prefsHandler) { // com.apple.eawt.Application reflectively try { Method enablePrefsMethod = macOSXApplication.getClass().getDeclaredMethod("setEnabledPreferencesMenu", new Class[] { boolean.class }); - enablePrefsMethod.invoke(macOSXApplication, new Object[] { Boolean.valueOf(enablePrefsMenu) }); + enablePrefsMethod.invoke(macOSXApplication, new Object[] { enablePrefsMenu }); } catch (Exception ex) { System.err.println("OSXAdapter could not access the About Menu"); throw new RuntimeException(ex); @@ -188,7 +188,7 @@ public boolean callTarget(Object appleEvent) throws InvocationTargetException, I if (result == null) { return true; } - return Boolean.valueOf(result.toString()).booleanValue(); + return Boolean.valueOf(result.toString()); } // InvocationHandler implementation From 5d7b6f14aefe34ef192d780d11e0c6fd2adbae1c Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Wed, 7 Sep 2016 19:22:23 +0000 Subject: [PATCH 0315/2182] PDFBOX-2852: user foreach loop, as suggested by Simon Steiner git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1759667 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/org/apache/pdfbox/pdfparser/COSParser.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/COSParser.java b/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/COSParser.java index 4bd06110a81..3fbf8d2cd41 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/COSParser.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdfparser/COSParser.java @@ -551,10 +551,9 @@ protected void parseDictObjects(COSDictionary dict, COSName... excludeObjects) t } else if (baseObj instanceof COSArray) { - final Iterator arrIter = ((COSArray) baseObj).iterator(); - while (arrIter.hasNext()) + for (COSBase cosBase : ((COSArray) baseObj)) { - addNewToList(toBeParsedList, arrIter.next(), addedObjects); + addNewToList(toBeParsedList, cosBase, addedObjects); } } else if (baseObj instanceof COSObject) From 2fda9f0004d3329abf98be8ad63c312ff12f002e Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Wed, 7 Sep 2016 19:27:06 +0000 Subject: [PATCH 0316/2182] PDFBOX-2852: user foreach loop, as suggested by Simon Steiner git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1759670 13f79535-47bb-0310-9956-ffa450edef68 --- pdfbox/src/main/java/org/apache/pdfbox/cos/COSArray.java | 4 ++-- .../org/apache/pdfbox/pdmodel/common/COSArrayList.java | 8 ++------ 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/cos/COSArray.java b/pdfbox/src/main/java/org/apache/pdfbox/cos/COSArray.java index d8fb5303c39..a815dd29f6b 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/cos/COSArray.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/cos/COSArray.java @@ -550,9 +550,9 @@ public float[] toFloatArray() public void setFloatArray( float[] value ) { this.clear(); - for( int i=0; i cosObjectableList ) else { array = new COSArray(); - Iterator iter = cosObjectableList.iterator(); - while( iter.hasNext() ) + for (Object next : cosObjectableList) { - Object next = iter.next(); if( next instanceof String ) { array.add( new COSString( (String)next ) ); @@ -468,10 +466,8 @@ else if( next == null ) private List toCOSObjectList( Collection list ) { List cosObjects = new ArrayList(); - Iterator iter = list.iterator(); - while( iter.hasNext() ) + for (Object next : list) { - Object next = iter.next(); if( next instanceof String ) { cosObjects.add( new COSString( (String)next ) ); From fb13dc99a716deea00fc2a742fd270206c0382fe Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Wed, 7 Sep 2016 19:30:47 +0000 Subject: [PATCH 0317/2182] PDFBOX-3065: add apache header git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1759673 13f79535-47bb-0310-9956-ffa450edef68 --- .../digitalsignature/ExternalSigningSupport.java | 16 ++++++++++++++++ .../digitalsignature/SigningSupport.java | 16 ++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/ExternalSigningSupport.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/ExternalSigningSupport.java index be4d9690ad2..542a458b8dc 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/ExternalSigningSupport.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/ExternalSigningSupport.java @@ -1,3 +1,19 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.apache.pdfbox.pdmodel.interactive.digitalsignature; import java.io.IOException; diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/SigningSupport.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/SigningSupport.java index e47d5ebe289..6b35025d535 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/SigningSupport.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/SigningSupport.java @@ -1,3 +1,19 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.apache.pdfbox.pdmodel.interactive.digitalsignature; import org.apache.pdfbox.pdfwriter.COSWriter; From a0dfc3fdae6a5df4be3870c434b75f9f312c2f43 Mon Sep 17 00:00:00 2001 From: Tilman Hausherr Date: Wed, 7 Sep 2016 20:08:15 +0000 Subject: [PATCH 0318/2182] PDFBOX-2852: user foreach loop, as suggested by Simon Steiner git-svn-id: https://svn.apache.org/repos/asf/pdfbox/branches/2.0@1759687 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/fontbox/util/autodetect/FontFileFinder.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/fontbox/src/main/java/org/apache/fontbox/util/autodetect/FontFileFinder.java b/fontbox/src/main/java/org/apache/fontbox/util/autodetect/FontFileFinder.java index 9d39ea480cf..f9717cddae5 100644 --- a/fontbox/src/main/java/org/apache/fontbox/util/autodetect/FontFileFinder.java +++ b/fontbox/src/main/java/org/apache/fontbox/util/autodetect/FontFileFinder.java @@ -111,10 +111,8 @@ private void walk(File directory, List results) File[] filelist = directory.listFiles(); if (filelist != null) { - int numOfFiles = filelist.length; - for (int i=0;i
    Lucene Field NameDescription