From 3feb2cfa04ef281de7d337be291ebde757394fe3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20R=C3=B8sdal?= <41650711+andreasrosdal@users.noreply.github.com> Date: Sat, 17 Aug 2024 09:26:36 +0200 Subject: [PATCH 1/7] Add openpdf-pdfrenderer as a fork of https://github.com/katjas/PDFrenderer in accordance with LGPL license. --- openpdf-pdfrenderer/LICENSE.txt | 170 + openpdf-pdfrenderer/README.md | 99 + openpdf-pdfrenderer/pom.xml | 48 + .../java/com/sun/pdfview/BaseWatchable.java | 398 ++ .../sun/pdfview/ByteBufferInputStream.java | 107 + .../src/main/java/com/sun/pdfview/Cache.java | 311 ++ .../java/com/sun/pdfview/Configuration.java | 207 + .../main/java/com/sun/pdfview/HexDump.java | 84 + .../pdfview/Identity8BitCharsetEncoder.java | 61 + .../main/java/com/sun/pdfview/ImageInfo.java | 74 + .../main/java/com/sun/pdfview/NameTree.java | 131 + .../java/com/sun/pdfview/OutlineNode.java | 60 + .../src/main/java/com/sun/pdfview/PDFCmd.java | 59 + .../java/com/sun/pdfview/PDFDebugger.java | 136 + .../java/com/sun/pdfview/PDFDestination.java | 299 ++ .../com/sun/pdfview/PDFDocCharsetEncoder.java | 106 + .../java/com/sun/pdfview/PDFErrorHandler.java | 14 + .../main/java/com/sun/pdfview/PDFFile.java | 1875 +++++++ .../main/java/com/sun/pdfview/PDFImage.java | 1356 ++++++ .../sun/pdfview/PDFImageParseException.java | 18 + .../main/java/com/sun/pdfview/PDFObject.java | 849 ++++ .../main/java/com/sun/pdfview/PDFPage.java | 965 ++++ .../main/java/com/sun/pdfview/PDFPaint.java | 78 + .../com/sun/pdfview/PDFParseException.java | 39 + .../main/java/com/sun/pdfview/PDFParser.java | 1537 ++++++ .../java/com/sun/pdfview/PDFRenderer.java | 1038 ++++ .../java/com/sun/pdfview/PDFShapeCmd.java | 204 + .../java/com/sun/pdfview/PDFStringUtil.java | 230 + .../java/com/sun/pdfview/PDFTextFormat.java | 390 ++ .../main/java/com/sun/pdfview/PDFXref.java | 153 + .../sun/pdfview/PdfSubByteSampleModel.java | 143 + .../main/java/com/sun/pdfview/RefImage.java | 53 + .../main/java/com/sun/pdfview/Watchable.java | 71 + .../com/sun/pdfview/action/GoToAction.java | 49 + .../com/sun/pdfview/action/GoToEAction.java | 269 + .../com/sun/pdfview/action/GoToRAction.java | 75 + .../com/sun/pdfview/action/LaunchAction.java | 492 ++ .../com/sun/pdfview/action/PDFAction.java | 107 + .../pdfview/action/PdfObjectParseUtil.java | 100 + .../com/sun/pdfview/action/UriAction.java | 45 + .../annotation/AnnotationBorderStyle.java | 88 + .../pdfview/annotation/AnnotationType.java | 106 + .../pdfview/annotation/CircleAnnotation.java | 26 + .../annotation/FreetextAnnotation.java | 24 + .../pdfview/annotation/LinkAnnotation.java | 67 + .../pdfview/annotation/MarkupAnnotation.java | 257 + .../sun/pdfview/annotation/PDFAnnotation.java | 236 + .../pdfview/annotation/SquareAnnotation.java | 25 + .../pdfview/annotation/StampAnnotation.java | 70 + .../annotation/TextMarkupAnnotation.java | 82 + .../pdfview/annotation/WidgetAnnotation.java | 300 ++ .../sun/pdfview/colorspace/AltColorSpace.java | 73 + .../colorspace/AlternateColorSpace.java | 95 + .../pdfview/colorspace/CMYKColorSpace.java | 79 + .../sun/pdfview/colorspace/CalGrayColor.java | 133 + .../sun/pdfview/colorspace/CalRGBColor.java | 250 + .../sun/pdfview/colorspace/IndexedColor.java | 137 + .../com/sun/pdfview/colorspace/LabColor.java | 138 + .../pdfview/colorspace/MaskColorSpace.java | 101 + .../sun/pdfview/colorspace/PDFColorSpace.java | 237 + .../sun/pdfview/colorspace/PatternSpace.java | 107 + .../pdfview/colorspace/YCCKColorSpace.java | 133 + .../java/com/sun/pdfview/colorspace/sGray.icc | Bin 0 -> 2464 bytes .../com/sun/pdfview/decode/ASCII85Decode.java | 150 + .../sun/pdfview/decode/ASCIIHexDecode.java | 126 + .../java/com/sun/pdfview/decode/CCITTCodes | 236 + .../sun/pdfview/decode/CCITTFaxDecode.java | 117 + .../sun/pdfview/decode/CCITTFaxDecoder.java | 1581 ++++++ .../com/sun/pdfview/decode/DCTDecode.java | 128 + .../com/sun/pdfview/decode/FlateDecode.java | 96 + .../sun/pdfview/decode/ImageDataDecoder.java | 80 + .../com/sun/pdfview/decode/JPXDecode.java | 86 + .../com/sun/pdfview/decode/LZWDecode.java | 201 + .../com/sun/pdfview/decode/PDFDecoder.java | 214 + .../com/sun/pdfview/decode/PNGPredictor.java | 212 + .../com/sun/pdfview/decode/Predictor.java | 173 + .../sun/pdfview/decode/RunLengthDecode.java | 94 + .../com/sun/pdfview/decode/TIFFPredictor.java | 123 + .../pdfview/decrypt/CryptFilterDecrypter.java | 139 + ...ryptionUnsupportedByPlatformException.java | 39 + ...cryptionUnsupportedByProductException.java | 36 + .../pdfview/decrypt/IdentityDecrypter.java | 72 + .../PDFAuthenticationFailureException.java | 34 + .../com/sun/pdfview/decrypt/PDFDecrypter.java | 104 + .../pdfview/decrypt/PDFDecrypterFactory.java | 337 ++ .../com/sun/pdfview/decrypt/PDFPassword.java | 279 ++ .../pdfview/decrypt/StandardDecrypter.java | 1137 +++++ .../UnsupportedEncryptionException.java | 39 + .../com/sun/pdfview/font/BuiltinFont.java | 234 + .../com/sun/pdfview/font/CIDFontType0.java | 68 + .../com/sun/pdfview/font/CIDFontType2.java | 272 ++ .../java/com/sun/pdfview/font/FlPoint.java | 48 + .../com/sun/pdfview/font/FontSupport.java | 416 ++ .../java/com/sun/pdfview/font/NativeFont.java | 442 ++ .../com/sun/pdfview/font/OutlineFont.java | 154 + .../java/com/sun/pdfview/font/PDFFont.java | 530 ++ .../sun/pdfview/font/PDFFontDescriptor.java | 540 ++ .../com/sun/pdfview/font/PDFFontEncoding.java | 227 + .../java/com/sun/pdfview/font/PDFGlyph.java | 101 + .../java/com/sun/pdfview/font/TTFFont.java | 373 ++ .../java/com/sun/pdfview/font/Type0Font.java | 71 + .../java/com/sun/pdfview/font/Type1CFont.java | 1191 +++++ .../java/com/sun/pdfview/font/Type1Font.java | 907 ++++ .../java/com/sun/pdfview/font/Type3Font.java | 176 + .../com/sun/pdfview/font/cid/PDFCMap.java | 108 + .../sun/pdfview/font/cid/ToUnicodeMap.java | 310 ++ .../sun/pdfview/font/ttf/AdobeGlyphList.java | 181 + .../java/com/sun/pdfview/font/ttf/CMap.java | 185 + .../com/sun/pdfview/font/ttf/CMapFormat0.java | 157 + .../com/sun/pdfview/font/ttf/CMapFormat4.java | 466 ++ .../com/sun/pdfview/font/ttf/CMapFormat6.java | 140 + .../com/sun/pdfview/font/ttf/CmapTable.java | 294 ++ .../java/com/sun/pdfview/font/ttf/Glyf.java | 206 + .../sun/pdfview/font/ttf/GlyfCompound.java | 329 ++ .../com/sun/pdfview/font/ttf/GlyfSimple.java | 364 ++ .../com/sun/pdfview/font/ttf/GlyfTable.java | 157 + .../com/sun/pdfview/font/ttf/HeadTable.java | 473 ++ .../com/sun/pdfview/font/ttf/HheaTable.java | 382 ++ .../com/sun/pdfview/font/ttf/HmtxTable.java | 122 + .../com/sun/pdfview/font/ttf/LocaTable.java | 117 + .../com/sun/pdfview/font/ttf/MaxpTable.java | 426 ++ .../com/sun/pdfview/font/ttf/NameTable.java | 430 ++ .../com/sun/pdfview/font/ttf/PostTable.java | 545 +++ .../sun/pdfview/font/ttf/TrueTypeFont.java | 468 ++ .../sun/pdfview/font/ttf/TrueTypeTable.java | 194 + .../pdfview/font/ttf/resource/glyphlist.txt | 4323 +++++++++++++++++ .../sun/pdfview/function/FunctionType0.java | 444 ++ .../sun/pdfview/function/FunctionType2.java | 150 + .../sun/pdfview/function/FunctionType3.java | 183 + .../sun/pdfview/function/FunctionType4.java | 121 + .../com/sun/pdfview/function/PDFFunction.java | 347 ++ .../function/postscript/PostScriptParser.java | 69 + .../function/postscript/operation/Abs.java | 19 + .../function/postscript/operation/Add.java | 19 + .../function/postscript/operation/And.java | 20 + .../function/postscript/operation/Atan.java | 30 + .../postscript/operation/Bitshift.java | 25 + .../postscript/operation/Ceiling.java | 19 + .../function/postscript/operation/Copy.java | 64 + .../function/postscript/operation/Cvi.java | 28 + .../function/postscript/operation/Cvr.java | 26 + .../function/postscript/operation/Div.java | 22 + .../function/postscript/operation/Dup.java | 22 + .../function/postscript/operation/Eq.java | 40 + .../function/postscript/operation/Exch.java | 13 + .../function/postscript/operation/Exp.java | 23 + .../postscript/operation/Expression.java | 17 + .../function/postscript/operation/False.java | 20 + .../function/postscript/operation/Floor.java | 19 + .../function/postscript/operation/Ge.java | 30 + .../function/postscript/operation/Gt.java | 28 + .../function/postscript/operation/Idiv.java | 22 + .../function/postscript/operation/If.java | 28 + .../function/postscript/operation/IfElse.java | 32 + .../function/postscript/operation/Index.java | 11 + .../function/postscript/operation/Le.java | 29 + .../function/postscript/operation/Ln.java | 19 + .../function/postscript/operation/Log.java | 19 + .../function/postscript/operation/Lt.java | 27 + .../function/postscript/operation/Mod.java | 24 + .../function/postscript/operation/Mul.java | 21 + .../function/postscript/operation/Ne.java | 21 + .../function/postscript/operation/Neg.java | 21 + .../function/postscript/operation/Not.java | 21 + .../postscript/operation/OperationSet.java | 115 + .../function/postscript/operation/Or.java | 20 + .../function/postscript/operation/Pop.java | 12 + .../operation/PostScriptOperation.java | 13 + .../postscript/operation/PushAsNumber.java | 35 + .../function/postscript/operation/Roll.java | 50 + .../function/postscript/operation/Round.java | 21 + .../function/postscript/operation/Sin.java | 20 + .../function/postscript/operation/Sqrt.java | 19 + .../function/postscript/operation/Sub.java | 23 + .../function/postscript/operation/True.java | 20 + .../postscript/operation/Truncate.java | 21 + .../function/postscript/operation/Xor.java | 19 + .../com/sun/pdfview/pattern/DummyShader.java | 25 + .../com/sun/pdfview/pattern/PDFPattern.java | 136 + .../com/sun/pdfview/pattern/PDFShader.java | 244 + .../com/sun/pdfview/pattern/PatternType1.java | 407 ++ .../com/sun/pdfview/pattern/PatternType2.java | 64 + .../com/sun/pdfview/pattern/ShaderType2.java | 396 ++ .../com/sun/pdfview/pattern/ShaderType3.java | 389 ++ .../sun/pdfview/font/res/BaseFonts.properties | 57 + .../com/sun/pdfview/font/res/d050000l.pfb | Bin 0 -> 45955 bytes .../com/sun/pdfview/font/res/n019003l.pfb | Bin 0 -> 68590 bytes .../com/sun/pdfview/font/res/n019004l.pfb | Bin 0 -> 72400 bytes .../com/sun/pdfview/font/res/n019023l.pfb | Bin 0 -> 71719 bytes .../com/sun/pdfview/font/res/n019024l.pfb | Bin 0 -> 73879 bytes .../com/sun/pdfview/font/res/n021003l.pfb | Bin 0 -> 113206 bytes .../com/sun/pdfview/font/res/n021004l.pfb | Bin 0 -> 108822 bytes .../com/sun/pdfview/font/res/n021023l.pfb | Bin 0 -> 108217 bytes .../com/sun/pdfview/font/res/n021024l.pfb | Bin 0 -> 96211 bytes .../com/sun/pdfview/font/res/n022003l.pfb | Bin 0 -> 96263 bytes .../com/sun/pdfview/font/res/n022004l.pfb | Bin 0 -> 120373 bytes .../com/sun/pdfview/font/res/n022023l.pfb | Bin 0 -> 101133 bytes .../com/sun/pdfview/font/res/n022024l.pfb | Bin 0 -> 114228 bytes .../com/sun/pdfview/font/res/s050000l.pfb | Bin 0 -> 32213 bytes .../src/test/java/PdfRendererToImageTest.java | 120 + pdf-swing/pom.xml | 5 +- pom.xml | 6 +- 202 files changed, 41547 insertions(+), 7 deletions(-) create mode 100644 openpdf-pdfrenderer/LICENSE.txt create mode 100644 openpdf-pdfrenderer/README.md create mode 100644 openpdf-pdfrenderer/pom.xml create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/BaseWatchable.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/ByteBufferInputStream.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/Cache.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/Configuration.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/HexDump.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/Identity8BitCharsetEncoder.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/ImageInfo.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/NameTree.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/OutlineNode.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFCmd.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFDebugger.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFDestination.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFDocCharsetEncoder.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFErrorHandler.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFFile.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFImage.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFImageParseException.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFObject.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFPage.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFPaint.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFParseException.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFParser.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFRenderer.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFShapeCmd.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFStringUtil.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFTextFormat.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFXref.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PdfSubByteSampleModel.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/RefImage.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/Watchable.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/action/GoToAction.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/action/GoToEAction.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/action/GoToRAction.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/action/LaunchAction.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/action/PDFAction.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/action/PdfObjectParseUtil.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/action/UriAction.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/AnnotationBorderStyle.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/AnnotationType.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/CircleAnnotation.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/FreetextAnnotation.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/LinkAnnotation.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/MarkupAnnotation.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/PDFAnnotation.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/SquareAnnotation.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/StampAnnotation.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/TextMarkupAnnotation.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/WidgetAnnotation.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/AltColorSpace.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/AlternateColorSpace.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/CMYKColorSpace.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/CalGrayColor.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/CalRGBColor.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/IndexedColor.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/LabColor.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/MaskColorSpace.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/PDFColorSpace.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/PatternSpace.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/YCCKColorSpace.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/sGray.icc create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/ASCII85Decode.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/ASCIIHexDecode.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/CCITTCodes create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/CCITTFaxDecode.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/CCITTFaxDecoder.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/DCTDecode.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/FlateDecode.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/ImageDataDecoder.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/JPXDecode.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/LZWDecode.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/PDFDecoder.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/PNGPredictor.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/Predictor.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/RunLengthDecode.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/TIFFPredictor.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/CryptFilterDecrypter.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/EncryptionUnsupportedByPlatformException.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/EncryptionUnsupportedByProductException.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/IdentityDecrypter.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/PDFAuthenticationFailureException.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/PDFDecrypter.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/PDFDecrypterFactory.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/PDFPassword.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/StandardDecrypter.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/UnsupportedEncryptionException.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/BuiltinFont.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/CIDFontType0.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/CIDFontType2.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/FlPoint.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/FontSupport.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/NativeFont.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/OutlineFont.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/PDFFont.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/PDFFontDescriptor.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/PDFFontEncoding.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/PDFGlyph.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/TTFFont.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/Type0Font.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/Type1CFont.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/Type1Font.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/Type3Font.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/cid/PDFCMap.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/cid/ToUnicodeMap.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/AdobeGlyphList.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/CMap.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/CMapFormat0.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/CMapFormat4.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/CMapFormat6.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/CmapTable.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/Glyf.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/GlyfCompound.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/GlyfSimple.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/GlyfTable.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/HeadTable.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/HheaTable.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/HmtxTable.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/LocaTable.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/MaxpTable.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/NameTable.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/PostTable.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/TrueTypeFont.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/TrueTypeTable.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/resource/glyphlist.txt create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/FunctionType0.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/FunctionType2.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/FunctionType3.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/FunctionType4.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/PDFFunction.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/PostScriptParser.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Abs.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Add.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/And.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Atan.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Bitshift.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Ceiling.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Copy.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Cvi.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Cvr.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Div.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Dup.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Eq.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Exch.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Exp.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Expression.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/False.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Floor.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Ge.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Gt.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Idiv.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/If.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/IfElse.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Index.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Le.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Ln.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Log.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Lt.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Mod.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Mul.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Ne.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Neg.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Not.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/OperationSet.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Or.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Pop.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/PostScriptOperation.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/PushAsNumber.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Roll.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Round.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Sin.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Sqrt.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Sub.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/True.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Truncate.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Xor.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/pattern/DummyShader.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/pattern/PDFPattern.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/pattern/PDFShader.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/pattern/PatternType1.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/pattern/PatternType2.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/pattern/ShaderType2.java create mode 100644 openpdf-pdfrenderer/src/main/java/com/sun/pdfview/pattern/ShaderType3.java create mode 100644 openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/BaseFonts.properties create mode 100644 openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/d050000l.pfb create mode 100644 openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/n019003l.pfb create mode 100644 openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/n019004l.pfb create mode 100644 openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/n019023l.pfb create mode 100644 openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/n019024l.pfb create mode 100644 openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/n021003l.pfb create mode 100644 openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/n021004l.pfb create mode 100644 openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/n021023l.pfb create mode 100644 openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/n021024l.pfb create mode 100644 openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/n022003l.pfb create mode 100644 openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/n022004l.pfb create mode 100644 openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/n022023l.pfb create mode 100644 openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/n022024l.pfb create mode 100644 openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/s050000l.pfb create mode 100644 openpdf-pdfrenderer/src/test/java/PdfRendererToImageTest.java diff --git a/openpdf-pdfrenderer/LICENSE.txt b/openpdf-pdfrenderer/LICENSE.txt new file mode 100644 index 000000000..cc4078c9b --- /dev/null +++ b/openpdf-pdfrenderer/LICENSE.txt @@ -0,0 +1,170 @@ +The GNU Lesser General Public License, version 2.1 (LGPL-2.1) +[OSI Approved License] +GNU Lesser General Public License + +Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. + + [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] + +Preamble + +The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. + +This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. + +When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. + +To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. + +For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. + +We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. + +To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. + +Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. + +Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. + +When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. + +We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. + +For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. + +In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. + +Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. + +The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. +TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + +0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". + +A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. + +The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) + +"Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. + +Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. + +1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. + +You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. + +2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. + + (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) + + These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. + + Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. + + In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. + +3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. + +Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. + +This option is useful when you wish to copy part of the code of the Library into a program that is not a library. + +4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. + +If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. + +5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. + +However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. + +When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. + +If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) + +Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. + +6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. + +You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: + + a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. + + e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. + +For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. + +It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. + +7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. + + b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. + +8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. + +9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. + +10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. + +11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. + +This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. + +12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. + +13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. + +14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. + +NO WARRANTY + +15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. +END OF TERMS AND CONDITIONS +How to Apply These Terms to Your New Libraries +If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). + +To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. + + Copyright (C) + + This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + signature of Ty Coon, 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! \ No newline at end of file diff --git a/openpdf-pdfrenderer/README.md b/openpdf-pdfrenderer/README.md new file mode 100644 index 000000000..680c5b0ea --- /dev/null +++ b/openpdf-pdfrenderer/README.md @@ -0,0 +1,99 @@ +openpdf-pdfrenderer +=================== + +PDF to Image renderer for OpenPDF. + +Because every PDF library should be able to create a PNG from a PDF. + +License: GNU Lesser General Public License + +--- + +This is a fork of [pdf-renderer](http://java.net/projects/pdf-renderer) (covered by the LGPL-2.1 license) for improvement purposes. + +The principal objective of the fork is to improve the original PDF renderer. The original version is able to handle most of the PDF 1.4 features, but has several bugs and missing functionality. + + + +To do: +------ +* some colours are displayed incorrect, there seem to be open issues regarding colour space handling +* some fonts can't be rendered and are replaced with built in fonts +* embedded Type0 font with a CIDType0 font is not supported correctly. Currently there is a hack in the code to fall back to the built in fonts in this case. +* try to improve support of auto adjust stroke and overprint mode - the data is read but not really handled correctly. + +Done: +----- +* support for widget annotation containing digital signature +* support function type 4 rendering (subset of the PostScript language, specification taken from http://www.adobe.com/devnet/acrobat/pdfs/adobe_supplement_iso32000.pdf) +* support link annotations for being able to render links +* rough support of stamp and freetext annotations +* handle alternate colour spaces (colour space plus a function to be applied on the colour values) +* fixes transparency issues / transparent masked images (even though transparency is still not completely supported) +* corrected handling of overlapping shapes +* better support Type0 fonts that use embedded CID fonts +* jbig2 image format decoded with (improved) "jpedal" API +* DeviceCMY / DeviceRGB colour spaces are working now, but some PDFs are still displayed in wrong format. +* Improved reading of CMYK images. Some colours are still displayed wrong. (using the ch.randelshofer.media.jpeg.JPEGImageIO API) +* Improved run length decoding (corrected reading of buffer) +* fixed compression issues +* fixed size of outline fonts +* fixed several exceptions +* Fixed various font encoding problems (Flex in Type 1, wrong stemhints in Type 1C and inverted presentation of Type 3) +* fixed rotation of text (http://java.net/jira/browse/PDF_RENDERER-91) +* JPEG decoding with imageio +* Work-around lack of YCCK decoding support in standard JRE image readers and thus allow CMYK jpeg images without using 3rd party image readers (e.g., JAI) +* Employ local TTF files if available instead of using the built-ins as substitutes. Scanning of available TTFs will take some time on the first request for an unavailable TTF. This behaviour can be disabled by setting the system property PDFRenderer.avoidExternalTtf to true. The PDFRenderer.fontSearchPath system property can be used to alter the search path, though Windows and Mac OS X defaults should hopefully be sensible. +* Added TIFF Type 2 Predictor for decoding +* use built in font as workaround for MMType1 fonts instead of throwing an exception +* introduced configuration options for improving the memory usage when rendering PDFs with large (e.g. scanned) images +* improved parsing of SMask images +* modified parsing of paths, some closures were missing +* added some debugging +* Add option to inject exception handling - e.g. for redirecting the stack trace to a log file +* Add SymbolSetEncoding + +Usage / Example +------- + +// example class for displaying a PDF file +```java +public class PDFDisplay extends JComponent{ + + // byte array containing the PDF file content + private byte[] bytes = null; + + + // some more code + + @Override + public void paintComponent(Graphics g) { + int pageindex = 1; + PDFFile pdfFile = new PDFFile(ByteBuffer.wrap(this.bytes)); + PDFPage page = pdfFile.getPage(pageIndex); + Paper paper = new Paper(); + int formatOrientation = page.getAspectRatio() > 1 ? PageFormat.LANDSCAPE + : PageFormat.PORTRAIT; + if(formatOrientation == PageFormat.LANDSCAPE) { + paper.setSize(page.getHeight(), page.getWidth()); + }else { + paper.setSize(page.getWidth(), page.getHeight()); + } + PageFormat pageFormat = new PageFormat(); + pageFormat.setPaper(paper); + pageFormat.setOrientation(formatOrientation); + + Graphics2D g2d = (Graphics2D)g.create(); + Rectangle imgbounds = new Rectangle(0, 0, (int)pageFormat.getWidth(), + (int)pageFormat.getHeight()); + PDFRenderer renderer = new PDFRenderer(page, g2d, imgbounds, null, Color.WHITE); + try { + this.page.waitForFinish(); + } + catch (InterruptedException e) { + // some exception handling + } + renderer.run(); + } +} +``` diff --git a/openpdf-pdfrenderer/pom.xml b/openpdf-pdfrenderer/pom.xml new file mode 100644 index 000000000..3ed4c1536 --- /dev/null +++ b/openpdf-pdfrenderer/pom.xml @@ -0,0 +1,48 @@ + + + + com.github.librepdf + openpdf-parent + 2.0.4-SNAPSHOT + + + 4.0.0 + openpdf-pdfrenderer + openpdf-pdfrenderer + + + + Lesser General Public License (LGPL) + http://www.gnu.org/copyleft/lesser.html + + + PDF renderer implementation supporting the subset of PDF 1.4 specification. + + + + + com.github.librepdf + openpdf + ${project.version} + test + + + + org.junit.jupiter + junit-jupiter-api + test + + + org.junit.jupiter + junit-jupiter-params + test + + + org.assertj + assertj-core + test + + + + \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/BaseWatchable.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/BaseWatchable.java new file mode 100644 index 000000000..6c79bbd50 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/BaseWatchable.java @@ -0,0 +1,398 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.sun.pdfview; + +/** + * An abstract implementation of the watchable interface, that is extended + * by the parser and renderer to do their thing. + */ +public abstract class BaseWatchable implements Watchable, Runnable { + + /** the current status, from the list in Watchable */ + private int status = Watchable.UNKNOWN; + /** a lock for status-related operations */ + private final Object statusLock = new Object(); + /** a lock for parsing operations */ + private final Object parserLock = new Object(); + /** when to stop */ + private Gate gate; + /** suppress local stack trace on setError. */ + private static boolean SuppressSetErrorStackTrace = false; + /** the thread we are running in */ + private Thread thread; + private Exception exception; + + // handle exceptions via this class + private static PDFErrorHandler errorHandler = new PDFErrorHandler(); + + /** + * Creates a new instance of BaseWatchable + */ + protected BaseWatchable() { + setStatus(Watchable.NOT_STARTED); + } + + /** + * Perform a single iteration of this watchable. This is the minimum + * granularity which the go() commands operate over. + * + * @return one of three values:
    + *
  • Watchable.RUNNING if there is still data to be processed + *
  • Watchable.NEEDS_DATA if there is no data to be processed but + * the execution is not yet complete + *
  • Watchable.COMPLETED if the execution is complete + *
+ */ + protected abstract int iterate() throws Exception; + + /** + * Prepare for a set of iterations. Called before the first iterate() call + * in a sequence. Subclasses should extend this method if they need to do + * anything to setup. + */ + protected void setup() { + // do nothing + } + + /** + * Clean up after a set of iterations. Called after iteration has stopped + * due to completion, manual stopping, or error. + */ + protected void cleanup() { + // do nothing + } + + @Override + public void run() { + try { + Thread.sleep(1); + // call setup once we started + if (getStatus() == Watchable.NOT_STARTED) { + setup(); + } + + setStatus(Watchable.PAUSED); + + synchronized (this.parserLock) { + while (!isFinished() && getStatus() != Watchable.STOPPED) { + if (isExecutable()) { + // set the status to running + setStatus(Watchable.RUNNING); + + try { + // keep going until the status is no longer running, + // our gate tells us to stop, or no-one is watching + int laststatus = Watchable.RUNNING; + while ((getStatus() == Watchable.RUNNING) && (this.gate == null || !this.gate.iterate())) { + // update the status based on this iteration + int status = iterate(); + if (status != laststatus) { + // update status only when necessary, this increases performance + setStatus(status); + laststatus = status; + } + + } + + // make sure we are paused + if (getStatus() == Watchable.RUNNING) { + setStatus(Watchable.PAUSED); + } + } catch (Exception ex) { + setError(ex); + } + } else { + // wait for our status to change + synchronized (this.statusLock) { + if (!isExecutable()) { + try { + this.statusLock.wait(); + } catch (InterruptedException ie) { + // ignore + } + } + } + } + } + } + // call cleanup when we are done + if (getStatus() == Watchable.COMPLETED || getStatus() == Watchable.ERROR) { + + cleanup(); + } + } catch (InterruptedException e) { + PDFDebugger.debug("Interrupted."); + } + // notify that we are no longer running + this.thread = null; + } + + /** + * Get the status of this watchable + * + * @return one of the well-known statuses + */ + @Override + public int getStatus() { + return this.status; + } + + /** + * Return whether this watchable has finished. A watchable is finished + * when its status is either COMPLETED, STOPPED or ERROR + */ + public boolean isFinished() { + int s = getStatus(); + return (s == Watchable.COMPLETED || + s == Watchable.ERROR); + } + + /** + * return true if this watchable is ready to be executed + */ + public boolean isExecutable() { + return ((this.status == Watchable.PAUSED || this.status == Watchable.RUNNING) && + (this.gate == null || !this.gate.stop())); + } + + /** + * Stop this watchable if it is not already finished. + * Stop will cause all processing to cease, + * and the watchable to be destroyed. + */ + @Override + public void stop() { + if (!isFinished()) setStatus(Watchable.STOPPED); + } + + /** + * Start this watchable and run in a new thread until it is finished or + * stopped. + * Note the watchable may be stopped if go() with a + * different time is called during execution. + */ + @Override + public synchronized void go() { + this.gate = null; + + execute(false); + } + + /** + * Start this watchable and run until it is finished or stopped. + * Note the watchable may be stopped if go() with a + * different time is called during execution. + * + * @param synchronous if true, run in this thread + */ + public synchronized void go(boolean synchronous) { + this.gate = null; + + execute(synchronous); + } + + /** + * Start this watchable and run for the given number of steps or until + * finished or stopped. + * + * @param steps the number of steps to run for + */ + @Override + public synchronized void go(int steps) { + this.gate = new Gate(); + this.gate.setStopIterations(steps); + + execute(false); + } + + /** + * Start this watchable and run for the given amount of time, or until + * finished or stopped. + * + * @param millis the number of milliseconds to run for + */ + @Override + public synchronized void go(long millis) { + this.gate = new Gate(); + this.gate.setStopTime(millis); + + execute(false); + } + + /** + * Wait for this watchable to finish + */ + public void waitForFinish() { + synchronized (this.statusLock) { + while (!isFinished() && getStatus() != Watchable.STOPPED) { + try { + this.statusLock.wait(); + } catch (InterruptedException ex) { + // ignore + } + } + } + } + + /** + * Start executing this watchable + * + * @param synchronous if true, run in this thread + */ + protected synchronized void execute(boolean synchronous) { + // see if we're already running + if (this.thread != null) { + // we're already running. Make sure we wake up on any change. + synchronized (this.statusLock) { + this.statusLock.notifyAll(); + } + + return; + } else if (isFinished()) { + // we're all finished + return; + } + + // we'return not running. Start up + if (synchronous) { + this.thread = Thread.currentThread(); + run(); + } else { + this.thread = new Thread(this); + this.thread.setName(getClass().getName()); + //Fix for NPE: Taken from http://java.net/jira/browse/PDF_RENDERER-46 + synchronized (statusLock) { + Thread.UncaughtExceptionHandler h = new Thread.UncaughtExceptionHandler() { + @Override + public void uncaughtException( Thread th, Throwable ex ) + { + PDFDebugger.debug( "Uncaught exception: " + ex ); + } + }; + thread.setUncaughtExceptionHandler( h ); + thread.start(); + try { + statusLock.wait(); + } catch (InterruptedException ex) { + // ignore + } + } + } + } + + /** + * Set the status of this watchable + */ + protected void setStatus(int status) { + synchronized (this.statusLock) { + this.status = status; + + this.statusLock.notifyAll(); + } + } + + /** + * return true if we would be suppressing setError stack traces. + * + * @return boolean + */ + public static boolean isSuppressSetErrorStackTrace () { + return SuppressSetErrorStackTrace; + } + + /** + * set suppression of stack traces from setError. + * + * @param suppressTrace + */ + public static void setSuppressSetErrorStackTrace(boolean suppressTrace) { + SuppressSetErrorStackTrace = suppressTrace; + } + + /** + * Set an error on this watchable + */ + protected void setError(Exception error) { + exception = error; + if (!SuppressSetErrorStackTrace) { + errorHandler.publishException(error); + } + + setStatus(Watchable.ERROR); + } + + public Exception getException() { + return exception; + } + + /** A class that lets us give it a target time or number of steps, + * and will tell us to stop after that much time or that many steps + */ + static class Gate { + + /** whether this is a time-based (true) or step-based (false) gate */ + private boolean timeBased; + /** the next gate, whether time or iterations */ + private long nextGate; + + /** set the stop time */ + public void setStopTime(long millisFromNow) { + this.timeBased = true; + this.nextGate = System.currentTimeMillis() + millisFromNow; + } + + /** set the number of iterations until we stop */ + public void setStopIterations(int iterations) { + this.timeBased = false; + this.nextGate = iterations; + } + + /** check whether we should stop. + */ + public boolean stop() { + if (this.timeBased) { + return (System.currentTimeMillis() >= this.nextGate); + } else { + return (this.nextGate < 0); + } + } + + /** Notify the gate of one iteration. Returns true if we should + * stop or false if not + */ + public boolean iterate() { + if (!this.timeBased) { + this.nextGate--; + } + + return stop(); + } + } + + public static void setErrorHandler(PDFErrorHandler e) { + errorHandler = e; + } + + public static PDFErrorHandler getErrorHandler(){ + if(errorHandler == null) { + errorHandler = new PDFErrorHandler(); + } + return errorHandler; + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/ByteBufferInputStream.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/ByteBufferInputStream.java new file mode 100644 index 000000000..862870008 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/ByteBufferInputStream.java @@ -0,0 +1,107 @@ +/* + * Copyright 2010 Pirion Systems Pty Ltd, 139 Warry St, + * Fortitude Valley, Queensland, Australia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.sun.pdfview; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; + +/** + * Exposes a {@link ByteBuffer} as an {@link InputStream}. + * + * @author Luke Kirby + */ +public class ByteBufferInputStream extends InputStream { + + /** The underlying byte buffer */ + private ByteBuffer buffer; + + /** + * Class constructor + * @param buffer the buffer to present as an input stream, positioned + * at the current read position of the byte buffer + */ + public ByteBufferInputStream(ByteBuffer buffer) { + this.buffer = buffer; + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + + if (b == null) { + throw new NullPointerException(); + } else if (off < 0 || len < 0 || len > b.length - off) { + throw new IndexOutOfBoundsException(); + } else if (len == 0) { + return 0; + } + + final int remaining = buffer.remaining(); + if (remaining == 0) { + return -1; + } else if (remaining < len) { + buffer.get(b, off, remaining); + return remaining; + } else { + buffer.get(b, off, len); + return len; + } + } + + @Override + public long skip(long n) throws IOException { + if (n <= 0) { + return 0; + } else { + final int remaining = buffer.remaining(); + if (n < remaining) { + buffer.position(buffer.position() + remaining); + return remaining; + } else { + buffer.position((int) (buffer.position() + n)); + return n; + } + } + } + + @Override + public int read() throws IOException { + return buffer.get(); + } + + @Override + public int available() throws IOException { + return buffer.remaining(); + } + + @Override + public void mark(int readlimit) { + buffer.mark(); + } + + @Override + public boolean markSupported() { + return true; + } + + @Override + public void reset() throws IOException { + buffer.reset(); + } +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/Cache.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/Cache.java new file mode 100644 index 000000000..ec2a08df8 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/Cache.java @@ -0,0 +1,311 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.sun.pdfview; + +import java.awt.image.BufferedImage; +import java.lang.ref.SoftReference; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +/** + * A cache of PDF pages and images. + */ +public class Cache { + + /** the pages in the cache, mapped by page number */ + private final Map> pages; + + /** Creates a new instance of a Cache */ + public Cache() { + this.pages = Collections.synchronizedMap(new HashMap>()); + } + + /** + * Add a page to the cache. This method should be used for + * pages which have already been completely rendered. + * + * @param pageNumber the page number of this page + * @param page the page to add + */ + public void addPage(Integer pageNumber, PDFPage page) { + addPageRecord(pageNumber, page, null); + } + + /** + * Add a page to the cache. This method should be used for + * pages which are still in the process of being rendered. + * + * @param pageNumber the page number of this page + * @param page the page to add + * @param parser the parser which is parsing this page + */ + public void addPage(Integer pageNumber, PDFPage page, PDFParser parser) { + addPageRecord(pageNumber, page, parser); + } + + /** + * Add an image to the cache. This method should be used for images + * which have already been completely rendered + * + * @param page page this image is associated with + * @param info the image info associated with this image + * @param image the image to add + */ + public void addImage(PDFPage page, ImageInfo info, BufferedImage image) { + addImageRecord(page, info, image, null); + } + + /** + * Add an image to the cache. This method should be used for images + * which are still in the process of being rendered. + * + * @param page the page this image is associated with + * @param info the image info associated with this image + * @param image the image to add + * @param renderer the renderer which is rendering this page + */ + public void addImage(PDFPage page, ImageInfo info, BufferedImage image, + PDFRenderer renderer) { + addImageRecord(page, info, image, renderer); + } + + /** + * Get a page from the cache + * + * @param pageNumber the number of the page to get + * @return the page, if it is in the cache, or null if not + */ + public PDFPage getPage(Integer pageNumber) { + PageRecord rec = getPageRecord(pageNumber); + if (rec != null) { + return (PDFPage) rec.value; + } + + // not found + return null; + } + + /** + * Get a page's parser from the cache + * + * @param pageNumber the number of the page to get the parser for + * @return the parser, or null if it is not in the cache + */ + public PDFParser getPageParser(Integer pageNumber) { + PageRecord rec = getPageRecord(pageNumber); + if (rec != null) { + return (PDFParser) rec.generator; + } + + // not found + return null; + } + + /** + * Get an image from the cache + * + * @param page the page the image is associated with + * @param info the image info that describes the image + * + * @return the image if it is in the cache, or null if not + */ + public BufferedImage getImage(PDFPage page, ImageInfo info) { + Record rec = getImageRecord(page, info); + if (rec != null) { + return (BufferedImage) rec.value; + } + + // not found + return null; + } + + /** + * Get an image's renderer from the cache + * + * @param page the page this image was generated from + * @param info the image info describing the image + * @return the renderer, or null if it is not in the cache + */ + public PDFRenderer getImageRenderer(PDFPage page, ImageInfo info) { + Record rec = getImageRecord(page, info); + if (rec != null) { + return (PDFRenderer) rec.generator; + } + + // not found + return null; + } + + /** + * Remove a page and all its associated images, as well as its parser + * and renderers, from the cache + * + * @param pageNumber the number of the page to remove + */ + public void removePage(Integer pageNumber) { + removePageRecord(pageNumber); + } + + /** + * Remove an image and its associated renderer from the cache + * + * @param page the page the image is generated from + * @param info the image info of the image to remove + */ + public void removeImage(PDFPage page, ImageInfo info) { + removeImageRecord(page, info); + } + + /** + * The internal routine to add a page to the cache, and return the + * page record which was generated + */ + PageRecord addPageRecord(Integer pageNumber, PDFPage page, + PDFParser parser) { + PageRecord rec = new PageRecord(); + rec.value = page; + rec.generator = parser; + + this.pages.put(pageNumber, new SoftReference(rec)); + + return rec; + } + + /** + * Get a page's record from the cache + * + * @return the record, or null if it's not in the cache + */ + PageRecord getPageRecord(Integer pageNumber) { + PDFDebugger.debug("Request for page " + pageNumber, 1000); + SoftReference ref = this.pages.get(pageNumber); + if (ref != null) { + String val = (ref.get() == null) ? " not in " : " in "; + PDFDebugger.debug("Page " + pageNumber + val + "cache", 1000); + return ref.get(); + } + + PDFDebugger.debug("Page " + pageNumber + " not in cache", 1000); + // not in cache + return null; + } + + /** + * Remove a page's record from the cache + */ + PageRecord removePageRecord(Integer pageNumber) { + SoftReference ref = this.pages.remove(pageNumber); + if (ref != null) { + return ref.get(); + } + + // not in cache + return null; + } + + /** + * The internal routine to add an image to the cache and return the + * record that was generated. + */ + Record addImageRecord(PDFPage page, ImageInfo info, + BufferedImage image, PDFRenderer renderer) { + // first, find or create the relevant page record + Integer pageNumber = Integer.valueOf(page.getPageNumber()); + PageRecord pageRec = getPageRecord(pageNumber); + if (pageRec == null) { + pageRec = addPageRecord(pageNumber, page, null); + } + + // next, create the image record + Record rec = new Record(); + rec.value = image; + rec.generator = renderer; + + // add it to the cache + pageRec.images.put(info, new SoftReference(rec)); + + return rec; + } + + /** + * Get an image's record from the cache + * + * @return the record, or null if it's not in the cache + */ + Record getImageRecord(PDFPage page, ImageInfo info) { + // first find the relevant page record + Integer pageNumber = Integer.valueOf(page.getPageNumber()); + + PDFDebugger.debug("Request for image on page " + pageNumber, 1000); + + PageRecord pageRec = getPageRecord(pageNumber); + if (pageRec != null) { + SoftReference ref = pageRec.images.get(info); + if (ref != null) { + String val = (ref.get() == null) ? " not in " : " in "; + PDFDebugger.debug("Image on page " + pageNumber + val + " cache", 1000); + return ref.get(); + } + } + + PDFDebugger.debug("Image on page " + pageNumber + " not in cache", 1000); + // not found + return null; + } + + /** + * Remove an image's record from the cache + */ + Record removeImageRecord(PDFPage page, ImageInfo info) { + // first find the relevant page record + Integer pageNumber = Integer.valueOf(page.getPageNumber()); + PageRecord pageRec = getPageRecord(pageNumber); + if (pageRec != null) { + SoftReference ref = pageRec.images.remove(info); + if (ref != null) { + return ref.get(); + } + + } + + return null; + } + + /** the basic information about a page or image */ + class Record { + + /** the page or image itself */ + Object value; + /** the thing generating the page, or null if done/not provided */ + BaseWatchable generator; + } + + /** the record stored for each page in the cache */ + class PageRecord extends Record { + + /** any images associated with the page */ + Map> images; + + /** create a new page record */ + public PageRecord() { + this.images = Collections.synchronizedMap(new HashMap>()); + } + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/Configuration.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/Configuration.java new file mode 100644 index 000000000..e17bf3011 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/Configuration.java @@ -0,0 +1,207 @@ +package com.sun.pdfview; + +/** + * Since there is no context that is passed between the various classes that + * perform the pdf parsing and rendering, we introduce this class to at least + * globally configure PDFRenderer. + * + * Typically you would configure the global instance before using any other + * PDFRenderer API. + */ +public class Configuration { + private static Configuration INSTANCE; + + /** whether grey scale images will be converted to ARGB */ + private boolean convertGreyscaleImagesToArgb = true; + /** threshold in pixels after which images are rendered in chunks (disabled by default) */ + private int thresholdForBandedImageRendering = 0; + /** whether color convert op should be used or not for parsing an image*/ + private boolean avoidColorConvertOp = false; + /** Use blur before image resize to enhance the result (Antialias) **/ + private boolean useBlurResizingForImages = true; + + /** Print signature fields on pdf **/ + private boolean printSigantureFields = true; + /** Print stamp annotations on pdf **/ + private boolean printStampAnnotations = true; + /** Print widget annotations on pdf **/ + private boolean printWidgetAnnotations = true; + /** Print freetext annotations on pdf **/ + private boolean printFreetextAnnotations = true; + /** Print link annotations on pdf **/ + private boolean printLinkAnnotations = true; + + public static synchronized Configuration getInstance() { + if (INSTANCE == null) { + INSTANCE = new Configuration(); + } + return INSTANCE; + } + + /** + * Enables or disables the conversion of greyscale images to ARGB. + * Disabling this may have a lower memory overhead with high resolution + * (e.g. scanned) images. Note that this has to be called before + * {@link #getImage()} is called to have an effect. + * + * Enabled by default. + * @param aFlag whether greyscale images shall be converted to ARGB. + */ + public void setConvertGreyscaleImagesToArgb(boolean aFlag) { + convertGreyscaleImagesToArgb = aFlag; + } + + /** + * Returns true if greyscale images will be converted to ARGB + */ + public boolean isConvertGreyscaleImagesToArgb() { + return convertGreyscaleImagesToArgb; + } + + /** + * If an image is higher than the given size (in pixels) then + * the image will be rendered in chunks, rather than as one big image. + * This may lead to lower memory consumption for e.g. scanned PDFs with + * large images. + * + * Set to a value <= 0 to disable banded image rendering. + * Defaults to 0 (off) + * + * @param aSize the height threshold at which to enable banded image rendering + */ + public void setThresholdForBandedImageRendering(int aSize) { + thresholdForBandedImageRendering = aSize; + } + + /** + * Returns the image height threshold at which to enable banded image rendering. + * @return the threshold value, or a value <= 0 if banded rendering is disabled + */ + public int getThresholdForBandedImageRendering() { + return thresholdForBandedImageRendering; + } + + /** + * Is the color converting op switched on or off? + * @return - the usage of this color convert op + */ + public boolean isAvoidColorConvertOp() { + return avoidColorConvertOp; + } + + /** + * Set this to false to switch off the + * use of this color convert op which may segfault on some platforms + * due to a variety of problems related to thread safety and + * the native cmm library underlying this conversion op, e.g., + * https://forums.oracle.com/forums/thread.jspa?threadID=1261882&;tstart=225&messageID=5356357 + * (Unix platforms seem the most affected) + * + * If the system is bug-free, though, this does make use + * of native libraries and sees a not insignificant speed-up, + * though it's still not exactly fast. If we don't run this op + * now, it's performed at some later stage, but without using + * the native code + * @param avoidColorConvertOp + */ + public void setAvoidColorConvertOp(boolean avoidColorConvertOp) { + this.avoidColorConvertOp = avoidColorConvertOp; + } + + /** + * Use blur before image resize to enhance the result (Antialias)? + * @return the useBlurResizingForImages + */ + public boolean isUseBlurResizingForImages() { + return useBlurResizingForImages; + } + + /** + * Use blur before image resize to enhance the result (Antialias) + * + * @param useBlurResizingForImages + */ + public void setUseBlurResizingForImages(boolean useBlurResizingForImages) { + this.useBlurResizingForImages = useBlurResizingForImages; + } + + /** + * Print signature fields on pdf + * + * @param printSignatureField + */ + public void setPrintSignatureFields(boolean printSignatureFields) { + this.printSigantureFields = printSignatureFields; + } + + /** + * @return true if signature fields will be printed on pdf + */ + public boolean isPrintSignatureFields() { + return this.printSigantureFields; + } + + /** + * Print stamp annotations on pdf + * + * @param printStampAnnotation + */ + public void setPrintStampAnnotations(boolean printStampAnnotations) { + this.printStampAnnotations = printStampAnnotations; + } + + /** + * @return true if stamp annotations will be printed on pdf + */ + public boolean isPrintStampAnnotations() { + return this.printStampAnnotations; + } + + /** + * Print widget annotations on pdf + * + * @param printWidgetAnnotations + */ + public void setPrintWidgetAnnotations(boolean printWidgetAnnotations) { + this.printWidgetAnnotations = printWidgetAnnotations; + } + + /** + * @return true if widget annotations will be printed on pdf + */ + public boolean isPrintWidgetAnnotations() { + return this.printWidgetAnnotations; + } + + /** + * Print freetext annotations on pdf + * + * @param printFreetextAnnotations + */ + public void setPrintFreetextAnnotations(boolean printFreetextAnnotations) { + this.printFreetextAnnotations = printFreetextAnnotations; + } + + /** + * @return true if freetext annotations will be printed on pdf + */ + public boolean isPrintFreetextAnnotations() { + return this.printFreetextAnnotations; + } + + /** + * Print link annotations on pdf + * + * @param printLinkAnnotations + */ + public void setPrintLinkAnnotations(boolean printLinkAnnotations) { + this.printLinkAnnotations = printLinkAnnotations; + } + + /** + * @return true if link annotations will be printed on pdf + */ + public boolean isPrintLinkAnnotations() { + return this.printLinkAnnotations; + } +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/HexDump.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/HexDump.java new file mode 100644 index 000000000..5421d78b4 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/HexDump.java @@ -0,0 +1,84 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.sun.pdfview; + +import java.io.IOException; +import java.io.RandomAccessFile; + +public class HexDump { + + public static void printData(byte[] data) { + char[] parts = new char[17]; + int partsloc = 0; + for (int i = 0; i < data.length; i++) { + int d = (data[i]) & 0xff; + if (d == 0) { + parts[partsloc++] = '.'; + } else if (d < 32 || d >= 127) { + parts[partsloc++] = '?'; + } else { + parts[partsloc++] = (char) d; + } + if (i % 16 == 0) { + int start = Integer.toHexString(data.length).length(); + int end = Integer.toHexString(i).length(); + + for (int j = start; j > end; j--) { + System.out.print("0"); + } + System.out.print(Integer.toHexString(i) + ": "); + } + if (d < 16) { + System.out.print("0" + Integer.toHexString(d)); + } else { + System.out.print(Integer.toHexString(d)); + } + if ((i & 15) == 15 || i == data.length - 1) { + System.out.println(" " + new String(parts)); + partsloc = 0; + } else if ((i & 7) == 7) { + System.out.print(" "); + parts[partsloc++] = ' '; + } else if ((i & 1) == 1) { + System.out.print(" "); + } + } + System.out.println(); + } + + public static void main(String args[]) { + if (args.length != 1) { + System.out.println("Usage: "); + System.out.println(" HexDump "); + System.exit(-1); + } + + try { + RandomAccessFile raf = new RandomAccessFile(args[0], "r"); + + int size = (int) raf.length(); + byte[] data = new byte[size]; + + raf.readFully(data); + printData(data); + } catch (IOException ioe) { + BaseWatchable.getErrorHandler().publishException(ioe); + } + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/Identity8BitCharsetEncoder.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/Identity8BitCharsetEncoder.java new file mode 100644 index 000000000..75cfef220 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/Identity8BitCharsetEncoder.java @@ -0,0 +1,61 @@ +/* + * Copyright 2008 Pirion Systems Pty Ltd, 139 Warry St, + * Fortitude Valley, Queensland, Australia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package com.sun.pdfview; + +import java.nio.charset.CharsetEncoder; +import java.nio.charset.CoderResult; +import java.nio.CharBuffer; +import java.nio.ByteBuffer; + +/** + * A {@link CharsetEncoder} that attempts to write out the lower 8 bits + * of any character. Characters >= 256 in value are regarded + * as unmappable. + * + * @author Luke Kirby + */ +public class Identity8BitCharsetEncoder extends CharsetEncoder { + + public Identity8BitCharsetEncoder() { + super(null, 1, 1); + } + + @Override + protected CoderResult encodeLoop(CharBuffer in, ByteBuffer out) { + while (in.remaining() > 0) { + if (out.remaining() < 1) { + return CoderResult.OVERFLOW; + } + final char c = in.get(); + if (c >= 0 && c < 256) { + out.put((byte) c); + } else { + return CoderResult.unmappableForLength(1); + } + } + return CoderResult.UNDERFLOW; + } + + @Override + public boolean isLegalReplacement(byte[] repl) { + // avoid referencing the non-existent character set + return true; + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/ImageInfo.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/ImageInfo.java new file mode 100644 index 000000000..a17bdd4ac --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/ImageInfo.java @@ -0,0 +1,74 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.sun.pdfview; + +import java.awt.geom.Rectangle2D; +import java.awt.Color; + +public class ImageInfo { + + int width; + int height; + Rectangle2D clip; + Color bgColor; + + public ImageInfo(int width, int height, Rectangle2D clip) { + this(width, height, clip, Color.WHITE); + } + + public ImageInfo(int width, int height, Rectangle2D clip, Color bgColor) { + this.width = width; + this.height = height; + this.clip = clip; + this.bgColor = bgColor; + } + + // a hashcode that uses width, height and clip to generate its number + @Override + public int hashCode() { + int code = (this.width ^ this.height << 16); + + if (this.clip != null) { + code ^= ((int) this.clip.getWidth() | (int) this.clip.getHeight()) << 8; + code ^= ((int) this.clip.getMinX() | (int) this.clip.getMinY()); + } + + return code; + } + + // an equals method that compares values + @Override + public boolean equals(Object o) { + if (!(o instanceof ImageInfo)) { + return false; + } + + ImageInfo ii = (ImageInfo) o; + + if (this.width != ii.width || this.height != ii.height) { + return false; + } else if (this.clip != null && ii.clip != null) { + return this.clip.equals(ii.clip); + } else if (this.clip == null && ii.clip == null) { + return true; + } else { + return false; + } + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/NameTree.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/NameTree.java new file mode 100644 index 000000000..8b41a2606 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/NameTree.java @@ -0,0 +1,131 @@ +/* + * $Id: NameTree.java,v 1.3 2009/01/16 16:26:09 tomoke Exp $ + * + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.sun.pdfview; + +import java.io.IOException; + +/** + * A PDF name tree consists of three kinds of nodes: + *
    + *
  • The root node contains only a kids entry, pointing to many + * other objects + *
  • An intermediate node contains the limits of all the children in + * its subtree, and a kids entry for each child + *
  • A leaf node contains a set of name-to-object mappings in a dictionary, + * as well as the limits of the data contained in that child. + *
+ * A PDF name tree is sorted in accordance with the String.compareTo() method. + */ +public class NameTree { + + /** the root object */ + private PDFObject root; + + /** Creates a new instance of NameTree */ + public NameTree(PDFObject root) { + this.root = root; + } + + /** + * Find the PDF object corresponding to the given String in a name tree + * + * @param key the key we are looking for in the name tree + * @return the object associated with str, if found, or null if not + */ + public PDFObject find(String key) throws IOException { + return find(root, key); + } + + /** + * Recursively walk the name tree looking for a given value + */ + private PDFObject find(PDFObject root, String key) + throws IOException { + // first, look for a Names entry, meaning this is a leaf + PDFObject names = root.getDictRef("Names"); + if (names != null) { + return findInArray(names.getArray(), key); + } + + // no names given, look for kids + PDFObject kidsObj = root.getDictRef("Kids"); + if (kidsObj != null) { + PDFObject[] kids = kidsObj.getArray(); + + for (int i = 0; i < kids.length; i++) { + // find the limits of this kid + PDFObject limitsObj = kids[i].getDictRef("Limits"); + if (limitsObj != null) { + String lowerLimit = limitsObj.getAt(0).getStringValue(); + String upperLimit = limitsObj.getAt(1).getStringValue(); + + // are we in range? + if ((key.compareTo(lowerLimit) >= 0) && + (key.compareTo(upperLimit) <= 0)) { + + // we are, so find in this child + return find(kids[i], key); + } + } + } + } + + // no luck + return null; + } + + /** + * Find an object in a (key,value) array. Do this by splitting in half + * repeatedly. + */ + private PDFObject findInArray(PDFObject[] array, String key) + throws IOException { + int start = 0; + int end = array.length / 2; + + while (end >= start && start >= 0 && end < array.length) { + // find the key at the midpoint + int pos = start + ((end - start) / 2); + String posKey = array[pos * 2].getStringValue(); + + // compare the key to the key we are looking for + int comp = key.compareTo(posKey); + if (comp == 0) { + // they match. Return the value + int tmp = (pos * 2) + 1; + if(array.length>tmp){ + return array[tmp]; + }else { + return null; + } + } else if (comp > 0) { + // too big, search the top half of the tree + start = pos + 1; + } else if (comp < 0) { + // too small, search the bottom half of the tree + end = pos - 1; + } + } + + // not found + return null; + } +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/OutlineNode.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/OutlineNode.java new file mode 100644 index 000000000..977527cac --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/OutlineNode.java @@ -0,0 +1,60 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.sun.pdfview; + +import javax.swing.tree.DefaultMutableTreeNode; + +import com.sun.pdfview.action.PDFAction; + +public class OutlineNode extends DefaultMutableTreeNode { + // the name of this node + + private String title; + + /** + * Create a new outline node + * + * @param title the node's visible name in the tree + */ + public OutlineNode(String title) { + this.title = title; + } + + /** + * Get the PDF action associated with this node + */ + public PDFAction getAction() { + return (PDFAction) getUserObject(); + } + + /** + * Set the PDF action associated with this node + */ + public void setAction(PDFAction action) { + setUserObject(action); + } + + /** + * Return the node's visible name in the tree + */ + @Override + public String toString() { + return this.title; + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFCmd.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFCmd.java new file mode 100644 index 000000000..3cb0f82ea --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFCmd.java @@ -0,0 +1,59 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.sun.pdfview; + +import java.awt.geom.Rectangle2D; + +/** + * The abstract superclass of all drawing commands for a PDFPage. + * @author Mike Wessler + */ +public abstract class PDFCmd { + + /** + * mark the page or change the graphics state + * @param state the current graphics state; may be modified during + * execution. + * @return the region of the page made dirty by executing this command + * or null if no region was touched. Note this value should be + * in the coordinates of the image touched, not the page. + */ + public abstract Rectangle2D execute(PDFRenderer state); + + /** + * a human readable representation of this command + */ + @Override + public String toString() { + String name = getClass().getName(); + int lastDot = name.lastIndexOf('.'); + if (lastDot >= 0) { + return name.substring(lastDot + 1); + } else { + return name; + } + } + + /** + * the details of this command + */ + public String getDetails() { + return super.toString(); + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFDebugger.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFDebugger.java new file mode 100644 index 000000000..92e23c2e0 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFDebugger.java @@ -0,0 +1,136 @@ +package com.sun.pdfview; + +import java.awt.Rectangle; +import java.awt.geom.GeneralPath; +import java.awt.geom.Point2D; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.HashMap; + +import javax.imageio.ImageIO; + +public class PDFDebugger { + public final static String DEBUG_DCTDECODE_DATA = "debugdctdecode"; + public static final boolean DEBUG_TEXT = false; + public static final boolean DEBUG_IMAGES = false; + public static final boolean DEBUG_OPERATORS = false; + public static final boolean DEBUG_PATH = false; + public static final int DEBUG_STOP_AT_INDEX = 0; + public static final boolean DISABLE_TEXT = false; + public static final boolean DISABLE_IMAGES = false; + public static final boolean DISABLE_PATH_STROKE = false; + public static final boolean DISABLE_PATH_FILL = false; + public static final boolean DISABLE_PATH_STROKE_FILL = false; + public static final boolean DISABLE_CLIP = false; + public static final boolean DISABLE_FORMS = false; + public static final boolean DISABLE_SHADER = false; + public static final boolean SHOW_TEXT_REGIONS = false; + public static final boolean SHOW_TEXT_ANCHOR = false; + public static final boolean DISABLE_THUMBNAILS = false; + public static final long DRAW_DELAY = 0; + + public static int debuglevel = 4000; + + @SuppressWarnings("serial") + public static class DebugStopException extends Exception { + // nothing to do + } + + public static void debugImage(BufferedImage image, String name) { + if (PDFDebugger.DEBUG_IMAGES) { + if(image == null) { + return; + } + try { + // retrieve image + File outputfile = new File("D:/tmp/PDFimages/" + name + ".png"); + ImageIO.write(image, "png", outputfile); + } catch (IOException e) { + BaseWatchable.getErrorHandler().publishException(e); + } + } + } + + // TODO: add debug level and print it? + public static void debug(String msg, int level) { + if (level > debuglevel) { + System.out.println(escape(msg)); + } + } + + // TODO: add debug level and print it? + public static void debug(String msg) { + debug(msg, debuglevel); + } + + public static String escape(String msg) { + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < msg.length(); i++) { + char c = msg.charAt(i); + if (c != '\n' && (c < 32 || c >= 127)) { + c = '?'; + } + sb.append(c); + } + return sb.toString(); + } + + public static void setDebugLevel(int level) { + debuglevel = level; + } + + + public static String dumpStream(byte[] stream) { + return PDFDebugger.escape(new String(stream).replace('\r', '\n')); + } + + public static void logPath(GeneralPath path, String operation) { + if (PDFDebugger.DEBUG_PATH){ + if (operation != null) { + System.out.println("Operation: " + operation + "; "); + } + System.out.println("Current path: "); + Rectangle b = path.getBounds(); + if (b != null) + System.out.println(" Bounds [x=" + b.x + ",y=" + b.y + ",width=" + b.width + ",height=" + b.height + "]"); + Point2D p = path.getCurrentPoint(); + if (p != null) + System.out.println(" Point [x=" + p.getX() + ",y=" + p.getY() + "]"); + } + } + + /** + * take a byte array and write a temporary file with it's data. + * This is intended to capture data for analysis, like after decoders. + * + * @param ary + * @param name + */ + public static void emitDataFile(byte[] ary, String name) { + FileOutputStream ostr; + try { + File file = File.createTempFile("DateFile", name); + ostr = new FileOutputStream(file); + PDFDebugger.debug("Write: " + file.getPath()); + ostr.write(ary); + ostr.close(); + } catch (IOException ex) { + // ignore + } + } + + public static void dump(PDFObject obj) throws IOException { + PDFDebugger.debug("dumping PDF object: " + obj); + if (obj == null) { + return; + } + HashMap dict = obj.getDictionary(); + PDFDebugger.debug(" dict = " + dict); + for (Object key : dict.keySet()) { + PDFDebugger.debug("key = " + key + " value = " + dict.get(key)); + } + } + +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFDestination.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFDestination.java new file mode 100644 index 000000000..18a5a2136 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFDestination.java @@ -0,0 +1,299 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.sun.pdfview; + +import java.io.IOException; + +/** + * Represents a destination in a PDF file. Destinations take 3 forms: + *
    + *
  • An explicit destination, which contains a reference to a page as well as + * some stuff about how to fit it into the window. + *
  • A named destination, which uses the PDF file's Dests entry in the + * document catalog to map a name to an explicit destination + *
  • A string destintation, which uses the PDF file's Dests entry. in the name + * directory to map a string to an explicit destination. + *
+ * + * All three of these cases are handled by the getDestination() method. + */ +public class PDFDestination { + + /** The known types of destination */ + public static final int XYZ = 0; + public static final int FIT = 1; + public static final int FITH = 2; + public static final int FITV = 3; + public static final int FITR = 4; + public static final int FITB = 5; + public static final int FITBH = 6; + public static final int FITBV = 7; + /** the type of this destination (from the list above) */ + private int type; + /** the page we refer to */ + private PDFObject pageObj; + /** the left coordinate of the fit area, if applicable */ + private float left; + /** the right coordinate of the fit area, if applicable */ + private float right; + /** the top coordinate of the fit area, if applicable */ + private float top; + /** the bottom coordinate of the fit area, if applicable */ + private float bottom; + /** the zoom, if applicable */ + private float zoom; + + /** + * Creates a new instance of PDFDestination + * + * @param pageObj + * the page object this destination refers to + * @param type + * the type of page this object refers to + */ + protected PDFDestination(PDFObject pageObj, int type) { + this.pageObj = pageObj; + this.type = type; + } + + /** + * Get a destination from either an array (explicit destination), a name + * (named destination) or a string (name tree destination). + * + * @param obj + * the PDFObject representing this destination + * @param root + * the root of the PDF object tree + */ + public static PDFDestination getDestination(PDFObject obj, PDFObject root) throws IOException { + // resolve string and name issues + if (obj.getType() == PDFObject.NAME) { + obj = getDestFromName(obj, root); + } else if (obj.getType() == PDFObject.STRING) { + obj = getDestFromString(obj, root); + } + + // make sure we have the right kind of object + if (obj == null || obj.getType() != PDFObject.ARRAY) { + throw new PDFParseException("Can't create destination from: " + obj); + } + + // the array is in the form [page type args ... ] + PDFObject[] destArray = obj.getArray(); + + // create the destination based on the type + PDFDestination dest = null; + String type = destArray[1].getStringValue(); + if (type.equals("XYZ")) { + dest = new PDFDestination(destArray[0], XYZ); + } else if (type.equals("Fit")) { + dest = new PDFDestination(destArray[0], FIT); + } else if (type.equals("FitH")) { + dest = new PDFDestination(destArray[0], FITH); + } else if (type.equals("FitV")) { + dest = new PDFDestination(destArray[0], FITV); + } else if (type.equals("FitR")) { + dest = new PDFDestination(destArray[0], FITR); + } else if (type.equals("FitB")) { + dest = new PDFDestination(destArray[0], FITB); + } else if (type.equals("FitBH")) { + dest = new PDFDestination(destArray[0], FITBH); + } else if (type.equals("FitBV")) { + dest = new PDFDestination(destArray[0], FITBV); + } else { + throw new PDFParseException("Unknown destination type: " + type); + } + + // now fill in the arguments based on the type + switch (dest.getType()) { + case XYZ: + dest.setLeft(destArray[2].getFloatValue()); + dest.setTop(destArray[3].getFloatValue()); + dest.setZoom(destArray[4].getFloatValue()); + break; + case FITH: + if (destArray.length > 2) { + dest.setTop(destArray[2].getFloatValue()); + } else { + dest.setTop(0.0F); + } + break; + case FITV: + if (destArray.length > 2) { + dest.setTop(destArray[2].getFloatValue()); + } else { + dest.setTop(0.0F); + } + break; + case FITR: + dest.setLeft(destArray[2].getFloatValue()); + dest.setBottom(destArray[3].getFloatValue()); + dest.setRight(destArray[4].getFloatValue()); + dest.setTop(destArray[5].getFloatValue()); + break; + case FITBH: + if (destArray.length > 2) { + dest.setTop(destArray[2].getFloatValue()); + } else { + dest.setTop(0.0F); + } + break; + case FITBV: + if (destArray.length > 2) { + dest.setTop(destArray[2].getFloatValue()); + } else { + dest.setTop(0.0F); + } + break; + } + + return dest; + } + + /** + * Get the type of this destination + */ + public int getType() { + return this.type; + } + + /** + * Get the PDF Page object associated with this destination + */ + public PDFObject getPage() { + return this.pageObj; + } + + /** + * Get the left coordinate value + */ + public float getLeft() { + return this.left; + } + + /** + * Set the left coordinate value + */ + public void setLeft(float left) { + this.left = left; + } + + /** + * Get the right coordinate value + */ + public float getRight() { + return this.right; + } + + /** + * Set the right coordinate value + */ + public void setRight(float right) { + this.right = right; + } + + /** + * Get the top coordinate value + */ + public float getTop() { + return this.top; + } + + /** + * Set the top coordinate value + */ + public void setTop(float top) { + this.top = top; + } + + /** + * Get the bottom coordinate value + */ + public float getBottom() { + return this.bottom; + } + + /** + * Set the bottom coordinate value + */ + public void setBottom(float bottom) { + this.bottom = bottom; + } + + /** + * Get the zoom value + */ + public float getZoom() { + return this.zoom; + } + + /** + * Set the zoom value + */ + public void setZoom(float zoom) { + this.zoom = zoom; + } + + /** + * Get a destination, given a name. This means the destination is in the + * root node's dests dictionary. + */ + private static PDFObject getDestFromName(PDFObject name, PDFObject root) throws IOException { + // find the dests object in the root node + PDFObject dests = root.getDictRef("Dests"); + if (dests != null) { + // find this name in the dests dictionary + return dests.getDictRef(name.getStringValue()); + } + + // not found + return null; + } + + /** + * Get a destination, given a string. This means the destination is in the + * root node's names dictionary. + */ + private static PDFObject getDestFromString(PDFObject str, PDFObject root) throws IOException { + // find the names object in the root node + PDFObject names = root.getDictRef("Names"); + if (names != null) { + // find the dests entry in the names dictionary + PDFObject dests = names.getDictRef("Dests"); + if (dests != null) { + // create a name tree object + NameTree tree = new NameTree(dests); + + // find the value we're looking for + PDFObject obj = tree.find(str.getStringValue()); + + // if we get back a dictionary, look for the /D value + if (obj != null && obj.getType() == PDFObject.DICTIONARY) { + obj = obj.getDictRef("D"); + } + + // found it + return obj; + } + } + + // not found + return null; + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFDocCharsetEncoder.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFDocCharsetEncoder.java new file mode 100644 index 000000000..03a3b186d --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFDocCharsetEncoder.java @@ -0,0 +1,106 @@ +/* Copyright 2008 Pirion Systems Pty Ltd, 139 Warry St, + * Fortitude Valley, Queensland, Australia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package com.sun.pdfview; + +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.CharsetEncoder; +import java.nio.charset.CoderResult; +import java.util.HashMap; +import java.util.Map; + +/** + * Encodes into a PDFDocEncoding representation. Note that only 256 characters + * (if that) are represented in the PDFDocEncoding, so users should be + * prepared to deal with unmappable character exceptions. + * + * @see "PDF Reference version 1.7, Appendix D" + * + * @author Luke Kirby + */ +public class PDFDocCharsetEncoder extends CharsetEncoder { + + /** + * Identify whether a particular character preserves the same byte value + * upon encoding in PDFDocEncoding + * @param ch the character + * @return whether the character is identity encoded + */ + public static boolean isIdentityEncoding(char ch) { + return ch >= 0 && ch <= 255 && IDENT_PDF_DOC_ENCODING_MAP[ch]; + + } + + /** + * For each character that exists in PDFDocEncoding, identifies whether + * the byte value in UTF-16BE is the same as it is in PDFDocEncoding + */ + final static boolean[] IDENT_PDF_DOC_ENCODING_MAP = new boolean[256]; + + /** + * For non-identity encoded characters, maps from the character to + * the byte value in PDFDocEncoding. If an entry for a non-identity + * coded character is absent from this map, that character is unmappable + * in the PDFDocEncoding. + */ + final static Map EXTENDED_TO_PDF_DOC_ENCODING_MAP = + new HashMap(); + static + { + for (byte i = 0; i < PDFStringUtil.PDF_DOC_ENCODING_MAP.length; ++i) { + final char c = PDFStringUtil.PDF_DOC_ENCODING_MAP[i]; + final boolean identical = (c == i); + IDENT_PDF_DOC_ENCODING_MAP[i] = identical; + if (!identical) { + EXTENDED_TO_PDF_DOC_ENCODING_MAP.put(c, i); + } + } + } + + public PDFDocCharsetEncoder() { + super(null, 1, 1); + } + + @Override + protected CoderResult encodeLoop(CharBuffer in, ByteBuffer out) { + while (in.remaining() > 0) { + if (out.remaining() < 1) { + return CoderResult.OVERFLOW; + } + final char c = in.get(); + if (c >= 0 && c < 256 && IDENT_PDF_DOC_ENCODING_MAP[c]) { + out.put((byte) c); + } else { + final Byte mapped = EXTENDED_TO_PDF_DOC_ENCODING_MAP.get(c); + if (mapped != null) { + out.put(mapped); + } else { + return CoderResult.unmappableForLength(1); + } + } + } + return CoderResult.UNDERFLOW; + } + + @Override + public boolean isLegalReplacement(byte[] repl) { + // avoid referencing the non-existent character set + return true; + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFErrorHandler.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFErrorHandler.java new file mode 100644 index 000000000..64a10a246 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFErrorHandler.java @@ -0,0 +1,14 @@ +package com.sun.pdfview; + +/** + * Simple class to handle exceptions - as default we just print the stack trace + * but it's possible to inject another behaviour + * @author xond + * + */ +public class PDFErrorHandler { + + public void publishException(Throwable e){ + e.printStackTrace(); + } +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFFile.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFFile.java new file mode 100644 index 000000000..27cd2d8da --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFFile.java @@ -0,0 +1,1875 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.sun.pdfview; + +import java.awt.geom.Rectangle2D; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.StringTokenizer; + +import com.sun.pdfview.action.GoToAction; +import com.sun.pdfview.action.PDFAction; +import com.sun.pdfview.annotation.PDFAnnotation; +import com.sun.pdfview.decrypt.EncryptionUnsupportedByPlatformException; +import com.sun.pdfview.decrypt.EncryptionUnsupportedByProductException; +import com.sun.pdfview.decrypt.IdentityDecrypter; +import com.sun.pdfview.decrypt.PDFAuthenticationFailureException; +import com.sun.pdfview.decrypt.PDFDecrypter; +import com.sun.pdfview.decrypt.PDFDecrypterFactory; +import com.sun.pdfview.decrypt.PDFPassword; +import com.sun.pdfview.decrypt.UnsupportedEncryptionException; + +/** + * An encapsulation of a .pdf file. The methods of this class + * can parse the contents of a PDF file, but those methods are + * hidden. Instead, the public methods of this class allow + * access to the pages in the PDF file. Typically, you create + * a new PDFFile, ask it for the number of pages, and then + * request one or more PDFPages. + * @author Mike Wessler + */ +public class PDFFile { + + public final static int NUL_CHAR = 0; + public final static int FF_CHAR = 12; + + private String versionString = "1.1"; + private int majorVersion = 1; + private int minorVersion = 1; + /** the end of line character */ + /** the comment text to begin the file to determine it's version */ + private final static String VERSION_COMMENT = "%PDF-"; + /** + * A ByteBuffer containing the file data + */ + ByteBuffer buf; + /** + * the cross reference table mapping object numbers to locations + * in the PDF file + */ + PDFXref[] objIdx; + /** the root PDFObject, as specified in the PDF file */ + PDFObject root = null; + /** the Encrypt PDFObject, from the trailer */ + PDFObject encrypt = null; + + /** The Info PDFPbject, from the trailer, for simple metadata */ + PDFObject info = null; + + /** a mapping of page numbers to parsed PDF commands */ + Cache cache; + /** + * whether the file is printable or not (trailer -> Encrypt -> P & 0x4) + */ + private boolean printable = true; + /** + * whether the file is saveable or not (trailer -> Encrypt -> P & 0x10) + */ + private boolean saveable = true; + + /** + * The default decrypter for streams and strings. By default, no + * encryption is expected, and thus the IdentityDecrypter is used. + */ + private PDFDecrypter defaultDecrypter = IdentityDecrypter.getInstance(); + + /** + * get a PDFFile from a .pdf file. The file must me a random access file + * at the moment. It should really be a file mapping from the nio package. + *

+ * Use the getPage(...) methods to get a page from the PDF file. + * @param buf the RandomAccessFile containing the PDF. + * @throws IOException if there's a problem reading from the buffer + * @throws PDFParseException if the document appears to be malformed, or + * its features are unsupported. If the file is encrypted in a manner that + * the product or platform does not support then the exception's {@link + * PDFParseException#getCause() cause} will be an instance of {@link + * UnsupportedEncryptionException}. + * @throws PDFAuthenticationFailureException if the file is password + * protected and requires a password + */ + public PDFFile(ByteBuffer buf) throws IOException { + this(buf, null); + } + + public PDFFile(ByteBuffer buf, boolean doNotParse) throws IOException { + this.buf = buf; + } + + /** + * get a PDFFile from a .pdf file. The file must me a random access file + * at the moment. It should really be a file mapping from the nio package. + *

+ * Use the getPage(...) methods to get a page from the PDF file. + * @param buf the RandomAccessFile containing the PDF. + * @param password the user or owner password + * @throws IOException if there's a problem reading from the buffer + * @throws PDFParseException if the document appears to be malformed, or + * its features are unsupported. If the file is encrypted in a manner that + * the product or platform does not support then the exception's {@link + * PDFParseException#getCause() cause} will be an instance of {@link + * UnsupportedEncryptionException}. + * @throws PDFAuthenticationFailureException if the file is password + * protected and the supplied password does not decrypt the document + */ + public PDFFile(ByteBuffer buf, PDFPassword password) throws IOException { + this.buf = buf; + + this.cache = new Cache(); + + parseFile(password); + } + + /** + * Gets whether the owner of the file has given permission to print + * the file. + * @return true if it is okay to print the file + */ + public boolean isPrintable() { + return this.printable; + } + + /** + * Gets whether the owner of the file has given permission to save + * a copy of the file. + * @return true if it is okay to save the file + */ + public boolean isSaveable() { + return this.saveable; + } + + /** + * get the root PDFObject of this PDFFile. You generally shouldn't need + * this, but we've left it open in case you want to go spelunking. + */ + public PDFObject getRoot() { + return this.root; + } + + /** + * return the number of pages in this PDFFile. The pages will be + * numbered from 1 to getNumPages(), inclusive. + */ + public int getNumPages() { + try { + return this.root.getDictRef("Pages").getDictRef("Count").getIntValue(); + } catch (Exception ioe) { + return 0; + } + } + + /** + * Get metadata (e.g., Author, Title, Creator) from the Info dictionary + * as a string. + * @param name the name of the metadata key (e.g., Author) + * @return the info + * @throws IOException if the metadata cannot be read + */ + public String getStringMetadata(String name) + throws IOException { + if (this.info != null) { + final PDFObject meta = this.info.getDictRef(name); + return meta != null ? meta.getTextStringValue() : null; + } else { + return null; + } + } + + /** + * Get the keys into the Info metadata, for use with + * {@link #getStringMetadata(String)} + * @return the keys present into the Info dictionary + * @throws IOException if the keys cannot be read + */ + public Iterator getMetadataKeys() + throws IOException { + if (this.info != null) { + return this.info.getDictKeys(); + } else { + return Collections.emptyList().iterator(); + } + } + + + /** + * Used internally to track down PDFObject references. You should never + * need to call this. + *

+ * Since this is the only public method for tracking down PDF objects, + * it is synchronized. This means that the PDFFile can only hunt down + * one object at a time, preventing the file's location from getting + * messed around. + *

+ * This call stores the current buffer position before any changes are made + * and restores it afterwards, so callers need not know that the position + * has changed. + * + */ + public synchronized PDFObject dereference(PDFXref ref, PDFDecrypter decrypter) + throws IOException { + int id = ref.getID(); + + // make sure the id is valid and has been read + if (id >= this.objIdx.length || this.objIdx[id] == null) { + return PDFObject.nullObj; + } + + // check to see if this is already dereferenced + PDFObject obj = this.objIdx[id].getObject(); + if (obj != null) { + return obj; + } + + // store the current position in the buffer + int startPos = this.buf.position(); + + boolean compressed = this.objIdx[id].getCompressed(); + if (!compressed) { + int loc = this.objIdx[id].getFilePos(); + if (loc < 0) { + return PDFObject.nullObj; + } + + // move to where this object is + this.buf.position(loc); + + // read the object and cache the reference + obj= readObject(ref.getID(), ref.getGeneration(), decrypter); + } + else { // compressed + int compId = this.objIdx[id].getID(); + int idx = this.objIdx[id].getIndex(); + if (idx < 0) + return PDFObject.nullObj; + PDFXref compRef = new PDFXref(compId, 0); + PDFObject compObj = dereference(compRef, decrypter); + int first = compObj.getDictionary().get("First").getIntValue(); + int length = compObj.getDictionary().get("Length").getIntValue(); + int n = compObj.getDictionary().get("N").getIntValue(); + if (idx >= n) + return PDFObject.nullObj; + ByteBuffer strm = compObj.getStreamBuffer(); + + ByteBuffer oldBuf = this.buf; + this.buf = strm; + // skip other nums + for (int i=0; i + * + * ISO 32000-1:2008 - Table 2 + * + * @param c the character to test + */ + public static boolean isDelimiter(int c) { + switch (c) { + case '(': // LEFT PARENTHESIS + case ')': // RIGHT PARENTHESIS + case '<': // LESS-THAN-SIGN + case '>': // GREATER-THAN-SIGN + case '[': // LEFT SQUARE BRACKET + case ']': // RIGHT SQUARE BRACKET + case '{': // LEFT CURLY BRACKET + case '}': // RIGHT CURLY BRACKET + case '/': // SOLIDUS + case '%': // PERCENT SIGN + return true; + default: + return false; + } + } + + /** + * return true if the character is neither a whitespace or a delimiter. + * + * @param c the character to test + * @return boolean + */ + public static boolean isRegularCharacter (int c) { + return !(isWhiteSpace(c) || isDelimiter(c)); + } + + /** + * read the next object from the file + * @param objNum the object number of the object containing the object + * being read; negative only if the object number is unavailable (e.g., if + * reading from the trailer, or reading at the top level, in which + * case we can expect to be reading an object description) + * @param objGen the object generation of the object containing the object + * being read; negative only if the objNum is unavailable + * @param decrypter the decrypter to use + */ + private PDFObject readObject( + int objNum, int objGen, PDFDecrypter decrypter) throws IOException { + return readObject(objNum, objGen, false, decrypter); + } + + /** + * read the next object with a special catch for numbers + * @param numscan if true, don't bother trying to see if a number is + * an object reference (used when already in the middle of testing for + * an object reference, and not otherwise) + * @param objNum the object number of the object containing the object + * being read; negative only if the object number is unavailable (e.g., if + * reading from the trailer, or reading at the top level, in which + * case we can expect to be reading an object description) + * @param objGen the object generation of the object containing the object + * being read; negative only if the objNum is unavailable + * @param decrypter the decrypter to use + */ + private PDFObject readObject( + int objNum, int objGen, + boolean numscan, PDFDecrypter decrypter) throws IOException { + // skip whitespace + int c; + PDFObject obj = null; + while (obj == null && this.buf.hasRemaining()) { + while (isWhiteSpace(c = this.buf.get())) { + if(!buf.hasRemaining()) { + break; + } + } + // check character for special punctuation: + if (c == '<') { + // could be start of , or start of <> + c = this.buf.get(); + if (c == '<') { + // it's a dictionary + obj= readDictionary(objNum, objGen, decrypter); + } else { + this.buf.position(this.buf.position() - 1); + obj= readHexString(objNum, objGen, decrypter); + } + } else if (c == '(') { + obj= readLiteralString(objNum, objGen, decrypter); + } else if (c == '[') { + // it's an array + obj= readArray(objNum, objGen, decrypter); + } else if (c == '/') { + // it's a name + obj = readName(); + } else if (c == '%') { + // it's a comment + readLine(); + } else if ((c >= '0' && c <= '9') || c == '-' || c == '+' || c == '.') { + // it's a number + obj = readNumber((char) c); + if (!numscan) { + // It could be the start of a reference. + // Check to see if there's another number, then "R". + // + // We can't use mark/reset, since this could be called + // from dereference, which already is using a mark + int startPos = this.buf.position(); + + PDFObject testnum= readObject(-1, -1, true, decrypter); + if (testnum != null && + testnum.getType() == PDFObject.NUMBER) { + PDFObject testR= readObject(-1, -1, true, decrypter); + if (testR != null && + testR.getType() == PDFObject.KEYWORD && + testR.getStringValue().equals("R")) { + // yup. it's a reference. + PDFXref xref = new PDFXref(obj.getIntValue(), + testnum.getIntValue()); + // Create a placeholder that will be dereferenced + // as needed + obj = new PDFObject(this, xref); + } else if (testR != null && + testR.getType() == PDFObject.KEYWORD && + testR.getStringValue().equals("obj")) { + // it's an object description + obj= readObjectDescription( + obj.getIntValue(), + testnum.getIntValue(), + decrypter); + } else { + this.buf.position(startPos); + } + } else { + this.buf.position(startPos); + } + } + } else if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) { + // it's a keyword + obj = readKeyword((char) c); + } else { + // it's probably a closing character. + // throwback + this.buf.position(this.buf.position() - 1); + break; + } + } + return obj; + } + + /** + * Get the next non-white space character + * @param buf the buffer to read from + * @return the next non-whitespace character + */ + private int nextNonWhitespaceChar(ByteBuffer buf) { + int c; + while (isWhiteSpace(c = buf.get())) { + // nothing + } + return c; + } + + /** + * Consume all sequential whitespace from the current buffer position, + * leaving the buffer positioned at non-whitespace + * @param buf the buffer to read from + */ + private void consumeWhitespace(ByteBuffer buf) { + nextNonWhitespaceChar(buf); + buf.position(buf.position() - 1); + } + + /** + * requires the next few characters (after whitespace) to match the + * argument. + * @param match the next few characters after any whitespace that + * must be in the file + * @return true if the next characters match; false otherwise. + */ + private boolean nextItemIs(String match) throws IOException { + // skip whitespace + int c = nextNonWhitespaceChar(buf); + for (int i = 0; i < match.length(); i++) { + if (i > 0) { + c = this.buf.get(); + } + if (c != match.charAt(i)) { + return false; + } + } + return true; + } + + /** + * process a version string, to determine the major and minor versions + * of the file. + * + * @param versionString + */ + private void processVersion(String versionString) { + try { + StringTokenizer tokens = new StringTokenizer(versionString, "."); + this.majorVersion = Integer.parseInt(tokens.nextToken()); + this.minorVersion = Integer.parseInt(tokens.nextToken()); + this.versionString = versionString; + } catch (Exception e) { + // ignore + } + } + + /** + * return the major version of the PDF header. + * + * @return int + */ + public int getMajorVersion() { + return this.majorVersion; + } + + /** + * return the minor version of the PDF header. + * + * @return int + */ + public int getMinorVersion() { + return this.minorVersion; + } + + /** + * return the version string from the PDF header. + * + * @return String + */ + public String getVersionString() { + return this.versionString; + } + + /** + * read an entire << dictionary >>. The initial + * << has already been read. + * @param objNum the object number of the object containing the dictionary + * being read; negative only if the object number is unavailable, which + * should only happen if we're reading a dictionary placed directly + * in the trailer + * @param objGen the object generation of the object containing the object + * being read; negative only if the objNum is unavailable + * @param decrypter the decrypter to use + * @return the Dictionary as a PDFObject. + */ + private PDFObject readDictionary( + int objNum, int objGen, PDFDecrypter decrypter) throws IOException { + HashMap hm = new HashMap(); + // we've already read the <<. Now get /Name obj pairs until >> + PDFObject name; + while ((name= readObject(objNum, objGen, decrypter))!=null) { + // make sure first item is a NAME + if (name.getType() != PDFObject.NAME) { + throw new PDFParseException("First item in dictionary must be a /Name. (Was " + name + ")"); + } + PDFObject value= readObject(objNum, objGen, decrypter); + if (value != null) { + hm.put(name.getStringValue(), value); + } + } + if (!nextItemIs(">>")) { + throw new PDFParseException("End of dictionary wasn't '>>'"); + } + return new PDFObject(this, PDFObject.DICTIONARY, hm); + } + + /** + * read a character, and return its value as if it were a hexidecimal + * digit. + * @return a number between 0 and 15 whose value matches the next + * hexidecimal character. Returns -1 if the next character isn't in + * [0-9a-fA-F] + */ + private int readHexDigit() throws IOException { + int a; + while (isWhiteSpace(a = this.buf.get())) { + } + switch (a) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + a -= '0'; + break; + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': + a -= 'a' - 10; + break; + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': + a -= 'A' - 10; + break; + default: + a = -1; + break; + } + return a; + } + + /** + * return the 8-bit value represented by the next two hex characters. + * If the next two characters don't represent a hex value, return -1 + * and reset the read head. If there is only one hex character, + * return its value as if there were an implicit 0 after it. + */ + private int readHexPair() throws IOException { + int first = readHexDigit(); + if (first < 0) { + this.buf.position(this.buf.position() - 1); + return -1; + } + int second = readHexDigit(); + if (second < 0) { + this.buf.position(this.buf.position() - 1); + return (first << 4); + } else { + return (first << 4) + second; + } + } + + /** + * read a < hex string >. The initial < has already been read. + * @param objNum the object number of the object containing the dictionary + * being read; negative only if the object number is unavailable, which + * should only happen if we're reading a string placed directly + * in the trailer + * @param objGen the object generation of the object containing the object + * being read; negative only if the objNum is unavailable + * @param decrypter the decrypter to use + */ + private PDFObject readHexString( + int objNum, int objGen, PDFDecrypter decrypter) throws IOException { + // we've already read the <. Now get the hex bytes until > + int val; + StringBuffer sb = new StringBuffer(); + while ((val = readHexPair()) >= 0) { + sb.append((char) val); + } + if (buf.hasRemaining() && this.buf.get() != '>') { + throw new PDFParseException("Bad character in Hex String"); + } + return new PDFObject(this, PDFObject.STRING, + decrypter.decryptString(objNum, objGen, sb.toString())); + } + + /** + *

read a ( character string ). The initial ( has already been read. + * Read until a *balanced* ) appears.

+ * + *

Section 3.2.3 of PDF Refernce version 1.7 defines the format of + * String objects. Regarding literal strings:

+ * + *
Within a literal string, the backslash (\) is used as an + * escape character for various purposes, such as to include newline + * characters, nonprinting ASCII characters, unbalanced parentheses, or + * the backslash character itself in the string. The character + * immediately following the backslash determines its precise + * interpretation (see Table 3.2). If the character following the + * backslash is not one of those shown in the table, the backslash + * is ignored.
+ * + * *

This only reads 8 bit basic character 'strings' so as to avoid a + * text string interpretation when one is not desired (e.g., for byte + * strings, as used by the decryption mechanism). For an interpretation of + * a string returned from this method, where the object type is defined + * as a 'text string' as per Section 3.8.1, Table 3.31 "PDF Data Types", + * {@link PDFStringUtil#asTextString} ()} or + * {@link PDFObject#getTextStringValue()} must be employed.

+ * + * @param objNum the object number of the object containing the dictionary + * being read; negative only if the object number is unavailable, which + * should only happen if we're reading a dictionary placed directly + * in the trailer + * @param objGen the object generation of the object containing the object + * being read; negative only if the objNum is unavailable + * @param decrypter the decrypter to use + */ + private PDFObject readLiteralString( + int objNum, int objGen, PDFDecrypter decrypter) throws IOException { + int c; + + // we've already read the (. now get the characters until a + // *balanced* ) appears. Translate \r \n \t \b \f \( \) \\ \ddd + // if a cr/lf follows a backslash, ignore the cr/lf + int parencount = 1; + StringBuffer sb = new StringBuffer(); + + while (buf.hasRemaining() && parencount > 0) { + c = this.buf.get() & 0xFF; + // process unescaped parenthesis + if (c == '(') { + parencount++; + } else if (c == ')') { + parencount--; + if (parencount == 0) { + c = -1; + break; + } + } else if (c == '\\') { + + // From the spec: + // Within a literal string, the backslash (\) is used as an + // escape character for various purposes, such as to include + // newline characters, nonprinting ASCII characters, + // unbalanced parentheses, or the backslash character itself + // in the string. The character immediately following the + // backslash determines its precise interpretation (see + // Table 3.2). If the character following the backslash is not + // one of those shown in the table, the backslash is ignored. + // + // summary of rules: + // + // \n \r \t \b \f 2-char sequences are used to represent their + // 1-char counterparts + // + // \( and \) are used to escape parenthesis + // + // \\ for a literal backslash + // + // \ddd (1-3 octal digits) for a character code + // + // \ is used to put formatting newlines into the + // file, but aren't actually part of the string; EOL may be + // CR, LF or CRLF + // + // any other sequence should see the backslash ignored + + // grab the next character to see what we're dealing with + c = this.buf.get() & 0xFF; + if (c >= '0' && c < '8') { + // \ddd form - one to three OCTAL digits + int count = 0; + int val = 0; + while (c >= '0' && c < '8' && count < 3) { + val = val * 8 + c - '0'; + c = this.buf.get() & 0xFF; + count++; + } + // we'll have read one character too many + this.buf.position(this.buf.position() - 1); + c = val; + } else if (c == 'n') { + c = '\n'; + } else if (c == 'r') { + c = '\r'; + } else if (c == 't') { + c = '\t'; + } else if (c == 'b') { + c = '\b'; + } else if (c == 'f') { + c = '\f'; + } else if (c == '\r') { + // escaped CR to be ignored; look for a following LF + c = this.buf.get() & 0xFF; + if (c != '\n') { + // not an LF, we'll consume this character on + // the next iteration + this.buf.position(this.buf.position() - 1); + } + c = -1; + } else if (c == '\n') { + // escaped LF to be ignored + c = -1; + } + // any other c should be used as is, as it's either + // one of ()\ in which case it should be used literally, + // or the backslash should just be ignored + } + if (c >= 0) { + sb.append((char) c); + } + } + return new PDFObject(this, PDFObject.STRING, + decrypter.decryptString(objNum, objGen, sb.toString())); + } + + /** + * Read a line of text. This follows the semantics of readLine() in + * DataInput -- it reads character by character until a '\n' is + * encountered. If a '\r' is encountered, it is discarded. + */ + private String readLine() { + StringBuffer sb = new StringBuffer(); + + while (this.buf.remaining() > 0) { + char c = (char) this.buf.get(); + + if (c == '\r') { + if (this.buf.remaining() > 0) { + char n = (char) this.buf.get(this.buf.position()); + if (n == '\n') { + this.buf.get(); + } + } + break; + } else if (c == '\n') { + break; + } + + sb.append(c); + } + + return sb.toString(); + } + + /** + * read an [ array ]. The initial [ has already been read. PDFObjects + * are read until ]. + * @param objNum the object number of the object containing the dictionary + * being read; negative only if the object number is unavailable, which + * should only happen if we're reading an array placed directly + * in the trailer + * @param objGen the object generation of the object containing the object + * being read; negative only if the objNum is unavailable + * @param decrypter the decrypter to use + */ + private PDFObject readArray( + int objNum, int objGen, PDFDecrypter decrypter) throws IOException { + // we've already read the [. Now read objects until ] + ArrayList ary = new ArrayList(); + PDFObject obj; + while((obj= readObject(objNum, objGen, decrypter))!=null) { + ary.add(obj); + } + if (this.buf.hasRemaining() && this.buf.get() != ']') { + throw new PDFParseException("Array should end with ']'"); + } + PDFObject[] objlist = new PDFObject[ary.size()]; + for (int i = 0; i < objlist.length; i++) { + objlist[i] = ary.get(i); + } + return new PDFObject(this, PDFObject.ARRAY, objlist); + } + + /** + * read a /name. The / has already been read. + */ + private PDFObject readName() throws IOException { + // we've already read the / that begins the name. + // all we have to check for is #hh hex notations. + StringBuffer sb = new StringBuffer(); + int c; + while (this.buf.hasRemaining() && isRegularCharacter(c = this.buf.get())) { + if (c < '!' && c > '~') { + break; // out-of-range, should have been hex + } + // H.3.2.4 indicates version 1.1 did not do hex escapes + if (c == '#' && (this.majorVersion >= 1 && this.minorVersion > 1)) { + int hex = readHexPair(); + if (hex >= 0) { + c = hex; + } else { + throw new PDFParseException("Bad #hex in /Name"); + } + } + sb.append((char) c); + } + this.buf.position(this.buf.position() - 1); + return new PDFObject(this, PDFObject.NAME, sb.toString()); + } + + /** + * read a number. The initial digit or . or - is passed in as the + * argument. + */ + private PDFObject readNumber(char start) throws IOException { + // we've read the first digit (it's passed in as the argument) + boolean neg = start == '-'; + boolean sawdot = start == '.'; + double dotmult = sawdot ? 0.1 : 1; + double value = (start >= '0' && start <= '9') ? start - '0' : 0; + while (true && this.buf.hasRemaining()) { + int c = this.buf.get(); + if (c == '.') { + if (sawdot) { + throw new PDFParseException("Can't have two '.' in a number"); + } + sawdot = true; + dotmult = 0.1; + } else if (c >= '0' && c <= '9') { + int val = c - '0'; + if (sawdot) { + value += val * dotmult; + dotmult *= 0.1; + } else { + value = value * 10 + val; + } + } else { + this.buf.position(this.buf.position() - 1); + break; + } + } + if (neg) { + value = -value; + } + return new PDFObject(this, PDFObject.NUMBER, Double.valueOf(value)); + } + + /** + * read a bare keyword. The initial character is passed in as the + * argument. + */ + private PDFObject readKeyword(char start) throws IOException { + // we've read the first character (it's passed in as the argument) + StringBuffer sb = new StringBuffer(String.valueOf(start)); + int c; + while (buf.hasRemaining() && isRegularCharacter(c = this.buf.get())) { + sb.append((char) c); + } + this.buf.position(this.buf.position() - 1); + return new PDFObject(this, PDFObject.KEYWORD, sb.toString()); + } + + /** + * read an entire PDFObject. The intro line, which looks something + * like "4 0 obj" has already been read. + * @param objNum the object number of the object being read, being + * the first number in the intro line (4 in "4 0 obj") + * @param objGen the object generation of the object being read, being + * the second number in the intro line (0 in "4 0 obj"). + * @param decrypter the decrypter to use + */ + private PDFObject readObjectDescription( + int objNum, int objGen, PDFDecrypter decrypter) throws IOException { + // we've already read the 4 0 obj bit. Next thing up is the object. + // object descriptions end with the keyword endobj + long debugpos = this.buf.position(); + PDFObject obj = readObject(objNum, objGen, decrypter); + // see if it's a dictionary. If so, this could be a stream. + PDFObject endkey = readObject(objNum, objGen, decrypter); + if (endkey.getType() != PDFObject.KEYWORD && endkey.getType() != PDFObject.STREAM) { + PDFDebugger.debug("WARNING: Expected 'stream' or 'endobj' but was " + endkey.getType() + " " + String.valueOf(endkey.getStringValue())); + } + if (obj.getType() == PDFObject.DICTIONARY && endkey.getStringValue() != null && endkey.getStringValue().equals("stream")) { + // skip until we see \n + readLine(); + ByteBuffer data = readStream(obj); + if (data == null) { + data = ByteBuffer.allocate(0); + } + obj.setStream(data); + endkey = readObject(objNum, objGen, decrypter); + } + // at this point, obj is the object, keyword should be "endobj" + String endcheck = endkey.getStringValue(); + if (endcheck == null || !endcheck.equals("endobj")) { + PDFDebugger.debug("WARNING: object at " + debugpos + " didn't end with 'endobj'"); + } + obj.setObjectId(objNum, objGen); + return obj; + } + + /** + * read the stream portion of a PDFObject. Calls decodeStream to + * un-filter the stream as necessary. + * + * @param dict the dictionary associated with this stream. + * @return a ByteBuffer with the encoded stream data + */ + private ByteBuffer readStream(PDFObject dict) throws IOException { + // pointer is at the start of a stream. read the stream and + // decode, based on the entries in the dictionary + PDFObject lengthObj = dict.getDictRef("Length"); + int length = -1; + if (lengthObj != null) { + length = lengthObj.getIntValue(); + } + if (length < 0) { + throw new PDFParseException("Unknown length for stream"); + } + + // slice the data + int start = this.buf.position(); + ByteBuffer streamBuf = this.buf.slice(); + streamBuf.limit(length); + + // move the current position to the end of the data + this.buf.position(this.buf.position() + length); + int ending = this.buf.position(); + + if (!nextItemIs("endstream")) { + PDFDebugger.debug("read " + length + " chars from " + start + " to " + ending); + throw new PDFParseException("Stream ended inappropriately"); + } + + return streamBuf; + // now decode stream + // return PDFDecoder.decodeStream(dict, streamBuf); + } + + /** + * read the cross reference table from a PDF file. When this method + * is called, the file pointer must point to the start of the word + * "xref" in the file. Reads the xref table and the trailer dictionary. + * If dictionary has a /Prev entry, move file pointer + * and read new trailer + * @param password + */ + private void readTrailer(PDFPassword password) + throws + IOException, + PDFAuthenticationFailureException, + EncryptionUnsupportedByProductException, + EncryptionUnsupportedByPlatformException { + // the table of xrefs + this.objIdx = new PDFXref[50]; + + int pos = this.buf.position(); + + PDFDecrypter newDefaultDecrypter = null; + + // read a bunch of nested trailer tables + while (true) { + // make sure we are looking at an xref table + if (!nextItemIs("xref")) { + this.buf.position(pos); + readTrailer15(password); + return; +// throw new PDFParseException("Expected 'xref' at start of table"); + } + + // read a bunch of linked tabled + while (true) { + // read until the word "trailer" + PDFObject obj=readObject(-1, -1, IdentityDecrypter.getInstance()); + if (obj.getType() == PDFObject.KEYWORD && + obj.getStringValue().equals("trailer")) { + break; + } + + // read the starting position of the reference + if (obj.getType() != PDFObject.NUMBER) { + throw new PDFParseException("Expected number for first xref entry"); + } + int refstart = obj.getIntValue(); + + // read the size of the reference table + obj = readObject(-1, -1, IdentityDecrypter.getInstance()); + if (obj.getType() != PDFObject.NUMBER) { + throw new PDFParseException("Expected number for length of xref table"); + } + int reflen = obj.getIntValue(); + + // skip a line + readLine(); + + if (refstart == 1) {// Check and try to fix incorrect Object Number Start + int startPos = this.buf.position(); + try { + byte[] refline = new byte[20]; + this.buf.get(refline); + if (refline[17] == 'f') {// free + PDFXref objIndex = new PDFXref(refline); + if (objIndex.getID() == 0 && objIndex.getGeneration() == 65535) { // The highest generation number possible + refstart--; + } + } + } catch (Exception e) {// in case of error ignore + } + this.buf.position(startPos); + } + + // extend the objIdx table, if necessary + if (refstart + reflen >= this.objIdx.length) { + PDFXref nobjIdx[] = new PDFXref[refstart + reflen]; + System.arraycopy(this.objIdx, 0, nobjIdx, 0, this.objIdx.length); + this.objIdx = nobjIdx; + } + + // read reference lines + for (int refID = refstart; refID < refstart + reflen; refID++) { + // each reference line is 20 bytes long + byte[] refline = new byte[20]; + this.buf.get(refline); + + // ignore this line if the object ID is already defined + if (this.objIdx[refID] != null) { + continue; + } + + // see if it's an active object + if (refline[17] == 'n') { + this.objIdx[refID] = new PDFXref(refline); + } else { + this.objIdx[refID] = new PDFXref(null); + } + } + } + + // at this point, the "trailer" word (not EOL) has been read. + PDFObject trailerdict = readObject(-1, -1, IdentityDecrypter.getInstance()); + if (trailerdict.getType() != PDFObject.DICTIONARY) { + throw new IOException("Expected dictionary after \"trailer\""); + } + + // read the root object location + if (this.root == null) { + this.root = trailerdict.getDictRef("Root"); + if (this.root != null) { + this.root.setObjectId(PDFObject.OBJ_NUM_TRAILER, + PDFObject.OBJ_NUM_TRAILER); + } + } + + // read the encryption information + if (this.encrypt == null) { + this.encrypt = trailerdict.getDictRef("Encrypt"); + if (this.encrypt != null) { + this.encrypt.setObjectId(PDFObject.OBJ_NUM_TRAILER, + PDFObject.OBJ_NUM_TRAILER); + } + + if (this.encrypt != null && !PDFDecrypterFactory.isFilterExist(this.encrypt)) { + this.encrypt = null; // the filter is not located at this trailer, we will try later again + } else { + newDefaultDecrypter = PDFDecrypterFactory.createDecryptor(this.encrypt, trailerdict.getDictRef("ID"), password); + } + } + + + if (this.info == null) { + this.info = trailerdict.getDictRef("Info"); + if (this.info != null) { + if (!this.info.isIndirect()) { + throw new PDFParseException( + "Info in trailer must be an indirect reference"); + } + this.info.setObjectId(PDFObject.OBJ_NUM_TRAILER, + PDFObject.OBJ_NUM_TRAILER); + } + } + + // support for hybrid-PDFs containing an additional compressed-xref-stream + PDFObject xrefstmPos = trailerdict.getDictRef("XRefStm"); + if (xrefstmPos != null) { + int pos14 = this.buf.position(); + this.buf.position(xrefstmPos.getIntValue()); + readTrailer15(password); + this.buf.position(pos14); + } + + // read the location of the previous xref table + PDFObject prevloc = trailerdict.getDictRef("Prev"); + if (prevloc != null) { + this.buf.position(prevloc.getIntValue()); + } else { + break; + } + // see if we have an optional Version entry + + + if (this.root.getDictRef("Version") != null) { + processVersion(this.root.getDictRef("Version").getStringValue()); + } + } + + // make sure we found a root + if (this.root == null) { + throw new PDFParseException("No /Root key found in trailer dictionary"); + } + + if (this.encrypt != null && newDefaultDecrypter!=null) { + PDFObject permissions = this.encrypt.getDictRef("P"); + if (permissions!=null && !newDefaultDecrypter.isOwnerAuthorised()) { + int perms= permissions != null ? permissions.getIntValue() : 0; + if (permissions!=null) { + this.printable = (perms & 4) != 0; + this.saveable = (perms & 16) != 0; + } + } + // Install the new default decrypter only after the trailer has + // been read, as nothing we're reading passing through is encrypted + this.defaultDecrypter = newDefaultDecrypter; + } + + // dereference the root object + this.root.dereference(); + } + + /** + * read the cross reference table from a PDF file. When this method + * is called, the file pointer must point to the start of the word + * "xref" in the file. Reads the xref table and the trailer dictionary. + * If dictionary has a /Prev entry, move file pointer + * and read new trailer + * @param password + */ + private void readTrailer15(PDFPassword password) + throws + IOException, + PDFAuthenticationFailureException, + EncryptionUnsupportedByProductException, + EncryptionUnsupportedByPlatformException { + + // the table of xrefs + // objIdx is initialized from readTrailer(), do not overwrite here data from hybrid PDFs +// objIdx = new PDFXref[50]; + PDFDecrypter newDefaultDecrypter = null; + + while (true) { + PDFObject xrefObj = readObject(-1, -1, IdentityDecrypter.getInstance()); + if (xrefObj == null) { + break; + } + HashMap trailerdict = xrefObj.getDictionary(); + if (trailerdict == null) { + break; + } + PDFObject pdfObject = trailerdict.get("W"); + if (pdfObject == null) { + break; + } + PDFObject[] wNums = pdfObject.getArray(); + int l1 = wNums[0].getIntValue(); + int l2 = wNums[1].getIntValue(); + int l3 = wNums[2].getIntValue(); + + int size = trailerdict.get("Size").getIntValue(); + + byte[] strmbuf = xrefObj.getStream(); + int strmPos = 0; + + PDFObject idxNums = trailerdict.get("Index"); + int[] idxArray; + if (idxNums == null) { + idxArray = new int[]{0, size}; + } + else { + PDFObject[] idxNumArr = idxNums.getArray(); + idxArray = new int[idxNumArr.length]; + for (int i = 0; i < idxNumArr.length; i++) { + idxArray[i] = idxNumArr[i].getIntValue(); + } + } + int idxLen = idxArray.length; + int idxPos = 0; + + + while (idxPos= this.objIdx.length) { + PDFXref nobjIdx[] = new PDFXref[refstart + reflen]; + System.arraycopy(this.objIdx, 0, nobjIdx, 0, this.objIdx.length); + this.objIdx = nobjIdx; + } + + // read reference lines + for (int refID = refstart; refID < refstart + reflen; refID++) { + + int type = readNum(strmbuf, strmPos, l1); + strmPos += l1; + int id = readNum(strmbuf, strmPos, l2); + strmPos += l2; + int gen = readNum(strmbuf, strmPos, l3); + strmPos += l3; + + // ignore this line if the object ID is already defined + if (this.objIdx[refID] != null) { + continue; + } + + // see if it's an active object + if (type == 0) { // inactive + this.objIdx[refID] = new PDFXref(null); + } else if (type == 1) { // active uncompressed + this.objIdx[refID] = new PDFXref(id, gen); + } else { // active compressed + this.objIdx[refID] = new PDFXref(id, gen, true); + } + + } + } + + // read the root object location + if (this.root == null) { + this.root = trailerdict.get("Root"); + if (this.root != null) { + this.root.setObjectId(PDFObject.OBJ_NUM_TRAILER, + PDFObject.OBJ_NUM_TRAILER); + } + } + + // read the encryption information + if (this.encrypt == null) { + this.encrypt = trailerdict.get("Encrypt"); + if (this.encrypt != null) { + this.encrypt.setObjectId(PDFObject.OBJ_NUM_TRAILER, + PDFObject.OBJ_NUM_TRAILER); + + } + if (this.encrypt != null && !PDFDecrypterFactory.isFilterExist(this.encrypt)) { + this.encrypt = null; // the filter is not located at this trailer, we will try later again + } else { + newDefaultDecrypter = PDFDecrypterFactory.createDecryptor(this.encrypt, trailerdict.get("ID"), password); + } + } + + if (this.info == null) { + this.info = trailerdict.get("Info"); + if (this.info != null) { + if (!this.info.isIndirect()) { + throw new PDFParseException( + "Info in trailer must be an indirect reference"); + } + this.info.setObjectId(PDFObject.OBJ_NUM_TRAILER, + PDFObject.OBJ_NUM_TRAILER); + } + } + + // read the location of the previous xref table + PDFObject prevloc = trailerdict.get("Prev"); + if (prevloc != null) { + this.buf.position(prevloc.getIntValue()); + } else { + break; + } + // see if we have an optional Version entry + + + if (this.root.getDictRef("Version") != null) { + processVersion(this.root.getDictRef("Version").getStringValue()); + } + } + + // make sure we found a root + if (this.root == null) { + throw new PDFParseException("No /Root key found in trailer dictionary"); + } + + // check what permissions are relevant + if (this.encrypt != null && newDefaultDecrypter!=null) { + PDFObject permissions = this.encrypt.getDictRef("P"); + if (permissions!=null && !newDefaultDecrypter.isOwnerAuthorised()) { + int perms= permissions != null ? permissions.getIntValue() : 0; + if (permissions!=null) { + this.printable = (perms & 4) != 0; + this.saveable = (perms & 16) != 0; + } + } + // Install the new default decrypter only after the trailer has + // been read, as nothing we're reading passing through is encrypted + this.defaultDecrypter = newDefaultDecrypter; + } + + // dereference the root object + this.root.dereference(); + } + + private int readNum(byte[] sbuf, int pos, int numBytes) { + int result = 0; + for (int i=0; i= 0) { + this.buf.position(scanPos); + this.buf.get(scan); + + // find startxref in scan + String scans = new String(scan); + loc = scans.indexOf("startxref"); + if (loc >= 0) { + if (scanPos + loc + scan.length <= this.buf.limit()) { + scanPos = scanPos + loc; + loc = 0; + } + + break; + } + scanPos -= scan.length - 10; + } + + if (scanPos < 0) { + throw new IOException("This may not be a PDF File"); + } + + this.buf.position(scanPos); + this.buf.get(scan); + String scans = new String(scan); + + loc += 10; // skip over "startxref" and first EOL char + if (scans.charAt(loc) < 32) { + loc++; + } // skip over possible 2nd EOL char + while (scans.charAt(loc) == 32) { + loc++; + } // skip over possible leading blanks + // read number + int numstart = loc; + while (loc < scans.length() && + scans.charAt(loc) >= '0' && + scans.charAt(loc) <= '9') { + loc++; + } + int xrefpos = Integer.parseInt(scans.substring(numstart, loc)); + this.buf.position(xrefpos); + + try { + readTrailer(password); + } catch (UnsupportedEncryptionException e) { + throw new PDFParseException(e.getMessage(), e); + } + } + + /** + * Gets the outline tree as a tree of OutlineNode, which is a subclass + * of DefaultMutableTreeNode. If there is no outline tree, this method + * returns null. + */ + public OutlineNode getOutline() throws IOException { + // find the outlines entry in the root object + PDFObject oroot = this.root.getDictRef("Outlines"); + OutlineNode work = null; + OutlineNode outline = null; + if (oroot != null) { + // find the first child of the outline root + PDFObject scan = oroot.getDictRef("First"); + outline = work = new OutlineNode(""); + + // scan each sibling in turn + while (scan != null) { + // add the new node with it's name + String title = scan.getDictRef("Title").getTextStringValue(); + OutlineNode build = new OutlineNode(title); + work.add(build); + + // find the action + PDFAction action = null; + + PDFObject actionObj = scan.getDictRef("A"); + if (actionObj != null) { + try { + action = PDFAction.getAction(actionObj, getRoot()); + } + catch (PDFParseException e) { + // oh well + } + } else { + // try to create an action from a destination + PDFObject destObj = scan.getDictRef("Dest"); + if (destObj != null) { + try { + PDFDestination dest = + PDFDestination.getDestination(destObj, getRoot()); + + action = new GoToAction(dest); + } catch (IOException ioe) { + // oh well + } + } + } + + // did we find an action? If so, add it + if (action != null) { + build.setAction(action); + } + + // find the first child of this node + PDFObject kid = scan.getDictRef("First"); + if (kid != null) { + work = build; + scan = kid; + } else { + // no child. Process the next sibling + PDFObject next = scan.getDictRef("Next"); + while (next == null) { + scan = scan.getDictRef("Parent"); + next = scan.getDictRef("Next"); + work = (OutlineNode) work.getParent(); + if (work == null) { + break; + } + } + scan = next; + } + } + } + + return outline; + } + + /** + * Gets the page number (starting from 1) of the page represented by + * a particular PDFObject. The PDFObject must be a Page dictionary or + * a destination description (or an action). + * @return a number between 1 and the number of pages indicating the + * page number, or 0 if the PDFObject is not in the page tree. + */ + public int getPageNumber(PDFObject page) throws IOException { + if (page.getType() == PDFObject.ARRAY) { + page = page.getAt(0); + } + + // now we've got a page. Make sure. + PDFObject typeObj = page.getDictRef("Type"); + if (typeObj == null || !typeObj.getStringValue().equals("Page")) { + return 0; + } + + int count = 0; + while (true) { + PDFObject parent = page.getDictRef("Parent"); + if (parent == null) { + break; + } + PDFObject kids[] = parent.getDictRef("Kids").getArray(); + for (int i = 0; i < kids.length; i++) { + if (kids[i].equals(page)) { + break; + } else { + PDFObject kcount = kids[i].getDictRef("Count"); + if (kcount != null) { + count += kcount.getIntValue(); + } else { + count += 1; + } + } + } + page = parent; + } + return count; + } + + /** + * Get the page commands for a given page in a separate thread. + * + * @param pagenum the number of the page to get commands for + */ + public PDFPage getPage(int pagenum) { + return getPage(pagenum, false); + } + + /** + * Get the page commands for a given page. + * + * @param pagenum the number of the page to get commands for + * @param wait if true, do not exit until the page is complete. + */ + public PDFPage getPage(int pagenum, boolean wait) { + Integer key = Integer.valueOf(pagenum); + HashMap resources = null; + PDFObject pageObj = null; + + PDFPage page = this.cache.getPage(key); + PDFParser parser = this.cache.getPageParser(key); + if (page == null) { + try { + // hunt down the page! + resources = new HashMap(); + + PDFObject topPagesObj = this.root.getDictRef("Pages"); + pageObj = findPage(topPagesObj, 0, pagenum, resources); + + if (pageObj == null) { + return null; + } + + page = createPage(pagenum, pageObj); + + byte[] stream = getContents(pageObj); + parser = new PDFParser(page, stream, resources); + + this.cache.addPage(key, page, parser); + } catch (IOException ioe) { + return null; + } + } + + if (parser != null) { + if (!parser.isFinished()) { + parser.go(wait); + } + if (parser.getStatus() == Watchable.ERROR) { + PDFDebugger.debug("Error in parsing the PDF page!"); + } + } + + return page; + } + + /** + * Stop the rendering of a particular image on this page + */ + public void stop(int pageNum) { + PDFParser parser = this.cache.getPageParser(Integer.valueOf(pageNum)); + if (parser != null) { + // stop it + parser.stop(); + } + } + + /** + * get the stream representing the content of a particular page. + * + * @param pageObj the page object to get the contents of + * @return a concatenation of any content streams for the requested + * page. + */ + private byte[] getContents(PDFObject pageObj) throws IOException { + // concatenate all the streams + PDFObject contentsObj = pageObj.getDictRef("Contents"); + if (contentsObj == null) { + return new byte[0]; + } + + PDFObject contents[] = contentsObj.getArray(); + + // see if we have only one stream (the easy case) + if (contents.length == 1) { + return contents[0].getStream(); + } + + // first get the total length of all the streams + int len = 0; + for (int i = 0; i < contents.length; i++) { + byte[] data = contents[i].getStream(); + if (data == null) { + throw new PDFParseException("No stream on content " + i + + ": " + contents[i]); + } + len += data.length; + } + + // now assemble them all into one object + byte[] stream = new byte[len]; + len = 0; + for (int i = 0; i < contents.length; i++) { + byte data[] = contents[i].getStream(); + System.arraycopy(data, 0, stream, len, data.length); + len += data.length; + } + + return stream; + } + + /** + * Create a PDF Page object by finding the relevant inherited + * properties + * + * @param pageObj the PDF object for the page to be created + */ + private PDFPage createPage(int pagenum, PDFObject pageObj) + throws IOException { + int rotation = 0; + Rectangle2D mediabox = null; // third choice, if no crop + Rectangle2D cropbox = null; // second choice + Rectangle2D trimbox = null; // first choice + + PDFObject mediaboxObj = getInheritedValue(pageObj, "MediaBox"); + if (mediaboxObj != null) { + mediabox = parseNormalisedRectangle(mediaboxObj); + } + + PDFObject cropboxObj = getInheritedValue(pageObj, "CropBox"); + if (cropboxObj != null) { + cropbox = parseNormalisedRectangle(cropboxObj); + } + + PDFObject trimboxObj = getInheritedValue(pageObj, "TrimBox"); + if (trimboxObj != null) { + trimbox = parseNormalisedRectangle(trimboxObj); + } + + PDFObject rotateObj = getInheritedValue(pageObj, "Rotate"); + if (rotateObj != null) { + rotation = rotateObj.getIntValue(); + } + + // read annotations and add them to the PDF page + PDFObject annots = getInheritedValue(pageObj, "Annots"); + List annotationList = new ArrayList(); + if (annots != null) { + if (annots.getType() != PDFObject.ARRAY) { + throw new PDFParseException("Can't parse annotations: " + annots.toString()); + } + PDFObject[] array = annots.getArray(); + for (PDFObject object : array) { + try { + PDFAnnotation pdfAnnot = PDFAnnotation.createAnnotation(object); + if(pdfAnnot != null) { + annotationList.add(pdfAnnot); + } + }catch (PDFParseException e) { + // do nothing, annotations could not be parsed and links will not be displayed. + } + } + } + + Rectangle2D bbox = (trimbox == null ? ((cropbox == null) ? mediabox : cropbox) : trimbox); + PDFPage page = new PDFPage(pagenum, bbox, rotation, this.cache); + page.setAnnots(annotationList); + return page; + } + + /** + * Get the PDFObject representing the content of a particular page. Note + * that the number of the page need not have anything to do with the + * label on that page. If there are two blank pages, and then roman + * numerals for the page number, then passing in 6 will get page (iv). + * + * @param pagedict the top of the pages tree + * @param start the page number of the first page in this dictionary + * @param getPage the number of the page to find; NOT the page's label. + * @param resources a HashMap that will be filled with any resource + * definitions encountered on the search for the page + */ + private PDFObject findPage(PDFObject pagedict, int start, int getPage, + Map resources) throws IOException { + PDFObject rsrcObj = pagedict.getDictRef("Resources"); + if (rsrcObj != null) { + resources.putAll(rsrcObj.getDictionary()); + } + + PDFObject typeObj = pagedict.getDictRef("Type"); + if (typeObj != null && typeObj.getStringValue().equals("Page")) { + // we found our page! + return pagedict; + } + + // find the first child for which (start + count) > getPage + PDFObject kidsObj = pagedict.getDictRef("Kids"); + if (kidsObj != null) { + PDFObject[] kids = kidsObj.getArray(); + for (int i = 0; i < kids.length; i++) { + int count = 1; + // BUG: some PDFs (T1Format.pdf) don't have the Type tag. + // use the Count tag to indicate a Pages dictionary instead. + PDFObject countItem = kids[i].getDictRef("Count"); + // if (kids[i].getDictRef("Type").getStringValue().equals("Pages")) { + if (countItem != null) { + count = countItem.getIntValue(); + } + + if (start + count >= getPage) { + return findPage(kids[i], start, getPage, resources); + } + + start += count; + } + } + + return null; + } + + /** + * Find a property value in a page that may be inherited. If the value + * is not defined in the page itself, follow the page's "parent" links + * until the value is found or the top of the tree is reached. + * + * @param pageObj the object representing the page + * @param propName the name of the property we are looking for + */ + private PDFObject getInheritedValue(PDFObject pageObj, String propName) + throws IOException { + // see if we have the property + PDFObject propObj = pageObj.getDictRef(propName); + if (propObj != null) { + return propObj; + } + + // recursively see if any of our parent have it + PDFObject parentObj = pageObj.getDictRef("Parent"); + if (parentObj != null) { + return getInheritedValue(parentObj, propName); + } + + // no luck + return null; + } + + public static Rectangle2D parseNormalisedRectangle(PDFObject obj) + throws IOException { + + if (obj != null) { + if (obj.getType() == PDFObject.ARRAY) { + PDFObject bounds[] = obj.getArray(); + if (bounds.length == 4) { + final double x0 = bounds[0].getDoubleValue(); + final double y0 = bounds[1].getDoubleValue(); + final double x1 = bounds[2].getDoubleValue(); + final double y1 = bounds[3].getDoubleValue(); + + final double minX; + final double maxY; + final double maxX; + final double minY; + + if (x0 < x1) { + minX = x0; + maxX = x1; + } else { + minX = x1; + maxX = x0; + } + if (y0 < y1) { + minY = y0; + maxY = y1; + } else { + minY = y1; + maxY = y0; + } + + return new Rectangle2D.Double(minX, minY, Math.abs(maxX - minX), Math.abs(maxY - minY)); + + } else { + throw new PDFParseException("Rectangle definition didn't have 4 elements"); + } + } else { + throw new PDFParseException("Rectangle definition not an array"); + } + } else { + throw new PDFParseException("Rectangle not present"); + } + + } + + /** + * Get the default decrypter for the document + * @return the default decrypter; never null, even for documents that + * aren't encrypted + */ + public PDFDecrypter getDefaultDecrypter() { + return this.defaultDecrypter; + } +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFImage.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFImage.java new file mode 100644 index 000000000..c9f1fe0f9 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFImage.java @@ -0,0 +1,1356 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.sun.pdfview; + +import java.awt.Color; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.Point; +import java.awt.Transparency; +import java.awt.color.ColorSpace; +import java.awt.color.ICC_ColorSpace; +import java.awt.geom.AffineTransform; +import java.awt.image.AffineTransformOp; +import java.awt.image.BufferedImage; +import java.awt.image.ColorConvertOp; +import java.awt.image.ColorModel; +import java.awt.image.ComponentColorModel; +import java.awt.image.DataBuffer; +import java.awt.image.DataBufferByte; +import java.awt.image.DataBufferInt; +import java.awt.image.IndexColorModel; +import java.awt.image.MultiPixelPackedSampleModel; +import java.awt.image.PackedColorModel; +import java.awt.image.PixelInterleavedSampleModel; +import java.awt.image.Raster; +import java.awt.image.RasterFormatException; +import java.awt.image.SampleModel; +import java.awt.image.WritableRaster; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.Arrays; +import java.util.Iterator; +import java.util.Map; + +import javax.imageio.IIOException; +import javax.imageio.ImageIO; +import javax.imageio.ImageReadParam; +import javax.imageio.ImageReader; +import javax.imageio.metadata.IIOMetadata; +import javax.imageio.metadata.IIOMetadataFormatImpl; + +import org.w3c.dom.Attr; +import org.w3c.dom.Node; + +import com.sun.pdfview.colorspace.AlternateColorSpace; +import com.sun.pdfview.colorspace.IndexedColor; +import com.sun.pdfview.colorspace.PDFColorSpace; +import com.sun.pdfview.colorspace.YCCKColorSpace; +import com.sun.pdfview.decode.PDFDecoder; +import com.sun.pdfview.function.FunctionType0; + +/** + * Encapsulates a PDF Image + */ +public class PDFImage { + + private static int[][] GREY_TO_ARGB = new int[8][]; + + /** + * color key mask. Array of start/end pairs of ranges of color components to + * mask out. If a component falls within any of the ranges it is clear. + */ + private int[] colorKeyMask = null; + /** the width of this image in pixels */ + private int width; + /** the height of this image in pixels */ + private int height; + /** the colorspace to interpret the samples in */ + private PDFColorSpace colorSpace; + /** the number of bits per sample component */ + private int bpc; + /** whether this image is a mask or not */ + private boolean imageMask = false; + /** the SMask image, if any */ + private PDFImage sMask; + /** the decode array */ + private float[] decode; + /** the actual image data */ + private final PDFObject imageObj; + /** true if the image is in encoded in JPEG*/ + private final boolean jpegDecode; + + /** + * Create an instance of a PDFImage + * @throws IOException if {@link PDFDecoder} throws one while evaluating if the image is a Jpeg + */ + protected PDFImage(PDFObject imageObj) throws IOException { + this.imageObj = imageObj; + this.jpegDecode = PDFDecoder.isLastFilter(imageObj, PDFDecoder.DCT_FILTERS); + } + + /** + * Read a PDFImage from an image dictionary and stream + * + * @param obj + * the PDFObject containing the image's dictionary and stream + * @param resources + * the current resources + * @param useAsSMask + * - flag for switching colors in case image is used as sMask + * internally this is needed for handling transparency in smask + * images. + */ + public static PDFImage createImage(PDFObject obj, Map resources, boolean useAsSMask) + throws IOException { + // create the image + PDFImage image = new PDFImage(obj); + + // get the width (required) + PDFObject widthObj = obj.getDictRef("Width"); + if (widthObj == null) { + throw new PDFParseException("Unable to read image width: " + obj); + } + image.setWidth(widthObj.getIntValue()); + + // get the height (required) + PDFObject heightObj = obj.getDictRef("Height"); + if (heightObj == null) { + throw new PDFParseException("Unable to get image height: " + obj); + } + image.setHeight(heightObj.getIntValue()); + + // figure out if we are an image mask (optional) + PDFObject imageMaskObj = obj.getDictRef("ImageMask"); + if (imageMaskObj != null) { + image.setImageMask(imageMaskObj.getBooleanValue()); + } + // read the bpc and colorspace (required except for masks) + if (image.isImageMask()) { + image.setBitsPerComponent(1); + // create the indexed color space for the mask + // [PATCHED by michal.busta@gmail.com] - default value od Decode + // according to PDF spec. is [0, 1] + // so the color arry should be: + // [PATCHED by XOND] - switched colors in case the image is used as + // SMask for another image, otherwise transparency isn't + // handled correctly. + Color[] colors = useAsSMask ? new Color[] { Color.WHITE, Color.BLACK } + : new Color[] { Color.BLACK, Color.WHITE }; + PDFObject imageMaskDecode = obj.getDictRef("Decode"); + if (imageMaskDecode != null) { + PDFObject[] decodeArray = imageMaskDecode.getArray(); + float decode0 = decodeArray[0].getFloatValue(); + if (decode0 == 1.0f) { + colors = useAsSMask ? new Color[] { Color.BLACK, Color.WHITE } + : new Color[] { Color.WHITE, Color.BLACK }; + } + + /* + * float[] decode = new float[decodeArray.length]; for (int i = + * 0; i < decodeArray.length; i++) { decode[i] = + * decodeArray[i].getFloatValue(); } image.setDecode(decode); + */ + } + + image.setColorSpace(new IndexedColor(colors)); + } else { + // get the bits per component (required) + PDFObject bpcObj = obj.getDictRef("BitsPerComponent"); + if (bpcObj == null) { + throw new PDFParseException("Unable to get bits per component: " + obj); + } + image.setBitsPerComponent(bpcObj.getIntValue()); + + // get the color space (required) + PDFObject csObj = obj.getDictRef("ColorSpace"); + if (csObj == null) { + throw new PDFParseException("No ColorSpace for image: " + obj); + } + + PDFColorSpace cs = PDFColorSpace.getColorSpace(csObj, resources); + image.setColorSpace(cs); + + // read the decode array + PDFObject decodeObj = obj.getDictRef("Decode"); + if (decodeObj != null) { + PDFObject[] decodeArray = decodeObj.getArray(); + + float[] decode = new float[decodeArray.length]; + for (int i = 0; i < decodeArray.length; i++) { + decode[i] = decodeArray[i].getFloatValue(); + } + + image.setDecode(decode); + } + + // read the soft mask. + // If ImageMask is true, this entry must not be present. + // (See implementation note 52 in Appendix H.) + PDFObject sMaskObj = obj.getDictRef("SMask"); + if (sMaskObj == null) { + // try the explicit mask, if there is no SoftMask + sMaskObj = obj.getDictRef("Mask"); + } + + if (sMaskObj != null) { + if (sMaskObj.getType() == PDFObject.STREAM) { + try { + PDFImage sMaskImage = PDFImage.createImage(sMaskObj, resources, true); + image.setSMask(sMaskImage); + } catch (IOException ex) { + PDFDebugger.debug("ERROR: there was a problem parsing the mask for this object"); + PDFDebugger.dump(obj); + BaseWatchable.getErrorHandler().publishException(ex); + } + } else if (sMaskObj.getType() == PDFObject.ARRAY) { + // retrieve the range of the ColorKeyMask + // colors outside this range will not be painted. + try { + image.setColorKeyMask(sMaskObj); + } catch (IOException ex) { + PDFDebugger.debug("ERROR: there was a problem parsing the color mask for this object"); + PDFDebugger.dump(obj); + BaseWatchable.getErrorHandler().publishException(ex); + } + } + } + } + + return image; + } + + /** + * Get the image that this PDFImage generates. + * + * @return a buffered image containing the decoded image data + * @throws PDFImageParseException + */ + public BufferedImage getImage() throws PDFImageParseException { + try { + BufferedImage bi = (BufferedImage) this.imageObj.getCache(); + + if (bi == null) { + byte[] data = imageObj.getStream(); + ByteBuffer jpegBytes = null; + if (this.jpegDecode) { + // if we're lucky, the stream will have just the DCT + // filter applied to it, and we'll have a reference to + // an underlying mapped file, so we'll manage to avoid + // a copy of the encoded JPEG bytes + jpegBytes = imageObj.getStreamBuffer(PDFDecoder.DCT_FILTERS); + } + // parse the stream data into an actual image + bi = parseData(data, jpegBytes); + this.imageObj.setCache(bi); + } + return bi; + } catch (IOException ioe) { + // let the caller know that there was a problem parsing the image + throw new PDFImageParseException("Error reading image: "+ioe.getMessage(), ioe); + } + } + + /** + *

+ * Parse the image stream into a buffered image. Note that this is + * guaranteed to be called after all the other setXXX methods have been + * called. + *

+ * + *

+ * NOTE: the color convolving is extremely slow on large images. It would be + * good to see if it could be moved out into the rendering phases, where we + * might be able to scale the image down first.

RGB + // transformation when reading JPEGs does not adhere to the spec. + // We're just going to let java read this in - as it is, the + // standard + // jpeg reader looks for the specific Adobe marker header so that + // it may apply the transform, so that's good. If that marker + // isn't present, then it also applies a number of other heuristics + // to determine whether the transform should be applied. + // (http://java.sun.com/javase/6/docs/api/javax/imageio/metadata/doc-files/jpeg_metadata.html) + // In practice, it probably almost always does the right thing here, + // though note that the present or default value of the + // ColorTransform + // dictionary entry is not being observed, so there is scope for + // error. Hopefully the JAI reader does the same. + + // We might need to attempt this with multiple readers, so let's + // remember where the jpeg data starts + jpegData.mark(); + + JpegDecoder decoder = new JpegDecoder(jpegData, cm); + + IOException decodeEx = null; + try { + bi = decoder.decode(); + } catch (IOException e) { + decodeEx = e; + // The native readers weren't able to process the image. + // One common situation is that the image is YCCK/CMYK encoded, + // which isn't supported by the default jpeg readers. + // We've got a work-around we can attempt, though: + decoder.ycckcmykDecodeMode(true); + try { + bi = decoder.decode(); + } catch (IOException e2) { + // It probably wasn't the YCCK/CMYK issue! + // try the "old" implementation + bi = parseData(data, null); + return bi; + } + } + + // the decoder may have requested installation of a new color model + cm = decoder.getColorModel(); + + // make these immediately unreachable, as the referenced + // jpeg data might be quite large + jpegData = null; + decoder = null; + + if (bi == null) { + // This isn't pretty, but it's what's been happening + // previously, so we'll preserve it for the time + // being. At least we'll offer a hint now! + assert decodeEx != null; + throw new IOException(decodeEx.getMessage() + ". Maybe installing JAI for expanded image format " + + "support would help?", decodeEx); + } + } else { + // create the data buffer + DataBuffer db = new DataBufferByte(data, data.length); + + // pick a color model, based on the number of components and + // bits per component + cm = getColorModel(); + + // create a compatible raster + SampleModel sm = cm.createCompatibleSampleModel(getWidth(), getHeight()); + WritableRaster raster; + try { + raster = Raster.createWritableRaster(sm, db, new Point(0, 0)); + } catch (RasterFormatException e) { + int tempExpectedSize = getWidth() * getHeight() * getColorSpace().getNumComponents() + * Math.max(8, getBitsPerComponent()) / 8; + + if (tempExpectedSize < 3) { + tempExpectedSize = 3; + } + if (tempExpectedSize > data.length) { + byte[] tempLargerData = new byte[tempExpectedSize]; + System.arraycopy(data, 0, tempLargerData, 0, data.length); + db = new DataBufferByte(tempLargerData, tempExpectedSize); + raster = Raster.createWritableRaster(sm, db, new Point(0, 0)); + } else { + throw e; + } + } + + /* + * Workaround for a bug on the Mac -- a class cast exception in + * drawImage() due to the wrong data buffer type (?) + */ + bi = null; + if (cm instanceof IndexColorModel) { + IndexColorModel icm = (IndexColorModel) cm; + + // choose the image type based on the size + int type = BufferedImage.TYPE_BYTE_BINARY; + if (getBitsPerComponent() == 8) { + type = BufferedImage.TYPE_BYTE_INDEXED; + } + + // create the image with an explicit indexed color model. + bi = new BufferedImage(getWidth(), getHeight(), type, icm); + + // set the data explicitly as well + bi.setData(raster); + } else if (cm.getPixelSize() == 1 && cm.getNumComponents() == 1) { + // If the image is black and white only, convert it into + // BYTE_GRAY + // format + // This is a lot faster compared to just drawing the original + // image + + // Are pixels decoded? + int[] cc = new int[] { 0, 1 }; + PDFObject o = imageObj.getDictRef("Decode"); + if (o != null && o.getAt(0) != null) { + cc[0] = o.getAt(0).getIntValue(); + cc[1] = o.getAt(1).getIntValue(); + } + + final byte[] ncc = new byte[] { (byte) -cc[0], (byte) -cc[1] }; + + bi = biColorToGrayscale(raster, ncc); + // Return when there is no SMask + if (getSMask() == null) + return bi; + } else { + // Raster is already in a format which is supported by Java2D, + // such as RGB or Gray. + bi = new BufferedImage(cm, raster, true, null); + } + } + + // hack to avoid *very* slow conversion + ColorSpace cs = cm.getColorSpace(); + ColorSpace rgbCS = ColorSpace.getInstance(ColorSpace.CS_sRGB); + if (isGreyscale(cs) && bpc <= 8 && getDecode() == null && jpegData == null + && Configuration.getInstance().isConvertGreyscaleImagesToArgb()) { + bi = convertGreyscaleToArgb(data, bi); + } else if (!isImageMask() && cs instanceof ICC_ColorSpace && !cs.equals(rgbCS) + && !Configuration.getInstance().isAvoidColorConvertOp()) { + ColorConvertOp op = new ColorConvertOp(cs, rgbCS, null); + + BufferedImage converted = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB); + + bi = op.filter(bi, converted); + } + else if (cs.getType() == ColorSpace.TYPE_CMYK) { + // convert to ARGB for faster drawing without ColorConvertOp + BufferedImage converted = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB); + Graphics2D graphics = converted.createGraphics(); + graphics.drawImage(bi,0,0,null); + graphics.dispose(); + bi = converted; + } + + // add in the alpha data supplied by the SMask, if any + PDFImage sMaskImage = getSMask(); + if (sMaskImage != null) { + BufferedImage si = null; + try { + int w = bi.getWidth(); + int h = bi.getHeight(); + // if the bitmap is only a few pixels it just defines the color + boolean maskOnly = (w <= 2); + if (maskOnly) { + // use size of mask + si = sMaskImage.getImage(); + w = si.getWidth(); + h = si.getHeight(); + } + else if (sMaskImage.getHeight() != h && sMaskImage.getWidth() != w) { + // in case the two images do not have the same size, scale + if (sMaskImage.getHeight()*sMaskImage.getWidth() > w*h) { + // upscale image + si = sMaskImage.getImage(); + w = si.getWidth(); + h = si.getHeight(); + int hints = Image.SCALE_FAST; + Image scaledInstance = bi.getScaledInstance(w, h, hints ); + bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); + Graphics graphics = bi.createGraphics(); + graphics.drawImage(scaledInstance, 0, 0, null); + graphics.dispose(); + } + else { + // upscale mask + si = scaleSMaskImage(sMaskImage); + } + } + else { + si = sMaskImage.getImage(); + } + PDFDebugger.debugImage(si, "smask" + this.imageObj.getObjNum()); + + BufferedImage outImage = new BufferedImage(w,h, BufferedImage.TYPE_INT_ARGB); + PDFDebugger.debugImage(si, "outImage" + this.imageObj.getObjNum()); + int[] srcArray = new int[w]; + int[] maskArray = new int[w]; + + for (int i = 0; i < h; i++) { + if (maskOnly) { + // use first pixel color from image + Arrays.fill(srcArray, bi.getRGB(0,0)); + } + else { + // pixel row from image + bi.getRGB(0, i, w, 1, srcArray, 0, w); + } + // pixel row from mask + si.getRGB(0, i, w, 1, maskArray, 0, w); + + for (int j = 0; j < w; j++) { + int ac = 0xff000000; + // alpha from mask with color from image + maskArray[j] = ((maskArray[j] & 0xff) << 24) | (srcArray[j] & ~ac); + } + // write pixel row + outImage.setRGB(0, i, w, 1, maskArray, 0, w); + } + + bi = outImage; + } catch (PDFImageParseException e) { + PDFDebugger.debug("Error parsing sMask image caused by:" + e.getMessage(), 100); + } + } + + PDFDebugger.debugImage(bi, "result" + this.imageObj.getObjNum()); + return bi; + } + + /** + * Scale the softmask image to the size of the actual image + * + * @param sMaskImage + * @return + * @throws PDFImageParseException + */ + private BufferedImage scaleSMaskImage(PDFImage sMaskImage) throws PDFImageParseException { + BufferedImage before = sMaskImage.getImage(); + int w = before.getWidth(); + int h = before.getHeight(); + + if (PDFDebugger.DEBUG_IMAGES) { + PDFDebugger.debug("Scaling image from " + w + "/" + h + " to " + this.width + "/" + this.height); + } + BufferedImage after = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); + AffineTransform at = new AffineTransform(); + + at.scale(((double) this.width / w), ((double) this.height / h)); + + AffineTransformOp scaleOp = new AffineTransformOp(at, AffineTransformOp.TYPE_BILINEAR); + return scaleOp.filter(before, after); + } + + private boolean isGreyscale(ColorSpace aCs) { + return aCs == PDFColorSpace.getColorSpace(PDFColorSpace.COLORSPACE_GRAY).getColorSpace(); + } + + private BufferedImage convertGreyscaleToArgb(byte[] data, BufferedImage bi) { + // we use an optimised greyscale colour conversion, as with scanned + // greyscale/mono documents consisting of nothing but page-size + // images, using the ICC converter is perhaps 15 times slower than this + // method. Using an example scanned, mainly monochrome document, on this + // developer's machine pages took an average of 3s to render using the + // ICC converter filter, and around 115ms using this method. We use + // pre-calculated tables generated using the ICC converter to map + // between + // each possible greyscale value and its desired value in sRGB. + // We also try to avoid going through SampleModels, WritableRasters or + // BufferedImages as that takes about 3 times as long. + final int[] convertedPixels = new int[getWidth() * getHeight()]; + final WritableRaster r = bi.getRaster(); + int i = 0; + final int[] greyToArgbMap = getGreyToArgbMap(bpc); + if (bpc == 1) { + int calculatedLineBytes = (getWidth() + 7) / 8; + int rowStartByteIndex; + // avoid hitting the WritableRaster for the common 1 bpc case + if (greyToArgbMap[0] == 0 && greyToArgbMap[1] == 0xFFFFFFFF) { + // optimisation for common case of a direct map to full white + // and black, using bit twiddling instead of consulting the + // greyToArgb map + for (int y = 0; y < getHeight(); ++y) { + // each row is byte-aligned + rowStartByteIndex = y * calculatedLineBytes; + for (int x = 0; x < getWidth(); ++x) { + final byte b = data[rowStartByteIndex + x / 8]; + final int white = b >> (7 - (x & 7)) & 1; + // if white == 0, white - 1 will be 0xFFFFFFFF, + // which when xored with 0xFFFFFF will produce 0 + // if white == 1, white - 1 will be 0, + // which when xored with 0xFFFFFF will produce 0xFFFFFF + // (ignoring the top two bytes, which are always set + // high anyway) + convertedPixels[i] = 0xFF000000 | ((white - 1) ^ 0xFFFFFF); + ++i; + } + } + } else { + // 1 bpc case where we can't bit-twiddle and need to consult + // the map + for (int y = 0; y < getHeight(); ++y) { + rowStartByteIndex = y * calculatedLineBytes; + for (int x = 0; x < getWidth(); ++x) { + final byte b = data[rowStartByteIndex + x / 8]; + final int val = b >> (7 - (x & 7)) & 1; + convertedPixels[i] = greyToArgbMap[val]; + ++i; + } + } + } + } else { + for (int y = 0; y < getHeight(); ++y) { + for (int x = 0; x < getWidth(); ++x) { + final int greyscale = r.getSample(x, y, 0); + convertedPixels[i] = greyToArgbMap[greyscale]; + ++i; + } + } + } + + final ColorModel ccm = ColorModel.getRGBdefault(); + return new BufferedImage(ccm, + Raster.createPackedRaster(new DataBufferInt(convertedPixels, convertedPixels.length), getWidth(), + getHeight(), getWidth(), ((PackedColorModel) ccm).getMasks(), null), + false, null); + } + + private static int[] getGreyToArgbMap(int numBits) { + assert numBits <= 8; + int[] argbVals = GREY_TO_ARGB[numBits - 1]; + if (argbVals == null) { + argbVals = createGreyToArgbMap(numBits); + } + return argbVals; + } + + /** + * Create a map from all bit-patterns of a certain depth greyscale to the + * corresponding sRGB values via the ICC colorr converter. + * + * @param numBits + * the number of greyscale bits + * @return a 2^bits array of standard 32-bit ARGB fits for each greyscale + * value at that bitdepth + */ + private static int[] createGreyToArgbMap(int numBits) { + final ColorSpace greyCs = PDFColorSpace.getColorSpace(PDFColorSpace.COLORSPACE_GRAY).getColorSpace(); + + byte[] greyVals = new byte[1 << numBits]; + for (int i = 0; i < greyVals.length; ++i) { + greyVals[i] = (byte) (i & 0xFF); + } + + final int[] argbVals = new int[greyVals.length]; + final int mask = (1 << numBits) - 1; + final WritableRaster inRaster = Raster.createPackedRaster(new DataBufferByte(greyVals, greyVals.length), + greyVals.length, 1, greyVals.length, new int[] { mask }, null); + + final BufferedImage greyImage = new BufferedImage(new PdfComponentColorModel(greyCs, new int[] { numBits }), + inRaster, false, null); + + final ColorModel ccm = ColorModel.getRGBdefault(); + final WritableRaster outRaster = Raster.createPackedRaster(new DataBufferInt(argbVals, argbVals.length), + argbVals.length, 1, argbVals.length, ((PackedColorModel) ccm).getMasks(), null); + final BufferedImage srgbImage = new BufferedImage(ccm, outRaster, false, null); + + final ColorConvertOp op = new ColorConvertOp(greyCs, ColorSpace.getInstance(ColorSpace.CS_sRGB), null); + + op.filter(greyImage, srgbImage); + + GREY_TO_ARGB[numBits - 1] = argbVals; + return argbVals; + } + + /** + * Creates a new image of type {@link TYPE_BYTE_GRAY} which represents the + * given raster + * + * @param raster + * Raster of an image with just two colors, bitwise encoded + * @param ncc + * Array with two entries that describe the corresponding gray + * values + */ + private BufferedImage biColorToGrayscale(final WritableRaster raster, final byte[] ncc) { + + final byte[] bufferO = ((DataBufferByte) raster.getDataBuffer()).getData(); + + BufferedImage converted = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_BYTE_GRAY); + + byte[] buffer = ((DataBufferByte) converted.getRaster().getDataBuffer()).getData(); + int i = 0; + final int height = converted.getHeight(); + final int width = converted.getWidth(); + for (int y = 0; y < height; y++) { + int base = y * width + 7; + if ((y + 1) * width < buffer.length) { + for (int x = 0; x < width; x += 8) { + final byte bits = bufferO[i]; + i++; + for (byte j = 7; j >= 0; j--) { + if (buffer.length <= (base - j)) { + break; + } + final int c = ((bits >>> j) & 1); + buffer[base - j] = ncc[c]; + } + base += 8; + } + } else { + for (int x = 0; x < width; x += 8) { + final byte bits = bufferO[i]; + i++; + for (byte j = 7; j >= 0; j--) { + if (base - j >= buffer.length) + break; + buffer[base - j] = ncc[((bits >>> j) & 1)]; + } + base += 8; + } + } + } + return converted; + } + + /** + * Get the image's width + */ + public int getWidth() { + return this.width; + } + + /** + * Set the image's width + */ + protected void setWidth(int width) { + this.width = width; + } + + /** + * Get the image's height + */ + public int getHeight() { + return this.height; + } + + /** + * Set the image's height + */ + protected void setHeight(int height) { + this.height = height; + } + + /** + * set the color key mask. It is an array of start/end entries to indicate + * ranges of color indicies that should be masked out. + * + * @param maskArrayObject + */ + private void setColorKeyMask(PDFObject maskArrayObject) throws IOException { + PDFObject[] maskObjects = maskArrayObject.getArray(); + this.colorKeyMask = null; + int[] masks = new int[maskObjects.length]; + for (int i = 0; i < masks.length; i++) { + masks[i] = maskObjects[i].getIntValue(); + } + this.colorKeyMask = masks; + } + + /** + * Get the colorspace associated with this image, or null if there isn't one + */ + protected PDFColorSpace getColorSpace() { + return this.colorSpace; + } + + /** + * Set the colorspace associated with this image + */ + protected void setColorSpace(PDFColorSpace colorSpace) { + this.colorSpace = colorSpace; + } + + /** + * Get the number of bits per component sample + */ + protected int getBitsPerComponent() { + return this.bpc; + } + + /** + * Set the number of bits per component sample + */ + protected void setBitsPerComponent(int bpc) { + this.bpc = bpc; + } + + /** + * Return whether or not this is an image mask + */ + public boolean isImageMask() { + return this.imageMask; + } + + /** + * Set whether or not this is an image mask + */ + public void setImageMask(boolean imageMask) { + this.imageMask = imageMask; + } + + /** + * Return the soft mask associated with this image + */ + public PDFImage getSMask() { + return this.sMask; + } + + /** + * Set the soft mask image + */ + protected void setSMask(PDFImage sMask) { + this.sMask = sMask; + } + + /** + * Get the decode array + */ + protected float[] getDecode() { + return this.decode; + } + + /** + * Set the decode array + */ + protected void setDecode(float[] decode) { + this.decode = decode; + } + + /** + * get a Java ColorModel consistent with the current color space, number of + * bits per component and decode array + * + * @param bpc + * the number of bits per component + */ + private ColorModel getColorModel() { + PDFColorSpace cs = getColorSpace(); + + if (cs instanceof IndexedColor) { + IndexedColor ics = (IndexedColor) cs; + + byte[] components = ics.getColorComponents(); + int num = ics.getCount(); + + // process the decode array + if (this.decode != null) { + byte[] normComps = new byte[components.length]; + + // move the components array around + for (int i = 0; i < num; i++) { + byte[] orig = new byte[1]; + orig[0] = (byte) i; + + float[] res = normalize(orig, null, 0); + int idx = (int) res[0]; + + normComps[i * 3] = components[idx * 3]; + normComps[(i * 3) + 1] = components[(idx * 3) + 1]; + normComps[(i * 3) + 2] = components[(idx * 3) + 2]; + } + + components = normComps; + } + + // make sure the size of the components array is 2 ^ numBits + // since if it's not, Java will complain + int correctCount = 1 << getBitsPerComponent(); + if (correctCount < num) { + byte[] fewerComps = new byte[correctCount * 3]; + + System.arraycopy(components, 0, fewerComps, 0, correctCount * 3); + + components = fewerComps; + num = correctCount; + } + if (this.colorKeyMask == null || this.colorKeyMask.length == 0) { + return new IndexColorModel(getBitsPerComponent(), num, components, 0, false); + } else { + byte[] aComps = new byte[num * 4]; + int idx = 0; + for (int i = 0; i < num; i++) { + aComps[idx++] = components[(i * 3)]; + aComps[idx++] = components[(i * 3) + 1]; + aComps[idx++] = components[(i * 3) + 2]; + aComps[idx++] = (byte) 0xFF; + } + for (int i = 0; i < this.colorKeyMask.length; i += 2) { + for (int j = this.colorKeyMask[i]; j <= this.colorKeyMask[i + 1]; j++) { + aComps[(j * 4) + 3] = 0; // make transparent + } + } + return new IndexColorModel(getBitsPerComponent(), num, aComps, 0, true); + } + } else if (cs instanceof AlternateColorSpace) { + // ColorSpace altCS = new AltColorSpace(((AlternateColorSpace) + // cs).getFunktion(), cs.getColorSpace()); + ColorSpace altCS = cs.getColorSpace(); + int[] bits = new int[altCS.getNumComponents()]; + for (int i = 0; i < bits.length; i++) { + bits[i] = getBitsPerComponent(); + } + return new DecodeComponentColorModel(altCS, bits); + } else { + // If the image is a JPEG, then CMYK color space has been converted to RGB in DCTDecode + if (this.jpegDecode && cs.getColorSpace().getType() == ColorSpace.TYPE_CMYK) { + ColorSpace rgbCS = ColorSpace.getInstance(ColorSpace.CS_sRGB); + int[] bits = new int[rgbCS.getNumComponents()]; + for (int i = 0; i < bits.length; i++) { + bits[i] = getBitsPerComponent(); + } + return new DecodeComponentColorModel(rgbCS, bits); + } + ColorSpace colorSpace = cs.getColorSpace(); + int[] bits = new int[colorSpace.getNumComponents()]; + for (int i = 0; i < bits.length; i++){ + bits[i] = getBitsPerComponent(); + } + + return new DecodeComponentColorModel(cs.getColorSpace(), bits); + } + } + + /** + * Normalize an array of values to match the decode array + */ + private float[] normalize(byte[] pixels, float[] normComponents, int normOffset) { + if (normComponents == null) { + normComponents = new float[normOffset + pixels.length]; + } + + float[] decodeArray = getDecode(); + + for (int i = 0; i < pixels.length; i++) { + int val = pixels[i] & 0xff; + int pow = ((int) Math.pow(2, getBitsPerComponent())) - 1; + float ymin = decodeArray[i * 2]; + float ymax = decodeArray[(i * 2) + 1]; + + normComponents[normOffset + i] = FunctionType0.interpolate(val, 0, pow, ymin, ymax); + } + + return normComponents; + } + + /** + * A wrapper for ComponentColorSpace which normalizes based on the decode + * array. + */ + class DecodeComponentColorModel extends ComponentColorModel { + + public DecodeComponentColorModel(ColorSpace cs, int[] bpc) { + super(cs, bpc, false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE); + + if (bpc != null) { + this.pixel_bits = bpc.length * bpc[0]; + } + } + + @Override + public SampleModel createCompatibleSampleModel(int width, int height) { + // workaround -- create a MultiPixelPackedSample models for + // single-sample, less than 8bpp color models + if (getNumComponents() == 1 && getPixelSize() < 8) { + return new MultiPixelPackedSampleModel(getTransferType(), width, height, getPixelSize()); + } + + return super.createCompatibleSampleModel(width, height); + } + + @Override + public boolean isCompatibleRaster(Raster raster) { + if (getNumComponents() == 1 && getPixelSize() < 8) { + SampleModel sm = raster.getSampleModel(); + + if (sm instanceof MultiPixelPackedSampleModel) { + return (sm.getSampleSize(0) == getPixelSize()); + } else { + return false; + } + } + + return super.isCompatibleRaster(raster); + } + + @Override + public float[] getNormalizedComponents(Object pixel, float[] normComponents, int normOffset) { + if (getDecode() == null) { + return super.getNormalizedComponents(pixel, normComponents, normOffset); + } + + return normalize((byte[]) pixel, normComponents, normOffset); + } + } + + /** + * get a Java ColorModel consistent with the current color space, number of + * bits per component and decode array + * + * @param bpc + * the number of bits per component + */ + private ColorModel createColorModel() { + PDFColorSpace cs = getColorSpace(); + + if (cs instanceof IndexedColor) { + IndexedColor ics = (IndexedColor) cs; + + byte[] components = ics.getColorComponents(); + int num = ics.getCount(); + + // process the decode array + if (decode != null) { + byte[] normComps = new byte[components.length]; + + // move the components array around + for (int i = 0; i < num; i++) { + byte[] orig = new byte[1]; + orig[0] = (byte) i; + + float[] res = normalize(orig, null, 0); + int idx = (int) res[0]; + + normComps[i * 3] = components[idx * 3]; + normComps[(i * 3) + 1] = components[(idx * 3) + 1]; + normComps[(i * 3) + 2] = components[(idx * 3) + 2]; + } + + components = normComps; + } + + // make sure the size of the components array is 2 ^ numBits + // since if it's not, Java will complain + int correctCount = 1 << getBitsPerComponent(); + if (correctCount < num) { + byte[] fewerComps = new byte[correctCount * 3]; + + System.arraycopy(components, 0, fewerComps, 0, correctCount * 3); + + components = fewerComps; + num = correctCount; + } + if (colorKeyMask == null || colorKeyMask.length == 0) { + return new IndexColorModel(getBitsPerComponent(), num, components, 0, false); + } else { + byte[] aComps = new byte[num * 4]; + int idx = 0; + for (int i = 0; i < num; i++) { + aComps[idx++] = components[(i * 3)]; + aComps[idx++] = components[(i * 3) + 1]; + aComps[idx++] = components[(i * 3) + 2]; + aComps[idx++] = (byte) 0xFF; + } + for (int i = 0; i < colorKeyMask.length; i += 2) { + for (int j = colorKeyMask[i]; j <= colorKeyMask[i + 1]; j++) { + aComps[(j * 4) + 3] = 0; // make transparent + } + } + return new IndexColorModel(getBitsPerComponent(), num, aComps, 0, true); + } + } else { + int[] bits = new int[cs.getNumComponents()]; + for (int i = 0; i < bits.length; i++) { + bits[i] = getBitsPerComponent(); + } + + return decode != null ? new DecodeComponentColorModel(cs.getColorSpace(), bits) + : new PdfComponentColorModel(cs.getColorSpace(), bits); + } + } + + /** + * Decodes jpeg data, possibly attempting a manual YCCK decode if requested. + * Users should use {@link #getColorModel()} to see which color model should + * now be used after a successful decode. + */ + private class JpegDecoder { + /** The jpeg bytes */ + private final ByteBuffer jpegData; + /** The color model employed */ + private ColorModel cm; + /** Whether the YCCK/CMYK decode work-around should be used */ + private boolean ycckcmykDecodeMode = false; + + /** + * Class constructor + * + * @param jpegData + * the JPEG data + * @param cm + * the color model as presented in the PDF + */ + private JpegDecoder(ByteBuffer jpegData, ColorModel cm) { + this.jpegData = jpegData; + this.cm = cm; + } + + /** + * Identify whether the decoder should operate in YCCK/CMYK decode mode, + * whereby the YCCK Chroma is specifically looked for and the color + * model is changed to support converting raw YCCK color values, working + * around a lack of YCCK/CMYK report in the standard Java jpeg readers. + * Non-YCCK images will not be decoded while in this mode. + * + * @param ycckcmykDecodeMode + */ + public void ycckcmykDecodeMode(boolean ycckcmykDecodeMode) { + this.ycckcmykDecodeMode = ycckcmykDecodeMode; + } + + /** + * Get the color model that should be used now + * + * @return + */ + public ColorModel getColorModel() { + return cm; + } + + /** + * Attempt to decode the jpeg data + * + * @return the successfully decoded image + * @throws IOException + * if the image couldn't be decoded due to a lack of support + * or some IO problem + */ + private BufferedImage decode() throws IOException { + + ImageReadParam readParam = null; + if (getDecode() != null) { + // we have to allocate our own buffered image so that we can + // install our colour model which will do the desired decode + readParam = new ImageReadParam(); + SampleModel sm = cm.createCompatibleSampleModel(getWidth(), getHeight()); + final WritableRaster raster = Raster.createWritableRaster(sm, new Point(0, 0)); + readParam.setDestination(new BufferedImage(cm, raster, true, null)); + } + + Iterator jpegReaderIt = ImageIO.getImageReadersByFormatName("jpeg"); + IIOException lastIioEx = null; + while (jpegReaderIt.hasNext()) { + try { + final ImageReader jpegReader = jpegReaderIt.next(); + jpegReader.setInput(ImageIO.createImageInputStream(new ByteBufferInputStream(jpegData)), true, + false); + try { + return readImage(jpegReader, readParam); + } catch (Exception e) { + if (e instanceof IIOException) { + throw (IIOException) e; + } + // Any other exceptions here are probably due to + // internal + // problems with the image reader. + // A concrete example of this happening is described + // here: + // http://java.net/jira/browse/PDF_RENDERER-132 where + // JAI imageio extension throws an + // IndexOutOfBoundsException on progressive JPEGs. + // We'll just treat it as an IIOException for + // convenience + // and hopefully a subsequent reader can handle it + throw new IIOException("Internal reader error?", e); + } finally { + jpegReader.dispose(); + } + } catch (IIOException e) { + // its most likely complaining about an unsupported image + // type; hopefully the next image reader will be able to + // understand it + jpegData.reset(); + lastIioEx = e; + } + } + + throw lastIioEx; + + } + + private BufferedImage readImage(ImageReader jpegReader, ImageReadParam param) throws IOException { + if (ycckcmykDecodeMode) { + // The standard Oracle Java JPEG readers can't deal with CMYK + // YCCK encoded images + // without a little help from us. We'll try and pick up such + // instances and work around it. + final IIOMetadata imageMeta = jpegReader.getImageMetadata(0); + if (imageMeta != null) { + final Node standardMeta = imageMeta.getAsTree(IIOMetadataFormatImpl.standardMetadataFormatName); + if (standardMeta != null) { + final Node chroma = getChild(standardMeta, "Chroma"); + if (chroma != null) { + final Node csType = getChild(chroma, "ColorSpaceType"); + if (csType != null) { + final Attr csTypeNameNode = (Attr) csType.getAttributes().getNamedItem("name"); + if (csTypeNameNode != null) { + final String typeName = csTypeNameNode.getValue(); + final boolean YCCK; + if ((YCCK = "YCCK".equals(typeName)) || "CMYK".equals(typeName)) { + // If it's a YCCK image, then we can + // coax a workable image out of it + // by grabbing the raw raster and + // installing a YCCK converting + // color space wrapper around the + // existing (CMYK) color space; this + // will + // do the YCCK conversion for us + // + // If it's a CMYK image - just raster it + // in existing CMYK color space + + // first make sure we can get the + // unadjusted raster + final Raster raster = jpegReader.readRaster(0, param); + + if (YCCK) { + // and now use it with a YCCK + // converting color space. + PDFImage.this.colorSpace = new PDFColorSpace( + new YCCKColorSpace(colorSpace.getColorSpace())); + // re-calculate the color model + // since the color space has changed + cm = PDFImage.this.createColorModel(); + } + + return new BufferedImage(cm, Raster.createWritableRaster( + raster.getSampleModel(), raster.getDataBuffer(), null), true, null); + + } + } + } + } + } + } + + throw new IIOException("Neither YCCK nor CMYK image"); + + } else { + + if (param != null && param.getDestination() != null) { + // if we've already set up a destination image then we'll + // use it + return jpegReader.read(0, param); + } else { + // otherwise we'll create a new buffered image with the + // desired color model + //return new BufferedImage(cm, jpegReader.read(0, param).getRaster(), true, null); + BufferedImage bi = jpegReader.read(0, param); + try { + return new BufferedImage(cm, bi.getRaster(), true, null); + } catch (IllegalArgumentException raster_ByteInterleavedRaster) { + BufferedImage bi2 = new BufferedImage(bi.getWidth(), bi.getHeight(), + BufferedImage.TYPE_BYTE_INDEXED, + new IndexColorModel(8, 1, new byte[] { 0 }, new byte[] { 0 }, new byte[] { 0 }, 0)); + cm = bi2.getColorModel(); + return bi2; + } + } + } + + } + + /** + * Get a named child node + * + * @param aNode + * the node + * @param aChildName + * the name of the child node + * @return the first direct child node with that name or null if it + * doesn't exist + */ + private Node getChild(Node aNode, String aChildName) { + for (int i = 0; i < aNode.getChildNodes().getLength(); ++i) { + final Node child = aNode.getChildNodes().item(i); + if (child.getNodeName().equals(aChildName)) { + return child; + } + } + return null; + } + } + + /** + * A wrapper for ComponentColorSpace which normalizes based on the decode + * array. + */ + static class PdfComponentColorModel extends ComponentColorModel { + + int bitsPerComponent; + + public PdfComponentColorModel(ColorSpace cs, int[] bpc) { + super(cs, bpc, false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE); + + pixel_bits = bpc.length * bpc[0]; + this.bitsPerComponent = bpc[0]; + } + + @Override + public SampleModel createCompatibleSampleModel(int width, int height) { + + if (bitsPerComponent >= 8) { + assert bitsPerComponent == 8 || bitsPerComponent == 16; + final int numComponents = getNumComponents(); + int[] bandOffsets = new int[numComponents]; + for (int i = 0; i < numComponents; i++) { + bandOffsets[i] = i; + } + return new PixelInterleavedSampleModel(getTransferType(), width, height, numComponents, + width * numComponents, bandOffsets); + } else { + switch (getPixelSize()) { + case 1: + case 2: + case 4: + // pixels don't span byte boundaries, so we can use the + // standard multi pixel + // packing, which offers a slight performance advantage over + // the other sample + // model, which must consider such cases. Given that sample + // model interactions + // can dominate processing, this small distinction is + // worthwhile + return new MultiPixelPackedSampleModel(getTransferType(), width, height, getPixelSize()); + default: + // pixels will cross byte boundaries + assert getTransferType() == DataBuffer.TYPE_BYTE; + return new PdfSubByteSampleModel(width, height, getNumComponents(), bitsPerComponent); + } + } + } + + @Override + public boolean isCompatibleRaster(Raster raster) { + if (bitsPerComponent < 8 || getNumComponents() == 1) { + SampleModel sm = raster.getSampleModel(); + return sm.getSampleSize(0) == bitsPerComponent; + } + return super.isCompatibleRaster(raster); + } + + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFImageParseException.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFImageParseException.java new file mode 100644 index 000000000..04facc5a4 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFImageParseException.java @@ -0,0 +1,18 @@ +package com.sun.pdfview; + +import java.io.IOException; + +/** + * an exception class for recording errors when parsing an PDFImage + * @author Katja Sondermann + */ +public class PDFImageParseException extends IOException { + public PDFImageParseException(String msg) { + super(msg); + } + + public PDFImageParseException(String msg, Throwable cause) { + this(msg); + initCause(cause); + } +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFObject.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFObject.java new file mode 100644 index 000000000..81a11be07 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFObject.java @@ -0,0 +1,849 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.sun.pdfview; + +import java.io.IOException; +import java.lang.ref.SoftReference; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import com.sun.pdfview.decode.PDFDecoder; +import com.sun.pdfview.decrypt.IdentityDecrypter; +import com.sun.pdfview.decrypt.PDFDecrypter; + +/** + * a class encapsulating all the possibilities of content for + * an object in a PDF file. + *

+ * A PDF object can be a simple type, like a Boolean, a Number, + * a String, or the Null value. It can also be a NAME, which + * looks like a string, but is a special type in PDF files, like + * "/Name". + *

+ * A PDF object can also be complex types, including Array; + * Dictionary; Stream, which is a Dictionary plus an array of + * bytes; or Indirect, which is a reference to some other + * PDF object. Indirect references will always be dereferenced + * by the time any data is returned from one of the methods + * in this class. + * + * @author Mike Wessler + */ +public class PDFObject { + + /** an indirect reference*/ + public static final int INDIRECT = 0; // PDFXref + /** a Boolean */ + public static final int BOOLEAN = 1; // Boolean + /** a Number, represented as a double */ + public static final int NUMBER = 2; // Double + /** a String */ + public static final int STRING = 3; // String + /** a special string, seen in PDF files as /Name */ + public static final int NAME = 4; // String + /** an array of PDFObjects */ + public static final int ARRAY = 5; // Array of PDFObject + /** a Hashmap that maps String names to PDFObjects */ + public static final int DICTIONARY = 6; // HashMap(String->PDFObject) + /** a Stream: a Hashmap with a byte array */ + public static final int STREAM = 7; // HashMap + byte[] + /** the NULL object (there is only one) */ + public static final int NULL = 8; // null + /** a special PDF bare word, like R, obj, true, false, etc */ + public static final int KEYWORD = 9; // String + /** + * When a value of {@link #getObjGen objNum} or {@link #getObjGen objGen}, + * indicates that the object is not top-level, and is embedded in another + * object + */ + public static final int OBJ_NUM_EMBEDDED = -2; + + /** + * When a value of {@link #getObjGen objNum} or {@link #getObjGen objGen}, + * indicates that the object is not top-level, and is embedded directly + * in the trailer. + */ + public static final int OBJ_NUM_TRAILER = -1; + + /** the NULL PDFObject */ + public static final PDFObject nullObj = new PDFObject(null, NULL, null); + /** the type of this object */ + private int type; + /** the value of this object. It can be a wide number of things, defined by type */ + private Object value; + /** the encoded stream, if this is a STREAM object */ + private ByteBuffer stream; + /** a cached version of the decoded stream */ + private SoftReference decodedStream; + /** The filter limits used to generate the cached decoded stream */ + private Set decodedStreamFilterLimits = null; + /** + * the PDFFile from which this object came, used for + * dereferences + */ + private final PDFFile owner; + /** + * a cache of translated data. This data can be + * garbage collected at any time, after which it will + * have to be rebuilt. + */ + private SoftReference cache; + + /** @see #getObjNum() */ + private int objNum = OBJ_NUM_EMBEDDED; + + /** @see #getObjGen() */ + private int objGen = OBJ_NUM_EMBEDDED; + + /** + * create a new simple PDFObject with a type and a value + * @param owner the PDFFile in which this object resides, used + * for dereferencing. This may be null. + * @param type the type of object + * @param value the value. For DICTIONARY, this is a HashMap. + * for ARRAY it's an ArrayList. For NUMBER, it's a Double. + * for BOOLEAN, it's Boolean.TRUE or Boolean.FALSE. For + * everything else, it's a String. + */ + public PDFObject(PDFFile owner, int type, Object value) { + this.type = type; + if (type == NAME) { + value = ((String) value).intern(); + } else if (type == KEYWORD && value.equals("true")) { + this.type = BOOLEAN; + value = Boolean.TRUE; + } else if (type == KEYWORD && value.equals("false")) { + this.type = BOOLEAN; + value = Boolean.FALSE; + } + this.value = value; + this.owner = owner; + } + + /** + * create a new PDFObject that is the closest match to a + * given Java object. Possibilities include Double, String, + * PDFObject[], HashMap, Boolean, or PDFParser.Tok, + * which should be "true" or "false" to turn into a BOOLEAN. + * + * @param obj the sample Java object to convert to a PDFObject. + * @throws PDFParseException if the object isn't one of the + * above examples, and can't be turned into a PDFObject. + */ + public PDFObject(Object obj) throws PDFParseException { + this.owner = null; + this.value = obj; + if ((obj instanceof Double) || (obj instanceof Integer)) { + this.type = NUMBER; + } else if (obj instanceof String) { + this.type = NAME; + } else if (obj instanceof PDFObject[]) { + this.type = ARRAY; + } else if (obj instanceof Object[]) { + Object[] srcary = (Object[]) obj; + PDFObject[] dstary = new PDFObject[srcary.length]; + for (int i = 0; i < srcary.length; i++) { + dstary[i] = new PDFObject(srcary[i]); + } + value = dstary; + this.type = ARRAY; + } else if (obj instanceof HashMap) { + this.type = DICTIONARY; + } else if (obj instanceof Boolean) { + this.type = BOOLEAN; + } else if (obj instanceof PDFParser.Tok) { + PDFParser.Tok tok = (PDFParser.Tok) obj; + if (tok!=null && tok.name!=null && tok.name.equals("true")) { + this.value = Boolean.TRUE; + this.type = BOOLEAN; + } else if (tok!=null && tok.name!=null && tok.name.equals("false")) { + this.value = Boolean.FALSE; + this.type = BOOLEAN; + } else { + this.value = tok.name; + this.type = NAME; + } + } else { + throw new PDFParseException("Bad type for raw PDFObject: " + obj); + } + } + + /** + * create a new PDFObject based on a PDFXref + * @param owner the PDFFile from which the PDFXref was drawn + * @param xref the PDFXref to turn into a PDFObject + */ + public PDFObject(PDFFile owner, PDFXref xref) { + this.type = INDIRECT; + this.value = xref; + this.owner = owner; + } + + /** + * Convenient method to get a dictionary value as String + * @param name of the dictionary value + * @return the value or null if no entry exists with that name + * @throws IOException + */ + public String getDictRefAsString(String name) throws IOException { + PDFObject ref = getDictRef(name); + return ref == null ? null : ref.getStringValue(); + } + + /** + * Convenient method to get a dictionary value as String + * @param name of the dictionary value + * @return the value or null if no entry exists with that name + * @throws IOException + */ + public Boolean getDictRefAsBoolean(String name) throws IOException { + PDFObject ref = getDictRef(name); + return ref == null ? null : ref.getBooleanValue(); + } + + /** + * Convenient method to get a dictionary value as Integer + * @param name of the dictionary value + * @return the value or null if no entry exists with that name + * @throws IOException + */ + public Integer getDictRefAsInt(String name) throws IOException { + PDFObject ref = getDictRef(name); + return ref == null ? null : ref.getIntValue(); + } + + /** + * Convenient method to get a dictionary value as int[] + * @param name of the dictionary value + * @return the value or null if no entry exists with that name + * @throws IOException + */ + public int[] getDictRefAsIntArray(String name) throws IOException { + PDFObject ref = getDictRef(name); + if (ref == null) { + return null; + } + PDFObject[] values = ref.getArray(); + int[] result = new int[values.length]; + for (int i = 0; i < values.length; i++) { + result[i] = values[i].getIntValue(); + } + return result; + } + + /** + * Convenient method to get a dictionary value as float[] + * @param name of the dictionary value + * @return the value or null if no entry exists with that name + * @throws IOException + */ + public float[] getDictRefAsFloatArray(String name) throws IOException { + PDFObject ref = getDictRef(name); + if (ref == null) { + return null; + } + PDFObject[] values = ref.getArray(); + float[] result = new float[values.length]; + for (int i = 0; i < values.length; i++) { + result[i] = values[i].getFloatValue(); + } + return result; + } + + + /** + * Convenient method to get a dictionary value as Float + * @param name of the dictionary value + * @return the value or null if no entry exists with that name + * @throws IOException + */ + public Float getDictRefAsFloat(String name) throws IOException { + PDFObject ref = getDictRef(name); + return ref == null ? null : ref.getFloatValue(); + } + + /** + * Convenient method to get a dictionary value as Double + * @param name of the dictionary value + * @return the value or null if no entry exists with that name + * @throws IOException + */ + public Double getDictRefAsDouble(String name) throws IOException { + PDFObject ref = getDictRef(name); + return ref == null ? null : ref.getDoubleValue(); + } + + /** + * get the type of this object. The object will be + * dereferenced, so INDIRECT will never be returned. + * @return the type of the object + */ + public int getType() throws IOException { + if (type == INDIRECT) { + return dereference().getType(); + } + + return type; + } + + /** + * set the stream of this object. It should have been + * a DICTIONARY before the call. + * @param data the data, as a ByteBuffer. + */ + public void setStream(ByteBuffer data) { + this.type = STREAM; + this.stream = data; + } + + /** + * get the value in the cache. May become null at any time. + * @return the cached value, or null if the value has been + * garbage collected. + */ + public Object getCache() throws IOException { + if (type == INDIRECT) { + return dereference().getCache(); + } else if (cache != null) { + return cache.get(); + } else { + return null; + } + } + + /** + * set the cached value. The object may be garbage collected + * if no other reference exists to it. + * @param obj the object to be cached + */ + public void setCache(Object obj) throws IOException { + if (type == INDIRECT) { + dereference().setCache(obj); + return; + } else { + cache = new SoftReference(obj); + } + } + + public byte[] getStream(Set filterLimits) throws IOException + { + if (type == INDIRECT) { + return dereference().getStream(filterLimits); + } else if (type == STREAM && stream != null) { + byte[] data = null; + + synchronized (stream) { + // decode + ByteBuffer streamBuf = decodeStream(filterLimits); + // ByteBuffer streamBuf = stream; + + // First try to use the array with no copying. This can only + // be done if the buffer has a backing array, and is not a slice + if (streamBuf.hasArray() && streamBuf.arrayOffset() == 0) { + byte[] ary = streamBuf.array(); + + // make sure there is no extra data in the buffer + if (ary.length == streamBuf.remaining()) { + return ary; + } + } + + // Can't use the direct buffer, so copy the data (bad) + data = new byte[streamBuf.remaining()]; + streamBuf.get(data); + + // return the stream to its starting position + streamBuf.flip(); + } + + return data; + } else if (type == STRING) { + return PDFStringUtil.asBytes(getStringValue()); + } else { + // wrong type + return null; + } + } + + /** + * get the stream from this object. Will return null if this + * object isn't a STREAM. + * @return the stream, or null, if this isn't a STREAM. + */ + public byte[] getStream() throws IOException { + return getStream(Collections.emptySet()); + } + + /** + * get the stream from this object as a byte buffer. Will return null if + * this object isn't a STREAM. + * @return the buffer, or null, if this isn't a STREAM. + */ + public ByteBuffer getStreamBuffer() throws IOException { + return getStreamBuffer(Collections.emptySet()); + } + + /** + * get the stream from this object as a byte buffer. Will return null if + * this object isn't a STREAM. + * @return the buffer, or null, if this isn't a STREAM. + */ + public ByteBuffer getStreamBuffer(Set filterLimits) throws IOException { + if (type == INDIRECT) { + return dereference().getStreamBuffer(filterLimits); + } else if (type == STREAM && stream != null) { + synchronized (stream) { + ByteBuffer streamBuf = decodeStream(filterLimits); + // ByteBuffer streamBuf = stream; + return streamBuf.duplicate(); + } + } else if (type == STRING) { + String src = getStringValue(); + return ByteBuffer.wrap(src.getBytes()); + } + + // wrong type + return null; + } + + /** + * Get the decoded stream value + */ + private ByteBuffer decodeStream(Set filterLimits) throws IOException { + ByteBuffer outStream = null; + + // first try the cache + if (decodedStream != null && filterLimits.equals(decodedStreamFilterLimits)) { + outStream = (ByteBuffer) decodedStream.get(); + } + + // no luck in the cache, do the actual decoding + if (outStream == null) { + stream.rewind(); + outStream = PDFDecoder.decodeStream(this, stream, filterLimits); + decodedStreamFilterLimits = new HashSet(filterLimits); + decodedStream = new SoftReference(outStream); + } + + return outStream; + } + + /** + * get the value as an int. Will return 0 if this object + * isn't a NUMBER. + */ + public int getIntValue() throws IOException { + if (type == INDIRECT) { + return dereference().getIntValue(); + } else if (type == NUMBER) { + return ((Number) value).intValue(); + } + + // wrong type + return 0; + } + + /** + * get the value as a float. Will return 0 if this object + * isn't a NUMBER + */ + public float getFloatValue() throws IOException { + if (type == INDIRECT) { + return dereference().getFloatValue(); + } else if (type == NUMBER) { + return ((Double) value).floatValue(); + } + + // wrong type + return 0; + } + + /** + * get the value as a double. Will return 0 if this object + * isn't a NUMBER. + */ + public double getDoubleValue() throws IOException { + if (type == INDIRECT) { + return dereference().getDoubleValue(); + } else if (type == NUMBER) { + return ((Number) value).doubleValue(); + } + + // wrong type + return 0; + } + + /** + * get the value as a String. Will return null if the object + * isn't a STRING, NAME, or KEYWORD. This method will NOT + * convert a NUMBER to a String. If the string is actually + * a text string (i.e., may be encoded in UTF16-BE or PdfDocEncoding), + * then one should use {@link #getTextStringValue()} or use one + * of the {@link PDFStringUtil} methods on the result from this + * method. The string value represents exactly the sequence of 8 bit + * characters present in the file, decrypted and decoded as appropriate, + * into a string containing only 8 bit character values - that is, each + * char will be between 0 and 255. + */ + public String getStringValue() throws IOException { + if (type == INDIRECT) { + return dereference().getStringValue(); + } else if (type == STRING || type == NAME || type == KEYWORD) { + return (String) value; + } + + // wrong type + return null; + } + + /** + * Get the value as a text string; i.e., a string encoded in UTF-16BE + * or PDFDocEncoding. Simple latin alpha-numeric characters are preserved in + * both these encodings. + * @return the text string value + * @throws IOException + */ + public String getTextStringValue() throws IOException { + return PDFStringUtil.asTextString(getStringValue()); + } + + /** + * get the value as a PDFObject[]. If this object is an ARRAY, + * will return the array. Otherwise, will return an array + * of one element with this object as the element. + */ + public PDFObject[] getArray() throws IOException { + if (type == INDIRECT) { + return dereference().getArray(); + } else if (type == ARRAY) { + PDFObject[] ary = (PDFObject[]) value; + return ary; + } else { + PDFObject[] ary = new PDFObject[1]; + ary[0] = this; + return ary; + } + } + + /** + * get the value as a boolean. Will return false if this + * object is not a BOOLEAN + */ + public boolean getBooleanValue() throws IOException { + if (type == INDIRECT) { + return dereference().getBooleanValue(); + } else if (type == BOOLEAN) { + return value == Boolean.TRUE; + } + + // wrong type + return false; + } + + /** + * if this object is an ARRAY, get the PDFObject at some + * position in the array. If this is not an ARRAY, returns + * null. + */ + public PDFObject getAt(int idx) throws IOException { + if (type == INDIRECT) { + return dereference().getAt(idx); + } else if (type == ARRAY) { + PDFObject[] ary = (PDFObject[]) value; + return ary[idx]; + } + + // wrong type + return null; + } + + /** + * get an Iterator over all the keys in the dictionary. If + * this object is not a DICTIONARY or a STREAM, returns an + * Iterator over the empty list. + */ + public Iterator getDictKeys() throws IOException { + if (type == INDIRECT) { + return dereference().getDictKeys(); + } else if (type == DICTIONARY || type == STREAM) { + return ((HashMap) value).keySet().iterator(); + } + + // wrong type + return new ArrayList().iterator(); + } + + /** + * get the dictionary as a HashMap. If this isn't a DICTIONARY + * or a STREAM, returns null + */ + public HashMap getDictionary() throws IOException { + if (type == INDIRECT) { + return dereference().getDictionary(); + } else if (type == DICTIONARY || type == STREAM) { + return (HashMap) value; + } + + // wrong type + return new HashMap(); + } + + /** + * get the value associated with a particular key in the + * dictionary. If this isn't a DICTIONARY or a STREAM, + * or there is no such key, returns null. + */ + public PDFObject getDictRef(String key) throws IOException { + if (type == INDIRECT) { + return dereference().getDictRef(key); + } else if (type == DICTIONARY || type == STREAM) { + key = key.intern(); + HashMap h = (HashMap) value; + PDFObject obj = (PDFObject) h.get(key.intern()); + return obj; + } + + // wrong type + return null; + } + + /** + * returns true only if this object is a DICTIONARY or a + * STREAM, and the "Type" entry in the dictionary matches a + * given value. + * @param match the expected value for the "Type" key in the + * dictionary + * @return whether the dictionary is of the expected type + */ + public boolean isDictType(String match) throws IOException { + if (type == INDIRECT) { + return dereference().isDictType(match); + } else if (type != DICTIONARY && type != STREAM) { + return false; + } + + PDFObject obj = getDictRef("Type"); + return obj != null && obj.getStringValue().equals(match); + } + + public PDFDecrypter getDecrypter() { + // PDFObjects without owners are always created as part of + // content instructions. Such an object will never have encryption + // applied to it, as the stream that contains it is the + // unit of encryption, with no further encryption being applied + // within. So if someone asks for the decrypter for + // one of these in-stream objects, no decryption should + // ever be applied. This can be seen with inline images. + return owner != null ? + owner.getDefaultDecrypter() : + IdentityDecrypter.getInstance(); + } + + /** + * Set the object identifiers + * @param objNum the object number + * @param objGen the object generation number + */ + public void setObjectId(int objNum, int objGen) { + assert objNum >= OBJ_NUM_TRAILER; + assert objGen >= OBJ_NUM_TRAILER; + this.objNum = objNum; + this.objGen = objGen; + } + + /** + * Get the object number of this object; a negative value indicates that + * the object is not numbered, as it's not a top-level object: if the value + * is {@link #OBJ_NUM_EMBEDDED}, it is because it's embedded within + * another object. If the value is {@link #OBJ_NUM_TRAILER}, it's because + * it's an object from the trailer. + * @return the object number, if positive + */ + public int getObjNum() { + return objNum; + } + + /** + * Get the object generation number of this object; a negative value + * indicates that the object is not numbered, as it's not a top-level + * object: if the value is {@link #OBJ_NUM_EMBEDDED}, it is because it's + * embedded within another object. If the value is {@link + * #OBJ_NUM_TRAILER}, it's because it's an object from the trailer. + * @return the object generation number, if positive + */ + public int getObjGen() { + return objGen; + } + + /** + * return a representation of this PDFObject as a String. + * Does NOT dereference anything: this is the only method + * that allows you to distinguish an INDIRECT PDFObject. + */ + @Override + public String toString() { + try { + if (type == INDIRECT) { + StringBuffer str = new StringBuffer (); + str.append("Indirect to #" + ((PDFXref) value).getID()); + try { + str.append("\n" + dereference().toString()); + } catch (Throwable t) { + str.append(t.toString()); + } + return str.toString(); + } else if (type == BOOLEAN) { + return "Boolean: " + (getBooleanValue() ? "true" : "false"); + } else if (type == NUMBER) { + return "Number: " + getDoubleValue(); + } else if (type == STRING) { + return "String: " + getStringValue(); + } else if (type == NAME) { + return "Name: /" + getStringValue(); + } else if (type == ARRAY) { + return "Array, length=" + ((PDFObject[]) value).length; + } else if (type == DICTIONARY) { + StringBuffer sb = new StringBuffer(); + PDFObject obj = getDictRef("Type"); + if (obj != null) { + sb.append(obj.getStringValue()); + obj = getDictRef("Subtype"); + if (obj == null) { + obj = getDictRef("S"); + } + if (obj != null) { + sb.append("/" + obj.getStringValue()); + } + } else { + sb.append("Untyped"); + } + sb.append(" dictionary. Keys:"); + HashMap hm = (HashMap) value; + Iterator it = hm.entrySet().iterator(); + Map.Entry entry; + while (it.hasNext()) { + entry = (Map.Entry) it.next(); + sb.append("\n " + entry.getKey() + " " + entry.getValue()); + } + return sb.toString(); + } else if (type == STREAM) { + byte[] st = getStream(); + if (st == null) { + return "Broken stream"; + } + return "Stream: [[" + new String(st, 0, st.length > 30 ? 30 : st.length) + "]]"; + } else if (type == NULL) { + return "Null"; + } else if (type == KEYWORD) { + return "Keyword: " + getStringValue(); + /* } else if (type==IMAGE) { + StringBuffer sb= new StringBuffer(); + java.awt.Image im= (java.awt.Image)stream; + sb.append("Image ("+im.getWidth(null)+"x"+im.getHeight(null)+", with keys:"); + HashMap hm= (HashMap)value; + Iterator it= hm.keySet().iterator(); + while(it.hasNext()) { + sb.append(" "+(String)it.next()); + } + return sb.toString();*/ + } else { + return "Whoops! big error! Unknown type"; + } + } catch (IOException ioe) { + return "Caught an error: " + ioe; + } + } + + /** + * Make sure that this object is dereferenced. Use the cache of + * an indirect object to cache the dereferenced value, if possible. + */ + public PDFObject dereference() throws IOException { + if (type == INDIRECT) { + PDFObject obj = null; + + if (cache != null) { + obj = (PDFObject) cache.get(); + } + + if (obj == null || obj.value == null) { + if (owner == null) { + PDFDebugger.debug("Bad seed (owner==null)! Object=" + this); + } + + obj = owner.dereference((PDFXref)value, getDecrypter()); + + cache = new SoftReference(obj); + } + + return obj; + } else { + // not indirect, no need to dereference + return this; + } + } + + /** + * Identify whether the object is currently an indirect/cross-reference + * @return whether currently indirect + */ + public boolean isIndirect() { + return (type == INDIRECT); + } + + /** + * Test whether two PDFObject are equal. Objects are equal IFF they + * are the same reference OR they are both indirect objects with the + * same id and generation number in their xref + */ + @Override + public boolean equals(Object o) { + if (super.equals(o)) { + // they are the same object + return true; + } else if (type == INDIRECT && o instanceof PDFObject) { + // they are both PDFObjects. Check type and xref. + PDFObject obj = (PDFObject) o; + + if (obj.type == INDIRECT) { + PDFXref lXref = (PDFXref) value; + PDFXref rXref = (PDFXref) obj.value; + + return ((lXref.getID() == rXref.getID()) && + (lXref.getGeneration() == rXref.getGeneration())); + } + } + + return false; + } + + /** + * Returns the root of this object. + * @return + */ + public PDFObject getRoot() { + return owner.getRoot(); + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFPage.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFPage.java new file mode 100644 index 000000000..ae44df772 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFPage.java @@ -0,0 +1,965 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.sun.pdfview; +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Image; +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.geom.GeneralPath; +import java.awt.geom.NoninvertibleTransformException; +import java.awt.geom.Rectangle2D; +import java.awt.image.BufferedImage; +import java.awt.image.ImageObserver; +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import com.sun.pdfview.annotation.AnnotationType; +import com.sun.pdfview.annotation.PDFAnnotation; + +/** +* A PDFPage encapsulates the parsed commands required to render a +* single page from a PDFFile. The PDFPage is not itself drawable; +* instead, create a PDFImage to display something on the screen. +*

+* This file also contains all of the PDFCmd commands that might be a part of the command stream in +* a PDFPage. They probably should be inner classes of PDFPage instead of separate non-public +* classes. +* +* @author Mike Wessler +*/ +public class PDFPage { + /** + * the array of commands. The length of this array will always + * be greater than or equal to the actual number of commands. + */ + private final List commands; + /** + * whether this page has been finished. If true, there will be no + * more commands added to the cmds list. + */ + private boolean finished = false; + /** the page number used to find this page */ + private final int pageNumber; + /** the bounding box of the page, in page coordinates */ + private final Rectangle2D bbox; + /** the rotation of this page, in degrees */ + private final int rotation; + /** + * a map from image info (width, height, clip) to a soft reference to the + * rendered image + */ + private final Cache cache; + /** a map from image info to weak references to parsers that are active */ + public Map> renderers; + /** List of annotations for this page */ + private List annots; + + /** + * create a PDFPage with dimensions in bbox and rotation. + */ + public PDFPage(Rectangle2D bbox, int rotation) { + this(-1, bbox, rotation, null); + } + + /** + * create a PDFPage with dimensions in bbox and rotation. + */ + public PDFPage(int pageNumber, Rectangle2D bbox, int rotation, Cache cache) { + this.pageNumber = pageNumber; + this.cache = cache; + if (bbox == null) { + bbox = new Rectangle2D.Float(0, 0, 1, 1); + } + rotation = rotation % 360; // less than a full turn + if (rotation < 0) { + rotation += 360; + } + rotation = rotation / 90; // for page rotation use only multiples of 90 degrees + rotation = rotation * 90; // 0, 90, 180, 270 + this.rotation = rotation; + if (rotation == 90 || rotation == 270) { + bbox = new Rectangle2D.Double(bbox.getX(), bbox.getY(), bbox.getHeight(), bbox.getWidth()); + } + this.bbox = bbox; + // initialize the cache of images and parsers + this.renderers = Collections.synchronizedMap(new HashMap>()); + // initialize the list of commands + this.commands = Collections.synchronizedList(new ArrayList(250)); + // corresponding pop in PDFParser -> setStatus + this.addPush(); + } + + /** + * Get the width and height of this image in the correct aspect ratio. + * The image returned will have at least one of the width and + * height values identical to those requested. The other + * dimension may be smaller, so as to keep the aspect ratio + * the same as in the original page. + * + * @param width + * the maximum width of the image + * @param height + * the maximum height of the image + * @param clip + * the region in page space of the page to + * display. It may be null, in which the page's defined crop box + * will be used. + */ + public Dimension getUnstretchedSize(int width, int height, Rectangle2D clip) { + if (clip == null) { + clip = this.bbox; + } else { + if (getRotation() == 90 || getRotation() == 270) { + clip = new Rectangle2D.Double(clip.getX(), clip.getY(), clip.getHeight(), clip.getWidth()); + } + } + double ratio = clip.getHeight() / clip.getWidth(); + double askratio = (double) height / (double) width; + if (askratio > ratio) { + // asked for something too high + height = (int) (width * ratio + 0.5); + } else { + // asked for something too wide + width = (int) (height / ratio + 0.5); + } + return new Dimension(width, height); + } + + /** + * Get an image producer which can be used to draw the image + * represented by this PDFPage. The ImageProducer is guaranteed to + * stay in sync with the PDFPage as commands are added to it. + * + * The image will contain the section of the page specified by the clip, + * scaled to fit in the area given by width and height. + * + * @param width + * the width of the image to be produced + * @param height + * the height of the image to be produced + * @param clip + * the region in page space of the entire page to + * display + * @param observer + * an image observer who will be notified when the + * image changes, or null + * @return an Image that contains the PDF data + */ + public Image getImage(int width, int height, Rectangle2D clip, ImageObserver observer) { + return getImage(width, height, clip, observer, true, false); + } + + /** + * Get an image producer which can be used to draw the image + * represented by this PDFPage. The ImageProducer is guaranteed to + * stay in sync with the PDFPage as commands are added to it. + * + * The image will contain the section of the page specified by the clip, + * scaled to fit in the area given by width and height. + * + * @param width + * the width of the image to be produced + * @param height + * the height of the image to be produced + * @param clip + * the region in page space of the entire page to + * display + * @param observer + * an image observer who will be notified when the + * image changes, or null + * @param drawbg + * if true, put a white background on the image. If not, + * draw no color (alpha 0) for the background. + * @param wait + * if true, do not return until this image is fully rendered. + * @return an Image that contains the PDF data + */ + public Image getImage(int width, int height, Rectangle2D clip, ImageObserver observer, boolean drawbg, boolean wait) { + // see if we already have this image + BufferedImage image = null; + PDFRenderer renderer = null; + ImageInfo info = new ImageInfo(width, height, clip, null); + if (this.cache != null) { + image = this.cache.getImage(this, info); + renderer = this.cache.getImageRenderer(this, info); + } + // not in the cache, so create it + if (image == null) { + if (drawbg) { + info.bgColor = Color.WHITE; + } + image = new RefImage(info.width, info.height, BufferedImage.TYPE_INT_ARGB); + renderer = new PDFRenderer(this, info, image); + if (this.cache != null) { + this.cache.addImage(this, info, image, renderer); + } + this.renderers.put(info, new WeakReference(renderer)); + } + // the renderer may be null if we are getting this image from the + // cache and rendering has completed. + if (renderer != null) { + if (observer != null) { + renderer.addObserver(observer); + } + + if (!renderer.isFinished()) { + renderer.go(wait); + if (renderer.getStatus() == Watchable.ERROR) { + PDFDebugger.debug("Error during reading image!"); + } + } + } + // return the image + return image; + } + + /** + * get the page number used to lookup this page + * + * @return the page number + */ + public int getPageNumber() { + return this.pageNumber; + } + + /** + * get the aspect ratio of the correctly oriented page. + * + * @return the width/height aspect ratio of the page + */ + public float getAspectRatio() { + return getWidth() / getHeight(); + } + + /** + * get the bounding box of the page, before any rotation. + */ + public Rectangle2D getBBox() { + return this.bbox; + } + + /** + * get the width of this page, after rotation + */ + public float getWidth() { + return (float) this.bbox.getWidth(); + } + + /** + * get the height of this page, after rotation + */ + public float getHeight() { + return (float) this.bbox.getHeight(); + } + + /** + * get the rotation of this image + */ + public int getRotation() { + return this.rotation; + } + + /** + * Get the initial transform to map from a specified clip rectangle in + * pdf coordinates to an image of the specfied width and + * height in device coordinates + * + * @param width + * the width of the image + * @param height + * the height of the image + * @param clip + * the desired clip rectangle (in PDF space) or null to use + * the page's bounding box + */ + public AffineTransform getInitialTransform(int width, int height, Rectangle2D clip) { + AffineTransform at = new AffineTransform(); + switch (getRotation()) { + case 0: + at = new AffineTransform(1, 0, 0, -1, 0, height); + break; + case 90: + at = new AffineTransform(0, 1, 1, 0, 0, 0); + break; + case 180: + at = new AffineTransform(-1, 0, 0, 1, width, 0); + break; + case 270: + at = new AffineTransform(0, -1, -1, 0, width, height); + break; + } + double clipW; + double clipH; + if (clip == null) { + clip = getBBox(); + clipW = clip.getWidth(); + clipH = clip.getHeight(); + } else if (getRotation() == 90 || getRotation() == 270) { + int tmp = width; + width = height; + height = tmp; + clipW = clip.getHeight(); + clipH = clip.getWidth(); + } else { + clipW = clip.getWidth(); + clipH = clip.getHeight(); + } + // now scale the image to be the size of the clip + double scaleX = width / clipW; + double scaleY = height / clipH; + at.scale(scaleX, scaleY); + // create a transform that moves the top left corner of the clip region + // (minX, minY) to (0,0) in the image + at.translate(-clip.getMinX(), -clip.getMinY()); + return at; + } + + /** + * get the current number of commands for this page + */ + public int getCommandCount() { + return this.commands.size(); + } + + /** + * get the command at a given index + */ + public PDFCmd getCommand(int index) { + return this.commands.get(index); + } + + /** + * get all the commands in the current page + */ + public List getCommands() { + return this.commands; + } + + /** + * get all the commands in the current page starting at the given index + */ + public List getCommands(int startIndex) { + return getCommands(startIndex, getCommandCount()); + } + + /* + * get the commands in the page within the given start and end indices + */ + public List getCommands(int startIndex, int endIndex) { + return this.commands.subList(startIndex, endIndex); + } + + public PDFCmd findLastCommand(Class cls) { + int index = this.commands.size(); + while (index-- > 0) { + PDFCmd cmd = this.commands.get(index); + if (cmd.getClass().isAssignableFrom(cls)) { + return cmd; + } + } + return null; + } + + /** + * Add a single command to the page list. + */ + public void addCommand(PDFCmd cmd) { + synchronized (this.commands) { + this.commands.add(cmd); + } + // notify any outstanding images + updateImages(); + } + + /** + * add a collection of commands to the page list. This is probably + * invoked as the result of an XObject 'do' command, or through a + * type 3 font. + */ + public void addCommands(PDFPage page) { + addCommands(page, null); + } + + /** + * add a collection of commands to the page list. This is probably + * invoked as the result of an XObject 'do' command, or through a + * type 3 font. + * + * @param page + * the source of other commands. It MUST be finished. + * @param extra + * a transform to perform before adding the commands. + * If null, no extra transform will be added. + */ + public void addCommands(PDFPage page, AffineTransform extra) { + synchronized (this.commands) { + addPush(); + if (extra != null) { + addXform(extra); + } + // addXform(page.getTransform()); + this.commands.addAll(page.getCommands()); + addPop(); + } + // notify any outstanding images + updateImages(); + } + + /** + * Clear all commands off the current page + */ + public void clearCommands() { + synchronized (this.commands) { + this.commands.clear(); + } + // notify any outstanding images + updateImages(); + } + + /** + * get whether parsing for this PDFPage has been completed and all + * commands are in place. + */ + public boolean isFinished() { + return this.finished; + } + + /** + * wait for finish + */ + public synchronized void waitForFinish() throws InterruptedException { + if (!this.finished) { + wait(); + } + } + + /** + * Stop the rendering of a particular image on this page + */ + public void stop(int width, int height, Rectangle2D clip) { + ImageInfo info = new ImageInfo(width, height, clip); + synchronized (this.renderers) { + // find our renderer + WeakReference rendererRef = this.renderers.get(info); + if (rendererRef != null) { + PDFRenderer renderer = (PDFRenderer) rendererRef.get(); + if (renderer != null) { + // stop it + renderer.stop(); + } + } + } + } + + /** + * The entire page is done. This must only be invoked once. All + * observers will be notified. + */ + public synchronized void finish() { + PDFDebugger.debug("Page finished!", 1000); + this.finished = true; + notifyAll(); + // notify any outstanding images + updateImages(); + } + + /** push the graphics state */ + public void addPush() { + addCommand(new PDFPushCmd()); + } + + /** pop the graphics state */ + public void addPop() { + addCommand(new PDFPopCmd()); + } + + /** concatenate a transform to the graphics state */ + public void addXform(AffineTransform at) { + // PDFXformCmd xc= lastXformCmd(); + // xc.at.concatenate(at); + addCommand(new PDFXformCmd(new AffineTransform(at))); + } + + /** + * set the stroke width + * + * @param w + * the width of the stroke + */ + public PDFChangeStrokeCmd addStrokeWidth(float w) { + PDFChangeStrokeCmd sc = new PDFChangeStrokeCmd(); + // if (w == 0) { + // w = 0.1f; + // } + sc.setWidth(w); + addCommand(sc); + return sc; + } + + /** + * set the end cap style + * + * @param capstyle + * the cap style: 0 = BUTT, 1 = ROUND, 2 = SQUARE + */ + public void addEndCap(int capstyle) { + PDFChangeStrokeCmd sc = new PDFChangeStrokeCmd(); + int cap = BasicStroke.CAP_BUTT; + switch (capstyle) { + case 0: + cap = BasicStroke.CAP_BUTT; + break; + case 1: + cap = BasicStroke.CAP_ROUND; + break; + case 2: + cap = BasicStroke.CAP_SQUARE; + break; + } + sc.setEndCap(cap); + addCommand(sc); + } + + /** + * set the line join style + * + * @param joinstyle + * the join style: 0 = MITER, 1 = ROUND, 2 = BEVEL + */ + public void addLineJoin(int joinstyle) { + PDFChangeStrokeCmd sc = new PDFChangeStrokeCmd(); + int join = BasicStroke.JOIN_MITER; + switch (joinstyle) { + case 0: + join = BasicStroke.JOIN_MITER; + break; + case 1: + join = BasicStroke.JOIN_ROUND; + break; + case 2: + join = BasicStroke.JOIN_BEVEL; + break; + } + sc.setLineJoin(join); + addCommand(sc); + } + + /** + * set the miter limit + */ + public void addMiterLimit(float limit) { + PDFChangeStrokeCmd sc = new PDFChangeStrokeCmd(); + sc.setMiterLimit(limit); + addCommand(sc); + } + + /** + * set the dash style + * + * @param dashary + * the array of on-off lengths + * @param phase + * offset of the array at the start of the line drawing + */ + public void addDash(float[] dashary, float phase) { + PDFChangeStrokeCmd sc = new PDFChangeStrokeCmd(); + sc.setDash(dashary, phase); + addCommand(sc); + } + + /** + * set the current path + * + * @param path + * the path + * @param style + * the style: PDFShapeCmd.STROKE, PDFShapeCmd.FILL, + * @param autoAdjustStroke + * PDFShapeCmd.BOTH, PDFShapeCmd.CLIP, or some combination. + */ + public void addPath(GeneralPath path, int style, boolean autoAdjustStroke) { + addCommand(new PDFShapeCmd(path, style, autoAdjustStroke)); + } + + public void addShadeCommand(PDFPaint p, Rectangle2D box) { + addCommand(new PDFShadeCommand(p, box)); + } + + /** + * set the fill paint + */ + public void addFillPaint(PDFPaint p) { + addCommand(new PDFFillPaintCmd(p)); + } + + /** set the stroke paint */ + public void addStrokePaint(PDFPaint p) { + addCommand(new PDFStrokePaintCmd(p)); + } + + /** + * set the fill alpha + */ + public void addFillAlpha(float a) { + addCommand(new PDFFillAlphaCmd(a)); + } + + /** set the stroke alpha */ + public void addStrokeAlpha(float a) { + addCommand(new PDFStrokeAlphaCmd(a)); + } + + /** + * draw an image + * + * @param image + * the image to draw + */ + public void addImage(PDFImage image) { + addCommand(new PDFImageCmd(image)); + } + + /** + * Notify all images we know about that a command has been added + */ + public void updateImages() { + for (Iterator> i = this.renderers.values().iterator(); i.hasNext();) { + WeakReference ref = i.next(); + PDFRenderer renderer = (PDFRenderer) ref.get(); + if (renderer != null) { + if (renderer.getStatus() == Watchable.NEEDS_DATA) { + // there are watchers. Set the state to paused and + // let the watcher decide when to start. + renderer.setStatus(Watchable.PAUSED); + } + } + } + } + + /************************************************************************* + * Get a list of all annotations for this PDF page + * + * @return List + ************************************************************************/ + public List getAnnots() { + return this.annots; + } + + /************************************************************************* + * Get a list of all annotations of the given type for this PDF page + * + * @return List + ************************************************************************/ + public List getAnnots(AnnotationType type) { + List list = new ArrayList(); + if (this.annots != null) { + for (PDFAnnotation annot : this.annots) { + if (annot.getType() == type) { + list.add(annot); + } + } + } + return list; + } + + /************************************************************************* + * Set annotations for this PDF page + * + * @param annots + ************************************************************************/ + public void setAnnots(List annots) { + this.annots = annots; + } + + public void addAnnotations() { + if(this.annots != null) { + for (PDFAnnotation pdfAnnotation : this.annots) { + // add command to the page if needed + this.commands.addAll(pdfAnnotation.getPageCommandsForAnnotation()); + } + } + } + + public static PDFImageCmd createImageCmd(PDFImage image) { + return new PDFImageCmd(image); + } + + public static PDFPushCmd createPushCmd() { + return new PDFPushCmd(); + } + + public static PDFPopCmd createPopCmd() { + return new PDFPopCmd(); + } + + public static PDFXformCmd createXFormCmd(AffineTransform at) { + return new PDFXformCmd(new AffineTransform(at)); + } +} + +/** +* draw an image +*/ +class PDFImageCmd extends PDFCmd { + PDFImage image; + + public PDFImageCmd(PDFImage image) { + this.image = image; + } + + @Override + public Rectangle2D execute(PDFRenderer state) { + return state.drawImage(this.image); + } +} + +/** +* set the fill paint +*/ +class PDFFillPaintCmd extends PDFCmd { + PDFPaint p; + + public PDFFillPaintCmd(PDFPaint p) { + this.p = p; + } + + @Override + public Rectangle2D execute(PDFRenderer state) { + state.setFillPaint(this.p); + return null; + } +} + +/** +* set the stroke paint +*/ +class PDFStrokePaintCmd extends PDFCmd { + PDFPaint p; + + public PDFStrokePaintCmd(PDFPaint p) { + this.p = p; + } + + @Override + public Rectangle2D execute(PDFRenderer state) { + state.setStrokePaint(this.p); + return null; + } +} + +/** +* set the fill paint +*/ +class PDFFillAlphaCmd extends PDFCmd { + float a; + + public PDFFillAlphaCmd(float a) { + this.a = a; + } + + @Override + public Rectangle2D execute(PDFRenderer state) { + state.setFillAlpha(this.a); + return null; + } +} + +/** +* set the stroke paint +*/ +class PDFStrokeAlphaCmd extends PDFCmd { + float a; + + public PDFStrokeAlphaCmd(float a) { + this.a = a; + } + + @Override + public Rectangle2D execute(PDFRenderer state) { + state.setStrokeAlpha(this.a); + return null; + } +} + +/** +* set the shade paint +*/ +class PDFShadeCommand extends PDFCmd { + PDFPaint p; + Rectangle2D box; + + PDFShadeCommand(PDFPaint p, Rectangle2D box) { + this.p = p; + this.box = box; + } + + PDFShadeCommand(PDFPaint p) { + this.p = p; + this.box = null; + } + + @Override + public Rectangle2D execute(PDFRenderer state) { + // TODO: Not sure this is the right way to get the area for the sh cmd + Shape s = box; + Shape clip = state.getImage().getGraphics().getClipBounds(); + if (clip != null) { + s = clip; + } + if (s == null) { + s = state.getImage().getData().getBounds(); + try { + s = state.getLastTransform().createInverse().createTransformedShape(s); + } catch (NoninvertibleTransformException e) { + BaseWatchable.getErrorHandler().publishException(e); + } + } + state.setFillAlpha(1); + state.setFillPaint(p); + return (new PDFShapeCmd(new GeneralPath(s), PDFShapeCmd.FILL, false)).execute(state); + } +} + +/** +* push the graphics state +*/ +class PDFPushCmd extends PDFCmd { + @Override + public Rectangle2D execute(PDFRenderer state) { + state.push(); + return null; + } +} + +/** +* pop the graphics state +*/ +class PDFPopCmd extends PDFCmd { + @Override + public Rectangle2D execute(PDFRenderer state) { + state.pop(); + return null; + } +} + +/** +* concatenate a transform to the graphics state +*/ +class PDFXformCmd extends PDFCmd { + AffineTransform at; + + public PDFXformCmd(AffineTransform at) { + if (at == null) { + throw new RuntimeException("Null transform in PDFXformCmd"); + } + this.at = at; + } + + @Override + public Rectangle2D execute(PDFRenderer state) { + state.transform(this.at); + return null; + } + + public String toString(PDFRenderer state) { + return "PDFXformCmd: " + this.at; + } + + @Override + public String getDetails() { + StringBuffer buf = new StringBuffer(); + buf.append("PDFXformCommand: \n"); + buf.append(this.at.toString()); + return buf.toString(); + } +} + +/** +* change the stroke style +*/ +class PDFChangeStrokeCmd extends PDFCmd { + float w, limit, phase; + int cap, join; + float[] ary; + + public PDFChangeStrokeCmd() { + this.w = PDFRenderer.NOWIDTH; + this.cap = PDFRenderer.NOCAP; + this.join = PDFRenderer.NOJOIN; + this.limit = PDFRenderer.NOLIMIT; + this.ary = PDFRenderer.NODASH; + this.phase = PDFRenderer.NOPHASE; + } + + /** + * set the width of the stroke. Rendering needs to account for a minimum + * stroke width in creating the output. + * + * @param w + * float + */ + public void setWidth(float w) { + this.w = w; + } + + public void setEndCap(int cap) { + this.cap = cap; + } + + public void setLineJoin(int join) { + this.join = join; + } + + public void setMiterLimit(float limit) { + this.limit = limit; + } + + public void setDash(float[] ary, float phase) { + if (ary != null) { + // make sure no pairs start with 0, since having no opaque + // region doesn't make any sense. + for (int i = 0; i < ary.length - 1; i += 2) { + if (ary[i] == 0) { + /* Give a very small value, since 0 messes java up */ + ary[i] = 0.00001f; + break; + } + } + } + this.ary = ary; + this.phase = phase; + } + + @Override + public Rectangle2D execute(PDFRenderer state) { + state.setStrokeParts(this.w, this.cap, this.join, this.limit, this.ary, this.phase); + return null; + } + + public String toString(PDFRenderer state) { + return "STROKE: w=" + this.w + " cap=" + this.cap + " join=" + this.join + " limit=" + this.limit + " ary=" + this.ary + " phase=" + this.phase; + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFPaint.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFPaint.java new file mode 100644 index 000000000..c75a8179d --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFPaint.java @@ -0,0 +1,78 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.sun.pdfview; + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Paint; +import java.awt.geom.GeneralPath; +import java.awt.geom.Rectangle2D; + +/** + * PDFPaint is some kind of shader that knows how to fill a path. + * At the moment, only a solid color is implemented, but gradients + * and textures should be possible, too. + * @author Mike Wessler + */ +public class PDFPaint { + + private Paint mainPaint; + + /** + * create a new PDFPaint based on a solid color + */ + protected PDFPaint(Paint p) { + this.mainPaint = p; + } + + /** + * get the PDFPaint representing a solid color + */ + public static PDFPaint getColorPaint(Color c) { + return getPaint(c); + } + + /** + * get the PDFPaint representing a generic paint + */ + public static PDFPaint getPaint(Paint p) { + return new PDFPaint(p); + } + + /** + * fill a path with the paint, and record the dirty area. + * @param state the current graphics state + * @param g the graphics into which to draw + * @param s the path to fill + */ + public Rectangle2D fill(PDFRenderer state, Graphics2D g, + GeneralPath s) { + g.setPaint(this.mainPaint); + g.fill(s); + + return s.createTransformedShape(g.getTransform()).getBounds2D(); + } + + /** + * get the primary color associated with this PDFPaint. + */ + public Paint getPaint() { + return this.mainPaint; + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFParseException.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFParseException.java new file mode 100644 index 000000000..eefb190e4 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFParseException.java @@ -0,0 +1,39 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.sun.pdfview; + +import java.io.IOException; + +/** + * an exception class for recording parse errors in the PDF file + * @author Mike Wessler + */ +public class PDFParseException extends IOException { + + public PDFParseException(String msg) { + super(msg); + } + + public PDFParseException(String msg, Throwable cause) { + this(msg); + initCause(cause); + } + + +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFParser.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFParser.java new file mode 100644 index 000000000..f11b42fb7 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFParser.java @@ -0,0 +1,1537 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.sun.pdfview; +import static java.awt.geom.Path2D.WIND_EVEN_ODD; + +import java.awt.geom.AffineTransform; +import java.awt.geom.GeneralPath; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.lang.ref.WeakReference; +import java.nio.ByteBuffer; +import java.text.NumberFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Stack; + +import com.sun.pdfview.PDFDebugger.DebugStopException; +import com.sun.pdfview.colorspace.PDFColorSpace; +import com.sun.pdfview.colorspace.PatternSpace; +import com.sun.pdfview.decode.PDFDecoder; +import com.sun.pdfview.font.PDFFont; +import com.sun.pdfview.pattern.PDFShader; + +/** +* PDFParser is the class that parses a PDF content stream and +* produces PDFCmds for a PDFPage. You should never ever see it run: +* it gets created by a PDFPage only if needed, and may even run in +* its own thread. +* +* @author Mike Wessler +*/ +public class PDFParser extends BaseWatchable { + private int mDebugCommandIndex; + // ---- parsing variables + private Stack stack; // stack of Object + private Stack parserStates; // stack of RenderState + // the current render state + private ParserState state; + private GeneralPath path; + private int clip; + private int loc; + private boolean resend = false; + private Tok tok; + private boolean catchexceptions = true; // Indicates state of BX...EX + /** + * a weak reference to the page we render into. For the page + * to remain available, some other code must retain a strong reference to + * it. + */ + private final WeakReference pageRef; + /** + * the actual command, for use within a singe iteration. Note that + * this must be released at the end of each iteration to assure the + * page can be collected if not in use + */ + private PDFPage cmds; + // ---- result variables + byte[] stream; + HashMap resources; + + boolean errorwritten = false; + private boolean autoAdjustStroke = false; + private boolean strokeOverprint; + private int strokeOverprintMode; + private boolean fillOverprint; + private int fillOverprintMode; + private boolean addAnnotation; + + /** + * Don't call this constructor directly. Instead, use + * PDFFile.getPage(int pagenum) to get a PDFPage. There should + * never be any reason for a user to create, access, or hold + * on to a PDFParser. + */ + public PDFParser(PDFPage cmds, byte[] stream, HashMap resources) { + super(); + this.pageRef = new WeakReference(cmds); + this.resources = resources; + if (resources == null) { + this.resources = new HashMap(); + } + this.stream = stream; + } + + // /////////////////////////////////////////////////////////////// + // B E G I N R E A D E R S E C T I O N + // /////////////////////////////////////////////////////////////// + /** + * a token from a PDF Stream + */ + static class Tok { + /** begin bracket < */ + public static final int BRKB = 11; + /** end bracket > */ + public static final int BRKE = 10; + /** begin array [ */ + public static final int ARYB = 9; + /** end array ] */ + public static final int ARYE = 8; + /** String (, readString looks for trailing ) */ + public static final int STR = 7; + /** begin brace { */ + public static final int BRCB = 5; + /** end brace } */ + public static final int BRCE = 4; + /** number */ + public static final int NUM = 3; + /** keyword */ + public static final int CMD = 2; + /** name (begins with /) */ + public static final int NAME = 1; + /** unknown token */ + public static final int UNK = 0; + /** end of stream */ + public static final int EOF = -1; + /** the string value of a STR, NAME, or CMD token */ + public String name; + /** the value of a NUM token */ + public double value; + /** the type of the token */ + public int type; + + /** a printable representation of the token */ + @Override + public String toString() { + if (this.type == NUM) { + return "NUM: " + this.value; + } else if (this.type == CMD) { + return "CMD: " + this.name; + } else if (this.type == UNK) { + return "UNK"; + } else if (this.type == EOF) { + return "EOF"; + } else if (this.type == NAME) { + return "NAME: " + this.name; + } else if (this.type == CMD) { + return "CMD: " + this.name; + } else if (this.type == STR) { + return "STR: (" + this.name; + } else if (this.type == ARYB) { + return "ARY ["; + } else if (this.type == ARYE) { + return "ARY ]"; + } else { + return "some kind of brace (" + this.type + ")"; + } + } + + /** + * reset the token to it's original state + */ + public void reset() { + name = null; + value = 0.0; + type = UNK; + } + } + + /** + * get the next token. + */ + private Tok nextToken() { + if (this.resend) { + this.resend = false; + return this.tok; + } + if (this.tok != null) { + this.tok.reset(); + } else { + tok = new Tok(); + } + // skip whitespace + while (this.loc < this.stream.length && PDFFile.isWhiteSpace(this.stream[this.loc])) { + this.loc++; + } + if (this.loc >= this.stream.length) { + this.tok.type = Tok.EOF; + return this.tok; + } + int c = this.stream[this.loc++]; + // examine the character: + while (c == '%' || c == 28) { + // skip comments + StringBuffer comment = new StringBuffer(); + while (this.loc < this.stream.length && c != '\n') { + comment.append((char) c); + c = this.stream[this.loc++]; + } + if (this.loc < this.stream.length) { + c = this.stream[this.loc++]; // eat the newline + if (c == '\r') { + c = this.stream[this.loc++]; // eat a following return + } + // skip whitespace + while (this.loc < this.stream.length && PDFFile.isWhiteSpace(c)) { + c = this.stream[this.loc++]; + } + } + PDFDebugger.debug("Read comment: " + comment.toString(), -1); + } + if (c == '[') { + this.tok.type = Tok.ARYB; + } else if (c == ']') { + this.tok.type = Tok.ARYE; + } else if (c == '(') { + // read a string + this.tok.type = Tok.STR; + this.tok.name = readString(); + } else if (c == '{') { + this.tok.type = Tok.BRCB; + } else if (c == '}') { + this.tok.type = Tok.BRCE; + } else if (c == '<' && this.stream[this.loc++] == '<') { + this.tok.type = Tok.BRKB; + } else if (c == '>' && this.stream[this.loc++] == '>') { + this.tok.type = Tok.BRKE; + } else if (c == '<') { + this.loc--; + this.tok.type = Tok.STR; + this.tok.name = readByteArray(); + } else if (c == '/') { + this.tok.type = Tok.NAME; + this.tok.name = readName(); + } else if (c == '.' || c == '-' || (c >= '0' && c <= '9')) { + this.loc--; + this.tok.type = Tok.NUM; + this.tok.value = readNum(); + } else if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '\'' || c == '"') { + this.loc--; + this.tok.type = Tok.CMD; + this.tok.name = readName(); + } else { + PDFDebugger.debug("Encountered character: " + c + " (" + (char) c + ")", 1); + this.tok.type = Tok.UNK; + } + return this.tok; + } + + /** + * read a name (sequence of non-PDF-delimiting characters) from the + * stream. + */ + private String readName() { + int start = this.loc; + while (this.loc < this.stream.length && PDFFile.isRegularCharacter(this.stream[this.loc])) { + this.loc++; + } + return new String(this.stream, start, this.loc - start); + } + + /** + * read a floating point number from the stream + */ + private double readNum() { + int c = this.stream[this.loc++]; + boolean neg = c == '-'; + boolean sawdot = c == '.'; + double dotmult = sawdot ? 0.1 : 1; + double value = (c >= '0' && c <= '9') ? c - '0' : 0; + while (true) { + c = this.stream[this.loc++]; + if (c == '.') { + if (sawdot) { + this.loc--; + break; + } + sawdot = true; + dotmult = 0.1; + } else if (c >= '0' && c <= '9') { + int val = c - '0'; + if (sawdot) { + value += val * dotmult; + dotmult *= 0.1; + } else { + value = value * 10 + val; + } + } else { + this.loc--; + break; + } + } + if (neg) { + value = -value; + } + return value; + } + + /** + *

+ * read a String from the stream. Strings begin with a '(' character, which has already been + * read, and end with a balanced ')' character. A '\' character starts an escape sequence of up + * to three octal digits. + *

+ * + *

+ * Parenthesis must be enclosed by a balanced set of parenthesis, so a string may enclose + * balanced parenthesis. + *

+ * + * @return the string with escape sequences replaced with their + * values + */ + private String readString() { + int parenLevel = 0; + StringBuffer sb = new StringBuffer(); + while (this.loc < this.stream.length) { + int c = this.stream[this.loc++]; + if (c == ')') { + if (parenLevel-- == 0) { + break; + } + } else if (c == '(') { + parenLevel++; + } else if (c == '\\') { + // escape sequences + c = this.stream[this.loc++]; + if (c >= '0' && c < '8') { + int count = 0; + int val = 0; + while (c >= '0' && c < '8' && count < 3) { + val = val * 8 + c - '0'; + c = this.stream[this.loc++]; + count++; + } + this.loc--; + c = val; + } else if (c == 'n') { + c = '\n'; + } else if (c == 'r') { + c = '\r'; + } else if (c == 't') { + c = '\t'; + } else if (c == 'b') { + c = '\b'; + } else if (c == 'f') { + c = '\f'; + } else if (c == '\n' || c == '\r') { + continue; + } + } + sb.append((char) c); + } + return sb.toString(); + } + + /** + * read a byte array from the stream. Byte arrays begin with a '<' + * character, which has already been read, and end with a '>' + * character. Each byte in the array is made up of two hex characters, + * the first being the high-order bit. + * + * We translate the byte arrays into char arrays by combining two bytes + * into a character, and then translate the character array into a string. + * [JK FIXME this is probably a really bad idea!] + * + * @return the byte array + */ + private String readByteArray() { + StringBuffer buf = new StringBuffer(); + int count = 0; + char w = (char) 0; + // read individual bytes and format into a character array + while ((this.loc < this.stream.length) && (this.stream[this.loc] != '>')) { + char c = (char) this.stream[this.loc]; + byte b = (byte) 0; + if (c >= '0' && c <= '9') { + b = (byte) (c - '0'); + } else if (c >= 'a' && c <= 'f') { + b = (byte) (10 + (c - 'a')); + } else if (c >= 'A' && c <= 'F') { + b = (byte) (10 + (c - 'A')); + } else { + this.loc++; + continue; + } + // calculate where in the current byte this character goes + int offset = 1 - (count % 2); + w |= (0xf & b) << (offset * 4); + // increment to the next char if we've written four bytes + if (offset == 0) { + buf.append(w); + w = (char) 0; + } + count++; + this.loc++; + } + // ignore trailing '>' + this.loc++; + return buf.toString(); + } + + // /////////////////////////////////////////////////////////////// + // B E G I N P A R S E R S E C T I O N + // /////////////////////////////////////////////////////////////// + /** + * Called to prepare for some iterations + */ + @Override + public void setup() { + this.stack = new Stack(); + this.parserStates = new Stack(); + this.state = new ParserState(); + this.path = new GeneralPath(); + this.loc = 0; + this.clip = 0; + // initialize the ParserState + this.state.fillCS = PDFColorSpace.getColorSpace(PDFColorSpace.COLORSPACE_GRAY); + this.state.strokeCS = PDFColorSpace.getColorSpace(PDFColorSpace.COLORSPACE_GRAY); + this.state.textFormat = new PDFTextFormat(); + } + + /** + * parse the stream. commands are added to the PDFPage initialized + * in the constructor as they are encountered. + *

+ * Page numbers in comments refer to the Adobe PDF specification.
+ * commands are listed in PDF spec 32000-1:2008 in Table A.1 + * + * @return

    + *
  • Watchable.RUNNING when there are commands to be processed
  • Watchable.COMPLETED + * when the page is done and all the commands have been processed
  • Watchable.STOPPED + * if the page we are rendering into is no longer available + *
+ */ + @SuppressWarnings("unused") + @Override + public int iterate() throws Exception { + // make sure the page is still available, and create the reference + // to it for use within this iteration + this.cmds = this.pageRef.get(); + if (this.cmds == null) { + PDFDebugger.debug("Page gone. Stopping", 10); + return Watchable.STOPPED; + } + Object obj; + try { + obj = parseObject(); + } catch (DebugStopException e) { + return Watchable.STOPPED; + } + // if there's nothing left to parse, we're done + if (obj == null) { + return Watchable.COMPLETED; + } + if (obj instanceof Tok) { + // it's a command. figure out what to do. + // (if not, the token will be "pushed" onto the stack) + String cmd = ((Tok) obj).name; + PDFDebugger.debug("Command: " + cmd + " (stack size is " + this.stack.size() + ")", 10); + if (cmd.equals("q")) { + // push the parser state + this.parserStates.push((ParserState) this.state.clone()); + // push graphics state + this.cmds.addPush(); + } else if (cmd.equals("Q")) { + processQCmd(); + } else if (cmd.equals("cm")) { + // set transform to array of values + float[] elts = popFloat(6); + AffineTransform xform = new AffineTransform(elts); + this.cmds.addXform(xform); + } else if (cmd.equals("w")) { + // set stroke width + this.cmds.addStrokeWidth(popFloat()); + } else if (cmd.equals("J")) { + // set end cap style + this.cmds.addEndCap(popInt()); + } else if (cmd.equals("j")) { + // set line join style + this.cmds.addLineJoin(popInt()); + } else if (cmd.equals("M")) { + // set miter limit + this.cmds.addMiterLimit(popInt()); + } else if (cmd.equals("d")) { + // set dash style and phase + float phase = popFloat(); + float[] dashary = popFloatArray(); + if (!PDFDebugger.DISABLE_PATH_STROKE) { + this.cmds.addDash(dashary, phase); + } + } else if (cmd.equals("ri")) { + popString(); + // TODO: do something with rendering intent (page 197) + } else if (cmd.equals("i")) { + popFloat(); + // TODO: do something with flatness tolerance + } else if (cmd.equals("gs")) { + // set graphics state to values in a named dictionary + String popString = popString(); + PDFDebugger.debug("Set GS state "+popString, 10); + setGSState(popString); + } else if (cmd.equals("m")) { + // path move to + float y = popFloat(); + float x = popFloat(); + this.path.moveTo(x, y); + PDFDebugger.logPath(path, "2 moved to " + x + ", " + y); + } else if (cmd.equals("l")) { + // path line to + float y = popFloat(); + float x = popFloat(); + this.path.lineTo(x, y); + PDFDebugger.logPath(path, "1 line to " + x + ", " + y); + } else if (cmd.equals("c")) { + // path curve to + float a[] = popFloat(6); + this.path.curveTo(a[0], a[1], a[2], a[3], a[4], a[5]); + PDFDebugger.logPath(path, "1 curve to " + Arrays.toString(a)); + } else if (cmd.equals("v")) { + // path curve; first control point= start + float a[] = popFloat(4); + Point2D cp = this.path.getCurrentPoint(); + this.path.curveTo((float) cp.getX(), (float) cp.getY(), a[0], a[1], a[2], a[3]); + PDFDebugger.logPath(path, "2 curve to " + Arrays.toString(a) + ", " + cp.getX() + "," + cp.getY()); + } else if (cmd.equals("y")) { + // path curve; last control point= end + float a[] = popFloat(4); + this.path.curveTo(a[0], a[1], a[2], a[3], a[2], a[3]); + PDFDebugger.logPath(path, "3 curve to " + Arrays.toString(a)); + } else if (cmd.equals("h")) { + tryClosingPath(); + PDFDebugger.logPath(path, "closed"); + } else if (cmd.equals("re")) { + // path add rectangle + float a[] = popFloat(4); + this.path.moveTo(a[0], a[1]); + PDFDebugger.logPath(path, "1 moved to " + a[0] + "," + a[1]); + this.path.lineTo(a[0] + a[2], a[1]); + PDFDebugger.logPath(path, "2 line to " + (a[0] + a[2]) + "," + a[1]); + this.path.lineTo(a[0] + a[2], a[1] + a[3]); + PDFDebugger.logPath(path, "3 line to " + (a[0] + a[2]) + "," + (a[1] + a[3])); + this.path.lineTo(a[0], a[1] + a[3]); + PDFDebugger.logPath(path, "4 line to " + a[0] + "," + (a[1] + a[3])); + tryClosingPath(); + PDFDebugger.logPath(path, "closed"); + } else if (cmd.equals("S")) { + // stroke the path + if (!PDFDebugger.DISABLE_PATH_STROKE || (!PDFDebugger.DISABLE_CLIP && this.clip == PDFShapeCmd.CLIP)) { + if(autoAdjustStroke || strokeOverprint || fillOverprint) { + path.closePath(); + PDFDebugger.logPath(path, "closed"); + } + this.cmds.addPath(this.path, PDFShapeCmd.STROKE | this.clip, this.autoAdjustStroke); + } + this.clip = 0; + this.path = new GeneralPath(); + PDFDebugger.logPath(path, "new path"); + } else if (cmd.equals("s")) { + tryClosingPath(); + PDFDebugger.logPath(path, "closed"); + if (!PDFDebugger.DISABLE_PATH_STROKE || (!PDFDebugger.DISABLE_CLIP && this.clip == PDFShapeCmd.CLIP)) { + this.cmds.addPath(this.path, PDFShapeCmd.STROKE | this.clip, this.autoAdjustStroke); + } + this.clip = 0; + this.path = new GeneralPath(); + PDFDebugger.logPath(path, "new path"); + } else if (cmd.equals("f") || cmd.equals("F")) { + tryClosingPath(); + // fill the path (close/not close identical) + if (!PDFDebugger.DISABLE_PATH_FILL || (!PDFDebugger.DISABLE_CLIP && this.clip == PDFShapeCmd.CLIP)) { + this.cmds.addPath(this.path, PDFShapeCmd.FILL | this.clip, this.autoAdjustStroke); + } + this.clip = 0; + this.path = new GeneralPath(); + PDFDebugger.logPath(path, "new path"); + } else if (cmd.equals("f*")) { + // fill the path using even/odd rule + this.path.setWindingRule(WIND_EVEN_ODD); + PDFDebugger.logPath(path, "set winding rule" + WIND_EVEN_ODD); + if (!PDFDebugger.DISABLE_PATH_FILL || (!PDFDebugger.DISABLE_CLIP && this.clip == PDFShapeCmd.CLIP)) { + this.cmds.addPath(this.path, PDFShapeCmd.FILL | this.clip, this.autoAdjustStroke); + } + this.clip = 0; + this.path = new GeneralPath(); + PDFDebugger.logPath(path, "new path"); + } else if (cmd.equals("B")) { + // fill and stroke the path + if (!PDFDebugger.DISABLE_PATH_STROKE_FILL || (!PDFDebugger.DISABLE_CLIP && this.clip == PDFShapeCmd.CLIP)) { + this.cmds.addPath(this.path, PDFShapeCmd.BOTH | this.clip, this.autoAdjustStroke); + } + this.clip = 0; + this.path = new GeneralPath(); + PDFDebugger.logPath(path, "new path"); + } else if (cmd.equals("B*")) { + // fill path using even/odd rule and stroke it + this.path.setWindingRule(WIND_EVEN_ODD); + PDFDebugger.logPath(path, "set winding rule" + WIND_EVEN_ODD); + if (!PDFDebugger.DISABLE_PATH_STROKE_FILL || (!PDFDebugger.DISABLE_CLIP && this.clip == PDFShapeCmd.CLIP)) { + this.cmds.addPath(this.path, PDFShapeCmd.BOTH | this.clip, this.autoAdjustStroke); + } + this.clip = 0; + this.path = new GeneralPath(); + PDFDebugger.logPath(path, "new path"); + } else if (cmd.equals("b")) { + tryClosingPath(); + PDFDebugger.logPath(path, "close"); + if (!PDFDebugger.DISABLE_PATH_STROKE_FILL || (!PDFDebugger.DISABLE_CLIP && this.clip == PDFShapeCmd.CLIP)) { + this.cmds.addPath(this.path, PDFShapeCmd.BOTH | this.clip, this.autoAdjustStroke); + } + this.clip = 0; + this.path = new GeneralPath(); + PDFDebugger.logPath(path, "new path"); + } else if (cmd.equals("b*")) { + tryClosingPath(); + PDFDebugger.logPath(path, "close"); + this.path.setWindingRule(WIND_EVEN_ODD); + PDFDebugger.logPath(path, "set winding rule " + WIND_EVEN_ODD); + if (!PDFDebugger.DISABLE_PATH_STROKE_FILL || (!PDFDebugger.DISABLE_CLIP && this.clip == PDFShapeCmd.CLIP)) { + this.cmds.addPath(this.path, PDFShapeCmd.BOTH | this.clip, this.autoAdjustStroke); + } + this.clip = 0; + this.path = new GeneralPath(); + PDFDebugger.logPath(path, "new path"); + } else if (cmd.equals("n")) { + if (path.getCurrentPoint() != null) { + tryClosingPath(); + PDFDebugger.logPath(path, "closed"); + } + // clip with the path and discard it + if (!PDFDebugger.DISABLE_CLIP) { + if (this.clip != 0) { + this.cmds.addPath(this.path, this.clip, this.autoAdjustStroke); + } + } + this.clip = 0; + this.path = new GeneralPath(); + PDFDebugger.logPath(path, "new path"); + } else if (cmd.equals("W")) { + // mark this path for clipping! + this.clip = PDFShapeCmd.CLIP; + } else if (cmd.equals("W*")) { + // mark this path using even/odd rule for clipping + this.path.setWindingRule(WIND_EVEN_ODD); + PDFDebugger.logPath(path, "set winding rule " + WIND_EVEN_ODD); + this.clip = PDFShapeCmd.CLIP; + } else if (cmd.equals("sh")) { + // shade a region that is defined by the shader itself. + // shading the current space from a dictionary + // should only be used for limited-dimension shadings + String gdictname = popString(); + // set up the pen to do a gradient fill according + // to the dictionary + PDFObject shobj = findResource(gdictname, "Shading"); + if (!PDFDebugger.DISABLE_SHADER) { + doShader(shobj); + } + } else if (cmd.equals("CS")) { + // set the stroke color space + this.state.strokeCS = parseColorSpace(new PDFObject(this.stack.pop())); + } else if (cmd.equals("cs")) { + // set the fill color space + this.state.fillCS = parseColorSpace(new PDFObject(this.stack.pop())); + } else if (cmd.equals("SC")) { + // set the stroke color + int n = this.state.strokeCS.getNumComponents(); + this.cmds.addStrokePaint(this.state.strokeCS.getPaint(popFloat(n))); + } else if (cmd.equals("SCN")) { + // set the stroke colour + if (this.state.strokeCS instanceof PatternSpace) { + this.cmds.addFillPaint(doPattern((PatternSpace) this.state.strokeCS)); + } else { + int n = this.state.strokeCS.getNumComponents(); + this.cmds.addStrokePaint(this.state.strokeCS.getPaint(popFloat(n))); + } + } else if (cmd.equals("sc")) { + // set the fill color + int n = this.state.fillCS.getNumComponents(); + this.cmds.addFillPaint(this.state.fillCS.getPaint(popFloat(n))); + } else if (cmd.equals("scn")) { + if (this.state.fillCS instanceof PatternSpace) { + this.cmds.addFillPaint(doPattern((PatternSpace) this.state.fillCS)); + } else { + int n = this.state.fillCS.getNumComponents(); + this.cmds.addFillPaint(this.state.fillCS.getPaint(popFloat(n))); + } + } else if (cmd.equals("G")) { + // set the stroke color to a Gray value + this.state.strokeCS = PDFColorSpace.getColorSpace(PDFColorSpace.COLORSPACE_GRAY); + this.cmds.addStrokePaint(this.state.strokeCS.getPaint(popFloat(1))); + } else if (cmd.equals("g")) { + // set the fill color to a Gray value + this.state.fillCS = PDFColorSpace.getColorSpace(PDFColorSpace.COLORSPACE_GRAY); + this.cmds.addFillPaint(this.state.fillCS.getPaint(popFloat(1))); + } else if (cmd.equals("RG")) { + // set the stroke color to an RGB value + this.state.strokeCS = PDFColorSpace.getColorSpace(PDFColorSpace.COLORSPACE_RGB); + this.cmds.addStrokePaint(this.state.strokeCS.getPaint(popFloat(3))); + } else if (cmd.equals("rg")) { + // set the fill color to an RGB value + this.state.fillCS = PDFColorSpace.getColorSpace(PDFColorSpace.COLORSPACE_RGB); + this.cmds.addFillPaint(this.state.fillCS.getPaint(popFloat(3))); + } else if (cmd.equals("K")) { +// if(strokeOverprint && strokeOverprintMode == 1) { +// if (this.state.strokeCS instanceof PatternSpace) { +// this.cmds.addFillPaint(doPattern((PatternSpace) this.state.strokeCS)); +// } else { +// int n = this.state.strokeCS.getNumComponents(); +// this.cmds.addStrokePaint(this.state.strokeCS.getPaint(popFloat(n))); +// } +// }else { + // set the stroke color to a CMYK value + this.state.strokeCS = PDFColorSpace.getColorSpace(PDFColorSpace.COLORSPACE_CMYK); + this.cmds.addStrokePaint(this.state.strokeCS.getPaint(popFloat(4))); +// } + } else if (cmd.equals("k")) { +// if(fillOverprint && fillOverprintMode == 1) { +// // if OP = true and OPM = 1 apply the same as in "scn" +// if (this.state.fillCS instanceof PatternSpace) { +// this.cmds.addFillPaint(doPattern((PatternSpace) this.state.fillCS)); +// } else { +// // set the fill color to a CMYK value +// int n = this.state.fillCS.getNumComponents(); +// this.cmds.addFillPaint(this.state.fillCS.getPaint(popFloat(n))); +// } +// }else { + this.state.fillCS = PDFColorSpace.getColorSpace(PDFColorSpace.COLORSPACE_CMYK); + this.cmds.addFillPaint(this.state.fillCS.getPaint(popFloat(4))); +// } + } else if (cmd.equals("Do")) { + // make a do call on the referenced object + String name = popString(); + if (PDFDebugger.DEBUG_IMAGES) { + PDFDebugger.debug("XObject reference to " + name); + } + PDFObject xobj = findResource(name, "XObject"); + doXObject(xobj); + } else if (cmd.equals("BT")) { + processBTCmd(); + } else if (cmd.equals("ET")) { + // end of text. noop + this.state.textFormat.end(); + } else if (cmd.equals("Tc")) { + // set character spacing + this.state.textFormat.setCharSpacing(popFloat()); + } else if (cmd.equals("Tw")) { + // set word spacing + this.state.textFormat.setWordSpacing(popFloat()); + } else if (cmd.equals("Tz")) { + // set horizontal scaling + this.state.textFormat.setHorizontalScale(popFloat()); + } else if (cmd.equals("TL")) { + // set leading + this.state.textFormat.setLeading(popFloat()); + } else if (cmd.equals("Tf")) { + // set text font + float sz = popFloat(); + String fontref = popString(); + this.state.textFormat.setFont(getFontFrom(fontref), sz); + } else if (cmd.equals("Tr")) { + // set text rendering mode + this.state.textFormat.setMode(popInt()); + } else if (cmd.equals("Ts")) { + // set text rise + this.state.textFormat.setRise(popFloat()); + } else if (cmd.equals("Td")) { + // set text matrix location + float y = popFloat(); + float x = popFloat(); + this.state.textFormat.carriageReturn(x, y); + } else if (cmd.equals("TD")) { + // set leading and matrix: -y TL x y Td + float y = popFloat(); + float x = popFloat(); + this.state.textFormat.setLeading(-y); + this.state.textFormat.carriageReturn(x, y); + } else if (cmd.equals("Tm")) { + // set text matrix + this.state.textFormat.setMatrix(popFloat(6)); + } else if (cmd.equals("T*")) { + // go to next line + this.state.textFormat.carriageReturn(); + } else if (cmd.equals("Tj")) { + // show text + this.state.textFormat.doText(this.cmds, popString(), this.autoAdjustStroke); + } else if (cmd.equals("\'")) { + // next line and show text: T* string Tj + this.state.textFormat.carriageReturn(); + this.state.textFormat.doText(this.cmds, popString(), this.autoAdjustStroke); + } else if (cmd.equals("\"")) { + // draw string on new line with char & word spacing: + // aw Tw ac Tc string ' + String string = popString(); + float ac = popFloat(); + float aw = popFloat(); + this.state.textFormat.setWordSpacing(aw); + this.state.textFormat.setCharSpacing(ac); + this.state.textFormat.doText(this.cmds, string, this.autoAdjustStroke); + } else if (cmd.equals("TJ")) { + // show kerned string + this.state.textFormat.doText(this.cmds, popArray(), this.autoAdjustStroke); + } else if (cmd.equals("BI")) { + // parse inline image + parseInlineImage(); + } else if (cmd.equals("BX")) { + this.catchexceptions = true; // ignore errors + } else if (cmd.equals("EX")) { + this.catchexceptions = false; // stop ignoring errors + } else if (cmd.equals("MP")) { + // mark point (role= mark role name) + popString(); + } else if (cmd.equals("DP")) { + // mark point with dictionary (role, ref) + // result is either inline dict or name in "Properties" rsrc + this.stack.pop(); + popString(); + } else if (cmd.equals("BMC")) { + // begin marked content (role) + popString(); + } else if (cmd.equals("BDC")) { + // begin marked content with dict (role, ref) + // result is either inline dict or name in "Properties" rsrc + this.stack.pop(); + popString(); + } else if (cmd.equals("EMC")) { + // end marked content + } else if (cmd.equals("d0")) { + // character width in type3 fonts + popFloat(2); + } else if (cmd.equals("d1")) { + // character width in type3 fonts + popFloat(6); + } else if (cmd.equals("QBT")) {// 'Q' & 'BT' mushed together! + processQCmd(); + processBTCmd(); + } else if (cmd.equals("Qq")) {// 'Q' & 'q' mushed together! + processQCmd(); + // push the parser state + this.parserStates.push((ParserState) this.state.clone()); + // push graphics state + this.cmds.addPush(); + } else if (cmd.equals("qBT")) {// 'q' & 'BT' mushed together! + // push the parser state + this.parserStates.push((ParserState) this.state.clone()); + // push graphics state + this.cmds.addPush(); + processBTCmd(); + } else if (cmd.equals("q1")) { + PDFDebugger.debug("**** WARNING: Not handled command: " + cmd + " **************************", 10); + } else if (cmd.equals("q0")) { + PDFDebugger.debug("**** WARNING: Not handled command: " + cmd + " **************************", 10); + } else { + if (this.catchexceptions) { + PDFDebugger.debug("**** WARNING: Unknown command: " + cmd + " **************************", 10); + } else { + throw new PDFParseException("Unknown command: " + cmd); + } + } + if (this.stack.size() != 0) { + PDFDebugger.debug("**** WARNING! Stack not zero! (cmd=" + cmd + ", size=" + this.stack.size() + ") *************************", 10); + this.stack.setSize(0); + } + } else { + this.stack.push(obj); + } + // release or reference to the page object, so that it can be + // gc'd if it is no longer in use + this.cmds = null; + return Watchable.RUNNING; + } + + /** + * Try to close a path but don't fail with exception if this is not working. + * This is just a workaround for some PDFs with wrong content... + */ + private void tryClosingPath() { + try { + this.path.closePath(); + PDFDebugger.logPath(path, "closed"); + }catch(java.awt.geom.IllegalPathStateException e) { + PDFDebugger.debug("Failed to close path", 1000); + } + } + + @SuppressWarnings("unused") + private void onNextObject(Tok obj) throws DebugStopException { + String progress; + if (true) { + double percent = (100d * this.loc) / this.stream.length; + NumberFormat nf = NumberFormat.getInstance(); + nf.setMinimumFractionDigits(1); + nf.setMaximumFractionDigits(1); + progress = nf.format(percent) + "%"; + } else { + progress = this.loc + " of " + this.stream.length; + } + String operators = ""; + for (Object operator : this.stack) { + operators += operator + " "; + } + if (PDFDebugger.DEBUG_OPERATORS) { + PDFDebugger.debug("parser{" + hashCode() + "} " + progress + ": #" + mDebugCommandIndex + " \t" + operators + obj.name); + } + mDebugCommandIndex++; + if (PDFDebugger.DEBUG_STOP_AT_INDEX > 0 && mDebugCommandIndex > PDFDebugger.DEBUG_STOP_AT_INDEX) { + System.err.println("Debugging: stopped at instruction #" + mDebugCommandIndex); + throw new DebugStopException(); + } + if (PDFDebugger.DRAW_DELAY > 0) { + try { + Thread.sleep(PDFDebugger.DRAW_DELAY); + } catch (InterruptedException e) { + } + } + } + + /** + * abstracted command processing for Q command. Used directly and as + * part of processing of mushed QBT command. + */ + private void processQCmd() { + // pop graphics state ('Q') + this.cmds.addPop(); + // pop the parser state + if (this.parserStates.isEmpty() == false) { + this.state = this.parserStates.pop(); + } + } + + /** + * abstracted command processing for BT command. Used directly and as + * part of processing of mushed QBT command. + */ + private void processBTCmd() { + // begin text block: reset everything. + this.state.textFormat.reset(); + } + + /** + * Cleanup when iteration is done + */ + @Override + public void cleanup() { + this.state.textFormat.flush(); + this.cmds.finish(); + this.stack = null; + this.parserStates = null; + this.state = null; + this.path = null; + this.cmds = null; + this.tok = null; + } + + public void dumpStreamToError() { + if (this.errorwritten) { + return; + } + this.errorwritten = true; + try { + File oops = File.createTempFile("PDFError", ".err"); + FileOutputStream fos = new FileOutputStream(oops); + fos.write(this.stream); + fos.close(); + } catch (IOException ioe) { /* Do nothing */ + } + ; + } + + // /////////////////////////////////////////////////////////////// + // H E L P E R S + // /////////////////////////////////////////////////////////////// + /** + * get a property from a named dictionary in the resources of this + * content stream. + * + * @param name + * the name of the property in the dictionary + * @param inDict + * the name of the dictionary in the resources + * @return the value of the property in the dictionary + */ + private PDFObject findResource(String name, String inDict) throws IOException { + if (inDict != null) { + PDFObject in = this.resources.get(inDict); + if (in == null || in.getType() != PDFObject.DICTIONARY) { + throw new PDFParseException("No dictionary called " + inDict + " found in the resources"); + } + return in.getDictRef(name); + } else { + return this.resources.get(name); + } + } + + /** + * Insert a PDF object into the command stream. The object must + * either be an Image or a Form, which is a set of PDF commands + * in a stream. + * + * @param obj + * the object to insert, an Image or a Form. + */ + private void doXObject(PDFObject obj) throws IOException { + String type = obj.getDictRef("Subtype").getStringValue(); + if (type == null) { + type = obj.getDictRef("S").getStringValue(); + } + if (type.equals("Image")) { + doImage(obj); + } else if (type.equals("Form")) { + doForm(obj); + } else { + throw new PDFParseException("Unknown XObject subtype: " + type); + } + } + + /** + * Parse image data into a Java BufferedImage and add the image + * command to the page. + * + * @param obj + * contains the image data, and a dictionary describing + * the width, height and color space of the image. + */ + private void doImage(PDFObject obj) throws IOException { + if (!PDFDebugger.DISABLE_IMAGES) { + if (PDFDebugger.DEBUG_IMAGES) { + final boolean jpegDecode = PDFDecoder.isLastFilter(obj, PDFDecoder.DCT_FILTERS); + if (jpegDecode) { + PDFDebugger.debug("Image is JPEG"); + } else { + PDFDebugger.debug("Image not JPEG"); + } + } + this.cmds.addImage(PDFImage.createImage(obj, this.resources, false)); + } + } + + /** + * Inject a stream of PDF commands onto the page. Optimized to cache + * a parsed stream of commands, so that each Form object only needs + * to be parsed once. + * + * @param obj + * a stream containing the PDF commands, a transformation + * matrix, bounding box, and resources. + */ + private void doForm(PDFObject obj) throws IOException { + // check to see if we've already parsed this sucker + PDFPage formCmds = (PDFPage) obj.getCache(); + if (formCmds == null) { + // rats. parse it. + AffineTransform at; + Rectangle2D bbox; + PDFObject matrix = obj.getDictRef("Matrix"); + if (matrix == null) { + at = new AffineTransform(); + } else { + float elts[] = new float[6]; + for (int i = 0; i < elts.length; i++) { + elts[i] = (matrix.getAt(i)).getFloatValue(); + } + at = new AffineTransform(elts); + } + PDFObject bobj = obj.getDictRef("BBox"); + bbox = new Rectangle2D.Float(bobj.getAt(0).getFloatValue(), bobj.getAt(1).getFloatValue(), bobj.getAt(2).getFloatValue(), bobj.getAt(3).getFloatValue()); + formCmds = new PDFPage(bbox, 0); + formCmds.addXform(at); + HashMap r = new HashMap(this.resources); + PDFObject rsrc = obj.getDictRef("Resources"); + if (rsrc != null) { + r.putAll(rsrc.getDictionary()); + } + PDFParser form = new PDFParser(formCmds, obj.getStream(), r); + form.go(true); + obj.setCache(formCmds); + } + if (!PDFDebugger.DISABLE_FORMS) { + this.cmds.addPush(); + this.cmds.addCommands(formCmds); + this.cmds.addPop(); + } + } + + /** + * Set the values into a PatternSpace + */ + private PDFPaint doPattern(PatternSpace patternSpace) throws IOException { + float[] components = null; + String patternName = popString(); + PDFObject pattern = findResource(patternName, "Pattern"); + if (pattern == null) { + throw new PDFParseException("Unknown pattern : " + patternName); + } + if (this.stack.size() > 0) { + components = popFloat(this.stack.size()); + } + return patternSpace.getPaint(pattern, components, this.resources); + } + + /** + * Parse the next object out of the PDF stream. This could be a + * Double, a String, a HashMap (dictionary), Object[] array, or + * a Tok containing a PDF command. + */ + private Object parseObject() throws PDFParseException, DebugStopException { + Tok t = nextToken(); + if (t.type == Tok.NUM) { + return Double.valueOf(this.tok.value); + } else if (t.type == Tok.STR) { + return this.tok.name; + } else if (t.type == Tok.NAME) { + return this.tok.name; + } else if (t.type == Tok.BRKB) { + HashMap hm = new HashMap(); + String name = null; + Object obj; + while ((obj = parseObject()) != null) { + if (name == null) { + name = (String) obj; + } else { + hm.put(name, new PDFObject(obj)); + name = null; + } + } + if (this.tok.type != Tok.BRKE) { + throw new PDFParseException("Inline dict should have ended with '>>'"); + } + return hm; + } else if (t.type == Tok.ARYB) { + // build an array + ArrayList ary = new ArrayList(); + Object obj; + while ((obj = parseObject()) != null) { + ary.add(obj); + } + if (this.tok.type != Tok.ARYE) { + throw new PDFParseException("Expected ']'"); + } + return ary.toArray(); + } else if (t.type == Tok.CMD) { + onNextObject(t); + return t; + } + PDFDebugger.debug("**** WARNING! parseObject unknown token! (t.type=" + t.type + ") *************************", 10); + return null; + } + + /** + * Parse an inline image. An inline image starts with BI (already + * read, contains a dictionary until ID, and then image data until + * EI. + */ + private void parseInlineImage() throws IOException, DebugStopException { + // build dictionary until ID, then read image until EI + HashMap hm = new HashMap(); + while (true) { + Tok t = nextToken(); + if (t.type == Tok.CMD) { + onNextObject(t); + if (t.name.equals("ID")) { + break; + } + } + // it should be a name; + String name = t.name; + if(PDFDebugger.DEBUG_IMAGES) { + PDFDebugger.debug("ParseInlineImage, token: " + name); + } + if (name.equals("BPC")) { + name = "BitsPerComponent"; + } else if (name.equals("CS")) { + name = "ColorSpace"; + } else if (name.equals("D")) { + name = "Decode"; + } else if (name.equals("DP")) { + name = "DecodeParms"; + } else if (name.equals("F")) { + name = "Filter"; + } else if (name.equals("H")) { + name = "Height"; + } else if (name.equals("IM")) { + name = "ImageMask"; + } else if (name.equals("W")) { + name = "Width"; + } else if (name.equals("I")) { + name = "Interpolate"; + } + Object vobj = parseObject(); + hm.put(name, new PDFObject(vobj)); + } + if (this.stream[this.loc] == '\r') { + this.loc++; + } + if (this.stream[this.loc] == '\n' || this.stream[this.loc] == ' ') { + this.loc++; + } + PDFObject imObj = hm.get("ImageMask"); + if (imObj != null && imObj.getBooleanValue()) { + // [PATCHED by michal.busta@gmail.com] - default value according to PDF spec. is [0, 1] + // there is no need to swap array - PDF image should handle this values + Double[] decode = { Double.valueOf(0), Double.valueOf(1) }; + PDFObject decodeObj = hm.get("Decode"); + if (decodeObj != null) { + decode[0] = Double.valueOf(decodeObj.getAt(0).getDoubleValue()); + decode[1] = Double.valueOf(decodeObj.getAt(1).getDoubleValue()); + } + hm.put("Decode", new PDFObject(decode)); + } + PDFObject obj = new PDFObject(null, PDFObject.DICTIONARY, hm); + int dstart = this.loc; + // now skip data until a whitespace followed by EI + while (!PDFFile.isWhiteSpace(this.stream[this.loc]) || this.stream[this.loc + 1] != 'E' || this.stream[this.loc + 2] != 'I') { + this.loc++; + } + // data runs from dstart to loc + if (PDFDebugger.DEBUG_IMAGES) { + PDFDebugger.debug("InlineImage from " + dstart + " to " + this.loc); + } + byte[] data = new byte[this.loc - dstart]; + System.arraycopy(this.stream, dstart, data, 0, this.loc - dstart); + obj.setStream(ByteBuffer.wrap(data)); + this.loc += 3; + doImage(obj); + } + + /** + * build a shader from a dictionary. + */ + private void doShader(PDFObject shaderObj) throws IOException { + PDFShader shader = PDFShader.getShader(shaderObj, this.resources); + if(shader == null) { + return; + } + this.cmds.addPush(); + Rectangle2D bbox = shader.getBBox(); + if (bbox != null) { + this.cmds.addFillPaint(shader.getPaint()); + this.cmds.addPath(new GeneralPath(bbox), PDFShapeCmd.FILL, this.autoAdjustStroke); + } else { + this.cmds.addFillPaint(shader.getPaint()); + this.cmds.addPath(null, PDFShapeCmd.FILL, this.autoAdjustStroke); + } + this.cmds.addPop(); + } + + /** + * get a PDFFont from the resources, given the resource name of the + * font. + * + * @param fontref + * the resource key for the font + */ + private PDFFont getFontFrom(String fontref) throws IOException { + PDFObject obj = findResource(fontref, "Font"); + return PDFFont.getFont(obj, this.resources); + } + + /** + * add graphics state commands contained within a dictionary. + * + * @param name + * the resource name of the graphics state dictionary + */ + private void setGSState(String name) throws IOException { + // obj must be a string that is a key to the "ExtGState" dict + PDFObject gsobj = findResource(name, "ExtGState"); + // TODO: lots of graphic states are not yet considered, see chapter 8.4.5 of the PDF specification. + // get LW, LC, LJ, Font, SM, CA, ML, D, RI, FL, BM, ca + // out of the reference, which is a dictionary + if (gsobj == null) { + return; + } + PDFObject d; + boolean handled = false; + if ((d = gsobj.getDictRef("LW")) != null) { + this.cmds.addStrokeWidth(d.getFloatValue()); + handled = true; + } + if ((d = gsobj.getDictRef("LC")) != null) { + this.cmds.addEndCap(d.getIntValue()); + handled = true; + } + if ((d = gsobj.getDictRef("LJ")) != null) { + this.cmds.addLineJoin(d.getIntValue()); + handled = true; + } + if ((d = gsobj.getDictRef("Font")) != null) { + this.state.textFormat.setFont(getFontFrom(d.getAt(0).getStringValue()), d.getAt(1).getFloatValue()); + handled = true; + } + if ((d = gsobj.getDictRef("ML")) != null) { + this.cmds.addMiterLimit(d.getFloatValue()); + handled = true; + } + if ((d = gsobj.getDictRef("D")) != null) { + PDFObject pdash[] = d.getAt(0).getArray(); + float dash[] = new float[pdash.length]; + for (int i = 0; i < pdash.length; i++) { + dash[i] = pdash[i].getFloatValue(); + } + if (!PDFDebugger.DISABLE_PATH_STROKE) { + this.cmds.addDash(dash, d.getAt(1).getFloatValue()); + } + handled = true; + } + if ((d = gsobj.getDictRef("CA")) != null) { + this.cmds.addStrokeAlpha(d.getFloatValue()); + handled = true; + } + if ((d = gsobj.getDictRef("ca")) != null) { + this.cmds.addFillAlpha(d.getFloatValue()); + handled = true; + } + if((d = gsobj.getDictRef("SA")) != null) { + // automatic stroke adjustment + this.autoAdjustStroke = d.getBooleanValue(); + handled = true; + } + if((d = gsobj.getDictRef("OP")) != null) { + this.strokeOverprint = d.getBooleanValue(); + PDFObject x = gsobj.getDictRef("OPM"); + if(x!= null) { + this.strokeOverprintMode = x.getIntValue(); + } + handled = true; + } + if((d = gsobj.getDictRef("op")) != null) { + this.fillOverprint = d.getBooleanValue(); + PDFObject x = gsobj.getDictRef("OPM"); + if(x!= null) { + this.fillOverprintMode = x.getIntValue(); + } + handled = true; + } + if(!handled) { + PDFDebugger.debug("graphic state command unknown!", 10); + } + } + + /** + * generate a PDFColorSpace description based on a PDFObject. The + * object could be a standard name, or the name of a resource in + * the ColorSpace dictionary, or a color space name with a defining + * dictionary or stream. + */ + private PDFColorSpace parseColorSpace(PDFObject csobj) throws IOException { + if (csobj == null) { + return this.state.fillCS; + } + return PDFColorSpace.getColorSpace(csobj, this.resources); + } + + /** + * pop a single float value off the stack. + * + * @return the float value of the top of the stack + * @throws PDFParseException + * if the value on the top of the stack + * isn't a number + */ + private float popFloat() throws PDFParseException { + if (this.stack.isEmpty() == false) { + Object obj = this.stack.pop(); + if (obj instanceof Double) { + return ((Double) obj).floatValue(); + } else { + throw new PDFParseException("Expected a number here."); + } + } + return 0; + } + + /** + * pop an array of float values off the stack. This is equivalent + * to filling an array from end to front by popping values off the + * stack. + * + * @param count + * the number of numbers to pop off the stack + * @return an array of length count + * @throws PDFParseException + * if any of the values popped off the + * stack are not numbers. + */ + private float[] popFloat(int count) throws PDFParseException { + float[] ary = new float[count]; + for (int i = count - 1; i >= 0; i--) { + ary[i] = popFloat(); + } + return ary; + } + + /** + * pop a single integer value off the stack. + * + * @return the integer value of the top of the stack + * @throws PDFParseException + * if the top of the stack isn't a number. + */ + private int popInt() throws PDFParseException { + Object obj = this.stack.pop(); + if (obj instanceof Double) { + return ((Double) obj).intValue(); + } else { + throw new PDFParseException("Expected a number here."); + } + } + + /** + * pop an array of integer values off the stack. This is equivalent + * to filling an array from end to front by popping values off the + * stack. + * + * @param count + * the number of numbers to pop off the stack + * @return an array of length count + * @throws PDFParseException + * if any of the values popped off the + * stack are not numbers. + */ + private float[] popFloatArray() throws PDFParseException { + Object obj = this.stack.pop(); + if (!(obj instanceof Object[])) { + throw new PDFParseException("Expected an [array] here."); + } + Object[] source = (Object[]) obj; + float[] ary = new float[source.length]; + for (int i = 0; i < ary.length; i++) { + if (source[i] instanceof Double) { + ary[i] = ((Double) source[i]).floatValue(); + } else { + throw new PDFParseException("This array doesn't consist only of floats."); + } + } + return ary; + } + + /** + * pop a String off the stack. + * + * @return the String from the top of the stack + * @throws PDFParseException + * if the top of the stack is not a NAME + * or STR. + */ + private String popString() throws PDFParseException { + Object obj = this.stack.pop(); + if (!(obj instanceof String)) { + throw new PDFParseException("Expected string here: " + obj.toString()); + } else { + return (String) obj; + } + } + + /** + * pop a PDFObject off the stack. + * + * @return the PDFObject from the top of the stack + * @throws PDFParseException + * if the top of the stack does not contain + * a PDFObject. + */ + @SuppressWarnings("unused") + private PDFObject popObject() throws PDFParseException { + Object obj = this.stack.pop(); + if (!(obj instanceof PDFObject)) { + throw new PDFParseException("Expected a reference here: " + obj.toString()); + } + return (PDFObject) obj; + } + + /** + * pop an array off the stack + * + * @return the array of objects that is the top element of the stack + * @throws PDFParseException + * if the top element of the stack does not + * contain an array. + */ + private Object[] popArray() throws PDFParseException { + Object obj = this.stack.pop(); + if (!(obj instanceof Object[])) { + throw new PDFParseException("Expected an [array] here: " + obj.toString()); + } + return (Object[]) obj; + } + + /** + * A class to store state needed whiel rendering. This includes the + * stroke and fill color spaces, as well as the text formatting + * parameters. + */ + class ParserState implements Cloneable { + /** the fill color space */ + PDFColorSpace fillCS; + /** the stroke color space */ + PDFColorSpace strokeCS; + /** the text paramters */ + PDFTextFormat textFormat; + + /** + * Clone the render state. + */ + @Override + public Object clone() { + ParserState newState = new ParserState(); + // no need to clone color spaces, since they are immutable + newState.fillCS = this.fillCS; + newState.strokeCS = this.strokeCS; + // we do need to clone the textFormat + newState.textFormat = (PDFTextFormat) this.textFormat.clone(); + return newState; + } + } + + @Override + protected void setStatus(int status) { + if(status == BaseWatchable.COMPLETED) { + if(!addAnnotation){ + // corresponding push in constructor PDFPage + this.cmds.addPop(); + this.cmds.addAnnotations(); + addAnnotation = true; + } + } + super.setStatus(status); + } +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFRenderer.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFRenderer.java new file mode 100644 index 000000000..16f89a6a9 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFRenderer.java @@ -0,0 +1,1038 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.sun.pdfview; + +import java.awt.AlphaComposite; +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.Paint; +import java.awt.Rectangle; +import java.awt.RenderingHints; +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.geom.GeneralPath; +import java.awt.geom.Rectangle2D; +import java.awt.image.BufferedImage; +import java.awt.image.BufferedImageOp; +import java.awt.image.ColorModel; +import java.awt.image.ConvolveOp; +import java.awt.image.ImageObserver; +import java.awt.image.IndexColorModel; +import java.awt.image.Kernel; +import java.awt.image.WritableRaster; +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Stack; + +/** + * This class turns a set of PDF Commands from a PDF page into an image. It + * encapsulates the state of drawing in terms of stroke, fill, transform, + * etc., as well as pushing and popping these states. + * + * When the run method is called, this class goes through all remaining commands + * in the PDF Page and draws them to its buffered image. It then updates any + * ImageConsumers with the drawn data. + */ +public class PDFRenderer extends BaseWatchable implements Runnable { + + /** the page we were generate from */ + private PDFPage page; + /** where we are in the page's command list */ + private int currentCommand; + /** a weak reference to the image we render into. For the image + * to remain available, some other code must retain a strong reference to it. + */ + private WeakReference imageRef; + /** the graphics object for use within an iteration. Note this must be + * set to null at the end of each iteration, or the image will not be + * collected + */ + private Graphics2D g; + /** the current graphics state */ + private GraphicsState state; + /** the stack of push()ed graphics states */ + private Stack stack; + /** the total region of this image that has been written to */ + private Rectangle2D globalDirtyRegion; + /** the image observers that will be updated when this image changes */ + private final List observers; + /** the last shape we drew (to check for overlaps) */ + private GeneralPath lastShape; + private AffineTransform lastTransform; + /** the info about the image, if we need to recreate it */ + private final ImageInfo imageinfo; + /** the next time the image should be notified about updates */ + private long then = 0; + /** the sum of all the individual dirty regions since the last update */ + private Rectangle2D unupdatedRegion; + + /** how long (in milliseconds) to wait between image updates */ + public static final long UPDATE_DURATION = 200; + public static final float NOPHASE = -1000; + public static final float NOWIDTH = -1000; + public static final float NOLIMIT = -1000; + public static final int NOCAP = -1000; + public static final float[] NODASH = null; + public static final int NOJOIN = -1000; + + + /** + * create a new PDFGraphics state + * @param page the current page + * @param imageinfo the paramters of the image to render + */ + public PDFRenderer(PDFPage page, ImageInfo imageinfo, BufferedImage bi) { + super(); + + this.page = page; + this.imageinfo = imageinfo; + this.imageRef = new WeakReference(bi); + + // initialize the list of observers + this.observers = new ArrayList(); + } + + /** + * create a new PDFGraphics state, given a Graphics2D. This version + * will not create an image, and you will get a NullPointerException + * if you attempt to call getImage(). + * @param page the current page + * @param g the Graphics2D object to use for drawing + * @param imgbounds the bounds of the image into which to fit the page + * @param clip the portion of the page to draw, in page space, or null + * if the whole page should be drawn + * @param bgColor the color to draw the background of the image, or + * null for no color (0 alpha value) + */ + public PDFRenderer(PDFPage page, Graphics2D g, Rectangle imgbounds, + Rectangle2D clip, Color bgColor) { + super(); + + this.page = page; + this.g = g; + this.imageinfo = new ImageInfo(imgbounds.width, imgbounds.height, + clip, bgColor); + g.translate(imgbounds.x, imgbounds.y); + + // initialize the list of observers + this.observers = new ArrayList(); + } + + /** + * Set up the graphics transform to match the clip region + * to the image size. + */ + private void setupRendering(Graphics2D g) { + g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, + RenderingHints.VALUE_INTERPOLATION_BICUBIC); + g.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, + RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY); + + if (this.imageinfo.bgColor != null) { + g.setColor(this.imageinfo.bgColor); + g.fillRect(0, 0, this.imageinfo.width, this.imageinfo.height); + } + + g.setColor(Color.BLACK); + + // set the initial clip and transform on the graphics + AffineTransform at = getInitialTransform(); + g.transform(at); + + // set up the initial graphics state + this.state = new GraphicsState(); + this.state.cliprgn = null; + this.state.stroke = new BasicStroke(1.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER); + this.state.strokePaint = PDFPaint.getColorPaint(Color.black); + this.state.fillPaint = this.state.strokePaint; + this.state.fillAlpha = AlphaComposite.getInstance(AlphaComposite.SRC); + this.state.strokeAlpha = AlphaComposite.getInstance(AlphaComposite.SRC); + this.state.xform = g.getTransform(); + + // initialize the stack + this.stack = new Stack(); + + // initialize the current command + this.currentCommand = 0; + } + + /** + * push the current graphics state onto the stack. Continue working + * with the current object; calling pop() restores the state of this + * object to its state when push() was called. + */ + public void push() { + this.state.cliprgn = this.g.getClip(); + this.stack.push(this.state); + + this.state = (GraphicsState) this.state.clone(); + } + + /** + * restore the state of this object to what it was when the previous + * push() was called. + */ + public void pop() { + if(this.stack.isEmpty() == false) { + this.state = this.stack.pop(); + } + + setTransform(this.state.xform); + setClip(this.state.cliprgn); + } + + /** + * draw an outline using the current stroke and draw paint + * @param s the path to stroke + * @return a Rectangle2D to which the current region being + * drawn will be added. May also be null, in which case no dirty + * region will be recorded. + */ + public Rectangle2D stroke(GeneralPath s, boolean autoAdjustStroke) { + // TODO: consider autoAdjustStroke here instead of during parsing + // PDF specification p. 130 / > 10.6.5 + this.g.setComposite(this.state.strokeAlpha); + s = new GeneralPath(autoAdjustStrokeWidth(this.g, this.state.stroke).createStrokedShape(s)); + return this.state.strokePaint.fill(this, this.g, s); + } + + /** + * auto adjust the stroke width, according to 6.5.4, which presumes that + * the device characteristics (an image) require a single pixel wide + * line, even if the width is set to less. We determine the scaling to + * see if we would produce a line that was too small, and if so, scale + * it up to produce a graphics line of 1 pixel, or so. This matches our + * output with Adobe Reader. + * + * @param g + * @param bs + * @return + */ + private BasicStroke autoAdjustStrokeWidth(Graphics2D g, BasicStroke bs) { + AffineTransform bt = new AffineTransform(g.getTransform()); + float width = bs.getLineWidth() * (float) bt.getScaleX(); + BasicStroke stroke = bs; + if (width < 1f) { + if (bt.getScaleX() > 0.01) { + width = 1.0f / (float) bt.getScaleX(); + } else { + // prevent division by a really small number + width = stroke.getLineWidth()<1f?1.0f:stroke.getLineWidth(); + } + stroke = new BasicStroke(width, bs.getEndCap(), bs.getLineJoin(), bs.getMiterLimit(), bs.getDashArray(), bs.getDashPhase()); + } + return stroke; + } + + /** + * draw an outline. + * @param p the path to draw + * @param bs the stroke with which to draw the path + */ + public void draw(GeneralPath p, BasicStroke bs) { + this.g.setComposite(this.state.fillAlpha); + this.g.setPaint(this.state.fillPaint.getPaint()); + this.g.setStroke(autoAdjustStrokeWidth(this.g, bs)); + this.g.draw(p); + } + + /** + * fill an outline using the current fill paint + * @param s the path to fill + */ + public Rectangle2D fill(GeneralPath s) { + this.g.setComposite(this.state.fillAlpha); + if (s == null) { + GraphicsState gs = stack.peek(); + if (gs.cliprgn != null) { + s = new GeneralPath(gs.cliprgn); + } + } + return this.state.fillPaint.fill(this, this.g, s); + } + + /** + * draw an image. + * @param image the image to draw + */ + public Rectangle2D drawImage(PDFImage image) { + + BufferedImage bi; + try { + bi = image.getImage(); + }catch (PDFImageParseException e) { + // maybe it was an unsupported format, or something. + // Nothing to draw, anyway! + return new Rectangle2D.Double(); + } + + // transform must use bitmap size + AffineTransform at = new AffineTransform(1f / bi.getWidth(), 0, + 0, -1f / bi.getHeight(), + 0, 1); + + if (image.isImageMask()) { + bi = getMaskedImage(bi); + } + + Rectangle r = g.getTransform().createTransformedShape(new Rectangle(0,0,1,1)).getBounds(); + boolean isBlured = false; + + if (Configuration.getInstance().isUseBlurResizingForImages() && + bi.getType() != BufferedImage.TYPE_CUSTOM && + bi.getWidth() >= 1.75*r.getWidth() && bi.getHeight() >= 1.75*r.getHeight()){ + try { + return smartDrawImage(image, bi, r, at); + }catch (Exception e) { + // do nothing, just go on with the "default" processing + } + } + + this.g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER)); + + //Image quality is better when using texturepaint instead of drawimage + //but it is also slower :( + this.g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, + RenderingHints.VALUE_INTERPOLATION_BILINEAR); + // banded rendering may lead to lower memory consumption for e.g. scanned PDFs with large images + int bandSize = Configuration.getInstance().getThresholdForBandedImageRendering(); + if (bandSize > 0 && bi.getHeight() > bandSize) { + // draw in bands + int tempMax = bi.getHeight(); + for (int offset=0; offset= 1.75*r.getWidth() && bi.getHeight() >= 1.75*r.getHeight()){ + + BufferedImageOp op; + // indexed colored images need to be converted for the convolveOp + boolean colorConversion = (bi.getColorModel() instanceof IndexColorModel); + final float maxFactor = 3.5f; + final boolean RESIZE = true; + if (bi.getWidth() > maxFactor*r.getWidth() && bi.getHeight() > maxFactor*r.getHeight()){ + //First resize, otherwise we risk that we get out of heapspace + int newHeight = (int)Math.round(maxFactor*r.getHeight()); + int newWidth = (int)Math.round(maxFactor*r.getWidth()); + if (!RESIZE) { + newHeight = bi.getHeight(); + newWidth = bi.getWidth(); + } + BufferedImage resized = new BufferedImage(newWidth, + newHeight, colorConversion?BufferedImage.TYPE_INT_ARGB:bi.getType()); + Graphics2D bg = (Graphics2D) resized.getGraphics(); + bg.setRenderingHint(RenderingHints.KEY_INTERPOLATION, + RenderingHints.VALUE_INTERPOLATION_BILINEAR); + bg.drawImage(bi, 0, 0, newWidth, newHeight, null); + bi = resized; + at = new AffineTransform(1f / bi.getWidth(), 0, + 0, -1f / bi.getHeight(), + 0, 1); + + final float weight = 1.0f/16.0f; + final float[] blurKernel = { + weight, weight, weight, weight, + weight, weight, weight, weight, + weight, weight, weight, weight, + weight, weight, weight, weight, + }; + op = new ConvolveOp(new Kernel(4, 4, blurKernel), ConvolveOp.EDGE_NO_OP, null); + } + else { + final float weight = 1.0f/18.0f; + final float[] blurKernel = { + 1*weight, 2*weight, 1*weight, + 2*weight, 6*weight, 2*weight, + 1*weight, 2*weight, 1*weight + }; + if (colorConversion) { + BufferedImage colored = new BufferedImage(bi.getWidth(), + bi.getHeight(), colorConversion?BufferedImage.TYPE_INT_ARGB:bi.getType()); + Graphics2D bg = (Graphics2D) colored.getGraphics(); + bg.setRenderingHint(RenderingHints.KEY_INTERPOLATION, + RenderingHints.VALUE_INTERPOLATION_BILINEAR); + bg.drawImage(bi, 0, 0, bi.getWidth(), bi.getHeight(), null); + bi = colored; + } + op = new ConvolveOp(new Kernel(3, 3, blurKernel), ConvolveOp.EDGE_NO_OP, null); + } + + BufferedImage blured = op.createCompatibleDestImage(bi, + colorConversion?ColorModel.getRGBdefault():bi.getColorModel()); + + op.filter(bi, blured); + bi = blured; + isBlured = true; + } + + this.g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER)); + + //Image quality is better when using texturepaint instead of drawimage + //but it is also slower :( + this.g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, + RenderingHints.VALUE_INTERPOLATION_BILINEAR); + // banded rendering may lead to lower memory consumption for e.g. scanned PDFs with large images + int bandSize = Configuration.getInstance().getThresholdForBandedImageRendering(); + if (bandSize > 0 && bi.getHeight() > bandSize) { + // draw in bands + int tempMax = bi.getHeight(); + for (int offset=0; offset
  • Watchable.RUNNING when there are commands to be processed + *
  • Watchable.NEEDS_DATA when there are no commands to be + * processed, but the page is not yet complete + *
  • Watchable.COMPLETED when the page is done and all + * the commands have been processed + *
  • Watchable.STOPPED if the image we are rendering into + * has gone away + * + */ + @Override + public int iterate() throws Exception { + // make sure we have a page to render + if (this.page == null) { + return Watchable.COMPLETED; + } + + // check if this renderer is based on a weak reference to a graphics + // object. If it is, and the graphics is no longer valid, then just quit + BufferedImage bi = null; + if (this.imageRef != null) { + bi = this.imageRef.get(); + if (bi == null) { + PDFDebugger.debug("Image went away. Stopping"); + return Watchable.STOPPED; + } + + this.g = bi.createGraphics(); + } + + // check if there are any commands to parse. If there aren't, + // just return, but check if we'return really finished or not + if (this.currentCommand >= this.page.getCommandCount()) { + if (this.page.isFinished()) { + return Watchable.COMPLETED; + } else { + return Watchable.NEEDS_DATA; + } + } + + // find the current command + PDFCmd cmd = this.page.getCommand(this.currentCommand++); + if (cmd == null) { + // uh oh. Synchronization problem! + throw new PDFParseException("Command not found!"); + } + + // execute the command + Rectangle2D dirtyRegion = cmd.execute(this); + + // append to the global dirty region + this.globalDirtyRegion = addDirtyRegion(dirtyRegion, this.globalDirtyRegion); + this.unupdatedRegion = addDirtyRegion(dirtyRegion, this.unupdatedRegion); + + long now = System.currentTimeMillis(); + if (now > this.then || rendererFinished()) { + // now tell any observers, so they can repaint + notifyObservers(bi, this.unupdatedRegion); + this.unupdatedRegion = null; + this.then = now + UPDATE_DURATION; + } + + // if we are based on a reference to a graphics, don't hold on to it + // since that will prevent the image from being collected. + if (this.imageRef != null) { + this.g = null; + } + + // if we need to stop, it will be caught at the start of the next + // iteration. + return Watchable.RUNNING; + } + + /** + * Called when iteration has stopped + */ + @Override + public void cleanup() { + this.page = null; + this.state = null; + this.stack = null; + this.globalDirtyRegion = null; + this.lastShape = null; + + this.observers.clear(); + + // keep around the image ref and image info for use in + // late addObserver() call + } + + /** + * Append a rectangle to the total dirty region of this shape + */ + private Rectangle2D addDirtyRegion(Rectangle2D region, Rectangle2D glob) { + if (region == null) { + return glob; + } else if (glob == null) { + return region; + } else { + Rectangle2D.union(glob, region, glob); + return glob; + } + } + + /** + * Determine if we are finished + */ + private boolean rendererFinished() { + if (this.page == null) { + return true; + } + + return (this.page.isFinished() && this.currentCommand == this.page.getCommandCount()); + } + + /** + * Notify the observer that a region of the image has changed + */ + private void notifyObservers(BufferedImage bi, Rectangle2D region) { + if (bi == null) { + return; + } + + int startx, starty, width, height; + int flags = 0; + + // don't do anything if nothing is there or no one is listening + if ((region == null && !rendererFinished()) || this.observers == null || + this.observers.size() == 0) { + return; + } + + if (region != null) { + // get the image data for the total dirty region + startx = (int) Math.floor(region.getMinX()); + starty = (int) Math.floor(region.getMinY()); + width = (int) Math.ceil(region.getWidth()); + height = (int) Math.ceil(region.getHeight()); + + // sometimes width or height is negative. Grrr... + if (width < 0) { + startx += width; + width = -width; + } + if (height < 0) { + starty += height; + height = -height; + } + + flags = 0; + } else { + startx = 0; + starty = 0; + width = this.imageinfo.width; + height = this.imageinfo.height; + } + if (rendererFinished()) { + flags |= ImageObserver.ALLBITS; + // forget about the Graphics -- allows the image to be + // garbage collected. + this.g = null; + } else { + flags |= ImageObserver.SOMEBITS; + } + + synchronized (this.observers) { + for (Iterator i = this.observers.iterator(); i.hasNext();) { + ImageObserver observer = i.next(); + + boolean result = observer.imageUpdate(bi, flags, + startx, starty, + width, height); + + // if result is false, the observer no longer wants to + // be notified of changes + if (!result) { + i.remove(); + } + } + } + } + + /** + * Convert an image mask into an image by painting over any pixels + * that have a value in the image with the current paint + */ + private BufferedImage getMaskedImage(BufferedImage bi) { + + // get the color of the current paint + final Paint paint = state.fillPaint.getPaint(); + if (!(paint instanceof Color)) { + // TODO - support other types of Paint + return bi; + } + + Color col = (Color) paint; + ColorModel colorModel = bi.getColorModel(); + if (colorModel instanceof IndexColorModel) { + int mapSize = ((IndexColorModel) colorModel).getMapSize(); + int pixelSize = colorModel.getPixelSize(); + if (mapSize == 2 && pixelSize == 1) { + // we have a monochrome image mask with 1 bit per pixel + // swap out the standard color with the current paint color + int[] rgbValues = new int[2]; + ((IndexColorModel) colorModel).getRGBs(rgbValues); + byte[] colorComponents = null; + if (rgbValues[0] == 0xff000000) { + // normal case color at 0 + colorComponents = new byte[]{ + (byte) col.getRed(), + (byte) col.getGreen(), + (byte) col.getBlue(), + (byte) col.getAlpha(), + 0, 0, 0, 0 // the background is transparent + }; + } + else if (rgbValues[1] == 0xff000000){ + // alternate case color at 1 + colorComponents = new byte[]{ + 0, 0, 0, 0, // the background is transparent + (byte) col.getRed(), + (byte) col.getGreen(), + (byte) col.getBlue(), + (byte) col.getAlpha() + }; + } + + if (colorComponents != null) { + // replace mapped colors + int startIndex = 0; + boolean hasAlpha = true; + ColorModel replacementColorModel = new IndexColorModel(pixelSize, mapSize, colorComponents, startIndex, hasAlpha); + WritableRaster raster = bi.getRaster(); + BufferedImage adaptedImage = new BufferedImage(replacementColorModel, raster, false, null); + return adaptedImage; + } + else { + return bi; // no color replacement + } + } + } + + // format as 8 bits each of ARGB + int paintColor = col.getAlpha() << 24; + paintColor |= col.getRed() << 16; + paintColor |= col.getGreen() << 8; + paintColor |= col.getBlue(); + + // transparent (alpha = 1) + int noColor = 0; + + // get the coordinates of the source image + int startX = bi.getMinX(); + int startY = bi.getMinY(); + int width = bi.getWidth(); + int height = bi.getHeight(); + + // create a destion image of the same size + BufferedImage dstImage = + new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); + + // copy the pixels row by row + for (int i = 0; i < height; i++) { + int[] srcPixels = new int[width]; + int[] dstPixels = new int[srcPixels.length]; + + // read a row of pixels from the source + bi.getRGB(startX, startY + i, width, 1, srcPixels, 0, height); + + // figure out which ones should get painted + for (int j = 0; j < srcPixels.length; j++) { + if (srcPixels[j] == 0xff000000) { + dstPixels[j] = paintColor; + } else { + dstPixels[j] = noColor; + } + } + + // write the destination image + dstImage.setRGB(startX, startY + i, width, 1, dstPixels, 0, height); + } + + return dstImage; + } + + class GraphicsState implements Cloneable { + + /** the clip region */ + Shape cliprgn; + /** the current stroke */ + BasicStroke stroke; + /** the current paint for drawing strokes */ + PDFPaint strokePaint; + /** the current paint for filling shapes */ + PDFPaint fillPaint; + /** the current compositing alpha for stroking */ + AlphaComposite strokeAlpha; + /** the current compositing alpha for filling */ + AlphaComposite fillAlpha; + /** the current transform */ + AffineTransform xform; + + /** Clone this Graphics state. + * + * Note that cliprgn is not cloned. It must be set manually from + * the current graphics object's clip + */ + @Override + public Object clone() { + GraphicsState cState = new GraphicsState(); + cState.cliprgn = null; + + // copy immutable fields + cState.strokePaint = this.strokePaint; + cState.fillPaint = this.fillPaint; + cState.strokeAlpha = this.strokeAlpha; + cState.fillAlpha = this.fillAlpha; + + // clone mutable fields + cState.stroke = new BasicStroke(this.stroke.getLineWidth(), + this.stroke.getEndCap(), + this.stroke.getLineJoin(), + this.stroke.getMiterLimit(), + this.stroke.getDashArray(), + this.stroke.getDashPhase()); + cState.xform = (AffineTransform) this.xform.clone(); + + return cState; + } + } + + /************************************************************************* + * @return Returns the lastTransform. + ************************************************************************/ + public AffineTransform getLastTransform() { + return this.lastTransform; + } + + /************************************************************************* + * Remember the current transformation + ************************************************************************/ + public void rememberTransformation() { + this.lastTransform = this.state.xform; + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFShapeCmd.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFShapeCmd.java new file mode 100644 index 000000000..5f9932aef --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFShapeCmd.java @@ -0,0 +1,204 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.sun.pdfview; +import java.awt.BasicStroke; +import java.awt.geom.AffineTransform; +import java.awt.geom.GeneralPath; +import java.awt.geom.PathIterator; +import java.awt.geom.Rectangle2D; + +/** +* Encapsulates a path. Also contains extra fields and logic to check +* for consecutive abutting anti-aliased regions. We stroke the shared +* line between these regions again with a 1-pixel wide line so that +* the background doesn't show through between them. +* +* @author Mike Wessler +*/ +public class PDFShapeCmd extends PDFCmd { + /** stroke the outline of the path with the stroke paint */ + public static final int STROKE = 1; + /** fill the path with the fill paint */ + public static final int FILL = 2; + /** perform both stroke and fill */ + public static final int BOTH = 3; + /** set the clip region to the path */ + public static final int CLIP = 4; + /** base path */ + private final GeneralPath gp; + /** the style */ + private final int style; + /** the bounding box of the path */ + // private Rectangle2D bounds; + /** the stroke style for the anti-antialias stroke */ + BasicStroke againstroke = new BasicStroke(2, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL); + private boolean autoAdjustStroke = false; + + /** + * create a new PDFShapeCmd and check it against the previous one + * to find any shared edges. + * + * @param gp + * the path + * @param style + * the style: an OR of STROKE, FILL, or CLIP. As a + * convenience, BOTH = STROKE | FILL. + */ + public PDFShapeCmd(GeneralPath gp, int style, boolean autoAdjustStroke) { + this.gp = gp; + this.style = style; + this.autoAdjustStroke = autoAdjustStroke; + } + + /** + * perform the stroke and record the dirty region + */ + @Override + public Rectangle2D execute(PDFRenderer state) { + Rectangle2D rect = null; + if ((this.style & FILL) != 0) { + rect = state.fill(this.gp); + GeneralPath strokeagain = checkOverlap(state); + if (strokeagain != null) { + state.draw(strokeagain, this.againstroke); + } + if (this.gp != null) { + state.setLastShape(this.gp); + state.rememberTransformation(); + } + } + if ((this.style & STROKE) != 0) { + Rectangle2D strokeRect = state.stroke(this.gp, autoAdjustStroke); + if (rect == null) { + rect = strokeRect; + } else { + rect = rect.createUnion(strokeRect); + } + } + if ((this.style & CLIP) != 0) { + state.clip(this.gp); + } + return rect; + } + + /** + * Check for overlap with the previous shape to make anti-aliased shapes + * that are near each other look good + */ + private GeneralPath checkOverlap(PDFRenderer state) { + if (this.style == FILL && this.gp != null && state.getLastShape() != null) { + float mypoints[] = new float[16]; + float prevpoints[] = new float[16]; + int mycount = getPoints(this.gp, mypoints, state.getTransform()); + int prevcount = getPoints(state.getLastShape(), prevpoints, state.getLastTransform()); + // now check mypoints against prevpoints for opposite pairs: + if (mypoints != null && prevpoints != null) { + for (int i = 0; i < prevcount; i += 4) { + for (int j = 0; j < mycount; j += 4) { + if ((Math.abs(mypoints[j + 2] - prevpoints[i]) < 0.01 && Math.abs(mypoints[j + 3] - prevpoints[i + 1]) < 0.01 && Math.abs(mypoints[j] - prevpoints[i + 2]) < 0.01 && Math + .abs(mypoints[j + 1] - prevpoints[i + 3]) < 0.01)) { + // it seems that need to use the original points location (without the Affine Transform) + mypoints = new float[16]; + getPoints(this.gp, mypoints, null);// without AffineTransform + + GeneralPath strokeagain = new GeneralPath(); + strokeagain.moveTo(mypoints[j], mypoints[j + 1]); + strokeagain.lineTo(mypoints[j + 2], mypoints[j + 3]); + return strokeagain; + } + } + } + } + } + // no issues + return null; + } + + /** + * Get an array of 16 points from a path + * + * @return the number of points we actually got + */ + private int getPoints(GeneralPath path, float[] mypoints, AffineTransform at) { + int count = 0; + float x = 0; + float y = 0; + float startx = 0; + float starty = 0; + float[] coords = new float[6]; + PathIterator pi = path.getPathIterator(at); + while (!pi.isDone()) { + if (count >= mypoints.length) { + mypoints = null; + break; + } + int pathtype = pi.currentSegment(coords); + switch (pathtype) { + case PathIterator.SEG_MOVETO: + startx = x = coords[0]; + starty = y = coords[1]; + break; + case PathIterator.SEG_LINETO: + mypoints[count++] = x; + mypoints[count++] = y; + x = mypoints[count++] = coords[0]; + y = mypoints[count++] = coords[1]; + break; + case PathIterator.SEG_QUADTO: + x = coords[2]; + y = coords[3]; + break; + case PathIterator.SEG_CUBICTO: + x = mypoints[4]; + y = mypoints[5]; + break; + case PathIterator.SEG_CLOSE: + mypoints[count++] = x; + mypoints[count++] = y; + x = mypoints[count++] = startx; + y = mypoints[count++] = starty; + break; + } + pi.next(); + } + return count; + } + + /** + * Get detailed information about this shape + */ + @Override + public String getDetails() { + StringBuffer sb = new StringBuffer(); + Rectangle2D b = this.gp.getBounds2D(); + sb.append("ShapeCommand at: " + b.getX() + ", " + b.getY() + "\n"); + sb.append("Size: " + b.getWidth() + " x " + b.getHeight() + "\n"); + sb.append("Mode: "); + if ((this.style & FILL) != 0) { + sb.append("FILL "); + } + if ((this.style & STROKE) != 0) { + sb.append("STROKE "); + } + if ((this.style & CLIP) != 0) { + sb.append("CLIP"); + } + return sb.toString(); + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFStringUtil.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFStringUtil.java new file mode 100644 index 000000000..75a408f03 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFStringUtil.java @@ -0,0 +1,230 @@ +/* + * Copyright 2008 Pirion Systems Pty Ltd, 139 Warry St, + * Fortitude Valley, Queensland, Australia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.sun.pdfview; + +import java.io.*; +import java.nio.CharBuffer; +import java.nio.charset.CharacterCodingException; + +/** + *

    Utility methods for dealing with PDF Strings, such as: + *

      + *
    • {@link #asTextString(String) converting to text strings} + *
    • {@link #asPDFDocEncoded(String) converting to PDFDocEncoded strings} + *
    • {@link #asUTF16BEEncoded converting to UTF-16BE strings} + *
    • converting basic strings between {@link #asBytes(String) byte} and + * {@link #asBasicString(byte[], int, int) string} representations + *

    + * + *

    We refer to basic strings as those corresponding to the PDF 'string' type. + * PDFRenderer represents these as {@link String}s, though this is somewhat + * deceiving, as they are, effectively, just sequences of bytes, although byte + * values <= 127 do correspond to the ASCII character set. Outside of this, + * the 'string' type, as repesented by basic strings do not possess any + * character set or encoding, and byte values >= 128 are entirely acceptable. + * For a basic string as represented by a String, each character has a value + * less than 256 and is represented in the String as if the bytes represented as + * it were in ISO-8859-1 encoding. This, however, is merely for convenience. For + * strings that are user visible, and that don't merely represent some + * identifying token, the PDF standard employs a 'text string' type that offers + * the basic string as an encoding of in either UTF-16BE (with a byte order + * marking) or a specific 8-byte encoding, PDFDocEncoding. Using a basic string + * without conversion when the actual type is a 'text string' is erroneous + * (though without consequence if the string consists only of ASCII + * alphanumeric values). Care must be taken to either convert basic strings to + * text strings (also expressed as a String) when appropriate, using either the + * methods in this class, or {@link PDFObject#getTextStringValue()}}. For + * strings that are 'byte strings', {@link #asBytes(String)} or {@link + * PDFObject#getStream()} should be used.

    . + * + * @author Luke Kirby + */ +public class PDFStringUtil { + + /** + *

    Take a basic PDF string and determine if it is in UTF-16BE encoding + * by looking at the lead characters for a byte order marking (BOM). If it + * appears to be UTF-16BE, we return the string representation of the + * UTF-16BE encoding of those bytes. If the BOM is not present, the bytes + * from the input string are decoded using the PDFDocEncoding charset.

    + * + *

    From the PDF Reference 1.7, p158: + * + *

    The text string type is used for character strings that are + * encoded in either PDFDocEncoding or the UTF-16BE Unicode character + * encoding scheme. PDFDocEncoding can encode all of the ISO Latin 1 + * character set and is documented in Appendix D. UTF-16BE can encode all + * Unicode characters. UTF-16BE and Unicode character encoding are + * described in the Unicode Standard by the Unicode Consortium (see the + * Bibliography). Note that PDFDocEncoding does not support all Unicode + * characters whereas UTF-16BE does.
    + *

    + * + * @param basicString the basic PDF string, as offered by {@link + * PDFObject#getStringValue()} + * @return either the original input, or the input decoded as UTF-16 + */ + public static String asTextString(String basicString) { + if (basicString == null) { + return null; + } + + if (basicString.length() >= 2) { + if ((basicString.charAt(0) == (char) 0xFE + && basicString.charAt(1) == (char) 0xFF)) { + // found the BOM! + return asUTF16BEEncoded(basicString); + } + } + + // it's not UTF16-BE encoded, so it must be + return asPDFDocEncoded(basicString); + } + + /** + * Take a basic PDF string and produce a string of its bytes as encoded in + * PDFDocEncoding. The PDFDocEncoding is described in the PDF Reference. + * + * @param basicString the basic PDF string, as offered by {@link + * PDFObject#getStringValue()} + * @return the decoding of the string's bytes in PDFDocEncoding + */ + public static String asPDFDocEncoded(String basicString) { + final StringBuilder buf = new StringBuilder(basicString.length()); + for (int i = 0; i < basicString.length(); ++i) { + final char c = PDF_DOC_ENCODING_MAP[basicString.charAt(i) & 0xFF]; + buf.append(c); + } + return buf.toString(); + } + + public byte[] toPDFDocEncoded(String string) + throws CharacterCodingException { + // we can just grab array since we know that if charset completes + // without error then there's the output buffer will be exactly + // correct in size, since there's only ever 1 byte for one char. + return new PDFDocCharsetEncoder().encode(CharBuffer.wrap(string)). + array(); + } + + /** + * Take a basic PDF string and produce a string from its bytes as an + * UTF16-BE encoding. The first 2 bytes are presumed to be the big-endian + * byte markers, 0xFE and 0xFF; that is not checked by this method. + * + * @param basicString the basic PDF string, as offered by {@link + * PDFObject#getStringValue()} + * @return the decoding of the string's bytes in UTF16-BE + */ + public static String asUTF16BEEncoded(String basicString) { + try { + return new String(asBytes(basicString), + 2, basicString.length() - 2, "UTF-16BE"); + } catch (UnsupportedEncodingException e) { + // UTF-16BE should always be available + throw new RuntimeException("No UTF-16BE charset!"); + } + } + + /** + * Get the corresponding byte array for a basic string. This is effectively + * the char[] array cast to bytes[], as chars in basic strings only use the + * least significant byte. + * + * @param basicString the basic PDF string, as offered by {@link + * PDFObject#getStringValue()} + * @return the bytes corresponding to its characters + */ + public static byte[] asBytes(String basicString) { + final byte[] b = new byte[basicString.length()]; + for (int i = 0; i < b.length; ++i) { + b[i] = (byte) basicString.charAt(i); + } + return b; + } + + /** + * Create a basic string from bytes. This is effectively the byte array + * cast to a char array and turned into a String. + * @param bytes the source of the bytes for the basic string + * @param offset the offset into butes where the string starts + * @param length the number of bytes to turn into a string + * @return the corresponding string + */ + public static String asBasicString( + byte[] bytes, int offset, int length) { + final char[] c = new char[length]; + for (int i = 0; i < c.length; ++i) { + c[i] = (char) bytes[i + offset]; + } + return new String(c); + } + + /** + * Create a basic string from bytes. This is effectively the byte array + * cast to a char array and turned into a String. + * @param bytes the bytes, all of which are used + * @return the corresponding string + */ + public static String asBasicString(byte[] bytes) { + return asBasicString(bytes, 0, bytes.length); + } + + /** + * Maps from PDFDocEncoding bytes to unicode characters. Table generated + * by PDFDocEncodingMapGenerator. + */ + final static char[] PDF_DOC_ENCODING_MAP = new char[] { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, //00-07 + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, //08-0F + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, //10-17 + 0x02D8, 0x02C7, 0x02C6, 0x02D9, 0x02DD, 0x02DB, 0x02DA, 0x02DC, //18-1F + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, //20-27 + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, //28-2F + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, //30-37 + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, //38-3F + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, //40-47 + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, //48-4F + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, //50-57 + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, //58-5F + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, //60-67 + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, //68-6F + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, //70-77 + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0xFFFD, //78-7F + 0x2022, 0x2020, 0x2021, 0x2026, 0x2014, 0x2013, 0x0192, 0x2044, //80-87 + 0x2039, 0x203A, 0x2212, 0x2030, 0x201E, 0x201C, 0x201D, 0x2018, //88-8F + 0x2019, 0x201A, 0x2122, 0xFB01, 0xFB02, 0x0141, 0x0152, 0x0160, //90-97 + 0x0178, 0x017D, 0x0131, 0x0142, 0x0153, 0x0161, 0x017E, 0xFFFD, //98-9F + 0x20AC, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, //A0-A7 + 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0xFFFD, 0x00AE, 0x00AF, //A8-AF + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, //B0-B7 + 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, //B8-BF + 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, //C0-C7 + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, //C8-CF + 0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, //D0-D7 + 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF, //D8-DF + 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, //E0-E7 + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, //E8-EF + 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, //F0-F7 + 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF, //F8-FF + }; + + + +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFTextFormat.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFTextFormat.java new file mode 100644 index 000000000..d6fab0774 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFTextFormat.java @@ -0,0 +1,390 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.sun.pdfview; + +import java.awt.Color; +import java.awt.geom.AffineTransform; +import java.awt.geom.GeneralPath; +import java.awt.geom.Point2D; +import java.util.Iterator; +import java.util.List; + +import com.sun.pdfview.font.PDFFont; +import com.sun.pdfview.font.PDFGlyph; + +/** +* a class encapsulating the text state +* +* @author Mike Wessler +*/ +public class PDFTextFormat implements Cloneable { + /** character spacing */ + private float tc = 0; + /** word spacing */ + private float tw = 0; + /** horizontal scaling */ + private float th = 1; + /** leading */ + private float tl = 0; + /** rise amount */ + private float tr = 0; + /** text mode */ + private int tm = PDFShapeCmd.FILL; + /** text knockout */ + private float tk = 0; + /** current matrix transform */ + private final AffineTransform cur; + /** matrix transform at start of line */ + private AffineTransform line; + /** font */ + private PDFFont font; + /** font size */ + private float fsize = 1; + /** are we between BT and ET? */ + private boolean inuse = false; + // private Object array[]= new Object[1]; + /** build text rep of word */ + private final StringBuffer word = new StringBuffer(); + // this is where we build and keep the word list for this page. + /** start location of the hunk of text */ + private final Point2D.Float wordStart; + /** location of the end of the previous hunk of text */ + private final Point2D.Float prevEnd; + + /** + * create a new PDFTextFormat, with initial values + */ + public PDFTextFormat() { + this.cur = new AffineTransform(); + this.line = new AffineTransform(); + this.wordStart = new Point2D.Float(-100, -100); + this.prevEnd = new Point2D.Float(-100, -100); + this.tc = this.tw = this.tr = this.tk = 0; + this.tm = PDFShapeCmd.FILL; + this.th = 1; + } + + /** + * reset the PDFTextFormat for a new run + */ + public void reset() { + this.cur.setToIdentity(); + this.line.setToIdentity(); + this.inuse = true; + this.word.setLength(0); + } + + /** + * end a span of text + */ + public void end() { + this.inuse = false; + } + + /** get the char spacing */ + public float getCharSpacing() { + return this.tc; + } + + /** set the character spacing */ + public void setCharSpacing(float spc) { + this.tc = spc; + } + + /** get the word spacing */ + public float getWordSpacing() { + return this.tw; + } + + /** set the word spacing */ + public void setWordSpacing(float spc) { + this.tw = spc; + } + + /** + * Get the horizontal scale + * + * @return the horizontal scale, in percent + */ + public float getHorizontalScale() { + return this.th * 100; + } + + /** + * set the horizontal scale. + * + * @param scl + * the horizontal scale, in percent (100=normal) + */ + public void setHorizontalScale(float scl) { + this.th = scl / 100; + } + + /** get the leading */ + public float getLeading() { + return this.tl; + } + + /** set the leading */ + public void setLeading(float spc) { + this.tl = spc; + } + + /** get the font */ + public PDFFont getFont() { + return this.font; + } + + /** get the font size */ + public float getFontSize() { + return this.fsize; + } + + /** set the font and size */ + public void setFont(PDFFont f, float size) { + this.font = f; + this.fsize = size; + } + + /** + * Get the mode of the text + */ + public int getMode() { + return this.tm; + } + + /** + * set the mode of the text. The correspondence of m to mode is + * show in the following table. m is a value from 0-7 in binary: + * + * 000 Fill + * 001 Stroke + * 010 Fill + Stroke + * 011 Nothing + * 100 Fill + Clip + * 101 Stroke + Clip + * 110 Fill + Stroke + Clip + * 111 Clip + * + * Therefore: Fill corresponds to the low bit being 0; Clip + * corresponds to the hight bit being 1; and Stroke corresponds + * to the middle xor low bit being 1. + */ + public void setMode(int m) { + int mode = 0; + if ((m & 0x1) == 0) { + mode |= PDFShapeCmd.FILL; + } + if ((m & 0x4) != 0) { + mode |= PDFShapeCmd.CLIP; + } + if (((m & 0x1) ^ ((m & 0x2) >> 1)) != 0) { + mode |= PDFShapeCmd.STROKE; + } + this.tm = mode; + } + + /** + * Set the mode from another text format mode + * + * @param mode + * the text render mode using the + * codes from PDFShapeCmd and not the wacky PDF codes + */ + public void setTextFormatMode(int mode) { + this.tm = mode; + } + + /** + * Get the rise + */ + public float getRise() { + return this.tr; + } + + /** + * set the rise + */ + public void setRise(float spc) { + this.tr = spc; + } + + /** + * perform a carriage return + */ + public void carriageReturn() { + carriageReturn(0, -this.tl); + } + + /** + * perform a carriage return by translating by x and y. The next + * carriage return will be relative to the new location. + */ + public void carriageReturn(float x, float y) { + this.line.concatenate(AffineTransform.getTranslateInstance(x, y)); + this.cur.setTransform(this.line); + } + + /** + * Get the current transform + */ + public AffineTransform getTransform() { + return this.cur; + } + + /** + * set the transform matrix directly + */ + public void setMatrix(float[] matrix) { + this.line = new AffineTransform(matrix); + this.cur.setTransform(this.line); + } + + /** + * add some text to the page. + * + * @param cmds + * the PDFPage to add the commands to + * @param text + * the text to add + */ + public void doText(PDFPage cmds, String text, boolean autoAdjustStroke) { + Point2D.Float zero = new Point2D.Float(); + AffineTransform scale = new AffineTransform(this.fsize * this.th, 0, /* 0 */ + 0, this.fsize, /* 0 */ + 0, this.tr /* 1 */); + AffineTransform at = new AffineTransform(); + List l = this.font.getGlyphs(text); + if (PDFDebugger.SHOW_TEXT_ANCHOR) { + if (PDFDebugger.DEBUG_TEXT) { + PDFDebugger.debug("POINT count: " + l.size()); + } + } + for (Iterator i = l.iterator(); i.hasNext();) { + PDFGlyph glyph = i.next(); + at.setTransform(this.cur); + at.concatenate(scale); + if (PDFDebugger.SHOW_TEXT_REGIONS) { + GeneralPath path = new GeneralPath(); + path.moveTo(0, 0); + path.lineTo(1, 0); + path.lineTo(1, 1); + path.lineTo(0, 1); + path.lineTo(0, 0); + path.closePath(); + path = (GeneralPath) path.createTransformedShape(at); + if (PDFDebugger.DEBUG_TEXT) { + PDFDebugger.debug("BOX " + path.getBounds()); + } + PDFCmd lastColor = cmds.findLastCommand(PDFFillPaintCmd.class); + if (PDFDebugger.DEBUG_TEXT) { + PDFDebugger.debug("BOX " + lastColor); + } + cmds.addFillPaint(PDFPaint.getColorPaint(new Color(160, 160, 255))); + cmds.addPath(path, PDFShapeCmd.FILL, autoAdjustStroke); + if (lastColor != null) { + cmds.addCommand(lastColor); + } + } + Point2D advance = glyph.getAdvance(); + if (!PDFDebugger.DISABLE_TEXT) { + advance = glyph.addCommands(cmds, at, this.tm); + } + double advanceX = (advance.getX() * this.fsize) + this.tc; + double advanceY = advance.getY() + this.fsize; + if (glyph.getChar() == ' ') { + advanceX += this.tw; + } + advanceX *= this.th; + if (PDFDebugger.SHOW_TEXT_ANCHOR) { + AffineTransform at2 = new AffineTransform(); + at2.setTransform(this.cur); + GeneralPath path = new GeneralPath(); + path.moveTo(0, 0); + path.lineTo(6, 0); + path.lineTo(6, 6); + path.lineTo(0, 6); + path.lineTo(0, 0); + path.closePath(); + path = (GeneralPath) path.createTransformedShape(at2); + if (PDFDebugger.DEBUG_TEXT) { + PDFDebugger.debug("POINT " + advance); + } + PDFCmd lastColor = cmds.findLastCommand(PDFFillPaintCmd.class); + cmds.addFillPaint(PDFPaint.getColorPaint(new Color(255, 0, 0))); + cmds.addPath(path, PDFShapeCmd.FILL, autoAdjustStroke); + if (lastColor != null) { + cmds.addCommand(lastColor); + } + } + this.cur.translate(advanceX, advance.getY()); + } + this.cur.transform(zero, this.prevEnd); + } + + /** + * add some text to the page. + * + * @param cmds + * the PDFPage to add the commands to + * @param ary + * an array of Strings and Doubles, where the Strings + * represent text to be added, and the Doubles represent kerning + * amounts. + */ + public void doText(PDFPage cmds, Object ary[], boolean autoAdjustStroke) throws PDFParseException { + for (int i = 0; i < ary.length; i++) { + if (ary[i] instanceof String) { + doText(cmds, (String) ary[i], autoAdjustStroke); + } else if (ary[i] instanceof Double) { + float val = ((Double) ary[i]).floatValue() / 1000f; + this.cur.translate(-val * this.fsize * this.th, 0); + } else { + throw new PDFParseException("Bad element in TJ array"); + } + } + } + + /** + * finish any unfinished words. TODO: write this! + */ + public void flush() { + // TODO: finish any unfinished words + } + + /** + * Clone the text format + */ + @Override + public Object clone() { + PDFTextFormat newFormat = new PDFTextFormat(); + // copy values + newFormat.setCharSpacing(getCharSpacing()); + newFormat.setWordSpacing(getWordSpacing()); + newFormat.setHorizontalScale(getHorizontalScale()); + newFormat.setLeading(getLeading()); + newFormat.setTextFormatMode(getMode()); + newFormat.setRise(getRise()); + // copy immutable fields + newFormat.setFont(getFont(), getFontSize()); + // clone transform (mutable) + // newFormat.getTransform().setTransform(getTransform()); + return newFormat; + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFXref.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFXref.java new file mode 100644 index 000000000..74f66dd42 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFXref.java @@ -0,0 +1,153 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.sun.pdfview; + +import java.lang.ref.SoftReference; + +/** + * a cross reference representing a line in the PDF cross referencing + * table. + *

    + * There are two forms of the PDFXref, destinguished by absolutely nothing. + * The first type of PDFXref is used as indirect references in a PDFObject. + * In this type, the id is an index number into the object cross reference + * table. The id will range from 0 to the size of the cross reference + * table. + *

    + * The second form is used in the Java representation of the cross reference + * table. In this form, the id is the file position of the start of the + * object in the PDF file. See the use of both of these in the + * PDFFile.dereference() method, which takes a PDFXref of the first form, + * and uses (internally) a PDFXref of the second form. + *

    + * This is an unhappy state of affairs, and should be fixed. Fortunatly, + * the two uses have already been factored out as two different methods. + * + * @author Mike Wessler + */ +public class PDFXref { + + private int id; + private int generation; + private final boolean compressed; + + // this field is only used in PDFFile.objIdx + private SoftReference reference = null; + + /** + * create a new PDFXref, given a parsed id and generation. + */ + public PDFXref(int id, int gen) { + this.id = id; + this.generation = gen; + this.compressed = false; + } + + /** + * create a new PDFXref, given a parsed id, compressedObjId and index + */ + public PDFXref(int id, int gen, boolean compressed) { + this.id = id; + this.generation = gen; + this.compressed = compressed; + } + + /** + * create a new PDFXref, given a sequence of bytes representing the + * fixed-width cross reference table line + */ + public PDFXref(byte[] line) { + if (line == null) { + this.id = -1; + this.generation = -1; + } else { + this.id = Integer.parseInt(new String(line, 0, 10).trim()); + this.generation = Integer.parseInt(new String(line, 11, 5).trim()); + } + this.compressed = false; + } + + /** + * get the character index into the file of the start of this object + */ + public int getFilePos() { + return this.id; + } + + /** + * get the generation of this object + */ + public int getGeneration() { + return this.generation; + } + + /** + * get the generation of this object + */ + public int getIndex() { + return this.generation; + } + + /** + * get the object number of this object + */ + public int getID() { + return this.id; + } + + /** + * get compressed flag of this object + */ + public boolean getCompressed() { + return this.compressed; + } + + + /** + * Get the object this reference refers to, or null if it hasn't been + * set. + * @return the object if it exists, or null if not + */ + public PDFObject getObject() { + if (this.reference != null) { + return this.reference.get(); + } + + return null; + } + + /** + * Set the object this reference refers to. + */ + public void setObject(PDFObject obj) { + this.reference = new SoftReference(obj); + } + + @Override + public boolean equals(Object obj) { + return (obj instanceof PDFXref) && + ((PDFXref)obj).id == id && + ((PDFXref)obj).generation == generation; + } + + @Override + public int hashCode() { + return id ^ (generation << 8); + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PdfSubByteSampleModel.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PdfSubByteSampleModel.java new file mode 100644 index 000000000..16f286464 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PdfSubByteSampleModel.java @@ -0,0 +1,143 @@ +/* + * $Id: PdfSubByteSampleModel.java,v 1.1 2010-05-23 22:07:05 lujke Exp $ + * + * Copyright 2010 Pirion Systems Pty Ltd, 139 Warry St, + * Fortitude Valley, Queensland, Australia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.sun.pdfview; + +import java.awt.image.DataBuffer; +import java.awt.image.SampleModel; + +/** + * Provides a read-only sample-model where components are less than a byte in + * width while allowing for pixels to cross byte-boundaries. For example, this + * allows 2 pixels made of 3 4-bit-bands (p[pixel,band]) + * to be stored in 3 bytes as p[0,1] p[0,2] | p[0,3] p[1,0] | p[1,1] p[1,2]. + * {@link java.awt.image.MultiPixelPackedSampleModel}, which allows for sub-byte + * components, does not allow for such byte spanning, while the PDF + * specification does permit it -- hence the existence of this class. + * + * @author Luke Kirby, Pirion Systems + */ +public class PdfSubByteSampleModel extends SampleModel +{ + private final int transferBytesPerPixel; + private final int storageBitsPerPixel; + private final int bitsPerLine; + private final int bitsPerBand; + private final int componentMask; + private final int[] sampleSize; + private final int ignoredBitsPerComponentPerByte; + + public PdfSubByteSampleModel(int w, int h, int numComponents, int bitsPerComponent) + { + super(DataBuffer.TYPE_BYTE, w, h, numComponents); + assert bitsPerComponent < 8 : "This is designed just for use with per-component sizes of less than 8 bits; " + + "you should probably use PixelInterleavedSampleModel"; + assert bitsPerComponent == 1 || bitsPerComponent == 2 || bitsPerComponent == 4 : + "we don't want to grab components across byte boundaries"; + transferBytesPerPixel = (numComponents * bitsPerComponent + 7) / 8; + storageBitsPerPixel = numComponents * bitsPerComponent; + // account for possible bits of padding on the end + bitsPerLine = 8 * ((storageBitsPerPixel * w + 7) / 8); + this.bitsPerBand = bitsPerComponent; + componentMask = (1 << this.bitsPerBand) - 1; + + sampleSize = new int[numComponents]; + for (int i = 0; i < sampleSize.length; ++i) { + sampleSize[i] = bitsPerComponent; + } + ignoredBitsPerComponentPerByte = 8 - bitsPerBand; + } + + @Override + public int getNumDataElements() + { + return transferBytesPerPixel; + } + + @Override + public Object getDataElements(int x, int y, Object obj, DataBuffer data) + { + byte[] elements = obj != null ? (byte[])obj : new byte[numBands]; + int bitIndex = y * bitsPerLine + storageBitsPerPixel * x; + for (int i = 0; i < elements.length; ++i) { + elements[i] = (byte) getComponent(data, bitIndex); + bitIndex += bitsPerBand; + } + return elements; + } + + private int getComponent(DataBuffer data, int aBitIndex) + { + final int boffset = aBitIndex >> 3; // == aBitIndex / 8 + final int b = data.getElem(boffset); + final int bitIndexInB = aBitIndex & 7; + final int shift = ignoredBitsPerComponentPerByte - bitIndexInB; + return (b >>> shift) & componentMask; + } + + @Override + public void setDataElements(int x, int y, Object obj, DataBuffer data) + { + throw new UnsupportedOperationException("read only"); + } + + @Override + public int getSample(int x, int y, int b, DataBuffer data) + { + return getComponent(data, y * bitsPerLine + storageBitsPerPixel * x + bitsPerBand * b); + } + + @Override + public void setSample(int x, int y, int b, int s, DataBuffer data) + { + throw new UnsupportedOperationException("read only"); + + } + + @Override + public SampleModel createCompatibleSampleModel(int w, int h) + { + throw new UnsupportedOperationException("Not required"); + } + + @Override + public SampleModel createSubsetSampleModel(int[] bands) + { + throw new UnsupportedOperationException("Not required"); + } + + @Override + public DataBuffer createDataBuffer() + { + throw new UnsupportedOperationException("Not required"); + } + + @Override + public int[] getSampleSize() + { + return sampleSize; + } + + @Override + public int getSampleSize(int band) + { + return bitsPerBand; + } +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/RefImage.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/RefImage.java new file mode 100644 index 000000000..07e645190 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/RefImage.java @@ -0,0 +1,53 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.sun.pdfview; + +import java.awt.Graphics2D; +import java.awt.image.BufferedImage; + +/** + * A BufferedImage subclass that holds a strong reference to its graphics + * object. This means that the graphics will never go away as long as + * someone holds a reference to this image, and createGraphics() and + * getGraphics() can be called multiple times safely, and will always return + * the same graphics object. + */ +public class RefImage extends BufferedImage { + + /** a strong reference to the graphics object */ + private Graphics2D g; + + /** Creates a new instance of RefImage */ + public RefImage(int width, int height, int type) { + super(width, height, type); + } + + /** + * Create a graphics object only if it is currently null, otherwise + * return the existing graphics object. + */ + @Override + public Graphics2D createGraphics() { + if (this.g == null) { + this.g = super.createGraphics(); + } + + return this.g; + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/Watchable.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/Watchable.java new file mode 100644 index 000000000..f412e9ddd --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/Watchable.java @@ -0,0 +1,71 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.sun.pdfview; + +/** + * An interface for rendering or parsing, which can be stopped and started. + */ +public interface Watchable { + + /** the possible statuses */ + public static final int UNKNOWN = 0; + public static final int NOT_STARTED = 1; + public static final int PAUSED = 2; + public static final int NEEDS_DATA = 3; + public static final int RUNNING = 4; + public static final int STOPPED = 5; + public static final int COMPLETED = 6; + public static final int ERROR = 7; + + /** + * Get the status of this watchable + * + * @return one of the well-known statuses + */ + public int getStatus(); + + /** + * Stop this watchable. Stop will cause all processing to cease, + * and the watchable to be destroyed. + */ + public void stop(); + + /** + * Start this watchable and run until it is finished or stopped. + * Note the watchable may be stopped if go() with a + * different time is called during execution. + */ + public void go(); + + /** + * Start this watchable and run for the given number of steps or until + * finished or stopped. + * + * @param steps the number of steps to run for + */ + public void go(int steps); + + /** + * Start this watchable and run for the given amount of time, or until + * finished or stopped. + * + * @param millis the number of milliseconds to run for + */ + public void go(long millis); +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/action/GoToAction.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/action/GoToAction.java new file mode 100644 index 000000000..ebdcf0478 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/action/GoToAction.java @@ -0,0 +1,49 @@ +package com.sun.pdfview.action; + +import java.io.IOException; + +import com.sun.pdfview.PDFObject; +import com.sun.pdfview.PDFDestination; +import com.sun.pdfview.PDFParseException; + +/** + * An action which specifies going to a particular destination + */ +public class GoToAction extends PDFAction { + /** the destination to go to */ + private PDFDestination dest; + + /** + * Creates a new instance of GoToAction from an object + * + * @param obj the PDFObject with the action information + */ + public GoToAction(PDFObject obj, PDFObject root) throws IOException { + super("GoTo"); + + // find the destination + PDFObject destObj = obj.getDictRef("D"); + if (destObj == null) { + throw new PDFParseException("No destination in GoTo action " + obj); + } + + // parse it + this.dest = PDFDestination.getDestination(destObj, root); + } + + /** + * Create a new GoToAction from a destination + */ + public GoToAction(PDFDestination dest) { + super("GoTo"); + + this.dest = dest; + } + + /** + * Get the destination this action refers to + */ + public PDFDestination getDestination() { + return this.dest; + } +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/action/GoToEAction.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/action/GoToEAction.java new file mode 100644 index 000000000..2ed4ef886 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/action/GoToEAction.java @@ -0,0 +1,269 @@ +package com.sun.pdfview.action; + +import java.io.IOException; +import java.util.ArrayList; + +import com.sun.pdfview.PDFDestination; +import com.sun.pdfview.PDFObject; +import com.sun.pdfview.PDFParseException; + +/***************************************************************************** + * Action directing to a location within an embedded PDF document + * + * @author Katja Sondermann + * @since 07.07.2009 + ****************************************************************************/ +public class GoToEAction extends PDFAction { + + /** the destination within the remote PDF file */ + private PDFDestination destination; + /** the remote file this action refers to (optional)*/ + private String file = null; + /** Should the remote file be opened in a new window? (optional)*/ + private boolean newWindow = false; + /** The target dictionary*/ + private GoToETarget target; + + /** + * Creates a new instance of GoToEAction from an object + * @param obj the PDFObject with the action information + * @throws IOException - in case the action can not be parsed + */ + public GoToEAction(PDFObject obj, PDFObject root) throws IOException { + super("GoToE"); + // find the destination and parse it + this.destination = PdfObjectParseUtil.parseDestination("D", obj, root, true); + + // find the remote file and parse it + this.file = PdfObjectParseUtil.parseStringFromDict("F", obj, false); + + // find the new window attribute and parse it if available + this.newWindow = PdfObjectParseUtil.parseBooleanFromDict("NewWindow", obj, false); + + // parse the target dictionary + PDFObject targetObj = obj.getDictRef("T"); + ArrayList list = new ArrayList(); + this.target = parseTargetDistionary(targetObj, list); + } + + /************************************************************************* + * Parse a target dictionary if available + * @param targetObj + * @param list - a list of all already parsed targets, for not getting in an endless loop + * (if a target is found which is already contained, the recursive calling + * of this method will stop). + * @throws IOException - in case a value can not be parsed + ************************************************************************/ + private GoToETarget parseTargetDistionary(PDFObject targetObj, ArrayList list) throws IOException { + GoToETarget target = null; + if (targetObj != null) { + target = new GoToETarget(); + + // find the relation and parse it + target.setRelation(PdfObjectParseUtil.parseStringFromDict("R", targetObj, true)); + + // find the name of the embedded file and parse it + target.setNameInTree(PdfObjectParseUtil.parseStringFromDict("N", targetObj, false)); + + // find the page number and parse it + String page = PdfObjectParseUtil.parseStringFromDict("P", targetObj, false); + if(page == null){ + page = ""+PdfObjectParseUtil.parseIntegerFromDict("P", targetObj, false); + } + target.setPageNo(page); + + // find the annotation index and parse it + String annot = PdfObjectParseUtil.parseStringFromDict("A", targetObj, false); + if(annot == null){ + annot = ""+PdfObjectParseUtil.parseIntegerFromDict("A", targetObj, false); + } + target.setAnnotNo(annot); + + //find target dictionary and parse it + PDFObject subTargetObj = targetObj.getDictRef("T"); + if(subTargetObj != null){ + // call this method recursive, in case the target was not already contained in the + // list (this is checked for not getting into an infinite loop) + if(list.contains(target) == false){ + list.add(target); + GoToETarget subTargetDictionary = parseTargetDistionary(subTargetObj, list); + target.setTargetDictionary(subTargetDictionary); + } + } + } else { + if (this.file == null) { + throw new PDFParseException("No target dictionary in GoToE action " + targetObj); + } + } + return target; + } + + /************************************************************************* + * Create a new GoToEAction from the given attributes + * @param dest + * @param file + * @param newWindow + ************************************************************************/ + public GoToEAction(PDFDestination dest, String file, boolean newWindow) { + super("GoToR"); + this.file = file; + this.destination = dest; + this.newWindow = newWindow; + } + + /************************************************************************* + * Get the destination this action refers to + * @return PDFDestination + ************************************************************************/ + public PDFDestination getDestination() { + return this.destination; + } + + /************************************************************************* + * Get the file this action refers to + * @return PDFDestination + ************************************************************************/ + public String getFile() { + return this.file; + } + + /************************************************************************* + * Should the remote file be opened in a new window? + * @return boolean + ************************************************************************/ + public boolean isNewWindow() { + return this.newWindow; + } + + /************************************************************************* + * Get the target dictionary + * @return GoToETarget + ************************************************************************/ + public GoToETarget getTarget() { + return this.target; + } + + + /***************************************************************************** + * Inner class for holding the target dictionary's information + * + * @version $Id: GoToEAction.java,v 1.1 2009-07-10 12:47:31 xond Exp $ + * @author xond + * @since 07.07.2009 + ****************************************************************************/ + public static class GoToETarget { + private String relation; + private String nameInTree; + private String pageNo; + private String annotNo; + private GoToETarget targetDictionary; + + /************************************************************************* + * Relation between current document and the target. Can either be "P" or "C" + * @return String + ************************************************************************/ + public String getRelation() { + return this.relation; + } + + /************************************************************************* + * Relation between current document and the target. Can either be "P" or "C" + * @param relation + ************************************************************************/ + public void setRelation(String relation) { + this.relation = relation; + } + + /************************************************************************* + * The file name in the embedded files tree + * @return String + ************************************************************************/ + public String getNameInTree() { + return this.nameInTree; + } + + /************************************************************************* + * The file name in the embedded files tree + * @param nameInTree + ************************************************************************/ + public void setNameInTree(String nameInTree) { + this.nameInTree = nameInTree; + } + + /************************************************************************* + * Page Number: + * If the value can be parsed as Integer, it specifies the page number in + * the current document containing the file attachment annotation. If the + * value is a string, it defines a named destination in the current document + * that provides the page number of the file attachment annotation. + * + * @return String + ************************************************************************/ + public String getPageNo() { + return this.pageNo; + } + + /************************************************************************* + * Page Number: + * If the value can be parsed as Integer, it specifies the page number in + * the current document containing the file attachment annotation. If the + * value is a string, it defines a named destination in the current document + * that provides the page number of the file attachment annotation. + * + * @param pageNo + ************************************************************************/ + public void setPageNo(String pageNo) { + this.pageNo = pageNo; + } + + /************************************************************************* + * The index of the according annotation in the annotations array + * @return String + ************************************************************************/ + public String getAnnotNo() { + return this.annotNo; + } + + /************************************************************************* + * The index of the according annotation in the annotations array + * @param annotNo + ************************************************************************/ + public void setAnnotNo(String annotNo) { + this.annotNo = annotNo; + } + + /************************************************************************* + * A target dictionary specifying additional target information. If missing, + * the current document is the target file containing the destination. + * @return GoToETarget + ************************************************************************/ + public GoToETarget getTargetDictionary() { + return this.targetDictionary; + } + + /************************************************************************* + * A target dictionary specifying additional target information. If missing, + * the current document is the target file containing the destination. + * @param targetDictionary + ************************************************************************/ + public void setTargetDictionary(GoToETarget targetDictionary) { + this.targetDictionary = targetDictionary; + } + + @Override + public boolean equals(Object obj) { + if((obj instanceof GoToETarget) == false){ + return false; + } + if(super.equals(obj)){ + return true; + } + GoToETarget that = (GoToETarget)obj; + // compare the strng values, as the attributes may also be null + return String.valueOf(this.annotNo).equals(String.valueOf(that.annotNo)) + && String.valueOf(this.nameInTree).equals(String.valueOf(that.nameInTree)) + && String.valueOf(this.pageNo).equals(String.valueOf(that.pageNo)) + && String.valueOf(this.relation).equals(String.valueOf(that.relation)); + } + } +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/action/GoToRAction.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/action/GoToRAction.java new file mode 100644 index 000000000..e04d21624 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/action/GoToRAction.java @@ -0,0 +1,75 @@ +package com.sun.pdfview.action; + +import java.io.IOException; + +import com.sun.pdfview.PDFDestination; +import com.sun.pdfview.PDFObject; + +/***************************************************************************** + * Action directing to a location within another PDF document + * + * @author Katja Sondermann + * @since 07.07.2009 + ****************************************************************************/ +public class GoToRAction extends PDFAction { + + /** the destination within the remote PDF file */ + private PDFDestination destination; + /** the remote file this action refers to*/ + private String file; + /** Should the remote file be opened in a new window? (optional)*/ + private boolean newWindow=false; + /** + * Creates a new instance of GoToRAction from an object + * @param obj the PDFObject with the action information + * @throws IOException - in case the action can not be parsed + */ + public GoToRAction(PDFObject obj, PDFObject root) throws IOException { + super("GoToR"); + // find the destination and parse it + this.destination = PdfObjectParseUtil.parseDestination("D", obj, root, true); + + // find the remote file and parse it + this.file = PdfObjectParseUtil.parseStringFromDict("F", obj, true); + + // find the new window attribute and parse it if available + this.newWindow = PdfObjectParseUtil.parseBooleanFromDict("NewWindow", obj, false); + } + + /************************************************************************* + * Create a new GoToRAction from the given attributes + * @param dest + * @param file + * @param newWindow + ************************************************************************/ + public GoToRAction(PDFDestination dest, String file, boolean newWindow){ + super("GoToR"); + this.file = file; + this.destination = dest; + this.newWindow = newWindow; + } + + /************************************************************************* + * Get the destination this action refers to + * @return PDFDestination + ************************************************************************/ + public PDFDestination getDestination() { + return this.destination; + } + + /************************************************************************* + * Get the file this action refers to + * @return PDFDestination + ************************************************************************/ + public String getFile() { + return this.file; + } + + /************************************************************************* + * Should the remote file be opened in a new window? + * @return boolean + ************************************************************************/ + public boolean isNewWindow() { + return this.newWindow; + } +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/action/LaunchAction.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/action/LaunchAction.java new file mode 100644 index 000000000..9b5a8640a --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/action/LaunchAction.java @@ -0,0 +1,492 @@ +package com.sun.pdfview.action; + +import java.io.IOException; + +import com.sun.pdfview.PDFObject; +import com.sun.pdfview.PDFParseException; + +/***************************************************************************** + * Action for launching an application, mostly used to open a file. + * + * @author Katja Sondermann + * @since 08.07.2009 + ****************************************************************************/ +public class LaunchAction extends PDFAction { + // file separator according to PDF spec + public final static String SOLIDUS = "/"; + + /** the file/application to be opened (optional)*/ + private FileSpec file; + /** should a new window be opened (optional)*/ + private boolean newWindow = false; + private PDFObject unixParam; + private PDFObject macParam; + private WinLaunchParam winParam; + + /** + * Creates a new instance of LaunchAction from an object + * + * @param obj - the PDFObject with the action information + * @param root - the root object + */ + public LaunchAction(PDFObject obj, PDFObject root) throws IOException { + super("Launch"); + // find the file/application and parse it + PDFObject fileObj = obj.getDictRef("F"); + this.file = parseFileSpecification(fileObj); + + // find the new window flag and parse it + PDFObject newWinObj = obj.getDictRef("NewWindow"); + if (newWinObj != null) { + this.newWindow = newWinObj.getBooleanValue(); + } + // parse the OS specific launch parameters: + this.winParam = parseWinDict(obj.getDictRef("Win")); + // unix and mac dictionaries are not further specified, so can not be parsed yet. + this.unixParam = obj.getDictRef("Unix"); + this.macParam = obj.getDictRef("Mac"); + + // check if at least the file or one of the OS specific launch parameters is set: + if ((this.file == null) + && (this.winParam == null) + && (this.unixParam == null) + && (this.macParam == null)) { + throw new PDFParseException("Could not parse launch action (file or OS " + + "specific launch parameters are missing): " + obj.toString()); + } + } + + /************************************************************************* + * Is the file name absolute (if not, it is relative to the path of the + * currently opened PDF file). + * If the file name starts with a "/", it is considered to be absolute. + * + * @return boolean + ************************************************************************/ + public static boolean isAbsolute(String fileName) { + return fileName.startsWith(SOLIDUS); + } + + /************************************************************************* + * Parse the file specification object + * @param fileObj + * @return FileSpec - might be null in case the passed object is null + * @throws IOException + * @throws PDFParseException + ************************************************************************/ + private FileSpec parseFileSpecification(PDFObject fileObj) throws PDFParseException, IOException { + FileSpec file = null; + if (fileObj != null) { + file = new FileSpec(); + if(fileObj.getType() == PDFObject.DICTIONARY){ + file.setFileSystem(PdfObjectParseUtil.parseStringFromDict("FS", fileObj, false)); + file.setFileName(PdfObjectParseUtil.parseStringFromDict("F", fileObj, false)); + file.setUnicode(PdfObjectParseUtil.parseStringFromDict("UF", fileObj, false)); + file.setDosFileName(PdfObjectParseUtil.parseStringFromDict("DOS", fileObj, false)); + file.setMacFileName(PdfObjectParseUtil.parseStringFromDict("Mac", fileObj, false)); + file.setUnixFileName(PdfObjectParseUtil.parseStringFromDict("Unix", fileObj, false)); + file.setVolatileFile(PdfObjectParseUtil.parseBooleanFromDict("V", fileObj, false)); + file.setDescription(PdfObjectParseUtil.parseStringFromDict("Desc", fileObj, false)); + file.setId(fileObj.getDictRef("ID")); + file.setEmbeddedFile(fileObj.getDictRef("EF")); + file.setRelatedFile(fileObj.getDictRef("RF")); + file.setCollectionItem(fileObj.getDictRef("CI")); + }else if(fileObj.getType() == PDFObject.STRING){ + file.setFileName(fileObj.getStringValue()); + }else{ + throw new PDFParseException("File specification could not be parsed " + + "(should be of type 'Dictionary' or 'String'): " + fileObj.toString()); + } + } + return file; + } + + + /************************************************************************* + * Parse the windows specific launch parameters + * @param winDict + * @throws IOException - in case of a problem during parsing content + ************************************************************************/ + private WinLaunchParam parseWinDict(PDFObject winDict) throws IOException { + if (winDict == null) { + return null; + } + WinLaunchParam param = new WinLaunchParam(); + + // find and parse the file/application name + param.setFileName(PdfObjectParseUtil.parseStringFromDict("F", winDict, true)); + + // find and parse the directory + param.setDirectory(PdfObjectParseUtil.parseStringFromDict("D", winDict, false)); + + // find and parse the operation to be performed + param.setOperation(PdfObjectParseUtil.parseStringFromDict("O", winDict, false)); + + // find and parse the parameter to be passed to the application + param.setParameter(PdfObjectParseUtil.parseStringFromDict("P", winDict, false)); + + return param; + } + + /************************************************************************* + * The file / application to be opened + * @return FileSpec + ************************************************************************/ + public FileSpec getFileSpecification() { + return this.file; + } + + /************************************************************************* + * Should a new window be opened for the file/application? + * @return boolean + ************************************************************************/ + public boolean isNewWindow() { + return this.newWindow; + } + + /************************************************************************* + * Get the unix specific launch parameters. + * Note: The dictionary is not specified yet in the PDF spec., so the PdfObject + * which is returned here is not parsed. + * @return PDFObject + ************************************************************************/ + public PDFObject getUnixParam() { + return this.unixParam; + } + + /************************************************************************* + * Get the mac specific launch parameters. + * Note: The dictionary is not specified yet in the PDF spec., so the PdfObject + * which is returned here is not parsed. + * @return PDFObject + ************************************************************************/ + public PDFObject getMacParam() { + return this.macParam; + } + + /************************************************************************* + * Get the windows specific launch parameters. + * @return WinLaunchParam + ************************************************************************/ + public WinLaunchParam getWinParam() { + return this.winParam; + } + + /***************************************************************************** + * Internal class for the windows specific launch parameters + * + * @version $Id: LaunchAction.java,v 1.1 2009-07-10 12:47:31 xond Exp $ + * @author xond + * @since 08.07.2009 + ****************************************************************************/ + public class WinLaunchParam { + private String fileName; + private String directory; + private String operation = "open"; + private String parameter; + + /************************************************************************* + * The file/application name to be opened + * @return String + ************************************************************************/ + public String getFileName() { + return this.fileName; + } + + /************************************************************************* + * The file/application name to be opened + * @param fileName + ************************************************************************/ + public void setFileName(String fileName) { + this.fileName = fileName; + } + + /************************************************************************* + * The directory in standard DOS syntax + * @return String + ************************************************************************/ + public String getDirectory() { + return this.directory; + } + + /************************************************************************* + * The directory in standard DOS syntax + * @param directory + ************************************************************************/ + public void setDirectory(String directory) { + this.directory = directory; + } + + /************************************************************************* + * The operation to be performed (open or print). Ignored + * in case the "F" parameter describes a file to be opened. + * Default is "open". + * @return String + ************************************************************************/ + public String getOperation() { + return this.operation; + } + + /************************************************************************* + * The operation to be performed ("open" or "print").Ignored + * in case the "F" parameter describes a file to be opened. + * Default is "open". + * @param operation + ************************************************************************/ + public void setOperation(String operation) { + this.operation = operation; + } + + /************************************************************************* + * A parameter which shall be passed to the application. Ignored + * in case the "F" parameter describes a file to be opened. + * @return String + ************************************************************************/ + public String getParameter() { + return this.parameter; + } + + /************************************************************************* + * A parameter which shall be passed to the application. Ignored + * in case the "F" parameter describes a file to be opened. + * @param parameter + ************************************************************************/ + public void setParameter(String parameter) { + this.parameter = parameter; + } + } + + /***************************************************************************** + * Inner class for storing a file specification + * + * @version $Id: LaunchAction.java,v 1.1 2009-07-10 12:47:31 xond Exp $ + * @author xond + * @since 08.07.2009 + ****************************************************************************/ + public static class FileSpec{ + private String fileSystem; + private String fileName; + private String dosFileName; + private String unixFileName; + private String macFileName; + private String unicode; + private PDFObject id; + private boolean volatileFile; + private PDFObject embeddedFile; + private PDFObject relatedFile; + private String description; + private PDFObject collectionItem; + + /************************************************************************* + * The name of the file system that should be used to interpret this entry. + * @return String + ************************************************************************/ + public String getFileSystem() { + return this.fileSystem; + } + + /************************************************************************* + * The name of the file system that should be used to interpret this entry. + * @param fileSystem + ************************************************************************/ + public void setFileSystem(String fileSystem) { + this.fileSystem = fileSystem; + } + + /************************************************************************* + * Get the filename: + * first try to get the file name for the used OS, if it's not available + * return the common file name. + * @return String + ************************************************************************/ + public String getFileName() { + String system = System.getProperty("os.name"); + if(system.startsWith("Windows")){ + if(this.dosFileName != null){ + return this.dosFileName; + } + }else if(system.startsWith("mac os x")){ + if(this.macFileName != null){ + return this.macFileName; + } + }else { + if(this.unixFileName != null){ + return this.unixFileName; + } + } + return this.fileName; + } + + /************************************************************************* + * The file name. + * @param fileName + ************************************************************************/ + public void setFileName(String fileName) { + this.fileName = fileName; + } + + /************************************************************************* + * A file specification string representing a DOS file name. + * @return String + ************************************************************************/ + public String getDosFileName() { + return this.dosFileName; + } + + /************************************************************************* + * A file specification string representing a DOS file name. + * @param dosFileName + ************************************************************************/ + public void setDosFileName(String dosFileName) { + this.dosFileName = dosFileName; + } + + /************************************************************************* + * A file specification string representing a unix file name. + * @return String + ************************************************************************/ + public String getUnixFileName() { + return this.unixFileName; + } + + /************************************************************************* + * A file specification string representing a unix file name. + * @param unixFileName + ************************************************************************/ + public void setUnixFileName(String unixFileName) { + this.unixFileName = unixFileName; + } + + /************************************************************************* + * A file specification string representing a mac file name. + * @return String + ************************************************************************/ + public String getMacFileName() { + return this.macFileName; + } + + /************************************************************************* + * A file specification string representing a mac file name. + * @param macFileName + ************************************************************************/ + public void setMacFileName(String macFileName) { + this.macFileName = macFileName; + } + + /************************************************************************* + * Unicode file name + * @return String + ************************************************************************/ + public String getUnicode() { + return this.unicode; + } + + /************************************************************************* + * Unicode file name + * @param unicode + ************************************************************************/ + public void setUnicode(String unicode) { + this.unicode = unicode; + } + + /************************************************************************* + * ID - array of two byte strings constituting a file identifier, which + * should be included in the referenced file. + * + * @return PDFObject + ************************************************************************/ + public PDFObject getId() { + return this.id; + } + + /************************************************************************* + * ID - array of two byte strings constituting a file identifier, which + * should be included in the referenced file. + * + * @param id + ************************************************************************/ + public void setId(PDFObject id) { + this.id = id; + } + + /************************************************************************* + * Is the file volatile? + * @return boolean + ************************************************************************/ + public boolean isVolatileFile() { + return this.volatileFile; + } + + /************************************************************************* + * Is the file volatile? + * @param volatileFile + ************************************************************************/ + public void setVolatileFile(boolean volatileFile) { + this.volatileFile = volatileFile; + } + + /************************************************************************* + * Dictionary of embedded file streams + * @return PDFObject + ************************************************************************/ + public PDFObject getEmbeddedFile() { + return this.embeddedFile; + } + + /************************************************************************* + * Dictionary of embedded file streams + * @param embeddedFile + ************************************************************************/ + public void setEmbeddedFile(PDFObject embeddedFile) { + this.embeddedFile = embeddedFile; + } + + /************************************************************************* + * Dictionary of related files. + * @return PDFObject + ************************************************************************/ + public PDFObject getRelatedFile() { + return this.relatedFile; + } + + /************************************************************************* + * Dictionary of related files. + * @param relatedFile + ************************************************************************/ + public void setRelatedFile(PDFObject relatedFile) { + this.relatedFile = relatedFile; + } + + /************************************************************************* + * File specification description + * @return String + ************************************************************************/ + public String getDescription() { + return this.description; + } + + /************************************************************************* + * File specification description + * @param description + ************************************************************************/ + public void setDescription(String description) { + this.description = description; + } + + /************************************************************************* + * Collection item dictionary + * @return PDFObject + ************************************************************************/ + public PDFObject getCollectionItem() { + return this.collectionItem; + } + + /************************************************************************* + * Collection item dictionary + * @param collectionItem + ************************************************************************/ + public void setCollectionItem(PDFObject collectionItem) { + this.collectionItem = collectionItem; + } + } +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/action/PDFAction.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/action/PDFAction.java new file mode 100644 index 000000000..43e8c168e --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/action/PDFAction.java @@ -0,0 +1,107 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package com.sun.pdfview.action; + +import java.io.IOException; + +import com.sun.pdfview.PDFObject; +import com.sun.pdfview.PDFParseException; + +/** + * The common super-class of all PDF actions. + */ +public class PDFAction { + /** the type of this action */ + private String type; + + /** the next action or array of actions */ + private PDFObject next; + + /** Creates a new instance of PDFAction */ + public PDFAction(String type) { + this.type = type; + } + + /** + * Get an action of the appropriate type from a PDFObject + * + * @param obj the PDF object containing the action to parse + * @param root the root of the PDF object tree + */ + public static PDFAction getAction(PDFObject obj, PDFObject root) + throws IOException + { + // figure out the action type + PDFObject typeObj = obj.getDictRef("S"); + if (typeObj == null) { + throw new PDFParseException("No action type in object: " + obj); + } + + // create the action based on the type + PDFAction action = null; + String type = typeObj.getStringValue(); + if (type.equals("GoTo")) { + action = new GoToAction(obj, root); + }else if(type.equals("GoToE")){ + action = new GoToEAction(obj, root); + }else if(type.equals("GoToR")){ + action = new GoToRAction(obj, root); + }else if(type.equals("URI")){ + action = new UriAction(obj, root); + }else if(type.equals("Launch")){ + action = new LaunchAction(obj, root); + } + else { + /** [JK FIXME: Implement other action types! ] */ + throw new PDFParseException("Unknown Action type: " + type); + } + + // figure out if there is a next action + PDFObject nextObj = obj.getDictRef("Next"); + if (nextObj != null) { + action.setNext(nextObj); + } + + // return the action + return action; + } + + /** + * Get the type of this action + */ + public String getType() { + return this.type; + } + + /** + * Get the next action or array of actions + */ + public PDFObject getNext() { + return this.next; + } + + /** + * Set the next action or array of actions + */ + public void setNext(PDFObject next) { + this.next = next; + } + +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/action/PdfObjectParseUtil.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/action/PdfObjectParseUtil.java new file mode 100644 index 000000000..4d73fc659 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/action/PdfObjectParseUtil.java @@ -0,0 +1,100 @@ +package com.sun.pdfview.action; + +import java.io.IOException; + +import com.sun.pdfview.PDFDestination; +import com.sun.pdfview.PDFObject; +import com.sun.pdfview.PDFParseException; + +/***************************************************************************** + * Utility class for parsing values from a PDFObject + * + * @author Katja Sondermann + * @since 08.07.2009 + ****************************************************************************/ +public class PdfObjectParseUtil { + + /************************************************************************* + * Parse a String value with the given key from parent object. If it's mandatory + * and not available, an exception will be thrown. + * @param key + * @param parent + * @param mandatory + * @return String - can be null if not mandatory + * @throws IOException - in case of a parsing error + ************************************************************************/ + public static String parseStringFromDict(String key, PDFObject parent, boolean mandatory) throws IOException{ + PDFObject val = parent; + while (val.getType() == PDFObject.DICTIONARY) { + val = val.getDictRef(key); + if(val == null){ + if(mandatory){ + throw new PDFParseException(key + "value could not be parsed : " + parent.toString()); + } + return null; + } + } + return val.getStringValue(); + } + + /************************************************************************* + * Parse a Boolean value with the given key from parent object. If it's mandatory + * and not available, an exception will be thrown. + * @param key + * @param parent + * @param mandatory + * @return boolean - false if not available and not mandatory + * @throws IOException + ************************************************************************/ + public static boolean parseBooleanFromDict(String key, PDFObject parent, boolean mandatory) throws IOException{ + PDFObject val = parent.getDictRef(key); + if(val == null){ + if(mandatory){ + throw new PDFParseException(key + "value could not be parsed : " + parent.toString()); + } + return false; + } + return val.getBooleanValue(); + } + + /************************************************************************* + * Parse a integer value with the given key from parent object. If it's mandatory + * and not available, an exception will be thrown. + * @param key + * @param parent + * @param mandatory + * @return int - returns "0" in case the value is not a number + * @throws IOException + ************************************************************************/ + public static int parseIntegerFromDict(String key, PDFObject parent, boolean mandatory) throws IOException{ + PDFObject val = parent.getDictRef(key); + if(val == null){ + if(mandatory){ + throw new PDFParseException(key + "value could not be parsed : " + parent.toString()); + } + return 0; + } + return val.getIntValue(); + } + + /************************************************************************* + * Parse a destination object + * @param key + * @param parent + * @param root + * @param mandatory + * @return PDFDestination - can be null if not mandatory + * @throws IOException + ************************************************************************/ + public static PDFDestination parseDestination(String key, PDFObject parent, PDFObject root, boolean mandatory) throws IOException{ + PDFObject destObj = parent.getDictRef(key); + if (destObj == null) { + if(mandatory){ + throw new PDFParseException("Error parsing destination " + parent); + } + return null; + } + return PDFDestination.getDestination(destObj, root); + + } +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/action/UriAction.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/action/UriAction.java new file mode 100644 index 000000000..7eb5da9b6 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/action/UriAction.java @@ -0,0 +1,45 @@ +package com.sun.pdfview.action; + +import java.io.IOException; + +import com.sun.pdfview.PDFObject; + +/***************************************************************************** + * URI action, containing a web link + * + * @author Katja Sondermann + * @since 07.07.2009 + ****************************************************************************/ +public class UriAction extends PDFAction { + + /** The URL this action links to */ + private String uri; + + /************************************************************************* + * Constructor, reading the URL from the given action object + * @param type + * @throws IOException - in case the action can not be parsed + ************************************************************************/ + public UriAction(PDFObject obj, PDFObject root) throws IOException { + super("URI"); + this.uri = PdfObjectParseUtil.parseStringFromDict("URI", obj, true); + } + + /************************************************************************* + * Constructor + * @param type + * @throws IOException + ************************************************************************/ + public UriAction(String uri) throws IOException { + super("URI"); + this.uri = uri; + } + + /************************************************************************* + * Get the URI this action directs to + * @return String + ************************************************************************/ + public String getUri() { + return this.uri; + } +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/AnnotationBorderStyle.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/AnnotationBorderStyle.java new file mode 100644 index 000000000..c69c97b51 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/AnnotationBorderStyle.java @@ -0,0 +1,88 @@ +package com.sun.pdfview.annotation; + +import java.io.IOException; + +import com.sun.pdfview.PDFObject; + +/** + * Annotation border style + * @author Bernd Rosstauscher + */ +public class AnnotationBorderStyle { + + public enum BorderStyle { + SOLID("S"), + DASHED("D"), + BEVELED("B"), + INSET("I"), + UNDERLINE("U"); + + private String code; + + private BorderStyle(String code) { + this.code = code; + } + + public String getCode() { + return code; + } + + public static BorderStyle fromCode(String code) { + for (BorderStyle bs : BorderStyle.values()) { + if (bs.getCode().equals(code)) { + return bs; + } + } + return SOLID; + } + + } + + private Integer width; + private BorderStyle borderStyle; + private int[] dashArray; + + /** + * Creates a annotation border style + */ + public AnnotationBorderStyle() { + super(); + } + + /** + * Parse a border style from a BS dictionary. + * @param bs the pdf dictionary to parse. + * @return the border style object. + * @throws IOException + */ + public static AnnotationBorderStyle parseFromDictionary(PDFObject bs) throws IOException { + AnnotationBorderStyle result = new AnnotationBorderStyle(); + result.width = bs.getDictRefAsInt("W"); + result.borderStyle = BorderStyle.fromCode(bs.getDictRefAsString("S")); + result.dashArray = bs.getDictRefAsIntArray("D"); + // TODO BE Border effect not supported yet + return result; + } + + /** + * @return the border style enum + */ + public BorderStyle getBorderStyle() { + return borderStyle; + } + + /** + * @return the width of the border line + */ + public Integer getWidth() { + return width; + } + + /** + * @return specifying the dash for the border line + */ + public int[] getDashArray() { + return dashArray; + } + +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/AnnotationType.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/AnnotationType.java new file mode 100644 index 000000000..1632ce8f1 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/AnnotationType.java @@ -0,0 +1,106 @@ +package com.sun.pdfview.annotation; + +import com.sun.pdfview.Configuration; + +/** + * @author Bernd Rosstauscher + * + */ +public enum AnnotationType{ + UNKNOWN("-", 0, PDFAnnotation.class), + LINK("Link", 1, LinkAnnotation.class), + WIDGET("Widget", 2, WidgetAnnotation.class), + STAMP("Stamp", 3, StampAnnotation.class), + FREETEXT("FreeText", 5, FreetextAnnotation.class), + SIGNATURE("Sig", 6, WidgetAnnotation.class), + + // added more annotation types. Most of them only with basic features + // We render them all via the base class MarkupAnnotation + + TEXT("Text", 7, MarkupAnnotation.class), + LINE("Line", 8, MarkupAnnotation.class), + SQUARE("Square", 9, SquareAnnotation.class), + CIRCLE("Circle", 10, CircleAnnotation.class), + POLYGON("Polygon", 11, MarkupAnnotation.class), + POLYLINE("PolyLine", 12, MarkupAnnotation.class), + HIGHLIGHT("Highlight", 13, TextMarkupAnnotation.class), + UNDERLINE("Underline", 14, TextMarkupAnnotation.class), + SQUIGGLY("Squiggly", 15, TextMarkupAnnotation.class), + STRIKEOUT("StrikeOut", 16, TextMarkupAnnotation.class), + CARET("Caret", 17, MarkupAnnotation.class), + INK("Ink", 18, MarkupAnnotation.class), + //POPUP("Popup", 19, MarkupAnnotation.class), + FILEATTACHMENT("FileAttachment", 20, PDFAnnotation.class), + SOUND("Sound", 21, PDFAnnotation.class), + MOVIE("Movie", 22, PDFAnnotation.class), + SCREEN("Screen", 23, PDFAnnotation.class), + PRINTERMARK("PrinterMark", 24, PDFAnnotation.class), + TRAPNET("TrapNet", 25, PDFAnnotation.class), + WATERMARK("Watermark", 26, PDFAnnotation.class), + THREED("3D", 27, PDFAnnotation.class), + REDACT("Redact", 28, MarkupAnnotation.class), + ; + + /** + * @return true if this annotation type should be displayed else false. + */ + boolean displayAnnotation() { + switch(this) { + case STAMP: return Configuration.getInstance().isPrintStampAnnotations(); + case WIDGET: return Configuration.getInstance().isPrintWidgetAnnotations(); + case FREETEXT: return Configuration.getInstance().isPrintFreetextAnnotations(); + case LINK: return Configuration.getInstance().isPrintLinkAnnotations(); + case SIGNATURE: return Configuration.getInstance().isPrintSignatureFields(); + case UNKNOWN: return false; + default: { + // Fallback for all the annotation types that are currently mapped to MarkupAnnotation + return MarkupAnnotation.class.isAssignableFrom(this.className) + && Configuration.getInstance().isPrintFreetextAnnotations(); + } + } + } + + private String definition; + private int internalId; + private Class className; + + private AnnotationType(String definition, int typeId, Class className) { + this.definition = definition; + this.internalId = typeId; + this.className = className; + } + + /** + * @return the definition + */ + public String getDefinition() { + return definition; + } + /** + * @return the internalId + */ + public int getInternalId() { + return internalId; + } + + /** + * @return the className + */ + public Class getClassName() { + return className; + } + + /** + * Get annotation type by it's type + * @param definition + * @return + */ + public static AnnotationType getByDefinition(String definition) { + for (AnnotationType type : values()) { + if(type.definition.equals(definition)) { + return type; + } + } + return UNKNOWN; + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/CircleAnnotation.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/CircleAnnotation.java new file mode 100644 index 000000000..2b55f2e85 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/CircleAnnotation.java @@ -0,0 +1,26 @@ +package com.sun.pdfview.annotation; + +import java.io.IOException; + +import com.sun.pdfview.PDFObject; + +/***************************************************************************** + * PDF annotation for a circle + * + * @author Bernd Rosstauscher + ****************************************************************************/ +public class CircleAnnotation extends MarkupAnnotation { + + // TODO Not all of this is fully implemented yet. + // But it will work if the visual representation is done via an "Appearance Stream" + + /************************************************************************* + * Constructor + * @param annotObject + * @throws IOException + ************************************************************************/ + public CircleAnnotation(PDFObject annotObject) throws IOException { + super(annotObject, AnnotationType.CIRCLE); + + } +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/FreetextAnnotation.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/FreetextAnnotation.java new file mode 100644 index 000000000..193271491 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/FreetextAnnotation.java @@ -0,0 +1,24 @@ +package com.sun.pdfview.annotation; + +import java.io.IOException; + +import com.sun.pdfview.PDFObject; + +/***************************************************************************** + * PDF annotation describing a free text + * Currently only supports the XObjects which can be found in the path AP->N + * of the annotation object (same implementation as the stamp annotation) + * @author Katja Sondermann + * @since 28.03.2012 + ****************************************************************************/ +public class FreetextAnnotation extends MarkupAnnotation { + + /************************************************************************* + * Constructor + * @param annotObject + * @throws IOException + ************************************************************************/ + public FreetextAnnotation(PDFObject annotObject) throws IOException { + super(annotObject, AnnotationType.FREETEXT); + } +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/LinkAnnotation.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/LinkAnnotation.java new file mode 100644 index 000000000..939d2ec0d --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/LinkAnnotation.java @@ -0,0 +1,67 @@ +package com.sun.pdfview.annotation; + +import java.io.IOException; + +import com.sun.pdfview.PDFDestination; +import com.sun.pdfview.PDFObject; +import com.sun.pdfview.PDFParseException; +import com.sun.pdfview.action.GoToAction; +import com.sun.pdfview.action.PDFAction; + +/***************************************************************************** + * PDF annotation describing a link to either a location within the current + * document, a location in another PDF file, an application/file to be opened + * or a web site. + * In the PDF structure a link can be a destination ("DEST") or an action ("A"). + * Both ways are handled as actions internally, i.e. for getting the links + * destination, you should get the action from this annotation object. It can be + * one of the following actions: + *

  • GotoAction - for a file internal destination
  • + *
  • GoToRAction - for a destination in a remote PDF file
  • + *
  • GoToEAction - for a destination in an embedded PDF file
  • + *
  • UriAction - for a web link
  • + *
  • LaunchAction - for launching an application/opening a file
  • + * + * @author Katja Sondermann + * @since 06.07.2009 + ****************************************************************************/ +public class LinkAnnotation extends PDFAnnotation { + + private PDFAction action = null; + + /************************************************************************* + * Constructor + * @param annotObject + * @throws IOException + ************************************************************************/ + public LinkAnnotation(PDFObject annotObject) throws IOException { + super(annotObject, AnnotationType.LINK); + // a link annotation can either have an action (GoTo or URI) or a destination (DEST) + PDFObject actionObj = annotObject.getDictRef("A"); + if (actionObj != null) { + this.action = PDFAction.getAction(actionObj, annotObject.getRoot()); + } else { + // if a destination is given, create a GoToAction from it + PDFObject dest = annotObject.getDictRef("Dest"); + if(dest == null) { + dest = annotObject.getDictRef("DEST"); + } + if (dest != null) { + this.action = new GoToAction(PDFDestination.getDestination(dest, annotObject.getRoot())); + } else { + throw new PDFParseException( + "Could not parse link annotation (no Action or Destination found): " + + annotObject.toString()); + } + } + } + + /************************************************************************* + * Get the contained PDFAction + * @return PDFAction - can be null in case the contains + * a destination object + ************************************************************************/ + public PDFAction getAction() { + return this.action; + } +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/MarkupAnnotation.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/MarkupAnnotation.java new file mode 100644 index 000000000..fb1d055e1 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/MarkupAnnotation.java @@ -0,0 +1,257 @@ +package com.sun.pdfview.annotation; + +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; +import java.awt.geom.Rectangle2D.Float; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import com.sun.pdfview.PDFCmd; +import com.sun.pdfview.PDFImage; +import com.sun.pdfview.PDFObject; +import com.sun.pdfview.PDFPage; +import com.sun.pdfview.PDFParseException; +import com.sun.pdfview.PDFParser; + +/***************************************************************************** + * PDF annotation describing a all kind of "markup" annotations which are visible + * in the PDF. + * + * @author Bernd Rosstauscher + ****************************************************************************/ +public class MarkupAnnotation extends PDFAnnotation { + + private PDFObject onAppearance; + private PDFObject offAppearance; + private List onCmd; + private List offCmd; + private boolean appearanceStateOn; + private AnnotationBorderStyle borderStyle; + private String textLabel; + private PDFAnnotation popupAnnotation; + + + /************************************************************************* + * Constructor + * @param annotObject + * @throws IOException + ************************************************************************/ + + public MarkupAnnotation(PDFObject annotObject, AnnotationType type) throws IOException { + super(annotObject, type); + + this.textLabel = annotObject.getDictRefAsString("T"); + // TODO more is missing here like CA, RC, ... + + parsePopupAnnotation(annotObject.getDictRef("Popup")); + parseAP(annotObject.getDictRef("AP")); + parseBorderStyleDictionary(annotObject.getDictRef("BS")); + } + + /** + * Parses the appearance stream into PDF commands + * @param dictRef + * @throws IOException + */ + protected void parseAP(PDFObject dictRef) throws IOException { + if(dictRef == null) { + return; + } + PDFObject normalAP = dictRef.getDictRef("N"); + if(normalAP == null) { + return; + } + if(normalAP.getType() == PDFObject.DICTIONARY) { + this.onAppearance = normalAP.getDictRef("On"); + this.offAppearance = normalAP.getDictRef("Off"); + PDFObject as = dictRef.getDictRef("AS"); + this.appearanceStateOn = (as != null) && ("On".equals(as.getStringValue())); + }else { + this.onAppearance = normalAP; + this.offAppearance = null; + appearanceStateOn = true; + } + parseOnOffCommands(); + } + + /** + * Parses the mouse On or Off appearance stream + * depending on which one is currently active. + * @throws IOException + */ + private void parseOnOffCommands() throws IOException { + if(onAppearance != null) { + onCmd = parseIntoPdfCommands(onAppearance); + } + if(offAppearance != null) { + offCmd = parseIntoPdfCommands(offAppearance); + } + } + + /** + * Parses the border style dictionary + * @param bs + * @throws IOException + */ + protected void parseBorderStyleDictionary(PDFObject bs) throws IOException { + if (bs != null) { + this.borderStyle = AnnotationBorderStyle.parseFromDictionary(bs); + } + } + + /** + * @return the border style or null if not specified. + */ + public AnnotationBorderStyle getBorderStyle() { + return borderStyle; + } + + /** + * Parses the popup annotation + * @param popupObj + * @throws IOException + */ + private void parsePopupAnnotation(PDFObject popupObj) throws IOException { + this.popupAnnotation = (popupObj != null)?createAnnotation(popupObj):null; + } + + + private List parseIntoPdfCommands(PDFObject obj) throws IOException { + // TODO see also WidgetAnnotation.parseCommand which seems to be copied code + // We should merge these two + String type = obj.getDictRef("Subtype").getStringValue(); + if (type == null) { + type = obj.getDictRef ("S").getStringValue (); + } + ArrayList result = new ArrayList(); + result.add(PDFPage.createPushCmd()); + result.add(PDFPage.createPushCmd()); + if (type.equals("Image")) { + // stamp annotation transformation + AffineTransform rectAt = getPositionTransformation(); + result.add(PDFPage.createXFormCmd(rectAt)); + + PDFImage img = PDFImage.createImage(obj, new HashMap() , false); + result.add(PDFPage.createImageCmd(img)); + } else if (type.equals("Form")) { + + // rats. parse it. + PDFObject bobj = obj.getDictRef("BBox"); + float xMin = bobj.getAt(0).getFloatValue(); + float yMin = bobj.getAt(1).getFloatValue(); + float xMax = bobj.getAt(2).getFloatValue(); + float yMax = bobj.getAt(3).getFloatValue(); + Float bbox = new Rectangle2D.Float(xMin, + yMin, + xMax - xMin, + yMax - yMin); + PDFPage formCmds = new PDFPage(bbox, 0); + + // stamp annotation transformation + AffineTransform rectAt = getPositionTransformation(); + formCmds.addXform(rectAt); + + AffineTransform rectScaled = getScalingTransformation(bbox); + formCmds.addXform(rectScaled); + + // form transformation + AffineTransform at; + PDFObject matrix = obj.getDictRef("Matrix"); + if (matrix == null) { + at = new AffineTransform(); + } else { + float elts[] = new float[6]; + for (int i = 0; i < elts.length; i++) { + elts[i] = (matrix.getAt(i)).getFloatValue(); + } + at = new AffineTransform(elts); + } + formCmds.addXform(at); + + HashMap r = new HashMap(new HashMap()); + PDFObject rsrc = obj.getDictRef("Resources"); + if (rsrc != null) { + r.putAll(rsrc.getDictionary()); + } + + PDFParser form = new PDFParser(formCmds, obj.getStream(), r); + form.go(true); + + result.addAll(formCmds.getCommands()); + } else { + throw new PDFParseException("Unknown XObject subtype: " + type); + } + result.add(PDFPage.createPopCmd()); + result.add(PDFPage.createPopCmd()); + return result; + } + + /** + * Transform to the position of the stamp annotation + * @return + */ + private AffineTransform getPositionTransformation() { + Float rect2 = getRect(); + double[] f = new double[] {1, + 0, + 0, + 1, + rect2.getMinX(), + rect2.getMinY()}; + return new AffineTransform(f); + } + + /** + * @return the onAppearance + */ + public PDFObject getOnAppearance() { + return onAppearance; + } + + /** + * @return the offAppearance + */ + public PDFObject getOffAppearance() { + return offAppearance; + } + + /** + * @return the appearanceStateOn + */ + public boolean isAppearanceStateOn() { + return appearanceStateOn; + } + + public void switchAppearance() { + this.appearanceStateOn = !this.appearanceStateOn; + } + + public PDFObject getCurrentAppearance() { + return appearanceStateOn?onAppearance:offAppearance; + } + + public List getCurrentCommand() { + return appearanceStateOn?onCmd:offCmd; + } + + @Override + public List getPageCommandsForAnnotation() { + List pageCommandsForAnnotation = super.getPageCommandsForAnnotation(); + pageCommandsForAnnotation.addAll(getCurrentCommand()); + return pageCommandsForAnnotation; + } + + /** + * @return the popupAnnotation + */ + public PDFAnnotation getPopupAnnotation() { + return popupAnnotation; + } + + public String getTextLabel() { + return textLabel; + } + +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/PDFAnnotation.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/PDFAnnotation.java new file mode 100644 index 000000000..9832e7f82 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/PDFAnnotation.java @@ -0,0 +1,236 @@ +package com.sun.pdfview.annotation; + +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; +import java.awt.geom.Rectangle2D.Float; +import java.io.IOException; +import java.lang.reflect.Constructor; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; + +import com.sun.pdfview.Configuration; +import com.sun.pdfview.PDFCmd; +import com.sun.pdfview.PDFObject; +import com.sun.pdfview.PDFParseException; + +/***************************************************************************** + * Encapsulate a PDF annotation. This is only the super-class of PDF annotations, + * which has an "unknown" annotation type. + * Use the createAnnotation() method for getting an annotation of the correct + * type (if implemented). + * + * @author Katja Sondermann + * @since 03.07.2009 + ****************************************************************************/ +public class PDFAnnotation{ + + /** Definition of some annotation sub-types*/ + public static final String GOTO = "GoTo"; + public static final String GOTOE = "GoToE"; + public static final String GOTOR = "GoToR"; + public static final String URI = "URI"; + + public enum Flags { + UNKNOWN, // 0 + INVISIBLE, // 1 + HIDDEN, // 2 + PRINT, // 3 + NO_ZOOM, // 4 + NO_ROTATE, // 5 + NO_VIEW, // 6 + READ_ONLY, // 7 + LOCKED, // 8 + TOGGLE_NO_VIEW, // 9 + LOCKED_CONTENTS // 10 + } + + + private final PDFObject pdfObj; + private final AnnotationType type; + private final Float rect; + private final String subType; + private final String contents; + + private final String annotationName; + private String modified; + private Integer flags; + private String appearanceState; + + /************************************************************************* + * Constructor + * @param annotObject - the PDFObject which contains the annotation description + * @throws IOException + ************************************************************************/ + public PDFAnnotation(PDFObject annotObject) throws IOException{ + this(annotObject, AnnotationType.UNKNOWN); + } + + /************************************************************************* + * Constructor + * @param annotObject - the PDFObject which contains the annotation description + * @throws IOException + ************************************************************************/ + public PDFAnnotation(PDFObject annotObject, AnnotationType type) throws IOException{ + this.pdfObj = annotObject; + // in case a general "PdfAnnotation" is created the type is unknown + this.type = type; + + this.subType = annotObject.getDictRefAsString("Subtype"); + this.contents = annotObject.getDictRefAsString("Contents"); + this.annotationName = annotObject.getDictRefAsString("NM"); + this.modified = annotObject.getDictRefAsString("M"); + this.flags = annotObject.getDictRefAsInt("F"); + this.appearanceState = annotObject.getDictRefAsString("AS"); + + // TODO add Border, C, StructParent, OC + + this.rect = this.parseRect(annotObject.getDictRef("Rect")); + } + + /************************************************************************* + * Create a new PDF annotation object. + * + * Currently supported annotation types: + *
  • Link annotation
  • + * + * @param parent + * @return PDFAnnotation + * @throws IOException + ************************************************************************/ + public static PDFAnnotation createAnnotation(PDFObject parent) throws IOException{ + PDFObject subtypeValue = parent.getDictRef("Subtype"); + if(subtypeValue == null) { + return null; + } + String subtypeS = subtypeValue.getStringValue(); + AnnotationType annotationType = AnnotationType.getByDefinition(subtypeS); + + //if Subtype is Widget than check if it is also a Signature + if(annotationType == AnnotationType.WIDGET) { + PDFObject sigType = parent.getDictRef("FT"); + if(sigType != null) { + String sigTypeS = sigType.getStringValue(); + if(AnnotationType.getByDefinition(sigTypeS) == AnnotationType.SIGNATURE) { + annotationType = AnnotationType.getByDefinition(sigTypeS); + } + } + } + + if(annotationType.displayAnnotation()) { + Class className = annotationType.getClassName(); + + try { + if (className.equals(MarkupAnnotation.class) || className.equals(TextMarkupAnnotation.class)) { + Constructor constructor = className.getConstructor(PDFObject.class, AnnotationType.class); + return (PDFAnnotation)constructor.newInstance(parent, annotationType); + } else { + Constructor constructor = className.getConstructor(PDFObject.class); + return (PDFAnnotation)constructor.newInstance(parent); + } + } catch (Exception e) { + throw new PDFParseException("Could not parse annotation!", e); + } + } + + return null; + } + + /** + * Get a Rectangle2D.Float representation for a PDFObject that is an + * array of four Numbers. + * @param obj a PDFObject that represents an Array of exactly four + * Numbers. + */ + public Rectangle2D.Float parseRect(PDFObject obj) throws IOException { + if (obj.getType() == PDFObject.ARRAY) { + PDFObject bounds[] = obj.getArray(); + if (bounds.length == 4) { + return new Rectangle2D.Float(bounds[0].getFloatValue(), + bounds[1].getFloatValue(), + bounds[2].getFloatValue() - bounds[0].getFloatValue(), + bounds[3].getFloatValue() - bounds[1].getFloatValue()); + } else { + throw new PDFParseException("Rectangle definition didn't have 4 elements"); + } + } else { + throw new PDFParseException("Rectangle definition not an array"); + } + } + + /************************************************************************* + * Get the PDF Object which contains the annotation values + * @return PDFObject + ************************************************************************/ + public PDFObject getPdfObj() { + return this.pdfObj; + } + + /************************************************************************* + * Get the annotation type + * @return int + ************************************************************************/ + public AnnotationType getType() { + return this.type; + } + + /************************************************************************* + * Get the rectangle on which the annotation should be applied to + * @return Rectangle2D.Float + ************************************************************************/ + public Float getRect() { + return this.rect; + } + + public String getSubType() { + return subType; + } + + public String getAnnotationName() { + return annotationName; + } + + public String getAppearanceState() { + return appearanceState; + } + + public String getContents() { + return contents; + } + + public Integer getFlags() { + return flags; + } + + public boolean isFlagSet(Flags flag) { + return flags != null + && BigInteger.valueOf(flags).testBit(flag.ordinal()); + } + + public String getModified() { + return modified; + } + + @Override + public String toString() { + return this.pdfObj.toString(); + } + + /** + * Get list of pdf commands for this annotation + * @return + */ + public List getPageCommandsForAnnotation() { + return new ArrayList(); + } + + + protected AffineTransform getScalingTransformation(Float bbox) { + AffineTransform at = new AffineTransform(); + double scaleHeight = getRect().getHeight()/bbox.getHeight(); + double scaleWidth = getRect().getWidth()/bbox.getWidth(); + at.scale(scaleWidth, scaleHeight); + return at; + } + +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/SquareAnnotation.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/SquareAnnotation.java new file mode 100644 index 000000000..88f3a5b19 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/SquareAnnotation.java @@ -0,0 +1,25 @@ +package com.sun.pdfview.annotation; + +import java.io.IOException; + +import com.sun.pdfview.PDFObject; + +/***************************************************************************** + * PDF annotation for a square + * + * @author Bernd Rosstauscher + ****************************************************************************/ +public class SquareAnnotation extends MarkupAnnotation { + + // TODO Not all of this is fully implemented yet. + // But it will work if the visual representation is done via an "Appearance Stream" + + /************************************************************************* + * Constructor + * @param annotObject + * @throws IOException + ************************************************************************/ + public SquareAnnotation(PDFObject annotObject) throws IOException { + super(annotObject, AnnotationType.SQUARE); + } +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/StampAnnotation.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/StampAnnotation.java new file mode 100644 index 000000000..4d297fc42 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/StampAnnotation.java @@ -0,0 +1,70 @@ +package com.sun.pdfview.annotation; + +import java.io.IOException; +import java.util.List; + +import com.sun.pdfview.PDFCmd; +import com.sun.pdfview.PDFObject; + +/***************************************************************************** + * PDF annotation describing a stamp + * + * @author Katja Sondermann + * @since 26.03.2012 + ****************************************************************************/ +public class StampAnnotation extends MarkupAnnotation { + + private String iconName; + private List iconCommands; + + /************************************************************************* + * Constructor + * @param annotObject + * @throws IOException + ************************************************************************/ + public StampAnnotation(PDFObject annotObject) throws IOException { + super(annotObject, AnnotationType.STAMP); + this.iconName = annotObject.getDictRefAsString("Name"); + + // No AP so use the icon name + if (iconName != null && annotObject.getDictRef("AP") == null) { + parseIconCommands(); + } + + } + + /** + * If the stamp is represented by one of the predefined icons + * this will parse it and create PDFCommands for them. + */ + private void parseIconCommands() { + // TODO Add code for the different icon constants. + // fill iconCommands + + // These command names exist. + + // Approved, Experimental, NotApproved, AsIs, Expired , + // NotForPublicRelease, Confidential, Final, Sold, + // Departmental, ForComment, TopSecret, Draft, ForPublicRelease + } + + /** + * @return the iconName + */ + public String getIconName() { + return iconName; + } + + /** + *@return the PDF commands to render this annotation + */ + @Override + public List getCurrentCommand() { + List apCommand = super.getCurrentCommand(); + if (apCommand != null) { + return apCommand; + } + return this.iconCommands; + } + +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/TextMarkupAnnotation.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/TextMarkupAnnotation.java new file mode 100644 index 000000000..21d99d423 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/TextMarkupAnnotation.java @@ -0,0 +1,82 @@ +package com.sun.pdfview.annotation; + +import java.awt.Rectangle; +import java.awt.geom.AffineTransform; +import java.awt.geom.GeneralPath; +import java.awt.geom.Rectangle2D; +import java.awt.geom.Rectangle2D.Float; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import com.sun.pdfview.PDFCmd; +import com.sun.pdfview.PDFImage; +import com.sun.pdfview.PDFObject; +import com.sun.pdfview.PDFPage; +import com.sun.pdfview.PDFParseException; +import com.sun.pdfview.PDFParser; +import com.sun.pdfview.PDFShapeCmd; + +/***************************************************************************** + * PDF annotation describing a text markup: Highlight, Underline, Squiggle, StrikeOut + * + * @author Bernd Rosstauscher + ****************************************************************************/ +public class TextMarkupAnnotation extends MarkupAnnotation { + + private int[] quadPoints; + private List highlightCommands; + + /************************************************************************* + * Constructor + * @param annotObject + * @throws IOException + ************************************************************************/ + public TextMarkupAnnotation(PDFObject annotObject, AnnotationType annotationType) throws IOException { + super(annotObject, annotationType); + this.quadPoints = annotObject.getDictRefAsIntArray("QuadPoints"); + + // No AP so use the quad points and highlight mode + if (annotObject.getDictRef("AP") == null) { + parseHighlightCommands(); + } + + } + + /** + * Parse the highlight commands + */ + private void parseHighlightCommands() { + // invalid quad points + if (this.quadPoints == null || this.quadPoints.length % 4 != 0) { + return; + } + highlightCommands = new ArrayList(); + highlightCommands.add(PDFPage.createPushCmd()); + + //TODO currently we use the same code for: Highlight, Underline, Squiggle, StrikeOut + // We should also set the correct colors and such. + + // Draw a box + for (int i = 0; i < quadPoints.length; i+=4) { + GeneralPath gp = new GeneralPath(new Rectangle(quadPoints[i], quadPoints[i+1], quadPoints[i+2], quadPoints[i+3])); + highlightCommands.add(new PDFShapeCmd(gp, PDFShapeCmd.FILL, true)); + } + highlightCommands.add(PDFPage.createPopCmd()); + } + + /** + * Gets the highlight painting commands + * Use either Quads or Appearance Stream + */ + @Override + public List getCurrentCommand() { + List apCommand = super.getCurrentCommand(); + if (apCommand != null) { + return apCommand; + } + return this.highlightCommands; + } + +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/WidgetAnnotation.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/WidgetAnnotation.java new file mode 100644 index 000000000..21e4740ae --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/WidgetAnnotation.java @@ -0,0 +1,300 @@ +package com.sun.pdfview.annotation; + +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; +import java.awt.geom.Rectangle2D.Float; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import com.sun.pdfview.PDFCmd; +import com.sun.pdfview.PDFImage; +import com.sun.pdfview.PDFObject; +import com.sun.pdfview.PDFPage; +import com.sun.pdfview.PDFParseException; +import com.sun.pdfview.PDFParser; + +/** + * PDF annotation describing a widget. + * @since Aug 20, 2010 + */ +public class WidgetAnnotation extends PDFAnnotation { + + private String fieldValue; + private FieldType fieldType; + private String fieldName; + private PDFObject fieldValueRef; + private List cmd; + + /** + * Type for PDF form elements + * @version $Id: WidgetAnnotation.java,v 1.2 2010-09-30 10:34:44 xphc Exp $ + * @author xphc + * @since Aug 20, 2010 + */ + public enum FieldType { + /** Button Field */ + Button("Btn"), + /** Text Field */ + Text("Tx"), + /** Choice Field */ + Choice("Ch"), + /** Signature Field */ + Signature("Sig"); + + private final String typeCode; + + FieldType(String typeCode) { + this.typeCode = typeCode; + } + + static FieldType getByCode(String typeCode) { + FieldType[] values = values(); + for (FieldType value : values) { + if (value.typeCode.equals(typeCode)) + return value; + } + return null; + } + } + + public WidgetAnnotation(PDFObject annotObject) throws IOException { + super(annotObject, AnnotationType.WIDGET); + + // The type of field that this dictionary describes. Field type is + // present for terminal fields but is inherited from parent if absent + // (see PDF Reference 1.7 table 8.69) + PDFObject fieldTypeRef = annotObject.getDictRef("FT"); + if (fieldTypeRef != null) { + // terminal field + this.fieldType = FieldType.getByCode(fieldTypeRef.getStringValue()); + } + else { + // must check parent since field type is inherited + PDFObject parent = annotObject.getDictRef("Parent"); + while (parent != null && parent.isIndirect()) { + parent = parent.dereference(); + } + if (parent != null) { + fieldTypeRef = parent.getDictRef("FT"); + this.fieldType = FieldType.getByCode(fieldTypeRef.getStringValue()); + } + } + + // Name defined for the field + PDFObject fieldNameRef = annotObject.getDictRef("T"); + if (fieldNameRef != null) { + this.fieldName = fieldNameRef.getTextStringValue(); + } + this.fieldValueRef = annotObject.getDictRef("V"); + if (this.fieldValueRef != null) { + this.fieldValue = this.fieldValueRef.getTextStringValue(); + } + parseAP(annotObject.getDictRef("AP")); + } + + private void parseAP(PDFObject dictRef) throws IOException { + if(dictRef == null) { + return; + } + PDFObject normalAP = dictRef.getDictRef("N"); + if(normalAP == null) { + return; + } + cmd = parseCommand(normalAP); + } + + /** + * @param obj + * @return + * @throws IOException + */ + private List parseCommand(PDFObject obj) throws IOException { + // TODO see also MarkupAnnotation.parseIntoPdfCommands() which seems to be copied code + // We should merge these two + PDFObject dictRefSubType = obj.getDictRef("Subtype"); + String type = null; + if(dictRefSubType != null) { + type = dictRefSubType.getStringValue(); + } + + if (type == null) { + PDFObject dictRefS = obj.getDictRef("S"); + if(dictRefS != null) { + type = dictRefS.getStringValue(); + } + } + + //if type is still null, check for AcroForm, if AcroForm is available the PDF could be not compatible + //with the PDF specification, anyway check if obj is in AcroForm, if so, proceed as for a good PDF + if(type == null) { + PDFObject acroForm = obj.getRoot().getDictRef("AcroForm"); + PDFObject fields = acroForm.getDictRef("Fields"); + PDFObject[] arrayFields = fields.getArray(); + + for (PDFObject pdfObject : arrayFields) { + PDFObject dictRefAP = pdfObject.getDictRef("AP"); + if(dictRefAP != null) { + PDFObject dictRefN = dictRefAP.getDictRef("N"); + + if(dictRefN.equals(obj)) { + PDFObject dictRefAS = pdfObject.getDictRef("AS"); + if(dictRefAS != null) { //this is a combobox + PDFObject dictRef = dictRefN.getDictRef(dictRefAS.getStringValue()); + obj = dictRef; + } + + type = "Form"; + break; + } + } + } + + if(type == null) { //check for radiobutton + PDFObject dictRef = obj.getDictRef("Off"); + if(dictRef != null) { + for (PDFObject pdfObject : arrayFields) { + PDFObject dictRefT = pdfObject.getDictRef("T"); + if(dictRefT != null && dictRefT.getStringValue().contains("Group")) { + PDFObject kids = pdfObject.getDictRef("Kids"); + PDFObject[] arrayKids = kids.getArray(); + for (PDFObject kid : arrayKids) { + PDFObject kidAP = kid.getDictRef("AP"); + PDFObject kidN = kidAP.getDictRef("N"); + if(kidN.equals(obj)) { + PDFObject kidAS = kid.getDictRef("AS"); + if(kidAS != null) { + PDFObject kidRef = kidN.getDictRef(kidAS.getStringValue()); + obj = kidRef; + } + + type = "Form"; + break; + } + } + } + } + } + } + } + + ArrayList result = new ArrayList(); + result.add(PDFPage.createPushCmd()); + result.add(PDFPage.createPushCmd()); + if ("Image".equals(type)) { + // stamp annotation transformation + AffineTransform rectAt = getPositionTransformation(); + result.add(PDFPage.createXFormCmd(rectAt)); + + PDFImage img = PDFImage.createImage(obj, new HashMap() , false); + result.add(PDFPage.createImageCmd(img)); + } else if ("Form".equals(type)) { + // rats. parse it. + PDFObject bobj = obj.getDictRef("BBox"); + Float bbox = new Rectangle2D.Float(bobj.getAt(0).getFloatValue(), + bobj.getAt(1).getFloatValue(), + bobj.getAt(2).getFloatValue(), + bobj.getAt(3).getFloatValue()); + PDFPage formCmds = new PDFPage(bbox, 0); + // stamp annotation transformation + AffineTransform rectAt = getPositionTransformation(); + formCmds.addXform(rectAt); + + AffineTransform rectScaled = getScalingTransformation(bbox); + formCmds.addXform(rectScaled); + + // form transformation + AffineTransform at; + PDFObject matrix = obj.getDictRef("Matrix"); + if (matrix == null) { + at = new AffineTransform(); + } else { + float elts[] = new float[6]; + for (int i = 0; i < elts.length; i++) { + elts[i] = (matrix.getAt(i)).getFloatValue(); + } + at = new AffineTransform(elts); + } + formCmds.addXform(at); + + HashMap r = new HashMap(new HashMap()); + PDFObject rsrc = obj.getDictRef("Resources"); + if (rsrc != null) { + r.putAll(rsrc.getDictionary()); + } + + PDFParser form = new PDFParser(formCmds, obj.getStream(), r); + form.go(true); + + result.addAll(formCmds.getCommands()); + } else { + throw new PDFParseException("Unknown XObject subtype: " + type); + } + result.add(PDFPage.createPopCmd()); + result.add(PDFPage.createPopCmd()); + return result; + } + + /** + * Transform to the position of the stamp annotation + * @return + */ + private AffineTransform getPositionTransformation() { + Float rect2 = getRect(); + double[] f = new double[] {1, + 0, + 0, + 1, + rect2.getMinX(), + rect2.getMinY()}; + return new AffineTransform(f); + } + + /** + * Returns the type of the field + * @return Field type + */ + public FieldType getFieldType() { + return this.fieldType; + } + + /** + * The field's value as a string. Might be {@code null}. + * @return The field value or {@code null}. + */ + public String getFieldValue() { + return this.fieldValue; + } + + /** + * Sets the field value for a text field. Note: this doesn't actually change + * the PDF file yet. + * + * @param fieldValue + * The new value for the text field + */ + public void setFieldValue(String fieldValue) { + this.fieldValue = fieldValue; + } + + /** + * Name for this widget. + * @return Widget name + */ + public String getFieldName() { + return this.fieldName; + } + + @Override + public List getPageCommandsForAnnotation() { + List pageCommandsForAnnotation = super.getPageCommandsForAnnotation(); + // cmd might be null if there is no AP (appearance dictionary) + // AP is optional see PDF Reference 1.7 table 8.15 + if (this.cmd != null) { + pageCommandsForAnnotation.addAll(this.cmd); + } + return pageCommandsForAnnotation; + } + +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/AltColorSpace.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/AltColorSpace.java new file mode 100644 index 000000000..f4c157cc1 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/AltColorSpace.java @@ -0,0 +1,73 @@ +package com.sun.pdfview.colorspace; + +import java.awt.color.ColorSpace; + +import com.sun.pdfview.function.PDFFunction; + +/***************************************************************************** + * Color Space implementation for handling the PDF AlternateColorSpace. + * A PDF function is applied to colorvalues before converting. + * + * @author Katja Sondermann + * @since 06.01.2011 + ****************************************************************************/ +public class AltColorSpace extends ColorSpace { + + private PDFFunction fkt; + private ColorSpace origCs; + /** + * Create a new CMYKColorSpace Instance. + */ + public AltColorSpace(PDFFunction fkt, ColorSpace origCs) { + super(origCs.getType(), fkt.getNumInputs()); + this.fkt = fkt; + this.origCs = origCs; + } + + /** + * Converts from CIEXYZ. + * + * @see java.awt.color.ColorSpace#fromCIEXYZ(float[]) + * @see org.scantegrity.lib.CMYKColorSpace#toCIEXYZ + */ + @Override + public float[] fromCIEXYZ(float[] p_colorvalue) { + p_colorvalue = this.fkt.calculate(p_colorvalue); + return this.origCs.fromCIEXYZ(p_colorvalue); + } + + /** + * Converts a given RGB. + * + * @param p_rgbvalue - The color to translate + * @return a float[4] of the CMYK values. + * @see java.awt.color.ColorSpace#fromRGB(float[]) + */ + @Override + public float[] fromRGB(float[] p_rgbvalue) { + p_rgbvalue = this.fkt.calculate(p_rgbvalue); + return this.origCs.fromCIEXYZ(p_rgbvalue); + } + + /** + * Converts to CIEXYZ. + * @see java.awt.color.ColorSpace#toCIEXYZ(float[]) + */ + @Override + public float[] toCIEXYZ(float[] p_colorvalue) { + float[] colorvalue = this.fkt.calculate(p_colorvalue); + return this.origCs.toCIEXYZ(colorvalue); + } + + /** + * Converts to RGB. + * + * @param p_colorvalue The color in CMYK. + * @see java.awt.color.ColorSpace#toRGB(float[]) + */ + @Override + public float[] toRGB(float[] p_colorvalue) { + float[] colorvalue = this.fkt.calculate(p_colorvalue); + return this.origCs.toRGB(colorvalue); + } +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/AlternateColorSpace.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/AlternateColorSpace.java new file mode 100644 index 000000000..d0deab603 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/AlternateColorSpace.java @@ -0,0 +1,95 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package com.sun.pdfview.colorspace; + +import java.awt.color.ColorSpace; + +import com.sun.pdfview.PDFPaint; +import com.sun.pdfview.function.PDFFunction; + +/** + * A color space that uses another color space to return values, and a + * function to map between values in the input and input values to the + * alternate color space + */ +public class AlternateColorSpace extends PDFColorSpace { + /** The alternate color space */ + private PDFColorSpace alternate; + + /** The function */ + private PDFFunction function; + + private AltColorSpace altcolorspace; + + /** Creates a new instance of AlternateColorSpace */ + public AlternateColorSpace(PDFColorSpace alternate, PDFFunction function) { + super(null); + + this.alternate = alternate; + this.function = function; + } + + /** + * get the number of components expected in the getPaint command + */ + @Override public int getNumComponents() { + if (this.function != null) { + return this.function.getNumInputs(); + } else { + return this.alternate.getNumComponents(); + } + } + + /** + * get the PDFPaint representing the color described by the + * given color components + * @param components the color components corresponding to the given + * colorspace + * @return a PDFPaint object representing the closest Color to the + * given components. + */ + @Override public PDFPaint getPaint(float[] components) { + if (this.function != null) { + // translate values using function + components = this.function.calculate(components); + } + + return this.alternate.getPaint(components); + } + + /** + * get the original Java ColorSpace. + */ + @Override public ColorSpace getColorSpace() { + if (altcolorspace == null) altcolorspace = new AltColorSpace(function, alternate.getColorSpace()); + return altcolorspace; + //return this.alternate.getColorSpace(); + } + + /************************************************************************* + * Get the PDF function + * @return PDFFunction + ************************************************************************/ + public PDFFunction getFunktion() { + return this.function; + } + + +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/CMYKColorSpace.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/CMYKColorSpace.java new file mode 100644 index 000000000..e5345b112 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/CMYKColorSpace.java @@ -0,0 +1,79 @@ +package com.sun.pdfview.colorspace; + +import java.awt.color.ColorSpace; + +public class CMYKColorSpace extends ColorSpace { + + private static final long serialVersionUID = 1L; + + /** + * Create a new CMYKColorSpace instance. + */ + public CMYKColorSpace() { + super(ColorSpace.TYPE_CMYK, 4); + } + + @Override + public float[] fromCIEXYZ(float[] colorvalue) { + // Convert CIEXYZ to RGB first + ColorSpace sRGB = ColorSpace.getInstance(ColorSpace.CS_sRGB); + float[] rgb = sRGB.fromCIEXYZ(colorvalue); + // Convert RGB to CMYK + return fromRGB(rgb); + } + + @Override + public float[] fromRGB(float[] rgbvalue) { + // Convert RGB to CMY + float c = 1 - rgbvalue[0]; + float m = 1 - rgbvalue[1]; + float y = 1 - rgbvalue[2]; + + // Extract the black key (K) + float k = Math.min(c, Math.min(m, y)); + + // Avoid division by zero and ensure we don't get negative values + float divisor = (1 - k) == 0 ? 1 : (1 - k); + float cC = (c - k) / divisor; + float mC = (m - k) / divisor; + float yC = (y - k) / divisor; + + return new float[]{cC, mC, yC, k}; + } + + @Override + public float[] toCIEXYZ(float[] colorvalue) { + // Convert CMYK to RGB first + float[] rgb = toRGB(colorvalue); + // Convert RGB to CIEXYZ + ColorSpace sRGB = ColorSpace.getInstance(ColorSpace.CS_sRGB); + return sRGB.toCIEXYZ(rgb); + } + + @Override + public float[] toRGB(float[] cmykvalue) { + float c = cmykvalue[0]; + float m = cmykvalue[1]; + float y = cmykvalue[2]; + float k = cmykvalue[3]; + + float r = (1 - c) * (1 - k); + float g = (1 - m) * (1 - k); + float b = (1 - y) * (1 - k); + + return new float[]{r, g, b}; + } + + /** + * Normalize ensures all color values returned are between 0 and 1. + * + * @param colors the color values to normalize + * @return the normalized color values + */ + private float[] normalize(float[] colors) { + for (int i = 0; i < colors.length; i++) { + colors[i] = Math.min(1.0f, Math.max(0.0f, colors[i])); + } + return colors; + } +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/CalGrayColor.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/CalGrayColor.java new file mode 100644 index 000000000..667707939 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/CalGrayColor.java @@ -0,0 +1,133 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package com.sun.pdfview.colorspace; + +import java.awt.color.ColorSpace; +import java.io.IOException; + +import com.sun.pdfview.PDFObject; + +/** + * A ColorSpace for calibrated gray + * @author Mike Wessler + */ +public class CalGrayColor extends ColorSpace { + float white[]= {1f, 1f, 1f}; + float black[]= {0, 0, 0}; + float gamma= 1; + static ColorSpace cie= ColorSpace.getInstance(ColorSpace.CS_sRGB); + + /** + * Create a new Calibrated Gray color space object, given + * the description in a PDF dictionary. + * @param obj a dictionary that contains an Array of 3 Numbers + * for "WhitePoint" and "BlackPoint", and a Number for "Gamma" + */ + public CalGrayColor(PDFObject obj) throws IOException { + // obj is a dictionary that has the following parts: + // WhitePoint [a b c] + // BlackPoint [a b c] + // Gamma a + super(TYPE_GRAY, 1); + PDFObject ary= obj.getDictRef("WhitePoint"); + if (ary!=null) { + for(int i=0; i<3; i++) { + this.white[i]= ary.getAt(i).getFloatValue(); + } + } + ary= obj.getDictRef("BlackPoint"); + if (ary!=null) { + for(int i=0; i<3; i++) { + this.black[i]= ary.getAt(i).getFloatValue(); + } + } + PDFObject g= obj.getDictRef("Gamma"); + if (g!=null) { + this.gamma= g.getFloatValue(); + } + } + + /** + * Create a new calibrated gray color space object, with the + * default values for black point, white point and gamma + */ + public CalGrayColor() { + super(TYPE_GRAY, 1); + } + + /** + * get the number of components (1). + */ + @Override public int getNumComponents() { + return 1; + } + + /** + * convert from Calibrated Gray to RGB. + * @param comp the gray value (0-1) + * @return the RGB values (0-1) + */ + @Override + public float[] toRGB(float comp[]) { + if (comp.length==1) { + float mul= (float)Math.pow(comp[0], this.gamma); + float xyz[] = { + this.white[0]*mul, + 0, + 0}; + float rgb[]= cie.fromCIEXYZ(xyz); + return rgb; + } else { + return this.black; + } + } + + /** + * convert from RGB to Calibrated Gray. NOT IMPLEMENTED + */ + @Override + public float[] fromRGB(float[] rgbvalue) { + return new float[1]; + } + + /** + * convert from CIEXYZ to Calibrated Gray. NOT IMPLEMENTED + */ + @Override + public float[] fromCIEXYZ(float[] colorvalue) { + return new float[1]; + } + + /** + * get the type of this ColorSpace (TYPE_GRAY) + */ + @Override public int getType() { + return TYPE_GRAY; + } + + /** + * convert from Calibrated Gray to CIEXYZ. NOT IMPLEMENTED + */ + @Override + public float[] toCIEXYZ(float[] colorvalue) { + return new float[3]; + } + +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/CalRGBColor.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/CalRGBColor.java new file mode 100644 index 000000000..5c69689c5 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/CalRGBColor.java @@ -0,0 +1,250 @@ +/* + * $Id: CalRGBColor.java,v 1.1 2009-07-01 12:43:19 bros Exp $ + * + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package com.sun.pdfview.colorspace; + +import java.awt.color.ColorSpace; +import java.io.IOException; + +import com.sun.pdfview.PDFObject; +import com.sun.pdfview.function.FunctionType0; + +/** + * A ColorSpace for calibrated RGB + * @author Mike Wessler + */ +public class CalRGBColor extends ColorSpace { + private static final float[] vonKriesM = { 0.40024f, -0.22630f, 0.00000f, + 0.70760f, 1.16532f, 0.00000f, + -0.08081f, 0.04570f, 0.91822f }; + private static final float[] vonKriesMinv = { 1.859936f, 0.361191f, 0.000000f, + -1.129382f, 0.638812f, 0.000000f, + 0.219897f, -0.000006f, 1.089064f }; + private static final float[] xyzToSRGB = { 3.24071f, -0.969258f, 0.0556352f, + -1.53726f, 1.87599f, -0.203996f, + -0.498571f, 0.0415557f, 1.05707f }; + + private static final float[] xyzToRGB = { 2.04148f, -0.969258f, 0.0134455f, + -0.564977f, 1.87599f, -0.118373f, + -0.344713f, 0.0415557f, 1.01527f }; + + float[] scale; + float[] max; + + float white[]= {1f, 1f, 1f}; + float black[]= {0, 0, 0}; + float matrix[]= {1f, 0, 0, 0, 1f, 0, 0, 0, 1f}; + float gamma[]= {1f, 1f, 1f}; + + static ColorSpace rgbCS= ColorSpace.getInstance(ColorSpace.CS_sRGB); + static ColorSpace cieCS= ColorSpace.getInstance(ColorSpace.CS_CIEXYZ); + + /** + * Create a new Calibrated RGB color space object, given the + * description in a PDF dictionary. + * @param obj a dictionary that contains an array of 3 Numbers + * for "WhitePoint" and "BlackPoint", a Number for "Gamma", and + * an array of 9 Numbers for "Matrix". + */ + public CalRGBColor(PDFObject obj) throws IOException { + // obj is a dictionary that has the following parts: + // WhitePoint [a b c] + // BlackPoint [a b c] + // Gamma a + super(CS_sRGB, 3); + + // find out what what is according to the CIE color space + // note that this is not reflexive (i.e. passing this value + // into toRGB does not get you (1.0, 1.0, 1.0) back) + // cieWhite = cieCS.fromRGB(new float[] { 1.0f, 1.0f, 1.0f } ); + + PDFObject ary= obj.getDictRef("WhitePoint"); + if (ary!=null) { + for(int i=0; i<3; i++) { + this.white[i]= ary.getAt(i).getFloatValue(); + } + } + ary= obj.getDictRef("BlackPoint"); + if (ary!=null) { + for(int i=0; i<3; i++) { + this.black[i]= ary.getAt(i).getFloatValue(); + } + } + ary= obj.getDictRef("Gamma"); + if (ary!=null) { + for (int i=0; i<3; i++) { + this.gamma[i]= ary.getAt(i).getFloatValue(); + } + } + ary= obj.getDictRef("Matrix"); + if (ary!=null) { + for (int i=0; i<9; i++) { + this.matrix[i]= ary.getAt(i).getFloatValue(); + } + } + + // create a scale matrix relative to the 50 CIE color space. + // see http://www.brucelindbloom.com/Eqn_RGB_XYZ_Matrix.html + // we use the Von Kries cone response domain + float[] cieWhite = rgbCS.toCIEXYZ(new float[] { 1f, 1f, 1f }); + + float[] sourceWhite = matrixMult(this.white, vonKriesM, 3); + float[] destWhite = matrixMult(cieWhite, vonKriesM, 3); + + this.scale = new float[] { destWhite[0] / sourceWhite[0], 0, 0, + 0, destWhite[1] / sourceWhite[1], 0, + 0, 0, destWhite[2] / sourceWhite[2] }; + this.scale = matrixMult(vonKriesM, this.scale, 3); + this.scale = matrixMult(this.scale, vonKriesMinv, 3); + + this.max = matrixMult(this.white, this.scale, 3); + this.max = ciexyzToSRGB(this.max); + } + + /** + * get the number of components (3) + */ + @Override public int getNumComponents() { + return 3; + } + + /** + * convert from Calibrated RGB to standard RGB + * @param comp the Calibrated RGB values (0-1) + * @return the RGB values (0-1) + */ + @Override + public float[] toRGB(float comp[]) { + if (comp.length==3) { + // compute r', g' and b' by raising the given values to the + // correct gamma + float a = (float)Math.pow(comp[0], this.gamma[0]); + float b = (float)Math.pow(comp[1], this.gamma[1]); + float c = (float)Math.pow(comp[2], this.gamma[2]); + + // now multiply by the matrix to get X, Y and Z values + float[] xyz = new float[] { + this.matrix[0]*a + this.matrix[3]*b + this.matrix[6]*c, + this.matrix[1]*a + this.matrix[4]*b + this.matrix[7]*c, + this.matrix[2]*a + this.matrix[5]*b + this.matrix[8]*c}; + + // now scale the xyz values + xyz = matrixMult(xyz, this.scale, 3); + + // convert to RGB + float[] rgb = ciexyzToSRGB(xyz); + + // cheat -- scale based on max + for (int i = 0; i < rgb.length; i++) { + rgb[i] = FunctionType0.interpolate(rgb[i], 0, this.max[i], 0, 1); + + // sometimes we get off a little bit due to precision loss + if (rgb[i] > 1.0) { + rgb[i] = 1.0f; + } + } + + return rgb; + } else { + return this.black; + } + } + + /** + * Convert from CIEXYZ, with scale and gamma calculated to sRGB + */ + private float[] ciexyzToSRGB(float[] xyz) { + float[] rgb = matrixMult(xyz, xyzToSRGB, 3); + + for (int i = 0; i < rgb.length; i++) { + if (rgb[i] < 0.0) { + rgb[i] = 0f; + } else if (rgb[i] > 1.0) { + rgb[i] = 1f; + } + + if (rgb[i] < 0.003928) { + rgb[i] *= 12.92; + } else { + rgb[i] = (float) ((Math.pow(rgb[i], 1.0 / 2.4) * 1.055) - 0.055); + } + } + + //float[] rgb = cieCS.toRGB(xyz); + return rgb; + } + + /** + * convert from RGB to Calibrated RGB. NOT IMPLEMENTED + */ + @Override + public float[] fromRGB(float[] rgbvalue) { + return new float[3]; + } + + /** + * convert from CIEXYZ to Calibrated RGB. NOT IMPLEMENTED + */ + @Override + public float[] fromCIEXYZ(float[] colorvalue) { + return new float[3]; + } + + /** + * get the type of this color space (TYPE_RGB) + */ + @Override public int getType() { + return TYPE_RGB; + } + + /** + * convert from Calibrated RGB to CIEXYZ. NOT IMPLEMENTED + */ + @Override + public float[] toCIEXYZ(float[] colorvalue) { + return new float[3]; + } + + /** + * Slowly multiply two matrices + * + * @param a the first matrix + * @param b the second matrix + * @param len the size of each row. All matrix lengths must be a + * multiple of len. + */ + float[] matrixMult(float[] a, float[] b, int len) { + int rows = a.length / len; + int cols = b.length / len; + + float[] out = new float[rows * cols]; + + for (int i = 0; i < rows; i++) { + for (int k = 0; k < cols; k++) { + for (int j = 0; j < len; j++) { + out[(i * cols) + k] += a[(i * len) + j] * b[(j * cols) + k]; + } + } + } + + return out; + } +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/IndexedColor.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/IndexedColor.java new file mode 100644 index 000000000..e37d38815 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/IndexedColor.java @@ -0,0 +1,137 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.sun.pdfview.colorspace; + +import java.awt.Color; +import java.io.IOException; + +import com.sun.pdfview.PDFObject; +import com.sun.pdfview.PDFPaint; + +/** + * A PDFColorSpace for an IndexedColor model + * + * @author Mike Wessler + */ +public class IndexedColor extends PDFColorSpace { + + /** + * r,g,and b components of the color table as a single array, for + * Java's IndexColorModel */ + protected byte[] finalcolors; + /** the color table */ + Color table[]; + /** size of the color table */ + int count; + /** number of channels in the base Color Space (unused) */ + int nchannels = 1; + + /** + * create a new IndexColor PDFColorSpace based on another PDFColorSpace, + * a count of colors, and a stream of values. Every consecutive n bytes + * of the stream is interpreted as a color in the base ColorSpace, where + * n is the number of components in that color space. + * + * @param base the color space in which the data is interpreted + * @param count the number of colors in the table + * @param stream a stream of bytes. The number of bytes must be count*n, + * where n is the number of components in the base colorspace. + */ + public IndexedColor(PDFColorSpace base, int count, PDFObject stream) throws IOException { + super(null); + count++; + this.count = count; + byte[] data = stream.getStream(); + this.nchannels = base.getNumComponents(); + boolean offSized = (data.length / this.nchannels) < count; + this.finalcolors = new byte[3 * count]; + this.table = new Color[count]; + float comps[] = new float[this.nchannels]; + int loc = 0; + int finalloc = 0; + for (int i = 0; i < count; i++) { + for (int j = 0; j < comps.length; j++) { + if (loc < data.length) { + comps[j] = ((data[loc++]) & 0xff) / 255f; + } else { + comps[j] = 1.0f; + } + } + this.table[i] = (Color) base.getPaint(comps).getPaint(); + this.finalcolors[finalloc++] = (byte) this.table[i].getRed(); + this.finalcolors[finalloc++] = (byte) this.table[i].getGreen(); + this.finalcolors[finalloc++] = (byte) this.table[i].getBlue(); + } + } + + /** + * create a new IndexColor PDFColorSpace based on a table of colors. + * + * @param table an array of colors + */ + public IndexedColor(Color[] table) throws IOException { + super(null); + + this.count = table.length; + this.table = table; + + this.finalcolors = new byte[3 * this.count]; + this.nchannels = 3; + + int loc = 0; + + for (int i = 0; i < this.count; i++) { + this.finalcolors[loc++] = (byte) table[i].getRed(); + this.finalcolors[loc++] = (byte) table[i].getGreen(); + this.finalcolors[loc++] = (byte) table[i].getBlue(); + } + } + + /** + * Get the number of indices + */ + public int getCount() { + return this.count; + } + + /** + * Get the table of color components + */ + public byte[] getColorComponents() { + return this.finalcolors; + } + + /** + * get the number of components of this colorspace (1) + */ + @Override + public int getNumComponents() { + return 1; + } + + /** + * get the color represented by the index. + * @param components an array of exactly one integer number whose + * value is between 0 and the size of the color table - 1. + */ + @Override + public PDFPaint getPaint(float components[]) { + return PDFPaint.getPaint(this.table[(int) components[0]]); + } +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/LabColor.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/LabColor.java new file mode 100644 index 000000000..1f1ca1dbe --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/LabColor.java @@ -0,0 +1,138 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package com.sun.pdfview.colorspace; + +import java.awt.color.ColorSpace; +import java.io.IOException; + +import com.sun.pdfview.PDFObject; + +/** + * A ColorSpace for Lab color + * @author Mike Wessler + */ +public class LabColor extends ColorSpace { + float white[]= {1f, 1f, 1f}; + float black[]= {0, 0, 0}; + float range[]= {-100f, 100f, -100f, 100f}; + static ColorSpace cie= ColorSpace.getInstance(ColorSpace.CS_sRGB); + + /** + * Create a new Lab color space object, given the description in + * a PDF dictionary. + * @param obj a dictionary that contains an Array of 3 Numbers for + * "WhitePoint" and "BlackPoint", and an array of 4 Numbers for + * "Range". + */ + public LabColor(PDFObject obj) throws IOException { + // obj is a dictionary that has the following parts: + // WhitePoint [a b c] + // BlackPoint [a b c] + // Gamma a + super(TYPE_Lab, 3); + PDFObject ary= obj.getDictRef("WhitePoint"); + if (ary!=null) { + for(int i=0; i<3; i++) { + this.white[i]= ary.getAt(i).getFloatValue(); + } + } + ary= obj.getDictRef("BlackPoint"); + if (ary!=null) { + for(int i=0; i<3; i++) { + this.black[i]= ary.getAt(i).getFloatValue(); + } + } + ary= obj.getDictRef("Range"); + if (ary!=null) { + for (int i=0; i<4; i++) { + this.range[i]= ary.getAt(i).getFloatValue(); + } + } + } + + /** + * get the number of components for this color space (3) + */ + @Override public int getNumComponents() { + return 3; + } + + /** + * Stage 2 of the conversion algorithm. Pulled out because + * it gets invoked for each component + */ + public final float stage2(float s1) { + return (s1>=6f/29f)?s1*s1*s1:108f/841f*(s1-4f/29f); + } + + /** + * convert from Lab to RGB + * @param comp the Lab values (0-1) + * @return the RGB values (0-1) + */ + @Override + public float[] toRGB(float comp[]) { + if (comp.length==3) { + float l= (comp[0]+16)/116+comp[1]/500; + float m= (comp[0]+16)/116; + float n= (comp[0]+16)/116-comp[2]/200; + float xyz[]= { + this.white[0]*stage2(l), + this.white[0]*stage2(m), + this.white[0]*stage2(n)}; + float rgb[]= cie.fromCIEXYZ(xyz); + return rgb; + } else { + return this.black; + } + } + + /** + * convert from RGB to Lab. NOT IMPLEMENTED + */ + @Override + public float[] fromRGB(float[] rgbvalue) { + return new float[3]; + } + + /** + * convert from CIEXYZ to Lab. NOT IMPLEMENTED + */ + @Override + public float[] fromCIEXYZ(float[] colorvalue) { + return new float[3]; + } + + /** + * get the type of this colorspace (TYPE_Lab) + */ + @Override public int getType() { + return TYPE_Lab; + } + + /** + * convert from Lab to CIEXYZ. NOT IMPLEMENTED + */ + @Override + public float[] toCIEXYZ(float[] colorvalue) { + return new float[3]; + } + +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/MaskColorSpace.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/MaskColorSpace.java new file mode 100644 index 000000000..fb107c006 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/MaskColorSpace.java @@ -0,0 +1,101 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package com.sun.pdfview.colorspace; + +import java.awt.Color; +import java.awt.color.ColorSpace; + +import com.sun.pdfview.PDFPaint; + +/** + * A color space used to implement masks. For now, the only type of mask + * supported is one where the image pixels specify where to paint, and the + * painting itself is done in a pre-specified PDF Paint. + */ +public class MaskColorSpace extends ColorSpace { + /** The paint to paint in. Note this cannot be a pattern or gradient. */ + private final PDFPaint paint; + + /** Creates a new instance of PaintColorSpace */ + public MaskColorSpace(PDFPaint paint) { + super (TYPE_RGB, 1); + + this.paint = paint; + } + + @Override + public float[] fromCIEXYZ(float[] colorvalue) { + float x = colorvalue[0]; + float y = colorvalue[1]; + float z = colorvalue[2]; + + float[] mask = new float[1]; + + if (Math.round(x) > 0 || Math.round(y) > 0 || Math.round(z) > 0) { + mask[0] = 1; + } else { + mask[0] = 0; + } + + return mask; + } + + @Override + public float[] fromRGB(float[] rgbvalue) { + float r = rgbvalue[0]; + float g = rgbvalue[1]; + float b = rgbvalue[2]; + + float[] mask = new float[1]; + + if (Math.round(r) > 0 || Math.round(g) > 0 || Math.round(b) > 0) { + mask[0] = 1; + } else { + mask[0] = 0; + } + + return mask; + } + + ColorSpace cie = ColorSpace.getInstance(ColorSpace.CS_CIEXYZ); + float[] prev1= this.cie.fromRGB(toRGB(new float[] {1.0f})); + float[] prev0= this.cie.fromRGB(toRGB(new float[] {0.0f})); + + @Override + public float[] toCIEXYZ(float[] colorvalue) { + if (colorvalue[0]==1) { + return this.prev1; + } else if (colorvalue[0]==0) { + return this.prev0; + } else { + return this.cie.fromRGB(toRGB(colorvalue)); + } + } + + @Override + public float[] toRGB(float[] colorvalue) { + return ((Color) this.paint.getPaint()).getRGBColorComponents(null); + } + + @Override public int getNumComponents() { + return 1; + } + +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/PDFColorSpace.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/PDFColorSpace.java new file mode 100644 index 000000000..5a0772470 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/PDFColorSpace.java @@ -0,0 +1,237 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.sun.pdfview.colorspace; + +import java.awt.Color; +import java.awt.color.ColorSpace; +import java.awt.color.ICC_ColorSpace; +import java.awt.color.ICC_Profile; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.util.Map; + +import com.sun.pdfview.PDFObject; +import com.sun.pdfview.PDFPaint; +import com.sun.pdfview.PDFParseException; +import com.sun.pdfview.function.PDFFunction; + + +/** + * A color space that can convert a set of color components into + * PDFPaint. + * @author Mike Wessler + */ +public class PDFColorSpace { + /** the name of the device-dependent gray color space */ + public static final int COLORSPACE_GRAY = 0; + + /** the name of the device-dependent RGB color space */ + public static final int COLORSPACE_RGB = 1; + + /** the name of the device-dependent CMYK color space */ + public static final int COLORSPACE_CMYK = 2; + + /** the name of the pattern color space */ + public static final int COLORSPACE_PATTERN = 3; + + /** the device-dependent color spaces */ + // private static PDFColorSpace graySpace = + // new PDFColorSpace(ColorSpace.getInstance(ColorSpace.CS_GRAY)); + private static PDFColorSpace rgbSpace = new PDFColorSpace(ColorSpace.getInstance( + ColorSpace.CS_sRGB)); + private static PDFColorSpace cmykSpace = new PDFColorSpace(new CMYKColorSpace()); + + /** the pattern space */ + private static PDFColorSpace patternSpace = new PatternSpace(); + + /** graySpace and the gamma correction for it. */ + private static PDFColorSpace graySpace; + + /** the color space */ + ColorSpace cs; + + /** + * create a PDFColorSpace based on a Java ColorSpace + * @param cs the Java ColorSpace + */ + public PDFColorSpace(ColorSpace cs) { + this.cs = cs; + } + + /** + * Get a color space by name + * + * @param name the name of one of the device-dependent color spaces + */ + public static PDFColorSpace getColorSpace(int name) { + switch (name) { + case COLORSPACE_GRAY: + return rgbSpace; + case COLORSPACE_RGB: + return rgbSpace; + + case COLORSPACE_CMYK: + return cmykSpace; + + case COLORSPACE_PATTERN: + return patternSpace; + + default: + throw new IllegalArgumentException("Unknown Color Space name: " + + name); + } + } + + /** + * Get a color space specified in a PDFObject + * + * @param csobj the PDFObject with the colorspace information + */ + public static PDFColorSpace getColorSpace(PDFObject csobj, Map resources) + throws IOException { + String name; + + PDFObject colorSpaces = null; + + if (resources != null) { + colorSpaces = (PDFObject) resources.get("ColorSpace"); + } + + if (csobj.getType() == PDFObject.NAME) { + name = csobj.getStringValue(); + + if (name.equals("DeviceGray") || name.equals("G")) { + return getColorSpace(COLORSPACE_GRAY); + } else if (name.equals("DeviceRGB") || name.equals("RGB")) { + return getColorSpace(COLORSPACE_RGB); + } else if (name.equals("DeviceCMYK") || name.equals("CMYK")) { + return getColorSpace(COLORSPACE_CMYK); + } else if (name.equals("Pattern")) { + return getColorSpace(COLORSPACE_PATTERN); + } else if (colorSpaces != null) { + csobj = colorSpaces.getDictRef(name); + } + } + + if (csobj == null) { + return null; + } else if (csobj.getCache() != null) { + return (PDFColorSpace) csobj.getCache(); + } + + PDFColorSpace value = null; + + // csobj is [/name <>] + PDFObject[] ary = csobj.getArray(); + name = ary[0].getStringValue(); + + if (name.equals("DeviceGray") || name.equals("G")) { + return getColorSpace(COLORSPACE_GRAY); + } else if (name.equals("DeviceRGB") || name.equals("RGB")) { + return getColorSpace(COLORSPACE_RGB); + } else if (name.equals("DeviceCMYK") || name.equals("CMYK")) { + return getColorSpace(COLORSPACE_CMYK); + } else if (name.equals("CalGray")) { + value = new PDFColorSpace(new CalGrayColor(ary[1])); + } else if (name.equals("CalRGB")) { + value = new PDFColorSpace(new CalRGBColor(ary[1])); + } else if (name.equals("Lab")) { + value = new PDFColorSpace(new LabColor(ary[1])); + } else if (name.equals("ICCBased")) { + try { + ByteArrayInputStream bais = new ByteArrayInputStream(ary[1].getStream()); + ICC_Profile profile = ICC_Profile.getInstance(bais); + if (profile.getColorSpaceType() == ColorSpace.CS_GRAY || profile.getColorSpaceType() == ColorSpace.TYPE_GRAY) { + return graySpace; + } + value = new PDFColorSpace(new ICC_ColorSpace(profile)); + } catch (IllegalArgumentException e) { + return getColorSpace(COLORSPACE_RGB); + } + } else if (name.equals("Separation") || name.equals("DeviceN")) { + PDFColorSpace alternate = getColorSpace(ary[2], resources); + PDFFunction function = PDFFunction.getFunction(ary[3]); + + value = new AlternateColorSpace(alternate, function); + } else if (name.equals("Indexed") || name.equals("I")) { + /** + * 4.5.5 [/Indexed baseColor hival lookup] + */ + PDFColorSpace refspace = getColorSpace(ary[1], resources); + + // number of indices= ary[2], data is in ary[3]; + int count = ary[2].getIntValue(); + try { + value = new IndexedColor(refspace, count, ary[3]); + }catch(Exception e) { + // there might be problems in reading the colorspace from stream, + // in that case use the reference colorspace + value = refspace; + } + + } else if (name.equals("Pattern")) { + if (ary.length == 1) { + return getColorSpace(COLORSPACE_PATTERN); + } + + PDFColorSpace base = getColorSpace(ary[1], resources); + + return new PatternSpace(base); + } else if(name.equals("DeviceRGB")) { + return getColorSpace(COLORSPACE_RGB); + } else if(name.equals("DeviceCMYK")) { + return getColorSpace(COLORSPACE_CMYK); + } else { + // removed access to ary[1] dur to index out of bounds exceptions + throw new PDFParseException("Unknown color space: " + name); + } + + csobj.setCache(value); + + return value; + } + + /** + * get the number of components expected in the getPaint command + */ + public int getNumComponents() { + return this.cs.getNumComponents(); + } + + /** + * get the PDFPaint representing the color described by the + * given color components + * @param components the color components corresponding to the given + * colorspace + * @return a PDFPaint object representing the closest Color to the + * given components. + */ + public PDFPaint getPaint(float[] components) { + float[] rgb = this.cs.toRGB(components); + + return PDFPaint.getColorPaint(new Color(rgb[0], rgb[1], rgb[2])); + } + + /** + * get the original Java ColorSpace. + */ + public ColorSpace getColorSpace() { + return this.cs; + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/PatternSpace.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/PatternSpace.java new file mode 100644 index 000000000..784a3bc67 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/PatternSpace.java @@ -0,0 +1,107 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package com.sun.pdfview.colorspace; + +import java.io.IOException; +import java.util.Map; + +import com.sun.pdfview.PDFObject; +import com.sun.pdfview.PDFPaint; +import com.sun.pdfview.pattern.PDFPattern; + +/** + * A PatternSpace fills with a pattern, the name of which is + * specified in the call to getPaint(). This pattern is + * read from the resources of the current page. The pattern space + * may also have a base color space which the pattern is defined in. + */ +public class PatternSpace extends PDFColorSpace { + private PDFColorSpace base; + + public PatternSpace() { + super(null); + } + + /** + * Create a pattern space with the given color space as a base + */ + public PatternSpace(PDFColorSpace base) { + super(null); + + this.base = base; + } + + /** + * Get the base color space + */ + public PDFColorSpace getBase() { + return this.base; + } + + /** + * Get the number of components we want + */ + @Override public int getNumComponents() { + if (this.base == null) { + return 0; + } else { + return this.base.getNumComponents(); + } + } + + /** + * get the PDFPaint representing the color described by the + * given color components + * @param components the color components corresponding to the given + * colorspace + * @return a PDFPaint object representing the closest Color to the + * given components. + */ + @Override public PDFPaint getPaint(float[] components) { + throw new IllegalArgumentException("Pattern spaces require a pattern " + + "name!"); + } + + /** + * Get the paint representing a pattern, optionally with the given + * base paint. + * + * @param patternObj the pattern to render + * @param components the components of the base paint + */ + public PDFPaint getPaint(PDFObject patternObj, float[] components, + Map resources) + throws IOException + { + PDFPaint basePaint = null; + + if (getBase() != null) { + basePaint = getBase().getPaint(components); + } + + PDFPattern pattern = (PDFPattern) patternObj.getCache(); + if (pattern == null) { + pattern = PDFPattern.getPattern(patternObj, resources); + patternObj.setCache(pattern); + } + + return pattern.getPaint(basePaint); + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/YCCKColorSpace.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/YCCKColorSpace.java new file mode 100644 index 000000000..659214775 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/YCCKColorSpace.java @@ -0,0 +1,133 @@ +/* + * Copyright 2008 Pirion Systems Pty Ltd, 139 Warry St, + * Fortitude Valley, Queensland, Australia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package com.sun.pdfview.colorspace; + +import java.awt.color.ColorSpace; + +/** + * A ColorSpace for the YCCK color space. This color space converts to CMYK and then + * uses an existing CMYK color space to convert from CMYK to RGB. This allows embedded + * CMYK color profiles to be used with YCCK images. If no CMYK color space is + * provided then by default it uses a CMYKColorSpace. Only toRGB is supported. + * + * @author Ben Day + */ +public class YCCKColorSpace extends ColorSpace +{ + + private final ColorSpace cmykColorSpace; + + /** + * create a new YCCK color space: a ColorSpace with 4 components + */ + public YCCKColorSpace(ColorSpace existingCmykColorSpace) + { + super(TYPE_4CLR, 4); + cmykColorSpace = existingCmykColorSpace; + } + + public YCCKColorSpace() + { + this(new CMYKColorSpace()); + } + + /** + * Convert from CIEXYZ to RGB. NOT IMPLEMENTED + */ + @Override + public float[] fromCIEXYZ(float[] colorvalue) + { + throw new UnsupportedOperationException("Not yet implemented"); + } + + /** + * Convert from RGB to YCCK. NOT IMPLEMENTED + * + * @param rgbvalue the red, green, and blue values (0-1) + * @return the YCCK values (0-1) + */ + @Override + public float[] fromRGB(float[] rgbvalue) + { + throw new UnsupportedOperationException("Not yet implemented"); + } + + /** + * the number of components + */ + @Override + public int getNumComponents() + { + return 4; + } + + /** + * the name of this color space + */ + @Override + public String getName(int idx) + { + return "YCCK"; + } + + /** + * the type of this color space (TYPE_4CLR) + */ + @Override + public int getType() + { + return TYPE_4CLR; + } + + /** + * Convert from YCCK to CIEXYZ. NOT IMPLEMENTED + */ + @Override + public float[] toCIEXYZ(float[] colorvalue) + { + return cmykColorSpace.toCIEXYZ(toCmyk(colorvalue)); + } + + /** + * Convert from YCCK to RGB. + * + * @param colorvalue the YCCK values (0-1) + * @return the RGB values (0-1) + */ + @Override + public float[] toRGB(float[] colorvalue) + { + return cmykColorSpace.toRGB(toCmyk(colorvalue)); + } + + private float[] toCmyk(float[] colorvalue) { + float y = colorvalue[0], cb = colorvalue[1], cr = colorvalue[2], k = colorvalue[3]; + float[] cmyk = new float[4]; + float v; + v = (float) (1.0 - (y + 1.402 * (cr - 0.5))); + cmyk[0] = v < 0.0f ? 0.0f : (v > 1.0f ? 1.0f : v); + v = (float) (1.0 - (y - 0.34414 * (cb - 0.5) - 0.71414 * (cr - 0.5))); + cmyk[1] = v < 0.0f ? 0.0f : (v > 1.0f ? 1.0f : v); + v = (float) (1.0 - (y + 1.772 * (cb - 0.5))); + cmyk[2] = v < 0.0f ? 0.0f : (v > 1.0f ? 1.0f : v); + cmyk[3] = k; + return cmyk; + } +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/sGray.icc b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/sGray.icc new file mode 100644 index 0000000000000000000000000000000000000000..0ac8e07534bf2269ec629e50445b9f69826c2fca GIT binary patch literal 2464 zcmb_dXHb*r7Jk3)OD~ipgbtyGBE1EW5_%}otEgZ?@1Y}#BH{|HAR^KfK|}!sSC=Ad zK}4~zC@5e-H^?HOtc$CNikgk6O6Q9DJ5fetXQYbeP=E;2xUrEu5snq%bqN7}jv`zI0FIOql_TN+;Fyw{%a4nR z&0rWC8X7a$yp*j`4FBBpjHsk^1}B-D!cR@%M`lEcM8JP;d|Sh$yYeG*zoGwQeDm+S z+<$#Zk2W#>X9kh%06N+hz*Ye8rBWzdYZ3~-Gy{N4i)={aX7aPX@1wpoG#~(R zKm)Qs38(=rpa+bB1+WJ8z!|s$Zx8@N!Dhe(u^i{L7_0q%f%U;;b=0x$<&fo1R>tU(Zjg~$*Ul7*BZ4M-O;pbOAd=oT~vJ%VPSMd&Z+6O6zlm-Pg4wVK z8~|^EW8gG64=#fD!!>X-d>Zb7ufliW30MHXf>#iL5D_|}g6JVE#1ZjE!jNc$kL*B7 zkZPnE=|uXGVdOp{K$eh?C=7~;To5UI7M-qjkLvkdAlQK#BNhe7Iq(`K;WHMQkY)=j&XOQ=k+sN0* z&&VIdsABqJ95J3)fmpp*kJz}_YjM1|hB#Y%vv{6(wfK4QyW&d{cnM7jM~O&@9TN2t z7bK=6RwSvCMv~r=Ns?uf?UJ`77bsYYCdHY;qZCn&Q?5~FsR&h#>PY2McT-!a*Qs+f z42?XMXzj?gvf9C{+XoPLfzN&h6RD9x6RlHMoX zDLpQ|DkCprFB2tGBGV-^A@fO=A?qxgAbUWzSN5qKN=`@4S1w!bsN8kAC3%{>wLDk8 zME;!oV+B}2N5M~Fo5FF05rq{+B}G@oRK;4wYl=%sbR~PGc%>?(%SwyNRApP`IOQtk zE6Oh!QVcdDkx|1KVl1mDsJN+Qsx+yLs;sFpRRdKERl8K5su9#!YSC&{YJ+Oa>dNX~ z>iOy&>W?+>8Z3=ijl&wl8mpR2&0x*Fn!TC}Oc^GJnaAv4PHU01?6lIfnzbHiW3*Y? z3ED@r@9DrgW;(Gt^*VQTVO?|GINc+y)RmQq$iMDjGEU>(2`O(VU zD#PlW)t}aS)(O__)(h*I>!a4Ute>?}wTZN8vJu!aY$I%s*$V7b>>}-&?Vj7K+4JmM z?dRFr?0EKR_G<@22fjnM!>Xf|<95dZC&bCssl;j2nc^JiT<84EMb#z7rNd>})y#F9 z>wp{D&BN`0+Z0EU!{xMbmfbDfx4RE{kUac7>O7u%>Ui=!`@LWD=2BpwtV z)E2ZF>=axXEC?|O*&cEyR4z0wv@Z-B78KSRwzAQAr&n%Guhmb(!nPJD3ZK5lq z7h-H;4#q6T+QnAKF2y;<)y2JucZ+X~Urq2%IGG?!3{LDy!X-r{T}Y-RCnOK0D5d12 zjHT+P7N-i*tkMppE%QD2t?5wuru4oHn&^`n$<)f+lR1-Rn^m9nAv-Ahe2!#Ja?VJu zPVT>u@b3O1#iE@>vwK|kbQFsf^NXkUTJLTA0rf-N52O1`_SNqDTEZ*2U20fbUHZ9< zTXy?LqaSO26z-4SKU!{HezXEpkz6r(!0y1QO3BK+%GrZn2Yad*RV7vL4sAJftJ<`> z@i5_V=3zmNXH8$NdTmAR=epRsiF$|nt_FpMeGRKect^&M+8^y~RBSA5{B$ht*uy5* zrk-Za=IY~^<5|aFv;?&bpJ1J6Yn5v)ZT)gG`J~{K->IQCi?+6Qh4%6exFfS;@pSm< zduN=^^mXcWHg(avO3#9`nP*@A6!FvKIgfLL=UL}Ff7bZ9p_|%W(gXG6_AK|t_6qt! z`^GM~Ul{DS?(hCZ|Cf^&RW8i-XT)rz`&YAHyGPAOd+u7??Yn1r zuYYX)*yVA%@vHZp?%#O8d2nZ9!^GHR;N-)p@F~GV-ou4QiI3hq&U(D|Wal(`y5y 0) { + char c = (char) this.buf.get(); + + if (!PDFFile.isWhiteSpace(c)) { + return c; + } + } + + // EOF reached + return -1; + } + + /** + * decode the next five ASCII85 characters into up to four decoded + * bytes. Return false when finished, or true otherwise. + * + * @param baos the ByteArrayOutputStream to write output to, set to the + * correct position + * @return false when finished, or true otherwise. + */ + private boolean decode5(ByteArrayOutputStream baos) + throws PDFParseException { + // stream ends in ~> + int[] five = new int[5]; + int i; + for (i = 0; i < 5; i++) { + five[i] = nextChar(); + if (five[i] == '~') { + if (nextChar() == '>') { + break; + } else { + throw new PDFParseException("Bad character in ASCII85Decode: not ~>"); + } + } else if (five[i] >= '!' && five[i] <= 'u') { + five[i] -= '!'; + } else if (five[i] == 'z') { + if (i == 0) { + five[i] = 0; + i = 4; + } else { + throw new PDFParseException("Inappropriate 'z' in ASCII85Decode"); + } + } else { + throw new PDFParseException("Bad character in ASCII85Decode: " + five[i] + " (" + (char) five[i] + ")"); + } + } + + if (i > 0) { + i -= 1; + } + + int value = + five[0] * 85 * 85 * 85 * 85 + + five[1] * 85 * 85 * 85 + + five[2] * 85 * 85 + + five[3] * 85 + + five[4]; + + for (int j = 0; j < i; j++) { + int shift = 8 * (3 - j); + baos.write((byte) ((value >> shift) & 0xff)); + } + + return (i == 4); + } + + /** + * decode the bytes + * @return the decoded bytes + */ + private ByteBuffer decode() throws PDFParseException { + // start from the beginning of the data + this.buf.rewind(); + + // allocate the output buffer + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + // decode the bytes + while (decode5(baos)) { + } + + return ByteBuffer.wrap(baos.toByteArray()); + } + + /** + * decode an array of bytes in ASCII85 format. + *

    + * In ASCII85 format, every 5 characters represents 4 decoded + * bytes in base 85. The entire stream can contain whitespace, + * and ends in the characters '~>'. + * + * @param buf the encoded ASCII85 characters in a byte buffer + * @param params parameters to the decoder (ignored) + * @return the decoded bytes + */ + public static ByteBuffer decode(ByteBuffer buf, PDFObject params) + throws PDFParseException { + ASCII85Decode me = new ASCII85Decode(buf); + return me.decode(); + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/ASCIIHexDecode.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/ASCIIHexDecode.java new file mode 100644 index 000000000..b3afacd00 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/ASCIIHexDecode.java @@ -0,0 +1,126 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package com.sun.pdfview.decode; + +import com.sun.pdfview.PDFFile; +import com.sun.pdfview.PDFObject; +import com.sun.pdfview.PDFParseException; + +import java.io.ByteArrayOutputStream; +import java.nio.ByteBuffer; + +/** + * decode an array of hex nybbles into a byte array + * + * @author Mike Wessler + */ +public class ASCIIHexDecode { + private ByteBuffer buf; + + /** + * initialize the decoder with an array of bytes in ASCIIHex format + */ + private ASCIIHexDecode(ByteBuffer buf) { + this.buf = buf; + } + + /** + * get the next character from the input + * @return a number from 0-15, or -1 for the end character + */ + private int readHexDigit() throws PDFParseException { + // read until we hit a non-whitespace character or the + // end of the stream + while (this.buf.remaining() > 0) { + int c = this.buf.get(); + + // see if we found a useful character + if (!PDFFile.isWhiteSpace((char) c)) { + if (c >= '0' && c <= '9') { + c -= '0'; + } else if (c >= 'a' && c <= 'f') { + c -= 'a' - 10; + } else if (c >= 'A' && c <= 'F') { + c -= 'A' - 10; + } else if (c == '>') { + c = -1; + } else { + // unknown character + throw new PDFParseException("Bad character " + c + + "in ASCIIHex decode"); + } + + // return the useful character + return c; + } + } + + // end of stream reached + throw new PDFParseException("Short stream in ASCIIHex decode"); + } + + /** + * decode the array + * @return the decoded bytes + */ + private ByteBuffer decode() throws PDFParseException { + // start at the beginning of the buffer + buf.rewind(); + + // allocate the output buffer + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + while (true) { + int first = readHexDigit(); + if (first == -1) { + break; + } + int second = readHexDigit(); + + if (second == -1) { + baos.write((byte) (first << 4)); + break; + } else { + baos.write((byte) ((first << 4) + second)); + } + } + + return ByteBuffer.wrap(baos.toByteArray()); + } + + /** + * decode an array of bytes in ASCIIHex format. + *

    + * ASCIIHex format consists of a sequence of Hexidecimal + * digits, with possible whitespace, ending with the + * '>' character. + * + * @param buf the encoded ASCII85 characters in a byte + * buffer + * @param params parameters to the decoder (ignored) + * @return the decoded bytes + */ + public static ByteBuffer decode(ByteBuffer buf, PDFObject params) + throws PDFParseException + { + ASCIIHexDecode me = new ASCIIHexDecode(buf); + return me.decode(); + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/CCITTCodes b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/CCITTCodes new file mode 100644 index 000000000..10c1c419c --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/CCITTCodes @@ -0,0 +1,236 @@ + +# $Id: CCITTCodes,v 1.2 2007/12/20 18:33:33 rbair Exp $ +# +# Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, +# Santa Clara, California 95054, U.S.A. All rights reserved. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +# WHITE CODES +00110101 0 +000111 1 +0111 2 +1000 3 +1011 4 +1100 5 +1110 6 +1111 7 +10011 8 +10100 9 +00111 10 +01000 11 +001000 12 +000011 13 +110100 14 +110101 15 +101010 16 +101011 17 +0100111 18 +0001100 19 +0001000 20 +0010111 21 +0000011 22 +0000100 23 +0101000 24 +0101011 25 +0010011 26 +0100100 27 +0011000 28 +00000010 29 +00000011 30 +00011010 31 +00011011 32 +00010010 33 +00010011 34 +00010100 35 +00010101 36 +00010110 37 +00010111 38 +00101000 39 +00101001 40 +00101010 41 +00101011 42 +00101100 43 +00101101 44 +00000100 45 +00000101 46 +00001010 47 +00001011 48 +01010010 49 +01010011 50 +01010100 51 +01010101 52 +00100100 53 +00100101 54 +01011000 55 +01011001 56 +01011010 57 +01011011 58 +01001010 59 +01001011 60 +00110010 61 +00110011 62 +00110100 63 +11011 64 +10010 128 +010111 192 +0110111 256 +00110110 320 +00110111 384 +01100100 448 +01100101 512 +01101000 576 +01100111 640 +011001100 704 +011001101 768 +011010010 832 +011010011 896 +011010100 960 +011010101 1024 +011010110 1088 +011010111 1152 +011011000 1216 +011011001 1280 +011011010 1344 +011011011 1408 +010011000 1472 +010011001 1536 +010011010 1600 +011000 1664 +010011011 1728 +00000001000 1792 +00000001100 1856 +00000001101 1920 +000000010010 1984 +000000010011 2048 +000000010100 2112 +000000010101 2176 +000000010110 2240 +000000010111 2304 +000000011100 2368 +000000011101 2432 +000000011110 2496 +000000011111 2560 +000000001111 -2 +0000000000 -1 + +# BLACK CODES +0000110111 0 +010 1 +11 2 +10 3 +011 4 +0011 5 +0010 6 +00011 7 +000101 8 +000100 9 +0000100 10 +0000101 11 +0000111 12 +00000100 13 +00000111 14 +000011000 15 +0000010111 16 +0000011000 17 +0000001000 18 +00001100111 19 +00001101000 20 +00001101100 21 +00000110111 22 +00000101000 23 +00000010111 24 +00000011000 25 +000011001010 26 +000011001011 27 +000011001100 28 +000011001101 29 +000001101000 30 +000001101001 31 +000001101010 32 +000001101011 33 +000011010010 34 +000011010011 35 +000011010100 36 +000011010101 37 +000011010110 38 +000011010111 39 +000001101100 40 +000001101101 41 +000011011010 42 +000011011011 43 +000001010100 44 +000001010101 45 +000001010110 46 +000001010111 47 +000001100100 48 +000001100101 49 +000001010010 50 +000001010011 51 +000000100100 52 +000000110111 53 +000000111000 54 +000000100111 55 +000000101000 56 +000001011000 57 +000001011001 58 +000000101011 59 +000000101100 60 +000001011010 61 +000001100110 62 +000001100111 63 +0000001111 64 +000011001000 128 +000011001001 192 +000001011011 256 +000000110011 320 +000000110100 384 +000000110101 448 +0000001101100 512 +0000001101101 576 +0000001001010 640 +0000001001011 704 +0000001001100 768 +0000001001101 832 +0000001110010 896 +0000001110011 960 +0000001110100 1024 +0000001110101 1088 +0000001110110 1152 +0000001110111 1216 +0000001010010 1280 +0000001010011 1344 +0000001010100 1408 +0000001010101 1472 +0000001011010 1536 +0000001011011 1600 +0000001100100 1664 +0000001100101 1728 +00000001000 1792 +00000001100 1856 +00000001101 1920 +000000010010 1984 +000000010011 2048 +000000010100 2112 +000000010101 2176 +000000010110 2240 +000000010111 2304 +000000011100 2368 +000000011101 2432 +000000011110 2496 +000000011111 2560 +000000001111 -2 +00000000000 -1 diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/CCITTFaxDecode.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/CCITTFaxDecode.java new file mode 100644 index 000000000..d6748a803 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/CCITTFaxDecode.java @@ -0,0 +1,117 @@ +package com.sun.pdfview.decode; + +import java.io.IOException; +import java.nio.ByteBuffer; + +import com.sun.pdfview.PDFDebugger; +import com.sun.pdfview.PDFObject; + +public class CCITTFaxDecode { + + + + protected static ByteBuffer decode(PDFObject dict, ByteBuffer buf, + PDFObject params) throws IOException { + + byte[] bytes = new byte[buf.remaining()]; + buf.get(bytes, 0, bytes.length); + return ByteBuffer.wrap(decode(dict, bytes)); + } + + + protected static byte[] decode(PDFObject dict, byte[] source) throws IOException { + int width = 1728; + PDFObject widthDef = dict.getDictRef("Width"); + if (widthDef == null) { + widthDef = dict.getDictRef("W"); + } + if (widthDef != null) { + width = widthDef.getIntValue(); + } + int height = 0; + PDFObject heightDef = dict.getDictRef("Height"); + if (heightDef == null) { + heightDef = dict.getDictRef("H"); + } + if (heightDef != null) { + height = heightDef.getIntValue(); + } + + // + int columns = getOptionFieldInt(dict, "Columns", width); + int rows = getOptionFieldInt(dict, "Rows", height); + int k = getOptionFieldInt(dict, "K", 0); + int size = rows * ((columns + 7) >> 3); + byte[] destination = new byte[size]; + + boolean align = getOptionFieldBoolean(dict, "EncodedByteAlign", false); + + CCITTFaxDecoder decoder = new CCITTFaxDecoder(1, columns, rows); + decoder.setAlign(align); + try { + if (k == 0) { + decoder.decodeT41D(destination, source, 0, rows); + } else if (k > 0) { + decoder.decodeT42D(destination, source, 0, rows); + } else if (k < 0) { + decoder.decodeT6(destination, source, 0, rows); + } + }catch (Exception e) { + PDFDebugger.debug("Error decoding CCITTFax image k: "+ k); + // some PDf producer don't correctly assign a k value for the deocde, + // as result we can try one more time using the T6. + //first, reset buffer + destination = new byte[size]; + try { + decoder.decodeT6(destination, source, 0, rows); + }catch (Exception e1) { + // do nothing + PDFDebugger.debug("Error decoding CCITTFax image"); + } + } + if (!getOptionFieldBoolean(dict, "BlackIs1", false)) { + for (int i = 0; i < destination.length; i++) { + // bitwise not + destination[i] = (byte) ~destination[i]; + } + } + + return destination; + } + + public static int getOptionFieldInt(PDFObject dict, String name, int defaultValue) throws IOException { + + PDFObject dictParams = getDecodeParams(dict); + + if (dictParams == null) { + return defaultValue; + } + PDFObject value = dictParams.getDictRef(name); + if (value == null) { + return defaultValue; + } + return value.getIntValue(); + } + + public static boolean getOptionFieldBoolean(PDFObject dict, String name, boolean defaultValue) throws IOException { + + PDFObject dictParams = getDecodeParams(dict); + + if (dictParams == null) { + return defaultValue; + } + PDFObject value = dictParams.getDictRef(name); + if (value == null) { + return defaultValue; + } + return value.getBooleanValue(); + } + + private static PDFObject getDecodeParams(PDFObject dict) throws IOException { + PDFObject decdParams = dict.getDictRef("DecodeParms"); + if (decdParams != null && decdParams.getType() == PDFObject.ARRAY) { + return decdParams.getArray()[0]; + } + return decdParams; + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/CCITTFaxDecoder.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/CCITTFaxDecoder.java new file mode 100644 index 000000000..0cbfdc0c1 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/CCITTFaxDecoder.java @@ -0,0 +1,1581 @@ +/* + * Based on the SUN code (see license beyond) changes are made to handle CCITTFax encoded + * data in a PDF image. This may or may not apply to real world CCITT documents. + * + * Copyright (c) 2007, intarsys consulting GmbH + * + * 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 of intarsys 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. + */ +/* + * Copyright (c) 2001 Sun Microsystems, Inc. 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. + * + * -Redistribution in binary form must reproduct 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 of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY + * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR + * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING + * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS + * LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, + * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER + * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF + * OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that Software is not designed,licensed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ +package com.sun.pdfview.decode; + +public class CCITTFaxDecoder { + static 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 + }; + + static 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. + static byte[] flipTable = { 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 + static 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 + static short[] additionalMakeup = { 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 + static short[] initBlack = { + // 0 - 7 + 3226, 6412, 200, 168, 38, 38, 134, 134, // 8 - 15 + 100, 100, 100, 100, 68, 68, 68, 68 }; + + // + static short[] twoBitBlack = { 292, 260, 226, 226 }; // 0 - 3 + + // Main black run table, using the last 9 bits of possible 13 bit code + static 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, }; + + static byte[] twoDCodes = { + // 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, }; + + private int bitPointer; + + private int bytePointer; + + private byte[] data; + + private int w; + + private boolean align = false; + + 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 boolean fillBits = false; + + /** + * @param fillOrder + * The fill order of the compressed data bytes. + * @param w + * @param h + */ + public CCITTFaxDecoder(int fillOrder, int w, int h) { + this.fillOrder = fillOrder; + // Some of the decode methods assume prevChangingElms + // and currChaningElems are at least of length 2. + if(w<2) { + w=2; + } + + this.w = w; + + this.bitPointer = 0; + this.bytePointer = 0; + this.prevChangingElems = new int[w]; + this.currChangingElems = new int[w]; + } + + private boolean align() { + if (this.align && this.bitPointer != 0) { + this.bytePointer++; + this.bitPointer = 0; + return true; + } + return false; + } + + protected boolean consumeEOL() { + // Get the next 12 bits. + int next12Bits = nextNBits(12); + if (next12Bits == 1) { + // EOL found & consumed + return true; + } + // no EOL - unread and return + updatePointer(12); + return false; + } + + // Returns run length + private int decodeBlackCodeWord() { + int current; + int entry; + int bits; + int isT; + int code = -1; + int runLength = 0; + boolean isWhite = false; + + while (!isWhite) { + current = nextLesserThan8Bits(4); + entry = initBlack[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 = additionalMakeup[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 RuntimeException( + "EOL code word encountered in Black run."); //$NON-NLS-1$ + } else { + runLength += code; + updatePointer(9 - bits); + if (isT == 0) { + isWhite = true; + } + } + } else if (code == 200) { + // Is a Terminating code + current = nextLesserThan8Bits(2); + entry = twoBitBlack[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; + } + + protected void decodeNextScanline(byte[] buffer, int lineOffset, + int bitOffset) { + int bits = 0; + int code = 0; + int isT = 0; + int current; + int entry; + int twoBits; + boolean isWhite = true; + + // Initialize starting of the changing elements array + this.changingElemSize = 0; + + // While scanline not complete + while (bitOffset < this.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 = additionalMakeup[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 RuntimeException("Invalid code encountered."); + } else if (bits == 15) { + // EOL recover + // move bits back... + updatePointer(10); + return; + } else { + // 11 bits - 0000 0111 1111 1111 = 0x07ff + code = (entry >>> 5) & 0x07ff; + bitOffset += code; + + updatePointer(10 - bits); + if (isT == 0) { + isWhite = false; + this.currChangingElems[this.changingElemSize++] = bitOffset; + } + } + } + + // Check whether this run completed one width, if so + // advance to next byte boundary for compression = 2. + if (bitOffset == this.w) { + align(); + break; + } + + while (isWhite == false) { + // Black run + current = nextLesserThan8Bits(4); + entry = initBlack[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 = additionalMakeup[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 recover + // unread bits ??? + updatePointer(9); + return; + } else { + setToBlack(buffer, lineOffset, bitOffset, code); + bitOffset += code; + + updatePointer(9 - bits); + if (isT == 0) { + isWhite = true; + this.currChangingElems[this.changingElemSize++] = bitOffset; + } + } + } else if (code == 200) { + // Is a Terminating code + current = nextLesserThan8Bits(2); + entry = twoBitBlack[current]; + code = (entry >>> 5) & 0x07ff; + bits = (entry >>> 1) & 0x0f; + + setToBlack(buffer, lineOffset, bitOffset, code); + bitOffset += code; + + updatePointer(2 - bits); + isWhite = true; + this.currChangingElems[this.changingElemSize++] = bitOffset; + } else { + // Is a Terminating code + setToBlack(buffer, lineOffset, bitOffset, code); + bitOffset += code; + + updatePointer(4 - bits); + isWhite = true; + this.currChangingElems[this.changingElemSize++] = bitOffset; + } + } + + // Check whether this run completed one width + if (bitOffset == this.w) { + align(); + break; + } + } + + this.currChangingElems[this.changingElemSize++] = bitOffset; + } + + // One-dimensional decoding methods + public void decodeT41D(byte[] buffer, byte[] compData, int startX, + int height) { + this.data = compData; + int scanlineStride = (this.w + 7) / 8; + this.bitPointer = 0; + this.bytePointer = 0; + + int lineOffset = 0; + for (int i = 0; i < height; i++) { + consumeEOL(); + decodeNextScanline(buffer, lineOffset, startX); + lineOffset += scanlineStride; + } + } + + // Two-dimensional decoding methods + public void decodeT42D(byte[] buffer, byte[] compData, int startX, + int height) { + this.data = compData; + int scanlineStride = (this.w + 7) / 8; + this.bitPointer = 0; + this.bytePointer = 0; + + int a0; + int a1; + int b1; + int b2; + int[] b = new int[2]; + int entry; + int code; + int bits; + boolean isWhite; + int currIndex = 0; + int[] temp; + + // The data must start with an EOL code + if (readEOL(true) != 1) { + throw new RuntimeException("First scanline must be 1D encoded."); //$NON-NLS-1$ + } + + 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(false) == 0) { + // 2D encoded scanline follows + + // Initialize previous scanlines changing elements, and + // initialize current scanline's changing elements array + temp = this.prevChangingElems; + this.prevChangingElems = this.currChangingElems; + this.currChangingElems = temp; + currIndex = 0; + + // a0 has to be set just before the start of this scanline. + a0 = -1; + isWhite = true; + bitOffset = startX; + + this.lastChangingElement = 0; + + while (bitOffset < this.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 = (twoDCodes[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; + this.currChangingElems[currIndex++] = bitOffset; + + number = decodeBlackCodeWord(); + setToBlack(buffer, lineOffset, bitOffset, number); + bitOffset += number; + this.currChangingElems[currIndex++] = bitOffset; + } else { + number = decodeBlackCodeWord(); + setToBlack(buffer, lineOffset, bitOffset, number); + bitOffset += number; + this.currChangingElems[currIndex++] = bitOffset; + + number = decodeWhiteCodeWord(); + bitOffset += number; + this.currChangingElems[currIndex++] = bitOffset; + } + + a0 = bitOffset; + } else if (code <= 8) { + // Vertical + a1 = b1 + (code - 5); + + this.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 RuntimeException( + "Invalid code encountered while decoding 2D group 3 compressed data."); //$NON-NLS-1$ + } + } + + // Add the changing element beyond the current scanline for the + // other color too + this.currChangingElems[currIndex++] = bitOffset; + this.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) { + this.data = compData; + int scanlineStride = (this.w + 7) / 8; + this.bitPointer = 0; + this.bytePointer = 0; + + int a0; + int a1; + int b1; + int b2; + int entry; + int code; + int 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 + + // Local cached reference + int[] cce = this.currChangingElems; + + // Assume invisible preceding row of all white pixels and insert + // both black and white changing elements beyond the end of this + // imaginary scanline. + this.changingElemSize = 0; + cce[this.changingElemSize++] = this.w; + cce[this.changingElemSize++] = this.w; + + int lineOffset = 0; + int bitOffset; + + for (int lines = 0; lines < height; lines++) { + // 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 = this.prevChangingElems; + this.prevChangingElems = this.currChangingElems; + cce = this.currChangingElems = temp; + currIndex = 0; + + // Start decoding the scanline at startX in the raster + bitOffset = startX; + + // Reset search start position for getNextChangingElement + this.lastChangingElement = 0; + + // Till one whole scanline is decoded + while (bitOffset < this.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 = (twoDCodes[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) { + if (b2 > this.w) { + b2 = this.w; + } + 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(); + if (number > this.w - bitOffset) { + number = this.w - bitOffset; + } + setToBlack(buffer, lineOffset, bitOffset, number); + bitOffset += number; + cce[currIndex++] = bitOffset; + } else { + // First a black run and then a white run follows + number = decodeBlackCodeWord(); + if (number > this.w - bitOffset) { + number = this.w - bitOffset; + } + 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) { + if (a1 > this.w) { + a1 = this.w; + } + setToBlack(buffer, lineOffset, bitOffset, a1 + - bitOffset); + } + bitOffset = a0 = a1; + isWhite = !isWhite; + + updatePointer(7 - bits); + } else if (code == 11) { + if (nextLesserThan8Bits(3) != 7) { + throw new RuntimeException( + "Invalid code encountered while decoding 2D group 4 compressed data."); //$NON-NLS-1$ + } + + 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 { + // break line - seems to be a common failure + // unread + updatePointer(7 - bits); + // and mark lines as complete + bitOffset = this.w; + // throw new RuntimeException( + // "Invalid code encountered while decoding 2D group 4 + // compressed data."); //$NON-NLS-1$ + } + } + + align(); + + // Add the changing element beyond the current scanline for the + // other color too + // make sure that the index does not exceed the bounds of the array + if (currIndex < this.w) { + cce[currIndex++] = bitOffset; + } + + // Number of changing elements in this scanline. + this.changingElemSize = currIndex; + + lineOffset += scanlineStride; + } + } + + // Returns run length + private int decodeWhiteCodeWord() { + int current; + int entry; + int bits; + int isT; + int twoBits; + int 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 = additionalMakeup[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 RuntimeException("Invalid code encountered."); //$NON-NLS-1$ + } else if (bits == 15) { // EOL + throw new RuntimeException( + "EOL code word encountered in White run."); //$NON-NLS-1$ + } else { + // 11 bits - 0000 0111 1111 1111 = 0x07ff + code = (entry >>> 5) & 0x07ff; + runLength += code; + updatePointer(10 - bits); + if (isT == 0) { + isWhite = false; + } + } + } + + return runLength; + } + + 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 = (this.lastChangingElement > 0) ? (this.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) { + this.lastChangingElement = i; + ret[0] = temp; + break; + } + } + + if ((i + 1) < ces) { + ret[1] = pce[i + 1]; + } + } + + public boolean isAlign() { + return this.align; + } + + public boolean isFillBits() { + return this.fillBits; + } + + private int nextLesserThan8Bits(int bitsToGet) { + byte b; + byte next; + int l = this.data.length - 1; + int bp = this.bytePointer; + + if (this.fillOrder == 1) { + b = this.data[bp]; + if (bp == l) { + next = 0x00; + } else { + next = this.data[bp + 1]; + } + } else if (this.fillOrder == 2) { + b = flipTable[this.data[bp] & 0xff]; + if (bp == l) { + next = 0x00; + } else { + next = flipTable[this.data[bp + 1] & 0xff]; + } + } else { + throw new RuntimeException("tag must be either 1 or 2."); //$NON-NLS-1$ + } + + int bitsLeft = 8 - this.bitPointer; + int bitsFromNextByte = bitsToGet - bitsLeft; + + int shift = bitsLeft - bitsToGet; + int i1; + int i2; + if (shift >= 0) { + i1 = (b & table1[bitsLeft]) >>> shift; + this.bitPointer += bitsToGet; + if (this.bitPointer == 8) { + this.bitPointer = 0; + this.bytePointer++; + } + } else { + i1 = (b & table1[bitsLeft]) << (-shift); + i2 = (next & table2[bitsFromNextByte]) >>> (8 - bitsFromNextByte); + + i1 |= i2; + this.bytePointer++; + this.bitPointer = bitsFromNextByte; + } + + return i1; + } + + private int nextNBits(int bitsToGet) { + byte b; + byte next; + byte next2next; + int l = this.data.length - 1; + int bp = this.bytePointer; + + if (this.fillOrder == 1) { + b = this.data[bp]; + + if (bp == l) { + next = 0x00; + next2next = 0x00; + } else if ((bp + 1) == l) { + next = this.data[bp + 1]; + next2next = 0x00; + } else { + next = this.data[bp + 1]; + next2next = this.data[bp + 2]; + } + } else if (this.fillOrder == 2) { + b = flipTable[this.data[bp] & 0xff]; + + if (bp == l) { + next = 0x00; + next2next = 0x00; + } else if ((bp + 1) == l) { + next = flipTable[this.data[bp + 1] & 0xff]; + next2next = 0x00; + } else { + next = flipTable[this.data[bp + 1] & 0xff]; + next2next = flipTable[this.data[bp + 2] & 0xff]; + } + } else { + throw new RuntimeException("tag must be either 1 or 2."); //$NON-NLS-1$ + } + + int bitsLeft = 8 - this.bitPointer; + int bitsFromNextByte = bitsToGet - bitsLeft; + int bitsFromNext2NextByte = 0; + if (bitsFromNextByte > 8) { + bitsFromNext2NextByte = bitsFromNextByte - 8; + bitsFromNextByte = 8; + } + + this.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; + this.bytePointer++; + this.bitPointer = bitsFromNext2NextByte; + } else { + if (bitsFromNextByte == 8) { + this.bitPointer = 0; + this.bytePointer++; + } else { + this.bitPointer = bitsFromNextByte; + } + } + + int i = i1 | i2; + return i; + } + + private int readEOL(boolean isFirstEOL) { + // Seek to the next EOL. + if (!seekEOL()) { + throw new RuntimeException("EOL not found"); + } + + if (!this.fillBits) { + int next12Bits = nextNBits(12); + if (isFirstEOL && (next12Bits == 0)) { + // Might have the case of EOL padding being used even + // though it was not flagged. + // This was observed to be the case in TIFFs produced + // by a well known vendor who shall remain nameless. + if (nextNBits(4) == 1) { + // EOL must be padded: reset the fillBits flag. + this.fillBits = true; + return 1; + } + } + if (next12Bits != 1) { + throw new RuntimeException( + "Scanline must begin with EOL code word."); //$NON-NLS-1$ + } + } else { + // 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 - this.bitPointer; + + if (nextNBits(bitsLeft) != 0) { + throw new RuntimeException( + "All fill bits preceding EOL code must be 0."); //$NON-NLS-1$ + } + + // 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 RuntimeException( + "All fill bits preceding EOL code must be 0."); //$NON-NLS-1$ + } + } + + // + // Some encoders under Group 3 Fax compression 1D writes TIFF + // files without the fill bits, but say otherwise. + // Need to check for this here. + // + int next8 = nextNBits(8); + + if (isFirstEOL && (next8 & 0xf0) == 0x10) { + // + // Fill bits are not actually used despite what the flag + // says. So switch fillBits off and then rewind so that + // only 12 bits have effectively been read. + // + this.fillBits = false; + updatePointer(4); + } else { + // + // This is the normal case. + // 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. + // + while (next8 != 1) { + // If not all zeros + if (next8 != 0) { + throw new RuntimeException("0 bits expected before EOL"); + } + next8 = nextNBits(8); + } + } + } + // The next one bit signifies 1D/2D encoding of next line. + return nextLesserThan8Bits(1); + } + + // Seeks to the next EOL in the compressed bitstream. + // Returns 'true' if and only if an EOL is found; if 'false' + // is returned it may be inferred that the EOF was reached first. + private boolean seekEOL() { + // Set maximum and current bit index into the compressed data. + int bitIndexMax = this.data.length * 8 - 1; + int bitIndex = this.bytePointer * 8 + this.bitPointer; + + // Loop while at least 12 bits are available. + while (bitIndex <= bitIndexMax - 12) { + // Get the next 12 bits. + int next12Bits = nextNBits(12); + bitIndex += 12; + + // Loop while the 12 bits are not unity, i.e., while the EOL + // has not been reached, and there is at least one bit left. + while (next12Bits != 1 && bitIndex < bitIndexMax) { + next12Bits = ((next12Bits & 0x000007ff) << 1) + | (nextLesserThan8Bits(1) & 0x00000001); + bitIndex++; + } + + // If EOL reached, rewind the pointers and return 'true'. + if (next12Bits == 1) { + updatePointer(12); + return true; + } + } + + // EOL not found: return 'false'. + return false; + } + + public void setAlign(boolean align) { + this.align = align; + } + + public void setFillBits(boolean fillBits) { + this.fillBits = fillBits; + } + + 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; + } + } + + // Move pointer backwards by given amount of bits + private void updatePointer(int bitsToMoveBack) { + if (bitsToMoveBack > 8) { + this.bytePointer -= bitsToMoveBack / 8; + bitsToMoveBack %= 8; + } + + int i = this.bitPointer - bitsToMoveBack; + + if (i < 0) { + this.bytePointer--; + this.bitPointer = 8 + i; + } else { + this.bitPointer = i; + } + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/DCTDecode.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/DCTDecode.java new file mode 100644 index 000000000..ca56b9372 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/DCTDecode.java @@ -0,0 +1,128 @@ +package com.sun.pdfview.decode; + +import java.awt.Image; +import java.awt.Toolkit; +import java.awt.image.BufferedImage; +import java.awt.image.ImageObserver; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.nio.ByteBuffer; + +import javax.imageio.ImageIO; +import javax.swing.ImageIcon; + +import com.sun.pdfview.PDFObject; +import com.sun.pdfview.PDFParseException; + +/** + * Decode a DCT encoded array into a byte array. This class uses Java's + * built-in JPEG image class to do the decoding. + * + * @author Mike Wessler + */ +public class DCTDecode { + + /** + * Decode an array of bytes in DCT format. + *

    + * DCT is the format used by JPEG images, so this class simply + * loads the DCT-format bytes as an image, then reads the bytes out + * of the image to create the array. Unfortunately, their most + * likely use is to get turned BACK into an image, so this isn't + * terribly efficient... but is general... don't hit, please. + *

    + * The DCT-encoded stream may have 1, 3, or 4 samples per pixel, depending + * on the colorspace of the image. In decoding, we look for the colorspace + * in the stream object's dictionary to decide how to decode this image. + * If no colorspace is present, we guess 3 samples per pixel. + * + * @param dict the stream dictionary + * @param buf the DCT-encoded buffer + * @param params the parameters to the decoder (ignored) + * @return the decoded buffer + * @throws PDFParseException + */ + protected static ByteBuffer decode(PDFObject dict, ByteBuffer buf, PDFObject params) throws PDFParseException { + BufferedImage bimg = loadImageData(buf); + byte[] output = ImageDataDecoder.decodeImageData(bimg); + return ByteBuffer.wrap(output); + } + + /** + * Load image data from the buffer. + * + * @param buf the buffer containing the image data + * @return a BufferedImage representing the image + * @throws PDFParseException if an error occurs during image loading + */ + private static BufferedImage loadImageData(ByteBuffer buf) throws PDFParseException { + buf.rewind(); + byte[] input = new byte[buf.remaining()]; + buf.get(input); + BufferedImage bimg; + try (ByteArrayInputStream bais = new ByteArrayInputStream(input)) { + try { + bimg = ImageIO.read(bais); + if (bimg == null) { + throw new PDFParseException("DCTDecode failed: ImageIO.read returned null"); + } + } catch (IOException ex) { + // If there's an issue reading the image, attempt to load it another way + Image img = Toolkit.getDefaultToolkit().createImage(input); + // Wait until the image is fully loaded + ImageIcon imageIcon = new ImageIcon(img); + // Copy to buffered image + bimg = new BufferedImage(imageIcon.getIconWidth(), imageIcon.getIconHeight(), BufferedImage.TYPE_INT_RGB); + bimg.getGraphics().drawImage(img, 0, 0, null); + } + } catch (Exception ex) { + PDFParseException ex2 = new PDFParseException("DCTDecode failed"); + ex2.initCause(ex); + throw ex2; + } + + return bimg; + } +} + +/** + * Image tracker. This class tracks the status of an image loading operation. + */ +class MyTracker implements ImageObserver { + boolean done = false; + + /** + * Create a new MyTracker that watches this image. The image will start loading immediately. + */ + public MyTracker(Image img) { + img.getWidth(this); + } + + /** + * More information has come in about the image. + */ + @Override + public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height) { + if ((infoflags & (ALLBITS | ERROR | ABORT)) != 0) { + synchronized (this) { + this.done = true; + notifyAll(); + } + return false; + } + return true; + } + + /** + * Wait until the image is done, then return. + */ + public synchronized void waitForAll() { + if (!this.done) { + try { + wait(); + } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); + } + } + } +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/FlateDecode.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/FlateDecode.java new file mode 100644 index 000000000..29354a101 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/FlateDecode.java @@ -0,0 +1,96 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.sun.pdfview.decode; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.zip.DataFormatException; +import java.util.zip.Inflater; + +import com.sun.pdfview.PDFObject; +import com.sun.pdfview.PDFParseException; + +/** + * decode a deFlated byte array + * @author Mike Wessler + */ +public class FlateDecode { + + /** + * decode a byte buffer in Flate format. + *

    + * Flate is a built-in Java algorithm. It's part of the java.util.zip + * package. + * + * @param buf the deflated input buffer + * @param params parameters to the decoder (unused) + * @return the decoded (inflated) bytes + */ + public static ByteBuffer decode(PDFObject dict, ByteBuffer buf, + PDFObject params) throws IOException { + Inflater inf = new Inflater(false); + + int bufSize = buf.remaining(); + + // copy the data, since the array() method is not supported + // on raf-based ByteBuffers + byte[] data = new byte[bufSize]; + buf.get(data); + + // set the input to the inflater + inf.setInput(data); + + // output to a byte-array output stream, since we don't + // know how big the output will be + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + byte[] decomp = new byte[bufSize]; + int read = 0; + + try { + while (!inf.finished()) { + read = inf.inflate(decomp); + if (read <= 0) { + if (inf.needsDictionary()) { + throw new PDFParseException("Don't know how to ask for a dictionary in FlateDecode"); + } else { + // just return the data which is already read + break; + } + } + baos.write(decomp, 0, read); + } + } catch (DataFormatException dfe) { + throw new PDFParseException("Data format exception:" + dfe.getMessage()); + } + + // return the output as a byte buffer + ByteBuffer outBytes = ByteBuffer.wrap(baos.toByteArray()); + + // undo a predictor algorithm, if any was used + if (params != null && params.getDictionary().containsKey("Predictor")) { + Predictor predictor = Predictor.getPredictor(params); + if (predictor != null) { + outBytes = predictor.unpredict(outBytes); + } + } + + return outBytes; + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/ImageDataDecoder.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/ImageDataDecoder.java new file mode 100644 index 000000000..f34b27483 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/ImageDataDecoder.java @@ -0,0 +1,80 @@ +package com.sun.pdfview.decode; + +import java.awt.Graphics; +import java.awt.image.BufferedImage; +import java.awt.image.DataBufferByte; +import java.awt.image.DataBufferInt; + +/***************************************************************************** + * Decode image data to a usable color space. + * + * @since 25.03.2011 + ****************************************************************************/ + +public class ImageDataDecoder { + + /************************************************************************* + * @param bimg + * @return + ************************************************************************/ + + static byte[] decodeImageData(BufferedImage bimg) { + byte[] output = null; + + int type = bimg.getType(); + + if (type == BufferedImage.TYPE_INT_RGB) { + // read back the data + DataBufferInt db = (DataBufferInt) bimg.getData() + .getDataBuffer(); + int[] data = db.getData(); + + output = new byte[data.length * 3]; + for (int i = 0, offset = 0; i < data.length; i++, offset += 3) { + output[offset] = (byte) (data[i] >> 16); + output[offset + 1] = (byte) (data[i] >> 8); + output[offset + 2] = (byte) (data[i]); + } + } else if (type == BufferedImage.TYPE_BYTE_GRAY) { + DataBufferByte db = (DataBufferByte) bimg.getData() + .getDataBuffer(); + output = db.getData(); + } else if (type == BufferedImage.TYPE_INT_ARGB) { + // read back the data + DataBufferInt db = (DataBufferInt) bimg.getData() + .getDataBuffer(); + int[] data = db.getData(); + + output = new byte[data.length * 4]; + for (int i = 0, offset = 0; i < data.length; i++, offset += 4) { + output[offset] = (byte) (data[i] >> 24); + output[offset + 1] = (byte) (data[i] >> 16); + output[offset + 2] = (byte) (data[i] >> 8); + output[offset + 3] = (byte) (data[i]); + } + } else { + // The raster is in some other format. + // We have to convert it into TYPE_INT_RGB before we can use it. + BufferedImage tmp = new BufferedImage(bimg.getWidth(), + bimg.getHeight(), BufferedImage.TYPE_INT_RGB); + Graphics g = tmp.createGraphics(); + g.drawImage(bimg, 0, 0, null); + g.dispose(); + // read back the data + DataBufferInt db = (DataBufferInt) tmp.getData() + .getDataBuffer(); + int[] data = db.getData(); + + output = new byte[data.length * 3]; + for (int i = 0, offset = 0; i < data.length; i++, offset += 3) { + output[offset] = (byte) (data[i] >> 16); + output[offset + 1] = (byte) (data[i] >> 8); + output[offset + 2] = (byte) (data[i]); + } + tmp.flush(); + } + return output; + } + + +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/JPXDecode.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/JPXDecode.java new file mode 100644 index 000000000..7750dcec9 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/JPXDecode.java @@ -0,0 +1,86 @@ +/* Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package com.sun.pdfview.decode; + +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.Iterator; + +import javax.imageio.ImageIO; +import javax.imageio.ImageReader; +import javax.imageio.stream.MemoryCacheImageInputStream; + +import com.sun.pdfview.PDFObject; +import com.sun.pdfview.PDFParseException; + +/** + * decode a JPX encoded imagestream into a byte array. This class uses Java's + * image_io JPEG2000 reader to do the decoding. + * + * @author Bernd Rosstauscher + */ + +public class JPXDecode { + + /************************************************************************* + * @param dict + * @param buf + * @param params + * @return + * @throws PDFParseException + ************************************************************************/ + + protected static ByteBuffer decode(PDFObject dict, ByteBuffer buf, PDFObject params) throws PDFParseException { + BufferedImage bimg = loadImageData(buf); + byte[] output = ImageDataDecoder.decodeImageData(bimg); + return ByteBuffer.wrap(output); + } + + /************************************************************************* + * @param buf + * @return + * @throws PDFParseException + * @throws IOException + ************************************************************************/ + + private static BufferedImage loadImageData(ByteBuffer buf) throws PDFParseException { + ImageReader reader = null; + try { + byte[] input = new byte[buf.remaining()]; + buf.get(input); + Iterator readers = ImageIO.getImageReadersByMIMEType("image/jpeg2000"); + if (readers.hasNext() == false) { + throw new PDFParseException("JPXDecode failed. No reader available"); + } + reader = readers.next(); + reader.setInput(new MemoryCacheImageInputStream(new ByteArrayInputStream(input))); + BufferedImage bimg = reader.read(0); + return bimg; + } catch (IOException e) { + throw new PDFParseException("JPXDecode failed", e); + } finally { + if (reader != null) { + reader.dispose(); + } + } + + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/LZWDecode.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/LZWDecode.java new file mode 100644 index 000000000..8200ca4c7 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/LZWDecode.java @@ -0,0 +1,201 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.sun.pdfview.decode; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; + +import com.sun.pdfview.PDFObject; +import com.sun.pdfview.PDFParseException; + +/** + * decode an LZW-encoded array of bytes. LZW is a patented algorithm. + * + *

    Feb 21, 2009 Legal statement on Intellectual Property from Unisys

    + * LZW Patent Information (http://www.unisys.com/about__unisys/lzw)
    + * License Information on GIF and Other LZW-based Technologies
    + * 

    + * Unisys U.S. LZW Patent No. 4,558,302 expired on June 20, 2003, + * the counterpart patents in the United Kingdom, France, Germany and + * Italy expired on June 18, 2004, the Japanese counterpart patents + * expired on June 20, 2004 and the counterpart Canadian patent + * expired on July 7, 2004. + *

    + * Unisys Corporation holds and has patents pending on a number of + * improvements on the inventions claimed in the above-expired patents. + * Information on these improvement patents and terms under which they + * may be licensed can be obtained by contacting the following: + *

    + * Unisys Corporation + * Welch Patent Licensing Department + * Mail Stop E8-114 + * Unisys Way + * Blue Bell, PA 19424 + *

    + * Via the Internet, send email to Robert.Marley@unisys.com. + *

    + * Via facsimile, send inquiries to Welch Patent Licensing Department at + * 215-986-3090. + *

    + * The above is presented for information purposes only, and is subject + * to change by Unisys. Additionally, this information should not be + * considered as legally obligating Unisys in any way with regard to license + * availability, or as to the terms and conditions offered for a license, + * or with regard to the interpretation of any license agreements. + * You should consult with your own legal counsel regarding your + * particular situation. + *

    + * + * @author Mike Wessler + */ +public class LZWDecode { + + ByteBuffer buf; + int bytepos; + int bitpos; + byte[] dict[] = new byte[4096][]; + int dictlen = 0; + int bitspercode = 9; + static int STOP = 257; + static int CLEARDICT = 256; + + /** + * initialize this decoder with an array of encoded bytes + * @param buf the buffer of bytes + */ + private LZWDecode(ByteBuffer buf) throws PDFParseException { + for (int i = 0; i < 256; i++) { + this.dict[i] = new byte[1]; + this.dict[i][0] = (byte) i; + } + this.dictlen = 258; + this.bitspercode = 9; + this.buf = buf; + this.bytepos = 0; + this.bitpos = 0; + } + + /** + * reset the dictionary to the initial 258 entries + */ + private void resetDict() { + this.dictlen = 258; + this.bitspercode = 9; + } + + /** + * get the next code from the input stream + */ + private int nextCode() { + int fillbits = this.bitspercode; + int value = 0; + if (this.bytepos >= this.buf.limit() - 1) { + return -1; + } + while (fillbits > 0) { + int nextbits = this.buf.get(this.bytepos); // bitsource + int bitsfromhere = 8 - this.bitpos; // how many bits can we take? + if (bitsfromhere > fillbits) { // don't take more than we need + bitsfromhere = fillbits; + } + value |= ((nextbits >> (8 - this.bitpos - bitsfromhere)) & + (0xff >> (8 - bitsfromhere))) << (fillbits - bitsfromhere); + fillbits -= bitsfromhere; + this.bitpos += bitsfromhere; + if (this.bitpos >= 8) { + this.bitpos = 0; + this.bytepos++; + } + } + return value; + } + + /** + * decode the array. + * @return the uncompressed byte array + */ + private ByteBuffer decode() throws PDFParseException { + // algorithm derived from: + // http://www.rasip.fer.hr/research/compress/algorithms/fund/lz/lzw.html + // and the PDFReference + int cW = CLEARDICT; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + while (true) { + int pW = cW; + cW = nextCode(); + if (cW == -1) { + throw new PDFParseException("Missed the stop code in LZWDecode!"); + } + if (cW == STOP) { + break; + } else if (cW == CLEARDICT) { + resetDict(); + // pW= -1; + } else if (pW == CLEARDICT) { + baos.write(this.dict[cW], 0, this.dict[cW].length); + } else { + if (cW < this.dictlen) { // it's a code in the dictionary + baos.write(this.dict[cW], 0, this.dict[cW].length); + byte[] p = new byte[this.dict[pW].length + 1]; + System.arraycopy(this.dict[pW], 0, p, 0, this.dict[pW].length); + p[this.dict[pW].length] = this.dict[cW][0]; + this.dict[this.dictlen++] = p; + } else { // not in the dictionary (should==dictlen) + // if (cW!=dictlen) { + // System.out.println("Got a bouncy code: "+cW+" (dictlen="+dictlen+")"); + // } + byte[] p = new byte[this.dict[pW].length + 1]; + System.arraycopy(this.dict[pW], 0, p, 0, this.dict[pW].length); + p[this.dict[pW].length] = p[0]; + baos.write(p, 0, p.length); + this.dict[this.dictlen++] = p; + } + if (this.dictlen >= (1 << this.bitspercode) - 1 && this.bitspercode < 12) { + this.bitspercode++; + } + } + } + return ByteBuffer.wrap(baos.toByteArray()); + } + + /** + * decode an array of LZW-encoded bytes to a byte array. + * + * @param buf the buffer of encoded bytes + * @param params parameters for the decoder (unused) + * @return the decoded uncompressed bytes + */ + public static ByteBuffer decode(ByteBuffer buf, PDFObject params) + throws IOException { + // decode the array + LZWDecode me = new LZWDecode(buf); + ByteBuffer outBytes = me.decode(); + + // undo a predictor algorithm, if any was used + if (params != null && params.getDictionary().containsKey("Predictor")) { + Predictor predictor = Predictor.getPredictor(params); + if (predictor != null) { + outBytes = predictor.unpredict(outBytes); + } + } + + return outBytes; + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/PDFDecoder.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/PDFDecoder.java new file mode 100644 index 000000000..49a135603 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/PDFDecoder.java @@ -0,0 +1,214 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.sun.pdfview.decode; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +import com.sun.pdfview.PDFObject; +import com.sun.pdfview.PDFParseException; +import com.sun.pdfview.decrypt.PDFDecrypterFactory; + +/** + * A PDF Decoder encapsulates all the methods of decoding a stream of bytes + * based on all the various encoding methods. + *

    + * You should use the decodeStream() method of this object rather than using + * any of the decoders directly. + */ +public class PDFDecoder { + + public final static Set DCT_FILTERS = new HashSet(Arrays.asList("DCT", "DCTDecode")); + + /** Creates a new instance of PDFDecoder */ + private PDFDecoder() { + } + + public static boolean isLastFilter(PDFObject dict, Set filters) throws IOException { + PDFObject filter = dict.getDictRef("Filter"); + if (filter == null) { + return false; + } else if (filter.getType() == PDFObject.NAME) { + return filters.contains(filter.getStringValue()); + } else { + final PDFObject[] ary = filter.getArray(); + return filters.contains(ary[ary.length - 1].getStringValue()); + } + } + + /** + * Utility class for reading and storing the specification of + * Filters on a stream + */ + private static class FilterSpec + { + PDFObject ary[]; + PDFObject params[]; + + private FilterSpec(PDFObject dict, PDFObject filter) throws IOException { + if (filter.getType() == PDFObject.NAME) { + ary = new PDFObject[1]; + ary[0] = filter; + params = new PDFObject[1]; + params[0] = dict.getDictRef("DecodeParms"); + } else { + ary = filter.getArray(); + PDFObject parmsobj = dict.getDictRef("DecodeParms"); + if (parmsobj != null) { + params = parmsobj.getArray(); + } else { + params = new PDFObject[ary.length]; + } + } + } + + } + + /** + * decode a byte[] stream using the filters specified in the object's + * dictionary (passed as argument 1). + * @param dict the dictionary associated with the stream + * @param streamBuf the data in the stream, as a byte buffer + */ + public static ByteBuffer decodeStream(PDFObject dict, ByteBuffer streamBuf, Set filterLimits) + throws IOException { + + PDFObject filter = dict.getDictRef("Filter"); + if (filter == null) { + // just apply default decryption + return dict.getDecrypter().decryptBuffer(null, dict, streamBuf); + } else { + // apply filters + FilterSpec spec = new FilterSpec(dict, filter); + + // determine whether default encryption applies or if there's a + // specific Crypt filter; it must be the first filter according to + // the errata for PDF1.7 + boolean specificCryptFilter = + spec.ary.length != 0 && spec.ary[0].getStringValue().equals("Crypt"); + if (!specificCryptFilter) { + // No Crypt filter, so should apply default decryption (if + // present!) + streamBuf = dict.getDecrypter().decryptBuffer( + null, dict, streamBuf); + } + + for (int i = 0; i < spec.ary.length; i++) { + String enctype = spec.ary[i].getStringValue(); + try { + if (filterLimits.contains(enctype)) { + break; + } + if (enctype == null) { + } else if (enctype.equals("FlateDecode") || enctype.equals("Fl")) { + streamBuf = FlateDecode.decode(dict, streamBuf, spec.params[i]); + } else if (enctype.equals("LZWDecode") || enctype.equals("LZW")) { + streamBuf = LZWDecode.decode(streamBuf, spec.params[i]); + } else if (enctype.equals("ASCII85Decode") || enctype.equals("A85")) { + streamBuf = ASCII85Decode.decode(streamBuf, spec.params[i]); + } else if (enctype.equals("ASCIIHexDecode") || enctype.equals("AHx")) { + streamBuf = ASCIIHexDecode.decode(streamBuf, spec.params[i]); + } else if (enctype.equals("RunLengthDecode") || enctype.equals("RL")) { + streamBuf = RunLengthDecode.decode(streamBuf, spec.params[i]); + } else if (enctype.equals("DCTDecode") || enctype.equals("DCT")) { + streamBuf = DCTDecode.decode(dict, streamBuf, spec.params[i]); + } else if (enctype.equals("JPXDecode")) { + streamBuf = JPXDecode.decode(dict, streamBuf, spec.params[i]); + } else if (enctype.equals("CCITTFaxDecode") || enctype.equals("CCF")) { + streamBuf = CCITTFaxDecode.decode(dict, streamBuf, spec.params[i]); + } else if (enctype.equals("Crypt")) { + String cfName = PDFDecrypterFactory.CF_IDENTITY; + if (spec.params[i] != null) { + final PDFObject nameObj = spec.params[i].getDictRef("Name"); + if (nameObj != null && nameObj.getType() == PDFObject.NAME) { + cfName = nameObj.getStringValue(); + } + } + streamBuf = dict.getDecrypter().decryptBuffer(cfName, null, streamBuf); + } else { + throw new PDFParseException("Unknown coding method:" + spec.ary[i].getStringValue()); + } + }catch(Exception e) { + throw new PDFParseException("Problem decoding "+enctype+" encoded stream!", e); + } + + } + } + + return streamBuf; + } + + /** + * The name of the Crypt filter to apply + * @param param the parameters to the Crypt filter + * @return the name of the crypt filter to apply + * @throws IOException if there's a problem reading the objects + */ + private static String getCryptFilterName(PDFObject param) throws IOException { + String cfName = PDFDecrypterFactory.CF_IDENTITY; + if (param != null) { + final PDFObject nameObj = param.getDictRef("Name"); + if (nameObj != null && nameObj.getType() == PDFObject.NAME) { + cfName = nameObj.getStringValue(); + } + } + return cfName; + } + + /** + * Determines whether a stream is encrypted or not; note that encodings + * (e.g., Flate, LZW) are not considered encryptions. + * @param dict the stream dictionary + * @return whether the stream is encrypted + * @throws IOException if the stream dictionary can't be read + */ + public static boolean isEncrypted(PDFObject dict) + throws IOException { + + PDFObject filter = dict.getDictRef("Filter"); + if (filter == null) { + // just apply default decryption + return dict.getDecrypter().isEncryptionPresent(); + } else { + + // apply filters + FilterSpec spec = new FilterSpec(dict, filter); + + // determine whether default encryption applies or if there's a + // specific Crypt filter; it must be the first filter according to + // the errata for PDF1.7 + boolean specificCryptFilter = spec.ary.length != 0 && + spec.ary[0].getStringValue().equals("Crypt"); + if (!specificCryptFilter) { + // No Crypt filter, so we just need to refer to + // the default decrypter + return dict.getDecrypter().isEncryptionPresent(); + } else { + String cfName = getCryptFilterName(spec.params[0]); + // see whether the specified crypt filter really decrypts + return dict.getDecrypter().isEncryptionPresent(cfName); + } + } + + } + +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/PNGPredictor.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/PNGPredictor.java new file mode 100644 index 000000000..116260173 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/PNGPredictor.java @@ -0,0 +1,212 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package com.sun.pdfview.decode; + +import java.nio.ByteBuffer; + +import java.io.IOException; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +/** + * Undo prediction based on the PNG algorithm. + */ +public class PNGPredictor extends Predictor { + /** Creates a new instance of PNGPredictor */ + public PNGPredictor() { + super (PNG); + } + + /** + * Undo data based on the png algorithm + */ + @Override + public ByteBuffer unpredict(ByteBuffer imageData) + throws IOException + { + List rows = new ArrayList(); + + byte[] curLine = null; + byte[] prevLine = null; + + // get the number of bytes per row + int rowSize = getColumns() * getColors() * getBitsPerComponent(); + rowSize = (int) Math.ceil(rowSize / 8.0); + + while(imageData.remaining() >= rowSize + 1) { + // the first byte determines the algorithm + int algorithm = (imageData.get() & 0xff); + + // read the rest of the line + curLine = new byte[rowSize]; + imageData.get(curLine); + + // use the algorithm, Luke + switch (algorithm) { + case 0: + // none + break; + case 1: + doSubLine(curLine); + break; + case 2: + doUpLine(curLine, prevLine); + break; + case 3: + doAverageLine(curLine, prevLine); + break; + case 4: + doPaethLine(curLine, prevLine); + break; + } + + rows.add(curLine); + prevLine = curLine; + } + + // turn into byte array + ByteBuffer outBuf = ByteBuffer.allocate(rows.size() * rowSize); + for (Iterator i = rows.iterator(); i.hasNext();) { + outBuf.put((byte[]) i.next()); + } + + // reset start pointer + outBuf.flip(); + + // return + return outBuf; + + } + + /** + * Return the value of the Sub algorithm on the line (compare bytes to + * the previous byte of the same color on this line). + */ + protected void doSubLine(byte[] curLine) { + // get the number of bytes per sample + int sub = (int) Math.ceil((getBitsPerComponent() * getColors()) / 8.0); + + for (int i = 0; i < curLine.length; i++) { + int prevIdx = i - sub; + if (prevIdx >= 0) { + curLine[i] += curLine[prevIdx]; + } + } + } + + /** + * Return the value of the up algorithm on the line (compare bytes to + * the same byte in the previous line) + */ + protected void doUpLine(byte[] curLine, byte[] prevLine) { + if (prevLine == null) { + // do nothing if this is the first line + return; + } + + for (int i = 0; i < curLine.length; i++) { + curLine[i] += prevLine[i]; + } + } + + /** + * Return the value of the average algorithm on the line (compare + * bytes to the average of the previous byte of the same color and + * the same byte on the previous line) + */ + protected void doAverageLine(byte[] curLine, byte[] prevLine) { + // get the number of bytes per sample + int sub = (int) Math.ceil((getBitsPerComponent() * getColors()) / 8.0); + + for (int i = 0; i < curLine.length; i++) { + int raw = 0; + int prior = 0; + + // get the last value of this color + int prevIdx = i - sub; + if (prevIdx >= 0) { + raw = curLine[prevIdx] & 0xff; + } + + // get the value on the previous line + if (prevLine != null) { + prior = prevLine[i] & 0xff; + } + + // add the average + curLine[i] += (byte) Math.floor((raw + prior) / 2); + } + } + + /** + * Return the value of the average algorithm on the line (compare + * bytes to the average of the previous byte of the same color and + * the same byte on the previous line) + */ + protected void doPaethLine(byte[] curLine, byte[] prevLine) { + // get the number of bytes per sample + int sub = (int) Math.ceil((getBitsPerComponent() * getColors()) / 8.0); + + for (int i = 0; i < curLine.length; i++) { + int left = 0; + int up = 0; + int upLeft = 0; + + // get the last value of this color + int prevIdx = i - sub; + if (prevIdx >= 0) { + left = curLine[prevIdx] & 0xff; + } + + // get the value on the previous line + if (prevLine != null) { + up = prevLine[i] & 0xff; + } + + if (prevIdx >= 0 && prevLine != null) { + upLeft = prevLine[prevIdx] & 0xff; + } + + // add the average + curLine[i] += (byte) paeth(left, up, upLeft); + } + } + + /** + * The paeth algorithm + */ + protected int paeth(int left, int up, int upLeft) { + int p = left + up - upLeft; + int pa = Math.abs(p - left); + int pb = Math.abs(p - up); + int pc = Math.abs(p - upLeft); + + if ((pa <= pb) && (pa <= pc)) { + return left; + } else if (pb <= pc) { + return up; + } else { + return upLeft; + } + } + +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/Predictor.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/Predictor.java new file mode 100644 index 000000000..4bd043e1f --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/Predictor.java @@ -0,0 +1,173 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package com.sun.pdfview.decode; + +import java.io.IOException; +import java.nio.ByteBuffer; + +import com.sun.pdfview.PDFObject; +import com.sun.pdfview.PDFParseException; + +/** + * The abstract superclass of various predictor objects that undo well-known + * prediction algorithms. + */ +public abstract class Predictor { + /** well known algorithms */ + public static final int TIFF = 0; + public static final int PNG = 1; + + /** the algorithm to use */ + private final int algorithm; + + /** the number of colors per sample */ + private int colors = 1; + + /** the number of bits per color component */ + private int bpc = 8; + + /** the number of columns per row */ + private int columns = 1; + + /** + * Create an instance of a predictor. Use getPredictor() + * instead of this. + */ + protected Predictor(int algorithm) { + this.algorithm = algorithm; + } + + /** + * Actually perform this algorithm on decoded image data. + * Subclasses must implement this method + */ + public abstract ByteBuffer unpredict(ByteBuffer imageData) + throws IOException; + + /** + * Get an instance of a predictor + * + * @param params the filter parameters + */ + public static Predictor getPredictor(PDFObject params) + throws IOException + { + // get the algorithm (required) + PDFObject algorithmObj = params.getDictRef("Predictor"); + if (algorithmObj == null) { + // no predictor + return null; + } + int algorithm = algorithmObj.getIntValue(); + + // create the predictor object + Predictor predictor = null; + switch (algorithm) { + case 1: + // no predictor + return null; + case 2: + predictor = new TIFFPredictor(); + break; + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + predictor = new PNGPredictor(); + break; + default: + throw new PDFParseException("Unknown predictor: " + algorithm); + } + + // read the colors (optional) + PDFObject colorsObj = params.getDictRef("Colors"); + if (colorsObj != null) { + predictor.setColors(colorsObj.getIntValue()); + } + + // read the bits per component (optional) + PDFObject bpcObj = params.getDictRef("BitsPerComponent"); + if (bpcObj != null) { + predictor.setBitsPerComponent(bpcObj.getIntValue()); + } + + // read the columns (optional) + PDFObject columnsObj = params.getDictRef("Columns"); + if (columnsObj != null) { + predictor.setColumns(columnsObj.getIntValue()); + } + + // all set + return predictor; + } + + /** + * Get the algorithm in use + * + * @return one of the known algorithm types + */ + public int getAlgorithm() { + return this.algorithm; + } + + /** + * Get the number of colors per sample + */ + public int getColors() { + return this.colors; + } + + /** + * Set the number of colors per sample + */ + protected void setColors(int colors) { + this.colors = colors; + } + + /** + * Get the number of bits per color component + */ + public int getBitsPerComponent() { + return this.bpc; + } + + /** + * Set the number of bits per color component + */ + public void setBitsPerComponent(int bpc) { + this.bpc = bpc; + } + + /** + * Get the number of columns + */ + public int getColumns() { + return this.columns; + } + + /** + * Set the number of columns + */ + public void setColumns(int columns) { + this.columns = columns; + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/RunLengthDecode.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/RunLengthDecode.java new file mode 100644 index 000000000..41ff6bf00 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/RunLengthDecode.java @@ -0,0 +1,94 @@ +/* + * Copyright 2009 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.sun.pdfview.decode; + +import java.io.ByteArrayOutputStream; +import java.nio.ByteBuffer; + +import com.sun.pdfview.PDFObject; +import com.sun.pdfview.PDFParseException; + +/** + * decode an array of Run Length encoded bytes into a byte array + * + * @author Mike Wessler + */ +public class RunLengthDecode { + /** the end of data in the RunLength encoding. */ + private static final int RUN_LENGTH_EOD = 128; + + private ByteBuffer buf; + + /** + * initialize the decoder with an array of bytes in RunLength format + */ + private RunLengthDecode(ByteBuffer buf) { + this.buf = buf; + } + + /** + * decode the array + * + * @return the decoded bytes + */ + private ByteBuffer decode() { + // start at the beginning of the buffer + this.buf.rewind(); + + // allocate the output buffer + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + int dupAmount; + byte[] buffer = new byte[128]; + while ((dupAmount = this.buf.get()&0xFF) != RUN_LENGTH_EOD) { + if (dupAmount >= 0 && dupAmount <= 127) { + int amountToCopy = dupAmount + 1; + this.buf.get(buffer, 0, amountToCopy); + baos.write(buffer, 0, amountToCopy); + } else { + byte dupByte = this.buf.get(); + for (int i = 0; i < 257 - dupAmount; i++) { + baos.write(dupByte); + } + } + } + return ByteBuffer.wrap(baos.toByteArray()); + } + + /** + * decode an array of bytes in RunLength format. + *

    + * RunLength format consists of a sequence of a byte-oriented format based + * on run length. There are a series of "runs", where a run is a length byte + * followed by 1 to 128 bytes of data. If the length is 0-127, the following + * length+1 (1 to 128) bytes are to be copied. If the length is 129 through + * 255, the following single byte is copied 257-length (2 to 128) times. A + * length value of 128 means and End of Data (EOD). + * + * @param buf + * the RUnLEngth encoded bytes in a byte buffer + * + * @param params + * parameters to the decoder (ignored) + * @return the decoded bytes + */ + public static ByteBuffer decode(ByteBuffer buf, PDFObject params) throws PDFParseException { + RunLengthDecode me = new RunLengthDecode(buf); + return me.decode(); + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/TIFFPredictor.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/TIFFPredictor.java new file mode 100644 index 000000000..648431602 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/TIFFPredictor.java @@ -0,0 +1,123 @@ +/* + * $Id: TIFFPredictor.java,v 1.1 2010-05-23 22:07:04 lujke Exp $ + * + * Copyright 2010 Pirion Systems Pty Ltd, 139 Warry St, + * Fortitude Valley, Queensland, Australia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package com.sun.pdfview.decode; + +import java.io.IOException; +import java.nio.ByteBuffer; + +/** + * Undo prediction based on the TIFF Predictor 2 algorithm + */ +public class TIFFPredictor extends Predictor { + + public TIFFPredictor() { + super (TIFF); + } + + /** + * Undo data based on the png algorithm + */ + public ByteBuffer unpredict(ByteBuffer imageData) + throws IOException + { + ByteBuffer out = ByteBuffer.allocate(imageData.limit()); + + final int numComponents = getColors(); + final int pixelBits = numComponents * getBitsPerComponent(); + + int bytePerRow = (getColumns() * pixelBits + 7) / 8; + + final byte[] row = new byte[bytePerRow]; + + while(imageData.remaining() > 0) { + imageData.get(row); + if (getBitsPerComponent() == 8) { + for (int i = numComponents; i < row.length; i += numComponents) { + for (int c = 0; c < numComponents; ++c) { + final int pos = i + c; + row[pos] += row[pos - numComponents]; + } + } + } else if (getBitsPerComponent() == 16) { + final short[] prev = new short[numComponents]; + for (int c = 0; c < numComponents; c += 1) { + final int pos = c * 2; + prev[c] = (short) ((row[pos] << 8 | (row[pos + 1]) & 0xFFFF)); + } + for (int i = numComponents * 2; i < row.length; i += numComponents * 2) { + for (int c = 0; c < numComponents; c += 1) { + final int pos = i + c * 2; + short cur = (short) ((row[pos] << 8 | (row[pos + 1]) & 0xFFFF)); + cur += prev[c]; + row[pos] = (byte) (cur >>> 8 & 0xFF); + row[pos + 1] = (byte) (cur & 0xFF); + prev[c] = cur; + } + } + } else { + assert getBitsPerComponent() == 1 || getBitsPerComponent() == 2 || getBitsPerComponent() == 4 : "we don't want to grab components across pixel boundaries"; + int bitsOnRow = pixelBits * getColumns(); // may be less than bytesOnRow * 8 + byte prev[] = new byte[numComponents]; + final int shiftWhenAligned = 8 - getBitsPerComponent(); + final int mask = (1 << getBitsPerComponent()) - 1; + for (int c = 0; c < numComponents; ++c) { + prev[c] = getbits(row, c * getBitsPerComponent(), shiftWhenAligned, mask); + } + for (int i = pixelBits; i < bitsOnRow; i += pixelBits) { + for (int c = 0; c < numComponents; ++c) { + byte cur = getbits(row, i + c * getBitsPerComponent(), shiftWhenAligned, mask); + cur += prev[c]; + prev[c] = cur; + setbits(row, i + c * getBitsPerComponent(), shiftWhenAligned, mask, cur); + } + } + } + out.put(row); + } + + + // reset start pointer + out.flip(); + + // return + return out; + + } + + private static byte getbits(byte[] data, int bitIndex, int shiftWhenByteAligned, int mask) + { + final int b = data[(bitIndex >> 3)]; + final int bitIndexInB = bitIndex & 7; + final int shift = shiftWhenByteAligned - bitIndexInB; + return (byte) ((b >>> shift) & mask); + } + + private static void setbits(byte[] data, int bitIndex, int shiftWhenByteAligned, int mask, byte bits) + { + final int b = data[(bitIndex >> 3)]; + final int bitIndexInB = bitIndex & 7; + final int shift = shiftWhenByteAligned - bitIndexInB; + data[bitIndex >> 3] = (byte) ((b & ~(mask << shift)) | (bits << shift)); + } + + +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/CryptFilterDecrypter.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/CryptFilterDecrypter.java new file mode 100644 index 000000000..85e7a9d84 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/CryptFilterDecrypter.java @@ -0,0 +1,139 @@ +/* + * Copyright 2008 Pirion Systems Pty Ltd, 139 Warry St, + * Fortitude Valley, Queensland, Australia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package com.sun.pdfview.decrypt; + +import java.nio.ByteBuffer; +import java.util.Map; + +import com.sun.pdfview.PDFObject; +import com.sun.pdfview.PDFParseException; + +/** + * Implements Version 4 standard decryption, whereby the Encrypt dictionary + * contains a list of named 'crypt filters', each of which is the equivalent + * of a {@link PDFDecrypter}. In addition to this list of crypt filters, + * the name of the filter to use for streams and the default filter to use + * for strings is specified. Requests to decode a stream with a named + * decrypter (typically Identity) instead of the default decrypter + * are honoured. + * + * @author Luke Kirby + */ +public class CryptFilterDecrypter implements PDFDecrypter { + + /** Maps from crypt filter names to their corresponding decrypters */ + private Map decrypters; + /** The default decrypter for stream content */ + private PDFDecrypter defaultStreamDecrypter; + /** The default decrypter for string content */ + private PDFDecrypter defaultStringDecrypter; + + /** + * Class constructor + * @param decrypters a map of crypt filter names to their corresponding + * decrypters. Must already contain the Identity filter. + * @param defaultStreamCryptName the crypt filter name of the default + * stream decrypter + * @param defaultStringCryptName the crypt filter name of the default + * string decrypter + * @throws PDFParseException if one of the named defaults is not + * present in decrypters + */ + public CryptFilterDecrypter( + Map decrypters, + String defaultStreamCryptName, + String defaultStringCryptName) + throws PDFParseException { + + this.decrypters = decrypters; + assert this.decrypters.containsKey("Identity") : + "Crypt Filter map does not contain required Identity filter"; + defaultStreamDecrypter = this.decrypters.get(defaultStreamCryptName); + if (defaultStreamDecrypter == null) { + throw new PDFParseException( + "Unknown crypt filter specified as default for streams: " + + defaultStreamCryptName); + } + defaultStringDecrypter = this.decrypters.get(defaultStringCryptName); + if (defaultStringDecrypter == null) { + throw new PDFParseException( + "Unknown crypt filter specified as default for strings: " + + defaultStringCryptName); + } + } + + @Override + public ByteBuffer decryptBuffer( + String cryptFilterName, PDFObject streamObj, ByteBuffer streamBuf) + throws PDFParseException { + final PDFDecrypter decrypter; + if (cryptFilterName == null) { + decrypter = defaultStreamDecrypter; + } else { + decrypter = decrypters.get(cryptFilterName); + if (decrypter == null) { + throw new PDFParseException("Unknown CryptFilter: " + + cryptFilterName); + } + } + return decrypter.decryptBuffer( + // elide the filter name to prevent V2 decrypters from + // complaining about a crypt filter name + null, + // if there's a specific crypt filter being used then objNum + // and objGen shouldn't contribute to the key, so we + // should make sure that no streamObj makes its way through + cryptFilterName != null ? null : streamObj, + streamBuf); + } + + @Override + public String decryptString(int objNum, int objGen, String inputBasicString) + throws PDFParseException { + return defaultStringDecrypter.decryptString(objNum, objGen, inputBasicString); + } + + @Override + public boolean isEncryptionPresent() { + for (final PDFDecrypter decrypter : decrypters.values()) { + if (decrypter.isEncryptionPresent()) { + return true; + } + } + return false; + } + + @Override + public boolean isEncryptionPresent(String cryptFilterName) { + PDFDecrypter decrypter = decrypters.get(cryptFilterName); + return decrypter != null && decrypter.isEncryptionPresent(cryptFilterName); + } + + @Override + public boolean isOwnerAuthorised() { + for (final PDFDecrypter decrypter : decrypters.values()) { + if (decrypter.isOwnerAuthorised()) { + return true; + } + } + return false; + } + +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/EncryptionUnsupportedByPlatformException.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/EncryptionUnsupportedByPlatformException.java new file mode 100644 index 000000000..433c4b809 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/EncryptionUnsupportedByPlatformException.java @@ -0,0 +1,39 @@ +/* Copyright 2008 Pirion Systems Pty Ltd, 139 Warry St, + * Fortitude Valley, Queensland, Australia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package com.sun.pdfview.decrypt; + +/** + * Identifies that the specified encryption mechanism, though supported by the + * product, is not supported by the platform that it is running on; i.e., that + * either the JCE does not support a required cipher or that its policy is + * such that a key of a given length can not be used. + * + * @author Luke Kirby + */ +public class EncryptionUnsupportedByPlatformException + extends UnsupportedEncryptionException { + + public EncryptionUnsupportedByPlatformException(String message) { + super(message); + } + + public EncryptionUnsupportedByPlatformException(String message, Throwable cause) { + super(message, cause); + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/EncryptionUnsupportedByProductException.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/EncryptionUnsupportedByProductException.java new file mode 100644 index 000000000..8e96b8c22 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/EncryptionUnsupportedByProductException.java @@ -0,0 +1,36 @@ +/* + * Copyright 2008 Pirion Systems Pty Ltd, 139 Warry St, + * Fortitude Valley, Queensland, Australia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package com.sun.pdfview.decrypt; + +/** + * Identifies that the specified encryption mechanism is not + * supported by this product, that is, PDFRenderer, as opposed to + * a {@link EncryptionUnsupportedByPlatformException limitation in + * the platform}. + * + * @author Luke Kirby + */ +public class EncryptionUnsupportedByProductException + extends UnsupportedEncryptionException { + + public EncryptionUnsupportedByProductException(String message) { + super(message); + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/IdentityDecrypter.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/IdentityDecrypter.java new file mode 100644 index 000000000..517bbd90d --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/IdentityDecrypter.java @@ -0,0 +1,72 @@ +/* + * Copyright 2008 Pirion Systems Pty Ltd, 139 Warry St, + * Fortitude Valley, Queensland, Australia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package com.sun.pdfview.decrypt; + +import java.nio.ByteBuffer; + +import com.sun.pdfview.PDFObject; +import com.sun.pdfview.PDFParseException; + +/** + * Performs identity decryption; that is, inputs aren't encrypted and + * are returned right back. + * + * @Author Luke Kirby + */ +public class IdentityDecrypter implements PDFDecrypter { + + private static IdentityDecrypter INSTANCE = new IdentityDecrypter(); + + @Override + public ByteBuffer decryptBuffer(String cryptFilterName, + PDFObject streamObj, ByteBuffer streamBuf) + throws PDFParseException { + + if (cryptFilterName != null) { + throw new PDFParseException("This Encryption version does not support Crypt filters"); + } + + return streamBuf; + } + + @Override + public String decryptString(int objNum, int objGen, String inputBasicString) { + return inputBasicString; + } + + public static IdentityDecrypter getInstance() { + return INSTANCE; + } + + @Override + public boolean isEncryptionPresent() { + return false; + } + + @Override + public boolean isEncryptionPresent(String cryptFilterName) { + return false; + } + + @Override + public boolean isOwnerAuthorised() { + return false; + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/PDFAuthenticationFailureException.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/PDFAuthenticationFailureException.java new file mode 100644 index 000000000..8d2fbd50c --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/PDFAuthenticationFailureException.java @@ -0,0 +1,34 @@ +/* Copyright 2008 Pirion Systems Pty Ltd, 139 Warry St, + * Fortitude Valley, Queensland, Australia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package com.sun.pdfview.decrypt; + +import com.sun.pdfview.PDFParseException; + +/** + * Identifies that the supplied password was incorrect or non-existent + * and required. + * @author Luke Kirby + */ +// TODO - consider having this not extend PDFParseException so that +// it will be handled more explicitly? +public class PDFAuthenticationFailureException extends PDFParseException { + public PDFAuthenticationFailureException(String message) { + super(message); + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/PDFDecrypter.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/PDFDecrypter.java new file mode 100644 index 000000000..63144767b --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/PDFDecrypter.java @@ -0,0 +1,104 @@ +/* + * Copyright 2008 Pirion Systems Pty Ltd, 139 Warry St, + * Fortitude Valley, Queensland, Australia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package com.sun.pdfview.decrypt; + +import java.nio.ByteBuffer; + +import com.sun.pdfview.PDFObject; +import com.sun.pdfview.PDFParseException; +import com.sun.pdfview.PDFStringUtil; + +/** + * A decrypter decrypts streams and strings in a PDF document. {@link + * #decryptBuffer(String, PDFObject, ByteBuffer)} } should be used for decoding + * streams, and {@link #decryptString(int, int, String)} for string values in + * the PDF. It is possible for strings and streams to be encrypted with + * different mechanisms, so the appropriate method must alwayus be used. + * + * @see "PDFReference 1.7, Section 3.5 Encryption" + * @author Luke Kirby + */ +public interface PDFDecrypter { + + /** + * Decrypt a buffer of data + * @param cryptFilterName the name of the crypt filter, if V4 + * encryption is being used, where individual crypt filters may + * be specified for individual streams. If encryption is not using + * V4 encryption (indicated by V=4 in the Encrypt dictionary) then + * this must be null. Null may also be specified with V4 encryption + * to indicate that the default filter should be used. + * @param streamObj the object whose stream is being decrypted. The + * containing object's number and generation contribute to the key used for + * stream encrypted with the document's default encryption, so this is + * typically required. Should be null only if a cryptFilterName is + * specified, as objects with specific stream filters use the general + * document key, rather than a stream-specific key. + * @param streamBuf the buffer to decrypt + * @return a buffer containing the decrypted stream, positioned at its + * beginning; will only be the same buffer as streamBuf if the identity + * decrypter is being used + * @throws PDFParseException if the named crypt filter does not exist, or + * if a crypt filter is named when named crypt filters are not supported. + * Problems due to incorrect passwords are revealed prior to this point. + */ + public ByteBuffer decryptBuffer( + String cryptFilterName, + PDFObject streamObj, + ByteBuffer streamBuf) + throws PDFParseException; + + /** + * Decrypt a {@link PDFStringUtil basic string}. + * @param objNum the object number of the containing object + * @param objGen the generation number of the containing object + * @param inputBasicString the string to be decrypted + * @return the decrypted string + * @throws PDFParseException if the named crypt filter does not exist, or + * if a crypt filter is named when named crypt filters are not supported. + * Problems due to incorrect passwords are revealed prior to this point. + */ + public String decryptString(int objNum, int objGen, String inputBasicString) + throws PDFParseException; + + /** + * Determine whether the password known by the decrypter indicates that + * the user is the owner of the document. Can be used, in conjunction + * with {@link #isEncryptionPresent()} to determine whether any + * permissions apply. + * @return whether owner authentication is being used to decrypt the + * document + */ + public boolean isOwnerAuthorised(); + + /** + * Determine whether this actually applies a decryption other than + * identity decryption. + * @return whether encryption is present + */ + public boolean isEncryptionPresent(); + + /** + * Determines whether decryption applies for a given crypt filter name + * @param cryptFilterName the crypt filter name + * @return whether the given crypt filter decrypts or not + */ + boolean isEncryptionPresent(String cryptFilterName); +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/PDFDecrypterFactory.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/PDFDecrypterFactory.java new file mode 100644 index 000000000..17742925d --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/PDFDecrypterFactory.java @@ -0,0 +1,337 @@ +/* Copyright 2008 Pirion Systems Pty Ltd, 139 Warry St, + * Fortitude Valley, Queensland, Australia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package com.sun.pdfview.decrypt; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import com.sun.pdfview.PDFObject; +import com.sun.pdfview.PDFParseException; + +/** + * Produces a {@link PDFDecrypter} for documents given a (possibly non-existent) + * Encrypt dictionary. Supports decryption of versions 1, 2 and 4 of the + * password-based encryption mechanisms as described in PDF Reference version + * 1.7. This means that it supports RC4 and AES encryption with keys of + * 40-128 bits; esentially, password-protected documents with compatibility + * up to Acrobat 8. + * + * @See "PDF Reference version 1.7, section 3.5: Encryption" + * @author Luke Kirby + */ +public class PDFDecrypterFactory { + + /** The name of the standard Identity CryptFilter */ + public static final String CF_IDENTITY = "Identity"; + + /** Default key length for versions where key length is optional */ + private static final int DEFAULT_KEY_LENGTH = 40; + + /** + * Create a decryptor for a given encryption dictionary. A check is + * immediately performed that the supplied password decrypts content + * described by the encryption specification. + * + * @param encryptDict the Encrypt dict as found in the document's trailer. + * May be null, in which case the {@link IdentityDecrypter} will + * be returned. + * @param documentId the object with key "ID" in the trailer's dictionary. + * Should always be present if Encrypt is. + * @param password the password to use; may be null + * @return The decryptor that should be used for all encrypted data in the + * PDF + * @throws IOException will typically be a {@link + * com.sun.pdfview.PDFParseException}, indicating an IO problem, an error + * in the structure of the document, or a failure to obtain various ciphers + * from the installed JCE providers + * @throws EncryptionUnsupportedByPlatformException if the encryption + * is not supported by the environment in which the code is executing + * @throws EncryptionUnsupportedByProductException if PDFRenderer does + * not currently support the specified encryption + * @throws PDFAuthenticationFailureException if the supplied password + * was not able to + */ + public static PDFDecrypter createDecryptor + (PDFObject encryptDict, PDFObject documentId, PDFPassword password) + throws + IOException, + EncryptionUnsupportedByPlatformException, + EncryptionUnsupportedByProductException, + PDFAuthenticationFailureException { + + // none of the classes beyond us want to see a null PDFPassword + password = PDFPassword.nonNullPassword(password); + + if (encryptDict == null) { + // No encryption specified + return IdentityDecrypter.getInstance(); + } else { + PDFObject filter = encryptDict.getDictRef("Filter"); + // this means that we'll fail if, for example, public key + // encryption is employed + if (filter != null && "Standard".equals(filter.getStringValue())) { + final PDFObject vObj = encryptDict.getDictRef("V"); + int v = vObj != null ? vObj.getIntValue() : 0; + if (v == 1 || v == 2) { + final PDFObject lengthObj = + encryptDict.getDictRef("Length"); + final Integer length = + lengthObj != null ? lengthObj.getIntValue() : null; + return createStandardDecrypter( + encryptDict, documentId, password, length, false, + StandardDecrypter.EncryptionAlgorithm.RC4); + } else if (v == 4) { + return createCryptFilterDecrypter( + encryptDict, documentId, password, v); + } else { + throw new EncryptionUnsupportedByPlatformException( + "Unsupported encryption version: " + v); + } + } else if (filter == null) { + throw new PDFParseException( + "No Filter specified in Encrypt dictionary"); + } else { + throw new EncryptionUnsupportedByPlatformException( + "Unsupported encryption Filter: " + filter + + "; only Standard is supported."); + } + } + } + + /** + * Create a decrypter working from a crypt filter dictionary, as in + * version 4 encryption + * + * @param encryptDict the Encrypt dictionary + * @param documentId the document ID + * @param password the provided password + * @param v the version of encryption being used; must be at least 4 + * @return the decrypter corresponding to the scheme expressed in + * encryptDict + * @throws PDFAuthenticationFailureException if the provided password + * does not decrypt this document + * @throws IOException if there is a problem reading the PDF, an invalid + * document structure, or an inability to obtain the required ciphers + * from the platform's JCE + * @throws EncryptionUnsupportedByPlatformException if the encryption + * is not supported by the environment in which the code is executing + * @throws EncryptionUnsupportedByProductException if PDFRenderer does + * not currently support the specified encryption + */ + private static PDFDecrypter createCryptFilterDecrypter( + PDFObject encryptDict, + PDFObject documentId, + PDFPassword password, + int v) + throws + PDFAuthenticationFailureException, + IOException, + EncryptionUnsupportedByPlatformException, + EncryptionUnsupportedByProductException { + + assert v >= 4 : "crypt filter decrypter not supported for " + + "standard encryption prior to version 4"; + + // encryptMetadata is true if not present. Note that we don't actually + // use this to change our reading of metadata streams (that's all done + // internally by the document specifying a Crypt filter of None if + // appropriate), but it does affect the encryption key. + boolean encryptMetadata = true; + final PDFObject encryptMetadataObj = + encryptDict.getDictRef("EncryptMetadata"); + if (encryptMetadataObj != null + && encryptMetadataObj.getType() == PDFObject.BOOLEAN) { + encryptMetadata = encryptMetadataObj.getBooleanValue(); + } + + final PDFObject bitLengthObj = encryptDict.getDictRef("Length"); + + // Assemble decrypters for each filter in the + // crypt filter (CF) dictionary + final Map cfDecrypters = + new HashMap(); + final PDFObject cfDict = encryptDict.getDictRef("CF"); + if (cfDict == null) { + throw new PDFParseException( + "No CF value present in Encrypt dict for V4 encryption"); + } + final Iterator cfNameIt = cfDict.getDictKeys(); + while (cfNameIt.hasNext()) { + final String cfName = cfNameIt.next(); + final PDFObject cryptFilter = cfDict.getDictRef(cfName); + + final PDFObject lengthObj = cryptFilter.getDictRef("Length"); + // The Errata for PDF 1.7 explains that the value of + // Length in CF dictionaries is in bytes + final Integer length = lengthObj != null ? lengthObj.getIntValue() * 8 : + (bitLengthObj != null) ? bitLengthObj.getIntValue() : null; + + // CFM is the crypt filter method, describing whether RC4, + // AES, or None (i.e., identity) is the encryption mechanism + // used for the name crypt filter + final PDFObject cfmObj = cryptFilter.getDictRef("CFM"); + final String cfm = cfmObj != null ? + cfmObj.getStringValue() : "None"; + final PDFDecrypter cfDecrypter; + if ("None".equals(cfm)) { + cfDecrypter = IdentityDecrypter.getInstance(); + } else if ("V2".equals(cfm)) { + cfDecrypter = createStandardDecrypter( + encryptDict, documentId, password, length, + encryptMetadata, + StandardDecrypter.EncryptionAlgorithm.RC4); + } else if ("AESV2".equals(cfm)) { + cfDecrypter = createStandardDecrypter( + encryptDict, documentId, password, length, + encryptMetadata, + StandardDecrypter.EncryptionAlgorithm.AESV2); + } else { + throw new UnsupportedOperationException( + "Unknown CryptFilter method: " + cfm); + } + cfDecrypters.put(cfName, cfDecrypter); + } + + // always put Identity in last so that it will override any + // Identity filter sneakily declared in the CF entry + cfDecrypters.put(CF_IDENTITY, IdentityDecrypter.getInstance()); + + PDFObject stmFObj = encryptDict.getDictRef("StmF"); + final String defaultStreamFilter = + stmFObj != null ? stmFObj.getStringValue() : CF_IDENTITY; + + PDFObject strFObj = encryptDict.getDictRef("StrF"); + final String defaultStringFilter = + strFObj != null ? strFObj.getStringValue() : CF_IDENTITY; + + return new CryptFilterDecrypter( + cfDecrypters, defaultStreamFilter, defaultStringFilter); + + } + + /** + * Create a standard single-algorithm AES or RC4 decrypter. The Encrypt + * dictionary is used where possible, but where different encryption + * versions employ different mechanisms of specifying configuration or may + * be specified via a CF entry (e.g. key length), the value is specified as + * a parameter. + * + * @param encryptDict the Encrypt dictionary + * @param documentId the document ID + * @param password the password + * @param keyLength the key length, in bits; may be null + * to use a {@link #DEFAULT_KEY_LENGTH default} + * @param encryptMetadata whether metadata is being encrypted + * @param encryptionAlgorithm, the encryption algorithm + * @return the decrypter + * @throws PDFAuthenticationFailureException if the provided password + * is not the one expressed by the encryption dictionary + * @throws IOException if there is a problem reading the PDF content, + * if the content does not comply with the PDF specification + * @throws EncryptionUnsupportedByPlatformException if the encryption + * is not supported by the environment in which the code is executing + * @throws EncryptionUnsupportedByProductException if PDFRenderer does + * not currently support the specified encryption + * + */ + private static PDFDecrypter createStandardDecrypter( + PDFObject encryptDict, + PDFObject documentId, + PDFPassword password, + Integer keyLength, + boolean encryptMetadata, + StandardDecrypter.EncryptionAlgorithm encryptionAlgorithm) + throws + PDFAuthenticationFailureException, + IOException, + EncryptionUnsupportedByPlatformException, + EncryptionUnsupportedByProductException { + + if (keyLength == null) { + keyLength = DEFAULT_KEY_LENGTH; + } + + // R describes the revision of the security handler + final PDFObject rObj = encryptDict.getDictRef("R"); + if (rObj == null) { + throw new PDFParseException( + "No R entry present in Encrypt dictionary"); + } + + final int revision = rObj.getIntValue(); + if (revision < 2 || revision > 4) { + throw new EncryptionUnsupportedByPlatformException( + "Unsupported Standard security handler revision; R=" + + revision); + } + + // O describes validation details for the owner key + final PDFObject oObj = encryptDict.getDictRef("O"); + if (oObj == null) { + throw new PDFParseException( + "No O entry present in Encrypt dictionary"); + } + final byte[] o = oObj.getStream(); + if (o.length != 32) { + throw new PDFParseException("Expected owner key O " + + "value of 32 bytes; found " + o.length); + } + + // U describes validation details for the user key + final PDFObject uObj = encryptDict.getDictRef("U"); + if (uObj == null) { + throw new PDFParseException( + "No U entry present in Encrypt dictionary"); + } + final byte[] u = uObj.getStream(); + if (u.length != 32) { + throw new PDFParseException( + "Expected user key U value of 32 bytes; found " + o.length); + } + + // P describes the permissions regarding document usage + final PDFObject pObj = encryptDict.getDictRef("P"); + if (pObj == null) { + throw new PDFParseException( + "Required P entry in Encrypt dictionary not found"); + } + + return new StandardDecrypter( + encryptionAlgorithm, documentId, keyLength, + revision, o, u, pObj.getIntValue(), encryptMetadata, password); + } + + /** + * @param encryptDict the Encrypt dict as found in the document's trailer. + * @return true if the Filter exist in the current dictionary + */ + public static boolean isFilterExist(PDFObject encryptDict) { + if (encryptDict != null) { + try { + PDFObject filter = encryptDict.getDictRef("Filter"); + return filter != null; + } catch (IOException e) { + } + } + return false; + } + +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/PDFPassword.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/PDFPassword.java new file mode 100644 index 000000000..7f953121b --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/PDFPassword.java @@ -0,0 +1,279 @@ +/* Copyright 2008 Pirion Systems Pty Ltd, 139 Warry St, + * Fortitude Valley, Queensland, Australia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package com.sun.pdfview.decrypt; + +import com.sun.pdfview.PDFDocCharsetEncoder; +import com.sun.pdfview.Identity8BitCharsetEncoder; +import com.sun.pdfview.PDFStringUtil; + +import java.util.*; +import java.nio.charset.CodingErrorAction; +import java.nio.charset.CharacterCodingException; +import java.nio.charset.CharsetEncoder; +import java.nio.CharBuffer; +import java.nio.ByteBuffer; + +/** + *

    Identifies a PDF Password, expressible either as a string or a + * byte sequence.

    + * + *

    In revisions up to version 1.e Expansion 3, the mapping between a string + * and the bytes corresponding to the password was poorly specified, meaning + * that the safest manner in which to specify a password was via a byte array. + * With 1.7 expansion 3, a still slightly problematic mapping was given for the + * Standard encryption algorithms through to version 4, and a very well + * specified mapping for the new version 5 encryption.

    + * + *

    So, for passwords specified in versions up to and including 4, a byte[] + * representation is the most accurate, but not necessarily the most convenient + * manner to provide passwords. For version 5, allowing passwords to be + * specified as Strings will be the preferred mechanism. Rather than specify two + * interfaces whenever a password can be provided - one for byte[] and one for + * String - we express the password as a class. This class can also offer a best + * guess at a String representation for a password for encryption versions up to + * and including 4.

    + * + * @author Luke Kirby + */ +public class PDFPassword { + + /** The empty password */ + public static final PDFPassword EMPTY_PASSWORD = + new PDFPassword(new byte[0]); + + /** + * Ensure a non-null PDFPassword by substituting the empty password + * for a null password + * @param password the password, may be null + * @return a non-null password + */ + public static PDFPassword nonNullPassword(PDFPassword password) { + return password != null ? password : EMPTY_PASSWORD; + } + + /** the password in bytes, if specified as such */ + private byte[] passwordBytes = null; + /** the passwird as a string, if specified as such */ + private String passwordString = null; + + /** + * Construct a byte-based password + * @param passwordBytes the password bytes + */ + public PDFPassword(byte[] passwordBytes) { + this.passwordBytes = + passwordBytes != null ? passwordBytes : new byte[0]; + } + + /** + * Construct a string-based password + * @param passwordString the password + */ + public PDFPassword(String passwordString) { + this.passwordString = passwordString != null ? passwordString : ""; + } + + /** + * Get the password bytes. + * + * @param unicodeConversion whether the specific conversion from a unicode + * String, as present for version 5 encryption, should be used + * @return a list of possible password bytes + */ + List getPasswordBytes(boolean unicodeConversion) { + // TODO - handle unicodeConversion when we support version 5 + if (this.passwordBytes != null || this.passwordString == null) { + return Collections.singletonList(this.passwordBytes); + } else { + if (isAlphaNum7BitString(this.passwordString)) { + // there's no reasonthat this string would get encoded + // in any other way + return Collections.singletonList( + PDFStringUtil.asBytes(this.passwordString)); + } else { + return generatePossiblePasswordBytes(this.passwordString); + } + } + } + + /** + * An array of password byte generators that attempts to enumerate the + * possible strategies that an encrypting application might take to convert + * a string to an array of bytes + */ + private final static PasswordByteGenerator[] PASSWORD_BYTE_GENERATORS = + new PasswordByteGenerator[]{ + + // The best option, and that recommended by the spec, is + // straight PDFDocEncoding of the string but its not + // mentioned what to do with undefined characters + // (presumably, an encryption generating app should not + // allow them, but there are no guarantees!). Plus, that + // hasn't always been the case. There's also a possiblity + // that we'll be presented with the byte encoding from + // whatever code page is default on the system that + // generated the password. I don't think we're going to try + // all different code pages, though. Here are + // a few ideas, anyway! + + // skip undefined chars + new PDFDocEncodingByteGenerator(null), + // replace undefined chars with 0 + new PDFDocEncodingByteGenerator(Byte.valueOf((byte) 0)), + // replace undefined chars with ? + new PDFDocEncodingByteGenerator(Byte.valueOf((byte) '?')), + // just strip the higher 8 bits! + new PasswordByteGenerator() { + @Override + public byte[] generateBytes(String password) { + return PDFStringUtil.asBytes(password); + } + }, + // skip 2-byte chars + new IdentityEncodingByteGenerator(null), + // replace 2-byte chars with 0 + new IdentityEncodingByteGenerator(Byte.valueOf((byte) 0)), + // replace 2-byte chars with ? + new IdentityEncodingByteGenerator(Byte.valueOf((byte) '?')) + }; + + /** + * Generate some possible byte representations of a string password + * + * @param passwordString the string password + * @return a list of unique possible byte representations + */ + private static List generatePossiblePasswordBytes( + String passwordString) { + + final List possibilties = new ArrayList(); + for (final PasswordByteGenerator generator : PASSWORD_BYTE_GENERATORS) { + byte[] generated = generator.generateBytes(passwordString); + // avoid duplicates + boolean alreadyGenerated = false; + for (int i = 0; !alreadyGenerated && i < possibilties.size(); ++i) { + if (Arrays.equals(possibilties.get(i), generated)) { + alreadyGenerated = true; + } + } + if (!alreadyGenerated) { + possibilties.add(generated); + } + } + return possibilties; + } + + private boolean isAlphaNum7BitString(String string) { + for (int i = 0; i < string.length(); ++i) { + final char c = string.charAt(i); + if (c >= 127 || !Character.isLetterOrDigit(c)) { + return false; + } + } + return true; + } + + /** + * Converts a string password to a byte[] representation + */ + private static interface PasswordByteGenerator { + byte[] generateBytes(String password); + } + + /** + * Converts strings to byte by employing a {@link CharsetEncoder} and a + * configurable mechanism to replace or ignore characters that are + * unrepresentable according to the encoder. + */ + private static abstract class CharsetEncoderGenerator + implements PasswordByteGenerator { + + private Byte replacementByte; + + /** + * Class constructor + * + * @param replacementByte the byte to replace to use to represent any + * unrepresentable character, or null if unrepresentable characters + * should just be ignored + */ + protected CharsetEncoderGenerator(Byte replacementByte) { + this.replacementByte = replacementByte; + } + + + @Override + public byte[] generateBytes(String password) { + final CharsetEncoder encoder = createCharsetEncoder(); + if (this.replacementByte != null) { + encoder.replaceWith(new byte[]{this.replacementByte}); + encoder.onUnmappableCharacter(CodingErrorAction.REPLACE); + } else { + encoder.onUnmappableCharacter(CodingErrorAction.IGNORE); + } + try { + final ByteBuffer b = encoder.encode(CharBuffer.wrap(password)); + final byte[] bytes = new byte[b.remaining()]; + b.get(bytes); + return bytes; + } catch (CharacterCodingException e) { + // shouldn't happen: unmappable characters should be the only + // problem, and we're not handling them with a report + return null; + } + } + + protected abstract CharsetEncoder createCharsetEncoder(); + + } + + /** + * Generate byte[] representations based on the PDFDocEncoding + */ + private static class PDFDocEncodingByteGenerator + extends CharsetEncoderGenerator { + + private PDFDocEncodingByteGenerator(Byte replacementByte) { + super(replacementByte); + } + + @Override + protected CharsetEncoder createCharsetEncoder() { + return new PDFDocCharsetEncoder(); + } + } + + /** + * Generate byte[] representations based on a Unicode code point identity + * encoding; characters over 255 in value are considered unrepresentable + */ + private static class IdentityEncodingByteGenerator + extends CharsetEncoderGenerator { + + private IdentityEncodingByteGenerator(Byte replacementByte) { + super(replacementByte); + } + + @Override + protected CharsetEncoder createCharsetEncoder() { + return new Identity8BitCharsetEncoder(); + } + } + +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/StandardDecrypter.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/StandardDecrypter.java new file mode 100644 index 000000000..b67296e3c --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/StandardDecrypter.java @@ -0,0 +1,1137 @@ +/* Copyright 2008 Pirion Systems Pty Ltd, 139 Warry St, + * Fortitude Valley, Queensland, Australia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package com.sun.pdfview.decrypt; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.security.GeneralSecurityException; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Arrays; +import java.util.List; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.SecretKey; +import javax.crypto.ShortBufferException; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +import com.sun.pdfview.PDFObject; +import com.sun.pdfview.PDFParseException; +import com.sun.pdfview.PDFStringUtil; + +/** + * Standard simple decrypter for versions 1, 2 and 4 of the Standard + * password-based decryption mechanisms, as described in section 3.5 of + * the PDF Reference version 1.7. + * + * @author Luke Kirby + */ +public class StandardDecrypter implements PDFDecrypter { + + /** + * Extra salt to add to AES-based decryption keys, as per PDF Reference 1.7 + */ + private static final byte[] AESV2_SALT = {'s', 'A', 'l', 'T'}; + + /** + * Describes an encryption algorithm to be used, declaring not only the + * cipher type, but also key generation techniques + */ + public enum EncryptionAlgorithm { + RC4, AESV2; + + boolean isRC4() { + return this == RC4; + } + + boolean isAES() { + return this == AESV2; + } + + } + + /** + * Padding used to bring passwords up to 32 bytes, as specified by the + * first step of Algorithm 3.2 in the PDF Reference version 1.7. + */ + private final static byte[] PW_PADDING = new byte[]{ + 0x28, (byte) 0xBF, 0x4E, 0x5E, 0x4E, 0x75, (byte) 0x8A, 0x41, + 0x64, 0x00, 0x4E, 0x56, (byte) 0xFF, (byte) 0xFA, 0x01, 0x08, + 0x2E, 0x2E, 0x00, (byte) 0xB6, (byte) 0xD0, 0x68, 0x3E, (byte) 0x80, + 0x2F, 0x0C, (byte) 0xA9, (byte) 0xFE, 0x64, 0x53, 0x69, 0x7A + }; + + /** + * The specification of the RC4 cipher for JCE interactions + */ + private static final String CIPHER_RC4 = "RC4"; + /** + * The key type for RC4 keys + */ + private static final String KEY_RC4 = "RC4"; + + /** + * The specification of the AES cipher for JCE interactions. As per the + * spec, cipher-block chanining (CBC) mode and PKCS5 padding are used + */ + private static final String CIPHER_AES = "AES/CBC/PKCS5Padding"; + /** + * The key type for AES keys + */ + private static final String KEY_AES = "AES"; + + /** + * Whether the owner password was specified + */ + private boolean ownerAuthorised = false; + + /** + * The general encryption key; may be mutated to form individual + * stream/string encryption keys + */ + private byte[] generalKeyBytes; + + /** + * The encryption algorithm being employed + */ + private EncryptionAlgorithm encryptionAlgorithm; + + /** + * Class constructor + * + * @param encryptionAlgorithm the algorithm used for encryption + * @param documentId the contents of the ID entry of the document's trailer + * dictionary; can be null, but according to the spec, shouldn't be. Is + * expected to be an array of two byte sequences. + * @param keyBitLength the length of the key in bits; should be a multiple + * of 8 between 40 and 128 + * @param revision the revision of the Standard encryption security handler + * being employed. Should be 2, 3 or 4. + * @param oValue the value of the O entry from the Encrypt dictionary + * @param uValue the value of the U entry from the Encrypt dictionary + * @param pValue the value of the P entry from the Encrypt dictionary + * @param encryptMetadata whether metadata is being encrypted, as identified + * by the Encrypt dict (with default true if not explicitly identified) + * @param password the password; not null + * @throws IOException if there's a problem reading the file + * @throws EncryptionUnsupportedByPlatformException if the encryption is not + * supported by the environment in which the code is executing + * @throws EncryptionUnsupportedByProductException if PDFRenderer does not + * currently support the specified encryption + */ + public StandardDecrypter( + EncryptionAlgorithm encryptionAlgorithm, + PDFObject documentId, int keyBitLength, + int revision, byte[] oValue, byte[] uValue, int pValue, + boolean encryptMetadata, PDFPassword password) + throws + IOException, + EncryptionUnsupportedByProductException, + EncryptionUnsupportedByPlatformException { + + this.encryptionAlgorithm = encryptionAlgorithm; + + // The spec (sensibly) demands that the documentId be present, + // but we'll play it safe + final byte[] firstDocIdValue; + if (documentId == null) { + firstDocIdValue = null; + } else { + firstDocIdValue = documentId.getAt(0).getStream(); + } + + testJceAvailability(keyBitLength); + + try { + final List passwordBytePossibilities = + password.getPasswordBytes(false); + for (int i = 0; + this.generalKeyBytes == null && i < passwordBytePossibilities.size(); + ++i) { + final byte[] passwordBytes = passwordBytePossibilities.get(i); + this.generalKeyBytes = checkOwnerPassword( + passwordBytes, firstDocIdValue, keyBitLength, + revision, oValue, uValue, pValue, encryptMetadata); + if (this.generalKeyBytes != null) { + // looks like the password was the owner password! + this.ownerAuthorised = true; + } else { + // try it as the user password + this.generalKeyBytes = checkUserPassword( + passwordBytes, firstDocIdValue, keyBitLength, + revision, oValue, uValue, pValue, encryptMetadata); + + } + } + } catch (GeneralSecurityException e) { + // Unexpected, as our test of JCE availability should have caught + // problems with cipher availability. + // It may well be a problem with document content? + throw new PDFParseException("Unable to check passwords: " + + e.getMessage(), e); + } + + if (this.generalKeyBytes == null) { + throw new PDFAuthenticationFailureException( + "Password failed authentication for both " + + "owner and user password"); + } + + } + + @Override + public ByteBuffer decryptBuffer( + String cryptFilterName, PDFObject streamObj, ByteBuffer streamBuf) + throws PDFParseException { + + if (cryptFilterName != null) { + throw new PDFParseException( + "This encryption version does not support Crypt filters"); + } + + if (streamObj != null) { + checkNums(streamObj.getObjNum(), streamObj.getObjGen()); + } + + final byte[] decryptionKeyBytes; + if (streamObj == null) { + // lack of a stream object indicates the unsalted key should be + // used + decryptionKeyBytes = getUnsaltedDecryptionKey(); + } else { + decryptionKeyBytes = getObjectSaltedDecryptionKey( + streamObj.getObjNum(), streamObj.getObjGen()); + } + return decryptBuffer(streamBuf, decryptionKeyBytes); + } + + @Override + public String decryptString(int objNum, int objGen, String inputBasicString) + throws PDFParseException { + final byte[] crypted = PDFStringUtil.asBytes(inputBasicString); + final byte[] decryptionKey = getObjectSaltedDecryptionKey(objNum, objGen); + final ByteBuffer decrypted = decryptBuffer(ByteBuffer.wrap(crypted), decryptionKey); + return PDFStringUtil.asBasicString(decrypted.array(), decrypted.arrayOffset(), decrypted.limit()); + } + + @Override + public boolean isOwnerAuthorised() { + return this.ownerAuthorised; + } + + @Override + public boolean isEncryptionPresent() { + return true; + } + + @Override + public boolean isEncryptionPresent(String cryptFilterName) { + return true; + } + + /** + * Test that the platform (i.e., the JCE) can offer us all of the ciphers at + * the key length we need for content decryption. This shouldn't be a + * problem on the Java 5 platform unless a particularly restrictive policy + * file is in place. Calling this on construction should avoid problems like + * these being exposed as PDFParseExceptions as they're used during + * decryption and key establishment. + * + * @param keyBitLength the length of the content key, in bits + * @throws EncryptionUnsupportedByPlatformException if the platform does not + * support the required ciphers and key lengths + * @throws PDFParseException if there's an internal error while testing + * cipher availability + */ + private void testJceAvailability(int keyBitLength) + throws + EncryptionUnsupportedByPlatformException, PDFParseException { + + // we need to supply a little buffer for AES, which will look + // for an initialisation vector of 16 bytes + final byte[] junkBuffer = new byte[16]; + Arrays.fill(junkBuffer, (byte) 0xAE); + // test using the longer key length for salted content so that + // we can check for maximum key length problems + final byte[] junkKey = + new byte[getSaltedContentKeyByteLength(keyBitLength / 8)]; + Arrays.fill(junkKey, (byte) 0xAE); + + try { + createAndInitialiseContentCipher( + ByteBuffer.wrap(junkBuffer), + junkKey); + } catch (PDFParseException e) { + throw new PDFParseException("Internal error; " + + "failed to produce test cipher: " + e.getMessage()); + } catch (NoSuchAlgorithmException e) { + throw new EncryptionUnsupportedByPlatformException( + "JCE does not offer required cipher", e); + } catch (NoSuchPaddingException e) { + throw new EncryptionUnsupportedByPlatformException( + "JCE does not offer required padding", e); + } catch (InvalidKeyException e) { + throw new EncryptionUnsupportedByPlatformException( + "JCE does accept key size of " + + (getSaltedContentKeyByteLength() * 8) + + " bits- could it be a policy restriction?", e); + } catch (InvalidAlgorithmParameterException e) { + throw new EncryptionUnsupportedByPlatformException( + "JCE did not accept cipher parameter", e); + } + + try { + createMD5Digest(); + } catch (NoSuchAlgorithmException e) { + throw new EncryptionUnsupportedByPlatformException( + "No MD5 digest available from JCE", e); + } + + if (this.encryptionAlgorithm != EncryptionAlgorithm.RC4) { + // we still need RC4 for U and O value checks. Check again! + final Cipher rc4; + try { + rc4 = createRC4Cipher(); + } catch (GeneralSecurityException e) { + throw new EncryptionUnsupportedByPlatformException( + "JCE did not offer RC4 cipher", e); + } + // 40 byte key is used for base U and O ciphers + final byte[] rc4JunkKey = new byte[5]; + Arrays.fill(junkKey, (byte) 0xAE); + try { + initDecryption(rc4, createRC4Key(rc4JunkKey)); + } catch (InvalidKeyException ex) { + throw new EncryptionUnsupportedByPlatformException( + "JCE did not accept 40-bit RC4 key; " + + "policy problem?", + ex); + } + } + } + + /** + * Decrypt a buffer + * + * @param encrypted the encrypted content + * @param decryptionKeyBytes the key to use for decryption + * @return a freshly allocated buffer containing the decrypted content + * @throws PDFParseException if there's a problem decrypting the content + */ + private ByteBuffer decryptBuffer( + ByteBuffer encrypted, byte[] decryptionKeyBytes) + throws PDFParseException { + + final Cipher cipher; + try { + cipher = createAndInitialiseContentCipher( + encrypted, decryptionKeyBytes); + } catch (GeneralSecurityException e) { + // we should have caught this earlier in testCipherAvailability + throw new PDFParseException( + "Unable to create cipher due to platform limitation: " + + e.getMessage(), e); + } + + try { + // the decrypted content will never be more than the encrypted + // content. Thanks to padding, this buffer will be at most 16 + // bytes bigger than the encrypted content + final ByteBuffer decryptedBuf = + ByteBuffer.allocate(encrypted.remaining()); + cipher.doFinal(encrypted, decryptedBuf); + decryptedBuf.flip(); + return decryptedBuf; + } catch (GeneralSecurityException e) { + throw new PDFParseException( + "Could not decrypt: " + e.getMessage(), e); + } + } + + /** + * Setup the cipher for decryption + * + * @param encrypted the encrypted content; required by AES encryption so + * that the initialisation vector can be established + * @param decryptionKeyBytes the bytes for the decryption key + * @return a content decryption cypher, ready to accept input + * @throws PDFParseException if the encrypted buffer is malformed or on an + * internal error + * @throws NoSuchAlgorithmException if the cipher algorithm is not supported + * by the platform + * @throws NoSuchPaddingException if the cipher padding is not supported by + * the platform + * @throws InvalidKeyException if the key is invalid according to the + * cipher, or too long + * @throws InvalidAlgorithmParameterException if the cipher parameters are + * bad + */ + private Cipher createAndInitialiseContentCipher( + ByteBuffer encrypted, + byte[] decryptionKeyBytes) + throws + PDFParseException, + NoSuchAlgorithmException, + NoSuchPaddingException, + InvalidKeyException, + InvalidAlgorithmParameterException { + + final Cipher cipher; + if (this.encryptionAlgorithm.isRC4()) { + cipher = Cipher.getInstance(CIPHER_RC4); + cipher.init(Cipher.DECRYPT_MODE, createRC4Key(decryptionKeyBytes)); + } else if (this.encryptionAlgorithm.isAES()) { + cipher = createAESCipher(); + final byte[] initialisationVector = new byte[16]; + if (encrypted.remaining() >= initialisationVector.length) { + encrypted.get(initialisationVector); + } else { + throw new PDFParseException( + "AES encrypted stream too short - " + + "no room for initialisation vector"); + } + + final SecretKeySpec aesKey = + new SecretKeySpec(decryptionKeyBytes, KEY_AES); + final IvParameterSpec aesIv = + new IvParameterSpec(initialisationVector); + cipher.init(Cipher.DECRYPT_MODE, aesKey, aesIv); + } else { + throw new PDFParseException( + "Internal error - unhandled cipher type: " + + this.encryptionAlgorithm); + } + return cipher; + } + + /** + * Get the unsalted content decryption key, used for streams with specific + * crypt filters, which aren't specific to particular objects + * + * @return the general key + */ + private byte[] getUnsaltedDecryptionKey() { + return this.generalKeyBytes; + } + + /** + * Get a decryption key salted with an object number and object generation, + * for use when decrypting a string or stream within an object numbered so + * + * @param objNum the object number + * @param objGen the object generation + * @return the key to be used for decrypting data associated with the object + * numbered so + * @throws PDFParseException if the MD5 digest is not available + */ + private byte[] getObjectSaltedDecryptionKey(int objNum, int objGen) + throws PDFParseException { + + byte[] decryptionKeyBytes; + final MessageDigest md5; + try { + md5 = createMD5Digest(); + } catch (NoSuchAlgorithmException e) { + // unexpected, as we will already have tested availability + throw new PDFParseException("Unable to get MD5 digester", e); + } + md5.update(this.generalKeyBytes); + md5.update((byte) objNum); + md5.update((byte) (objNum >> 8)); + md5.update((byte) (objNum >> 16)); + md5.update((byte) objGen); + md5.update((byte) (objGen >> 8)); + if (this.encryptionAlgorithm == EncryptionAlgorithm.AESV2) { + md5.update(AESV2_SALT); + } + final byte[] hash = md5.digest(); + final int keyLen = getSaltedContentKeyByteLength(); + decryptionKeyBytes = new byte[keyLen]; + System.arraycopy(hash, 0, decryptionKeyBytes, 0, keyLen); + return decryptionKeyBytes; + } + + /** + * Get the length of a salted key + * + * @return length in bytes + */ + private int getSaltedContentKeyByteLength() { + return getSaltedContentKeyByteLength(this.generalKeyBytes.length); + } + + /** + * Get the length of salted keys, in bytes. Unsalted keys will be the same + * length as {@link #generalKeyBytes} + * + * @param generalKeyByteLength the length of the general key, in bytes + * @return byte length of salted keys + */ + private int getSaltedContentKeyByteLength(int generalKeyByteLength) { + return Math.min(generalKeyByteLength + 5, 16); + } + + /** + * Check that object number and object generations are well-formed. It is + * possible for some {@link PDFObject}s to have uninitialised object numbers + * and generations, but such objects should not required decryption + * + * @param objNum the object number + * @param objGen the object generation + * @throws PDFParseException if the object numbering indicates that they + * aren't true object numbers + */ + private void checkNums(int objNum, int objGen) + throws PDFParseException { + if (objNum < 0) { + throw new PDFParseException( + "Internal error: Object has bogus object number"); + } else if (objGen < 0) { + throw new PDFParseException( + "Internal error: Object has bogus generation number"); + } + } + + /** + * Calculate what the U value should consist of given a particular key and + * document configuration. Correponds to Algorithms 3.4 and 3.5 of the + * PDF Reference version 1.7 + * + * @param generalKey the general encryption key + * @param firstDocIdValue the value of the first element in the document's + * ID entry in the trailer dictionary + * @param revision the revision of the security handler + * @return the U value for the given configuration + * @throws GeneralSecurityException if there's an error getting required + * ciphers, etc. (unexpected, since a check for algorithm availability is + * performed on construction) + * @throws EncryptionUnsupportedByProductException if the revision is not + * supported + */ + private byte[] calculateUValue( + byte[] generalKey, byte[] firstDocIdValue, int revision) + throws + GeneralSecurityException, + EncryptionUnsupportedByProductException { + + if (revision == 2) { + + // Algorithm 3.4: Computing the encryption dictionary’s U (user + // password) value (Revision 2) + + // Step 1 is provided to us as the parameter generalKey: + // Create an encryption key based on the user password string, as + // described in Algorithm 3.2 + + // Step 2: Encrypt the 32-byte padding string shown in step 1 of + // Algorithm 3.2, using an RC4 encryption function with the + // encryption key from the preceding step. + + Cipher rc4 = createRC4Cipher(); + SecretKey key = createRC4Key(generalKey); + initEncryption(rc4, key); + return crypt(rc4, PW_PADDING); + + } else if (revision >= 3) { + + // Algorithm 3.5: Computing the encryption dictionary’s U (user + // password) value (Revision 3 or greater) + + // Step 1 is provided to us as the parameter generalKey: + // Create an encryption key based on the user password string, as + // described in Algorithm 3.2 + + // Step 2: Initialize the MD5 hash function and pass the 32-byte + // padding string shown in step 1 of Algorithm 3.2 as input to this + // function + MessageDigest md5 = createMD5Digest(); + md5.update(PW_PADDING); + + // Step 3: Pass the first element of the file’s file identifier + // array (the value of the ID entry in the document’s trailer + // dictionary; see Table 3.13 on page 97) to the hash function and + // finish the hash. (See implementation note 26 in Appendix H.) + if (firstDocIdValue != null) { + md5.update(firstDocIdValue); + } + final byte[] hash = md5.digest(); + + // Step 4: Encrypt the 16-byte result of the hash, using an RC4 + // encryption function with the encryption key from step 1. + Cipher rc4 = createRC4Cipher(); + SecretKey key = createRC4Key(generalKey); + initEncryption(rc4, key); + final byte[] v = crypt(rc4, hash); + + // Step 5: Do the following 19 times: Take the output from the + // previous invocation of the RC4 function and pass it as input to + // a new invocation of the function; use an encryption key generated + // by taking each byte of the original encryption key (obtained in + // step 1) and performing an XOR (exclusive or) operation between + // that byte and the single-byte value of the iteration counter + // (from 1 to 19). + rc4shuffle(v, generalKey, rc4); + + // Step 6: Append 16 bytes of arbitrary padding to the output from + // the final invocation of the RC4 function and store the 32-byte + // result as the value of the U entry in the encryption dictionary. + assert v.length == 16; + final byte[] entryValue = new byte[32]; + System.arraycopy(v, 0, entryValue, 0, v.length); + System.arraycopy(v, 0, entryValue, 16, v.length); + return entryValue; + + } else { + throw new EncryptionUnsupportedByProductException( + "Unsupported standard security handler revision " + + revision); + } + } + + /** + * Calculate what the O value of the Encrypt dict should look like given a + * particular configuration. Not used, but useful for reference; this + * process is reversed to determine whether a given password is the + * owner password. Corresponds to Algorithm 3.3 of the PDF Reference + * version 1.7. + * + * @see #checkOwnerPassword + * @param ownerPassword the owner password + * @param userPassword the user password + * @param keyBitLength the key length in bits (40-128) + * @param revision the security handler revision + * @return the O value entry + * @throws GeneralSecurityException if ciphers are unavailable or + * inappropriately used + */ + private byte[] calculuateOValue( + byte[] ownerPassword, byte[] userPassword, + int keyBitLength, int revision) + throws GeneralSecurityException { + + // Steps 1-4 + final byte[] rc4KeyBytes = + getInitialOwnerPasswordKeyBytes( + ownerPassword, keyBitLength, revision); + final Cipher rc4 = createRC4Cipher(); + initEncryption(rc4, createRC4Key(rc4KeyBytes)); + + // Step 5: Pad or truncate the user password string as described in step + // 1 of Algorithm 3.2. + // Step 6: Encrypt the result of step 5, using an RC4 encryption + // function with the encryption key obtained in step 4. + byte[] pwvalue = crypt(rc4, padPassword(userPassword)); + + // Step 7: (Revision 3 or greater) Do the following 19 times: Take the + // output from the previous invocation of the RC4 function and pass it + // as input to a new invocation of the function; use an encryption key + // generated by taking each byte of the encryption key obtained in step + // 4 and performing an XOR (exclusive or) operation between + if (revision >= 3) { + rc4shuffle(pwvalue, rc4KeyBytes, rc4); + } + assert pwvalue.length == 32; + return pwvalue; + + } + + /** + * Check to see whether a given password is the owner password. Corresponds + * to algorithm 3.6 of PDF Reference version 1.7. + * + * @param ownerPassword the suggested owner password (may be null or + * empty) + * @param firstDocIdValue the byte stream from the first element of the + * value of the ID entry in the trailer dictionary + * @param keyBitLength the key length in bits + * @param revision the security handler revision + * @param oValue the O value from the Encrypt dictionary + * @param uValue the U value from the Encrypt dictionary + * @param pValue the P value from the Encrypt dictionary + * @param encryptMetadata the EncryptMetadata entry from the Encrypt dictionary + * (or false if not present or revision <= 3) + * @return the general/user key bytes if the owner password is currect, + * null otherwise + * @throws GeneralSecurityException if there's a problem with + * cipher or digest usage; unexpected + * @throws EncryptionUnsupportedByProductException if PDFRenderer doesn't + * support the security handler revision + * @throws PDFParseException if the document is malformed + */ + private byte[] checkOwnerPassword( + byte[] ownerPassword, byte[] firstDocIdValue, int keyBitLength, + int revision, byte[] oValue, byte[] uValue, int pValue, + boolean encryptMetadata) + throws + GeneralSecurityException, + EncryptionUnsupportedByProductException, + PDFParseException { + + // Step 1: Compute an encryption key from the supplied password string, + // as described in steps 1 to 4 of Algorithm 3.3. + final byte[] rc4KeyBytes = + getInitialOwnerPasswordKeyBytes(ownerPassword, + keyBitLength, revision); + final Cipher rc4 = createRC4Cipher(); + initDecryption(rc4, createRC4Key(rc4KeyBytes)); + + // Step 2: + final byte[] possibleUserPassword; + if (revision == 2) { + // (Revision 2 only) Decrypt the value of the encryption + // dictionary’s O entry, using an RC4 encryption function with the + // encryption key computed in step 1. + + possibleUserPassword = crypt(rc4, oValue); + } else if (revision >= 3) { + // (Revision 3 or greater) Do the following 20 times: Decrypt the + // value of the encryption dictionary’s O entry (first iteration) or + // the output from the previous iteration (all subsequent + // iterations), using an RC4 encryption function with a different + // encryption key at each iteration. The key is generated by taking + // the original key (obtained in step 1) and performing an XOR + // (exclusive or) operation between each byte of the key and the + // single-byte value of the iteration counter (from 19 to 0). + + // unshuffle the O entry; the unshuffle operation also + // contains the final decryption with the original key + possibleUserPassword = new byte[32]; + System.arraycopy(oValue, 0, possibleUserPassword, 0, + possibleUserPassword.length); + rc4unshuffle(rc4, possibleUserPassword, rc4KeyBytes); + } else { + throw new EncryptionUnsupportedByProductException( + "Unsupported revision: " + revision); + } + + // Step 3: The result of step 2 purports to be the user password. + // Authenticate this user password using Algorithm 3.6. If it is + // correct, the password supplied is the correct owner password. + return checkUserPassword( + possibleUserPassword, firstDocIdValue, keyBitLength, + revision, oValue, uValue, pValue, encryptMetadata); + + } + + /** + * Establish the key to be used for the generation and validation + * of the user password via the O entry. Corresponds to steps 1-4 in + * Algorithm 3.3 of the PDF Reference version 1.7. + * @param ownerPassword the owner password + * @param keyBitLength the length of the key in bits + * @param revision the security handler revision + * @return the key bytes to use for generation/validation of the O entry + * @throws GeneralSecurityException if there's a problem wranling ciphers + */ + private byte[] getInitialOwnerPasswordKeyBytes( + byte[] ownerPassword, int keyBitLength, int revision) + throws GeneralSecurityException { + + final MessageDigest md5 = createMD5Digest(); + + // Step 1: Pad or truncate the owner password string as described in + // step 1 of Algorithm 3.2. If there is no owner password, use the user + // password instead. (See implementation note 27 in Appendix H.) + // Step 2: Initialize the MD5 hash function and pass the result of step 1 as + // input to this function. + md5.update(padPassword(ownerPassword)); + + // Step 3.(Revision 3 or greater) Do the following 50 times: Take the + // output from the previous MD5 hash and pass it as input into a new MD5 + // hash + final byte[] hash = md5.digest(); + if (revision >= 3) { + for (int i = 0; i < 50; ++i) { + md5.update(hash); + digestTo(md5, hash); + } + } + + // Step 4: Create an RC4 encryption key using the first n bytes of + // the output from the final MD5 hash, where n is always 5 for revision + // 2 but, for revision 3 or greater, depends on the value of the + // encryption dictionary’s Length entry + final byte[] rc4KeyBytes = new byte[keyBitLength / 8]; + System.arraycopy(hash, 0, rc4KeyBytes, 0, rc4KeyBytes.length); + return rc4KeyBytes; + } + + /** + * Check to see whether a provided user password is correct with respect + * to an Encrypt dict configuration. Corresponds to algorithm 3.6 of + * the PDF Reference version 1.7 + * @param userPassword the user password to test; may be null or empty + * @param firstDocIdValue the byte stream from the first element of the + * value of the ID entry in the trailer dictionary + * @param keyBitLength the length of the key in bits + * @param revision the security handler revision + * @param oValue the O value from the Encrypt dictionary + * @param uValue the U value from the Encrypt dictionary + * @param pValue the P value from the Encrypt dictionary + * @param encryptMetadata the EncryptMetadata entry from the Encrypt dictionary + * (or false if not present or revision <= 3) + * @return the general/user encryption key if the user password is correct, + * or null if incorrect + * @throws GeneralSecurityException if there's a problem with + * cipher or digest usage; unexpected + * @throws EncryptionUnsupportedByProductException if PDFRenderer doesn't + * support the security handler revision + * @throws PDFParseException if the document is improperly constructed + */ + private byte[] checkUserPassword( + byte[] userPassword, byte[] firstDocIdValue, int keyBitLength, + int revision, byte[] oValue, byte[] uValue, int pValue, + boolean encryptMetadata) + throws + GeneralSecurityException, + EncryptionUnsupportedByProductException, + PDFParseException { + + // Algorithm 3.6: Authenticating the user password + + // Step 1: Perform all but the last step of Algorithm 3.4 (Revision 2) + // or Algorithm 3.5 (Revision 3 or greater) using the supplied password + // string + // + // I.e., figure out what the general key would be with the + // given password + // Algorithm 3.4/5,Step1: + // Determine general key based on user password, as per Algorithm 3.2 + final byte[] generalKey = calculateGeneralEncryptionKey( + userPassword, firstDocIdValue, keyBitLength, + revision, oValue, pValue, encryptMetadata); + // Algorithm 3.4/5,RemainingSteps: + final byte[] calculatedUValue = + calculateUValue(generalKey, firstDocIdValue, revision); + + // Step 2: If the result of step 1 is equal to the value of the + // encryption dictionary’s U entry (comparing on the first 16 bytes in + // the case of Revision 3 or greater), the password supplied is the + // correct user password. The key obtained in step 1 (that is, in the + // first step of Algorithm 3.4 or 3.5) can be used to decrypt the + // document using Algorithm 3.1 on page 119. + assert calculatedUValue.length == 32; + if (uValue.length != calculatedUValue.length) { + throw new PDFParseException("Improper U entry length; " + + "expected 32, is " + uValue.length); + } + // Only the first 16 bytes are significant if using revision > 2 + final int numSignificantBytes = revision == 2 ? 32 : 16; + for (int i = 0; i < numSignificantBytes; ++i) { + if (uValue[i] != calculatedUValue[i]) { + return null; + } + } + return generalKey; + } + + + /** + * Determine what the general encryption key is, given a configuration. This + * corresponds to Algorithm 3.2 of PDF Reference version 1.7. + * + * @param userPassword the desired user password; may be null or empty + * @param firstDocIdValue the byte stream from the first element of the + * value of the ID entry in the trailer dictionary + * @param keyBitLength the length of the key in bits + * @param revision the security handler revision + * @param oValue the O value from the Encrypt dictionary + * @param pValue the P value from the Encrypt dictionary + * @param encryptMetadata the EncryptMetadata entry from the Encrypt + * dictionary (or false if not present or revision <= 3) + * @return the general encryption key + * @throws GeneralSecurityException if an error occurs when obtaining + * and operating ciphers/digests + */ + private byte[] calculateGeneralEncryptionKey( + byte[] userPassword, byte[] firstDocIdValue, int keyBitLength, + int revision, byte[] oValue, int pValue, boolean encryptMetadata) + throws GeneralSecurityException { + + // Algorithm 3.2: Computing an encryption key + + // Step 1: Pad or truncate the password string to exactly 32 bytes... + final byte[] paddedPassword = padPassword(userPassword); + + // Step 2: Initialize the MD5 hash function and pass the result of step + // 1 as input to this function. + MessageDigest md5 = createMD5Digest(); + md5.reset(); + md5.update(paddedPassword); + + // Step 3: Pass the value of the encryption dictionary’s O entry to the + // MD5 hash function. (Algorithm 3.3 shows how the O value is computed.) + md5.update(oValue); + + // Step 4: Treat the value of the P entry as an unsigned 4-byte integer + // and pass these bytes to the MD5 hash function, low-order byte first + md5.update((byte) (pValue & 0xFF)); + md5.update((byte) ((pValue >> 8) & 0xFF)); + md5.update((byte) ((pValue >> 16) & 0xFF)); + md5.update((byte) (pValue >> 24)); + + // Step 5: Pass the first element of the file’s file identifier array + // (the value of the ID entry in the document’s trailer dictionary; see + // Table 3.13 on page 97) to the MD5 hash function. (See implementation + // note 26 in Appendix H.) + if (firstDocIdValue != null) { + md5.update(firstDocIdValue); + } + + // Step 6: (Revision 4 or greater) If document metadata is not being + // encrypted, pass 4 bytes with the value 0xFFFFFFFF to the MD5 hash + // function + if (revision >= 4 && !encryptMetadata) { + for (int i = 0; i < 4; ++i) { + md5.update((byte) 0xFF); + } + } + + // Step 7: finish the hash + byte[] hash = md5.digest(); + + final int keyLen = revision == 2 ? 5 : (keyBitLength / 8); + final byte[] key = new byte[keyLen]; + + // Step 8: (Revision 3 or greater) Do the following 50 times: Take the + // output from the previous MD5 hash and pass the first n bytes of the + // output as input into a new MD5 hash, where n is the number of bytes + // of the encryption key as defined by the value of the encryption + // dictionary’s Length entry + if (revision >= 3) { + for (int i = 0; i < 50; ++i) { + md5.update(hash, 0, key.length); + digestTo(md5, hash); + } + } + + // Set the encryption key to the first n bytes of the output from the + // final MD5 hash, where n is always 5 for revision 2 but, for revision + // 3 or greater, depends on the value of the encryption dictionary’s + // Length entry. + System.arraycopy(hash, 0, key, 0, key.length); + return key; + } + + /** + * Pad a password as per step 1 of Algorithm 3.2 of the PDF Reference + * version 1.7 + * @param password the password, may be null or empty + * @return the padded password, always 32 bytes long + */ + private byte[] padPassword(byte[] password) { + + if (password == null) { + password = new byte[0]; + } + + // Step 1: Pad or truncate the password string to exactly 32 bytes. If + // the password string is more than 32 bytes long, use only its first 32 + // bytes; if it is less than 32 bytes long, pad it by appending the + // required number of additional bytes from the beginning of the + // following padding string: + // < 28 BF 4E 5E 4E 75 8A 41 64 00 4E 56 FF FA 01 08 + // 2E 2E 00 B6 D0 68 3E 80 2F 0C A9 FE 64 53 69 7A > + // That is, if the password string is n bytes long, append the first 32 + // − n bytes of the padding string to the end of the password string. If + // the password string is empty (zero-length), meaning there is no user + // password, substitute the entire padding string in its place. + + byte[] padded = new byte[32]; + // limit password to 32 bytes + final int numContributingPasswordBytes = + password.length > padded.length ? + padded.length : password.length; + System.arraycopy(password, 0, padded, 0, numContributingPasswordBytes); + // Copy padding + if (password.length < padded.length) { + System.arraycopy(PW_PADDING, 0, padded, password.length, + padded.length - password.length); + } + return padded; + } + + /** + * Encrypt some bytes + * + * @param cipher the cipher + * @param input the plaintext + * @return the crypt text + * @throws BadPaddingException if there's bad padding + * @throws IllegalBlockSizeException if the block size is bad + */ + private byte[] crypt(Cipher cipher, byte[] input) + throws IllegalBlockSizeException, BadPaddingException { + return cipher.doFinal(input); + } + + /** + * Initialise a cipher for encryption + * + * @param cipher the cipher + * @param key the encryption key + * @throws InvalidKeyException if the key is invalid for the cipher + */ + private void initEncryption(Cipher cipher, SecretKey key) + throws InvalidKeyException { + cipher.init(Cipher.ENCRYPT_MODE, key); + } + + /** + * Shuffle some input using a series of RC4 encryptions with slight + * mutations of an given key per iteration. Shuffling happens in place. + * Refer to the documentation of the algorithm steps where this is called. + * + * @param shuffle the bytes to be shuffled + * @param key the original key + * @param rc4 the cipher to use + * @throws GeneralSecurityException if there's a problem with cipher + * operation + */ + private void rc4shuffle(byte[] shuffle, byte[] key, Cipher rc4) + throws GeneralSecurityException { + + final byte[] shuffleKey = new byte[key.length]; + for (int i = 1; i <= 19; ++i) { + for (int j = 0; j < shuffleKey.length; ++j) { + shuffleKey[j] = (byte) (key[j] ^ i); + } + initEncryption(rc4, createRC4Key(shuffleKey)); + cryptInPlace(rc4, shuffle); + } + } + + /** + * Reverse the {@link #rc4shuffle} operation, and the operation + * that invariable preceeds it, thereby obtaining an original message + * @param rc4 the RC4 cipher to use + * @param shuffle the bytes in which shuffling will take place; unshuffling + * happens in place + * @param key the encryption key + * @throws GeneralSecurityException if there's a problem with cipher + * operation + */ + private void rc4unshuffle(Cipher rc4, byte[] shuffle, byte[] key) + throws GeneralSecurityException { + + // there's an extra unshuffle at the end with the original key - + // this is why we end with i == 0, where the shuffle key will be the key + final byte[] shuffleKeyBytes = new byte[key.length]; + for (int i = 19; i >= 0; --i) { + for (int j = 0; j < shuffleKeyBytes.length; ++j) { + shuffleKeyBytes[j] = (byte) (key[j] ^ i); + } + initDecryption(rc4, createRC4Key(shuffleKeyBytes)); + cryptInPlace(rc4, shuffle); + } + } + + /** + * Encrypt/decrypt something in place + * @param rc4 the cipher to use; must be a stream cipher producing + * identical output length to input (e.g., RC4) + * @param buffer the buffer to read input from and write output to + * @throws IllegalBlockSizeException if an inappropriate cipher is used + * @throws ShortBufferException if an inappropriate cipher is used + * @throws BadPaddingException if an inappropriate cipher is used + */ + private void cryptInPlace(Cipher rc4, byte[] buffer) + throws IllegalBlockSizeException, ShortBufferException, BadPaddingException { + rc4.doFinal(buffer, 0, buffer.length, buffer); + } + + /** + * Setup a cipher for decryption + * @param cipher the cipher + * @param aKey the cipher key + * @throws InvalidKeyException if the key is of an unacceptable size or + * doesn't belong to the cipher + */ + private void initDecryption(Cipher cipher, Key aKey) + throws InvalidKeyException { + cipher.init(Cipher.DECRYPT_MODE, aKey); + } + + /** + * Create a new RC4 cipher. Should always be available for supported + * platforms. + * @return the cipher + * @throws NoSuchAlgorithmException if the RC4 cipher is unavailable + * @throws NoSuchPaddingException should not happen, as no padding + * is specified + */ + private Cipher createRC4Cipher() + throws NoSuchAlgorithmException, NoSuchPaddingException { + return Cipher.getInstance(CIPHER_RC4); + } + + /** + * Create a new AES cipher. Should always be available for supported + * platforms. + * @return the new cipher + * @throws NoSuchAlgorithmException if the AES cipher is unavailable + * @throws NoSuchPaddingException if the required padding is unavailable + */ + private Cipher createAESCipher() + throws NoSuchAlgorithmException, NoSuchPaddingException { + return Cipher.getInstance(CIPHER_AES); + } + + /** + * Create an MD5 digest. Should always be available for supported + * platforms. + * @return the MD5 digest + * @throws NoSuchAlgorithmException if the digest is not available + */ + private MessageDigest createMD5Digest() + throws NoSuchAlgorithmException { + return MessageDigest.getInstance("MD5"); + } + + /** + * Create an RC4 key + * + * @param keyBytes the bytes for the key + * @return the key + */ + private SecretKeySpec createRC4Key(byte[] keyBytes) { + return new SecretKeySpec(keyBytes, KEY_RC4); + } + + /** + * Hash into an existing byte array + * @param md5 the MD5 digest + * @param hash the hash destination + * @throws GeneralSecurityException if there's a problem hashing; e.g., + * if the buffer is too small + */ + private void digestTo(MessageDigest md5, byte[] hash) + throws GeneralSecurityException { + md5.digest(hash, 0, hash.length); + } + + +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/UnsupportedEncryptionException.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/UnsupportedEncryptionException.java new file mode 100644 index 000000000..62cd35ad2 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/UnsupportedEncryptionException.java @@ -0,0 +1,39 @@ +/* + * Copyright 2008 Pirion Systems Pty Ltd, 139 Warry St, + * Fortitude Valley, Queensland, Australia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package com.sun.pdfview.decrypt; + +/** + * Identifies that the specified encryption mechanism is not + * supported by this product or platform. + * + * @see EncryptionUnsupportedByPlatformException + * @see EncryptionUnsupportedByProductException + * @author Luke Kirby + */ +public abstract class UnsupportedEncryptionException extends Exception { + + protected UnsupportedEncryptionException(String message) { + super(message); + } + + protected UnsupportedEncryptionException(String message, Throwable cause) { + super(message, cause); + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/BuiltinFont.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/BuiltinFont.java new file mode 100644 index 000000000..99f149d4a --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/BuiltinFont.java @@ -0,0 +1,234 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.sun.pdfview.font; + +import java.awt.Font; +import java.io.IOException; +import java.io.InputStream; +import java.util.Map; +import java.util.Properties; + +import com.sun.pdfview.PDFObject; + +/** + * This class represents the 14 built-in fonts. It reads these fonts + * from files in the "res" directory, as specified in + * BaseNames.properties. + */ +public class BuiltinFont extends Type1Font { + + /** the properties file */ + private static Properties props; + /** the fonts themselves */ + private static Map fonts; + /** the names of the 14 base fonts */ + private static final String[] baseFonts = { + "Courier", "Courier-Bold", "Courier-BoldOblique", "Courier-Oblique", + "Helvetica", "Helvetica-Bold", "Helvetica-BoldOblique", + "Helvetica-Oblique", "Times-Roman", "Times-Bold", "Times-BoldItalic", + "Times-Italic", "Symbol", "ZapfDingbats" + }; + /** fonts others (e.g. Acrobad PDFWriter 3.02 for Windows) assume + * are there, even though they're not in the spec. Grrr... + * + * the format is + */ + private static final String[] mappedFonts = { + // map arial to helvetica + "Arial", "Helvetica", + "Arial,Bold", "Helvetica-Bold", + "Arial,BoldItalic", "Helvetica-BoldOblique", + "Arial,Italic", "Helvetica-Oblique", + // map ArialMT to Helvetica + "ArialMT", "Helvetica", + "Arial-BoldMT", "Helvetica-Bold", + "Arial-BoldItalicMT", "Helvetica-BoldOblique", + "Arial-ItalicMT", "Helvetica-Oblique", + // map TimesNewRoman to Times + "TimesNewRoman", "Times-Roman", + "TimesNewRoman,Bold", "Times-Bold", + "TimesNewRoman,BoldItalic", "Times-BoldItalic", + "TimesNewRoman,Italic", "Times-Italic", + // map TimesNewRomanPSMT to Times + "TimesNewRomanPSMT", "Times-Roman", + "TimesNewRomanPS-BoldMT", "Times-Bold", + "TimesNewRomanPS-BoldItalicMT", "Times-BoldItalic", + "TimesNewRomanPS-ItalicMT", "Times-Italic", + //Map some variants of Courier + "Courier,Bold", "Courier-Bold", + "Courier,BoldItalic", "Courier-BoldOblique", + "Courier,Italic", "Courier-Oblique", + // map CourierNew to Courier + "CourierNew", "Courier", + "CourierNew,Bold", "Courier-Bold", + "CourierNew,BoldItalic", "Courier-BoldOblique", + "CourierNew,Italic", "Courier-Oblique", + }; + + /** + * Create a new Builtin object based on the name of a built-in font + * + * This must be the name of one of the 14 built-in fonts! + * + * @param baseFont the name of the font, from the PDF file + * @param fontObj the object containing font information + */ + public BuiltinFont(String baseFont, PDFObject fontObj) throws IOException { + super(baseFont, fontObj, null); + + parseFont(baseFont); + } + + /** + * create a new BuiltingFont object based on a description of the + * font from the PDF file. Parse the description for key information + * and use that to generate an appropriate font. + */ + public BuiltinFont(String baseFont, PDFObject fontObj, + PDFFontDescriptor descriptor) + throws IOException { + super(baseFont, fontObj, descriptor); + + String fontName = descriptor.getFontName(); + + // check if it's one of the 14 base fonts + for (int i = 0; i < baseFonts.length; i++) { + if (fontName.equalsIgnoreCase(baseFonts[i])) { + parseFont(fontName); + return; + } + } + + // check if it's a mapped font + for (int i = 0; i < mappedFonts.length; i += 2) { + if (fontName.equalsIgnoreCase(mappedFonts[i])) { + parseFont(mappedFonts[i + 1]); + return; + } + } + + int flags = descriptor.getFlags(); + int style = ((flags & PDFFontDescriptor.FORCEBOLD) != 0) ? Font.BOLD : Font.PLAIN; + + if (fontName.indexOf("Bold") > 0) { + style |= Font.BOLD; + } + if ((descriptor.getItalicAngle() != 0) || + ((flags & (PDFFontDescriptor.SCRIPT | PDFFontDescriptor.ITALIC)) != 0)) { + style |= Font.ITALIC; + } + String name = null; + + if ((flags & PDFFontDescriptor.FIXED_PITCH) != 0) { // fixed width + if (((style & Font.BOLD) > 0) && ((style & Font.ITALIC) > 0)) { + name = "Courier-BoldOblique"; + } else if ((style & Font.BOLD) > 0) { + name = "Courier-Bold"; + } else if ((style & Font.ITALIC) > 0) { + name = "Courier-Oblique"; + } else { + name = "Courier"; + } + } else if ((flags & PDFFontDescriptor.SERIF) != 0) { // serif font + if (((style & Font.BOLD) > 0) && ((style & Font.ITALIC) > 0)) { + name = "Times-BoldItalic"; + } else if ((style & Font.BOLD) > 0) { + name = "Times-Bold"; + } else if ((style & Font.ITALIC) > 0) { + name = "Times-Italic"; + } else { + name = "Times-Roman"; + } + } else { + if (((style & Font.BOLD) > 0) && ((style & Font.ITALIC) > 0)) { + name = "Helvetica-BoldOblique"; + } else if ((style & Font.BOLD) > 0) { + name = "Helvetica-Bold"; + } else if ((style & Font.ITALIC) > 0) { + name = "Helvetica-Oblique"; + } else { + name = "Helvetica"; + } + } + + parseFont(name); + } + + /** + * Parse a font given only the name of a builtin font + */ + private void parseFont(String baseFont) throws IOException { + // load the base fonts properties files, if it isn't already loaded + if (props == null) { + props = new Properties(); + props.load(BuiltinFont.class.getResourceAsStream("/com/sun/pdfview/font/res/BaseFonts.properties")); + } + + // make sure we're a known font + if (!props.containsKey(baseFont + ".file")) { + throw new IllegalArgumentException("Unknown Base Font: " + baseFont); + } + + // get the font information from the properties file + String file = props.getProperty(baseFont + ".file"); + + // the size of the file + int length = Integer.parseInt(props.getProperty(baseFont + ".length")); + // the size of the unencrypted portion + int length1 = 0; + // the size of the encrypted portion + int length2 = 0; + + // read the data from the file + byte[] data = new byte[length]; + InputStream fontStream = NativeFont.class.getResourceAsStream("res/" + file); + int cur = 0; + while (cur < length) { + cur += fontStream.read(data, cur, length - cur); + } + fontStream.close(); + + // are we a pfb file? + if ((data[0] & 0xff) == 0x80) { + // read lengths from the file + length1 = (data[2] & 0xff); + length1 |= (data[3] & 0xff) << 8; + length1 |= (data[4] & 0xff) << 16; + length1 |= (data[5] & 0xff) << 24; + length1 += 6; + + length2 = (data[length1 + 2] & 0xff); + length2 |= (data[length1 + 3] & 0xff) << 8; + length2 |= (data[length1 + 4] & 0xff) << 16; + length2 |= (data[length1 + 5] & 0xff) << 24; + length1 += 6; + } else { + // get the values from the properties file + length1 = Integer.parseInt(props.getProperty(baseFont + ".length1")); + + if (props.containsKey(baseFont + ".length2")) { + length2 = Integer.parseInt(props.getProperty(baseFont + ".lenth2")); + } else { + length2 = length - length1; + } + } + + parseFont(data, length1, length2); + } +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/CIDFontType0.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/CIDFontType0.java new file mode 100644 index 000000000..f0eafee48 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/CIDFontType0.java @@ -0,0 +1,68 @@ +package com.sun.pdfview.font; + +import java.io.IOException; + +import com.sun.pdfview.PDFObject; +import com.sun.pdfview.font.cid.PDFCMap; +import com.sun.pdfview.font.ttf.AdobeGlyphList; + +/***************************************************************************** + * At the moment this is not fully supported to parse CID based fonts + * As a hack we try to use a built in font as substitution and use a + * toUnicode map to translate the characters if available. + * + * + * @version $Id: CIDFontType0.java,v 1.1 2011-08-03 15:48:56 bros Exp $ + * @author Bernd Rosstauscher + * @since 03.08.2011 + ****************************************************************************/ + +public class CIDFontType0 extends BuiltinFont { + + private PDFCMap glyphLookupMap; + + /************************************************************************* + * Constructor + * @param baseFont + * @param fontObj + * @param descriptor + * @throws IOException + ************************************************************************/ + + public CIDFontType0(String baseFont, PDFObject fontObj, + PDFFontDescriptor descriptor) throws IOException { + super(baseFont, fontObj, descriptor); + } + + /************************************************************************* + * @param fontObj + * @throws IOException + ************************************************************************/ + + public void parseToUnicodeMap(PDFObject fontObj) throws IOException { + PDFObject toUnicode = fontObj.getDictRef("ToUnicode"); + if (toUnicode != null) { + PDFCMap cmap = PDFCMap.getCMap(toUnicode); + this.glyphLookupMap = cmap; + } + } + + /** + * Get a character from the first font in the descendant fonts array + */ + @Override + protected PDFGlyph getGlyph(char src, String name) { + //TODO BROS 03.08.2011 Hack for unsupported Type0 CID based fonts + // If we have a toUnicodeMap then try to use that one when mapping to our build in font. + // See "9.10 Extraction of Text Content" in the PDF spec. + if (this.glyphLookupMap != null) { + src = this.glyphLookupMap.map(src); + //The preferred method of getting the glyph should be by name. + if (name == null && src != 160){//unless it NBSP + //so, try to find the name by the char + name = AdobeGlyphList.getGlyphName(src); + } + } + return super.getGlyph(src, name); + } +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/CIDFontType2.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/CIDFontType2.java new file mode 100644 index 000000000..17355e5a5 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/CIDFontType2.java @@ -0,0 +1,272 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.sun.pdfview.font; + +import java.awt.geom.GeneralPath; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.HashMap; +import java.util.Map; + +import com.sun.pdfview.PDFObject; + +/** + * a font object derived from a CID font. + * + * @author Jonathan Kaplan + */ +public class CIDFontType2 extends TTFFont { + + /** + * The width of each glyph from the DW and W arrays + */ + private Map widths = null; + /** + * The vertical width of each glyph from the DW2 and W2 arrays + */ + private Map widthsVertical = null; + + /* + * the default width + */ + private int defaultWidth = 1000; + /* + * the default vertical width + */ + private int defaultWidthVertical = 1000; + /** the CIDtoGID map, if any */ + private ByteBuffer cidToGidMap; + + /** + * create a new CIDFontType2 object based on the name of a built-in font + * and the font descriptor + * @param baseName the name of the font, from the PDF file + * @param fontObj a dictionary that contains the DW (defaultWidth) and + * W (width) parameters + * @param descriptor a descriptor for the font + */ + public CIDFontType2(String baseName, PDFObject fontObj, + PDFFontDescriptor descriptor) throws IOException { + super(baseName, fontObj, descriptor); + + parseWidths(fontObj); + + // read the CIDSystemInfo dictionary (required) + PDFObject systemInfoObj = fontObj.getDictRef("CIDSystemInfo"); + // read the cid to gid map (optional) + PDFObject mapObj = fontObj.getDictRef("CIDToGIDMap"); + + + // only read the map if it is a stream (if it is a name, it + // is "Identity" and can be ignored + if (mapObj != null && (mapObj.getType() == PDFObject.STREAM)) { + this.cidToGidMap = mapObj.getStreamBuffer(); + } + } + + /** Parse the Widths array and DW object */ + private void parseWidths(PDFObject fontObj) + throws IOException { + // read the default width (otpional) + PDFObject defaultWidthObj = fontObj.getDictRef("DW"); + if (defaultWidthObj != null && defaultWidthObj.getIntValue() != 0) { + // XOND: commented out the setting of new default width, as several + // PDFs are displayed in a wrong format due to this: +// this.defaultWidth = defaultWidthObj.getIntValue(); + } + + int entryIdx = 0; + int first = 0; + int last = 0; + PDFObject[] widthArray; + + // read the widths table + PDFObject widthObj = fontObj.getDictRef("W"); + if (widthObj != null) { + + // initialize the widths array + this.widths = new HashMap(); + + // parse the width array + widthArray = widthObj.getArray(); + + /* an entry can be in one of two forms: + * or + * [ array of values ] + * we use the entryIdx to differentitate between them + */ + for (int i = 0; i < widthArray.length; i++) { + if (entryIdx == 0) { + // first value in an entry. Just store it + first = widthArray[i].getIntValue(); + } else if (entryIdx == 1) { + // second value -- is it an int or array? + if (widthArray[i].getType() == PDFObject.ARRAY) { + // add all the entries in the array to the width array + PDFObject[] entries = widthArray[i].getArray(); + for (int c = 0; c < entries.length; c++) { + Character key = Character.valueOf((char) (c + first)); + + // value is width / default width + float value = entries[c].getIntValue(); + this.widths.put(key, new Float(value)); + } + // all done + entryIdx = -1; + } else { + last = widthArray[i].getIntValue(); + } + } else { + // third value. Set a range + int value = widthArray[i].getIntValue(); + + // set the range + for (int c = first; c <= last; c++) { + this.widths.put(Character.valueOf((char) c), new Float(value)); + } + + // all done + entryIdx = -1; + } + + entryIdx++; + } + } + + // read the optional vertical default width + defaultWidthObj = fontObj.getDictRef("DW2"); + if (defaultWidthObj != null) { + this.defaultWidthVertical = defaultWidthObj.getIntValue(); + } + + // read the vertical widths table + widthObj = fontObj.getDictRef("W2"); + if (widthObj != null) { + + // initialize the widths array + this.widthsVertical = new HashMap(); + + // parse the width2 array + widthArray = widthObj.getArray(); + + /* an entry can be in one of two forms: + * or + * [ array of values ] + * we use the entryIdx to differentitate between them + */ + entryIdx = 0; + first = 0; + last = 0; + + for (int i = 0; i < widthArray.length; i++) { + if (entryIdx == 0) { + // first value in an entry. Just store it + first = widthArray[i].getIntValue(); + } else if (entryIdx == 1) { + // second value -- is it an int or array? + if (widthArray[i].getType() == PDFObject.ARRAY) { + // add all the entries in the array to the width array + PDFObject[] entries = widthArray[i].getArray(); + for (int c = 0; c < entries.length; c++) { + Character key = Character.valueOf((char) (c + first)); + + // value is width / default width + float value = entries[c].getIntValue(); + this.widthsVertical.put(key, new Float(value)); + } + // all done + entryIdx = -1; + } else { + last = widthArray[i].getIntValue(); + } + } else { + // third value. Set a range + int value = widthArray[i].getIntValue(); + + // set the range + for (int c = first; c <= last; c++) { + this.widthsVertical.put(Character.valueOf((char) c), new Float(value)); + } + + // all done + entryIdx = -1; + } + + entryIdx++; + } + } + } + + /** Get the default width in text space */ + @Override + public int getDefaultWidth() { + return this.defaultWidth; + } + + /** Get the width of a given character */ + @Override + public float getWidth(char code, String name) { + if (this.widths == null) { + return 1f; + } + Float w = this.widths.get(Character.valueOf(code)); + if (w == null) { + return 1f; + } + + return w.floatValue() / getDefaultWidth(); + } + + /** Get the default vertical width in text space */ + public int getDefaultWidthVertical() { + return this.defaultWidthVertical; + } + + /** Get the vertical width of a given character */ + public float getWidthVertical(char code, String name) { + if (this.widthsVertical == null) { + return 1f; + } + Float w = this.widthsVertical.get(Character.valueOf(code)); + if (w == null) { + return 1f; + } + + return w.floatValue() / getDefaultWidthVertical(); + } + + /** + * Get the outline of a character given the character code. We + * interpose here in order to avoid using the CMap of the font in + * a CID mapped font. + */ + @Override + protected synchronized GeneralPath getOutline(char src, float width) { + int glyphId = (src & 0xffff); + + // check if there is a cidToGidMap + if (this.cidToGidMap != null) { + // read the map + glyphId = this.cidToGidMap.getChar(glyphId * 2); + } + + // call getOutline on the glyphId + return getOutline(glyphId, width); + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/FlPoint.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/FlPoint.java new file mode 100644 index 000000000..f68d5d72c --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/FlPoint.java @@ -0,0 +1,48 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package com.sun.pdfview.font; + +/** + * A floating-point Point, with public fields. Also contains a flag + * for "open" to indicate that the path this point is a member of has + * or hasn't been closed. + * + * @author Mike Wessler + */ +public class FlPoint { + /** x coordinate of the point */ + public float x= 0; + + /** y coordinate of the point */ + public float y= 0; + + /** + * whether the path this point is a part of is open or closed. + * used in Type1CFont.java. + */ + public boolean open= false; + + /** reset the values to (0,0) and closed */ + public final void reset() { + this.x= 0; + this.y= 0; + this.open= false; + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/FontSupport.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/FontSupport.java new file mode 100644 index 000000000..c6f767933 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/FontSupport.java @@ -0,0 +1,416 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.sun.pdfview.font; + +/** + * some constants and utility functions for font support. + * @author Mike Wessler + */ +public class FontSupport { + + /** + * names for glyphs in the standard Adobe order. This is the ordering + * of the glyphs in a font, not the mapping of character number to + * character. + */ + public static final String stdNames[] = { + ".notdef", "space", "exclam", "quotedbl", "numbersign", "dollar", + "percent", "ampersand", "quoteright", "parenleft", "parenright", + "asterisk", "plus", "comma", "hyphen", "period", "slash", "zero", + "one", "two", "three", "four", "five", "six", "seven", "eight", + "nine", "colon", "semicolon", "less", "equal", "greater", "question", + "at", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", + "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", + "bracketleft", "backslash", "bracketright", "asciicircum", + "underscore", "quoteleft", "a", "b", "c", "d", "e", "f", "g", "h", + "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", + "w", "x", "y", "z", "braceleft", "bar", "braceright", "asciitilde", + "exclamdown", "cent", "sterling", "fraction", "yen", "florin", + "section", "currency", "quotesingle", "quotedblleft", "guillemotleft", + "guilsinglleft", "guilsinglright", "fi", "fl", "endash", "dagger", + "daggerdbl", "periodcentered", "paragraph", "bullet", + "quotesinglbase", "quotedblbase", "quotedblright", "guillemotright", + "ellipsis", "perthousand", "questiondown", "grave", "acute", + "circumflex", "tilde", "macron", "breve", "dotaccent", "dieresis", + "ring", "cedilla", "hungarumlaut", "ogonek", "caron", "emdash", "AE", + "ordfeminine", "Lslash", "Oslash", "OE", "ordmasculine", "ae", + "dotlessi", "lslash", "oslash", "oe", "germandbls", "onesuperior", + "logicalnot", "mu", "trademark", "Eth", "onehalf", "plusminus", + "Thorn", "onequarter", "divide", "brokenbar", "degree", "thorn", + "threequarters", "twosuperior", "registered", "minus", "eth", + "multiply", "threesuperior", "copyright", "Aacute", "Acircumflex", + "Adieresis", "Agrave", "Aring", "Atilde", "Ccedilla", "Eacute", + "Ecircumflex", "Edieresis", "Egrave", "Iacute", "Icircumflex", + "Idieresis", "Igrave", "Ntilde", "Oacute", "Ocircumflex", "Odieresis", + "Ograve", "Otilde", "Scaron", "Uacute", "Ucircumflex", "Udieresis", + "Ugrave", "Yacute", "Ydieresis", "Zcaron", "aacute", "acircumflex", + "adieresis", "agrave", "aring", "atilde", "ccedilla", "eacute", + "ecircumflex", "edieresis", "egrave", "iacute", "icircumflex", + "idieresis", "igrave", "ntilde", "oacute", "ocircumflex", "odieresis", + "ograve", "otilde", "scaron", "uacute", "ucircumflex", "udieresis", + "ugrave", "yacute", "ydieresis", "zcaron", "exclamsmall", + "Hungarumlautsmall", "dollaroldstyle", "dollarsuperior", + "ampersandsmall", "Acutesmall", "parenleftsuperior", + "parenrightsuperior", "twodotenleader", "onedotenleader", + "zerooldstyle", "oneoldstyle", "twooldstyle", "threeoldstyle", + "fouroldstyle", "fiveoldstyle", "sixoldstyle", "sevenoldstyle", + "eightoldstyle", "nineoldstyle", "commasuperior", + "threequartersemdash", "periodsuperior", "questionsmall", "asuperior", + "bsuperior", "centsuperior", "dsuperior", "esuperior", "isuperior", + "lsuperior", "msuperior", "nsuperior", "osuperior", "rsuperior", + "ssuperior", "tsuperior", "ff", "ffi", "ffl", "parenleftinferior", + "parenrightinferior", "Circumflexsmall", "hyphensuperior", + "Gravesmall", "Asmall", "Bsmall", "Csmall", "Dsmall", "Esmall", + "Fsmall", "Gsmall", "Hsmall", "Ismall", "Jsmall", "Ksmall", "Lsmall", + "Msmall", "Nsmall", "Osmall", "Psmall", "Qsmall", "Rsmall", "Ssmall", + "Tsmall", "Usmall", "Vsmall", "Wsmall", "Xsmall", "Ysmall", "Zsmall", + "colonmonetary", "onefitted", "rupiah", "Tildesmall", + "exclamdownsmall", "centoldstyle", "Lslashsmall", "Scaronsmall", + "Zcaronsmall", "Dieresissmall", "Brevesmall", "Caronsmall", + "Dotaccentsmall", "Macronsmall", "figuredash", "hypheninferior", + "Ogoneksmall", "Ringsmall", "Cedillasmall", "questiondownsmall", + "oneeighth", "threeeighths", "fiveeighths", "seveneighths", + "onethird", "twothirds", "zerosuperior", "foursuperior", + "fivesuperior", "sixsuperior", "sevensuperior", "eightsuperior", + "ninesuperior", "zeroinferior", "oneinferior", "twoinferior", + "threeinferior", "fourinferior", "fiveinferior", "sixinferior", + "seveninferior", "eightinferior", "nineinferior", "centinferior", + "dollarinferior", "periodinferior", "commainferior", "Agravesmall", + "Aacutesmall", "Acircumflexsmall", "Atildesmall", "Adieresissmall", + "Aringsmall", "AEsmall", "Ccedillasmall", "Egravesmall", + "Eacutesmall", "Ecircumflexsmall", "Edieresissmall", "Igravesmall", + "Iacutesmall", "Icircumflexsmall", "Idieresissmall", "Ethsmall", + "Ntildesmall", "Ogravesmall", "Oacutesmall", "Ocircumflexsmall", + "Otildesmall", "Odieresissmall", "OEsmall", "Oslashsmall", + "Ugravesmall", "Uacutesmall", "Ucircumflexsmall", "Udieresissmall", + "Yacutesmall", "Thornsmall", "Ydieresissmall", "001.000", "001.001", + "001.002", "001.003", "Black", "Bold", "Book", "Light", "Medium", + "Regular", "Roman", "Semibold" + }; + + /** + * characters for glyphs in the standard order. These are string "values" + * to go with the names in stdNames. Not all glyphs have been translated + * to their unicode values. In many cases, the name of the glyph has + * been appended to an ASCII approximation of the glyph. Strings longer + * than 3 characters have this characteristic. To get the character, + * use the string if it contains 3 or fewer characters; otherwise, + * grab the first character off the string and use that. + */ + static final String stdValues[] = { + "", " ", "!", "\"", "#", "$", + "%", "&", "'", "(", ")", + "*", "+", ",", "-", ".", "/", "0", + "1", "2", "3", "4", "5", "6", "7", "8", + "9", ":", ";", "<", "=", ">", "?", + "@", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", + "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", + "[", "\\", "]", "^", + "_", "`", "a", "b", "c", "d", "e", "f", "g", "h", + "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", + "w", "x", "y", "z", "{", "|", "}", "~", + "\u00a1", "\u00a2", "\u00a3", "/fraction", "\u00a5", "Fflorin", + "\u00a7", "\u00a4", "\u00b4quotesingle", "\u201c", "?guillemotleft", + "\u2039", "\u203a", "fi", "fl", "--", "\u2020", + "\u2021", "\u00b7", "\u00b6", "\u2022", + "'quotesinglbase", "\"quotedblbase", "\"quotedblright", "?guillemotright", + "...ellipsis", "%perthousand", "?questiondown", "`grave", "'acute", + "^circumflex", "~tilde", "-macron", "?breve", "?dotaccent", "?dieresis", + "oring", "ccedilla", ":hungarumlaut", "?ogonek", ",caron", "---emdash", "AE", + "aordfeminine", "LLslash", "OOslash", "OE", "oordmasculine", "ae", + "idotlessi", "llslash", "ooslash", "oe", "Bgermandbls", "1onesuperior", + "~logicalnot", "?mu", "(TM)trademark", "?Eth", "1/2", "+/-", + "?Thorn", "1/4", "/divide", "|brokenbar", "*degree", "?thorn", + "3/4", "2twosuperior", "(R)", "-minus", "?eth", + "*multiply", "3threesuperior", "(C)", "AAacute", "AAcircumflex", + "AAdieresis", "AAgrave", "AAring", "AAtilde", "CCcedilla", "EEacute", + "EEcircumflex", "EEdieresis", "EEgrave", "IIacute", "IIcircumflex", + "IIdieresis", "IIgrave", "NNtilde", "OOacute", "OOcircumflex", "OOdieresis", + "OOgrave", "OOtilde", "SScaron", "UUacute", "UUcircumflex", "UUdieresis", + "UUgrave", "YYacute", "YYdieresis", "ZZcaron", "aaacute", "aacircumflex", + "aadieresis", "aagrave", "aaring", "aatilde", "cccedilla", "eeacute", + "eecircumflex", "eedieresis", "eegrave", "iiacute", "iicircumflex", + "iidieresis", "iigrave", "nntilde", "ooacute", "oocircumflex", "oodieresis", + "oograve", "ootilde", "sscaron", "uuacute", "uucircumflex", "uudieresis", + "uugrave", "yyacute", "yydieresis", "zzcaron", "!exclamsmall", + "?Hungarumlautsmall", "$dollaroldstyle", "$dollarsuperior", + "&ersandsmall", "'Acutesmall", "/parenleftsuperior", + "\\parenrightsuperior", "?twodotenleader", "?onedotenleader", + "0zerooldstyle", "1oneoldstyle", "2twooldstyle", "3threeoldstyle", + "4fouroldstyle", "5fiveoldstyle", "6sixoldstyle", "7sevenoldstyle", + "8eightoldstyle", "9nineoldstyle", "'commasuperior", + "--threequartersemdash", ".periodsuperior", "?questionsmall", "aasuperior", + "bbsuperior", "ccentsuperior", "ddsuperior", "eesuperior", "iisuperior", + "llsuperior", "mmsuperior", "nnsuperior", "oosuperior", "rrsuperior", + "sssuperior", "ttsuperior", "ff", "ffi", "ffl", "\\parenleftinferior", + "/parenrightinferior", "^Circumflexsmall", "-hyphensuperior", + "`Gravesmall", "AAsmall", "BBsmall", "CCsmall", "DDsmall", "EEsmall", + "FFsmall", "GGsmall", "HHsmall", "IIsmall", "JJsmall", "KKsmall", "LLsmall", + "MMsmall", "NNsmall", "OOsmall", "PPsmall", "QQsmall", "RRsmall", "SSsmall", + "TTsmall", "UUsmall", "VVsmall", "WWsmall", "XXsmall", "YYsmall", "ZZsmall", + ":colonmonetary", "1onefitted", "?rupiah", "~Tildesmall", + "!exclamdownsmall", "ccentoldstyle", "LLslashsmall", "SScaronsmall", + "ZZcaronsmall", "?Dieresissmall", "?Brevesmall", "^Caronsmall", + "?Dotaccentsmall", "?Macronsmall", "--figuredash", "-hypheninferior", + "?Ogoneksmall", "oRingsmall", ",Cedillasmall", "?questiondownsmall", + "1/8oneeighth", "3/8threeeighths", "5/8fiveeighths", "7/8seveneighths", + "1/3onethird", "2/3twothirds", "0zerosuperior", "4foursuperior", + "5fivesuperior", "6sixsuperior", "7sevensuperior", "8eightsuperior", + "9ninesuperior", "0zeroinferior", "1oneinferior", "2twoinferior", + "3threeinferior", "4fourinferior", "5fiveinferior", "6sixinferior", + "7seveninferior", "8eightinferior", "9nineinferior", "ccentinferior", + "$dollarinferior", ".periodinferior", ",commainferior", "AAgravesmall", + "AAacutesmall", "AAcircumflexsmall", "AAtildesmall", "AAdieresissmall", + "AAringsmall", "AEAEsmall", "CCcedillasmall", "EEgravesmall", + "EEacutesmall", "EEcircumflexsmall", "EEdieresissmall", "IIgravesmall", + "IIacutesmall", "IIcircumflexsmall", "IIdieresissmall", "EthEthsmall", + "NNtildesmall", "OOgravesmall", "OOacutesmall", "OOcircumflexsmall", + "OOtildesmall", "OOdieresissmall", "OEOEsmall", "OOslashsmall", + "UUgravesmall", "UUacutesmall", "UUcircumflexsmall", "UUdieresissmall", + "YYacutesmall", "?Thornsmall", "YYdieresissmall", "?001.000", "?001.001", + "?001.002", "?001.003", " Black", " Bold", " Book", " Light", " Medium", + " Regular", " Roman", " Semibold", + /* extra mac stuff */ + "?NUL", "?HT", " LF", " CR", "?DLE", "?DC1", "?DC2", "?DC3", "?DC4", "?RS", + "?US", "!=", "?DEL", "?infinity", "<=", ">=", + "?partialdiff", "?summation", "xproduct", "?pi", "?integral", "?Omega", + "?radical", "~=", "?Delta", " nbspace", "?lozenge", "?apple" + }; + + /** + * glyph order of the glyphs for the Type1C Expert character set. These + * are indices into the glyph name array. + */ + public static final int type1CExpertCharset[] = { + 1, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 13, 14, 15, 99, + 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 27, 28, 249, 250, + 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 109, 110, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, + 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, + 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, + 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, + 158, 155, 163, 319, 320, 321, 322, 323, 324, 325, 326, 150, 164, 169, + 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, + 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, + 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, + 369, 370, 371, 372, 373, 374, 375, 376, 377, 378 + }; + + /** + * glyph order of the glyphs for the Type1C Expert Sub character set. + * These are indices into the glyph name array. + */ + public static final int type1CExpertSubCharset[] = { + 1, 231, 232, 235, 236, 237, 238, 13, 14, 15, 99, 239, 240, 241, 242, + 243, 244, 245, 246, 247, 248, 27, 28, 249, 250, 251, 253, 254, 255, + 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 109, 110, 267, + 268, 269, 270, 272, 300, 301, 302, 305, 314, 315, 158, 155, 163, 320, + 321, 322, 323, 324, 325, 326, 150, 164, 169, 327, 328, 329, 330, 331, + 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, + 346 + }; + + /** + * extra names for the Macintosh glyph set. This array should be + * considered to be appended to the stdNames array. The stdValues array + * already contains values for this set. + */ + public static final String macExtras[] = { // index starts at 391=NUL + "NUL", "HT", "LF", "CR", "DLE", "DC1", "DC2", "DC3", "DC4", "RS", + "US", "notequal", "DEL", "infinity", "lessequal", "greaterequal", + "partialdiff", "summation", "product", "pi", "integral", "Omega", + "radical", "approxequal", "Delta", "nbspace", "lozenge", "apple" + }; + + /** + * character mapping from values to glyphs for the Macintosh MacRoman + * encoding + */ + public static final int macRomanEncoding[] = { + 391, 154, 167, 140, 146, 192, 221, 197, 226, 392, 393, 157, 162, 394, + 199, 228, 395, 396, 397, 398, 399, 155, 158, 150, 163, 169, 164, 160, + 166, 168, 400, 401, 1, 2, 3, 4, 5, 6, 7, 104, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 124, + 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, + 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 403, 173, 175, + 177, 178, 186, 189, 195, 200, 203, 201, 202, 205, 204, 206, 207, 210, + 208, 209, 211, 214, 212, 213, 215, 216, 219, 217, 218, 220, 222, 225, + 223, 224, 112, 161, 97, 98, 102, 116, 115, 149, 165, 170, 153, 125, + 131, 402, 138, 141, 404, 156, 405, 406, 100, 152, 407, 408, 409, 410, + 411, 139, 143, 412, 144, 147, 123, 96, 151, 413, 101, 414, 415, 106, + 120, 121, 416, 174, 176, 191, 142, 148, 111, 137, 105, 119, 65, 8, + 159, 417, 227, 198, 99, 103, 107, 108, 109, 110, 113, 114, 117, 118, + 122, 172, 179, 171, 180, 181, 182, 183, 184, 185, 187, 188, 418, 190, + 193, 194, 196, 145, 126, 127, 128, 129, 130, 132, 133, 134, 135, 136 + }; + + /** + * character mapping from values to glyphs for the isoLatin1Encoding + */ + public static final int isoLatin1Encoding[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 166, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 145, 124, 125, 126, 127, 128, + 129, 130, 131, 0, 132, 133, 0, 134, 135, 136, 1, 96, 97, 98, 103, + 100, 160, 102, 131, 170, 139, 106, 151, 14, 165, 128, 161, 156, 164, + 169, 125, 152, 115, 114, 133, 150, 143, 120, 158, 155, 163, 123, 174, + 171, 172, 176, 173, 175, 138, 177, 181, 178, 179, 180, 185, 182, 183, + 184, 154, 186, 190, 187, 188, 191, 189, 168, 141, 196, 193, 194, 195, + 197, 157, 149, 203, 200, 201, 205, 202, 204, 144, 206, 210, 207, 208, + 209, 214, 211, 212, 213, 167, 215, 219, 216, 217, 220, 218, 159, 147, + 225, 222, 223, 224, 226, 162, 227 + }; + + /** + * character mapping from values to glyphs for the Windows winAnsi + * character encoding + */ + public static final int winAnsiEncoding[] = { + 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 145, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, + 92, 93, 94, 95, 0, 0, 0, 117, 101, 118, 121, 112, 113, 0, 122, 192, + 107, 142, 0, 0, 0, 0, 65, 8, 105, 119, 116, 111, 137, 0, 153, 221, + 108, 148, 0, 0, 198, 1, 96, 97, 98, 103, 100, 160, 102, 131, 170, + 139, 106, 151, 14, 165, 128, 161, 156, 164, 169, 125, 152, 115, 114, + 133, 150, 143, 120, 158, 155, 163, 123, 174, 171, 172, 176, 173, 175, + 138, 177, 181, 178, 179, 180, 185, 182, 183, 184, 154, 186, 190, 187, + 188, 191, 189, 168, 141, 196, 193, 194, 195, 197, 157, 149, 203, 200, + 201, 205, 202, 204, 144, 206, 210, 207, 208, 209, 214, 211, 212, 213, + 167, 215, 219, 216, 217, 220, 218, 159, 147, 225, 222, 223, 224, 226, + 162, 227 + }; + + /** + * character mapping from values to glyphs for Adobe's standard + * character encoding + */ + public static final int standardEncoding[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, + 106, 107, 108, 109, 110, 0, 111, 112, 113, 114, 0, 115, 116, 117, + 118, 119, 120, 121, 122, 0, 123, 0, 124, 125, 126, 127, 128, 129, + 130, 131, 0, 132, 133, 0, 134, 135, 136, 137, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 138, 0, 139, 0, 0, 0, 0, 140, 141, 142, 143, + 0, 0, 0, 0, 0, 144, 0, 0, 0, 145, 0, 0, 146, 147, 148, 149, 0, 0, 0, + 0 + }; + + /** + * Character mapping from values to glyphs for the symbol set encoding + * Definition found here: PDF specification Annex D.5 Symbol Set and Encoding + */ + public static final int symbolSetEncoding[] = { + 101, 102, 103, 104, 105, 110, 240, 107, 301, 111, 113, 114, 115, 116, + 127, 117, 106, 120, 131, 302, 122, 123, 124, 121, 125, 241, 130, 132, + 300, 141, 046, 320, 341, 361, 273, 253, 333, 337, 334, 336, 335, 257, + 276, 254, 256, 255, 275, 052, 174, 142, 173, 175, 354, 355, 356, 374, + 375, 376, 357, 133, 135, 351, 352, 353, 371, 372, 373, 267, 277, 143, + 304, 305, 247, 072, 054, 100, 343, 323, 260, 144, 250, 270, 327, 070, + 316, 274, 306, 145, 075, 272, 150, 041, 044, 065, 246, 064, 244, 147, + 321, 076, 263, 251, 245, 362, 363, 364, 365, 307, 151, 153, 154, 074, + 243, 331, 330, 332, 340, 055, 242, 155, 264, 071, 317, 271, 313, 156, + 043, 167, 166, 157, 061, 050, 051, 346, 347, 350, 366, 367, 370, 266, + 045, 056, 136, 146, 152, 160, 053, 261, 325, 314, 311, 265, 171, 077, + 326, 140, 315, 312, 342, 322, 162, 262, 073, 067, 163, 126, 176, 066, + 057, 040, 252, 047, 345, 164, 134, 161, 112, 063, 344, 324, 062, 137, + 310, 042, 165, 303, 170, 060, 172 + }; + + /** + * get the name of a glyph from its encoding value (NOT the character + * value), using the standard encoding. + */ + public static String getName (int i) { + if (i < stdNames.length) { + return stdNames[i]; + } else { + i -= stdNames.length; + if (i < macExtras.length) { + return macExtras[i]; + } + } + return ".notdef"; + } + + /** + * get the encoding value a glyph given its name and a name table. + * @param name the name of the glyph + * @param table the charset as an array of names + * @return the index of the name in the table, or -1 if the name + * cannot be found in the table + */ + public static int findName (String name, String[] table) { + for (int i = 0; i < table.length; i++) { + if (name.equals (table[i])) { + return i; + } + } + return -1; + } + + /** + * get the encoding value of a glyph given its name and a charset. + * @param name the name of the glyph + * @param table the charset table + * @return the index of the name in the charset. + */ + public static int findName (String name, int[] table) { + for (int i = 0; i < table.length; i++) { + if (name.equals (getName (table[i]))) { + return i; + } + } + return -1; + } + + /** + * get the encoding value of a glyph given its name, in the standard + * charset. This is equivalent to findName(name, FontSupport.stdNames). + * @param name the name of the glyph + * @return the index of the name in stdNames, or -1 if the name doesn't + * appear in stdNames. + */ + public static int getStrIndex (String name) { + for (int i = 0; i < stdNames.length; i++) { + if (name.equals (stdNames[i])) { + return i; + } + } + return -1; + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/NativeFont.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/NativeFont.java new file mode 100644 index 000000000..a79b6c3f2 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/NativeFont.java @@ -0,0 +1,442 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.sun.pdfview.font; + +import java.awt.Font; +import java.awt.FontFormatException; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphVector; +import java.awt.font.OpenType; +import java.awt.geom.AffineTransform; +import java.awt.geom.GeneralPath; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.nio.ByteBuffer; + +import com.sun.pdfview.BaseWatchable; +import com.sun.pdfview.PDFDebugger; +import com.sun.pdfview.PDFObject; +import com.sun.pdfview.PDFParseException; +import com.sun.pdfview.font.ttf.CMap; +import com.sun.pdfview.font.ttf.CMapFormat0; +import com.sun.pdfview.font.ttf.CMapFormat4; +import com.sun.pdfview.font.ttf.CmapTable; +import com.sun.pdfview.font.ttf.HeadTable; +import com.sun.pdfview.font.ttf.HmtxTable; +import com.sun.pdfview.font.ttf.NameTable; +import com.sun.pdfview.font.ttf.PostTable; +import com.sun.pdfview.font.ttf.TrueTypeFont; +import com.sun.pdfview.font.ttf.TrueTypeTable; + +/** + * a font object derived from a true type font. + * + * @author Mike Wessler + */ +public class NativeFont extends OutlineFont { + + /** Control characters to filter out of the underlying font */ + protected static final char[] controlChars = {0x9, 0xa, 0xd}; + + /** the ids of our favorite CMaps */ + protected static final short[] mapIDs = { + 3, 1, /* Microsoft Unicode */ + 0, 0, /* unicode default */ + 0, 3, /* unicode 2.0 map */ + 1, 0 /* macintosh */}; + + /** the actual font in use */ + private Font f; + + /** the font render context */ + private final FontRenderContext basecontext = + new FontRenderContext (new AffineTransform (), + true, true); + + /** the cmap table from a TrueType font */ + private CmapTable cmapTable; + + /** the post table from a TrueType font */ + private PostTable postTable; + + /** the number of font units in one em */ + private int unitsPerEm; + + /** the hmtx table from the TrueType font */ + private HmtxTable hmtxTable; + + /** + * create a new NativeFont object based on a description of the + * font from the PDF file. If the description happens to contain + * an in-line true-type font file (under key "FontFile2"), use the + * true type font. Otherwise, parse the description for key information + * and use that to generate an appropriate font. + */ + public NativeFont (String baseFont, PDFObject fontObj, + PDFFontDescriptor descriptor) + throws IOException { + super (baseFont, fontObj, descriptor); + + String fontName = descriptor.getFontName (); + + PDFObject ttf = descriptor.getFontFile2 (); + if (ttf != null) { + byte[] fontdata = ttf.getStream (); + + try { + setFont (fontdata); + } catch (FontFormatException ffe) { + throw new PDFParseException ("Font format exception: " + ffe); + } + } else { + int flags = descriptor.getFlags (); + int style = ((flags & PDFFontDescriptor.FORCEBOLD) != 0) ? Font.BOLD : Font.PLAIN; + + if (fontName.indexOf ("Bold") > 0) { + style |= Font.BOLD; + } + if (descriptor.getItalicAngle () != 0) { + style |= Font.ITALIC; + } + if ((flags & PDFFontDescriptor.FIXED_PITCH) != 0) { // fixed width + setFont (new Font ("Monospaced", style, 1)); + } else if ((flags & PDFFontDescriptor.SERIF) != 0) { // serif font + setFont (new Font ("Serif", style, 1)); + } else { + setFont (new Font ("Sans-serif", style, 1)); + } + } + } + + /** + * Get a glyph outline by name + * + * @param name the name of the desired glyph + * @return the glyph outline, or null if unavailable + */ + @Override + protected GeneralPath getOutline (String name, float width) { + if (this.postTable != null && this.cmapTable != null) { + // map this character name to a glyph ID + short glyphID = this.postTable.getGlyphNameIndex (name); + + if (glyphID == 0) { + // no glyph -- try by index + return null; + } + + // the mapped character + char mappedChar = 0; + + for (int i = 0; i < mapIDs.length; i += 2) { + CMap map = this.cmapTable.getCMap (mapIDs[i], mapIDs[i + 1]); + if (map != null) { + mappedChar = map.reverseMap (glyphID); + + // we found a character + if (mappedChar != 0) { + break; + } + } + } + + return getOutline (mappedChar, width); + } + + // no maps found, hope the font can deal + return null; + } + + /** + * Get a glyph outline by character code + * + * Note this method must always return an outline + * + * @param src the character code of the desired glyph + * @return the glyph outline + */ + @Override + protected GeneralPath getOutline (char src, float width) { + // some true type fonts put characters in the undefined + // region of Unicode instead of as normal characters. + if (!this.f.canDisplay (src) && this.f.canDisplay ((char) (src + 0xf000))) { + src += 0xf000; + } + + // filter out control characters + for (int i = 0; i < controlChars.length; i++) { + if (controlChars[i] == src) { + src = (char) (0xf000 | src); + break; + } + } + + char[] glyph = new char[1]; + glyph[0] = src; + + GlyphVector gv = this.f.createGlyphVector (this.basecontext, glyph); + GeneralPath gp = new GeneralPath (gv.getGlyphOutline (0)); + + // this should be gv.getGlyphMetrics(0).getAdvance(), but that is + // broken on the Mac, so we need to read the advance from the + // hmtx table in the font + CMap map = this.cmapTable.getCMap (mapIDs[0], mapIDs[1]); + int glyphID = map.map (src); + float advance = (float) this.hmtxTable.getAdvance (glyphID) / (float) this.unitsPerEm; + + float widthfactor = width / advance; + gp.transform (AffineTransform.getScaleInstance (widthfactor, -1)); + + return gp; + } + + /** + * Set the font + * + * @param f the font to use + */ + protected void setFont (Font f) { + this.f = f; + + // if it's an OpenType font, parse the relevant tables to get + // glyph name to code mappings + if (f instanceof OpenType) { + OpenType ot = (OpenType) f; + + byte[] cmapData = ot.getFontTable (OpenType.TAG_CMAP); + byte[] postData = ot.getFontTable (OpenType.TAG_POST); + + TrueTypeFont ttf = new TrueTypeFont (0x10000); + + this.cmapTable = + (CmapTable) TrueTypeTable.createTable (ttf, "cmap", + ByteBuffer.wrap (cmapData)); + ttf.addTable ("cmap", this.cmapTable); + + this.postTable = + (PostTable) TrueTypeTable.createTable (ttf, "post", + ByteBuffer.wrap (postData)); + ttf.addTable ("post", this.postTable); + } + } + + /** + * Set the font + * + * @param fontdata the font data as a byte array + */ + protected void setFont (byte[] fontdata) + throws FontFormatException, IOException { + try { + // read the true type information + TrueTypeFont ttf = TrueTypeFont.parseFont (fontdata); + + // get the cmap, post, and hmtx tables for later use + this.cmapTable = (CmapTable) ttf.getTable ("cmap"); + this.postTable = (PostTable) ttf.getTable ("post"); + this.hmtxTable = (HmtxTable) ttf.getTable ("hmtx"); + + // read the units per em from the head table + HeadTable headTable = (HeadTable) ttf.getTable ("head"); + this.unitsPerEm = headTable.getUnitsPerEm (); + + /* Find out if we have the right info in our name table. + * This is a hack because Java can only deal with fonts that + * have a Microsoft encoded name in their name table (PlatformID 3). + * We'll 'adjust' the font to add it if not, and take our chances + * with our parsing, since it wasn't going to work anyway. + */ + NameTable nameTable = null; + + try { + nameTable = (NameTable) ttf.getTable ("name"); + } catch (Exception ex) { + PDFDebugger.debug("Error reading name table for font " + getBaseFont () + ". Repairing!"); + } + + boolean nameFixed = fixNameTable (ttf, nameTable); + + /* Figure out if we need to hack the CMap table. This might + * be the case if we use characters that Java considers control + * characters (0x9, 0xa and 0xd), that have to be re-mapped + */ + boolean cmapFixed = fixCMapTable (ttf, this.cmapTable); + + // use the parsed font instead of the original + if (nameFixed || cmapFixed) { + fontdata = ttf.writeFont (); + } + } catch (Exception ex) { + PDFDebugger.debug("Error parsing font : " + getBaseFont ()); + BaseWatchable.getErrorHandler().publishException(ex); + } + + ByteArrayInputStream bais = new ByteArrayInputStream (fontdata); + this.f = Font.createFont (Font.TRUETYPE_FONT, bais); + bais.close (); + } + + /** + * Fix a broken font name table for a TrueType font. Some fonts do not + * have Microsoft-specific name information, but Java won't work without + * it (grrr.). This method takes a font and adds the Microsoft data into + * it. + * + * @param ttf the font + * @param name the font's name table + * @return true if the table was fixed, or false if it was left as is + */ + private boolean fixNameTable (TrueTypeFont ttf, NameTable name) { + // if we didn't find the table, or there was an exception, + // just create a new one + if (name == null) { + name = (NameTable) TrueTypeTable.createTable (ttf, "name"); + ttf.addTable ("name", name); + } + + // first, figure out some info about the font + String fName = this.getBaseFont (); + String style = "Regular"; + + if (fName.indexOf ("Italic") > -1 || fName.indexOf ("italic") > -1) { + style = "Italic"; + } else if (fName.indexOf ("Bold") > -1 || fName.indexOf ("bold") > -1) { + style = "Bold"; + } + + if (fName.indexOf ('-') > -1) { + fName = fName.substring (0, fName.indexOf ('-')); + } + + short platID = NameTable.PLATFORMID_MICROSOFT; + short encID = 1; + short langID = 1033; + + short[] nameIDs = { + NameTable.NAMEID_COPYRIGHT, + NameTable.NAMEID_FAMILY, + NameTable.NAMEID_SUBFAMILY, + NameTable.NAMEID_SUBFAMILY_UNIQUE, + NameTable.NAMEID_FULL_NAME, + NameTable.NAMEID_VERSION, + NameTable.NAMEID_POSTSCRIPT_NAME, + NameTable.NAMEID_TRADEMARK + }; + + String[] defaultValues = { + "No copyright", + fName, + style, + fName + " " + style, + fName + " " + style, + "1.0 (Fake)", + fName, + "No Trademark" + }; + + boolean changed = false; + + for (int i = 0; i < nameIDs.length; i++) { + if (name.getRecord (platID, encID, langID, nameIDs[i]) == null) { + name.addRecord (platID, encID, langID, nameIDs[i], + defaultValues[i]); + changed = true; + } + } + + return changed; + } + + /** + * Fix the CMap table. This can be necessary if characters are mapped to + * control characters (0x9, 0xa, 0xd) Java will not render them, even + * though they are valid. + * + * Also, Java tends to not like it when there is only a Format 0 CMap, + * which happens frequently when included Format 4 CMaps are broken. + * Since PDF prefers the Format 0 map, while Java prefers the Format 4 map, + * it is generally necessary to re-write the Format 0 map as a Format 4 map + * to make most PDFs work. + * + * @param ttf the font + * @param cmap the CMap table + * @return true if the font was changed, or false if it was left as-is + */ + private boolean fixCMapTable (TrueTypeFont ttf, CmapTable cmap) { + CMapFormat4 fourMap = null; + CMapFormat0 zeroMap = null; + + for (int i = 0; i < mapIDs.length; i += 2) { + CMap map = this.cmapTable.getCMap (mapIDs[i], mapIDs[i + 1]); + if (map != null) { + if (fourMap == null && map instanceof CMapFormat4) { + fourMap = (CMapFormat4) map; + } else if (zeroMap == null && map instanceof CMapFormat0) { + zeroMap = (CMapFormat0) map; + } + } + } + + // if there were no maps, we could have problems. Just try creating + // an identity map + if (zeroMap == null && fourMap == null) { + fourMap = (CMapFormat4) CMap.createMap ((short) 4, (short) 0); + fourMap.addSegment ((short) getFirstChar (), + (short) getLastChar (), + (short) 0); + } + + // create our map based on the type 0 map, since PDF seems + // to prefer a type 0 map (Java prefers a unicode map) + if (zeroMap != null) { + fourMap = (CMapFormat4) CMap.createMap ((short) 4, (short) 0); + + // add the mappings from 0 to null and 1 to notdef + fourMap.addSegment ((short) 0, (short) 1, (short) 0); + + for (int i = getFirstChar (); i <= getLastChar (); i++) { + short value = (short) (zeroMap.map ((byte) i) & 0xff); + if (value != 0) { + fourMap.addSegment ((short) i, (short) i, + (short) (value - i)); + } + } + } + + // now that we have a type four map, remap control characters + for (int i = 0; i < controlChars.length; i++) { + short idx = (short) (0xf000 | controlChars[i]); + short value = (short) fourMap.map (controlChars[i]); + + fourMap.addSegment (idx, idx, (short) (value - idx)); + } + + // create a whole new table with just our map + cmap = (CmapTable) TrueTypeTable.createTable (ttf, "cmap"); + cmap.addCMap ((short) 3, (short) 1, fourMap); + + // replace the table in the font + ttf.addTable ("cmap", cmap); + + // change the stored table + this.cmapTable = cmap; + + return true; + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/OutlineFont.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/OutlineFont.java new file mode 100644 index 000000000..3c0024b42 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/OutlineFont.java @@ -0,0 +1,154 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.sun.pdfview.font; + +import java.awt.geom.GeneralPath; +import java.awt.geom.Point2D; +import java.io.IOException; + +import com.sun.pdfview.PDFObject; + +/** + * Supports width operations for Type1, Type1C, TrueType and Type3 fonts + */ +public abstract class OutlineFont extends PDFFont { + + /** the first character code */ + private int firstChar = -1; + /** the last character code */ + private int lastChar = -1; + /** the widths for each character code */ + private float[] widths; + + /** Creates a new instance of OutlineFont */ + public OutlineFont(String baseFont, PDFObject fontObj, + PDFFontDescriptor descriptor) throws IOException { + super(baseFont, descriptor); + + PDFObject firstCharObj = fontObj.getDictRef("FirstChar"); + PDFObject lastCharObj = fontObj.getDictRef("LastChar"); + PDFObject widthArrayObj = fontObj.getDictRef("Widths"); + + if (firstCharObj != null) { + this.firstChar = firstCharObj.getIntValue(); + } + if (lastCharObj != null) { + this.lastChar = lastCharObj.getIntValue(); + } + + if (widthArrayObj != null) { + PDFObject[] widthArray = widthArrayObj.getArray(); + + this.widths = new float[widthArray.length]; + + for (int i = 0; i < widthArray.length; i++) { + this.widths[i] = widthArray[i].getFloatValue() / getDefaultWidth(); + } + } + } + + /** Get the first character code */ + public int getFirstChar() { + return this.firstChar; + } + + /** Get the last character code */ + public int getLastChar() { + return this.lastChar; + } + + /** Get the default width in text space */ + public int getDefaultWidth() { + return 1000; + } + + /** Get the number of characters */ + public int getCharCount() { + return (getLastChar() - getFirstChar()) + 1; + } + + /** Get the width of a given character */ + public float getWidth(char code, String name) { + int idx = (code & 0xff) - getFirstChar(); + + // make sure we're in range + if (idx < 0 || this.widths == null || idx >= this.widths.length) { + // try to get the missing width from the font descriptor + if (getDescriptor() != null) { + return getDescriptor().getMissingWidth() / (float)getDefaultWidth(); + } else { + return 0; + } + } + + return this.widths[idx]; + } + + /** + * Get the glyph for a given character code and name + * + * The preferred method of getting the glyph should be by name. If the + * name is null or not valid, then the character code should be used. + * If the both the code and the name are invalid, the undefined glyph + * should be returned. + * + * Note this method must *always* return a glyph. + * + * @param src the character code of this glyph + * @param name the name of this glyph or null if unknown + * @return a glyph for this character + */ + @Override + protected PDFGlyph getGlyph(char src, String name) { + GeneralPath outline = null; + float width = getWidth(src, name); + + // first try by name + if (name != null) { + outline = getOutline(name, width); + } + + // now try by character code (guaranteed to return) + if (outline == null) { + outline = getOutline(src, width); + } + + // calculate the advance + Point2D.Float advance = new Point2D.Float(width, 0); + return new PDFGlyph(src, name, outline, advance); + } + + /** + * Get a glyph outline by name + * + * @param name the name of the desired glyph + * @return the glyph outline, or null if unavailable + */ + protected abstract GeneralPath getOutline(String name, float width); + + /** + * Get a glyph outline by character code + * + * Note this method must always return an outline + * + * @param src the character code of the desired glyph + * @return the glyph outline + */ + protected abstract GeneralPath getOutline(char src, float width); +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/PDFFont.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/PDFFont.java new file mode 100644 index 000000000..2ed2aef58 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/PDFFont.java @@ -0,0 +1,530 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.sun.pdfview.font; + +import java.io.File; +import java.io.FilenameFilter; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; + +import com.sun.pdfview.BaseWatchable; +import com.sun.pdfview.PDFDebugger; +import com.sun.pdfview.PDFObject; +import com.sun.pdfview.PDFParseException; +import com.sun.pdfview.PDFRenderer; +import com.sun.pdfview.font.cid.PDFCMap; +import com.sun.pdfview.font.cid.ToUnicodeMap; +import com.sun.pdfview.font.ttf.TrueTypeFont; + +/** + * a Font definition for PDF files + * @author Mike Wessler + */ +public abstract class PDFFont { + + private static final FilenameFilter TTF_FILTER = new FilenameFilter() { + @Override + public boolean accept(File dir, String name) { + return name.toLowerCase().endsWith(".ttf"); + } + }; + + private static Map namedFontsToLocalTtfFiles = null; + + /** the font SubType of this font */ + private String subtype; + /** the postscript name of this font */ + private String baseFont; + /** the font encoding (maps character ids to glyphs) */ + private PDFFontEncoding encoding; + /** the font descriptor */ + private PDFFontDescriptor descriptor; + /** the CMap that maps this font to unicode values */ + private PDFCMap unicodeMap; + /** a cache of glyphs indexed by character */ + private Map charCache; + + + + /** + * get the PDFFont corresponding to the font described in a PDFObject. + * The object is actually a dictionary containing the following keys:
    + * Type = "Font"
    + * Subtype = (Type1 | TrueType | Type3 | Type0 | MMType1 | CIDFontType0 | + * CIDFontType2)
    + * FirstChar = #
    + * LastChar = #
    + * Widths = array of #
    + * Encoding = (some name representing a dictionary in the resources | an + * inline dictionary) + *

    + * For Type1 and TrueType fonts, the dictionary also contains:
    + * BaseFont = (some name, or XXXXXX+Name as a subset of font Name) + *

    + * For Type3 font, the dictionary contains:
    + * FontBBox = (rectangle)
    + * FontMatrix = (array, typically [0.001, 0, 0, 0.001, 0, 0])
    + * CharProcs = (dictionary) + * Resources = (dictionary) + */ + public synchronized static PDFFont getFont(PDFObject obj, + HashMap resources) + throws IOException { + // the obj is actually a dictionary containing: + // Type (=Font) + // Subtype (Type1, TrueType, Type3, Type0, MMType1, CIDFontType0,2) + // FirstChar (int) + // LastChar (int) + // Widths (array) + // Encoding (name or dict) : assumes StandardEncoding + // and........ + // Type1 and TrueType fonts: + // BaseFont (name) // may be XXXXXX+Fontname as a subset. + // FontDescriptor (dict) + // Type3 fonts: + // FontBBox (rectangle) + // FontMatrix (array) // e.g. [0.001 0 0 0.001 0 0] + // CharProcs (dict) + // Resources (dict) + // + // Font descriptor (Type1 and TrueType fonts): + // FontName (name) + // Flags (1=monospace, 2=serif, 4=script, 7=italic, 19=bold) + // FontBBox (rectangle) + // ItalicAngle (float) + // Ascent (float) + // Descent (float) + // CapHeight (float) + // StemV (float) + // FontFile (stream for Type1 fonts) + // FontFile2 (stream for TrueType fonts) + // FontFile3 (stream for CFF/Type1C fonts) + // + // Font data can be Type1, TrueType(native), or Type1C + PDFFont font = (PDFFont) obj.getCache(); + if (font != null) { + return font; + } + + String baseFont = null; + PDFFontEncoding encoding = null; + PDFFontDescriptor descriptor = null; + + String subType = obj.getDictRef("Subtype").getStringValue(); + if (subType == null) { + subType = obj.getDictRef("S").getStringValue(); + } + PDFObject baseFontObj = obj.getDictRef("BaseFont"); + PDFObject encodingObj = obj.getDictRef("Encoding"); + PDFObject descObj = obj.getDictRef("FontDescriptor"); + + if (baseFontObj != null) { + baseFont = baseFontObj.getStringValue(); + } else { + baseFontObj = obj.getDictRef("Name"); + if (baseFontObj != null) { + baseFont = baseFontObj.getStringValue(); + } + } + + if (encodingObj != null) { + encoding = new PDFFontEncoding(subType, encodingObj); + } + + if (descObj != null) { + descriptor = new PDFFontDescriptor(descObj, subType); + } else { + descriptor = new PDFFontDescriptor(baseFont); + } + + if (subType.equals("Type0")) { + font = new Type0Font(baseFont, obj, descriptor); + } else if (subType.equals("Type1")) { + // load a type1 font + if (descriptor.getFontFile() != null) { + // it's a Type1 font, included. + font = new Type1Font(baseFont, obj, descriptor); + if(!((Type1Font)font).isName2OutlineFilled()){ + PDFDebugger.debug("Type1Font can't be parsed completelly, character mapping missing. Use a basefont instead."); + font = new BuiltinFont(baseFont, obj, descriptor); + } + } else if (descriptor.getFontFile3() != null) { + // it's a CFF (Type1C) font + font = new Type1CFont(baseFont, obj, descriptor); + } else { + // no font info. Fake it based on the FontDescriptor + font = new BuiltinFont(baseFont, obj, descriptor); + } + } else if (subType.equals("TrueType")) { + if (descriptor.getFontFile2() != null) { + // load a TrueType font + try { + font = new TTFFont(baseFont, obj, descriptor); + }catch (Exception e) { +// PDFRenderer.getErrorHandler().publishException(e); + PDFDebugger.debug("Error parsing font : " + baseFont); + // fake it with a built-in font + font = new BuiltinFont(baseFont, obj, descriptor); + } + } else { + final File extFontFile = findExternalTtf(baseFont); + if (extFontFile != null) { + try { + font = new TTFFont(baseFont, obj, descriptor, extFontFile); + }catch (Exception e) { +// PDFRenderer.getErrorHandler().publishException(e); + PDFDebugger.debug("Error parsing font : " + baseFont); + // fake it with a built-in font + font = new BuiltinFont(baseFont, obj, descriptor); + } + } else { + // fake it with a built-in font + font = new BuiltinFont(baseFont, obj, descriptor); + } + } + } else if (subType.equals("Type3")) { + // load a type 3 font + font = new Type3Font(baseFont, obj, resources, descriptor); + } else if (subType.equals("CIDFontType2")) { + if(descriptor.getFontFile2() != null) { + font = new CIDFontType2(baseFont, obj, descriptor); + }else { + // fake it with a built-in font + //but it prefer to use the CIDFontType0 that have the extra handling of ToUnicode, if found in the fontObj + font = new CIDFontType0(baseFont, obj, descriptor); + } + } else if (subType.equals("CIDFontType0")) { + if(descriptor.getFontFile2() !=null){ + font = new CIDFontType2(baseFont, obj, descriptor); + }else { + font = new CIDFontType0(baseFont, obj, descriptor); + } + } else if (subType.equals("MMType1")) { + // not yet implemented, fake it with a built-in font + font = new BuiltinFont(baseFont, obj, descriptor); + } else { + throw new PDFParseException("Don't know how to handle a '" + + subType + "' font"); + } + + font.setSubtype(subType); + font.setEncoding(encoding); + + obj.setCache(font); + return font; + } + + private static File findExternalTtf(String fontName) { + ensureNamedTtfFontFiles(); + return namedFontsToLocalTtfFiles.get(fontName); + } + + private synchronized static void ensureNamedTtfFontFiles() { + if (namedFontsToLocalTtfFiles == null) { + namedFontsToLocalTtfFiles = new HashMap(); + + if (Boolean.getBoolean("PDFRenderer.avoidExternalTtf")) { + return; + } + + for (final String fontDirName : getFontSearchPath()) { + + final File fontDir = new File(fontDirName); + if (fontDir.exists()) { + for (final File ttfFile : fontDir.listFiles(TTF_FILTER)) { + if (ttfFile.canRead()) { + try { + byte[] fontBytes; + RandomAccessFile fontRa = null; + try { + fontRa = new RandomAccessFile (ttfFile, "r"); + int size = (int) fontRa.length (); + fontBytes = new byte[size]; + fontRa.readFully(fontBytes); + } finally { + if (fontRa != null) { + fontRa.close(); + } + } + + TrueTypeFont ttf = TrueTypeFont.parseFont(fontBytes); + for (final String fontName : ttf.getNames()) { + if (!namedFontsToLocalTtfFiles.containsKey(fontName)) { + namedFontsToLocalTtfFiles.put(fontName, ttfFile); + } + } + } catch (Throwable t) { + // I'm not sure how much confidence we should have + // in the font parsing, so we'll avoid relying on + // this not to fail + System.err.println("Problem parsing " + ttfFile); + BaseWatchable.getErrorHandler().publishException(t); + } + } + } + } + } + } + + } + + private static String[] getFontSearchPath() { + String pathProperty = System.getProperty("PDFRenderer.fontSearchPath"); + if (pathProperty != null) { + return pathProperty.split(Pattern.quote(File.pathSeparator)); + } else { + return getDefaultFontSearchPath(); + } + } + + + private static String[] getDefaultFontSearchPath() + { + String osName = null; + try { + osName = System.getProperty("os.name"); + } catch (SecurityException e) { + // preserve null osName + } + + if (osName == null) { + // Makes it a bit tricky to figure out a nice default + return new String[0]; + } + + osName = osName != null ? osName.toLowerCase() : ""; + if (osName.startsWith("windows")) { + // start with some reasonable default + String path = "C:/WINDOWS/Fonts"; + try { + String windir = System.getenv("WINDIR"); + if (windir != null) { + path = windir + "/Fonts/"; + } + } catch (SecurityException secEx) { + // drop through and accept default path + } + return new String[] { path }; + } else if (osName != null && osName.startsWith("mac")) { + List paths = new ArrayList(Arrays.asList( + "/Library/Fonts", + "/Network/Library/Fonts", + "/System/Library/Fonts", + "/System Folder/Fonts")); + // try and add the user font dir at the front + try { + paths.add(0, System.getProperty("user.home") + "/Library/Fonts"); + } catch (SecurityException e) { + // I suppose we just won't use the user fonts + } + return paths.toArray(new String[paths.size()]); + } else { + // Feel free to insert some reasonable defaults for other + // (UNIX, most likely) platforms here + return new String[0]; + } + } + + /** + * Get the subtype of this font. + * @return the subtype, one of: Type0, Type1, TrueType or Type3 + */ + public String getSubtype() { + return this.subtype; + } + + /** + * Set the font subtype + */ + public void setSubtype(String subtype) { + this.subtype = subtype; + } + + /** + * Get the postscript name of this font + * @return the postscript name of this font + */ + public String getBaseFont() { + return this.baseFont; + } + + /** + * Set the postscript name of this font + * @param baseFont the postscript name of the font + */ + public void setBaseFont(String baseFont) { + this.baseFont = baseFont; + } + + /** + * Get the encoding for this font + * @return the encoding which maps from this font to actual characters + */ + public PDFFontEncoding getEncoding() { + return this.encoding; + } + + /** + * Set the encoding for this font + */ + public void setEncoding(PDFFontEncoding encoding) { + this.encoding = encoding; + } + + /** + * Get the descriptor for this font + * @return the font descriptor + */ + public PDFFontDescriptor getDescriptor() { + return this.descriptor; + } + + /** + * Set the descriptor font descriptor + */ + public void setDescriptor(PDFFontDescriptor descriptor) { + this.descriptor = descriptor; + } + + /** + * Get the CMap which maps the characters in this font to unicode names + */ + public PDFCMap getUnicodeMap() { + return this.unicodeMap; + } + + /** + * Set the CMap which maps the characters in this font to unicode names + */ + public void setUnicodeMap(PDFCMap unicodeMap) { + this.unicodeMap = unicodeMap; + } + + /** + * Get the glyphs associated with a given String in this font + * + * @param text the text to translate into glyphs + */ + public List getGlyphs(String text) { + List outList = null; + + // if we have an encoding, use it to get the commands + // don't use the encoding if it is "OneByteIdentityH" (hack for case #205739) + if (this.encoding != null && !this.encoding.isOneByteIdentity()) { + outList = this.encoding.getGlyphs(this, text); + } else { + // use the default mapping + char[] arry = text.toCharArray(); + outList = new ArrayList(arry.length); + + for (int i = 0; i < arry.length; i++) { + // only look at 2 bytes when there is no encoding + char src = (char) (arry[i] & 0xff); + outList.add(getCachedGlyph(src, null)); + } + } + + return outList; + } + + /** + * Get a glyph for a given character code. The glyph is returned + * from the cache if available, or added to the cache if not + * + * @param src the character code of this glyph + * @param name the name of the glyph, or null if the name is unknown + * @return a glyph for this character + */ + public PDFGlyph getCachedGlyph(char src, String name) { + if (this.charCache == null) { + this.charCache = new HashMap(); + } + + // try the cache + PDFGlyph glyph = this.charCache.get(Character.valueOf(src)); + + // if it's not there, add it to the cache + if (glyph == null) { + glyph = getGlyph(src, name); + this.charCache.put(Character.valueOf(src), glyph); + } + + return glyph; + } + + /** + * Create a PDFFont given the base font name and the font descriptor + * @param baseFont the postscript name of this font + * @param descriptor the descriptor for the font + */ + protected PDFFont(String baseFont, PDFFontDescriptor descriptor) { + setBaseFont(baseFont); + setDescriptor(descriptor); + } + + /** + * Get the glyph for a given character code and name + * + * The preferred method of getting the glyph should be by name. If the + * name is null or not valid, then the character code should be used. + * If the both the code and the name are invalid, the undefined glyph + * should be returned. + * + * Note this method must *always* return a glyph. + * + * @param src the character code of this glyph + * @param name the name of this glyph or null if unknown + * @return a glyph for this character + */ + protected abstract PDFGlyph getGlyph(char src, String name); + + /** + * Turn this font into a pretty String + */ + @Override + public String toString() { + return getBaseFont(); + } + + /** + * Compare two fonts base on the baseFont + */ + @Override + public boolean equals(Object o) { + if (!(o instanceof PDFFont)) { + return false; + } + + return ((PDFFont) o).getBaseFont().equals(getBaseFont()); + } + + /** + * Hash a font based on its base font + */ + @Override + public int hashCode() { + return getBaseFont().hashCode(); + } +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/PDFFontDescriptor.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/PDFFontDescriptor.java new file mode 100644 index 000000000..84763ff86 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/PDFFontDescriptor.java @@ -0,0 +1,540 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.sun.pdfview.font; + +import java.awt.geom.Rectangle2D; +import java.io.IOException; + +import com.sun.pdfview.PDFObject; +import com.sun.pdfview.PDFParser; + +/** + * + * @author jkaplan + */ +public class PDFFontDescriptor { + + /** All glyphs have the same width. */ + public final static int FIXED_PITCH = 1 << (1-1); + /** Glyphs have serifs. */ + public final static int SERIF = 1 << (2-1); + /** Font contains glyphs outside the Adobe standard Latin. */ + public final static int SYMBOLIC = 1 << (3-1); + /** Glyphs resemble cursive handwriting. */ + public final static int SCRIPT = 1 << (4-1); + /** Font uses the Adobe standard Latic character set. */ + public final static int NONSYMBOLIC = 1 << (6-1); + /** Glyphs have dominant vertical strokes that are slanted. */ + public final static int ITALIC = 1 << (7-1); + /** Font contains no lowercase letters. */ + public final static int ALLCAP = 1 << (17-1); + /** Font contains both uppercase and lowercase letters.. */ + public final static int SMALLCAP = 1 << (18-1); + /** Determines whether bold glyphs shall be painted with + * extra pixels even at very small text sizes. */ + public final static int FORCEBOLD = 1 << (19-1); + /** Holds value of property ascent. */ + private int ascent; + /** Holds value of property capHeight. */ + private int capHeight; + /** Holds value of property descent. */ + private int descent; + /** Holds value of property flags. */ + private int flags; + /** Holds the optional FontFamily (PDF 1.5) */ + private String fontFamily; + /** Holds value of property fontName. */ + private String fontName; + /** Holds the optional FontStretch (PDF 1.5) */ + private String fontStretch; + /** Holds the optional FontWeight (PDF 1.5) */ + private int fontWeight; + /** Holds value of property italicAngle. */ + private int italicAngle = 0; + /** Holds value of property stemV. */ + private int stemV; + /** Holds value of property avgWidth. */ + private int avgWidth = 0; + /** Holds value of property fontFile. */ + private PDFObject fontFile; + /** Holds value of property fontFile2. */ + private PDFObject fontFile2; + /** Holds value of property fontFile3. */ + private PDFObject fontFile3; + /** Holds value of property leading. */ + private int leading = 0; + /** Holds value of property maxWidth. */ + private int maxWidth = 0; + /** Holds value of property misingWidth. */ + private int missingWidth = 0; + /** Holds value of property stemH. */ + private int stemH = 0; + /** Holds value of property xHeight. */ + private int xHeight = 0; + /** Holds value of property charSet. */ + private PDFObject charSet; + /** Holds value of property fontBBox. */ + private Rectangle2D.Float fontBBox; + + /** Creates a new instance of PDFFontDescriptor */ + public PDFFontDescriptor(String basefont) { + setFontName(basefont); + // [[MW TODO: find basefont info and fill in the rest of the + // descriptor?]] + } + + /** Creates a new instance of PDFFontDescriptor */ + public PDFFontDescriptor(PDFObject obj, String fontSubType) throws IOException { + // required parameters + setFlags(obj.getDictRef("Flags").getIntValue()); + PDFObject fontNameObj = obj.getDictRef("FontName"); + if (fontNameObj == null){ + // fallback to avoid NPE try to use the BaseFont + fontNameObj = obj.getDictRef("BaseFont"); + } + setFontName(fontNameObj.getStringValue()); + setItalicAngle(obj.getDictRef("ItalicAngle").getIntValue()); + + // conditionally required parameters + boolean areConditionalParametersRequired = !"Type3".equals(fontSubType) + && !Boolean.getBoolean("PDFRenderer.lenientFontDescriptorParsing"); + + // these values are declared as Required except for Type 3 fonts + // however a value might not be available for some fonts and + // therefore some predefined value is set, so that we have a fallback + if ( obj.getDictionary().containsKey("Ascent")) { + setAscent(obj.getDictRef("Ascent").getIntValue()); + } + else if (areConditionalParametersRequired) { + setAscent(728); // value of ArialMT as used with Report Label + } + if ( obj.getDictionary().containsKey("CapHeight")) { + setCapHeight(obj.getDictRef("CapHeight").getIntValue()); + } + else if (areConditionalParametersRequired) { + setCapHeight(716); // value of ArialMT as used with Report Label + } + if ( obj.getDictionary().containsKey("Descent")) { + setDescent(obj.getDictRef("Descent").getIntValue()); + } + else if (areConditionalParametersRequired) { + setDescent(-210); // value of ArialMT as used with Report Label + } + if ( obj.getDictionary().containsKey("StemV")) { + setStemV(obj.getDictRef("StemV").getIntValue()); + } + else if (areConditionalParametersRequired) { + setStemV(109); // "normal" value for vertical stem width (PDFlib) + } + + // font bounding box (non-optional but a NPE won't help) + if (obj.getDictionary().containsKey("FontBBox")) { + PDFObject[] bboxdef = obj.getDictRef("FontBBox").getArray(); + float[] bboxfdef = new float[4]; + for (int i = 0; i < 4; i++) { + bboxfdef[i] = bboxdef[i].getFloatValue(); + } + setFontBBox(new Rectangle2D.Float(bboxfdef[0], bboxfdef[1], + bboxfdef[2] - bboxfdef[0], + bboxfdef[3] - bboxfdef[1])); + } + + // optional parameters + if (obj.getDictionary().containsKey("AvgWidth")) { + setAvgWidth(obj.getDictRef("AvgWidth").getIntValue()); + } + if (obj.getDictionary().containsKey("FontFile")) { + setFontFile(obj.getDictRef("FontFile")); + } + if (obj.getDictionary().containsKey("FontFile2")) { + setFontFile2(obj.getDictRef("FontFile2")); + } + if (obj.getDictionary().containsKey("FontFile3")) { + setFontFile3(obj.getDictRef("FontFile3")); + } + if (obj.getDictionary().containsKey("Leading")) { + setLeading(obj.getDictRef("Leading").getIntValue()); + } + if (obj.getDictionary().containsKey("MaxWidth")) { + setMaxWidth(obj.getDictRef("MaxWidth").getIntValue()); + } + if (obj.getDictionary().containsKey("MissingWidth")) { + setMissingWidth(obj.getDictRef("MissingWidth").getIntValue()); + } + if (obj.getDictionary().containsKey("StemH")) { + setStemH(obj.getDictRef("StemH").getIntValue()); + } + if (obj.getDictionary().containsKey("XHeight")) { + setXHeight(obj.getDictRef("XHeight").getIntValue()); + } + if (obj.getDictionary().containsKey("CharSet")) { + setCharSet(obj.getDictRef("CharSet")); + } + if (obj.getDictionary().containsKey("FontFamily")) { + setFontFamily(obj.getDictRef("FontFamily").getStringValue()); + } + if (obj.getDictionary().containsKey("FontWeight")) { + setFontWeight(obj.getDictRef("FontWeight").getIntValue()); + } + if (obj.getDictionary().containsKey("FontStretch")) { + setFontStretch(obj.getDictRef("FontStretch").getStringValue()); + } + } + + /** Getter for property ascent. + * @return Value of property ascent. + * + */ + public int getAscent() { + return this.ascent; + } + + /** Setter for property ascent. + * @param ascent New value of property ascent. + * + */ + public void setAscent(int ascent) { + this.ascent = ascent; + } + + /** Getter for property capHeight. + * @return Value of property capHeight. + * + */ + public int getCapHeight() { + return this.capHeight; + } + + /** Setter for property capHeight. + * @param capHeight New value of property capHeight. + * + */ + public void setCapHeight(int capHeight) { + this.capHeight = capHeight; + } + + /** Getter for property descent. + * @return Value of property descent. + * + */ + public int getDescent() { + return this.descent; + } + + /** Setter for property descent. + * @param descent New value of property descent. + * + */ + public void setDescent(int descent) { + this.descent = descent; + } + + /** Getter for property flags. + * @return Value of property flags. + * + */ + public int getFlags() { + return this.flags; + } + + /** Setter for property flags. + * @param flags New value of property flags. + * + */ + public void setFlags(int flags) { + this.flags = flags; + } + + /** Getter for property fontFamily. Option (PDF 1.5) + * @return Value of the property fontFamily + */ + public String getFontFamily() { + return this.fontFamily; + } + + /** Setter for property fontFamily. + * @param fontFamily New value of property fontFamily. + * + */ + public void setFontFamily(String fontFamily) { + this.fontFamily = fontFamily; + } + + /** Getter for property fontName. + * @return Value of property fontName. + * + */ + public String getFontName() { + return this.fontName; + } + + /** Setter for property fontName. + * @param fontName New value of property fontName. + * + */ + public void setFontName(String fontName) { + this.fontName = fontName; + } + + /** Getter for property fontStretch. Option (PDF 1.5) + * + * @return Value of the property fontStretch + */ + public String getFontStretch() { + return this.fontStretch; + } + + /** Setter for property fontStretch. Possible values are: + * UltraCondensed, ExtraCondensed, Condensed, SemiCondensed, + * Normal, SemiExpanded, Expanded, ExtraExpanded or UltraExpanded + * We do not check at this time. + * + * @param fontStretch New value of property fontStretch. + * + */ + public void setFontStretch(String fontStretch) { + this.fontStretch = fontStretch; + } + + /** Getter for property fontWeight. Option (PDF 1.5) + * + * @return Value of the property fontWeight + */ + public int getFontWeight() { + return this.fontWeight; + } + + /** Setter for property fontWeight. Possible values are: + * 100, 200, 300, 400, 500, 600, 700, 800, 900 + * We do not check at this time. + * + * @param fontWeight New value of property fontWeight. + * + */ + public void setFontWeight(int fontWeight) { + this.fontWeight = fontWeight; + } + + /** Getter for property italicAngle. + * @return Value of property italicAngle. + * + */ + public int getItalicAngle() { + return this.italicAngle; + } + + /** Setter for property italicAngle. + * @param italicAngle New value of property italicAngle. + * + */ + public void setItalicAngle(int italicAngle) { + this.italicAngle = italicAngle; + } + + /** Getter for property stemV. + * @return Value of property stemV. + * + */ + public int getStemV() { + return this.stemV; + } + + /** Setter for property stemV. + * @param stemV New value of property stemV. + * + */ + public void setStemV(int stemV) { + this.stemV = stemV; + } + + /** Getter for property avgWidth. + * @return Value of property avgWidth. + * + */ + public int getAvgWidth() { + return this.avgWidth; + } + + /** Setter for property avgWidth. + * @param avgWidth New value of property avgWidth. + * + */ + public void setAvgWidth(int avgWidth) { + this.avgWidth = avgWidth; + } + + /** Getter for property fontFile. + * @return Value of property fontFile. + * + */ + public PDFObject getFontFile() { + return this.fontFile; + } + + /** Setter for property fontFile. + * @param fontFile New value of property fontFile. + * + */ + public void setFontFile(PDFObject fontFile) { + this.fontFile = fontFile; + } + + /** Getter for property fontFile2. + * @return Value of property fontFile2. + * + */ + public PDFObject getFontFile2() { + return this.fontFile2; + } + + /** Setter for property fontFile2. + * @param fontFile2 New value of property fontFile2. + * + */ + public void setFontFile2(PDFObject fontFile2) { + this.fontFile2 = fontFile2; + } + + /** Getter for property fontFile3. + * @return Value of property fontFile3. + * + */ + public PDFObject getFontFile3() { + return this.fontFile3; + } + + /** Setter for property fontFile3. + * @param fontFile3 New value of property fontFile3. + * + */ + public void setFontFile3(PDFObject fontFile3) { + this.fontFile3 = fontFile3; + } + + /** Getter for property leading. + * @return Value of property leading. + * + */ + public int getLeading() { + return this.leading; + } + + /** Setter for property leading. + * @param leading New value of property leading. + * + */ + public void setLeading(int leading) { + this.leading = leading; + } + + /** Getter for property maxWidth. + * @return Value of property maxWidth. + * + */ + public int getMaxWidth() { + return this.maxWidth; + } + + /** Setter for property maxWidth. + * @param maxWidth New value of property maxWidth. + * + */ + public void setMaxWidth(int maxWidth) { + this.maxWidth = maxWidth; + } + + /** Getter for property misingWidth. + * @return Value of property misingWidth. + * + */ + public int getMissingWidth() { + return this.missingWidth; + } + + /** Setter for property misingWidth. + * @param missingWidth New value of property misingWidth. + */ + public void setMissingWidth(int missingWidth) { + this.missingWidth = missingWidth; + } + + /** Getter for property stemH. + * @return Value of property stemH. + * + */ + public int getStemH() { + return this.stemH; + } + + /** Setter for property stemH. + * @param stemH New value of property stemH. + * + */ + public void setStemH(int stemH) { + this.stemH = stemH; + } + + /** Getter for property xHeight. + * @return Value of property xHeight. + * + */ + public int getXHeight() { + return this.xHeight; + } + + /** Setter for property xHeight. + * @param xHeight New value of property xHeight. + * + */ + public void setXHeight(int xHeight) { + this.xHeight = xHeight; + } + + /** Getter for property charSet. + * @return Value of property charSet. + * + */ + public PDFObject getCharSet() { + return this.charSet; + } + + /** Setter for property charSet. + * @param charSet New value of property charSet. + * + */ + public void setCharSet(PDFObject charSet) { + this.charSet = charSet; + } + + /** Getter for property fontBBox. + * @return Value of property fontBBox. + * + */ + public Rectangle2D.Float getFontBBox() { + return this.fontBBox; + } + + /** Setter for property fontBBox. + * @param fontBBox New value of property fontBBox. + * + */ + public void setFontBBox(Rectangle2D.Float fontBBox) { + this.fontBBox = fontBBox; + } +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/PDFFontEncoding.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/PDFFontEncoding.java new file mode 100644 index 000000000..a0b7b3af2 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/PDFFontEncoding.java @@ -0,0 +1,227 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.sun.pdfview.font; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.sun.pdfview.PDFDebugger; +import com.sun.pdfview.PDFObject; +import com.sun.pdfview.PDFRenderer; +import com.sun.pdfview.font.cid.PDFCMap; + +/** + * The PDFFont encoding encapsulates the mapping from character codes + * in the PDF document to glyphs of the font. + * + * Encodings take two basic forms. For Type1, TrueType, and Type3 fonts, + * the encoding maps from character codes to Strings, which represent the + * glyphs of the font. For Type0 fonts, the mapping is a CMap which maps + * character codes to characters in one of many descendant fonts. + * + * Note that the data in the PDF might be ASCII characters (bytes) or it might + * be a multi-byte format such as unicode. For now we will assume all + * glyph ids fit into at most the two bytes of a character. + */ +public class PDFFontEncoding { + + /** Encoding types */ + private static final int TYPE_ENCODING = 0; + private static final int TYPE_CMAP = 1; + /** + * the base encoding (an array of integers which can be mapped to names + * using the methods on FontSupport + */ + private int[] baseEncoding; + /** any differences from the base encoding */ + private Map differences; + /** + * a CMap for fonts encoded by CMap + */ + private PDFCMap cmap; + /** + * the type of this encoding (encoding or CMap) + */ + private int type; + private PDFObject mapName; + + public PDFFontEncoding(PDFCMap cmap) { + super(); + this.type = TYPE_CMAP; + this.cmap = cmap; + } + + /** Creates a new instance of PDFFontEncoding */ + public PDFFontEncoding(String fontType, PDFObject encoding) + throws IOException { + if (encoding.getType() == PDFObject.NAME) { + // if the encoding is a String, it is the name of an encoding + // or the name of a CMap, depending on the type of the font + if (fontType.equals("Type0")) { + this.type = TYPE_CMAP; + this.cmap = PDFCMap.getCMap(encoding.getStringValue()); + } else { + this.type = TYPE_ENCODING; + + this.differences = new HashMap(); + this.baseEncoding = this.getBaseEncoding(encoding.getStringValue()); + } + } else { + // loook at the "Type" entry of the encoding to determine the type + String typeStr = encoding.getDictRef("Type").getStringValue(); + + if (typeStr.equals("Encoding")) { + // it is an encoding + this.type = TYPE_ENCODING; + parseEncoding(encoding); + } else if (typeStr.equals("CMap")) { + // it is a CMap + this.type = TYPE_CMAP; + this.cmap = PDFCMap.getCMap(encoding); + this.mapName = encoding.getDictRef("CMapName"); + } else { + throw new IllegalArgumentException("Uknown encoding type: " + this.type); + } + } + } + + /** Get the glyphs associated with a given String */ + public List getGlyphs(PDFFont font, String text) { + List outList = new ArrayList(text.length()); + + // go character by character through the text + char[] arry = text.toCharArray(); + for (int i = 0; i < arry.length; i++) { + switch (this.type) { + case TYPE_ENCODING: + outList.add(getGlyphFromEncoding(font, arry[i])); + break; + case TYPE_CMAP: + // 2 bytes -> 1 character in a CMap + char c = (char) ((arry[i] & 0xff) << 8); + if (i < arry.length - 1) { + c |= (char) (arry[++i] & 0xff); + } + outList.add(getGlyphFromCMap(font, c)); + break; + } + } + + return outList; + } + + /** + * Get a glyph from an encoding, given a font and character + */ + private PDFGlyph getGlyphFromEncoding(PDFFont font, char src) { + String charName = null; + + // only deal with one byte of source + src &= 0xff; + + // see if this character is in the differences list + if (this.differences.containsKey(Character.valueOf(src))) { + charName = this.differences.get(Character.valueOf(src)); + } else if (this.baseEncoding != null) { + // get the character name from the base encoding + int charID = this.baseEncoding[src]; + charName = FontSupport.getName(charID); + } + + return font.getCachedGlyph(src, charName); + } + + /** + * Get a glyph from a CMap, given a Type0 font and a character + */ + private PDFGlyph getGlyphFromCMap(PDFFont font, char src) { + int fontID = this.cmap.getFontID(src); + char charID = this.cmap.map(src); + + if (font instanceof Type0Font) { + font = ((Type0Font) font).getDescendantFont(fontID); + } + + return font.getCachedGlyph(charID, null); + } + + /** + * Parse a PDF encoding object for the actual encoding + */ + public void parseEncoding(PDFObject encoding) throws IOException { + this.differences = new HashMap(); + + // figure out the base encoding, if one exists + PDFObject baseEncObj = encoding.getDictRef("BaseEncoding"); + if (baseEncObj != null) { + this.baseEncoding = getBaseEncoding(baseEncObj.getStringValue()); + } + + // parse the differences array + PDFObject diffArrayObj = encoding.getDictRef("Differences"); + if (diffArrayObj != null) { + PDFObject[] diffArray = diffArrayObj.getArray(); + int curPosition = -1; + + for (int i = 0; i < diffArray.length; i++) { + if (diffArray[i].getType() == PDFObject.NUMBER) { + curPosition = diffArray[i].getIntValue(); + } else if (diffArray[i].getType() == PDFObject.NAME) { + Character key = Character.valueOf((char) curPosition); + this.differences.put(key, diffArray[i].getStringValue()); + curPosition++; + } else { + throw new IllegalArgumentException("Unexpected type in diff array: " + diffArray[i]); + } + } + } + } + + /** Get the base encoding for a given name */ + private int[] getBaseEncoding(String encodingName) { + if (encodingName.equals("MacRomanEncoding")) { + return FontSupport.macRomanEncoding; + } else if (encodingName.equals("MacExpertEncoding")) { + return FontSupport.type1CExpertCharset; + } else if (encodingName.equals("WinAnsiEncoding")) { + return FontSupport.winAnsiEncoding; + } else if (encodingName.equals("StandardEncoding")) { + return FontSupport.standardEncoding; + } else if(encodingName.equals("SymbolSetEncoding")) { + return FontSupport.symbolSetEncoding; + } else { + throw new IllegalArgumentException("Unknown encoding: " + encodingName); + } + } + + public boolean isOneByteIdentity() { + if(this.mapName != null) { + try { + return "OneByteIdentityH".equals(this.mapName.getStringValue()); + } catch (IOException e) { + PDFRenderer.getErrorHandler().publishException(e); + } + } + + return false; + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/PDFGlyph.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/PDFGlyph.java new file mode 100644 index 000000000..9452db286 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/PDFGlyph.java @@ -0,0 +1,101 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.sun.pdfview.font; + +import java.awt.geom.AffineTransform; +import java.awt.geom.GeneralPath; +import java.awt.geom.Point2D; + +import com.sun.pdfview.PDFPage; +import com.sun.pdfview.PDFShapeCmd; + +/** +* A single glyph in a stream of PDF text, which knows how to write itself +* onto a PDF command stream +*/ +public class PDFGlyph { + /** the character code of this glyph */ + private final char src; + /** the name of this glyph */ + private final String name; + /** the advance from this glyph */ + private final Point2D advance; + /** the shape represented by this glyph (for all fonts but type 3) */ + private GeneralPath shape; + /** the PDFPage storing this glyph's commands (for type 3 fonts) */ + private PDFPage page; + + /** Creates a new instance of PDFGlyph based on a shape */ + public PDFGlyph(char src, String name, GeneralPath shape, Point2D.Float advance) { + this.shape = shape; + this.advance = advance; + this.src = src; + this.name = name; + } + + /** Creates a new instance of PDFGlyph based on a page */ + public PDFGlyph(char src, String name, PDFPage page, Point2D advance) { + this.page = page; + this.advance = advance; + this.src = src; + this.name = name; + } + + /** Get the character code of this glyph */ + public char getChar() { + return this.src; + } + + /** Get the name of this glyph */ + public String getName() { + return this.name; + } + + /** Get the shape of this glyph */ + public GeneralPath getShape() { + return this.shape; + } + + /** Get the PDFPage for a type3 font glyph */ + public PDFPage getPage() { + return this.page; + } + + /** Add commands for this glyph to a page */ + public Point2D addCommands(PDFPage cmds, AffineTransform transform, int mode) { + if (this.shape != null) { + GeneralPath outline = (GeneralPath) this.shape.createTransformedShape(transform); + cmds.addCommand(new PDFShapeCmd(outline, mode, false)); + } else if (this.page != null) { + cmds.addCommands(this.page, transform); + } + return this.advance; + } + + public Point2D getAdvance() { + return advance; + } + + @Override + public String toString() { + StringBuffer str = new StringBuffer(); + str.append(this.name); + return str.toString(); + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/TTFFont.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/TTFFont.java new file mode 100644 index 000000000..05f0ecb99 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/TTFFont.java @@ -0,0 +1,373 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.sun.pdfview.font; + +import java.awt.geom.AffineTransform; +import java.awt.geom.GeneralPath; +import java.io.File; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.nio.MappedByteBuffer; +import java.nio.channels.FileChannel; +import java.util.Collection; + +import com.sun.pdfview.PDFObject; +import com.sun.pdfview.font.ttf.AdobeGlyphList; +import com.sun.pdfview.font.ttf.CMap; +import com.sun.pdfview.font.ttf.CmapTable; +import com.sun.pdfview.font.ttf.Glyf; +import com.sun.pdfview.font.ttf.GlyfCompound; +import com.sun.pdfview.font.ttf.GlyfSimple; +import com.sun.pdfview.font.ttf.GlyfTable; +import com.sun.pdfview.font.ttf.HeadTable; +import com.sun.pdfview.font.ttf.HmtxTable; +import com.sun.pdfview.font.ttf.PostTable; +import com.sun.pdfview.font.ttf.TrueTypeFont; + +/** + * A true-type font + */ +public class TTFFont extends OutlineFont { + + /** the truetype font itself */ + private TrueTypeFont font; + + /** the number of units per em in the font */ + private float unitsPerEm; + + public TTFFont (String baseFont, PDFObject fontObj, + PDFFontDescriptor descriptor) throws IOException { + this(baseFont, fontObj, descriptor, null); + } + /** + * create a new TrueTypeFont object based on a description of the + * font from the PDF file. If the description happens to contain + * an in-line true-type font file (under key "FontFile2"), use the + * true type font. Otherwise, parse the description for key information + * and use that to generate an appropriate font. + */ + public TTFFont (String baseFont, PDFObject fontObj, + PDFFontDescriptor descriptor, File fontFile) + throws IOException { + super (baseFont, fontObj, descriptor); + + PDFObject ttfObj = descriptor.getFontFile2 (); + + if (ttfObj != null || fontFile != null) { + if (ttfObj != null) { + font = TrueTypeFont.parseFont (ttfObj.getStreamBuffer ()); + } else { + final RandomAccessFile raFile = fontFile != null ? new RandomAccessFile(fontFile, "r") : null; + final FileChannel fc = raFile.getChannel(); + try { + MappedByteBuffer mappedFont = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size()); + font = TrueTypeFont.parseFont(mappedFont); + mappedFont = null; + } finally { + try { + fc.close(); + } catch (IOException ioEx) { + // swallow + } + try { + raFile.close(); + } catch (IOException ioEx) { + // swallow + } + } + } + // read the units per em from the head table + HeadTable head = (HeadTable) font.getTable ("head"); + unitsPerEm = head.getUnitsPerEm (); + } else { + font = null; + } + } + + public Collection getNames() + { + return font.getNames(); + } + + /** + * Get the outline of a character given the character code + */ + @Override + protected synchronized GeneralPath getOutline (char src, float width) { + // find the cmaps + CmapTable cmap = (CmapTable) this.font.getTable ("cmap"); + + // if there are no cmaps, this is (hopefully) a cid-mapped font, + // so just trust the value we were given for src + if (cmap == null) { + return getOutline ((int) src, width); + } + + CMap[] maps = cmap.getCMaps (); + + // try the maps in order + for (int i = 0; i < maps.length; i++) { + int idx = maps[i].map (src); + if (idx != 0) { + return getOutline (idx, width); + } + } + + // windows symbol font CMap may use one of the following code ranges + if (src >= 0 && src <= 0xFF) { + int[] symbolPages = new int[]{0xF000, 0xF100, 0xF200}; + for (int codePage : symbolPages) { + for (int i = 0; i < maps.length; i++) { + int idx = maps[i].map ( (char)(src | codePage)); + if (idx != 0) { + return getOutline (idx, width); + } + } + } + } + + // not found, return the empty glyph + return getOutline (0, width); + } + + /** + * lookup the outline using the (3, 1) cmap, as specified in 32000-1:2008, + * 9.6.6.4, when an Encoding is specified. + * + * @param val + * @param width + * @return GeneralPath + */ + protected synchronized GeneralPath getOutlineFrom31CMap (char val, + float width) { + // find the cmaps + CmapTable cmap = (CmapTable) this.font.getTable ("cmap"); + + if (cmap == null) { + return null; + } + + // find the (3, 1) cmap subtable (Microsoft Unicode) + CMap map = cmap.getCMap ((short) 3, (short) 1); + if (map == null) { + return null; + } + int idx = map.map (val); + if (idx != 0) { + return getOutline (idx, width); + } + + return null; + } + + /** + * Get the outline of a character given the character name + */ + @Override + protected synchronized GeneralPath getOutline (String name, float width) { + int idx; + PostTable post = (PostTable) this.font.getTable ("post"); + if (post != null) { + idx = post.getGlyphNameIndex (name); + if (idx != 0) { + return getOutline (idx, width); + } + } + + Integer res = AdobeGlyphList.getGlyphNameIndex (name); + if (res != null) { + idx = res; + return getOutlineFrom31CMap ((char) idx, width); + } + return null; + } + + /** + * Get the outline of a character given the glyph id + */ + protected synchronized GeneralPath getOutline (int glyphId, float width) { + // find the glyph itself + GlyfTable glyf = (GlyfTable) this.font.getTable ("glyf"); + Glyf g = glyf.getGlyph (glyphId); + + GeneralPath gp = null; + if (g instanceof GlyfSimple) { + gp = renderSimpleGlyph ((GlyfSimple) g); + } else if (g instanceof GlyfCompound) { + gp = renderCompoundGlyph (glyf, (GlyfCompound) g); + } else { + gp = new GeneralPath (); + } + + // calculate the advance + HmtxTable hmtx = (HmtxTable) this.font.getTable ("hmtx"); + float advance = hmtx.getAdvance (glyphId) / this.unitsPerEm; + + // scale the glyph to match the desired advance + float widthfactor = width / advance; + + // the base transform scales the glyph to 1x1 + AffineTransform at = AffineTransform.getScaleInstance(1 / this.unitsPerEm, 1 / this.unitsPerEm); + if (advance != 0) { + at.concatenate(AffineTransform.getScaleInstance(widthfactor, 1)); + } + + gp.transform (at); + + return gp; + } + + /** + * Render a simple glyf + */ + protected GeneralPath renderSimpleGlyph (GlyfSimple g) { + // the current contour + int curContour = 0; + + // the render state + RenderState rs = new RenderState (); + rs.gp = new GeneralPath (); + + for (int i = 0; i < g.getNumPoints (); i++) { + PointRec rec = new PointRec (g, i); + + if (rec.onCurve) { + addOnCurvePoint (rec, rs); + } else { + addOffCurvePoint (rec, rs); + } + + // see if we just ended a contour + if (i == g.getContourEndPoint (curContour)) { + curContour++; + + if (rs.firstOff != null) { + addOffCurvePoint (rs.firstOff, rs); + } + + if (rs.firstOn != null) { + addOnCurvePoint (rs.firstOn, rs); + } + + rs.firstOn = null; + rs.firstOff = null; + rs.prevOff = null; + } + } + + return rs.gp; + } + + /** + * Render a compound glyf + */ + protected GeneralPath renderCompoundGlyph (GlyfTable glyf, GlyfCompound g) { + GeneralPath gp = new GeneralPath (); + + for (int i = 0; i < g.getNumComponents (); i++) { + // find and render the component glyf + Glyf gl = glyf.getGlyph (g.getGlyphIndex (i)); + GeneralPath path = null; + if (gl instanceof GlyfSimple) { + path = renderSimpleGlyph ((GlyfSimple) gl); + } else if (gl instanceof GlyfCompound) { + path = renderCompoundGlyph (glyf, (GlyfCompound) gl); + } else { + throw new RuntimeException ( + "Unsupported glyph type " + gl.getClass ().getCanonicalName ()); + } + + // multiply the translations by units per em + double[] matrix = g.getTransform (i); + + // transform the path + path.transform (new AffineTransform (matrix)); + + // add it to the global path + gp.append (path, false); + } + + return gp; + } + + /** add a point on the curve */ + private void addOnCurvePoint (PointRec rec, RenderState rs) { + // if the point is on the curve, either move to it, + // or draw a line from the previous point + if (rs.firstOn == null) { + rs.firstOn = rec; + rs.gp.moveTo (rec.x, rec.y); + } else if (rs.prevOff != null) { + rs.gp.quadTo (rs.prevOff.x, rs.prevOff.y, rec.x, rec.y); + rs.prevOff = null; + } else { + rs.gp.lineTo (rec.x, rec.y); + } + } + + /** add a point off the curve */ + private void addOffCurvePoint (PointRec rec, RenderState rs) { + if (rs.prevOff != null) { + PointRec oc = new PointRec ((rec.x + rs.prevOff.x) / 2, + (rec.y + rs.prevOff.y) / 2, + true); + addOnCurvePoint (oc, rs); + } else if (rs.firstOn == null) { + rs.firstOff = rec; + } + rs.prevOff = rec; + } + + class RenderState { + // the shape itself + + GeneralPath gp; + // the first off and on-curve points in the current segment + + PointRec firstOn; + + PointRec firstOff; + // the previous off and on-curve points in the current segment + + PointRec prevOff; + + } + + /** a point on the stack of points */ + static class PointRec { + + int x; + + int y; + + boolean onCurve; + + public PointRec (int x, int y, boolean onCurve) { + this.x = x; + this.y = y; + this.onCurve = onCurve; + } + + public PointRec (GlyfSimple g, int idx) { + this.x = g.getXCoord (idx); + this.y = g.getYCoord (idx); + this.onCurve = g.onCurve (idx); + } + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/Type0Font.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/Type0Font.java new file mode 100644 index 000000000..be732831e --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/Type0Font.java @@ -0,0 +1,71 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package com.sun.pdfview.font; + +import java.io.IOException; + +import com.sun.pdfview.PDFObject; + +/** + * Type 0 fonts are composite fonts with a CMAP to map between + * source character codes and destination fonts/codes + * + * @author Jonathan Kaplan + */ +public class Type0Font extends PDFFont { + + /** + * The decendant fonts, indexed by font number from the CMAP + */ + PDFFont[] fonts; + + /** Creates a new instance of Type0Font */ + public Type0Font(String baseFont, PDFObject fontObj, + PDFFontDescriptor descriptor) throws IOException { + super (baseFont, descriptor); + + PDFObject[] descendantFonts = fontObj.getDictRef("DescendantFonts").getArray(); + + this.fonts = new PDFFont[descendantFonts.length]; + + for (int i = 0; i < descendantFonts.length; i++) { + PDFFont descFont = PDFFont.getFont(descendantFonts[i], null); + if (descFont instanceof CIDFontType0) { + ((CIDFontType0)descFont).parseToUnicodeMap(fontObj); + } + this.fonts[i] = descFont; + } + } + + /** + * Get a descendant font of this font by fontId + */ + public PDFFont getDescendantFont(int fontID) { + return this.fonts[fontID]; + } + + /** + * Get a character from the first font in the descendant fonts array + */ + @Override + protected PDFGlyph getGlyph(char src, String name) { + return (getDescendantFont(0).getGlyph(src, name)); + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/Type1CFont.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/Type1CFont.java new file mode 100644 index 000000000..a5368590f --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/Type1CFont.java @@ -0,0 +1,1191 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.sun.pdfview.font; + +import java.awt.geom.AffineTransform; +import java.awt.geom.GeneralPath; +import java.awt.geom.NoninvertibleTransformException; +import java.io.IOException; + +import com.sun.pdfview.PDFDebugger; +import com.sun.pdfview.PDFObject; + +/** + * A representation, with parser, of an Adobe Type 1C font. + * You can find information about CFF and Type 1C font encoding + * in + * http://partners.adobe.com/public/developer/en/font/5176.CFF.pdf + * and + * http://partners.adobe.com/public/developer/en/font/5177.Type2.pdf + * + * @author Mike Wessler + */ +public class Type1CFont extends OutlineFont { + + String chr2name[] = new String[256]; + + byte[] data; + + int pos; + + byte[] subrs; + + float[] stack = new float[100]; + + int stackptr = 0; + + int stemhints = 0; + + String names[]; + + int glyphnames[]; + + int encoding[] = new int[256]; + + String fontname; + + AffineTransform at = new AffineTransform (0.001f, 0, 0, 0.001f, 0, 0); + + int num; + + float fnum; + + int type; + + static int CMD = 0; + + static int NUM = 1; + + static int FLT = 2; + + /** + * create a new Type1CFont based on a font data stream and a descriptor + * @param baseFont the postscript name of this font + * @param src a stream containing the font + * @param descriptor the descriptor for this font + */ + public Type1CFont (String baseFont, PDFObject src, + PDFFontDescriptor descriptor) throws IOException { + super (baseFont, src, descriptor); + + PDFObject dataObj = descriptor.getFontFile3 (); + this.data = dataObj.getStream (); + this.pos = 0; + parse (); + + // TODO: free up (set to null) unused structures (data, subrs, stack) + } + + /** + * a debug method for printing the data + */ + private void printData () { + char[] parts = new char[17]; + int partsloc = 0; + for (int i = 0; i < this.data.length; i++) { + int d = (this.data[i]) & 0xff; + if (d == 0) { + parts[partsloc++] = '.'; + } else if (d < 32 || d >= 127) { + parts[partsloc++] = '?'; + } else { + parts[partsloc++] = (char) d; + } + if (d < 16) { + PDFDebugger.debug("0" + Integer.toHexString (d), 200); + } else { + PDFDebugger.debug(Integer.toHexString (d), 200); + } + if ((i & 15) == 15) { + PDFDebugger.debug(" " + new String (parts), 200); + partsloc = 0; + } else if ((i & 7) == 7) { + PDFDebugger.debug(" ", 200); + parts[partsloc++] = ' '; + } else if ((i & 1) == 1) { + PDFDebugger.debug(" ", 200); + } + } + } + + /** + * read the next decoded value from the stream + * @param charstring ???? + */ + private int readNext (boolean charstring) { + this.num = (this.data[this.pos++]) & 0xff; + if (this.num == 30 && !charstring) { // goofy floatingpoint rep + readFNum (); + return this.type = FLT; + } else if (this.num == 28) { + this.num = ((this.data[this.pos]) << 8) + ((this.data[this.pos + 1]) & 0xff); + this.pos += 2; + return this.type = NUM; + } else if (this.num == 29 && !charstring) { + this.num = ((this.data[this.pos] & 0xff) << 24) | + ((this.data[this.pos + 1] & 0xff) << 16) | + ((this.data[this.pos + 2] & 0xff) << 8) | + ((this.data[this.pos + 3] & 0xff)); + this.pos += 4; + return this.type = NUM; + } else if (this.num == 12) { // two-byte command + this.num = 1000 + ((this.data[this.pos++]) & 0xff); + return this.type = CMD; + } else if (this.num < 32) { + return this.type = CMD; + } else if (this.num < 247) { + this.num -= 139; + return this.type = NUM; + } else if (this.num < 251) { + this.num = (this.num - 247) * 256 + ((this.data[this.pos++]) & 0xff) + 108; + return this.type = NUM; + } else if (this.num < 255) { + this.num = -(this.num - 251) * 256 - ((this.data[this.pos++]) & 0xff) - 108; + return this.type = NUM; + } else if (!charstring) { // dict shouldn't have a 255 code + printData (); + throw new RuntimeException ("Got a 255 code while reading dict"); + } else { // num was 255 + this.fnum = (((this.data[this.pos] & 0xff) << 24) | + ((this.data[this.pos + 1] & 0xff) << 16) | + ((this.data[this.pos + 2] & 0xff) << 8) | + ((this.data[this.pos + 3] & 0xff))) / 65536f; + this.pos += 4; + return this.type = FLT; + } + } + + /** + * read the next funky floating point number from the input stream. + * value gets put into the fnum field. + */ + public void readFNum () { + // work in nybbles: 0-9=0-9, a=. b=E, c=E-, d=rsvd e=neg f=end + float f = 0; + boolean neg = false; + int exp = 0; + int eval = 0; + float mul = 1; + byte work = this.data[this.pos++]; + while (true) { + if (work == (byte) 0xdd) { + work = this.data[this.pos++]; + } + int nyb = (work >> 4) & 0xf; + work = (byte) ((work << 4) | 0xd); + if (nyb < 10) { + if (exp != 0) { // working on the exponent + eval = eval * 10 + nyb; + } else if (mul == 1) { // working on an int + f = f * 10 + nyb; + } else { // working on decimal part + f += nyb * mul; + mul /= 10f; + } + } else if (nyb == 0xa) { // decimal + mul = 0.1f; + } else if (nyb == 0xb) { // E+ + exp = 1; + } else if (nyb == 0xc) { // E- + exp = -1; + } else if (nyb == 0xe) { // neg + neg = true; + } else { + break; + } + } + this.fnum = (neg ? -1 : 1) * f * (float) Math.pow (10, eval * exp); + } + + /** + * read an integer from the input stream + * @param len the number of bytes in the integer + * @return the integer + */ + private int readInt (int len) { + int n = 0; + for (int i = 0; i < len; i++) { + n = (n << 8) | ((this.data[this.pos++]) & 0xff); + } + return n; + } + + /** + * read the next byte from the stream + * @return the byte + */ + private int readByte () { + return (this.data[this.pos++]) & 0xff; + } + + // DICT structure: + // operand operator operand operator ... + // INDEX structure: + // count(2) offsize [offset offset ... offset] data + // offset array has count+1 entries + // data starts at 3+(count+1)*offsize + // offset for data is offset+2+(count+1)*offsize + /** + * get the size of the dictionary located within the stream at + * some offset. + * @param loc the index of the start of the dictionary + * @return the size of the dictionary, in bytes. + */ + public int getIndexSize (int loc) { + int hold = this.pos; + this.pos = loc; + int count = readInt (2); + if (count <= 0) { + return 2; + } + int encsz = readByte (); + if (encsz < 1 || encsz > 4) { + throw new RuntimeException ("Offsize: " + encsz + + ", must be in range 1-4."); + } + // pos is now at the first offset. last offset is at count*encsz + this.pos += count * encsz; + int end = readInt (encsz); + this.pos = hold; + return 2 + (count + 1) * encsz + end; + } + + /** + * return the number of entries in an Index table. + * + * @param loc + * @return + */ + public int getTableLength (int loc) { + int hold = this.pos; + this.pos = loc; + int count = readInt (2); + if (count <= 0) { + return 2; + } + this.pos = hold; + return count; + } + + /** + * A range. There's probably a version of this class floating around + * somewhere already in Java. + */ + static class Range { + + private final int start; + + private final int len; + + public Range (int start, int len) { + this.start = start; + this.len = len; + } + + public final int getStart () { + return this.start; + } + + public final int getLen () { + return this.len; + } + + public final int getEnd () { + return this.start + this.len; + } + + @Override + public String toString () { + return "Range: start: " + this.start + ", len: " + this.len; + } + } + + /** + * Get the range of a particular index in a dictionary. + * @param index the start of the dictionary. + * @param id the index of the entry in the dictionary + * @return a range describing the offsets of the start and end of + * the entry from the start of the file, not the dictionary + */ + Range getIndexEntry (int index, int id) { + int hold = this.pos; + this.pos = index; + int count = readInt (2); + int encsz = readByte (); + if (encsz < 1 || encsz > 4) { + throw new RuntimeException ("Offsize: " + encsz + + ", must be in range 1-4."); + } + this.pos += encsz * id; + int from = readInt (encsz); + Range r = new Range (from + 2 + index + encsz * (count + 1), readInt ( + encsz) - from); + this.pos = hold; + return r; + } + // Top DICT: NAME CODE DEFAULT + // charstringtype 12 6 2 + // fontmatrix 12 7 0.001 0 0 0.001 + // charset 15 - (offset) names of glyphs (ref to name idx) + // encoding 16 - (offset) array of codes + // CharStrings 17 - (offset) + // Private 18 - (size, offset) + // glyph at position i in CharStrings has name charset[i] + // and code encoding[i] + int charstringtype = 2; + + float temps[] = new float[32]; + + int charsetbase = 0; + + int encodingbase = 0; + + int charstringbase = 0; + + int privatebase = 0; + + int privatesize = 0; + + int gsubrbase = 0; + + int lsubrbase = 0; + + int gsubrsoffset = 0; + + int lsubrsoffset = 0; + + int nglyphs = 1; + + /** + * read a dictionary that exists within some range, parsing the entries + * within the dictionary. + */ + private void readDict (Range r) { + this.pos = r.getStart (); + while (this.pos < r.getEnd ()) { + int cmd = readCommand (false); + if (cmd == 1006) { // charstringtype, default=2 + this.charstringtype = (int) this.stack[0]; + } else if (cmd == 1007) { // fontmatrix + if (this.stackptr == 4) { + this.at = new AffineTransform (this.stack[0], this.stack[1], + this.stack[2], this.stack[3], + 0, 0); + } else { + this.at = new AffineTransform (this.stack[0], this.stack[1], + this.stack[2], this.stack[3], + this.stack[4], this.stack[5]); + } + } else if (cmd == 15) { // charset + this.charsetbase = (int) this.stack[0]; + } else if (cmd == 16) { // encoding + this.encodingbase = (int) this.stack[0]; + } else if (cmd == 17) { // charstrings + this.charstringbase = (int) this.stack[0]; + } else if (cmd == 18) { // private + this.privatesize = (int) this.stack[0]; + this.privatebase = (int) this.stack[1]; + } else if (cmd == 19) { // subrs (in Private dict) + this.lsubrbase = this.privatebase + (int) this.stack[0]; + this.lsubrsoffset = calcoffset (this.lsubrbase); + } + this.stackptr = 0; + } + } + + /** + * read a complete command. this may involve several numbers + * which go onto a stack before an actual command is read. + * @param charstring ???? + * @return the command. Some numbers may also be on the stack. + */ + private int readCommand (boolean charstring) { + while (true) { + int t = readNext (charstring); + if (t == CMD) { + return this.num; + } else { + this.stack[this.stackptr++] = (t == NUM) ? (float) this.num : this.fnum; + } + } + } + + /** + * parse information about the encoding of this file. + * @param base the start of the encoding data + */ + private void readEncodingData (int base) { + if (base == 0) { // this is the StandardEncoding + System.arraycopy (FontSupport.standardEncoding, 0, this.encoding, 0, + FontSupport.standardEncoding.length); + } else if (base == 1) { // this is the expert encoding + PDFDebugger.debug("**** EXPERT ENCODING not yet implemented!"); + // TODO: copy ExpertEncoding + } else { + this.pos = base; + int encodingtype = readByte (); + if ((encodingtype & 127) == 0) { + int ncodes = readByte (); + for (int i = 1; i < ncodes + 1; i++) { + int idx = readByte () & 0xff; + this.encoding[idx] = i; + } + } else if ((encodingtype & 127) == 1) { + int nranges = readByte (); + int p = 1; + for (int i = 0; i < nranges; i++) { + int start = readByte (); + int more = readByte (); + for (int j = start; j < start + more + 1; j++) { + this.encoding[j] = p++; + } + } + } else { + PDFDebugger.debug("Bad encoding type: " + encodingtype); + } + // TODO: now check for supplemental encoding data + } + } + + /** + * read the names of the glyphs. + * @param base the start of the glyph name table + */ + private void readGlyphNames (int base) { + if (base == 0) { + this.glyphnames = new int[229]; + for (int i = 0; i < this.glyphnames.length; i++) { + this.glyphnames[i] = i; + } + return; + } else if (base == 1) { + this.glyphnames = FontSupport.type1CExpertCharset; + return; + } else if (base == 2) { + this.glyphnames = FontSupport.type1CExpertSubCharset; + return; + } + // nglyphs has already been set. + this.glyphnames = new int[this.nglyphs]; + this.glyphnames[0] = 0; + this.pos = base; + int t = readByte (); + if (t == 0) { + for (int i = 1; i < this.nglyphs; i++) { + this.glyphnames[i] = readInt (2); + } + } else if (t == 1) { + int n = 1; + while (n < this.nglyphs) { + int sid = readInt (2); + int range = readByte () + 1; + for (int i = 0; i < range; i++) { + this.glyphnames[n++] = sid++; + } + } + } else if (t == 2) { + int n = 1; + while (n < this.nglyphs) { + int sid = readInt (2); + int range = readInt (2) + 1; + for (int i = 0; i < range; i++) { + this.glyphnames[n++] = sid++; + } + } + } + } + + /** + * read a list of names + * @param base the start of the name table + */ + private void readNames (int base) { + this.pos = base; + int nextra = readInt (2); + this.names = new String[nextra]; + // safenames= new String[nextra]; + for (int i = 0; i < nextra; i++) { + Range r = getIndexEntry (base, i); + this.names[i] = new String (this.data, r.getStart (), r.getLen ()); + PDFDebugger.debug("Read name: "+i+" from "+r.getStart()+" to "+r.getEnd()+": "+safe(names[i]), 1000); + } + } + + /** + * parse the font data. + * @param encdif a dictionary describing the encoding. + */ + private void parse () throws IOException { + int majorVersion = readByte (); + int minorVersion = readByte (); + int hdrsz = readByte (); + int offsize = readByte (); + // jump over rest of header: base of font names index + int fnames = hdrsz; + // offset in the file of the array of font dicts + int topdicts = fnames + getIndexSize (fnames); + // offset in the file of local names + int theNames = topdicts + getIndexSize (topdicts); + // offset in the file of the array of global subroutines + this.gsubrbase = theNames + getIndexSize (theNames); + this.gsubrsoffset = calcoffset (this.gsubrbase); + // read extra names + readNames (theNames); + // does this file have more than one font? + this.pos = topdicts; + if (readInt (2) != 1) { + printData (); + throw new RuntimeException ("More than one font in this file!"); + } + Range r = getIndexEntry (fnames, 0); + this.fontname = new String (this.data, r.getStart (), r.getLen ()); + // read first dict + readDict (getIndexEntry (topdicts, 0)); + // read the private dictionary + readDict (new Range (this.privatebase, this.privatesize)); + // calculate the number of glyphs + this.pos = this.charstringbase; + this.nglyphs = readInt (2); + // now get the glyph names + readGlyphNames (this.charsetbase); + // now figure out the encoding + readEncodingData (this.encodingbase); + } + + /** + * get the index of a particular name. The name table starts with + * the standard names in FontSupport.stdNames, and is appended by + * any names in the name table from this font's dictionary. + */ + private int getNameIndex (String name) { + int val = FontSupport.findName (name, FontSupport.stdNames); + if (val == -1) { + val = FontSupport.findName (name, this.names) + FontSupport.stdNames.length; + } + if (val == -1) { + val = 0; + } + return val; + } + + /** + * convert a string to one in which any non-printable bytes are + * replaced by "<###>" where ## is the value of the byte. + */ + private String safe (String src) { + StringBuffer sb = new StringBuffer (); + for (int i = 0; i < src.length (); i++) { + char c = src.charAt (i); + if (c >= 32 && c < 128) { + sb.append (c); + } else { + sb.append ("<" + (int) c + ">"); + } + } + return sb.toString (); + } + + /** + * Read the data for a glyph from the glyph table, and transform + * it based on the current transform. + * + * @param base the start of the glyph table + * @param offset the index of this glyph in the glyph table + */ + private synchronized GeneralPath readGlyph (int base, int offset) { + FlPoint pt = new FlPoint (); + + // find this entry + Range r = getIndexEntry (base, offset); + + // create a path + GeneralPath gp = new GeneralPath (); + + + // rember the start position (for recursive calls due to seac) + int hold = this.pos; + + // read the glyph itself + this.stackptr = 0; + this.stemhints = 0; + parseGlyph (r, gp, pt); + + // restore the start position + this.pos = hold; + + gp.transform (this.at); + + return gp; + } + + /** + * calculate an offset code for a dictionary. Uses the count of entries + * to determine what the offset should be. + * + * @param base the index of the start of the dictionary + */ + public int calcoffset (int base) { + int len = getTableLength (base); + if (len < 1240) { + return 107; + } else if (len < 33900) { + return 1131; + } else { + return 32768; + } + } + + /** + * get the name associated with an ID. + * @param id the index of the name + * @return the name from the FontSupport.stdNames table augmented + * by the local name table + */ + public String getSID (int id) { + if (id < FontSupport.stdNames.length) { + return FontSupport.stdNames[id]; + } else { + id -= FontSupport.stdNames.length; + return this.names[id]; + } + } + + /** + * build an accented character out of two pre-defined glyphs. + * @param x the x offset of the accent + * @param y the y offset of the accent + * @param b the index of the base glyph + * @param a the index of the accent glyph + * @param gp the GeneralPath into which the combined glyph will be + * written. + */ + private void buildAccentChar (float x, float y, char b, char a, + GeneralPath gp) { + // get the outline of the accent + GeneralPath pathA = getOutline (a, getWidth (a, null)); + + // undo the effect of the transform applied in read + AffineTransform xformA = AffineTransform.getTranslateInstance (x, y); + try { + xformA.concatenate (this.at.createInverse ()); + } catch (NoninvertibleTransformException nte) { + // oh well ... + } + pathA.transform (xformA); + + GeneralPath pathB = getOutline (b, getWidth (b, null)); + + try { + AffineTransform xformB = this.at.createInverse (); + pathB.transform (xformB); + } catch (NoninvertibleTransformException nte) { + // ignore + } + + gp.append (pathB, false); + gp.append (pathA, false); + } + + /** + * parse a glyph defined in a particular range + * @param r the range of the glyph definition + * @param gp a GeneralPath in which to store the glyph outline + * @param pt a FlPoint representing the end of the current path + */ + void parseGlyph (Range r, GeneralPath gp, FlPoint pt) { + this.pos = r.getStart (); + int i; + float x1, y1, x2, y2, x3, y3, ybase; + int hold; + while (this.pos < r.getEnd ()) { + int cmd = readCommand (true); + hold = 0; + switch (cmd) { + case 1: // hstem + case 3: // vstem + this.stackptr = 0; + break; + case 4: // vmoveto + if (this.stackptr > 1) { // this is the first call, arg1 is width + this.stack[0] = this.stack[1]; + } + pt.y += this.stack[0]; + if (pt.open) { + gp.closePath (); + } + pt.open = false; + gp.moveTo (pt.x, pt.y); + this.stackptr = 0; + break; + case 5: // rlineto + for (i = 0; i < this.stackptr;) { + pt.x += this.stack[i++]; + pt.y += this.stack[i++]; + gp.lineTo (pt.x, pt.y); + } + pt.open = true; + this.stackptr = 0; + break; + case 6: // hlineto + for (i = 0; i < this.stackptr;) { + if ((i & 1) == 0) { + pt.x += this.stack[i++]; + } else { + pt.y += this.stack[i++]; + } + gp.lineTo (pt.x, pt.y); + } + pt.open = true; + this.stackptr = 0; + break; + case 7: // vlineto + for (i = 0; i < this.stackptr;) { + if ((i & 1) == 0) { + pt.y += this.stack[i++]; + } else { + pt.x += this.stack[i++]; + } + gp.lineTo (pt.x, pt.y); + } + pt.open = true; + this.stackptr = 0; + break; + case 8: // rrcurveto + for (i = 0; i < this.stackptr;) { + x1 = pt.x + this.stack[i++]; + y1 = pt.y + this.stack[i++]; + x2 = x1 + this.stack[i++]; + y2 = y1 + this.stack[i++]; + pt.x = x2 + this.stack[i++]; + pt.y = y2 + this.stack[i++]; + gp.curveTo (x1, y1, x2, y2, pt.x, pt.y); + } + pt.open = true; + this.stackptr = 0; + break; + case 10: // callsubr + hold = this.pos; + i = (int) this.stack[--this.stackptr] + this.lsubrsoffset; + Range lsubr = getIndexEntry (this.lsubrbase, i); + parseGlyph (lsubr, gp, pt); + this.pos = hold; + break; + case 11: // return + return; + case 14: // endchar + // width x y achar bchar endchar == x y achar bchar seac + if (this.stackptr == 5) { + buildAccentChar (this.stack[1], this.stack[2], (char) this.stack[3], + (char) this.stack[4], gp); + } else if (this.stackptr == 4) { + // see page 58 on specification 5177.Type2.pdf which indicates that + // these parameters are valid for Type1C as the width is optional + buildAccentChar(this.stack[0], this.stack[1], (char) this.stack[2], (char) this.stack[3], gp); + } + if (pt.open) { + gp.closePath (); + } + pt.open = false; + this.stackptr = 0; + stemhints = 0; + break; + case 18: // hstemhm + stemhints += (this.stackptr) / 2; + this.stackptr = 0; + break; + case 19: // hintmask + case 20: // cntrmask + stemhints += (this.stackptr) / 2; + this.pos += (stemhints - 1) / 8 + 1; + this.stackptr = 0; + break; + case 21: // rmoveto + if (this.stackptr > 2) { + this.stack[0] = this.stack[1]; + this.stack[1] = this.stack[2]; + } + pt.x += this.stack[0]; + pt.y += this.stack[1]; + if (pt.open) { + gp.closePath (); + } + gp.moveTo (pt.x, pt.y); + pt.open = false; + this.stackptr = 0; + break; + case 22: // hmoveto + if (this.stackptr > 1) { + this.stack[0] = this.stack[1]; + } + pt.x += this.stack[0]; + if (pt.open) { + gp.closePath (); + } + gp.moveTo (pt.x, pt.y); + pt.open = false; + this.stackptr = 0; + break; + case 23: // vstemhm + stemhints += (this.stackptr) / 2; + this.stackptr = 0; + break; + case 24: // rcurveline + for (i = 0; i < this.stackptr - 2;) { + x1 = pt.x + this.stack[i++]; + y1 = pt.y + this.stack[i++]; + x2 = x1 + this.stack[i++]; + y2 = y1 + this.stack[i++]; + pt.x = x2 + this.stack[i++]; + pt.y = y2 + this.stack[i++]; + gp.curveTo (x1, y1, x2, y2, pt.x, pt.y); + } + pt.x += this.stack[i++]; + pt.y += this.stack[i++]; + gp.lineTo (pt.x, pt.y); + pt.open = true; + this.stackptr = 0; + break; + case 25: // rlinecurve + for (i = 0; i < this.stackptr - 6;) { + pt.x += this.stack[i++]; + pt.y += this.stack[i++]; + gp.lineTo (pt.x, pt.y); + } + x1 = pt.x + this.stack[i++]; + y1 = pt.y + this.stack[i++]; + x2 = x1 + this.stack[i++]; + y2 = y1 + this.stack[i++]; + pt.x = x2 + this.stack[i++]; + pt.y = y2 + this.stack[i++]; + gp.curveTo (x1, y1, x2, y2, pt.x, pt.y); + pt.open = true; + this.stackptr = 0; + break; + case 26: // vvcurveto + i = 0; + if ((this.stackptr & 1) == 1) { // odd number of arguments + pt.x += this.stack[i++]; + } + while (i < this.stackptr) { + x1 = pt.x; + y1 = pt.y + this.stack[i++]; + x2 = x1 + this.stack[i++]; + y2 = y1 + this.stack[i++]; + pt.x = x2; + pt.y = y2 + this.stack[i++]; + gp.curveTo (x1, y1, x2, y2, pt.x, pt.y); + } + pt.open = true; + this.stackptr = 0; + break; + case 27: // hhcurveto + i = 0; + if ((this.stackptr & 1) == 1) { // odd number of arguments + pt.y += this.stack[i++]; + } + while (i < this.stackptr) { + x1 = pt.x + this.stack[i++]; + y1 = pt.y; + x2 = x1 + this.stack[i++]; + y2 = y1 + this.stack[i++]; + pt.x = x2 + this.stack[i++]; + pt.y = y2; + gp.curveTo (x1, y1, x2, y2, pt.x, pt.y); + } + pt.open = true; + this.stackptr = 0; + break; + case 29: // callgsubr + hold = this.pos; + i = (int) this.stack[--this.stackptr] + this.gsubrsoffset; + Range gsubr = getIndexEntry (this.gsubrbase, i); + parseGlyph (gsubr, gp, pt); + this.pos = hold; + break; + case 30: // vhcurveto + hold = 4; + case 31: // hvcurveto + for (i = 0; i < this.stackptr;) { + boolean hv = (((i + hold) & 4) == 0); + x1 = pt.x + (hv ? this.stack[i++] : 0); + y1 = pt.y + (hv ? 0 : this.stack[i++]); + x2 = x1 + this.stack[i++]; + y2 = y1 + this.stack[i++]; + pt.x = x2 + (hv ? 0 : this.stack[i++]); + pt.y = y2 + (hv ? this.stack[i++] : 0); + if (i == this.stackptr - 1) { + if (hv) { + pt.x += this.stack[i++]; + } else { + pt.y += this.stack[i++]; + } + } + gp.curveTo (x1, y1, x2, y2, pt.x, pt.y); + } + pt.open = true; + this.stackptr = 0; + break; + case 1000: // old dotsection command. ignore. + this.stackptr = 0; + break; + case 1003: // and + x1 = this.stack[--this.stackptr]; + y1 = this.stack[--this.stackptr]; + this.stack[this.stackptr++] = ((x1 != 0) && (y1 != 0)) ? 1 : 0; + break; + case 1004: // or + x1 = this.stack[--this.stackptr]; + y1 = this.stack[--this.stackptr]; + this.stack[this.stackptr++] = ((x1 != 0) || (y1 != 0)) ? 1 : 0; + break; + case 1005: // not + x1 = this.stack[--this.stackptr]; + this.stack[this.stackptr++] = (x1 == 0) ? 1 : 0; + break; + case 1009: // abs + this.stack[this.stackptr - 1] = Math.abs (this.stack[this.stackptr - 1]); + break; + case 1010: // add + x1 = this.stack[--this.stackptr]; + y1 = this.stack[--this.stackptr]; + this.stack[this.stackptr++] = x1 + y1; + break; + case 1011: // sub + x1 = this.stack[--this.stackptr]; + y1 = this.stack[--this.stackptr]; + this.stack[this.stackptr++] = y1 - x1; + break; + case 1012: // div + x1 = this.stack[--this.stackptr]; + y1 = this.stack[--this.stackptr]; + this.stack[this.stackptr++] = y1 / x1; + break; + case 1014: // neg + this.stack[this.stackptr - 1] = -this.stack[this.stackptr - 1]; + break; + case 1015: // eq + x1 = this.stack[--this.stackptr]; + y1 = this.stack[--this.stackptr]; + this.stack[this.stackptr++] = (x1 == y1) ? 1 : 0; + break; + case 1018: // drop + this.stackptr--; + break; + case 1020: // put + i = (int) this.stack[--this.stackptr]; + x1 = this.stack[--this.stackptr]; + this.temps[i] = x1; + break; + case 1021: // get + i = (int) this.stack[--this.stackptr]; + this.stack[this.stackptr++] = this.temps[i]; + break; + case 1022: // ifelse + if (this.stack[this.stackptr - 2] > this.stack[this.stackptr - 1]) { + this.stack[this.stackptr - 4] = this.stack[this.stackptr - 3]; + } + this.stackptr -= 3; + break; + case 1023: // random + this.stack[this.stackptr++] = (float) Math.random (); + break; + case 1024: // mul + x1 = this.stack[--this.stackptr]; + y1 = this.stack[--this.stackptr]; + this.stack[this.stackptr++] = y1 * x1; + break; + case 1026: // sqrt + this.stack[this.stackptr - 1] = (float) Math.sqrt (this.stack[this.stackptr - 1]); + break; + case 1027: // dup + x1 = this.stack[this.stackptr - 1]; + this.stack[this.stackptr++] = x1; + break; + case 1028: // exch + x1 = this.stack[this.stackptr - 1]; + this.stack[this.stackptr - 1] = this.stack[this.stackptr - 2]; + this.stack[this.stackptr - 2] = x1; + break; + case 1029: // index + i = (int) this.stack[this.stackptr - 1]; + if (i < 0) { + i = 0; + } + this.stack[this.stackptr - 1] = this.stack[this.stackptr - 2 - i]; + break; + case 1030: // roll + i = (int) this.stack[--this.stackptr]; + int n = (int) this.stack[--this.stackptr]; + // roll n number by i (+ = upward) + if (i > 0) { + i = i % n; + } else { + i = n - (-i % n); + } + // x x x x i y y y -> y y y x x x x i (where i=3) + if (i > 0) { + float roll[] = new float[n]; + System.arraycopy (this.stack, this.stackptr - 1 - i, roll, 0, i); + System.arraycopy (this.stack, this.stackptr - 1 - n, roll, i, + n - i); + System.arraycopy (roll, 0, this.stack, this.stackptr - 1 - n, n); + } + break; + case 1034: // hflex + x1 = pt.x + this.stack[0]; + y1 = ybase = pt.y; + x2 = x1 + this.stack[1]; + y2 = y1 + this.stack[2]; + pt.x = x2 + this.stack[3]; + pt.y = y2; + gp.curveTo (x1, y1, x2, y2, pt.x, pt.y); + x1 = pt.x + this.stack[4]; + y1 = pt.y; + x2 = x1 + this.stack[5]; + y2 = ybase; + pt.x = x2 + this.stack[6]; + pt.y = y2; + gp.curveTo (x1, y1, x2, y2, pt.x, pt.y); + pt.open = true; + this.stackptr = 0; + break; + case 1035: // flex + x1 = pt.x + this.stack[0]; + y1 = pt.y + this.stack[1]; + x2 = x1 + this.stack[2]; + y2 = y1 + this.stack[3]; + pt.x = x2 + this.stack[4]; + pt.y = y2 + this.stack[5]; + gp.curveTo (x1, y1, x2, y2, pt.x, pt.y); + x1 = pt.x + this.stack[6]; + y1 = pt.y + this.stack[7]; + x2 = x1 + this.stack[8]; + y2 = y1 + this.stack[9]; + pt.x = x2 + this.stack[10]; + pt.y = y2 + this.stack[11]; + gp.curveTo (x1, y1, x2, y2, pt.x, pt.y); + pt.open = true; + this.stackptr = 0; + break; + case 1036: // hflex1 + ybase = pt.y; + x1 = pt.x + this.stack[0]; + y1 = pt.y + this.stack[1]; + x2 = x1 + this.stack[2]; + y2 = y1 + this.stack[3]; + pt.x = x2 + this.stack[4]; + pt.y = y2; + gp.curveTo (x1, y1, x2, y2, pt.x, pt.y); + x1 = pt.x + this.stack[5]; + y1 = pt.y; + x2 = x1 + this.stack[6]; + y2 = y1 + this.stack[7]; + pt.x = x2 + this.stack[8]; + pt.y = ybase; + gp.curveTo (x1, y1, x2, y2, pt.x, pt.y); + pt.open = true; + this.stackptr = 0; + break; + case 1037: // flex1 + ybase = pt.y; + float xbase = pt.x; + x1 = pt.x + this.stack[0]; + y1 = pt.y + this.stack[1]; + x2 = x1 + this.stack[2]; + y2 = y1 + this.stack[3]; + pt.x = x2 + this.stack[4]; + pt.y = y2 + this.stack[5]; + gp.curveTo (x1, y1, x2, y2, pt.x, pt.y); + x1 = pt.x + this.stack[6]; + y1 = pt.y + this.stack[7]; + x2 = x1 + this.stack[8]; + y2 = y1 + this.stack[9]; + if (Math.abs (x2 - xbase) > Math.abs (y2 - ybase)) { + pt.x = x2 + this.stack[10]; + pt.y = ybase; + } else { + pt.x = xbase; + pt.y = y2 + this.stack[10]; + } + gp.curveTo (x1, y1, x2, y2, pt.x, pt.y); + pt.open = true; + this.stackptr = 0; + break; + default: + PDFDebugger.debug("ERROR! TYPE1C CHARSTRING CMD IS " + cmd); + break; + } + } + } + + /** + * Get a glyph outline by name + * + * @param name the name of the desired glyph + * @return the glyph outline, or null if unavailable + */ + @Override + protected GeneralPath getOutline (String name, float width) { + // first find the index of this name + int index = getNameIndex (name); + + // now find the glyph with that name + for (int i = 0; i < this.glyphnames.length; i++) { + if (this.glyphnames[i] == index) { + return readGlyph (this.charstringbase, i); + } + } + + // not found -- return the unknown glyph + return readGlyph (this.charstringbase, 0); + } + + /** + * Get a glyph outline by character code + * + * Note this method must always return an outline + * + * @param src the character code of the desired glyph + * @return the glyph outline + */ + @Override + protected GeneralPath getOutline (char src, float width) { + // ignore high bits + int index = (src & 0xff); + + // if we use a standard encoding, the mapping is from glyph to SID + // therefore we must find the glyph index in the name table + if (this.encodingbase == 0 || this.encodingbase == 1) { + for (int i = 0; i < this.glyphnames.length; i++) { + if (this.glyphnames[i] == this.encoding[index]) { + return readGlyph (this.charstringbase, i); + } + } + } else { + // for a custom encoding, the mapping is from glyph to GID, so + // we can just map the glyph directly + if (index > 0 && index < this.encoding.length) { + return readGlyph (this.charstringbase, this.encoding[index]); + } + } + + // for some reason the glyph was not found, return the empty glyph + return readGlyph (this.charstringbase, 0); + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/Type1Font.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/Type1Font.java new file mode 100644 index 000000000..835c3c04c --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/Type1Font.java @@ -0,0 +1,907 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.sun.pdfview.font; + +import java.awt.geom.AffineTransform; +import java.awt.geom.GeneralPath; +import java.awt.geom.NoninvertibleTransformException; +import java.awt.geom.Point2D; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.TreeMap; + +import com.sun.pdfview.PDFDebugger; +import com.sun.pdfview.PDFFile; +import com.sun.pdfview.PDFObject; + +/** + * A representation, with parser, of an Adobe Type 1 font. + * @author Mike Wessler + */ +public class Type1Font extends OutlineFont { + + String chr2name[]; + int password; + byte[] subrs[]; + int lenIV; + Map name2outline; + Map name2width; + AffineTransform at; + /** the Type1 stack of command values */ + float stack[] = new float[100]; + /** the current position in the Type1 stack */ + int sloc = 0; + /** the stack of postscript commands (used by callothersubr) */ + float psStack[] = new float[3]; + /** the current position in the postscript stack */ + int psLoc = 0; + + /** + * create a new Type1Font based on a font data stream and an encoding. + * @param baseName the postscript name of this font + * @param src the Font object as a stream with a dictionary + * @param descriptor the descriptor for this font + */ + public Type1Font(String baseName, PDFObject src, + PDFFontDescriptor descriptor) throws IOException { + super(baseName, src, descriptor); + + if (descriptor != null && descriptor.getFontFile() != null) { + // parse that file, filling name2outline and chr2name + int start = descriptor.getFontFile().getDictRef("Length1").getIntValue(); + int len = descriptor.getFontFile().getDictRef("Length2").getIntValue(); + byte font[] = descriptor.getFontFile().getStream(); + + parseFont(font, start, len); + } + } + + /** Read a font from it's data, start position and length */ + protected void parseFont(byte[] font, int start, int len) { + this.name2width = new HashMap(); + + byte data[] = null; + + if (isASCII(font, start)) { + byte[] bData = readASCII(font, start, start + len); + data = decrypt(bData, 0, bData.length, 55665, 4); + } else { + data = decrypt(font, start, start + len, 55665, 4); + } + + // encoding is in cleartext area + this.chr2name = readEncoding(font); + int lenIVLoc = findSlashName(data, "lenIV"); + PSParser psp = new PSParser(data, 0); + if (lenIVLoc < 0) { + this.lenIV = 4; + } else { + psp.setLoc(lenIVLoc + 6); + this.lenIV = Integer.parseInt(psp.readThing()); + } + this.password = 4330; + int matrixloc = findSlashName(font, "FontMatrix"); + if (matrixloc < 0) { + PDFDebugger.debug("No FontMatrix!"); + this.at = new AffineTransform(0.001f, 0, 0, 0.001f, 0, 0); + } else { + PSParser psp2 = new PSParser(font, matrixloc + 11); + // read [num num num num num num] + float xf[] = psp2.readArray(6); + this.at = new AffineTransform(xf); + } + + this.subrs = readSubrs(data); + this.name2outline = new TreeMap(readChars(data)); + // at this point, name2outline holds name -> byte[]. + } + + /** + * parse the encoding portion of the font definition + * @param d the font definition stream + * @return an array of the glyphs corresponding to each byte + */ + private String[] readEncoding(byte[] d) { + byte[][] ary = readArray(d, "Encoding", "def"); + String res[] = new String[256]; + for (int i = 0; i < ary.length; i++) { + if (ary[i] != null) { + if (ary[i][0] == '/') { + res[i] = new String(ary[i]).substring(1); + } else { + res[i] = new String(ary[i]); + } + } else { + res[i] = null; + } + } + return res; + } + + /** + * read the subroutines out of the font definition + * @param d the font definition stream + * @return an array of the subroutines, each as a byte array. + */ + private byte[][] readSubrs(byte[] d) { + return readArray(d, "Subrs", "index"); + } + + /** + * read a named array out of the font definition. + *

    + * this function attempts to parse an array out of a postscript + * definition without doing any postscript. It's actually looking + * for things that look like "dup id elt put", and + * placing the elt at the ith position in the array. + * @param d the font definition stream + * @param key the name of the array + * @param end a string that appears at the end of the array + * @return an array consisting of a byte array for each entry + */ + private byte[][] readArray(byte[] d, String key, String end) { + int i = findSlashName(d, key); + if (i < 0) { + // not found. + return new byte[0][]; + } + // now find things that look like "dup id elt put" + // end at "def" + PSParser psp = new PSParser(d, i); + String type = psp.readThing(); // read the key (i is the start of the key) + double val; + type = psp.readThing(); + if (type.equals("StandardEncoding")) { + byte[] stdenc[] = new byte[FontSupport.standardEncoding.length][]; + for (i = 0; i < stdenc.length; i++) { + stdenc[i] = FontSupport.getName(FontSupport.standardEncoding[i]).getBytes(); + } + return stdenc; + } + int len = Integer.parseInt(type); + byte[] out[] = new byte[len][]; + byte[] line; + while (true) { + String s = psp.readThing(); + if (s.equals("dup")) { + String thing = psp.readThing(); + int id = 0; + try { + id = Integer.parseInt(thing); + } catch (Exception e) { + break; + } + String elt = psp.readThing(); + line = elt.getBytes(); + if (Character.isDigit(elt.charAt(0))) { + int hold = Integer.parseInt(elt); + String special = psp.readThing(); + if (special.equals("-|") || special.equals("RD")) { + psp.setLoc(psp.getLoc() + 1); + line = psp.getNEncodedBytes(hold, this.password, this.lenIV); + } + } + out[id] = line; + } else if (s.equals(end)) { + break; + } + } + return out; + } + + /** + * decrypt an array using the Adobe Type 1 Font decryption algorithm. + * @param d the input array of bytes + * @param start where in the array to start decoding + * @param end where in the array to stop decoding + * @param key the decryption key + * @param skip how many bytes to skip initially + * @return the decrypted bytes. The length of this array will be + * (start-end-skip) bytes long + */ + private byte[] decrypt(byte[] d, int start, int end, int key, int skip) { + if (end - start - skip < 0) { + skip = 0; + } + byte[] o = new byte[end - start - skip]; + int r = key; + int ipos; + int c1 = 52845; + int c2 = 22719; + for (ipos = start; ipos < end; ipos++) { + int c = d[ipos] & 0xff; + int p = (c ^ (r >> 8)) & 0xff; + r = ((c + r) * c1 + c2) & 0xffff; + if (ipos - start - skip >= 0) { + o[ipos - start - skip] = (byte) p; + } + } + return o; + } + + /** + * Read data formatted as ASCII strings as binary data + * + * @param data the data, formatted as ASCII strings + * @param start where in the array to start decrypting + * @param end where in the array to stop decrypting + */ + private byte[] readASCII(byte[] data, int start, int end) { + // each byte of output is derived from one character (two bytes) of + // input + byte[] o = new byte[(end - start) / 2]; + + int count = 0; + int bit = 0; + + for (int loc = start; loc < end; loc++) { + char c = (char) (data[loc] & 0xff); + byte b = (byte) 0; + + if (c >= '0' && c <= '9') { + b = (byte) (c - '0'); + } else if (c >= 'a' && c <= 'f') { + b = (byte) (10 + (c - 'a')); + } else if (c >= 'A' && c <= 'F') { + b = (byte) (10 + (c - 'A')); + } else { + // linefeed or something. Skip. + continue; + } + + // which half of the byte are we? + if ((bit++ % 2) == 0) { + o[count] = (byte) (b << 4); + } else { + o[count++] |= b; + } + } + + return o; + } + + /** + * Determine if data is in ASCII or binary format. According to the spec, + * if any of the first 4 bytes are not character codes ('0' - '9' or + * 'A' - 'F' or 'a' - 'f'), then the data is binary. Otherwise it is + * ASCII + */ + private boolean isASCII(byte[] data, int start) { + // look at the first 4 bytes + for (int i = start; i < start + 4; i++) { + // get the byte as a character + char c = (char) (data[i] & 0xff); + + if (c >= '0' && c <= '9') { + continue; + } else if (c >= 'a' && c <= 'f') { + continue; + } else if (c >= 'A' && c <= 'F') { + continue; + } else { + // out of range + return false; + } + } + + // all were in range, so it is ASCII + return true; + } + + /** + * PostScript reader (not a parser, as the name would seem to indicate). + */ + class PSParser { + + byte[] data; + int loc; + + /** + * create a PostScript reader given some data and an initial offset + * into that data. + * @param data the bytes of the postscript information + * @param start an initial offset into the data + */ + public PSParser(byte[] data, int start) { + this.data = data; + this.loc = start; + } + + /** + * get the next postscript "word". This is basically the next + * non-whitespace block between two whitespace delimiters. + * This means that something like " [2 4 53]" will produce + * three items, while " [2 4 56 ]" will produce four. + */ + public String readThing() { + // skip whitespace + while (PDFFile.isWhiteSpace(this.data[this.loc])) { + this.loc++; + } + // read thing + int start = this.loc; + while (!PDFFile.isWhiteSpace(this.data[this.loc])) { + this.loc++; + if (!PDFFile.isRegularCharacter(this.data[this.loc])) { + break; // leave with the delimiter included + } + } + String s = new String(this.data, start, this.loc - start); + return s; + } + + /** + * read a set of numbers from the input. This method doesn't + * pay any attention to "[" or "]" delimiters, and reads any + * non-numeric items as the number 0. + * @param count the number of items to read + * @return an array of count floats + */ + public float[] readArray(int count) { + float[] ary = new float[count]; + int idx = 0; + while (idx < count) { + String thing = readThing(); + if (thing.charAt(0) == '[') { + thing = thing.substring(1); + } + if (thing.endsWith("]")) { + thing = thing.substring(0, thing.length() - 1); + } + if (thing.length() > 0) { + ary[idx++] = Float.parseFloat(thing); + } + } + return ary; + } + + /** + * get the current location within the input stream + */ + public int getLoc() { + return this.loc; + } + + /** + * set the current location within the input stream + */ + public void setLoc(int loc) { + this.loc = loc; + } + + /** + * treat the next n bytes of the input stream as encoded + * information to be decrypted. + * @param n the number of bytes to decrypt + * @param key the decryption key + * @param skip the number of bytes to skip at the beginning of the + * decryption + * @return an array of decrypted bytes. The length of the array + * will be n-skip. + */ + public byte[] getNEncodedBytes(int n, int key, int skip) { + byte[] result = decrypt(this.data, this.loc, this.loc + n, key, skip); + this.loc += n; + return result; + } + } + + /** + * get the index into the byte array of a slashed name, like "/name". + * @param d the search array + * @param name the name to look for, without the initial / + * @return the index of the first occurance of /name in the array. + */ + private int findSlashName(byte[] d, String name) { + int i; + for (i = 0; i < d.length; i++) { + if (d[i] == '/') { + // check for key + boolean found = true; + for (int j = 0; j < name.length(); j++) { + if (d[i + j + 1] != name.charAt(j)) { + found = false; + break; + } + } + if (found) { + return i; + } + } + } + return -1; + } + + /** + * get the character definitions of the font. + * @param d the font data + * @return a HashMap that maps string glyph names to byte arrays of + * decoded font data. + */ + private HashMap readChars(byte[] d) { + // skip thru data until we find "/"+key + HashMap hm = new HashMap(); + int i = findSlashName(d, "CharStrings"); + if (i < 0) { + // not found + return hm; + } + PSParser psp = new PSParser(d, i); + // read /name len -| [len bytes] |- + // until "end" + while (true) { + String s = psp.readThing(); + char c = s.charAt(0); + if (c == '/') { + int len = Integer.parseInt(psp.readThing()); + String go = psp.readThing(); // it's -| or RD + if (go.equals("-|") || go.equals("RD")) { + psp.setLoc(psp.getLoc() + 1); + byte[] line = psp.getNEncodedBytes(len, this.password, this.lenIV); + hm.put(s.substring(1), line); + } + } else if (s.equals("end")) { + break; + } + } + return hm; + } + + /** + * pop the next item off the stack + */ + private float pop() { + float val = 0; + if (this.sloc > 0) { + val = this.stack[--this.sloc]; + } + return val; + } + int callcount = 0; + + /** + * parse glyph data into a GeneralPath, and return the advance width. + * The working point is passed in as a parameter in order to allow + * recursion. + * @param cs the decrypted glyph data + * @param gp a GeneralPath into which the glyph shape will be stored + * @param pt a FlPoint object that will be used to generate the path + * @param wid a FlPoint into which the advance width will be placed. + */ + private void parse(byte[] cs, GeneralPath gp, FlPoint pt, FlPoint wid) { + int loc = 0; + float x1, x2, x3, y1, y2, y3; + boolean flexMode = false; + float[] flexArray = new float[16]; + int flexPt = 0; + while (loc < cs.length) { + int v = (cs[loc++]) & 0xff; + if (v == 255) { + this.stack[this.sloc++] = (((cs[loc]) & 0xff) << 24) + + (((cs[loc + 1]) & 0xff) << 16) + + (((cs[loc + 2]) & 0xff) << 8) + + (((cs[loc + 3]) & 0xff)); + loc += 4; + } else if (v >= 251) { + this.stack[this.sloc++] = -((v - 251) << 8) - ((cs[loc]) & 0xff) - 108; + loc++; + } else if (v >= 247) { + this.stack[this.sloc++] = ((v - 247) << 8) + ((cs[loc]) & 0xff) + 108; + loc++; + } else if (v >= 32) { + this.stack[this.sloc++] = v - 139; + } else { + switch (v) { + case 0: // x + throw new RuntimeException("Bad command (" + v + ")"); + case 1: // hstem + this.sloc = 0; + break; + case 2: // x + throw new RuntimeException("Bad command (" + v + ")"); + case 3: // vstem + this.sloc = 0; + break; + case 4: // y vmoveto + pt.y += pop(); + if (flexMode) { + flexArray[flexPt++] = pt.x; + flexArray[flexPt++] = pt.y; + } + else{ + gp.moveTo(pt.x, pt.y); + } + this.sloc = 0; + break; + case 5: // x y rlineto + pt.y += pop(); + pt.x += pop(); + gp.lineTo(pt.x, pt.y); + this.sloc = 0; + break; + case 6: // x hlineto + pt.x += pop(); + gp.lineTo(pt.x, pt.y); + this.sloc = 0; + break; + case 7: // y vlineto + pt.y += pop(); + gp.lineTo(pt.x, pt.y); + this.sloc = 0; + break; + case 8: // x1 y1 x2 y2 x3 y3 rcurveto + y3 = pop(); + x3 = pop(); + y2 = pop(); + x2 = pop(); + y1 = pop(); + x1 = pop(); + gp.curveTo(pt.x + x1, pt.y + y1, + pt.x + x1 + x2, pt.y + y1 + y2, + pt.x + x1 + x2 + x3, pt.y + y1 + y2 + y3); + pt.x += x1 + x2 + x3; + pt.y += y1 + y2 + y3; + this.sloc = 0; + break; + case 9: // closepath + gp.closePath(); + this.sloc = 0; + break; + case 10: // n callsubr + int n = (int) pop(); + if (n == 1) { + flexMode = true; + flexPt = 0; + this.sloc = 0; + break; + } + if (n == 0) { + if (flexPt != 14) { + PDFDebugger.debug("There must be 14 flex entries!"); + } + else { + gp.curveTo(flexArray[2], flexArray[3], flexArray[4], + flexArray[5], + flexArray[6], flexArray[7]); + gp.curveTo(flexArray[8], flexArray[9], flexArray[10], + flexArray[11], + flexArray[12], flexArray[13]); + flexMode = false; + this.sloc = 0; + //System.out.println("End Flex " + flexPt); + break; + } + } + if (n == 2) { + if (flexMode == false) { + PDFDebugger.debug("Flex mode assumed"); + } + else { + this.sloc = 0; + break; + } + } + if (this.subrs[n] == null) { + PDFDebugger.debug("No subroutine #" + n); + } else { + this.callcount++; + if (this.callcount > 10) { + PDFDebugger.debug("Call stack too large"); + } else { + parse(this.subrs[n], gp, pt, wid); + } + this.callcount--; + } + break; + case 11: // return + return; + case 12: // ext... + v = (cs[loc++]) & 0xff; + if (v == 6) { // s x y a b seac + char a = (char) pop(); + char b = (char) pop(); + float y = pop(); + float x = pop(); + buildAccentChar(x, y, a, b, gp); + this.sloc = 0; + } else if (v == 7) { // x y w h sbw + wid.y = pop(); + wid.x = pop(); + pt.y = pop(); + pt.x = pop(); + this.sloc = 0; + } else if (v == 12) { // a b div -> a/b + float b = pop(); + float a = pop(); + this.stack[this.sloc++] = a / b; + } else if (v == 33) { // a b setcurrentpoint + pt.y = pop(); + pt.x = pop(); + gp.moveTo(pt.x, pt.y); + this.sloc = 0; + } else if (v == 0) { // dotsection + this.sloc = 0; + } else if (v == 1) { // vstem3 + this.sloc = 0; + } else if (v == 2) { // hstem3 + this.sloc = 0; + } else if (v == 16) { // n callothersubr + int cn = (int) pop(); + int countargs = (int) pop(); + + switch (cn) { + case 0: + // push args2 and args3 onto stack + this.psStack[this.psLoc++] = pop(); + this.psStack[this.psLoc++] = pop(); + pop(); + break; + case 3: + // push 3 onto the postscript stack + this.psStack[this.psLoc++] = 3; + break; + default: + // push arguments onto the postscript stack + for (int i = 0; i > countargs; i--) { + this.psStack[this.psLoc++] = pop(); + } + break; + } + } else if (v == 17) { // pop + // pop from the postscript stack onto the type1 stack + this.stack[this.sloc++] = this.psStack[this.psLoc - 1]; + this.psLoc--; + } else { + throw new RuntimeException("Bad command (" + v + ")"); + } + break; + case 13: // s w hsbw + wid.x = pop(); + wid.y = 0; + pt.x = pop(); + pt.y = 0; + // gp.moveTo(pt.x, pt.y); + this.sloc = 0; + break; + case 14: // endchar + // return; + break; + case 15: // x + case 16: // x + case 17: // x + case 18: // x + case 19: // x + case 20: // x + throw new RuntimeException("Bad command (" + v + ")"); + case 21: // x y rmoveto + pt.y += pop(); + pt.x += pop(); + if (flexMode) { + flexArray[flexPt++] = pt.x; + flexArray[flexPt++] = pt.y; + } + else{ + gp.moveTo(pt.x, pt.y); + } + this.sloc = 0; + break; + case 22: // x hmoveto + pt.x += pop(); + if (flexMode) { + flexArray[flexPt++] = pt.x; + flexArray[flexPt++] = pt.y; + } + else { + gp.moveTo(pt.x, pt.y); + } + this.sloc = 0; + break; + case 23: // x + case 24: // x + case 25: // x + case 26: // x + case 27: // x + case 28: // x + case 29: // x + throw new RuntimeException("Bad command (" + v + ")"); + case 30: // y1 x2 y2 x3 vhcurveto + x3 = pop(); + y2 = pop(); + x2 = pop(); + y1 = pop(); + x1 = y3 = 0; + gp.curveTo(pt.x, pt.y + y1, + pt.x + x2, pt.y + y1 + y2, + pt.x + x2 + x3, pt.y + y1 + y2); + pt.x += x2 + x3; + pt.y += y1 + y2; + this.sloc = 0; + break; + case 31: // x1 x2 y2 y3 hvcurveto + y3 = pop(); + y2 = pop(); + x2 = pop(); + x1 = pop(); + y1 = x3 = 0; + gp.curveTo(pt.x + x1, pt.y, + pt.x + x1 + x2, pt.y + y2, + pt.x + x1 + x2, pt.y + y2 + y3); + pt.x += x1 + x2; + pt.y += y2 + y3; + this.sloc = 0; + break; + } + } + } + } + + /** + * build an accented character out of two pre-defined glyphs. + * @param x the x offset of the accent relativ to the sidebearing of the base char + * @param y the y offset of the accent relativ to the sidebearing of the base char + * @param a the index of the accent glyph + * @param b the index of the base glyph + * @param gp the GeneralPath into which the combined glyph will be + * written. + */ + private void buildAccentChar(float x, float y, char a, char b, + GeneralPath gp) { + // get the outline of the accent + GeneralPath pathA = getOutline(a, getWidth(a, null)); + // don't manipulate the original glyph + pathA = (GeneralPath) pathA.clone(); + try { + final AffineTransform xformA = at.createInverse(); + pathA.transform(xformA); + // Best x can't be calculated cause we don't know the left sidebearing of the base character. + // Leaving x=0 gives the best results. + // see Chapter 6 of http://partners.adobe.com/public/developer/en/font/5015.Type1_Supp.pdf + // and the definition of the seac-Command in http://partners.adobe.com/public/developer/en/font/T1_SPEC.PDF + final AffineTransform xformA2 = AffineTransform.getTranslateInstance(0, y); + pathA.transform(xformA2); + } catch (NoninvertibleTransformException nte) { + pathA.transform(AffineTransform.getTranslateInstance(x, y)); + } + + GeneralPath pathB = getOutline(b, getWidth(b, null)); + + try { + AffineTransform xformB = this.at.createInverse(); + pathB.transform(xformB); + } catch (NoninvertibleTransformException nte) { + // ignore + } + + gp.append(pathB, false); + gp.append(pathA, false); + } + + /** + * Get the width of a given character + * + * This method is overridden to work if the width array hasn't been + * populated (as for one of the 14 base fonts) + */ + @Override + public float getWidth(char code, String name) { + // we don't have first and last chars, so therefore no width array + if (getFirstChar() == -1 || getLastChar() == -1) { + String key = this.chr2name[code & 0xff]; + + // use a name if one is provided + if (name != null) { + key = name; + } + + if (key != null && this.name2outline.containsKey(key)) { + if (!this.name2width.containsKey(key)) { + // glyph has not yet been parsed + // getting the outline will force it to get read + getOutline(key, 0); + } + + FlPoint width = this.name2width.get(key); + if (width != null) { + return width.x / getDefaultWidth(); + } + } + + return 0; + } + + // return the width that has been specified + return super.getWidth(code, name); + } + + /** + * Decrypt a glyph stored in byte form + */ + private synchronized GeneralPath parseGlyph(byte[] cs, FlPoint advance, + AffineTransform at) { + GeneralPath gp = new GeneralPath(); + FlPoint curpoint = new FlPoint(); + + this.sloc = 0; + parse(cs, gp, curpoint, advance); + + gp.transform(at); + return gp; + } + + /** + * Get a glyph outline by name + * + * @param name the name of the desired glyph + * @return the glyph outline, or null if unavailable + */ + @Override + protected GeneralPath getOutline(String name, float width) { + // make sure we have a valid name + if (name == null || !this.name2outline.containsKey(name)) { + name = ".notdef"; + } + + // get whatever is stored in name. Could be a GeneralPath, could be byte[] + Object obj = this.name2outline.get(name); + + // if it's a byte array, it needs to be parsed + // otherwise, just return the path + if (obj instanceof GeneralPath) { + return (GeneralPath) obj; + } else { + byte[] cs = (byte[]) obj; + FlPoint advance = new FlPoint(); + + GeneralPath gp = parseGlyph(cs, advance, this.at); + + if (width != 0 && advance.x != 0) { + // scale the glyph to fit in the width + Point2D p = new Point2D.Float(advance.x, advance.y); + this.at.transform(p, p); + + double scale = width / p.getX(); + AffineTransform xform = AffineTransform.getScaleInstance(scale, 1.0); + gp.transform(xform); + } + + // put the parsed object in the cache + this.name2outline.put(name, gp); + this.name2width.put(name, advance); + return gp; + } + } + + /** + * Get a glyph outline by character code + * + * Note this method must always return an outline + * + * @param src the character code of the desired glyph + * @return the glyph outline + */ + @Override + protected GeneralPath getOutline(char src, float width) { + return getOutline(this.chr2name[src & 0xff], width); + } + + public boolean isName2OutlineFilled() { + return (name2outline!=null) && !name2outline.isEmpty(); + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/Type3Font.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/Type3Font.java new file mode 100644 index 000000000..5ff41d724 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/Type3Font.java @@ -0,0 +1,176 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.sun.pdfview.font; + +import java.awt.geom.AffineTransform; +import java.awt.geom.GeneralPath; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import com.sun.pdfview.BaseWatchable; +import com.sun.pdfview.PDFDebugger; +import com.sun.pdfview.PDFFile; +import com.sun.pdfview.PDFObject; +import com.sun.pdfview.PDFPage; +import com.sun.pdfview.PDFParser; + +/** + * A Type 3 Font, in which each glyph consists of a sequence of PDF + * commands. + * + * @author Mike Wessler + */ +public class Type3Font extends PDFFont { + + /** resources for the character definitions */ + HashMap rsrc; + /** the character processes, mapped by name */ + Map charProcs; + /** bounding box for the font characters */ + Rectangle2D bbox; + /** affine transform for the font characters */ + AffineTransform at; + /** the widths */ + float[] widths; + /** the start code */ + int firstChar; + /** the end code */ + int lastChar; + + /** + * Generate a Type 3 font. + * @param baseFont the postscript name of this font + * @param fontObj a dictionary containing references to the character + * definitions and font information + * @param resources a set of resources used by the character definitions + * @param descriptor the descriptor for this font + */ + public Type3Font(String baseFont, PDFObject fontObj, + HashMap resources, PDFFontDescriptor descriptor) throws IOException { + super(baseFont, descriptor); + + this.rsrc = new HashMap(); + + if (resources != null) { + this.rsrc.putAll(resources); + } + + // get the transform matrix + PDFObject matrix = fontObj.getDictRef("FontMatrix"); + float matrixAry[] = new float[6]; + for (int i = 0; i < 6; i++) { + matrixAry[i] = matrix.getAt(i).getFloatValue(); + } + this.at = new AffineTransform(matrixAry); + + // get the scale from the matrix + float scale = matrixAry[0] + matrixAry[2]; + + // put all the resources in a Hash + PDFObject rsrcObj = fontObj.getDictRef("Resources"); + if (rsrcObj != null) { + this.rsrc.putAll(rsrcObj.getDictionary()); + } + + // get the character processes, indexed by name + this.charProcs = fontObj.getDictRef("CharProcs").getDictionary(); + + // get the font bounding box + bbox = PDFFile.parseNormalisedRectangle(fontObj.getDictRef("FontBBox")); + if (bbox.isEmpty()) { + bbox = null; + } + + // get the widths + PDFObject[] widthArray = fontObj.getDictRef("Widths").getArray(); + this.widths = new float[widthArray.length]; + for (int i = 0; i < widthArray.length; i++) { + this.widths[i] = widthArray[i].getFloatValue(); + } + + // get first and last chars + this.firstChar = fontObj.getDictRef("FirstChar").getIntValue(); + this.lastChar = fontObj.getDictRef("LastChar").getIntValue(); + } + + /** + * Get the first character code + */ + public int getFirstChar() { + return this.firstChar; + } + + /** + * Get the last character code + */ + public int getLastChar() { + return this.lastChar; + } + + /** + * Get the glyph for a given character code and name + * + * The preferred method of getting the glyph should be by name. If the + * name is null or not valid, then the character code should be used. + * If the both the code and the name are invalid, the undefined glyph + * should be returned. + * + * Note this method must *always* return a glyph. + * + * @param src the character code of this glyph + * @param name the name of this glyph or null if unknown + * @return a glyph for this character + */ + @Override + protected PDFGlyph getGlyph(char src, String name) { + if (name == null) { + throw new IllegalArgumentException("Glyph name required for Type3 font!" + + "Source character: " + (int) src); + } + + PDFObject pageObj = (PDFObject) this.charProcs.get(name); + if (pageObj == null) { + // glyph not found. Return an empty glyph... + return new PDFGlyph(src, name, new GeneralPath(), new Point2D.Float(0, 0)); + } + + try { + PDFPage page = new PDFPage(this.bbox, 0); + page.addXform(this.at); + + PDFParser prc = new PDFParser(page, pageObj.getStream(), this.rsrc); + prc.go(true); + + float width = this.widths[src - this.firstChar]; + + Point2D advance = new Point2D.Float(width, 0); + advance = this.at.transform(advance, null); + + return new PDFGlyph(src, name, page, advance); + } catch (IOException ioe) { + // help! + PDFDebugger.debug("IOException in Type3 font: " + ioe); + BaseWatchable.getErrorHandler().publishException(ioe); + return null; + } + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/cid/PDFCMap.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/cid/PDFCMap.java new file mode 100644 index 000000000..b2f719548 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/cid/PDFCMap.java @@ -0,0 +1,108 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.sun.pdfview.font.cid; + +import java.io.IOException; +import java.util.HashMap; + +import com.sun.pdfview.PDFDebugger; +import com.sun.pdfview.PDFObject; + +/** + * A CMap maps from a character in a composite font to a font/glyph number + * pair in a CID font. + * + * @author jkaplan + */ +public abstract class PDFCMap { + /** + * A cache of known CMaps by name + */ + private static HashMap cache; + + /** Creates a new instance of CMap */ + protected PDFCMap() {} + + /** + * Get a CMap, given a PDF object containing one of the following: + * a string name of a known CMap + * a stream containing a CMap definition + */ + public static PDFCMap getCMap(PDFObject map) throws IOException { + if (map.getType() == PDFObject.NAME) { + return getCMap(map.getStringValue()); + } else if (map.getType() == PDFObject.STREAM) { + return parseCMap(map); + } else { + throw new IOException("CMap type not Name or Stream!"); + } + } + + /** + * Get a CMap, given a string name + */ + public static PDFCMap getCMap(String mapName) throws IOException { + if (cache == null) { + populateCache(); + } + + if (!cache.containsKey(mapName)) { + //throw new IOException("Unknown CMap: " + mapName); + PDFDebugger.debug("Unknown CMap: '" + mapName + "' procced with 'Identity-H'"); + return cache.get("Identity-H"); + } + + return cache.get(mapName); + } + + /** + * Populate the cache with well-known types + */ + protected static void populateCache() { + cache = new HashMap(); + + // add the Identity-H map + cache.put("Identity-H", new PDFCMap() { + @Override + public char map(char src) { + return src; + } + }); + } + + /** + * Parse a CMap from a CMap stream + */ + protected static PDFCMap parseCMap(PDFObject map) throws IOException { + return new ToUnicodeMap(map); + } + + /** + * Map a given source character to a destination character + */ + public abstract char map(char src); + + /** + * Get the font number assoicated with a given source character + */ + public int getFontID(char src) { + return 0; + } + +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/cid/ToUnicodeMap.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/cid/ToUnicodeMap.java new file mode 100644 index 000000000..86bf865c5 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/cid/ToUnicodeMap.java @@ -0,0 +1,310 @@ +package com.sun.pdfview.font.cid; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.StringReader; +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.sun.pdfview.PDFObject; + +/***************************************************************************** + * Parses a CMAP and builds a lookup table to map CMAP based codes to unicode. + * This is not a fully functional CMAP parser but a stripped down parser + * that should be able to parse some limited variants of CMAPs that are + * used for the ToUnicode mapping found for some Type0 fonts. + * + * @author Bernd Rosstauscher + * @since 03.08.2011 + ****************************************************************************/ + +public class ToUnicodeMap extends PDFCMap { + + /***************************************************************************** + * Small helper class to define a code range. + ****************************************************************************/ + + private static class CodeRangeMapping { + char srcStart; + char srcEnd; + + CodeRangeMapping(char srcStart, char srcEnd) { + this.srcStart = srcStart; + this.srcEnd = srcEnd; + } + + boolean contains(char c) { + return this.srcStart <= c + && c <= this.srcEnd; + } + + } + + /***************************************************************************** + * Small helper class to define a char range. + ****************************************************************************/ + + private static class CharRangeMapping { + char srcStart; + char srcEnd; + char destStart; + + CharRangeMapping(char srcStart, char srcEnd, char destStart) { + this.srcStart = srcStart; + this.srcEnd = srcEnd; + this.destStart = destStart; + } + + boolean contains(char c) { + return this.srcStart <= c + && c <= this.srcEnd; + } + + char map(char src) { + return (char) (this.destStart + (src-this.srcStart)); + } + + } + + private final Map singleCharMappings; + private final List charRangeMappings; + private final List codeRangeMappings; + + /************************************************************************* + * Constructor + * @param map + * @throws IOException + ************************************************************************/ + + public ToUnicodeMap(PDFObject map) throws IOException { + super(); + this.singleCharMappings = new HashMap(); + this.charRangeMappings = new ArrayList(); + this.codeRangeMappings = new ArrayList(); + parseMappings(map); + } + + /************************************************************************* + * @param map + * @throws IOException + ************************************************************************/ + + private void parseMappings(PDFObject map) throws IOException { + try { + StringReader reader = new StringReader(new String(map.getStream(), "ASCII")); + BufferedReader bf = new BufferedReader(reader); + String line = bf.readLine(); + while (line != null) { + if (line.contains("beginbfchar") || line.contains("begincidchar")) { + parseSingleCharMappingSection(bf, line.contains("begincidchar")); + } + if (line.contains("beginbfrange") || line.contains("begincidrange")) { + parseCharRangeMappingSection(bf, line.contains("begincidrange")); + } + if (line.contains("begincodespacerange")) { + parseCodeRangeMappingSection(bf, line); + } + line = bf.readLine(); + } + } catch (UnsupportedEncodingException e) { + throw new IOException(e); + } + } + + /************************************************************************* + * @param bf + * @throws IOException + ************************************************************************/ + + private void parseCharRangeMappingSection(BufferedReader bf, boolean isCid) throws IOException { + String line = bf.readLine(); + while (line != null) { + if (line.contains("endbfrange") || line.contains("endcidrange")) { + break; + } + parseRangeLine(line, isCid); + line = bf.readLine(); + } + } + + private void parseCodeRangeMappingSection(BufferedReader bf, String line) throws IOException { + //check if the prev line contains "endcodespacerange" + if(line.contains("endcodespacerange")) { + int indexOf = line.indexOf("endcodespacerange"); + line = line.substring(0, indexOf); + indexOf = line.indexOf("begincodespacerange"); + line = line.substring(indexOf+"begincodespacerange".length(), line.length()); + line = line.trim(); + + parseCodeRangeLine(line); + } + else { + String rline = bf.readLine(); + while (rline != null) { + if (rline.contains("endcodespacerange")) { + break; + } + parseCodeRangeLine(rline); + rline = bf.readLine(); + } + } + } + + /************************************************************************* + * @param line + * @return + ************************************************************************/ + + private void parseRangeLine(String line, boolean isCid) { + String[] mapping = line.split(" "); + if (mapping.length == 3) { + Character srcStart = parseChar(mapping[0]); + Character srcEnd = parseChar(mapping[1]); + Character destStart; + if(isCid) { + destStart = (char)Integer.parseInt(mapping[2]); + } + else { + destStart = parseChar(mapping[2]); + } + this.charRangeMappings.add(new CharRangeMapping(srcStart, srcEnd, destStart)); + } + else { + int indexOf1 = line.indexOf(">"); + String substring1 = line.substring(0, indexOf1+1); + + int indexOf2 = line.indexOf("<", indexOf1); + int indexOf3 = line.indexOf(">", indexOf2); + String substring2 = line.substring(indexOf2, indexOf3+1); + + int indexOf4 = line.indexOf("<", indexOf3); + String substring3 = line.substring(indexOf4, line.length()); + + if(!substring1.isEmpty() && !substring2.isEmpty() && !substring3.isEmpty()) { + Character srcStart = parseChar(substring1); + Character srcEnd = parseChar(substring2); + Character destStart = parseChar(substring3); + this.charRangeMappings.add(new CharRangeMapping(srcStart, srcEnd, destStart)); + } + } + } + + private void parseCodeRangeLine(String line) { + String[] mapping = line.split(" "); + if (mapping.length == 2) { + Character srcStart = parseChar(mapping[0]); + Character srcEnd = parseChar(mapping[1]); + this.codeRangeMappings.add(new CodeRangeMapping(srcStart, srcEnd)); + } + else { + int indexOf1 = line.indexOf(">"); + String substring1 = line.substring(0, indexOf1+1); + + int indexOf2 = line.indexOf("<", indexOf1); + String substring2 = line.substring(indexOf2, line.length()); + + if(!substring1.isEmpty() && !substring2.isEmpty()) { + Character srcStart = parseChar(substring1); + Character srcEnd = parseChar(substring2); + this.codeRangeMappings.add(new CodeRangeMapping(srcStart, srcEnd)); + } + } + } + + /************************************************************************* + * @param bf + * @throws IOException + ************************************************************************/ + + private void parseSingleCharMappingSection(BufferedReader bf, boolean isCID) throws IOException { + String line = bf.readLine(); + while (line != null) { + if (line.contains("endbfchar") || line.contains("endcidchar")) { + break; + } + parseSingleCharMappingLine(line, isCID); + line = bf.readLine(); + } + } + + /************************************************************************* + * @param line + * @return + ************************************************************************/ + + private void parseSingleCharMappingLine(String line, boolean isCID) { + String[] mapping = line.split(" "); + if (mapping.length == 2) { + if(isCID) { + this.singleCharMappings.put(parseChar(mapping[0]), (char)Integer.parseInt(mapping[1])); + } + else { + this.singleCharMappings.put(parseChar(mapping[0]), parseChar(mapping[1])); + } + } + } + + /************************************************************************* + * Parse a string of the format <0F3A> to a char. + * @param charDef + * @return + ************************************************************************/ + + private Character parseChar(String charDef) { + if (charDef.startsWith("<")) { + charDef = charDef.substring(1); + } + if (charDef.endsWith(">")) { + charDef = charDef.substring(0, charDef.length()-1); + } + try { + long result = Long.decode("0x" + charDef); + return (char) result; + } catch (NumberFormatException e) { + return (char) ' '; + } + } + + /************************************************************************* + * map + * @see com.sun.pdfview.font.cid.PDFCMap#map(char) + ************************************************************************/ + @Override + public char map(char src) { + Character mappedChar = null; + for (CodeRangeMapping codeRange : this.codeRangeMappings) { + if(codeRange.contains(src)) { + mappedChar = this.singleCharMappings.get(src); + if (mappedChar == null) { + mappedChar = lookupInRanges(src); + } + break; + } + } + if (mappedChar == null) { + // TODO XOND 27.03.2012: PDF Spec. "9.7.6.3Handling Undefined Characters" + mappedChar = 0; + } + return mappedChar; + } + + /************************************************************************* + * @param src + * @return + ************************************************************************/ + + private Character lookupInRanges(char src) { + Character mappedChar = null; + for (CharRangeMapping rangeMapping : this.charRangeMappings) { + if (rangeMapping.contains(src)) { + mappedChar = rangeMapping.map(src); + break; + } + } + return mappedChar; + } + +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/AdobeGlyphList.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/AdobeGlyphList.java new file mode 100644 index 000000000..c0f508623 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/AdobeGlyphList.java @@ -0,0 +1,181 @@ +package com.sun.pdfview.font.ttf; + +import java.io.*; +import java.util.*; + +/** + * Build an object which provides access to all the Adobe glyph names, using + * a unicode value, and which can translate a glyph name to one or more + * unicode values. + * +# ################################################################################### +# Copyright (c) 1997,1998,2002,2007 Adobe Systems Incorporated +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this documentation file to use, copy, publish, distribute, +# sublicense, and/or sell copies of the documentation, and to permit +# others to do the same, provided that: +# - No modification, editing or other alteration of this document is +# allowed; and +# - The above copyright notice and this permission notice shall be +# included in all copies of the documentation. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this documentation file, to create their own derivative works +# from the content of this document to use, copy, publish, distribute, +# sublicense, and/or sell the derivative works, and to permit others to do +# the same, provided that the derived work is not represented as being a +# copy or version of this document. +# +# Adobe shall not be liable to any party for any loss of revenue or profit +# or for indirect, incidental, special, consequential, or other similar +# damages, whether based on tort (including without limitation negligence +# or strict liability), contract or other legal or equitable grounds even +# if Adobe has been advised or had reason to know of the possibility of +# such damages. The Adobe materials are provided on an "AS IS" basis. +# Adobe specifically disclaims all express, statutory, or implied +# warranties relating to the Adobe materials, including but not limited to +# those concerning merchantability or fitness for a particular purpose or +# non-infringement of any third party rights regarding the Adobe +# materials. +# ################################################################################### +# Name: Adobe Glyph List +# Table version: 2.0 +# Date: September 20, 2002 +# +# See http://partners.adobe.com/asn/developer/typeforum/unicodegn.html +# +# Format: Semicolon-delimited fields: +# (1) glyph name +# (2) Unicode scalar value + * + * @author tomoke + */ +public class AdobeGlyphList { + + /** provide a translation from a glyph name to the possible unicode values. */ + static private HashMap glyphToUnicodes; + /** provide a translation from a unicode value to a glyph name. */ + static private HashMap unicodeToGlyph; + /** the loader thread we are reading through. */ + static Thread glyphLoaderThread = null; + + + static { + new AdobeGlyphList(); + } + + /** + *

    private constructor to restrict creation to a singleton.

    + * + *

    We initialize by creating the storage and parsing the glyphlist + * into the tables.

    + */ + private AdobeGlyphList() { + glyphToUnicodes = new HashMap(4500); + unicodeToGlyph = new HashMap(4500); + glyphLoaderThread = new Thread(new Runnable() { + + @Override + public void run() { + int[] codes; + StringTokenizer codeTokens; + String glyphName; + StringTokenizer tokens; + ArrayList unicodes = new ArrayList(); + + InputStream istr = getClass().getResourceAsStream("/com/sun/pdfview/font/ttf/resource/glyphlist.txt"); + + BufferedReader reader = new BufferedReader(new InputStreamReader(istr)); + String line = ""; + while (line != null) { + try { + unicodes.clear(); + line = reader.readLine(); + if (line == null) { + break; + } + line = line.trim(); + if (line.length() > 0 && !line.startsWith("#")) { + // ignore comment lines + tokens = new StringTokenizer(line, ";"); + glyphName = tokens.nextToken(); + codeTokens = new StringTokenizer(tokens.nextToken(), " "); + while (codeTokens.hasMoreTokens()) { + unicodes.add(codeTokens.nextToken()); + } + codes = new int[unicodes.size()]; + for (int i = 0; i < unicodes.size(); i++) { + codes[i] = Integer.parseInt(unicodes.get(i), 16); + unicodeToGlyph.put(Integer.valueOf(codes[i]), glyphName); + } + glyphToUnicodes.put(glyphName, codes); + } + + } catch (IOException ex) { + break; + } + } + } + }, "Adobe Glyph Loader Thread"); + glyphLoaderThread.setDaemon(true); + glyphLoaderThread.setPriority(Thread.MIN_PRIORITY); + glyphLoaderThread.start(); + } + + /** + * translate a glyph name into the possible unicode values that it + * might represent. It is possible to have more than one unicode + * value for a single glyph name. + * + * @param glyphName + * @return int[] + */ + public static int[] getUnicodeValues(String glyphName) { + while (glyphLoaderThread != null && glyphLoaderThread.isAlive()) { + synchronized (glyphToUnicodes) { + try { + glyphToUnicodes.wait(250); + } catch (InterruptedException ex) { + // ignore + } + } + } + return glyphToUnicodes.get(glyphName); + } + + /** + * return a single index for a glyph, though there may be multiples. + * + * @param glyphName + * @return Integer + */ + public static Integer getGlyphNameIndex(String glyphName) { + int [] unicodes = getUnicodeValues(glyphName); + if (unicodes == null) { + return null; + } else { + return Integer.valueOf(unicodes[0]); + } + } + + /** + * translate a unicode value into a glyph name. It is possible for + * different unicode values to translate into the same glyph name. + * + * @param unicode + * @return String + */ + public static String getGlyphName(int unicode) { + while (glyphLoaderThread != null && glyphLoaderThread.isAlive()) { + synchronized (glyphToUnicodes) { + try { + glyphToUnicodes.wait(250); + } catch (InterruptedException ex) { + // ignore + } + } + } + return unicodeToGlyph.get(Integer.valueOf(unicode)); + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/CMap.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/CMap.java new file mode 100644 index 000000000..3cfc46aac --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/CMap.java @@ -0,0 +1,185 @@ +/* + * $Id: CMap.java,v 1.1 2009-07-01 12:43:20 bros Exp $ + * + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.sun.pdfview.font.ttf; + +import java.nio.ByteBuffer; + +import com.sun.pdfview.PDFDebugger; + +/** + * + * @author jkaplan + */ +public abstract class CMap { + + /** + * The format of this map + */ + private final short format; + + /** + * The language of this map, or 0 for language-independent + */ + private final short language; + + /** Creates a new instance of CMap + * Don't use this directly, use CMap.createMap() + */ + protected CMap (short format, short language) { + this.format = format; + this.language = language; + } + + /** + * Create a map for the given format and language + + *

    The Macintosh standard character to glyph mapping is supported + * by format 0.

    + * + *

    Format 2 supports a mixed 8/16 bit mapping useful for Japanese, + * Chinese and Korean.

    + * + *

    Format 4 is used for 16 bit mappings.

    + * + *

    Format 6 is used for dense 16 bit mappings.

    + * + *

    Formats 8, 10, and 12 (properly 8.0, 10.0, and 12.0) are used + * for mixed 16/32-bit and pure 32-bit mappings.
    + * This supports text encoded with surrogates in Unicode 2.0 and later.

    + * + *

    Reference:
    + * http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6cmap.html

    + */ + public static CMap createMap (short format, short language) { + CMap outMap = null; + + switch (format) { + case 0: // CMap format 0 - single byte codes + outMap = new CMapFormat0 (language); + break; + case 4: // CMap format 4 - two byte encoding + outMap = new CMapFormat4 (language); + break; + case 6: // CMap format 6 - 16-bit, two byte encoding + outMap = new CMapFormat6 (language); + break; +// case 8: // CMap format 8 - Mixed 16-bit and 32-bit coverage +// outMap = new CMapFormat_8(language); +// break; +// // CMap format 10 - Format 10.0 is a bit like format 6, in that it +// // defines a trimmed array for a tight range of 32-bit character codes: +// case 10: +// outMap = new CMapFormat_10(language); +// break; +// // Format 12.0 is a bit like format 4, in that it defines +// // segments for sparse representation in 4-byte character space. +// case 12: // CMap format 12 - +// outMap = new CMapFormat_12(language); +// break; + default: + PDFDebugger.debug("Unsupport CMap format: " + format); + return null; + } + + return outMap; + } + + /** + * Get a map from the given data + * + * This method reads the format, data and length variables of + * the map. + */ + public static CMap getMap (ByteBuffer data) { + short format = data.getShort (); + short lengthShort = data.getShort (); + int length = 0xFFFF & lengthShort; + PDFDebugger.debug("CMAP, length: " + length + ", short: " + lengthShort, 100); + + // make sure our slice of the data only contains up to the length + // of this table + data.limit (Math.min (length, data.limit ())); + + short language = data.getShort (); + + CMap outMap = createMap (format, language); + if (outMap == null) { + return null; + } + + outMap.setData (data.limit (), data); + + return outMap; + } + + /** + * Get the format of this map + */ + public short getFormat () { + return this.format; + } + + /** + * Get the language of this map + */ + public short getLanguage () { + return this.language; + } + + /** + * Set the data for this map + */ + public abstract void setData (int length, ByteBuffer data); + + /** + * Get the data in this map as a byte buffer + */ + public abstract ByteBuffer getData (); + + /** + * Get the length of this map + */ + public abstract short getLength (); + + /** + * Map an 8 bit value to another 8 bit value + */ + public abstract byte map (byte src); + + /** + * Map a 16 bit value to another 16 but value + */ + public abstract char map (char src); + + /** + * Get the src code which maps to the given glyphID + */ + public abstract char reverseMap (short glyphID); + + /** Print a pretty string */ + @Override + public String toString () { + String indent = " "; + + return indent + " format: " + getFormat () + " length: " + + getLength () + " language: " + getLanguage () + "\n"; + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/CMapFormat0.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/CMapFormat0.java new file mode 100644 index 000000000..88b9488c9 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/CMapFormat0.java @@ -0,0 +1,157 @@ +/* + * $Id: CMapFormat0.java,v 1.1 2009-07-01 12:43:20 bros Exp $ + * + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package com.sun.pdfview.font.ttf; + +import java.nio.ByteBuffer; + +/** + * + * @author jkaplan + */ +public class CMapFormat0 extends CMap { + + /** + * The glyph index array + */ + private byte[] glyphIndex; + + /** Creates a new instance of CMapFormat0 */ + protected CMapFormat0(short language) { + super((short) 0, language); + + byte[] initialIndex = new byte[256]; + for (int i = 0; i < initialIndex.length; i++) { + initialIndex[i] = (byte) i; + } + setMap(initialIndex); + } + + /** + * Get the length of this table + */ + @Override + public short getLength() { + return (short) 262; + } + + /** + * Map from a byte + */ + @Override + public byte map(byte src) { + int i = 0xff & src; + + return this.glyphIndex[i]; + } + + /** + * Cannot map from short + */ + @Override + public char map(char src) { + if (src < 0 || src > 255) { + // out of range + return (char) 0; + } + + return (char) (map((byte) src) & 0xff); + } + + + /** + * Get the src code which maps to the given glyphID + */ + @Override + public char reverseMap(short glyphID) { + for (int i = 0; i < this.glyphIndex.length; i++) { + if ((this.glyphIndex[i] & 0xff) == glyphID) { + return (char) i; + } + } + + return (char) 0; + } + + /** + * Set the entire map + */ + public void setMap(byte[] glyphIndex) { + if (glyphIndex.length != 256) { + throw new IllegalArgumentException("Glyph map must be size 256!"); + } + + this.glyphIndex = glyphIndex; + } + + /** + * Set a single mapping entry + */ + public void setMap(byte src, byte dest) { + int i = 0xff & src; + + this.glyphIndex[i] = dest; + } + + /** + * Get the whole map + */ + protected byte[] getMap() { + return this.glyphIndex; + } + + /** + * Get the data in this map as a ByteBuffer + */ + @Override + public ByteBuffer getData() { + ByteBuffer buf = ByteBuffer.allocate(262); + + buf.putShort(getFormat()); + buf.putShort(getLength()); + buf.putShort(getLanguage()); + buf.put(getMap()); + + // reset the position to the beginning of the buffer + buf.flip(); + + return buf; + } + + /** + * Read the map in from a byte buffer + */ + @Override + public void setData(int length, ByteBuffer data) { + if (length != 262) { + throw new IllegalArgumentException("Bad length for CMap format 0"); + } + + if (data.remaining() != 256) { + throw new IllegalArgumentException("Wrong amount of data for CMap format 0"); + } + + byte[] map = new byte[256]; + data.get(map); + + setMap(map); + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/CMapFormat4.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/CMapFormat4.java new file mode 100644 index 000000000..f467c6972 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/CMapFormat4.java @@ -0,0 +1,466 @@ +/* + * $Id: CMapFormat4.java,v 1.3 2011-04-15 15:44:14 xphc Exp $ + * + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package com.sun.pdfview.font.ttf; + +import java.nio.ByteBuffer; +import java.util.Collections; +import java.util.Iterator; +import java.util.SortedMap; +import java.util.TreeMap; + +import com.sun.pdfview.font.ttf.CMapFormat4.Segment; + +/** + * + * @author jkaplan + */ +public class CMapFormat4 extends CMap { + + /** + * The segments and associated data can be a char[] or an Integer + */ + public SortedMap segments; + + /** Creates a new instance of CMapFormat0 */ + protected CMapFormat4(short language) { + super((short) 4, language); + + this.segments = Collections.synchronizedSortedMap(new TreeMap()); + + char[] map = new char[1]; + map[0] = (char) 0; + addSegment((short) 0xffff, (short) 0xffff, map); + } + + /** + * Add a segment with a map + */ + public void addSegment(short startCode, short endCode, char[] map) { + if (map.length != (endCode - startCode) + 1) { + throw new IllegalArgumentException("Wrong number of entries in map"); + } + + Segment s = new Segment(startCode, endCode, true); + // make sure we remove any old entries + this.segments.remove(s); + this.segments.put(s, map); + } + + /** + * Add a segment with an idDelta + */ + public void addSegment(short startCode, short endCode, short idDelta) { + Segment s = new Segment(startCode, endCode, false); + // make sure we remove any old entries + this.segments.remove(s); + this.segments.put(s, Integer.valueOf(idDelta)); + } + + /** + * Remove a segment + */ + public void removeSegment(short startCode, short endCode) { + Segment s = new Segment(startCode, endCode, true); + this.segments.remove(s); + } + + /** + * Get the length of this table + */ + @Override + public short getLength() { + // start with the size of the fixed header + short size = 16; + + // add the size of each segment header + size += this.segments.size() * 8; + + // add the total number of mappings times the size of a mapping + for (Iterator i = this.segments.keySet().iterator(); i.hasNext();) { + Segment s = (Segment) i.next(); + + // see if there's a map + if (s.hasMap) { + // if there is, add its size + char[] map = (char[]) this.segments.get(s); + size += map.length * 2; + } + } + + return size; + } + + /** + * Cannot map from a byte + */ + @Override + public byte map(byte src) { + char c = map((char) src); + if (c < Byte.MIN_VALUE || c > Byte.MAX_VALUE) { + // out of range + return 0; + } + + return (byte) c; + } + + /** + * Map from char + */ + @Override + public char map(char src) { + // find first segment with endcode > src + for (Iterator i = this.segments.keySet().iterator(); i.hasNext();) { + Segment s = (Segment) i.next(); + + if (s.endCode >= src) { + // are we within range? + if (s.startCode <= src) { + if (s.hasMap) { + // return the index of this character in + // the segment's map + char[] map = (char[]) this.segments.get(s); + return map[src - s.startCode]; + } else { + // return the character code + idDelta + Integer idDelta = (Integer) this.segments.get(s); + return (char) (src + idDelta.intValue()); + } + } else { + // undefined character + return (char) 0; + } + } + } + + // shouldn't get here! + return (char) 0; + } + + /** + * Get the src code which maps to the given glyphID + */ + @Override + public char reverseMap(short glyphID) { + // look at each segment + for (Iterator i = this.segments.keySet().iterator(); i.hasNext();) { + Segment s = (Segment) i.next(); + + // see if we have a map or a delta + if (s.hasMap) { + char[] map = (char[]) this.segments.get(s); + + // if we have a map, we have to iterate through it + for (int c = 0; c < map.length; c++) { + if (map[c] == glyphID) { + return (char) (s.startCode + c); + } + } + } else { + Integer idDelta = (Integer) this.segments.get(s); + + // we can do the math to see if we're in range + int start = s.startCode + idDelta.intValue(); + int end = s.endCode + idDelta.intValue(); + + if (glyphID >= start && glyphID <= end) { + // we're in the range + return (char) (glyphID - idDelta.intValue()); + } + } + } + + // not found! + return (char) 0; + } + + + /** + * Get the data in this map as a ByteBuffer + */ + @Override + public void setData(int length, ByteBuffer data) { + // read the table size values + short segCount = (short) (data.getShort() / 2); + short searchRange = data.getShort(); + short entrySelector = data.getShort(); + short rangeShift = data.getShort(); + + // create arrays to store segment info + short[] endCodes = new short[segCount]; + short[] startCodes = new short[segCount]; + short[] idDeltas = new short[segCount]; + short[] idRangeOffsets = new short[segCount]; + + // the start of the glyph array + int glyphArrayPos = 16 + (8 * segCount); + + // read the endCodes + for (int i = 0; i < segCount; i++) { + endCodes[i] = data.getShort(); + } + + // read the pad + data.getShort(); + + // read the start codes + for (int i = 0; i < segCount; i++) { + startCodes[i] = data.getShort(); + } + + // read the idDeltas + for (int i = 0; i < segCount; i++) { + idDeltas[i] = data.getShort(); + } + + // read the id range offsets + for (int i = 0; i < segCount; i++) { + idRangeOffsets[i] = data.getShort(); + + // calculate the actual offset + if (idRangeOffsets[i] <= 0) { + // the easy way + addSegment(startCodes[i], endCodes[i], idDeltas[i]); + } else { + // find the start of the data segment + int offset = (data.position() - 2) + idRangeOffsets[i]; + + // get the number of entries in the map + int size = (endCodes[i] - startCodes[i]) + 1; + + // allocate the actual map + char[] map = new char[size]; + + // remember our offset + data.mark(); + + // read the mappings + for (int c = 0; c < size; c++) { + data.position(offset + (c * 2)); + map[c] = data.getChar(); + } + + // reset the position + data.reset(); + + addSegment(startCodes[i], endCodes[i], map); + } + } + } + + /** + * Get the data in the map as a byte buffer + */ + @Override + public ByteBuffer getData() { + ByteBuffer buf = ByteBuffer.allocate(getLength()); + + // write the header + buf.putShort(getFormat()); + buf.putShort(getLength()); + buf.putShort(getLanguage()); + + // write the various values + buf.putShort((short) (getSegmentCount() * 2)); + buf.putShort(getSearchRange()); + buf.putShort(getEntrySelector()); + buf.putShort(getRangeShift()); + + // write the endCodes + for (Iterator i = this.segments.keySet().iterator(); i.hasNext();) { + Segment s = i.next(); + buf.putShort((short) s.endCode); + } + + // write the pad + buf.putShort((short) 0); + + // write the startCodes + for (Iterator i = this.segments.keySet().iterator(); i.hasNext();) { + Segment s = i.next(); + buf.putShort((short) s.startCode); + } + + // write the idDeltas for segments using deltas + for (Iterator i = this.segments.keySet().iterator(); i.hasNext();) { + Segment s = i.next(); + + if (!s.hasMap) { + Integer idDelta = (Integer) this.segments.get(s); + buf.putShort(idDelta.shortValue()); + } else { + buf.putShort((short) 0); + } + } + + // the start of the glyph array + int glyphArrayOffset = 16 + (8 * getSegmentCount()); + + // write the idRangeOffsets and maps for segments using maps + for (Iterator i = this.segments.keySet().iterator(); i.hasNext();) { + Segment s = i.next(); + + if (s.hasMap) { + // first set the offset, which is the number of bytes from the + // current position to the current offset + buf.putShort((short) (glyphArrayOffset - buf.position())); + + // remember the current position + buf.mark(); + + // move the position to the offset + buf.position(glyphArrayOffset); + + // now write the map + char[] map = (char[]) this.segments.get(s); + for (int c = 0; c < map.length; c++) { + buf.putChar(map[c]); + } + + // reset the data pointer + buf.reset(); + + // update the offset + glyphArrayOffset += map.length * 2; + } else { + buf.putShort((short) 0); + } + } + + // make sure we are at the end of the buffer before we flip + buf.position(glyphArrayOffset); + + // reset the data pointer + buf.flip(); + + return buf; + } + + /** + * Get the segment count + */ + public short getSegmentCount() { + return (short) this.segments.size(); + } + + /** + * Get the search range + */ + public short getSearchRange() { + double pow = Math.floor(Math.log(getSegmentCount()) / Math.log(2)); + double pow2 = Math.pow(2, pow); + + return (short) (2 * pow2); + } + + /** + * Get the entry selector + */ + public short getEntrySelector() { + int sr2 = getSearchRange() / 2; + return (short) (Math.log(sr2) / Math.log(2)); + } + + /** + * Get the rangeShift() + */ + public short getRangeShift() { + return (short) ((2 * getSegmentCount()) - getSearchRange()); + } + + /** Get a pretty string */ + @Override public String toString() { + StringBuffer buf = new StringBuffer(); + String indent = " "; + + buf.append(super.toString()); + buf.append(indent + "SegmentCount : " + getSegmentCount() + "\n"); + buf.append(indent + "SearchRange : " + getSearchRange() + "\n"); + buf.append(indent + "EntrySelector: " + getEntrySelector() + "\n"); + buf.append(indent + "RangeShift : " + getRangeShift() + "\n"); + + for (Iterator i = this.segments.keySet().iterator(); i.hasNext();) { + Segment s = i.next(); + + buf.append(indent); + buf.append("Segment: " + Integer.toHexString(s.startCode)); + buf.append("-" + Integer.toHexString(s.endCode) + " "); + buf.append("hasMap: " + s.hasMap + " "); + + if (!s.hasMap) { + buf.append("delta: " + this.segments.get(s)); + } + + buf.append("\n"); + } + + return buf.toString(); + } + + static class Segment implements Comparable { + /** the end code (highest code in this segment) */ + int endCode; + + /** the start code (lowest code in this segment) */ + int startCode; + + /** whether it is a map or a delta */ + boolean hasMap; + + /** Create a new segment */ + public Segment(short startCode, short endCode, boolean hasMap) { + // convert from unsigned short + this.endCode = (0xffff & endCode); + this.startCode = (0xffff & startCode); + + this.hasMap = hasMap; + } + + /** Equals based on compareTo (only compares endCode) */ + @Override public boolean equals(Object o) { + return (compareTo(o) == 0); + } + + /** Segments sort by increasing endCode */ + @Override + public int compareTo(Object o) { + if (!(o instanceof Segment)) { + return -1; + } + + Segment s = (Segment) o; + + // if regions overlap at all, declare the segments equal, + // to avoid overlap in the segment list + if (((s.endCode >= this.startCode) && (s.endCode <= this.endCode)) || + ((s.startCode >= this.startCode) && (s.startCode <= this.endCode))) { + return 0; + } if (this.endCode > s.endCode) { + return 1; + } else if (this.endCode < s.endCode) { + return -1; + } else { + return 0; + } + } + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/CMapFormat6.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/CMapFormat6.java new file mode 100644 index 000000000..e5b41197e --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/CMapFormat6.java @@ -0,0 +1,140 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package com.sun.pdfview.font.ttf; + +import java.nio.ByteBuffer; +import java.util.*; + +/** + * + * @author jkaplan + */ +public class CMapFormat6 extends CMap { + /** First character code of subrange. */ + private short firstCode; + /** Number of character codes in subrange. */ + private short entryCount; + /** Array of glyph index values for character codes in the range. */ + private short [] glyphIndexArray; + /** a reverse lookup from glyph id to index. */ + private HashMap glyphLookup = new HashMap(); + + /** Creates a new instance of CMapFormat0 */ + protected CMapFormat6(short language) { + super((short) 6, language); + } + + /** + * Get the length of this table + */ + @Override + public short getLength() { + // start with the size of the fixed header + short size = 5 * 2; + + // add the size of each segment header + size += this.entryCount * 2; + return size; + } + + /** + * Cannot map from a byte + */ + @Override + public byte map(byte src) { + char c = map((char) src); + if (c < Byte.MIN_VALUE || c > Byte.MAX_VALUE) { + // out of range + return 0; + } + return (byte) c; + } + + /** + * Map from char + */ + @Override + public char map(char src) { + + // find first segment with endcode > src + if (src < this.firstCode || src > (this.firstCode + this.entryCount)) { + // Codes outside of the range are assumed to be missing and are + // mapped to the glyph with index 0 + return '\000'; + } + return (char) this.glyphIndexArray[src - this.firstCode]; + } + + /** + * Get the src code which maps to the given glyphID + */ + @Override + public char reverseMap(short glyphID) { + Short result = this.glyphLookup.get(Short.valueOf(glyphID)); + if (result == null) { + return '\000'; + } + return (char) result.shortValue(); + } + + + /** + * Get the data in this map as a ByteBuffer + */ + @Override + public void setData(int length, ByteBuffer data) { + // read the table size values + this.firstCode = data.getShort(); + this.entryCount = data.getShort(); + + this.glyphIndexArray = new short [this.entryCount]; + for (int i = 0; i < this.glyphIndexArray.length; i++) { + this.glyphIndexArray[i] = data.getShort(); + this.glyphLookup.put(Short.valueOf(this.glyphIndexArray[i]), + Short.valueOf((short) (i + this.firstCode))); + } + } + + /** + * Get the data in the map as a byte buffer + */ + @Override + public ByteBuffer getData() { + ByteBuffer buf = ByteBuffer.allocate(getLength()); + + // write the header + buf.putShort(getFormat()); + buf.putShort(getLength()); + buf.putShort(getLanguage()); + + // write the various values + buf.putShort(this.firstCode); + buf.putShort(this.entryCount); + + // write the endCodes + for (int i = 0; i < this.glyphIndexArray.length; i++) { + buf.putShort(this.glyphIndexArray[i]); + } + // reset the data pointer + buf.flip(); + + return buf; + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/CmapTable.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/CmapTable.java new file mode 100644 index 000000000..5754af659 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/CmapTable.java @@ -0,0 +1,294 @@ +/* Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package com.sun.pdfview.font.ttf; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.SortedMap; +import java.util.TreeMap; + +import com.sun.pdfview.PDFDebugger; + +/** + * Represents the TTF "cmap" table + * + * @author jkaplan + */ +public class CmapTable extends TrueTypeTable { + + /** Holds value of property version. */ + private short version; + + /** + * Holds the CMap subtables, sorted properly + */ + private final SortedMap subtables; + + /** Creates a new instance of CmapTable */ + protected CmapTable() { + super(TrueTypeTable.CMAP_TABLE); + + setVersion((short) 0x0); + + this.subtables = Collections.synchronizedSortedMap(new TreeMap()); + } + + /** + * Add a CMap + */ + public void addCMap(short platformID, short platformSpecificID, + CMap cMap) { + CmapSubtable key = new CmapSubtable(platformID, platformSpecificID); + this.subtables.put(key, cMap); + } + + /** + * Get a CMap by platform and specific ID + */ + public CMap getCMap(short platformID, short platformSpecificID) { + CmapSubtable key = new CmapSubtable(platformID, platformSpecificID); + return this.subtables.get(key); + } + + /** + * Get all CMaps + */ + public CMap[] getCMaps() { + Collection c = new ArrayList(); + + CMap cmap_3_1 = this.getCMap((short)3, (short)1); + if (cmap_3_1 != null) { + c.add(cmap_3_1); + } + CMap cmap_1_0 = this.getCMap((short)1, (short)0); + if (cmap_1_0 != null) { + c.add(cmap_1_0); + } + + for (CMap cmap : this.subtables.values()) { + if (!c.contains(cmap)) { + c.add(cmap); + } + } + ; + CMap[] maps = new CMap[c.size()]; + + c.toArray(maps); + + return maps; + } + + /** + * Remove a CMap + */ + public void removeCMap(short platformID, short platformSpecificID) { + CmapSubtable key = new CmapSubtable(platformID, platformSpecificID); + this.subtables.remove(key); + } + + @Override public void setData(ByteBuffer data) { + setVersion(data.getShort()); + + short numberSubtables = data.getShort(); + + for (int i = 0; i < numberSubtables; i++) { + short platformID = data.getShort(); + short platformSpecificID = data.getShort(); + int offset = data.getInt(); + + data.mark(); + + // get the position from the start of this buffer + data.position(offset); + + ByteBuffer mapData = data.slice(); + + data.reset(); + + try { + CMap cMap = CMap.getMap(mapData); + if (cMap != null) { + addCMap(platformID, platformSpecificID, cMap); + } + } catch (Exception ex) { + PDFDebugger.debug("Error reading map. PlatformID=" + + platformID + ", PlatformSpecificID=" + + platformSpecificID); + PDFDebugger.debug("Reason: " + ex); + } + } + } + + @Override public ByteBuffer getData() { + ByteBuffer buf = ByteBuffer.allocate(getLength()); + + // write the table header + buf.putShort(getVersion()); + buf.putShort((short) this.subtables.size()); + + // the current offset to write to, starts at the end of the + // subtables + int curOffset = 4 + (this.subtables.size() * 8); + + // write the subtables + for (Iterator i = this.subtables.keySet().iterator(); i.hasNext();) { + CmapSubtable cms = (CmapSubtable) i.next(); + CMap map = this.subtables.get(cms); + + buf.putShort(cms.platformID); + buf.putShort(cms.platformSpecificID); + buf.putInt(curOffset); + + curOffset += map.getLength(); + } + + // write the tables + for (Iterator i = this.subtables.values().iterator(); i.hasNext();) { + CMap map = (CMap) i.next(); + buf.put(map.getData()); + } + + // reset the position to the start of the buffer + buf.flip(); + + return buf; + } + + /** + * Get the size of the table, in bytes + */ + @Override public int getLength() { + // start with the size of the fixed data + int length = 4; + + // add the size of the subtables + length += this.subtables.size() * 8; + + // add the size of the dynamic data + for (Iterator i = this.subtables.values().iterator(); i.hasNext();) { + // add the size of the subtable data + CMap map = (CMap) i.next(); + length += map.getLength(); + } + + return length; + } + + + /** Getter for property version. + * @return Value of property version. + * + */ + public short getVersion() { + return this.version; + } + + /** Setter for property version. + * @param version New value of property version. + * + */ + public void setVersion(short version) { + this.version = version; + } + + /** + * Get the number of tables + */ + public short getNumberSubtables() { + return (short) this.subtables.size(); + } + + /** Print a pretty string */ + @Override public String toString() { + StringBuffer buf = new StringBuffer(); + String indent = " "; + + buf.append(indent + "Version: " + this.getVersion() + "\n"); + buf.append(indent + "NumMaps: " + this.getNumberSubtables() + "\n"); + + for (Iterator i = this.subtables.keySet().iterator(); i.hasNext();) { + CmapSubtable key = (CmapSubtable) i.next(); + + buf.append(indent + "Map: platformID: " + key.platformID + + " PlatformSpecificID: " + key.platformSpecificID + "\n"); + + CMap map = this.subtables.get(key); + + buf.append(map.toString()); + } + + return buf.toString(); + } + + static class CmapSubtable implements Comparable { + /** + * The platformID for this subtable + */ + short platformID; + + /** + * The platform-specific id + */ + short platformSpecificID; + + /** + * Create a Cmap subtable + */ + protected CmapSubtable(short platformID, short platformSpecificID) { + this.platformID = platformID; + this.platformSpecificID = platformSpecificID; + } + + /** + * Compare two subtables + */ + @Override public boolean equals(Object obj) { + return (compareTo(obj) == 0); + } + + /** + * Sort ascending by platform ID and then specific ID + */ + @Override + public int compareTo(Object obj) { + if (!(obj instanceof CmapSubtable)) { + return -1; + } + + CmapSubtable cms = (CmapSubtable) obj; + if (this.platformID < cms.platformID) { + return -1; + } else if (this.platformID > cms.platformID) { + return 1; + } else { + if (this.platformSpecificID < cms.platformSpecificID) { + return -1; + } else if (this.platformSpecificID > cms.platformSpecificID) { + return 1; + } else { + return 0; + } + } + } + } + +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/Glyf.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/Glyf.java new file mode 100644 index 000000000..a20a20bec --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/Glyf.java @@ -0,0 +1,206 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package com.sun.pdfview.font.ttf; + +import java.nio.ByteBuffer; + +/** + * A single glyph in a pdf font. May be simple or compound via subclasses + */ +public class Glyf { + /** If true, the glyf is compound */ + private boolean isCompound; + + /** the number of contours */ + private short numContours; + + /** the minimum x value */ + private short minX; + + /** the minimum y value */ + private short minY; + + /** the maximum x value */ + private short maxX; + + /** the maximum y value */ + private short maxY; + + /** + * Creates a new instance of glyf + * Don't use this directly, use Glyf.getGlyf() + */ + protected Glyf() { + } + + /** + * Get a map from the given data + * + * This method reads the format, data and length variables of + * the map. + */ + public static Glyf getGlyf(ByteBuffer data) { + short numContours = data.getShort(); + + Glyf g = null; + if (numContours == 0) { + // no glyph data + g = new Glyf(); + } else if (numContours == -1) { + // compound glyf + g = new GlyfCompound(); + } else if (numContours > 0) { + // simple glyf + g = new GlyfSimple(); + } else { + throw new IllegalArgumentException("Unknown glyf type: " + + numContours); + } + + g.setNumContours(numContours); + g.setMinX(data.getShort()); + g.setMinY(data.getShort()); + g.setMaxX(data.getShort()); + g.setMaxY(data.getShort()); + + // do glyphtype-specific parsing + g.setData(data); + + return g; + } + + /** + * Set the data for this glyf. Do nothing, since a glyf with + * no contours has no glyf data. + */ + public void setData(ByteBuffer data) { + return; + } + + /** + * Get the data in this glyf as a byte buffer. Return the basic + * glyf data only, since there is no specific data. This method returns + * the data un-flipped, so subclasses can simply append to the allocated + * buffer. + */ + public ByteBuffer getData() { + ByteBuffer buf = ByteBuffer.allocate(getLength()); + + buf.putShort(getNumContours()); + buf.putShort(getMinX()); + buf.putShort(getMinY()); + buf.putShort(getMaxX()); + buf.putShort(getMaxY()); + + // don't flip the buffer, since it may be used by subclasses + return buf; + } + + /** + * Get the length of this glyf. A glyf with no data has a length + * of 10 (2 bytes each for 5 short values) + */ + public short getLength() { + return 10; + } + + /** + * Get whether this is a simple or compound glyf + */ + public boolean isCompound() { + return this.isCompound; + } + + /** + * Set whether this is a simple or compound glyf + */ + protected void setCompound(boolean isCompound) { + this.isCompound = isCompound; + } + + /** + * Get the number of contours in this glyf + */ + public short getNumContours() { + return this.numContours; + } + + /** + * Set the number of contours in this glyf + */ + protected void setNumContours(short numContours) { + this.numContours = numContours; + } + + /** + * Get the minimum x in this glyf + */ + public short getMinX() { + return this.minX; + } + + /** + * Set the minimum X in this glyf + */ + protected void setMinX(short minX) { + this.minX = minX; + } + + /** + * Get the minimum y in this glyf + */ + public short getMinY() { + return this.minY; + } + + /** + * Set the minimum Y in this glyf + */ + protected void setMinY(short minY) { + this.minY = minY; + } + /** + * Get the maximum x in this glyf + */ + public short getMaxX() { + return this.maxX; + } + + /** + * Set the maximum X in this glyf + */ + protected void setMaxX(short maxX) { + this.maxX = maxX; + } + + /** + * Get the maximum y in this glyf + */ + public short getMaxY() { + return this.maxY; + } + + /** + * Set the maximum Y in this glyf + */ + protected void setMaxY(short maxY) { + this.maxY = maxY; + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/GlyfCompound.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/GlyfCompound.java new file mode 100644 index 000000000..b4c9ba65a --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/GlyfCompound.java @@ -0,0 +1,329 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package com.sun.pdfview.font.ttf; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; + +/** + * A single simple glyph in a pdf font. + */ +public class GlyfCompound extends Glyf { + /** flags */ + private static final int ARG_1_AND_2_ARE_WORDS = 0x1; + private static final int ARGS_ARE_XY_VALUES = 0x2; + private static final int ROUND_XY_TO_GRID = 0x4; + private static final int WE_HAVE_A_SCALE = 0x8; + private static final int MORE_COMPONENTS = 0x20; + private static final int WE_HAVE_AN_X_AND_Y_SCALE = 0x40; + private static final int WE_HAVE_A_TWO_BY_TWO = 0x80; + private static final int WE_HAVE_INSTRUCTIONS = 0x100; + private static final int USE_MY_METRICS = 0x200; + private static final int OVERLAP_COMPOUND = 0x400; + + /** the flags for each compound glyph */ + private GlyfComponent[] components; + + /** the instructions for the compound as a whole */ + private byte[] instructions; + + /** + * Creates a new instance of a simple glyf + */ + protected GlyfCompound() { + } + + /** + * Set the data for this glyf. + */ + @Override public void setData(ByteBuffer data) { + // int pos = data.position(); + // byte[] prdata = new byte[data.remaining()]; + // data.get(prdata); + // HexDump.printData(prdata); + // data.position(pos); + + // read the contour end points + List comps = new ArrayList(); + GlyfComponent cur = null; + boolean hasInstructions = false; + + do { + cur = new GlyfComponent(); + cur.flags = data.getShort(); + cur.glyphIndex = data.getShort() & 0xFFFF; + + // read either e/f or matching points, as shorts or bytes... + if (((cur.flags & ARG_1_AND_2_ARE_WORDS) != 0) && + ((cur.flags & ARGS_ARE_XY_VALUES) != 0)) { + cur.e = data.getShort(); + cur.f = data.getShort(); + } else if (!((cur.flags & ARG_1_AND_2_ARE_WORDS) != 0) && + ((cur.flags & ARGS_ARE_XY_VALUES) != 0)) { + cur.e = data.get(); + cur.f = data.get(); + } else if ( ((cur.flags & ARG_1_AND_2_ARE_WORDS) != 0) && + !((cur.flags & ARGS_ARE_XY_VALUES) != 0)) { + cur.compoundPoint = data.getShort(); + cur.componentPoint = data.getShort(); + } else { + cur.compoundPoint = data.get(); + cur.componentPoint = data.get(); + } + + // read the linear transform + if ((cur.flags & WE_HAVE_A_SCALE) != 0) { + cur.a = (float) data.getShort() / (float) (1 << 14); + cur.d = cur.a; + } else if ((cur.flags & WE_HAVE_AN_X_AND_Y_SCALE) != 0) { + cur.a = (float) data.getShort() / (float) (1 << 14); + cur.d = (float) data.getShort() / (float) (1 << 14); + } else if ((cur.flags & WE_HAVE_A_TWO_BY_TWO) != 0) { + cur.a = (float) data.getShort() / (float) (1 << 14); + cur.b = (float) data.getShort() / (float) (1 << 14); + cur.c = (float) data.getShort() / (float) (1 << 14); + cur.d = (float) data.getShort() / (float) (1 << 14); + } + + if ((cur.flags & WE_HAVE_INSTRUCTIONS) != 0) { + hasInstructions = true; + } + + comps.add(cur); + } while ((cur.flags & MORE_COMPONENTS) != 0); + + GlyfComponent[] componentArray = new GlyfComponent[comps.size()]; + comps.toArray(componentArray); + setComponents(componentArray); + + byte[] instr = null; + if (hasInstructions) { + // read the instructions + short numInstructions = data.getShort(); + instr = new byte[numInstructions]; + for (int i = 0; i < instr.length; i++) { + instr[i] = data.get(); + } + } else { + instr = new byte[0]; + } + setInstructions(instr); + } + + /** + * Get the data in this glyf as a byte buffer. Not implemented. + */ + @Override public ByteBuffer getData() { + ByteBuffer buf = super.getData(); + + // don't flip the buffer, since it may be used by subclasses + return buf; + } + + /** + * Get the length of this glyf. Not implemented. + */ + @Override public short getLength() { + + // start with the length of the superclass + short length = super.getLength(); + return length; + } + + /** + * Get the number of components in this compound + */ + public int getNumComponents() { + return this.components.length; + } + + /** + * Get a given flag + */ + public short getFlag(int index) { + return this.components[index].flags; + } + + /** + * Get the glyf index for a given glyf + */ + public int getGlyphIndex(int index) { + return this.components[index].glyphIndex; + } + + /** + * Get the base affine transform. This is based on a whacy formula + * defined in the true type font spec. + */ + public double[] getTransform(int index) { + GlyfComponent gc = this.components[index]; + + float m = Math.max(Math.abs(gc.a), Math.abs(gc.b)); + if (Math.abs(Math.abs(gc.a) - Math.abs(gc.c)) < (33 / 65536)) { + m *= 2; + } + + float n = Math.max(Math.abs(gc.c), Math.abs(gc.d)); + if (Math.abs(Math.abs(gc.c) - Math.abs(gc.d)) < (33 / 65536)) { + n *= 2; + } + + float e = m * gc.e; + float f = n * gc.f; + + return new double[] { gc.a, gc.b, gc.c, gc.d, e, f }; + } + + /** + * Get the point in the compound glyph to match + */ + public int getCompoundPoint(int index) { + return this.components[index].compoundPoint; + } + + /** + * Get the point in the component glyph to match + */ + public int getComponentPoint(int index) { + return this.components[index].componentPoint; + } + + /** + * Determine whether args 1 and 2 are words or bytes + */ + public boolean argsAreWords(int index) { + return ((getFlag(index) & ARG_1_AND_2_ARE_WORDS) != 0); + } + + /** + * Determine whether args 1 and 2 are xy values or point indices + */ + public boolean argsAreXYValues(int index) { + return ((getFlag(index) & ARGS_ARE_XY_VALUES) != 0); + } + + /** + * Determine whether to round XY values to the grid + */ + public boolean roundXYToGrid(int index) { + return ((getFlag(index) & ROUND_XY_TO_GRID) != 0); + } + + /** + * Determine whether there is a simple scale + */ + public boolean hasAScale(int index) { + return ((getFlag(index) & WE_HAVE_A_SCALE) != 0); + } + + /** + * Determine whether there are more components left to read + */ + protected boolean moreComponents(int index) { + return ((getFlag(index) & MORE_COMPONENTS) != 0); + } + + /** + * Determine whether there are separate scales on X and Y + */ + protected boolean hasXYScale(int index) { + return ((getFlag(index) & WE_HAVE_AN_X_AND_Y_SCALE) != 0); + } + + /** + * Determine whether there is a 2x2 transform + */ + protected boolean hasTwoByTwo(int index) { + return ((getFlag(index) & WE_HAVE_A_TWO_BY_TWO) != 0); + } + + /** + * Determine whether there are instructions + */ + protected boolean hasInstructions(int index) { + return ((getFlag(index) & WE_HAVE_INSTRUCTIONS) != 0); + } + + /** + * Use the metrics of this component for the compound + */ + public boolean useMetrics(int index) { + return ((getFlag(index) & USE_MY_METRICS) != 0); + } + + /** + * This component overlaps the existing compound + */ + public boolean overlapCompound(int index) { + return ((getFlag(index) & OVERLAP_COMPOUND) != 0); + } + + /** + * Set the components + */ + void setComponents(GlyfComponent[] components) { + this.components = components; + } + + /** + * Get the number of instructions + */ + public short getNumInstructions() { + return (short) this.instructions.length; + } + + /** + * Get a given instruction + */ + public byte getInstruction(int index) { + return this.instructions[index]; + } + + /** + * Set the instructions + */ + protected void setInstructions(byte[] instructions) { + this.instructions = instructions; + } + + /** + * The record for a single component of this compound glyph + */ + static class GlyfComponent { + /** flags */ + short flags; + + /** the index of the component glyf */ + int glyphIndex; + + /** the points to match */ + int compoundPoint; + int componentPoint; + + /** affine transform of this component */ + float a = 1.0f; + float b = 0.0f; + float c = 0.0f; + float d = 1.0f; + float e = 0.0f; + float f = 0.0f; + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/GlyfSimple.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/GlyfSimple.java new file mode 100644 index 000000000..67a1f8442 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/GlyfSimple.java @@ -0,0 +1,364 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package com.sun.pdfview.font.ttf; + +import java.nio.ByteBuffer; + +/** + * A single simple glyph in a pdf font. + */ +public class GlyfSimple extends Glyf { + /** the end points of the various contours */ + private short[] contourEndPts; + + /** the instructions */ + private byte[] instructions; + + /** the flags */ + private byte[] flags; + + /** the x coordinates */ + private short[] xCoords; + + /** the y coordinates */ + private short[] yCoords; + + /** + * Creates a new instance of a simple glyf + */ + protected GlyfSimple() { + } + + /** + * Set the data for this glyf. + */ + @Override + public void setData(ByteBuffer data) { + // int pos = data.position(); + // byte[] prdata = new byte[data.remaining()]; + // data.get(prdata); + // HexDump.printData(prdata); + // data.position(pos); + + + // read the contour end points + short[] contourEndPts = new short[getNumContours()]; + for (int i = 0; i < contourEndPts.length; i++) { + contourEndPts[i] = data.getShort(); + } + setContourEndPoints(contourEndPts); + + // the number of points in the glyf is the number of the end + // point in the last contour + int numPoints = getContourEndPoint(getNumContours() - 1) + 1; + + // read the instructions + short numInstructions = data.getShort(); + byte[] instructions = new byte[numInstructions]; + for (int i = 0; i < instructions.length; i++) { + instructions[i] = data.get(); + } + setInstructions(instructions); + + // read the flags + byte[] flags = new byte[numPoints]; + for (int i = 0; i < flags.length; i++) { + flags[i] = data.get(); + + // check for repeats + if ((flags[i] & 0x8) != 0) { + byte f = flags[i]; + int n = (data.get() & 0xff); + for (int c = 0; c < n; c++) { + flags[++i] = f; + } + } + } + setFlags(flags); + + // read the x coordinates + short[] xCoords = new short[numPoints]; + for (int i = 0; i < xCoords.length; i++) { + if (i > 0) { + xCoords[i] = xCoords[i - 1]; + } + + // read this value + if (xIsByte(i)) { + int val = (data.get() & 0xff); + if (!xIsSame(i)) { + // the xIsSame bit controls the sign + val = -val; + } + xCoords[i] += val; + } else if (!xIsSame(i)) { + xCoords[i] += data.getShort(); + } + } + setXCoords(xCoords); + + // read the y coordinates + short[] yCoords = new short[numPoints]; + for (int i = 0; i < yCoords.length; i++) { + if (i > 0) { + yCoords[i] = yCoords[i - 1]; + } + // read this value + if (yIsByte(i)) { + int val = (data.get() & 0xff); + if (!yIsSame(i)) { + // the xIsSame bit controls the sign + val = -val; + } + yCoords[i] += val; + } else if (!yIsSame(i)) { + yCoords[i] += data.getShort(); + } + } + setYCoords(yCoords); + } + + /** + * Get the data in this glyf as a byte buffer. Return the basic + * glyf data only, since there is no specific data. This method returns + * the data un-flipped, so subclasses can simply append to the allocated + * buffer. + */ + @Override + public ByteBuffer getData() { + ByteBuffer buf = super.getData(); + + // write the contour end points + for (int i = 0; i < getNumContours(); i++) { + buf.putShort(getContourEndPoint(i)); + } + + // write the instructions + buf.putShort(getNumInstructions()); + for (int i = 0; i < getNumInstructions(); i++) { + buf.put(getInstruction(i)); + } + + // write the flags + for (int i = 0; i < getNumPoints(); i++) { + // check for repeats + byte r = 0; + while (i > 0 && (getFlag(i) == getFlag(i - 1))) { + r++; + i++; + } + if (r > 0) { + buf.put(r); + } else { + buf.put(getFlag(i)); + } + } + + // write the x coordinates + for (int i = 0; i < getNumPoints(); i++) { + if (xIsByte(i)) { + buf.put((byte) getXCoord(i)); + } else if (!xIsSame(i)) { + buf.putShort(getXCoord(i)); + } + } + + // write the y coordinates + for (int i = 0; i < getNumPoints(); i++) { + if (yIsByte(i)) { + buf.put((byte) getYCoord(i)); + } else if (!yIsSame(i)) { + buf.putShort(getYCoord(i)); + } + } + + // don't flip the buffer, since it may be used by subclasses + return buf; + } + + /** + * Get the length of this glyf. + */ + @Override + public short getLength() { + // start with the length of the superclass + short length = super.getLength(); + + // add the length of the end points + length += getNumContours() * 2; + + // add the length of the instructions + length += 2 + getNumInstructions(); + + // add the length of the flags, avoiding repeats + for (int i = 0; i < getNumPoints(); i++) { + // check for repeats + while (i > 0 && (getFlag(i) == getFlag(i - 1))); + length++; + } + + // add the length of the xCoordinates + for (int i = 0; i < getNumPoints(); i++) { + if (xIsByte(i)) { + length++; + } else if (!xIsSame(i)) { + length += 2; + } + + if (yIsByte(i)) { + length++; + } else if (!yIsSame(i)) { + length += 2; + } + } + + return length; + } + + /** + * Get the end point of a given contour + */ + public short getContourEndPoint(int index) { + return this.contourEndPts[index]; + } + + /** + * Set the number of contours in this glyf + */ + protected void setContourEndPoints(short[] contourEndPts) { + this.contourEndPts = contourEndPts; + } + + /** + * Get the number of instructions + */ + public short getNumInstructions() { + return (short) this.instructions.length; + } + + /** + * Get a given instruction + */ + public byte getInstruction(int index) { + return this.instructions[index]; + } + + /** + * Set the instructions + */ + protected void setInstructions(byte[] instructions) { + this.instructions = instructions; + } + + /** + * Get the number of points in the glyf + */ + public short getNumPoints() { + return (short) this.flags.length; + } + + /** + * Get a given flag + */ + public byte getFlag(int pointIndex) { + return this.flags[pointIndex]; + } + + /** + * Determine whether the given point is on the curve + */ + public boolean onCurve(int pointIndex) { + return ((getFlag(pointIndex) & 0x1) != 0); + } + + /** + * Determine whether the x value for the given point is byte or short. + * If true, it is a byte, if false it is a short + */ + protected boolean xIsByte(int pointIndex) { + return ((getFlag(pointIndex) & 0x2) != 0); + } + + /** + * Determine whether the x value for the given point is byte or short. + * If true, it is a byte, if false it is a short + */ + protected boolean yIsByte(int pointIndex) { + return ((getFlag(pointIndex) & 0x4) != 0); + } + + /** + * Determine whether this flag repeats + */ + protected boolean repeat(int pointIndex) { + return ((getFlag(pointIndex) & 0x8) != 0); + } + + /** + * Determine whether the x value for the given point is the same as + * the previous value. + */ + protected boolean xIsSame(int pointIndex) { + return ((getFlag(pointIndex) & 0x10) != 0); + } + + /** + * Determine whether the y value for the given point is the same as + * the previous value. + */ + protected boolean yIsSame(int pointIndex) { + return ((getFlag(pointIndex) & 0x20) != 0); + } + + /** + * Set the flags + */ + protected void setFlags(byte[] flags) { + this.flags = flags; + } + + /** + * Get a given x coordinate + */ + public short getXCoord(int pointIndex) { + return this.xCoords[pointIndex]; + } + + /** + * Set the x coordinates + */ + protected void setXCoords(short[] xCoords) { + this.xCoords = xCoords; + } + + /** + * Get a given y coordinate + */ + public short getYCoord(int pointIndex) { + return this.yCoords[pointIndex]; + } + + /** + * Set the x coordinates + */ + protected void setYCoords(short[] yCoords) { + this.yCoords = yCoords; + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/GlyfTable.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/GlyfTable.java new file mode 100644 index 000000000..41818f9f1 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/GlyfTable.java @@ -0,0 +1,157 @@ +/* Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package com.sun.pdfview.font.ttf; + +import java.nio.ByteBuffer; + +/** + * Model the TrueType Glyf table + */ +public class GlyfTable extends TrueTypeTable { + /** + * the glyph data, as either a byte buffer (unparsed) or a + * glyph object (parsed) + */ + private Object[] glyphs; + + /** + * The glyph location table + */ + private LocaTable loca; + + /** Creates a new instance of HmtxTable */ + protected GlyfTable(TrueTypeFont ttf) { + super (TrueTypeTable.GLYF_TABLE); + + this.loca = (LocaTable) ttf.getTable("loca"); + + MaxpTable maxp = (MaxpTable) ttf.getTable("maxp"); + int numGlyphs = maxp.getNumGlyphs(); + + this.glyphs = new Object[numGlyphs]; + } + + /** + * Get the glyph at a given index, parsing it as needed + */ + public Glyf getGlyph(int index) { + Object o = this.glyphs[index]; + if (o == null) { + return null; + } + + if (o instanceof ByteBuffer) { + Glyf g = Glyf.getGlyf((ByteBuffer) o); + this.glyphs[index] = g; + + return g; + } else { + return (Glyf) o; + } + } + + /** get the data in this map as a ByteBuffer */ + @Override + public ByteBuffer getData() { + int size = getLength(); + + ByteBuffer buf = ByteBuffer.allocate(size); + + // write the offsets + for (int i = 0; i < this.glyphs.length; i++) { + Object o = this.glyphs[i]; + if (o == null) { + continue; + } + + ByteBuffer glyfData = null; + if (o instanceof ByteBuffer) { + glyfData = (ByteBuffer) o; + } else { + glyfData = ((Glyf) o).getData(); + } + + glyfData.rewind(); + buf.put(glyfData); + glyfData.flip(); + } + + // reset the start pointer + buf.flip(); + + return buf; + } + + /** Initialize this structure from a ByteBuffer */ + @Override + public void setData(ByteBuffer data) { + for (int i = 0; i < this.glyphs.length; i++) { + int location = this.loca.getOffset(i); + int length = this.loca.getSize(i); + + if (length == 0) { + // undefined glyph + continue; + } + + data.position(location); + ByteBuffer glyfData = data.slice(); + glyfData.limit(length); + + this.glyphs[i] = glyfData; + } + } + + /** + * Get the length of this table + */ + @Override + public int getLength() { + int length = 0; + + for (int i = 0; i < this.glyphs.length; i++) { + Object o = this.glyphs[i]; + if (o == null) { + continue; + } + + if (o instanceof ByteBuffer) { + length += ((ByteBuffer) o).remaining(); + } else { + length += ((Glyf) o).getLength(); + } + } + + return length; + } + + /** + * Create a pretty String + */ + @Override + public String toString() { + StringBuffer buf = new StringBuffer(); + String indent = " "; + + buf.append(indent + "Glyf Table: (" + this.glyphs.length + " glyphs)\n"); + buf.append(indent + " Glyf 0: " + getGlyph(0)); + + return buf.toString(); + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/HeadTable.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/HeadTable.java new file mode 100644 index 000000000..e42cefff6 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/HeadTable.java @@ -0,0 +1,473 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package com.sun.pdfview.font.ttf; + +import java.nio.ByteBuffer; +import java.util.Date; + +/** + * + * @author jkaplan + */ +public class HeadTable extends TrueTypeTable { + + /** Holds value of property version. */ + private int version; + + /** Holds value of property fontRevision. */ + private int fontRevision; + + /** Holds value of property checksumAdjustment. */ + private int checksumAdjustment; + + /** Holds value of property magicNumber. */ + private int magicNumber; + + /** Holds value of property flags. */ + private short flags; + + /** Holds value of property unitsPerEm. */ + private short unitsPerEm; + + /** Holds value of property created. */ + private long created; + + /** Holds value of property modified. */ + private long modified; + + /** Holds value of property xMin. */ + private short xMin; + + /** Holds value of property yMin. */ + private short yMin; + + /** Holds value of property xMax. */ + private short xMax; + + /** Holds value of property yMax. */ + private short yMax; + + /** Holds value of property macStyle. */ + private short macStyle; + + /** Holds value of property lowestRecPPem. */ + private short lowestRecPPem; + + /** Holds value of property fontDirectionHint. */ + private short fontDirectionHint; + + /** Holds value of property indexToLocFormat. */ + private short indexToLocFormat; + + /** Holds value of property glyphDataFormat. */ + private short glyphDataFormat; + + /** Creates a new instance of HeadTable + * Makes up reasonable(?) defaults for all values + */ + protected HeadTable() { + super(TrueTypeTable.HEAD_TABLE); + + setVersion(0x10000); + setFontRevision(0x10000); + setChecksumAdjustment(0); + setMagicNumber(0x5f0f3cf5); + setFlags((short) 0x0); + setUnitsPerEm((short) 64); + setCreated(System.currentTimeMillis()); + setModified(System.currentTimeMillis()); + setXMin((short) 0); + setXMax(Short.MAX_VALUE); + setYMin((short) 0); + setYMax(Short.MAX_VALUE); + setMacStyle((short) 0x0); + setLowestRecPPem((short) 0); + setFontDirectionHint((short) 0); + setIndexToLocFormat((short) 0); + setGlyphDataFormat((short) 0); + } + + /** + * Parse the data before it is set + */ + @Override + public void setData(ByteBuffer data) { + if (data.remaining() < 54) { + throw new IllegalArgumentException("Bad Head table size " + data.remaining()); + } + setVersion(data.getInt()); + setFontRevision(data.getInt()); + setChecksumAdjustment(data.getInt()); + setMagicNumber(data.getInt()); + setFlags(data.getShort()); + setUnitsPerEm(data.getShort()); + setCreated(data.getLong()); + setModified(data.getLong()); + setXMin(data.getShort()); + setXMax(data.getShort()); + setYMin(data.getShort()); + setYMax(data.getShort()); + setMacStyle(data.getShort()); + setLowestRecPPem(data.getShort()); + setFontDirectionHint(data.getShort()); + setIndexToLocFormat(data.getShort()); + setGlyphDataFormat(data.getShort()); + } + + /** + * Get the data we have stored + */ + @Override + public ByteBuffer getData() { + ByteBuffer buf = ByteBuffer.allocate(getLength()); + + buf.putInt(getVersion()); + buf.putInt(getFontRevision()); + buf.putInt(getChecksumAdjustment()); + buf.putInt(getMagicNumber()); + buf.putShort(getFlags()); + buf.putShort(getUnitsPerEm()); + buf.putLong(getCreated()); + buf.putLong(getModified()); + buf.putShort(getXMin()); + buf.putShort(getXMax()); + buf.putShort(getYMin()); + buf.putShort(getYMax()); + buf.putShort(getMacStyle()); + buf.putShort(getLowestRecPPem()); + buf.putShort(getFontDirectionHint()); + buf.putShort(getIndexToLocFormat()); + buf.putShort(getGlyphDataFormat()); + + // reset the position to the start of the buffer + buf.flip(); + + return buf; + } + + /** + * Get the length of this table + */ + @Override + public int getLength() { + return 54; + } + + /** Getter for property version. + * @return Value of property version. + * + */ + public int getVersion() { + return this.version; + } + + /** Getter for property fontRevision. + * @return Value of property fontRevision. + * + */ + public int getFontRevision() { + return this.fontRevision; + } + + /** Getter for property checksumAdjustment. + * @return Value of property checksumAdjustment. + * + */ + public int getChecksumAdjustment() { + return this.checksumAdjustment; + } + + /** Getter for property magicNumber. + * @return Value of property magicNumber. + * + */ + public int getMagicNumber() { + return this.magicNumber; + } + + /** Getter for property flags. + * @return Value of property flags. + * + */ + public short getFlags() { + return this.flags; + } + + /** Getter for property unitsPerEm. + * @return Value of property unitsPerEm. + * + */ + public short getUnitsPerEm() { + return this.unitsPerEm; + } + + /** Getter for property created. + * @return Value of property created. + * + */ + public long getCreated() { + return this.created; + } + + /** Getter for property modified. + * @return Value of property modified. + * + */ + public long getModified() { + return this.modified; + } + + /** Getter for property xMin. + * @return Value of property xMin. + * + */ + public short getXMin() { + return this.xMin; + } + + /** Getter for property yMin. + * @return Value of property yMin. + * + */ + public short getYMin() { + return this.yMin; + } + + /** Getter for property xMax. + * @return Value of property xMax. + * + */ + public short getXMax() { + return this.xMax; + } + + /** Getter for property yMax. + * @return Value of property yMax. + * + */ + public short getYMax() { + return this.yMax; + } + + /** Getter for property macStyle. + * @return Value of property macStyle. + * + */ + public short getMacStyle() { + return this.macStyle; + } + + /** Getter for property lowestRecPPem. + * @return Value of property lowestRecPPem. + * + */ + public short getLowestRecPPem() { + return this.lowestRecPPem; + } + + /** Getter for property fontDirectionHint. + * @return Value of property fontDirectionHint. + * + */ + public short getFontDirectionHint() { + return this.fontDirectionHint; + } + + /** Getter for property indexToLocFormat. + * @return Value of property indexToLocFormat. + * + */ + public short getIndexToLocFormat() { + return this.indexToLocFormat; + } + + /** Getter for property glyphDataFormat. + * @return Value of property glyphDataFormat. + * + */ + public short getGlyphDataFormat() { + return this.glyphDataFormat; + } + + /** Setter for property XMax. + * @param xMax New value of property XMax. + * + */ + public void setXMax(short xMax) { + this.xMax = xMax; + } + + /** Setter for property XMin. + * @param xMin New value of property XMin. + * + */ + public void setXMin(short xMin) { + this.xMin = xMin; + } + + /** Setter for property YMax. + * @param yMax New value of property YMax. + * + */ + public void setYMax(short yMax) { + this.yMax = yMax; + } + + /** Setter for property YMin. + * @param yMin New value of property YMin. + * + */ + public void setYMin(short yMin) { + this.yMin = yMin; + } + + /** Setter for property checksumAdjustment. + * @param checksumAdjustment New value of property checksumAdjustment. + * + */ + public void setChecksumAdjustment(int checksumAdjustment) { + this.checksumAdjustment = checksumAdjustment; + } + + /** Setter for property created. + * @param created New value of property created. + * + */ + public void setCreated(long created) { + this.created = created; + } + + /** Setter for property flags. + * @param flags New value of property flags. + * + */ + public void setFlags(short flags) { + this.flags = flags; + } + + /** Setter for property fontDirectionHint. + * @param fontDirectionHint New value of property fontDirectionHint. + * + */ + public void setFontDirectionHint(short fontDirectionHint) { + this.fontDirectionHint = fontDirectionHint; + } + + /** Setter for property fontRevision. + * @param fontRevision New value of property fontRevision. + * + */ + public void setFontRevision(int fontRevision) { + this.fontRevision = fontRevision; + } + + /** Setter for property glyphDataFormat. + * @param glyphDataFormat New value of property glyphDataFormat. + * + */ + public void setGlyphDataFormat(short glyphDataFormat) { + this.glyphDataFormat = glyphDataFormat; + } + + /** Setter for property indexToLocFormat. + * @param indexToLocFormat New value of property indexToLocFormat. + * + */ + public void setIndexToLocFormat(short indexToLocFormat) { + this.indexToLocFormat = indexToLocFormat; + } + + /** Setter for property lowestRecPPem. + * @param lowestRecPPem New value of property lowestRecPPem. + * + */ + public void setLowestRecPPem(short lowestRecPPem) { + this.lowestRecPPem = lowestRecPPem; + } + + /** Setter for property macStyle. + * @param macStyle New value of property macStyle. + * + */ + public void setMacStyle(short macStyle) { + this.macStyle = macStyle; + } + + /** Setter for property magicNumber. + * @param magicNumber New value of property magicNumber. + * + */ + public void setMagicNumber(int magicNumber) { + this.magicNumber = magicNumber; + } + + /** Setter for property modified. + * @param modified New value of property modified. + * + */ + public void setModified(long modified) { + this.modified = modified; + } + + /** Setter for property unitsPerEm. + * @param unitsPerEm New value of property unitsPerEm. + * + */ + public void setUnitsPerEm(short unitsPerEm) { + this.unitsPerEm = unitsPerEm; + } + + /** Setter for property version. + * @param version New value of property version. + * + */ + public void setVersion(int version) { + this.version = version; + } + + /** + * Create a pretty string + */ + @Override + public String toString() { + StringBuffer buf = new StringBuffer(); + String indent = " "; + + buf.append(indent + "Version : " + Integer.toHexString(getVersion()) + "\n"); + buf.append(indent + "Revision : " + Integer.toHexString(getFontRevision()) + "\n"); + buf.append(indent + "ChecksumAdj : " + Integer.toHexString(getChecksumAdjustment()) + "\n"); + buf.append(indent + "MagicNumber : " + Integer.toHexString(getMagicNumber()) + "\n"); + buf.append(indent + "Flags : " + Integer.toBinaryString(getFlags()) + "\n"); + buf.append(indent + "UnitsPerEm : " + getUnitsPerEm() + "\n"); + buf.append(indent + "Created : " + new Date(getCreated()) + "\n"); + buf.append(indent + "Modified : " + new Date(getModified()) + "\n"); + buf.append(indent + "XMin : " + getXMin() + "\n"); + buf.append(indent + "XMax : " + getXMax() + "\n"); + buf.append(indent + "YMin : " + getYMin() + "\n"); + buf.append(indent + "YMax : " + getYMax() + "\n"); + buf.append(indent + "MacStyle : " + Integer.toBinaryString(getMacStyle()) + "\n"); + buf.append(indent + "LowestPPem : " + getLowestRecPPem() + "\n"); + buf.append(indent + "FontDirectionHint: " + getFontDirectionHint() + "\n"); + buf.append(indent + "IndexToLocFormat : " + getIndexToLocFormat() + "\n"); + buf.append(indent + "GlyphDataFormat : " + getGlyphDataFormat() + "\n"); + + return buf.toString(); + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/HheaTable.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/HheaTable.java new file mode 100644 index 000000000..4af3d9ea2 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/HheaTable.java @@ -0,0 +1,382 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package com.sun.pdfview.font.ttf; + +import java.nio.ByteBuffer; + +/** + * + * @author jkaplan + */ +public class HheaTable extends TrueTypeTable { + + /** Holds value of property version. */ + private int version; + + /** Holds value of property ascent. */ + private short ascent; + + /** Holds value of property descent. */ + private short descent; + + /** Holds value of property lineGap. */ + private short lineGap; + + /** Holds value of property advanceWidthMax. */ + private short advanceWidthMax; + + /** Holds value of property minLeftSideBearing. */ + private short minLeftSideBearing; + + /** Holds value of property minRightSideBearing. */ + private short minRightSideBearing; + + /** Holds value of property xMaxExtent. */ + private short xMaxExtent; + + /** Holds value of property caretSlopeRise. */ + private short caretSlopeRise; + + /** Holds value of property caretSlopeRun. */ + private short caretSlopeRun; + + /** Holds value of property caretOffset. */ + private short caretOffset; + + /** Holds value of property metricDataFormat. */ + private short metricDataFormat; + + /** Holds value of property numOfLongHorMetrics. */ + private short numOfLongHorMetrics; + + /** Creates a new instance of HeadTable + * Makes up reasonable(?) defaults for all values + */ + protected HheaTable() { + super(TrueTypeTable.HEAD_TABLE); + + setVersion(0x10000); + } + + /** + * Parse the data before it is set + */ + @Override + public void setData(ByteBuffer data) { + if (data.remaining() != 36) { + throw new IllegalArgumentException("Bad Head table size"); + } + setVersion(data.getInt()); + setAscent(data.getShort()); + setDescent(data.getShort()); + setLineGap(data.getShort()); + setAdvanceWidthMax(data.getShort()); + setMinLeftSideBearing(data.getShort()); + setMinRightSideBearing(data.getShort()); + setXMaxExtent(data.getShort()); + setCaretSlopeRise(data.getShort()); + setCaretSlopeRun(data.getShort()); + setCaretOffset(data.getShort()); + + // padding + data.getShort(); + data.getShort(); + data.getShort(); + data.getShort(); + + setMetricDataFormat(data.getShort()); + setNumOfLongHorMetrics(data.getShort()); + } + + /** + * Get the data we have stored + */ + @Override + public ByteBuffer getData() { + ByteBuffer buf = ByteBuffer.allocate(getLength()); + + buf.putInt(getVersion()); + buf.putShort(getAscent()); + buf.putShort(getDescent()); + buf.putShort(getLineGap()); + buf.putShort(getAdvanceWidthMax()); + buf.putShort(getMinLeftSideBearing()); + buf.putShort(getMinRightSideBearing()); + buf.putShort(getXMaxExtent()); + buf.putShort(getCaretSlopeRise()); + buf.putShort(getCaretSlopeRun()); + buf.putShort(getCaretOffset()); + + // padding + buf.putShort((short) 0); + buf.putShort((short) 0); + buf.putShort((short) 0); + buf.putShort((short) 0); + + buf.putShort(getMetricDataFormat()); + buf.putShort((short) getNumOfLongHorMetrics()); + + // reset the position to the start of the buffer + buf.flip(); + + return buf; + } + + /** + * Get the length of this table + */ + @Override + public int getLength() { + return 36; + } + + /** Getter for property version. + * @return Value of property version. + * + */ + public int getVersion() { + return this.version; + } + + /** Setter for property version. + * @param version New value of property version. + * + */ + public void setVersion(int version) { + this.version = version; + } + + /** + * Create a pretty string + */ + @Override + public String toString() { + StringBuffer buf = new StringBuffer(); + String indent = " "; + + buf.append(indent + "Version : " + Integer.toHexString(getVersion()) + "\n"); + buf.append(indent + "Ascent : " + getAscent() + "\n"); + buf.append(indent + "Descent : " + getDescent() + "\n"); + buf.append(indent + "LineGap : " + getLineGap() + "\n"); + buf.append(indent + "AdvanceWidthMax : " + getAdvanceWidthMax() + "\n"); + buf.append(indent + "MinLSB : " + getMinLeftSideBearing() + "\n"); + buf.append(indent + "MinRSB : " + getMinRightSideBearing() + "\n"); + buf.append(indent + "MaxExtent : " + getXMaxExtent() + "\n"); + buf.append(indent + "CaretSlopeRise : " + getCaretSlopeRise() + "\n"); + buf.append(indent + "CaretSlopeRun : " + getCaretSlopeRun() + "\n"); + buf.append(indent + "CaretOffset : " + getCaretOffset() + "\n"); + buf.append(indent + "MetricDataFormat : " + getMetricDataFormat() + "\n"); + buf.append(indent + "NumOfLongHorMetrics : " + getNumOfLongHorMetrics() + "\n"); + return buf.toString(); + } + + /** Getter for property ascent. + * @return Value of property ascent. + * + */ + public short getAscent() { + return this.ascent; + } + + /** Setter for property ascent. + * @param ascent New value of property ascent. + * + */ + public void setAscent(short ascent) { + this.ascent = ascent; + } + + /** Getter for property descent. + * @return Value of property descent. + * + */ + public short getDescent() { + return this.descent; + } + + /** Setter for property descent. + * @param descent New value of property descent. + * + */ + public void setDescent(short descent) { + this.descent = descent; + } + + /** Getter for property lineGap. + * @return Value of property lineGap. + * + */ + public short getLineGap() { + return this.lineGap; + } + + /** Setter for property lineGap. + * @param lineGap New value of property lineGap. + * + */ + public void setLineGap(short lineGap) { + this.lineGap = lineGap; + } + + /** Getter for property advanceWidthMax. + * @return Value of property advanceWidthMax. + * + */ + public short getAdvanceWidthMax() { + return this.advanceWidthMax; + } + + /** Setter for property advanceWidthMax. + * @param advanceWidthMax New value of property advanceWidthMax. + * + */ + public void setAdvanceWidthMax(short advanceWidthMax) { + this.advanceWidthMax = advanceWidthMax; + } + + /** Getter for property minLeftSideBearing. + * @return Value of property minLeftSideBearing. + * + */ + public short getMinLeftSideBearing() { + return this.minLeftSideBearing; + } + + /** Setter for property minLeftSideBearing. + * @param minLeftSideBearing New value of property minLeftSideBearing. + * + */ + public void setMinLeftSideBearing(short minLeftSideBearing) { + this.minLeftSideBearing = minLeftSideBearing; + } + + /** Getter for property minRIghtSideBearing. + * @return Value of property minRIghtSideBearing. + * + */ + public short getMinRightSideBearing() { + return this.minRightSideBearing; + } + + /** Setter for property minRIghtSideBearing. + * @param minRightSideBearing New value of property minRIghtSideBearing. + * + */ + public void setMinRightSideBearing(short minRightSideBearing) { + this.minRightSideBearing = minRightSideBearing; + } + + /** Getter for property xMaxExtent. + * @return Value of property xMaxExtent. + * + */ + public short getXMaxExtent() { + return this.xMaxExtent; + } + + /** Setter for property xMaxExtent. + * @param xMaxExtent New value of property xMaxExtent. + * + */ + public void setXMaxExtent(short xMaxExtent) { + this.xMaxExtent = xMaxExtent; + } + + /** Getter for property caretSlopeRise. + * @return Value of property caretSlopeRise. + * + */ + public short getCaretSlopeRise() { + return this.caretSlopeRise; + } + + /** Setter for property caretSlopeRise. + * @param caretSlopeRise New value of property caretSlopeRise. + * + */ + public void setCaretSlopeRise(short caretSlopeRise) { + this.caretSlopeRise = caretSlopeRise; + } + + /** Getter for property caretSlopeRun. + * @return Value of property caretSlopeRun. + * + */ + public short getCaretSlopeRun() { + return this.caretSlopeRun; + } + + /** Setter for property caretSlopeRun. + * @param caretSlopeRun New value of property caretSlopeRun. + * + */ + public void setCaretSlopeRun(short caretSlopeRun) { + this.caretSlopeRun = caretSlopeRun; + } + + /** Getter for property caretOffset. + * @return Value of property caretOffset. + * + */ + public short getCaretOffset() { + return this.caretOffset; + } + + /** Setter for property caretOffset. + * @param caretOffset New value of property caretOffset. + * + */ + public void setCaretOffset(short caretOffset) { + this.caretOffset = caretOffset; + } + + /** Getter for property metricDataFormat. + * @return Value of property metricDataFormat. + * + */ + public short getMetricDataFormat() { + return this.metricDataFormat; + } + + /** Setter for property metricDataFormat. + * @param metricDataFormat New value of property metricDataFormat. + * + */ + public void setMetricDataFormat(short metricDataFormat) { + this.metricDataFormat = metricDataFormat; + } + + /** Getter for property numOfLongHorMetrics. + * @return Value of property numOfLongHorMetrics. + * + */ + public int getNumOfLongHorMetrics() { + return this.numOfLongHorMetrics & 0xFFFF; + } + + /** Setter for property numOfLongHorMetrics. + * @param numOfLongHorMetrics New value of property numOfLongHorMetrics. + * + */ + public void setNumOfLongHorMetrics(short numOfLongHorMetrics) { + this.numOfLongHorMetrics = numOfLongHorMetrics; + } + +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/HmtxTable.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/HmtxTable.java new file mode 100644 index 000000000..f630206e7 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/HmtxTable.java @@ -0,0 +1,122 @@ +/* Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package com.sun.pdfview.font.ttf; + +import java.nio.ByteBuffer; +import java.util.Arrays; + +/** + * Model the TrueType Post table + * + * @author jkaplan + */ +public class HmtxTable extends TrueTypeTable { + /** advance widths for any glyphs that have one */ + short advanceWidths[]; + + /** left side bearings for each glyph */ + short leftSideBearings[]; + + /** Creates a new instance of HmtxTable */ + protected HmtxTable(TrueTypeFont ttf) { + super (TrueTypeTable.HMTX_TABLE); + + // the number of glyphs stored in the maxp table may be incorrect + // in the case of subsetted fonts produced by some pdf generators + MaxpTable maxp = (MaxpTable) ttf.getTable("maxp"); + int numGlyphs = maxp.getNumGlyphs(); + + HheaTable hhea = (HheaTable) ttf.getTable("hhea"); + int numOfLongHorMetrics = hhea.getNumOfLongHorMetrics(); + + this.advanceWidths = new short[numOfLongHorMetrics]; + this.leftSideBearings = new short[numGlyphs]; + } + + /** get the advance of a given glyph */ + public short getAdvance(int glyphID) { + if (glyphID < this.advanceWidths.length) { + return this.advanceWidths[glyphID]; + } else { + return this.advanceWidths[this.advanceWidths.length - 1]; + } + } + + /** get the left side bearing of a given glyph */ + public short getLeftSideBearing(int glyphID) { + return this.leftSideBearings[glyphID]; + } + + /** get the data in this map as a ByteBuffer */ + @Override + public ByteBuffer getData() { + int size = getLength(); + + ByteBuffer buf = ByteBuffer.allocate(size); + + // write the metrics + for (int i = 0; i < this.leftSideBearings.length; i++) { + if (i < this.advanceWidths.length) { + buf.putShort(this.advanceWidths[i]); + } + + buf.putShort(this.leftSideBearings[i]); + } + + // reset the start pointer + buf.flip(); + + return buf; + } + + /** Initialize this structure from a ByteBuffer */ + @Override + public void setData(ByteBuffer data) { + // some PDF writers subset the font but don't update the number of glyphs in the maxp table, + // this would appear to break the TTF spec. + // A better solution might be to try and override the numGlyphs in the maxp table based + // on the number of entries in the cmap table or by parsing the glyf table, but this + // appears to be the only place that gets affected by the discrepancy... so far!... + // so updating this allows it to work. + int i; + // only read as much data as is available + for (i = 0; i < this.leftSideBearings.length && data.hasRemaining(); i++) { + if (i < this.advanceWidths.length) { + this.advanceWidths[i] = data.getShort(); + } + + this.leftSideBearings[i] = data.getShort(); + } + // initialise the remaining advanceWidths and leftSideBearings to 0 + if (i < this.advanceWidths.length) { + Arrays.fill(this.advanceWidths, i, this.advanceWidths.length-1, (short) 0); + } + if (i < this.leftSideBearings.length) { + Arrays.fill(this.leftSideBearings, i, this.leftSideBearings.length-1, (short) 0); + } + } + + /** + * Get the length of this table + */ + @Override + public int getLength() { + return (this.advanceWidths.length * 2) + (this.leftSideBearings.length * 2); + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/LocaTable.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/LocaTable.java new file mode 100644 index 000000000..3a47d0e01 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/LocaTable.java @@ -0,0 +1,117 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package com.sun.pdfview.font.ttf; + +import java.nio.ByteBuffer; + +/** + * Model the TrueType Loca table + */ +public class LocaTable extends TrueTypeTable { + /** if true, the table stores glyphs in long format */ + private boolean isLong; + + /** the offsets themselves */ + private int offsets[]; + + /** Creates a new instance of HmtxTable */ + protected LocaTable(TrueTypeFont ttf) { + super (TrueTypeTable.LOCA_TABLE); + + MaxpTable maxp = (MaxpTable) ttf.getTable("maxp"); + int numGlyphs = maxp.getNumGlyphs(); + + HeadTable head = (HeadTable) ttf.getTable("head"); + short format = head.getIndexToLocFormat(); + this.isLong = (format == 1); + + this.offsets = new int[numGlyphs + 1]; + } + + /** + * get the offset, in bytes, of a given glyph from the start of + * the glyph table + */ + public int getOffset(int glyphID) { + return this.offsets[glyphID]; + } + + /** + * get the size, in bytes, of the given glyph + */ + public int getSize(int glyphID) { + return this.offsets[glyphID + 1] - this.offsets[glyphID]; + } + + /** + * Return true if the glyphs arte in long (int) format, or + * false if they are in short (short) format + */ + public boolean isLongFormat() { + return this.isLong; + } + + + /** get the data in this map as a ByteBuffer */ + @Override + public ByteBuffer getData() { + int size = getLength(); + + ByteBuffer buf = ByteBuffer.allocate(size); + + // write the offsets + for (int i = 0; i < this.offsets.length; i++) { + if (isLongFormat()) { + buf.putInt(this.offsets[i]); + } else { + buf.putShort((short) (this.offsets[i] / 2)); + } + } + + // reset the start pointer + buf.flip(); + + return buf; + } + + /** Initialize this structure from a ByteBuffer */ + @Override + public void setData(ByteBuffer data) { + for (int i = 0; i < this.offsets.length; i++) { + if (isLongFormat()) { + this.offsets[i] = data.getInt(); + } else { + this.offsets[i] = 2 * ( 0xFFFF & data.getShort()); + } + } + } + + /** + * Get the length of this table + */ + @Override + public int getLength() { + if (isLongFormat()) { + return this.offsets.length * 4; + } else { + return this.offsets.length * 2; + } + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/MaxpTable.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/MaxpTable.java new file mode 100644 index 000000000..c1b634674 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/MaxpTable.java @@ -0,0 +1,426 @@ +/* Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package com.sun.pdfview.font.ttf; + +import java.nio.ByteBuffer; + +/** + * + * @author jkaplan + */ +public class MaxpTable extends TrueTypeTable { + + /** Holds value of property version. */ + private int version; + + // the following are supposed to be USHORT, but will be Int to enclose the sign + // (http://www.microsoft.com/typography/OTSpec/maxp.htm) + /** Holds value of property numGlyphs. */ + private int numGlyphs; + + /** Holds value of property maxPoints. */ + private int maxPoints; + + /** Holds value of property maxContours. */ + private int maxContours; + + /** Holds value of property maxComponentPoints. */ + private int maxComponentPoints; + + /** Holds value of property maxComponentContours. */ + private int maxComponentContours; + + /** Holds value of property maxZones. */ + private int maxZones; + + /** Holds value of property maxTwilightPoints. */ + private int maxTwilightPoints; + + /** Holds value of property maxStorage. */ + private int maxStorage; + + /** Holds value of property maxFunctionDefs. */ + private int maxFunctionDefs; + + /** Holds value of property maxInstructionDefs. */ + private int maxInstructionDefs; + + /** Holds value of property maxStackElements. */ + private int maxStackElements; + + /** Holds value of property maxSizeOfInstructions. */ + private int maxSizeOfInstructions; + + /** Holds value of property maxComponentElements. */ + private int maxComponentElements; + + /** Holds value of property maxComponentDepth. */ + private int maxComponentDepth; + + /** Creates a new instance of MaxpTable */ + protected MaxpTable() { + super (TrueTypeTable.MAXP_TABLE); + + setVersion(0x10000); + setNumGlyphs(0); + setMaxPoints(0); + setMaxContours(0); + setMaxComponentPoints(0); + setMaxComponentContours(0); + setMaxZones(2); + setMaxTwilightPoints(0); + setMaxStorage(0); + setMaxFunctionDefs(0); + setMaxInstructionDefs(0); + setMaxStackElements(0); + setMaxSizeOfInstructions(0); + setMaxComponentElements(0); + setMaxComponentDepth(0); + } + + /** + * Set the values from data + */ + @Override + public void setData(ByteBuffer data) { + if (data.remaining() != 32) { + throw new IllegalArgumentException("Bad size for Maxp table"); + } + + setVersion(data.getInt()); + setNumGlyphs(data.getShort()); + setMaxPoints(data.getShort()); + setMaxContours(data.getShort()); + setMaxComponentPoints(data.getShort()); + setMaxComponentContours(data.getShort()); + setMaxZones(data.getShort()); + setMaxTwilightPoints(data.getShort()); + setMaxStorage(data.getShort()); + setMaxFunctionDefs(data.getShort()); + setMaxInstructionDefs(data.getShort()); + setMaxStackElements(data.getShort()); + setMaxSizeOfInstructions(data.getShort()); + setMaxComponentElements(data.getShort()); + setMaxComponentDepth(data.getShort()); + } + + /** + * Get a buffer from the data + */ + @Override + public ByteBuffer getData() { + ByteBuffer buf = ByteBuffer.allocate(getLength()); + + buf.putInt(getVersion()); + buf.putShort((short) getNumGlyphs()); + buf.putShort((short) getMaxPoints()); + buf.putShort((short) getMaxContours()); + buf.putShort((short) getMaxComponentPoints()); + buf.putShort((short) getMaxComponentContours()); + buf.putShort((short) getMaxZones()); + buf.putShort((short) getMaxTwilightPoints()); + buf.putShort((short) getMaxStorage()); + buf.putShort((short) getMaxFunctionDefs()); + buf.putShort((short) getMaxInstructionDefs()); + buf.putShort((short) getMaxStackElements()); + buf.putShort((short) getMaxSizeOfInstructions()); + buf.putShort((short) getMaxComponentElements()); + buf.putShort((short) getMaxComponentDepth()); + + // reset the position to the beginning of the buffer + buf.flip(); + + return buf; + } + + /** + * Get the length of this table + */ + @Override + public int getLength() { + return 32; + } + + /** Getter for property version. + * @return Value of property version. + * + */ + public int getVersion() { + return this.version; + } + + /** Setter for property version. + * @param version New value of property version. + * + */ + public void setVersion(int version) { + this.version = version; + } + + /** Getter for property numGlyphs. + * @return Value of property numGlyphs. + * + */ + public int getNumGlyphs() { + return this.numGlyphs & 0xFFFF; + } + + /** Setter for property numGlyphs. + * @param numGlyphs New value of property numGlyphs. + * + */ + public void setNumGlyphs(int numGlyphs) { + this.numGlyphs = numGlyphs; + } + + /** Getter for property maxPoints. + * @return Value of property maxPoints. + * + */ + public int getMaxPoints() { + return this.maxPoints & 0xFFFF; + } + + /** Setter for property maxPoints. + * @param maxPoints New value of property maxPoints. + * + */ + public void setMaxPoints(int maxPoints) { + this.maxPoints = maxPoints; + } + + /** Getter for property maxContours. + * @return Value of property maxContours. + * + */ + public int getMaxContours() { + return this.maxContours & 0xFFFF; + } + + /** Setter for property maxContours. + * @param maxContours New value of property maxContours. + * + */ + public void setMaxContours(int maxContours) { + this.maxContours = maxContours; + } + + /** Getter for property maxComponentPoints. + * @return Value of property maxComponentPoints. + * + */ + public int getMaxComponentPoints() { + return this.maxComponentPoints & 0xFFFF; + } + + /** Setter for property maxComponentPoints. + * @param maxComponentPoints New value of property maxComponentPoints. + * + */ + public void setMaxComponentPoints(int maxComponentPoints) { + this.maxComponentPoints = maxComponentPoints; + } + + /** Getter for property maxComponentContours. + * @return Value of property maxComponentContours. + * + */ + public int getMaxComponentContours() { + return this.maxComponentContours & 0xFFFF; + } + + /** Setter for property maxComponentContours. + * @param maxComponentContours New value of property maxComponentContours. + * + */ + public void setMaxComponentContours(int maxComponentContours) { + this.maxComponentContours = maxComponentContours; + } + + /** Getter for property maxZones. + * @return Value of property maxZones. + * + */ + public int getMaxZones() { + return this.maxZones & 0xFFFF; + } + + /** Setter for property maxZones. + * @param maxZones New value of property maxZones. + * + */ + public void setMaxZones(int maxZones) { + this.maxZones = maxZones; + } + + /** Getter for property maxTwilightPoints. + * @return Value of property maxTwilightPoints. + * + */ + public int getMaxTwilightPoints() { + return this.maxTwilightPoints & 0xFFFF; + } + + /** Setter for property maxTwilightPoints. + * @param maxTwilightPoints New value of property maxTwilightPoints. + * + */ + public void setMaxTwilightPoints(int maxTwilightPoints) { + this.maxTwilightPoints = maxTwilightPoints; + } + + /** Getter for property maxStorage. + * @return Value of property maxStorage. + * + */ + public int getMaxStorage() { + return this.maxStorage & 0xFFFF; + } + + /** Setter for property maxStorage. + * @param maxStorage New value of property maxStorage. + * + */ + public void setMaxStorage(int maxStorage) { + this.maxStorage = maxStorage; + } + + /** Getter for property maxFunctionDefs. + * @return Value of property maxFunctionDefs. + * + */ + public int getMaxFunctionDefs() { + return this.maxFunctionDefs & 0xFFFF; + } + + /** Setter for property maxFunctionDefs. + * @param maxFunctionDefs New value of property maxFunctionDefs. + * + */ + public void setMaxFunctionDefs(int maxFunctionDefs) { + this.maxFunctionDefs = maxFunctionDefs; + } + + /** Getter for property maxInstructionDefs. + * @return Value of property maxInstructionDefs. + * + */ + public int getMaxInstructionDefs() { + return this.maxInstructionDefs & 0xFFFF; + } + + /** Setter for property maxInstructionDefs. + * @param maxInstructionDefs New value of property maxInstructionDefs. + * + */ + public void setMaxInstructionDefs(int maxInstructionDefs) { + this.maxInstructionDefs = maxInstructionDefs; + } + + /** Getter for property maxStackElements. + * @return Value of property maxStackElements. + * + */ + public int getMaxStackElements() { + return this.maxStackElements & 0xFFFF; + } + + /** Setter for property maxStackElements. + * @param maxStackElements New value of property maxStackElements. + * + */ + public void setMaxStackElements(int maxStackElements) { + this.maxStackElements = maxStackElements; + } + + /** Getter for property maxSizeOfInstructions. + * @return Value of property maxSizeOfInstructions. + * + */ + public int getMaxSizeOfInstructions() { + return this.maxSizeOfInstructions & 0xFFFF; + } + + /** Setter for property maxSizeOfInstructions. + * @param maxSizeOfInstructions New value of property maxSizeOfInstructions. + * + */ + public void setMaxSizeOfInstructions(int maxSizeOfInstructions) { + this.maxSizeOfInstructions = maxSizeOfInstructions; + } + + /** Getter for property maxComponentElements. + * @return Value of property maxComponentElements. + * + */ + public int getMaxComponentElements() { + return this.maxComponentElements & 0xFFFF; + } + + /** Setter for property maxComponentElements. + * @param maxComponentElements New value of property maxComponentElements. + * + */ + public void setMaxComponentElements(int maxComponentElements) { + this.maxComponentElements = maxComponentElements; + } + + /** Getter for property maxComponentDepth. + * @return Value of property maxComponentDepth. + * + */ + public int getMaxComponentDepth() { + return this.maxComponentDepth & 0xFFFF; + } + + /** Setter for property maxComponentDepth. + * @param maxComponentDepth New value of property maxComponentDepth. + * + */ + public void setMaxComponentDepth(int maxComponentDepth) { + this.maxComponentDepth = maxComponentDepth; + } + + /** + * Create a pretty String + */ + @Override + public String toString() { + StringBuffer buf = new StringBuffer(); + String indent = " "; + + buf.append(indent + "Version : " + Integer.toHexString(getVersion()) + "\n"); + buf.append(indent + "NumGlyphs : " + getNumGlyphs() + "\n"); + buf.append(indent + "MaxPoints : " + getMaxPoints() + "\n"); + buf.append(indent + "MaxContours : " + getMaxContours() + "\n"); + buf.append(indent + "MaxCompPoints : " + getMaxComponentPoints() + "\n"); + buf.append(indent + "MaxCompContours : " + getMaxComponentContours() + "\n"); + buf.append(indent + "MaxZones : " + getMaxZones() + "\n"); + buf.append(indent + "MaxTwilightPoints: " + getMaxTwilightPoints() + "\n"); + buf.append(indent + "MaxStorage : " + getMaxStorage() + "\n"); + buf.append(indent + "MaxFuncDefs : " + getMaxFunctionDefs() + "\n"); + buf.append(indent + "MaxInstDefs : " + getMaxInstructionDefs() + "\n"); + buf.append(indent + "MaxStackElements : " + getMaxStackElements() + "\n"); + buf.append(indent + "MaxSizeInst : " + getMaxSizeOfInstructions() + "\n"); + buf.append(indent + "MaxCompElements : " + getMaxComponentElements() + "\n"); + buf.append(indent + "MaxCompDepth : " + getMaxComponentDepth() + "\n"); + + return buf.toString(); + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/NameTable.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/NameTable.java new file mode 100644 index 000000000..30c776362 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/NameTable.java @@ -0,0 +1,430 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package com.sun.pdfview.font.ttf; + +import java.nio.ByteBuffer; +import java.nio.charset.Charset; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.SortedMap; +import java.util.TreeMap; + +/** + * + * @author jon + */ +public class NameTable extends TrueTypeTable { + /** + * Values for platformID + */ + public static final short PLATFORMID_UNICODE = 0; + public static final short PLATFORMID_MACINTOSH = 1; + public static final short PLATFORMID_MICROSOFT = 3; + + /** + * Values for platformSpecificID if platform is Mac + */ + public static final short ENCODINGID_MAC_ROMAN = 0; + + /** + * Values for platformSpecificID if platform is Unicode + */ + public static final short ENCODINGID_UNICODE_DEFAULT = 0; + public static final short ENCODINGID_UNICODE_V11 = 1; + public static final short ENCODINGID_UNICODE_V2 = 3; + + /** + * Values for language ID if platform is Mac + */ + public static final short LANGUAGEID_MAC_ENGLISH = 0; + + /** + * Values for nameID + */ + public static final short NAMEID_COPYRIGHT = 0; + public static final short NAMEID_FAMILY = 1; + public static final short NAMEID_SUBFAMILY = 2; + public static final short NAMEID_SUBFAMILY_UNIQUE = 3; + public static final short NAMEID_FULL_NAME = 4; + public static final short NAMEID_VERSION = 5; + public static final short NAMEID_POSTSCRIPT_NAME = 6; + public static final short NAMEID_TRADEMARK = 7; + /** + * The format of this table + */ + private short format; + + /** + * The actual name records + */ + private SortedMap records; + + + /** Creates a new instance of NameTable */ + protected NameTable() { + super (TrueTypeTable.NAME_TABLE); + + this.records = Collections.synchronizedSortedMap(new TreeMap()); + } + + /** + * Add a record to the table + */ + public void addRecord(short platformID, short platformSpecificID, + short languageID, short nameID, + String value) { + NameRecord rec = new NameRecord(platformID, platformSpecificID, + languageID, nameID); + this.records.put(rec, value); + } + + /** + * Get a record from the table + */ + public String getRecord(short platformID, short platformSpecificID, + short languageID, short nameID) { + + NameRecord rec = new NameRecord(platformID, platformSpecificID, + languageID, nameID); + return this.records.get(rec); + } + + /** + * Remove a record from the table + */ + public void removeRecord(short platformID, short platformSpecificID, + short languageID, short nameID) { + NameRecord rec = new NameRecord(platformID, platformSpecificID, + languageID, nameID); + this.records.remove(rec); + } + + /** + * Determine if we have any records with a given platform ID + */ + public boolean hasRecords(short platformID) { + for (Iterator i = this.records.keySet().iterator(); i.hasNext(); ) { + NameRecord rec = (NameRecord) i.next(); + + if (rec.platformID == platformID) { + return true; + } + } + + return false; + } + + /** + * Determine if we have any records with a given platform ID and + * platform-specific ID + */ + public boolean hasRecords(short platformID, short platformSpecificID) { + for (Iterator i = this.records.keySet().iterator(); i.hasNext(); ) { + NameRecord rec = (NameRecord) i.next(); + + if (rec.platformID == platformID && + rec.platformSpecificID == platformSpecificID) { + return true; + } + } + + return false; + } + + /** + * Read the table from data + */ + @Override + public void setData(ByteBuffer data) { + //read table header + setFormat(data.getShort()); + int count = data.getShort(); + int stringOffset = data.getShort(); + + // read the records + for (int i = 0; i < count; i++) { + short platformID = data.getShort(); + short platformSpecificID = data.getShort(); + short languageID = data.getShort(); + short nameID = data.getShort(); + + int length = data.getShort() & 0xFFFF; + int offset = data.getShort() & 0xFFFF; + + // read the String data + data.mark(); + data.position(stringOffset + offset); + + ByteBuffer stringBuf = data.slice(); + stringBuf.limit(length); + + data.reset(); + + // choose the character set + String charsetName = getCharsetName(platformID, platformSpecificID); + Charset charset = Charset.forName(charsetName); + + // parse the data as a string + String value = charset.decode(stringBuf).toString(); + + // add to the mix + addRecord(platformID, platformSpecificID, languageID, nameID, value); + } + } + + /** + * Get the data in this table as a buffer + */ + @Override + public ByteBuffer getData() { + // alocate the output buffer + ByteBuffer buf = ByteBuffer.allocate(getLength()); + + // the start of string data + short headerLength = (short) (6 + (12 * getCount())); + + // write the header + buf.putShort(getFormat()); + buf.putShort(getCount()); + buf.putShort(headerLength); + + // the offset from the start of the strings table + short curOffset = 0; + + // add the size of each record + for (Iterator i = this.records.keySet().iterator(); i.hasNext();) { + NameRecord rec = (NameRecord) i.next(); + String value = this.records.get(rec); + + // choose the charset + String charsetName = getCharsetName(rec.platformID, + rec.platformSpecificID); + Charset charset = Charset.forName(charsetName); + + // encode + ByteBuffer strBuf = charset.encode(value); + short strLen = (short) (strBuf.remaining() & 0xFFFF); + + // write the IDs + buf.putShort(rec.platformID); + buf.putShort(rec.platformSpecificID); + buf.putShort(rec.languageID); + buf.putShort(rec.nameID); + + // write the size and offset + buf.putShort(strLen); + buf.putShort(curOffset); + + // remember or current position + buf.mark(); + + // move to the current offset and write the data + buf.position(headerLength + curOffset); + buf.put(strBuf); + + // reset stuff + buf.reset(); + + // increment offset + curOffset += strLen; + } + + // reset the pointer on the buffer + buf.position(headerLength + curOffset); + buf.flip(); + + return buf; + } + + /** + * Get the length of this table + */ + @Override + public int getLength() { + // start with the size of the fixed header plus the size of the + // records + int length = 6 + (12 * getCount()); + + // add the size of each record + for (Iterator i = this.records.keySet().iterator(); i.hasNext();) { + NameRecord rec = (NameRecord) i.next(); + String value = this.records.get(rec); + + // choose the charset + String charsetName = getCharsetName(rec.platformID, + rec.platformSpecificID); + Charset charset = Charset.forName(charsetName); + + // encode + ByteBuffer buf = charset.encode(value); + + // add the size of the coded buffer + length += buf.remaining(); + } + + return length; + } + + /** + * Get the format of this table + */ + public short getFormat() { + return this.format; + } + + /** + * Set the format of this table + */ + public void setFormat(short format) { + this.format = format; + } + + /** + * Get the number of records in the table + */ + public short getCount() { + return (short) this.records.size(); + } + + /** + * Get the charset name for a given platform, encoding and language + */ + public static String getCharsetName(int platformID, int encodingID) { + String charset = "US-ASCII"; + + switch (platformID) { + case PLATFORMID_UNICODE: + charset = "UTF-16"; + break; + case PLATFORMID_MICROSOFT: + charset = "UTF-16"; + break; + } + + return charset; + } + + /** Get a pretty string */ + @Override + public String toString() { + StringBuffer buf = new StringBuffer(); + String indent = " "; + + buf.append(indent + "Format: " + getFormat() + "\n"); + buf.append(indent + "Count : " + getCount() + "\n"); + + for (Iterator i = this.records.keySet().iterator(); i.hasNext();) { + NameRecord rec = (NameRecord) i.next(); + + buf.append(indent + " platformID: " + rec.platformID); + buf.append(" platformSpecificID: " + rec.platformSpecificID); + buf.append(" languageID: " + rec.languageID); + buf.append(" nameID: " + rec.nameID + "\n"); + buf.append(indent + " " + this.records.get(rec) + "\n"); + } + + return buf.toString(); + } + + public Collection getNames() + { + return Collections.unmodifiableCollection(records.values()); + } + + /** + * A class to hold the data associated with each record + */ + static class NameRecord implements Comparable { + /** + * Platform ID + */ + short platformID; + + /** + * Platform Specific ID (Encoding) + */ + short platformSpecificID; + + /** + * Language ID + */ + short languageID; + + /** + * Name ID + */ + short nameID; + + /** + * Create a new record + */ + NameRecord(short platformID, short platformSpecificID, + short languageID, short nameID) { + this.platformID = platformID; + this.platformSpecificID = platformSpecificID; + this.languageID = languageID; + this.nameID = nameID; + } + + + /** + * Compare two records + */ + @Override + public boolean equals(Object o) { + return (compareTo(o) == 0); + } + + /** + * Compare two records + */ + @Override + public int compareTo(Object obj) { + if (!(obj instanceof NameRecord)) { + return -1; + } + + NameRecord rec = (NameRecord) obj; + + if (this.platformID > rec.platformID) { + return 1; + } else if (this.platformID < rec.platformID) { + return -1; + } else if (this.platformSpecificID > rec.platformSpecificID) { + return 1; + } else if (this.platformSpecificID < rec.platformSpecificID) { + return -1; + } else if (this.languageID > rec.languageID) { + return 1; + } else if (this.languageID < rec.languageID) { + return -1; + } else if (this.nameID > rec.nameID) { + return 1; + } else if (this.nameID < rec.nameID) { + return -1; + } else { + return 0; + } + } + + + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/PostTable.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/PostTable.java new file mode 100644 index 000000000..9a8514a58 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/PostTable.java @@ -0,0 +1,545 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package com.sun.pdfview.font.ttf; + +import java.nio.ByteBuffer; +import java.util.Arrays; + +import com.sun.pdfview.PDFDebugger; + +/** + * Model the TrueType Post table + * + * @author jkaplan + */ +public class PostTable extends TrueTypeTable { + + /** Holds value of property format. */ + private int format; + + /** Holds value of property italicAngle. */ + private int italicAngle; + + /** Holds value of property underlinePosition. */ + private short underlinePosition; + + /** Holds value of property underlineThickness. */ + private short underlineThickness; + + /** Holds value of property isFixedPitch. */ + private short isFixedPitch; + + /** Holds value of property minMemType42. */ + private int minMemType42; + + /** Holds value of property maxMemType42. */ + private int maxMemType42; + + /** Holds value of property minMemType1. */ + private int minMemType1; + + /** Holds value of property maxMemType1. */ + private int maxMemType1; + + /** A map which character values to names and vice versa */ + private PostMap nameMap; + + /** Creates a new instance of PostTable */ + protected PostTable() { + super (TrueTypeTable.POST_TABLE); + + this.nameMap = new PostMap(); + } + + /** + * Map a character name to a glyphNameIndex + */ + public short getGlyphNameIndex(String name) { + return this.nameMap.getCharIndex(name); + } + + /** + * Map a character code to a glyphIndex name + */ + public String getGlyphName(char c) { + return this.nameMap.getCharName(c); + } + + /** get the data in this map as a ByteBuffer */ + @Override + public ByteBuffer getData() { + int size = getLength(); + + ByteBuffer buf = ByteBuffer.allocate(size); + + // write the header + buf.putInt(getFormat()); + buf.putInt(getItalicAngle()); + buf.putShort(getUnderlinePosition()); + buf.putShort(getUnderlineThickness()); + buf.putShort(getIsFixedPitch()); + buf.putShort((short) 0); + buf.putInt(getMinMemType42()); + buf.putInt(getMaxMemType42()); + buf.putInt(getMinMemType1()); + buf.putInt(getMaxMemType1()); + + // now write the table + buf.put(this.nameMap.getData()); + + // reset the start pointer + buf.flip(); + + return buf; + } + + /** Initialize this structure from a ByteBuffer */ + @Override + public void setData(ByteBuffer data) { + setFormat(data.getInt()); + setItalicAngle(data.getInt()); + setUnderlinePosition(data.getShort()); + setUnderlineThickness(data.getShort()); + setIsFixedPitch(data.getShort()); + data.getShort(); + setMinMemType42(data.getInt()); + setMaxMemType42(data.getInt()); + setMinMemType1(data.getInt()); + setMaxMemType1(data.getInt()); + + // create the map, based on the type + switch (this.format) { + case 0x10000: + this.nameMap = new PostMapFormat0(); + break; + case 0x20000: + this.nameMap = new PostMapFormat2(); + break; + case 0x30000: + // empty post map. + this.nameMap = new PostMap(); + break; + default: + this.nameMap = new PostMap(); + PDFDebugger.debug("Unknown post map type: " + + Integer.toHexString(this.format)); + break; + } + + // fill in the data in the map + this.nameMap.setData(data); + } + + /** + * Get the length of this table + */ + @Override + public int getLength() { + int size = 32; + if (this.nameMap != null) { + size += this.nameMap.getLength(); + } + + return size; + } + + /** Getter for property format. + * @return Value of property format. + * + */ + public int getFormat() { + return this.format; + } + + /** Setter for property format. + * @param format New value of property format. + * + */ + public void setFormat(int format) { + this.format = format; + } + + /** Getter for property italicAngle. + * @return Value of property italicAngle. + * + */ + public int getItalicAngle() { + return this.italicAngle; + } + + /** Setter for property italicAngle. + * @param italicAngle New value of property italicAngle. + * + */ + public void setItalicAngle(int italicAngle) { + this.italicAngle = italicAngle; + } + + /** Getter for property underlinePosition. + * @return Value of property underlinePosition. + * + */ + public short getUnderlinePosition() { + return this.underlinePosition; + } + + /** Setter for property underlinePosition. + * @param underlinePosition New value of property underlinePosition. + * + */ + public void setUnderlinePosition(short underlinePosition) { + this.underlinePosition = underlinePosition; + } + + /** Getter for property underlineThickness. + * @return Value of property underlineThickness. + * + */ + public short getUnderlineThickness() { + return this.underlineThickness; + } + + /** Setter for property underlineThickness. + * @param underlineThickness New value of property underlineThickness. + * + */ + public void setUnderlineThickness(short underlineThickness) { + this.underlineThickness = underlineThickness; + } + + /** Getter for property isFixedPitch. + * @return Value of property isFixedPitch. + * + */ + public short getIsFixedPitch() { + return this.isFixedPitch; + } + + /** Setter for property isFixedPitch. + * @param isFixedPitch New value of property isFixedPitch. + * + */ + public void setIsFixedPitch(short isFixedPitch) { + this.isFixedPitch = isFixedPitch; + } + + /** Getter for property minMemType42. + * @return Value of property minMemType42. + * + */ + public int getMinMemType42() { + return this.minMemType42; + } + + /** Setter for property minMemType42. + * @param minMemType42 New value of property minMemType42. + * + */ + public void setMinMemType42(int minMemType42) { + this.minMemType42 = minMemType42; + } + + /** Getter for property maxMemType42. + * @return Value of property maxMemType42. + * + */ + public int getMaxMemType42() { + return this.maxMemType42; + } + + /** Setter for property maxMemType42. + * @param maxMemType42 New value of property maxMemType42. + * + */ + public void setMaxMemType42(int maxMemType42) { + this.maxMemType42 = maxMemType42; + } + + /** Getter for property minMemType1. + * @return Value of property minMemType1. + * + */ + public int getMinMemType1() { + return this.minMemType1; + } + + /** Setter for property minMemType1. + * @param minMemType1 New value of property minMemType1. + * + */ + public void setMinMemType1(int minMemType1) { + this.minMemType1 = minMemType1; + } + + /** Getter for property maxMemType1. + * @return Value of property maxMemType1. + * + */ + public int getMaxMemType1() { + return this.maxMemType1; + } + + /** Setter for property maxMemType1. + * @param maxMemType1 New value of property maxMemType1. + * + */ + public void setMaxMemType1(int maxMemType1) { + this.maxMemType1 = maxMemType1; + } + + /** An empty post map */ + class PostMap { + /** map a name to a character index */ + short getCharIndex(String charName) { + return (short) 0; + } + + /** name a character index to a name */ + String getCharName(char charIndex) { + return null; + } + + /** get the length of the data in this map */ + int getLength() { + return 0; + } + + /** get the data in this map as a ByteBuffer */ + ByteBuffer getData() { + return ByteBuffer.allocate(0); + } + + /** set the data in this map from a ByteBuffer */ + void setData(ByteBuffer data) { + // do nothing + return; + } + } + + /** A Format 0 post map */ + class PostMapFormat0 extends PostMap { + /** the glyph names in standard Macintosh ordering */ + protected final String stdNames[] = { +/* 0 */ ".notdef", ".null", "nonmarkingreturn", "space", "exclam", "quotedbl", "numbersign", "dollar", +/* 8 */ "percent", "ampersand", "quotesingle", "parenleft", "parenright", "asterisk", "plus", "comma", +/* 16 */ "hyphen", "period", "slash", "zero", "one", "two", "three", "four", +/* 24 */ "five", "six", "seven", "eight", "nine", "colon", "semicolon", "less", +/* 32 */ "equal", "greater", "question", "at", "A", "B", "C", "D", +/* 40 */ "E", "F", "G", "H", "I", "J", "K", "L", +/* 48 */ "M", "N", "O", "P", "Q", "R", "S", "T", +/* 56 */ "U", "V", "W", "X", "Y", "Z", "bracketleft", "ackslash", +/* 64 */ "bracketright", "asciicircum", "underscore", "grave", "a", "b", "c", "d", +/* 72 */ "e", "f", "g", "h", "i", "j", "k", "l", +/* 80 */ "m", "n", "o", "p", "q", "r", "s", "t", +/* 88 */ "u", "v", "w", "x", "y", "z", "braceleft", "bar", +/* 96 */ "braceright", "asciitilde", "Adieresis", "Aring", "Ccedilla", "Eacute", "Ntilde", "Odieresis", +/* 104 */ "Udieresis", "aacute", "agrave", "acircumflex", "adieresis", "atilde", "aring", "ccedilla", +/* 112 */ "eacute", "egrave", "ecircumflex", "edieresis", "iacute", "igrave", "icircumflex", "idieresis", +/* 120 */ "ntilde", "oacute", "ograve", "ocircumflex", "odieresis", "otilde", "uacute", "ugrave", +/* 128 */ "ucircumflex", "udieresis", "dagger", "degree", "cent", "sterling", "section", "bullet", +/* 136 */ "paragraph", "germandbls", "registered", "copyright", "trademark", "acute", "dieresis", "notequal", +/* 144 */ "AE", "Oslash", "infinity", "plusminus", "lessequal", "greaterequal", "yen", "mu", +/* 152 */ "partialdiff", "summation", "product", "pi", "integral", "ordfeminine", "ordmasculine", "Omega", +/* 160 */ "ae", "oslash", "questiondown", "exclamdown", "logicalnot", "radical", "florin", "approxequal", +/* 168 */ "Delta", "guillemotleft", "guillemotright", "ellipsis", "nonbreakingspace", "Agrave", "Atilde", "Otilde", +/* 176 */ "OE", "oe", "endash", "emdash", "quotedblleft", "quotedblright", "quoteleft", "quoteright", +/* 184 */ "divide", "lozenge", "ydieresis", "Ydieresis", "fraction", "currency", "guilsinglleft", "guilsinglright", +/* 192 */ "fi", "fl", "daggerdbl", "periodcentered", "quotesinglbase", "quotedblbase", "perthousand", "Acircumflex", +/* 200 */ "Ecircumflex", "Aacute", "Edieresis", "Egrave", "Iacute", "Icircumflex", "Idieresis", "Igrave", +/* 208 */ "Oacute", "Ocircumflex", "apple", "Ograve", "Uacute", "Ucircumflex", "Ugrave", "dotlessi", +/* 216 */ "circumflex", "tilde", "macron", "breve", "dotaccent", "ring", "cedilla", "hungarumlaut", +/* 224 */ "ogonek", "caron", "Lslash", "lslash", "Scaron", "scaron", "Zcaron", "zcaron", +/* 232 */ "brokenbar", "Eth", "eth", "Yacute", "yacute", "Thorn", "thorn", "minus", +/* 240 */ "multiply", "onesuperior", "twosuperior", "threesuperior", "onehalf", "onequarter", "threequarters", "franc", +/* 248 */ "Gbreve", "gbreve", "Idotaccent", "Scedilla", "scedilla", "Cacute", "cacute", "Ccaron", +/* 256 */ "ccaron", "dcroat" + }; + + @Override + /** map a name to a character index */ + short getCharIndex(String charName) { + for (int i = 0; i < this.stdNames.length; i++) { + if (charName.equals(this.stdNames[i])) { + return (short) i; + } + } + + return (short) 0; + } + + @Override + /** name a character index to a name */ + String getCharName(char charIndex) { + return this.stdNames[charIndex]; + } + + @Override + /** get the length of the data in this map */ + int getLength() { + return 0; + } + + @Override + /** get the data in this map as a ByteBuffer */ + ByteBuffer getData() { + return ByteBuffer.allocate(0); + } + + @Override + /** set the data in this map from a ByteBuffer */ + void setData(ByteBuffer data) { + // do nothing + return; + } + } + + /** an extension to handle format 2 post maps */ + class PostMapFormat2 extends PostMapFormat0 { + /** the glyph name index */ + short[] glyphNameIndex; + + /** the glyph names */ + String[] glyphNames; + + @Override + /** Map a character name to an index */ + short getCharIndex(String charName) { + // find the index of this character name + short idx = -1; + + // first try the local names map + for (int i = 0; i < this.glyphNames.length; i++) { + if (charName.equals(this.glyphNames[i])) { + // this is the value from the glyph name index + idx = (short) (this.stdNames.length + i); + break; + } + } + + // if that doesn't work, try the standard names + if (idx == -1) { + idx = super.getCharIndex(charName); + } + + // now get the entry in the index + for (int c = 0; c < this.glyphNameIndex.length; c++) { + if (this.glyphNameIndex[c] == idx) { + return (short) c; + } + } + + // not found + return (short) 0; + } + + @Override + /** Map an index to a character name */ + String getCharName(char charIndex) { + if (charIndex >= this.stdNames.length) { + return this.glyphNames[charIndex - this.stdNames.length]; + } + + return super.getCharName(charIndex); + } + + @Override + /** get the length of this class's data */ + int getLength() { + // the size of the header plus the table of mappings + int size = 2 + (2 * this.glyphNameIndex.length); + + // the size of each string -- note the extra byte for a pascal + // string + for (int i = 0; i < this.glyphNames.length; i++) { + size += this.glyphNames[i].length() + 1; + } + + return size; + } + + @Override + /** get the data in this map as a byte array */ + ByteBuffer getData() { + ByteBuffer buf = ByteBuffer.allocate(getLength()); + + // write the number of glyphs + buf.putShort((short) this.glyphNameIndex.length); + + // write the name indices + for (int i = 0; i < this.glyphNameIndex.length; i++) { + buf.putShort(this.glyphNameIndex[i]); + } + + // write the names as pascal strings + for (int i = 0; i < this.glyphNames.length; i++) { + buf.put((byte) this.glyphNames[i].length()); + buf.put(this.glyphNames[i].getBytes()); + } + + // reset the start pointer + buf.flip(); + + return buf; + } + + @Override + /** set the contents of this map from a ByteBuffer */ + void setData(ByteBuffer data) { + short numGlyphs = data.getShort(); + this.glyphNameIndex = new short[numGlyphs]; + + // the highest glyph index seen so far + int maxGlyph = 257; + for (int i = 0; i < numGlyphs; i++) { + this.glyphNameIndex[i] = data.getShort(); + + // see if this is the highest glyph + if (this.glyphNameIndex[i] > maxGlyph) { + maxGlyph = this.glyphNameIndex[i]; + } + } + + // subtract off the default glyphs + maxGlyph -= 257; + + // read in any additional names + this.glyphNames = new String[maxGlyph]; + // fill with empty strings for avoiding nullpointer exception: glyph names + // are not mandatory for true type fonts according to the PDF spec. + Arrays.fill(this.glyphNames, ""); + + // read each name from a pascal string + // the length is stored in the first byte, followed by + // the data + for (int i = 0; i < maxGlyph; i++) { + if(data.hasRemaining()) { + // size in the first byte + byte size = data.get(); + + // then the data + byte[] stringData = new byte[size]; + data.get(stringData); + + this.glyphNames[i] = new String(stringData); + } + } + } + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/TrueTypeFont.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/TrueTypeFont.java new file mode 100644 index 000000000..ffecda80a --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/TrueTypeFont.java @@ -0,0 +1,468 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.sun.pdfview.font.ttf; + +import java.awt.Font; +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.io.RandomAccessFile; +import java.nio.ByteBuffer; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.Map; +import java.util.SortedMap; +import java.util.TreeMap; + +import com.sun.pdfview.BaseWatchable; +import com.sun.pdfview.PDFDebugger; + +/** + * + * @author jkaplan + */ +public class TrueTypeFont { + + private final int type; + // could be a ByteBuffer or a TrueTypeTable + + private final SortedMap tables; + + /** Creates a new instance of TrueTypeParser */ + public TrueTypeFont (int type) { + this.type = type; + + this.tables = Collections.synchronizedSortedMap ( + new TreeMap ()); + } + + /** + * Parses a TrueType font from a byte array + */ + public static TrueTypeFont parseFont (byte[] orig) { + ByteBuffer inBuf = ByteBuffer.wrap (orig); + return parseFont (inBuf); + } + + /** + * Parses a TrueType font from a byte buffer + */ + public static TrueTypeFont parseFont (ByteBuffer inBuf) { + int type = inBuf.getInt (); + short numTables = inBuf.getShort (); + @SuppressWarnings("unused") + short searchRange = inBuf.getShort (); + @SuppressWarnings("unused") + short entrySelector = inBuf.getShort (); + @SuppressWarnings("unused") + short rangeShift = inBuf.getShort (); + + TrueTypeFont font = new TrueTypeFont (type); + parseDirectories (inBuf, numTables, font); + + return font; + } + + /** + * Get the type of this font + */ + public int getType () { + return this.type; + } + + /** + * Add a table to the font + * + * @param tagString the name of this table, as a 4 character string + * (i.e. cmap or head) + * @param data the data for this table, as a byte buffer + */ + public void addTable (String tagString, ByteBuffer data) { + this.tables.put (tagString, data); + } + + /** + * Add a table to the font + * + * @param tagString the name of this table, as a 4 character string + * (i.e. cmap or head) + * @param table the table + */ + public void addTable (String tagString, TrueTypeTable table) { + this.tables.put (tagString, table); + } + + /** + * Get a table by name. This command causes the table in question + * to be parsed, if it has not already been parsed. + * + * @param tagString the name of this table, as a 4 character string + * (i.e. cmap or head) + */ + public TrueTypeTable getTable (String tagString) { + Object tableObj = this.tables.get (tagString); + + TrueTypeTable table = null; + + if (tableObj instanceof ByteBuffer) { + // the table has not yet been parsed. Parse it, and add the + // parsed version to the map of tables. + ByteBuffer data = (ByteBuffer) tableObj; + + table = TrueTypeTable.createTable (this, tagString, data); + addTable (tagString, table); + } else { + table = (TrueTypeTable) tableObj; + } + + return table; + } + + /** + * Remove a table by name + * + * @param tagString the name of this table, as a 4 character string + * (i.e. cmap or head) + */ + public void removeTable (String tagString) { + this.tables.remove (tagString); + } + + /** + * Get the number of tables + */ + public short getNumTables () { + return (short) this.tables.size (); + } + + /** + * Get the search range + */ + public short getSearchRange () { + double pow2 = Math.floor (Math.log (getNumTables ()) / Math.log (2)); + double maxPower = Math.pow (2, pow2); + + return (short) (16 * maxPower); + } + + /** + * Get the entry selector + */ + public short getEntrySelector () { + double pow2 = Math.floor (Math.log (getNumTables ()) / Math.log (2)); + double maxPower = Math.pow (2, pow2); + + return (short) (Math.log (maxPower) / Math.log (2)); + } + + /** + * Get the range shift + */ + public short getRangeShift () { + double pow2 = Math.floor (Math.log (getNumTables ()) / Math.log (2)); + double maxPower = Math.pow (2, pow2); + + return (short) ((maxPower * 16) - getSearchRange ()); + } + + /** + * Write a font given the type and an array of Table Directory Entries + */ + public byte[] writeFont () { + // allocate a buffer to hold the font + ByteBuffer buf = ByteBuffer.allocate (getLength ()); + + // write the font header + buf.putInt (getType ()); + buf.putShort (getNumTables ()); + buf.putShort (getSearchRange ()); + buf.putShort (getEntrySelector ()); + buf.putShort (getRangeShift ()); + + // first offset is the end of the table directory entries + int curOffset = 12 + (getNumTables () * 16); + + // write the tables + for (Iterator i = this.tables.keySet ().iterator (); i.hasNext ();) { + String tagString = i.next (); + int tag = TrueTypeTable.stringToTag (tagString); + + ByteBuffer data = null; + + Object tableObj = this.tables.get (tagString); + if (tableObj instanceof TrueTypeTable) { + data = ((TrueTypeTable) tableObj).getData (); + } else { + data = (ByteBuffer) tableObj; + } + + int dataLen = data.remaining (); + + // write the table directory entry + buf.putInt (tag); + buf.putInt (calculateChecksum (tagString, data)); + buf.putInt (curOffset); + buf.putInt (dataLen); + + // save the current position + buf.mark (); + + // move to the current offset and write the data + buf.position (curOffset); + buf.put (data); + + // reset the data start pointer + data.flip (); + + // return to the table directory entry + buf.reset (); + + // udate the offset + curOffset += dataLen; + + // don't forget the padding + while ((curOffset % 4) > 0) { + curOffset++; + } + } + + buf.position (curOffset); + buf.flip (); + + // adjust the checksum + updateChecksumAdj (buf); + + return buf.array (); + } + + /** + * Calculate the checksum for a given table + * + * @param tagString the name of the data + * @param data the data in the table + */ + private static int calculateChecksum (String tagString, ByteBuffer data) { + int sum = 0; + + data.mark (); + + // special adjustment for head table: always treat the 4-bytes + // starting at byte 8 as 0x0000. This the checkSumAdjustment so + // must be ignored here (see the TTF spec) + if (tagString.equals ("head")) { + if(!data.isReadOnly()) { + data.putInt (8, 0); + } + sum += data.getInt(); + sum += data.getInt(); + // consume the uncounted checkSumAdjustment int + data.getInt(); + } + + int nlongs = (data.remaining () + 3) / 4; + + while (nlongs-- > 0) { + if (data.remaining () > 3) { + sum += data.getInt (); + } else { + byte b0 = (data.remaining () > 0) ? data.get () : 0; + byte b1 = (data.remaining () > 0) ? data.get () : 0; + byte b2 = (data.remaining () > 0) ? data.get () : 0; + + sum += ((0xff & b0) << 24) | ((0xff & b1) << 16) | + ((0xff & b2) << 8); + } + } + + data.reset (); + + return sum; + } + + /** + * Get directory entries from a font + */ + private static void parseDirectories (ByteBuffer data, int numTables, + TrueTypeFont ttf) { + for (int i = 0; i < numTables; i++) { + int tag = data.getInt (); + String tagString = TrueTypeTable.tagToString (tag); + PDFDebugger.debug("TTFFont.parseDirectories: " + tagString, 100); + int checksum = data.getInt (); + int offset = data.getInt (); + int length = data.getInt (); + + // read the data + PDFDebugger.debug("TTFFont.parseDirectories: checksum: " + + checksum + ", offset: " + offset + ", length: " + length, 100); + data.mark (); + data.position (offset); + + ByteBuffer tableData = data.slice (); + tableData.limit (length); + + int calcChecksum = calculateChecksum (tagString, tableData); + + if (calcChecksum == checksum) { + ttf.addTable (tagString, tableData); + } else { + PDFDebugger.debug("Mismatched checksums on table " + tagString + ": " + calcChecksum + " != " + checksum, 200); + + ttf.addTable (tagString, tableData); + + } + data.reset (); + } + } + + /** + * Get the length of the font + * + * @return the length of the entire font, in bytes + */ + private int getLength () { + // the size of all the table directory entries + int length = 12 + (getNumTables () * 16); + + // for each directory entry, get the size, + // and don't forget the padding! + for (Iterator i = this.tables.values ().iterator (); i.hasNext ();) { + Object tableObj = i.next (); + + // add the length of the entry + if (tableObj instanceof TrueTypeTable) { + length += ((TrueTypeTable) tableObj).getLength (); + } else { + length += ((ByteBuffer) tableObj).remaining (); + } + + // pad + if ((length % 4) != 0) { + length += (4 - (length % 4)); + } + } + + return length; + } + + /** + * Update the checksumAdj field in the head table + */ + private void updateChecksumAdj (ByteBuffer fontData) { + int checksum = calculateChecksum ("", fontData); + int checksumAdj = 0xb1b0afba - checksum; + + // find the head table + int offset = 12 + (getNumTables () * 16); + + // find the head table + for (Iterator i = this.tables.keySet ().iterator (); i.hasNext ();) { + String tagString = i.next (); + + // adjust the checksum + if (tagString.equals ("head")) { + fontData.putInt (offset + 8, checksumAdj); + return; + } + + // add the length of the entry + Object tableObj = this.tables.get (tagString); + if (tableObj instanceof TrueTypeTable) { + offset += ((TrueTypeTable) tableObj).getLength (); + } else { + offset += ((ByteBuffer) tableObj).remaining (); + } + + // pad + if ((offset % 4) != 0) { + offset += (4 - (offset % 4)); + } + } + } + + /** + * Write the font to a pretty string + */ + @Override + public String toString () { + StringBuffer buf = new StringBuffer (); + + System.out.println ("Type : " + getType ()); + System.out.println ("NumTables : " + getNumTables ()); + System.out.println ("SearchRange : " + getSearchRange ()); + System.out.println ("EntrySelector: " + getEntrySelector ()); + System.out.println ("RangeShift : " + getRangeShift ()); + + for (Iterator> i = this.tables.entrySet ().iterator (); i.hasNext ();) { + Map.Entry e = i.next (); + + TrueTypeTable table = null; + if (e.getValue () instanceof ByteBuffer) { + table = getTable (e.getKey ()); + } else { + table = (TrueTypeTable) e.getValue (); + } + + System.out.println (table); + } + + return buf.toString (); + } + + public Collection getNames() { + NameTable table = (NameTable) getTable("name"); + if (table != null) { + return table.getNames(); + } else { + return Collections.emptyList(); + } + } + + /** + * @param args the command line arguments + */ + public static void main (String[] args) { + if (args.length != 1) { + System.out.println ("Usage: "); + System.out.println (" TrueTypeParser "); + System.exit (-1); + } + + try { + RandomAccessFile raf = new RandomAccessFile (args[0], "r"); + + int size = (int) raf.length (); + byte[] data = new byte[size]; + + raf.readFully (data); + + TrueTypeFont ttp = TrueTypeFont.parseFont (data); + + System.out.println (ttp); + + InputStream fontStream = new ByteArrayInputStream (ttp.writeFont ()); + + @SuppressWarnings("unused") + Font f = Font.createFont (Font.TRUETYPE_FONT, fontStream); + raf.close(); + } catch (Exception e) { + BaseWatchable.getErrorHandler().publishException(e); + } + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/TrueTypeTable.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/TrueTypeTable.java new file mode 100644 index 000000000..f89d1c37b --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/TrueTypeTable.java @@ -0,0 +1,194 @@ +/* Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.sun.pdfview.font.ttf; + +import java.nio.ByteBuffer; + +/** + * The base class for TrueType tables. Specific tables can extend this + * to add more functionality + */ +public class TrueTypeTable { + + /** + * Well known tables + */ + public static final int CMAP_TABLE = 0x636d6170; + public static final int GLYF_TABLE = 0x676c7966; + public static final int HEAD_TABLE = 0x68656164; + public static final int HHEA_TABLE = 0x68686561; + public static final int HMTX_TABLE = 0x686d7478; + public static final int MAXP_TABLE = 0x6d617870; + public static final int NAME_TABLE = 0x6e616d65; + public static final int POST_TABLE = 0x706f7374; + public static final int LOCA_TABLE = 0x6c6f6361; + /** + * This table's tag + */ + private int tag; + /** + * The data in this table, in ByteBuffer form + */ + private ByteBuffer data; + + /** + * Creates a new instance of TrueTypeTable. + * + * This method is protected. Use the getTable() methods + * to get new instances. + * + * @param tag the tag for this table + */ + protected TrueTypeTable(int tag) { + this.tag = tag; + } + + /** + * Get a new instance of an empty table by tag string + * + * @param ttf the font that contains this table + * @param tagString the tag for this table, as a 4 character string + * (e.g. head or cmap) + */ + public static TrueTypeTable createTable(TrueTypeFont ttf, + String tagString) { + return createTable(ttf, tagString, null); + } + + /** + * Get a new instance of a table with provided data + * + * @param ttf the font that contains this table + * @param tagString the tag for this table, as a 4 character string + * (e.g. head or cmap) + * @param data the table data + */ + public static TrueTypeTable createTable(TrueTypeFont ttf, + String tagString, ByteBuffer data) { + TrueTypeTable outTable = null; + + int tag = stringToTag(tagString); + + switch (tag) { + case CMAP_TABLE: // cmap table + outTable = new CmapTable(); + break; + case GLYF_TABLE: + outTable = new GlyfTable(ttf); + break; + case HEAD_TABLE: // head table + outTable = new HeadTable(); + break; + case HHEA_TABLE: // hhea table + outTable = new HheaTable(); + break; + case HMTX_TABLE: + outTable = new HmtxTable(ttf); + break; + case LOCA_TABLE: + outTable = new LocaTable(ttf); + break; + case MAXP_TABLE: // maxp table + outTable = new MaxpTable(); + break; + case NAME_TABLE: // name table + outTable = new NameTable(); + break; + case POST_TABLE: // post table + outTable = new PostTable(); + break; + default: + outTable = new TrueTypeTable(tag); + break; + } + + if (data != null) { + outTable.setData(data); + } + + return outTable; + } + + /** + * Get the table's tag + */ + public int getTag() { + return this.tag; + } + + /** + * Get the data in the table + */ + public ByteBuffer getData() { + return this.data; + } + + /** + * Set the data in the table + */ + public void setData(ByteBuffer data) { + this.data = data; + } + + /** + * Get the size of the table, in bytes + */ + public int getLength() { + return getData().remaining(); + } + + /** + * Get the tag as a string + */ + public static String tagToString(int tag) { + char[] c = new char[4]; + c[0] = (char) (0xff & (tag >> 24)); + c[1] = (char) (0xff & (tag >> 16)); + c[2] = (char) (0xff & (tag >> 8)); + c[3] = (char) (0xff & (tag)); + + return new String(c); + } + + /** + * Turn a string into a tag + */ + public static int stringToTag(String tag) { + char[] c = tag.toCharArray(); + + if (c.length != 4) { + throw new IllegalArgumentException("Bad tag length: " + tag); + } + + return c[0] << 24 | c[1] << 16 | c[2] << 8 | c[3]; + } + + /** + * Put into a nice string + */ + @Override + public String toString() { + String out = " " + tagToString(getTag()) + " Table. Data is: "; + if (getData() == null) { + out += "not set"; + } else { + out += "set"; + } + return out; + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/resource/glyphlist.txt b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/resource/glyphlist.txt new file mode 100644 index 000000000..b9d451a87 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/resource/glyphlist.txt @@ -0,0 +1,4323 @@ +# ################################################################################### +# Copyright (c) 1997,1998,2002,2007 Adobe Systems Incorporated +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this documentation file to use, copy, publish, distribute, +# sublicense, and/or sell copies of the documentation, and to permit +# others to do the same, provided that: +# - No modification, editing or other alteration of this document is +# allowed; and +# - The above copyright notice and this permission notice shall be +# included in all copies of the documentation. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this documentation file, to create their own derivative works +# from the content of this document to use, copy, publish, distribute, +# sublicense, and/or sell the derivative works, and to permit others to do +# the same, provided that the derived work is not represented as being a +# copy or version of this document. +# +# Adobe shall not be liable to any party for any loss of revenue or profit +# or for indirect, incidental, special, consequential, or other similar +# damages, whether based on tort (including without limitation negligence +# or strict liability), contract or other legal or equitable grounds even +# if Adobe has been advised or had reason to know of the possibility of +# such damages.Ê The Adobe materials are provided on an "AS IS" basis.Ê +# Adobe specifically disclaims all express, statutory, or implied +# warranties relating to the Adobe materials, including but not limited to +# those concerning merchantability or fitness for a particular purpose or +# non-infringement of any third party rights regarding the Adobe +# materials. +# ################################################################################### +# Name: Adobe Glyph List +# Table version: 2.0 +# Date: September 20, 2002 +# +# See http://partners.adobe.com/asn/developer/typeforum/unicodegn.html +# +# Format: Semicolon-delimited fields: +# (1) glyph name +# (2) Unicode scalar value +A;0041 +AE;00C6 +AEacute;01FC +AEmacron;01E2 +AEsmall;F7E6 +Aacute;00C1 +Aacutesmall;F7E1 +Abreve;0102 +Abreveacute;1EAE +Abrevecyrillic;04D0 +Abrevedotbelow;1EB6 +Abrevegrave;1EB0 +Abrevehookabove;1EB2 +Abrevetilde;1EB4 +Acaron;01CD +Acircle;24B6 +Acircumflex;00C2 +Acircumflexacute;1EA4 +Acircumflexdotbelow;1EAC +Acircumflexgrave;1EA6 +Acircumflexhookabove;1EA8 +Acircumflexsmall;F7E2 +Acircumflextilde;1EAA +Acute;F6C9 +Acutesmall;F7B4 +Acyrillic;0410 +Adblgrave;0200 +Adieresis;00C4 +Adieresiscyrillic;04D2 +Adieresismacron;01DE +Adieresissmall;F7E4 +Adotbelow;1EA0 +Adotmacron;01E0 +Agrave;00C0 +Agravesmall;F7E0 +Ahookabove;1EA2 +Aiecyrillic;04D4 +Ainvertedbreve;0202 +Alpha;0391 +Alphatonos;0386 +Amacron;0100 +Amonospace;FF21 +Aogonek;0104 +Aring;00C5 +Aringacute;01FA +Aringbelow;1E00 +Aringsmall;F7E5 +Asmall;F761 +Atilde;00C3 +Atildesmall;F7E3 +Aybarmenian;0531 +B;0042 +Bcircle;24B7 +Bdotaccent;1E02 +Bdotbelow;1E04 +Becyrillic;0411 +Benarmenian;0532 +Beta;0392 +Bhook;0181 +Blinebelow;1E06 +Bmonospace;FF22 +Brevesmall;F6F4 +Bsmall;F762 +Btopbar;0182 +C;0043 +Caarmenian;053E +Cacute;0106 +Caron;F6CA +Caronsmall;F6F5 +Ccaron;010C +Ccedilla;00C7 +Ccedillaacute;1E08 +Ccedillasmall;F7E7 +Ccircle;24B8 +Ccircumflex;0108 +Cdot;010A +Cdotaccent;010A +Cedillasmall;F7B8 +Chaarmenian;0549 +Cheabkhasiancyrillic;04BC +Checyrillic;0427 +Chedescenderabkhasiancyrillic;04BE +Chedescendercyrillic;04B6 +Chedieresiscyrillic;04F4 +Cheharmenian;0543 +Chekhakassiancyrillic;04CB +Cheverticalstrokecyrillic;04B8 +Chi;03A7 +Chook;0187 +Circumflexsmall;F6F6 +Cmonospace;FF23 +Coarmenian;0551 +Csmall;F763 +D;0044 +DZ;01F1 +DZcaron;01C4 +Daarmenian;0534 +Dafrican;0189 +Dcaron;010E +Dcedilla;1E10 +Dcircle;24B9 +Dcircumflexbelow;1E12 +Dcroat;0110 +Ddotaccent;1E0A +Ddotbelow;1E0C +Decyrillic;0414 +Deicoptic;03EE +Delta;2206 +Deltagreek;0394 +Dhook;018A +Dieresis;F6CB +DieresisAcute;F6CC +DieresisGrave;F6CD +Dieresissmall;F7A8 +Digammagreek;03DC +Djecyrillic;0402 +Dlinebelow;1E0E +Dmonospace;FF24 +Dotaccentsmall;F6F7 +Dslash;0110 +Dsmall;F764 +Dtopbar;018B +Dz;01F2 +Dzcaron;01C5 +Dzeabkhasiancyrillic;04E0 +Dzecyrillic;0405 +Dzhecyrillic;040F +E;0045 +Eacute;00C9 +Eacutesmall;F7E9 +Ebreve;0114 +Ecaron;011A +Ecedillabreve;1E1C +Echarmenian;0535 +Ecircle;24BA +Ecircumflex;00CA +Ecircumflexacute;1EBE +Ecircumflexbelow;1E18 +Ecircumflexdotbelow;1EC6 +Ecircumflexgrave;1EC0 +Ecircumflexhookabove;1EC2 +Ecircumflexsmall;F7EA +Ecircumflextilde;1EC4 +Ecyrillic;0404 +Edblgrave;0204 +Edieresis;00CB +Edieresissmall;F7EB +Edot;0116 +Edotaccent;0116 +Edotbelow;1EB8 +Efcyrillic;0424 +Egrave;00C8 +Egravesmall;F7E8 +Eharmenian;0537 +Ehookabove;1EBA +Eightroman;2167 +Einvertedbreve;0206 +Eiotifiedcyrillic;0464 +Elcyrillic;041B +Elevenroman;216A +Emacron;0112 +Emacronacute;1E16 +Emacrongrave;1E14 +Emcyrillic;041C +Emonospace;FF25 +Encyrillic;041D +Endescendercyrillic;04A2 +Eng;014A +Enghecyrillic;04A4 +Enhookcyrillic;04C7 +Eogonek;0118 +Eopen;0190 +Epsilon;0395 +Epsilontonos;0388 +Ercyrillic;0420 +Ereversed;018E +Ereversedcyrillic;042D +Escyrillic;0421 +Esdescendercyrillic;04AA +Esh;01A9 +Esmall;F765 +Eta;0397 +Etarmenian;0538 +Etatonos;0389 +Eth;00D0 +Ethsmall;F7F0 +Etilde;1EBC +Etildebelow;1E1A +Euro;20AC +Ezh;01B7 +Ezhcaron;01EE +Ezhreversed;01B8 +F;0046 +Fcircle;24BB +Fdotaccent;1E1E +Feharmenian;0556 +Feicoptic;03E4 +Fhook;0191 +Fitacyrillic;0472 +Fiveroman;2164 +Fmonospace;FF26 +Fourroman;2163 +Fsmall;F766 +G;0047 +GBsquare;3387 +Gacute;01F4 +Gamma;0393 +Gammaafrican;0194 +Gangiacoptic;03EA +Gbreve;011E +Gcaron;01E6 +Gcedilla;0122 +Gcircle;24BC +Gcircumflex;011C +Gcommaaccent;0122 +Gdot;0120 +Gdotaccent;0120 +Gecyrillic;0413 +Ghadarmenian;0542 +Ghemiddlehookcyrillic;0494 +Ghestrokecyrillic;0492 +Gheupturncyrillic;0490 +Ghook;0193 +Gimarmenian;0533 +Gjecyrillic;0403 +Gmacron;1E20 +Gmonospace;FF27 +Grave;F6CE +Gravesmall;F760 +Gsmall;F767 +Gsmallhook;029B +Gstroke;01E4 +H;0048 +H18533;25CF +H18543;25AA +H18551;25AB +H22073;25A1 +HPsquare;33CB +Haabkhasiancyrillic;04A8 +Hadescendercyrillic;04B2 +Hardsigncyrillic;042A +Hbar;0126 +Hbrevebelow;1E2A +Hcedilla;1E28 +Hcircle;24BD +Hcircumflex;0124 +Hdieresis;1E26 +Hdotaccent;1E22 +Hdotbelow;1E24 +Hmonospace;FF28 +Hoarmenian;0540 +Horicoptic;03E8 +Hsmall;F768 +Hungarumlaut;F6CF +Hungarumlautsmall;F6F8 +Hzsquare;3390 +I;0049 +IAcyrillic;042F +IJ;0132 +IUcyrillic;042E +Iacute;00CD +Iacutesmall;F7ED +Ibreve;012C +Icaron;01CF +Icircle;24BE +Icircumflex;00CE +Icircumflexsmall;F7EE +Icyrillic;0406 +Idblgrave;0208 +Idieresis;00CF +Idieresisacute;1E2E +Idieresiscyrillic;04E4 +Idieresissmall;F7EF +Idot;0130 +Idotaccent;0130 +Idotbelow;1ECA +Iebrevecyrillic;04D6 +Iecyrillic;0415 +Ifraktur;2111 +Igrave;00CC +Igravesmall;F7EC +Ihookabove;1EC8 +Iicyrillic;0418 +Iinvertedbreve;020A +Iishortcyrillic;0419 +Imacron;012A +Imacroncyrillic;04E2 +Imonospace;FF29 +Iniarmenian;053B +Iocyrillic;0401 +Iogonek;012E +Iota;0399 +Iotaafrican;0196 +Iotadieresis;03AA +Iotatonos;038A +Ismall;F769 +Istroke;0197 +Itilde;0128 +Itildebelow;1E2C +Izhitsacyrillic;0474 +Izhitsadblgravecyrillic;0476 +J;004A +Jaarmenian;0541 +Jcircle;24BF +Jcircumflex;0134 +Jecyrillic;0408 +Jheharmenian;054B +Jmonospace;FF2A +Jsmall;F76A +K;004B +KBsquare;3385 +KKsquare;33CD +Kabashkircyrillic;04A0 +Kacute;1E30 +Kacyrillic;041A +Kadescendercyrillic;049A +Kahookcyrillic;04C3 +Kappa;039A +Kastrokecyrillic;049E +Kaverticalstrokecyrillic;049C +Kcaron;01E8 +Kcedilla;0136 +Kcircle;24C0 +Kcommaaccent;0136 +Kdotbelow;1E32 +Keharmenian;0554 +Kenarmenian;053F +Khacyrillic;0425 +Kheicoptic;03E6 +Khook;0198 +Kjecyrillic;040C +Klinebelow;1E34 +Kmonospace;FF2B +Koppacyrillic;0480 +Koppagreek;03DE +Ksicyrillic;046E +Ksmall;F76B +L;004C +LJ;01C7 +LL;F6BF +Lacute;0139 +Lambda;039B +Lcaron;013D +Lcedilla;013B +Lcircle;24C1 +Lcircumflexbelow;1E3C +Lcommaaccent;013B +Ldot;013F +Ldotaccent;013F +Ldotbelow;1E36 +Ldotbelowmacron;1E38 +Liwnarmenian;053C +Lj;01C8 +Ljecyrillic;0409 +Llinebelow;1E3A +Lmonospace;FF2C +Lslash;0141 +Lslashsmall;F6F9 +Lsmall;F76C +M;004D +MBsquare;3386 +Macron;F6D0 +Macronsmall;F7AF +Macute;1E3E +Mcircle;24C2 +Mdotaccent;1E40 +Mdotbelow;1E42 +Menarmenian;0544 +Mmonospace;FF2D +Msmall;F76D +Mturned;019C +Mu;039C +N;004E +NJ;01CA +Nacute;0143 +Ncaron;0147 +Ncedilla;0145 +Ncircle;24C3 +Ncircumflexbelow;1E4A +Ncommaaccent;0145 +Ndotaccent;1E44 +Ndotbelow;1E46 +Nhookleft;019D +Nineroman;2168 +Nj;01CB +Njecyrillic;040A +Nlinebelow;1E48 +Nmonospace;FF2E +Nowarmenian;0546 +Nsmall;F76E +Ntilde;00D1 +Ntildesmall;F7F1 +Nu;039D +O;004F +OE;0152 +OEsmall;F6FA +Oacute;00D3 +Oacutesmall;F7F3 +Obarredcyrillic;04E8 +Obarreddieresiscyrillic;04EA +Obreve;014E +Ocaron;01D1 +Ocenteredtilde;019F +Ocircle;24C4 +Ocircumflex;00D4 +Ocircumflexacute;1ED0 +Ocircumflexdotbelow;1ED8 +Ocircumflexgrave;1ED2 +Ocircumflexhookabove;1ED4 +Ocircumflexsmall;F7F4 +Ocircumflextilde;1ED6 +Ocyrillic;041E +Odblacute;0150 +Odblgrave;020C +Odieresis;00D6 +Odieresiscyrillic;04E6 +Odieresissmall;F7F6 +Odotbelow;1ECC +Ogoneksmall;F6FB +Ograve;00D2 +Ogravesmall;F7F2 +Oharmenian;0555 +Ohm;2126 +Ohookabove;1ECE +Ohorn;01A0 +Ohornacute;1EDA +Ohorndotbelow;1EE2 +Ohorngrave;1EDC +Ohornhookabove;1EDE +Ohorntilde;1EE0 +Ohungarumlaut;0150 +Oi;01A2 +Oinvertedbreve;020E +Omacron;014C +Omacronacute;1E52 +Omacrongrave;1E50 +Omega;2126 +Omegacyrillic;0460 +Omegagreek;03A9 +Omegaroundcyrillic;047A +Omegatitlocyrillic;047C +Omegatonos;038F +Omicron;039F +Omicrontonos;038C +Omonospace;FF2F +Oneroman;2160 +Oogonek;01EA +Oogonekmacron;01EC +Oopen;0186 +Oslash;00D8 +Oslashacute;01FE +Oslashsmall;F7F8 +Osmall;F76F +Ostrokeacute;01FE +Otcyrillic;047E +Otilde;00D5 +Otildeacute;1E4C +Otildedieresis;1E4E +Otildesmall;F7F5 +P;0050 +Pacute;1E54 +Pcircle;24C5 +Pdotaccent;1E56 +Pecyrillic;041F +Peharmenian;054A +Pemiddlehookcyrillic;04A6 +Phi;03A6 +Phook;01A4 +Pi;03A0 +Piwrarmenian;0553 +Pmonospace;FF30 +Psi;03A8 +Psicyrillic;0470 +Psmall;F770 +Q;0051 +Qcircle;24C6 +Qmonospace;FF31 +Qsmall;F771 +R;0052 +Raarmenian;054C +Racute;0154 +Rcaron;0158 +Rcedilla;0156 +Rcircle;24C7 +Rcommaaccent;0156 +Rdblgrave;0210 +Rdotaccent;1E58 +Rdotbelow;1E5A +Rdotbelowmacron;1E5C +Reharmenian;0550 +Rfraktur;211C +Rho;03A1 +Ringsmall;F6FC +Rinvertedbreve;0212 +Rlinebelow;1E5E +Rmonospace;FF32 +Rsmall;F772 +Rsmallinverted;0281 +Rsmallinvertedsuperior;02B6 +S;0053 +SF010000;250C +SF020000;2514 +SF030000;2510 +SF040000;2518 +SF050000;253C +SF060000;252C +SF070000;2534 +SF080000;251C +SF090000;2524 +SF100000;2500 +SF110000;2502 +SF190000;2561 +SF200000;2562 +SF210000;2556 +SF220000;2555 +SF230000;2563 +SF240000;2551 +SF250000;2557 +SF260000;255D +SF270000;255C +SF280000;255B +SF360000;255E +SF370000;255F +SF380000;255A +SF390000;2554 +SF400000;2569 +SF410000;2566 +SF420000;2560 +SF430000;2550 +SF440000;256C +SF450000;2567 +SF460000;2568 +SF470000;2564 +SF480000;2565 +SF490000;2559 +SF500000;2558 +SF510000;2552 +SF520000;2553 +SF530000;256B +SF540000;256A +Sacute;015A +Sacutedotaccent;1E64 +Sampigreek;03E0 +Scaron;0160 +Scarondotaccent;1E66 +Scaronsmall;F6FD +Scedilla;015E +Schwa;018F +Schwacyrillic;04D8 +Schwadieresiscyrillic;04DA +Scircle;24C8 +Scircumflex;015C +Scommaaccent;0218 +Sdotaccent;1E60 +Sdotbelow;1E62 +Sdotbelowdotaccent;1E68 +Seharmenian;054D +Sevenroman;2166 +Shaarmenian;0547 +Shacyrillic;0428 +Shchacyrillic;0429 +Sheicoptic;03E2 +Shhacyrillic;04BA +Shimacoptic;03EC +Sigma;03A3 +Sixroman;2165 +Smonospace;FF33 +Softsigncyrillic;042C +Ssmall;F773 +Stigmagreek;03DA +T;0054 +Tau;03A4 +Tbar;0166 +Tcaron;0164 +Tcedilla;0162 +Tcircle;24C9 +Tcircumflexbelow;1E70 +Tcommaaccent;0162 +Tdotaccent;1E6A +Tdotbelow;1E6C +Tecyrillic;0422 +Tedescendercyrillic;04AC +Tenroman;2169 +Tetsecyrillic;04B4 +Theta;0398 +Thook;01AC +Thorn;00DE +Thornsmall;F7FE +Threeroman;2162 +Tildesmall;F6FE +Tiwnarmenian;054F +Tlinebelow;1E6E +Tmonospace;FF34 +Toarmenian;0539 +Tonefive;01BC +Tonesix;0184 +Tonetwo;01A7 +Tretroflexhook;01AE +Tsecyrillic;0426 +Tshecyrillic;040B +Tsmall;F774 +Twelveroman;216B +Tworoman;2161 +U;0055 +Uacute;00DA +Uacutesmall;F7FA +Ubreve;016C +Ucaron;01D3 +Ucircle;24CA +Ucircumflex;00DB +Ucircumflexbelow;1E76 +Ucircumflexsmall;F7FB +Ucyrillic;0423 +Udblacute;0170 +Udblgrave;0214 +Udieresis;00DC +Udieresisacute;01D7 +Udieresisbelow;1E72 +Udieresiscaron;01D9 +Udieresiscyrillic;04F0 +Udieresisgrave;01DB +Udieresismacron;01D5 +Udieresissmall;F7FC +Udotbelow;1EE4 +Ugrave;00D9 +Ugravesmall;F7F9 +Uhookabove;1EE6 +Uhorn;01AF +Uhornacute;1EE8 +Uhorndotbelow;1EF0 +Uhorngrave;1EEA +Uhornhookabove;1EEC +Uhorntilde;1EEE +Uhungarumlaut;0170 +Uhungarumlautcyrillic;04F2 +Uinvertedbreve;0216 +Ukcyrillic;0478 +Umacron;016A +Umacroncyrillic;04EE +Umacrondieresis;1E7A +Umonospace;FF35 +Uogonek;0172 +Upsilon;03A5 +Upsilon1;03D2 +Upsilonacutehooksymbolgreek;03D3 +Upsilonafrican;01B1 +Upsilondieresis;03AB +Upsilondieresishooksymbolgreek;03D4 +Upsilonhooksymbol;03D2 +Upsilontonos;038E +Uring;016E +Ushortcyrillic;040E +Usmall;F775 +Ustraightcyrillic;04AE +Ustraightstrokecyrillic;04B0 +Utilde;0168 +Utildeacute;1E78 +Utildebelow;1E74 +V;0056 +Vcircle;24CB +Vdotbelow;1E7E +Vecyrillic;0412 +Vewarmenian;054E +Vhook;01B2 +Vmonospace;FF36 +Voarmenian;0548 +Vsmall;F776 +Vtilde;1E7C +W;0057 +Wacute;1E82 +Wcircle;24CC +Wcircumflex;0174 +Wdieresis;1E84 +Wdotaccent;1E86 +Wdotbelow;1E88 +Wgrave;1E80 +Wmonospace;FF37 +Wsmall;F777 +X;0058 +Xcircle;24CD +Xdieresis;1E8C +Xdotaccent;1E8A +Xeharmenian;053D +Xi;039E +Xmonospace;FF38 +Xsmall;F778 +Y;0059 +Yacute;00DD +Yacutesmall;F7FD +Yatcyrillic;0462 +Ycircle;24CE +Ycircumflex;0176 +Ydieresis;0178 +Ydieresissmall;F7FF +Ydotaccent;1E8E +Ydotbelow;1EF4 +Yericyrillic;042B +Yerudieresiscyrillic;04F8 +Ygrave;1EF2 +Yhook;01B3 +Yhookabove;1EF6 +Yiarmenian;0545 +Yicyrillic;0407 +Yiwnarmenian;0552 +Ymonospace;FF39 +Ysmall;F779 +Ytilde;1EF8 +Yusbigcyrillic;046A +Yusbigiotifiedcyrillic;046C +Yuslittlecyrillic;0466 +Yuslittleiotifiedcyrillic;0468 +Z;005A +Zaarmenian;0536 +Zacute;0179 +Zcaron;017D +Zcaronsmall;F6FF +Zcircle;24CF +Zcircumflex;1E90 +Zdot;017B +Zdotaccent;017B +Zdotbelow;1E92 +Zecyrillic;0417 +Zedescendercyrillic;0498 +Zedieresiscyrillic;04DE +Zeta;0396 +Zhearmenian;053A +Zhebrevecyrillic;04C1 +Zhecyrillic;0416 +Zhedescendercyrillic;0496 +Zhedieresiscyrillic;04DC +Zlinebelow;1E94 +Zmonospace;FF3A +Zsmall;F77A +Zstroke;01B5 +a;0061 +aabengali;0986 +aacute;00E1 +aadeva;0906 +aagujarati;0A86 +aagurmukhi;0A06 +aamatragurmukhi;0A3E +aarusquare;3303 +aavowelsignbengali;09BE +aavowelsigndeva;093E +aavowelsigngujarati;0ABE +abbreviationmarkarmenian;055F +abbreviationsigndeva;0970 +abengali;0985 +abopomofo;311A +abreve;0103 +abreveacute;1EAF +abrevecyrillic;04D1 +abrevedotbelow;1EB7 +abrevegrave;1EB1 +abrevehookabove;1EB3 +abrevetilde;1EB5 +acaron;01CE +acircle;24D0 +acircumflex;00E2 +acircumflexacute;1EA5 +acircumflexdotbelow;1EAD +acircumflexgrave;1EA7 +acircumflexhookabove;1EA9 +acircumflextilde;1EAB +acute;00B4 +acutebelowcmb;0317 +acutecmb;0301 +acutecomb;0301 +acutedeva;0954 +acutelowmod;02CF +acutetonecmb;0341 +acyrillic;0430 +adblgrave;0201 +addakgurmukhi;0A71 +adeva;0905 +adieresis;00E4 +adieresiscyrillic;04D3 +adieresismacron;01DF +adotbelow;1EA1 +adotmacron;01E1 +ae;00E6 +aeacute;01FD +aekorean;3150 +aemacron;01E3 +afii00208;2015 +afii08941;20A4 +afii10017;0410 +afii10018;0411 +afii10019;0412 +afii10020;0413 +afii10021;0414 +afii10022;0415 +afii10023;0401 +afii10024;0416 +afii10025;0417 +afii10026;0418 +afii10027;0419 +afii10028;041A +afii10029;041B +afii10030;041C +afii10031;041D +afii10032;041E +afii10033;041F +afii10034;0420 +afii10035;0421 +afii10036;0422 +afii10037;0423 +afii10038;0424 +afii10039;0425 +afii10040;0426 +afii10041;0427 +afii10042;0428 +afii10043;0429 +afii10044;042A +afii10045;042B +afii10046;042C +afii10047;042D +afii10048;042E +afii10049;042F +afii10050;0490 +afii10051;0402 +afii10052;0403 +afii10053;0404 +afii10054;0405 +afii10055;0406 +afii10056;0407 +afii10057;0408 +afii10058;0409 +afii10059;040A +afii10060;040B +afii10061;040C +afii10062;040E +afii10063;F6C4 +afii10064;F6C5 +afii10065;0430 +afii10066;0431 +afii10067;0432 +afii10068;0433 +afii10069;0434 +afii10070;0435 +afii10071;0451 +afii10072;0436 +afii10073;0437 +afii10074;0438 +afii10075;0439 +afii10076;043A +afii10077;043B +afii10078;043C +afii10079;043D +afii10080;043E +afii10081;043F +afii10082;0440 +afii10083;0441 +afii10084;0442 +afii10085;0443 +afii10086;0444 +afii10087;0445 +afii10088;0446 +afii10089;0447 +afii10090;0448 +afii10091;0449 +afii10092;044A +afii10093;044B +afii10094;044C +afii10095;044D +afii10096;044E +afii10097;044F +afii10098;0491 +afii10099;0452 +afii10100;0453 +afii10101;0454 +afii10102;0455 +afii10103;0456 +afii10104;0457 +afii10105;0458 +afii10106;0459 +afii10107;045A +afii10108;045B +afii10109;045C +afii10110;045E +afii10145;040F +afii10146;0462 +afii10147;0472 +afii10148;0474 +afii10192;F6C6 +afii10193;045F +afii10194;0463 +afii10195;0473 +afii10196;0475 +afii10831;F6C7 +afii10832;F6C8 +afii10846;04D9 +afii299;200E +afii300;200F +afii301;200D +afii57381;066A +afii57388;060C +afii57392;0660 +afii57393;0661 +afii57394;0662 +afii57395;0663 +afii57396;0664 +afii57397;0665 +afii57398;0666 +afii57399;0667 +afii57400;0668 +afii57401;0669 +afii57403;061B +afii57407;061F +afii57409;0621 +afii57410;0622 +afii57411;0623 +afii57412;0624 +afii57413;0625 +afii57414;0626 +afii57415;0627 +afii57416;0628 +afii57417;0629 +afii57418;062A +afii57419;062B +afii57420;062C +afii57421;062D +afii57422;062E +afii57423;062F +afii57424;0630 +afii57425;0631 +afii57426;0632 +afii57427;0633 +afii57428;0634 +afii57429;0635 +afii57430;0636 +afii57431;0637 +afii57432;0638 +afii57433;0639 +afii57434;063A +afii57440;0640 +afii57441;0641 +afii57442;0642 +afii57443;0643 +afii57444;0644 +afii57445;0645 +afii57446;0646 +afii57448;0648 +afii57449;0649 +afii57450;064A +afii57451;064B +afii57452;064C +afii57453;064D +afii57454;064E +afii57455;064F +afii57456;0650 +afii57457;0651 +afii57458;0652 +afii57470;0647 +afii57505;06A4 +afii57506;067E +afii57507;0686 +afii57508;0698 +afii57509;06AF +afii57511;0679 +afii57512;0688 +afii57513;0691 +afii57514;06BA +afii57519;06D2 +afii57534;06D5 +afii57636;20AA +afii57645;05BE +afii57658;05C3 +afii57664;05D0 +afii57665;05D1 +afii57666;05D2 +afii57667;05D3 +afii57668;05D4 +afii57669;05D5 +afii57670;05D6 +afii57671;05D7 +afii57672;05D8 +afii57673;05D9 +afii57674;05DA +afii57675;05DB +afii57676;05DC +afii57677;05DD +afii57678;05DE +afii57679;05DF +afii57680;05E0 +afii57681;05E1 +afii57682;05E2 +afii57683;05E3 +afii57684;05E4 +afii57685;05E5 +afii57686;05E6 +afii57687;05E7 +afii57688;05E8 +afii57689;05E9 +afii57690;05EA +afii57694;FB2A +afii57695;FB2B +afii57700;FB4B +afii57705;FB1F +afii57716;05F0 +afii57717;05F1 +afii57718;05F2 +afii57723;FB35 +afii57793;05B4 +afii57794;05B5 +afii57795;05B6 +afii57796;05BB +afii57797;05B8 +afii57798;05B7 +afii57799;05B0 +afii57800;05B2 +afii57801;05B1 +afii57802;05B3 +afii57803;05C2 +afii57804;05C1 +afii57806;05B9 +afii57807;05BC +afii57839;05BD +afii57841;05BF +afii57842;05C0 +afii57929;02BC +afii61248;2105 +afii61289;2113 +afii61352;2116 +afii61573;202C +afii61574;202D +afii61575;202E +afii61664;200C +afii63167;066D +afii64937;02BD +agrave;00E0 +agujarati;0A85 +agurmukhi;0A05 +ahiragana;3042 +ahookabove;1EA3 +aibengali;0990 +aibopomofo;311E +aideva;0910 +aiecyrillic;04D5 +aigujarati;0A90 +aigurmukhi;0A10 +aimatragurmukhi;0A48 +ainarabic;0639 +ainfinalarabic;FECA +aininitialarabic;FECB +ainmedialarabic;FECC +ainvertedbreve;0203 +aivowelsignbengali;09C8 +aivowelsigndeva;0948 +aivowelsigngujarati;0AC8 +akatakana;30A2 +akatakanahalfwidth;FF71 +akorean;314F +alef;05D0 +alefarabic;0627 +alefdageshhebrew;FB30 +aleffinalarabic;FE8E +alefhamzaabovearabic;0623 +alefhamzaabovefinalarabic;FE84 +alefhamzabelowarabic;0625 +alefhamzabelowfinalarabic;FE88 +alefhebrew;05D0 +aleflamedhebrew;FB4F +alefmaddaabovearabic;0622 +alefmaddaabovefinalarabic;FE82 +alefmaksuraarabic;0649 +alefmaksurafinalarabic;FEF0 +alefmaksurainitialarabic;FEF3 +alefmaksuramedialarabic;FEF4 +alefpatahhebrew;FB2E +alefqamatshebrew;FB2F +aleph;2135 +allequal;224C +alpha;03B1 +alphatonos;03AC +amacron;0101 +amonospace;FF41 +ampersand;0026 +ampersandmonospace;FF06 +ampersandsmall;F726 +amsquare;33C2 +anbopomofo;3122 +angbopomofo;3124 +angkhankhuthai;0E5A +angle;2220 +anglebracketleft;3008 +anglebracketleftvertical;FE3F +anglebracketright;3009 +anglebracketrightvertical;FE40 +angleleft;2329 +angleright;232A +angstrom;212B +anoteleia;0387 +anudattadeva;0952 +anusvarabengali;0982 +anusvaradeva;0902 +anusvaragujarati;0A82 +aogonek;0105 +apaatosquare;3300 +aparen;249C +apostrophearmenian;055A +apostrophemod;02BC +apple;F8FF +approaches;2250 +approxequal;2248 +approxequalorimage;2252 +approximatelyequal;2245 +araeaekorean;318E +araeakorean;318D +arc;2312 +arighthalfring;1E9A +aring;00E5 +aringacute;01FB +aringbelow;1E01 +arrowboth;2194 +arrowdashdown;21E3 +arrowdashleft;21E0 +arrowdashright;21E2 +arrowdashup;21E1 +arrowdblboth;21D4 +arrowdbldown;21D3 +arrowdblleft;21D0 +arrowdblright;21D2 +arrowdblup;21D1 +arrowdown;2193 +arrowdownleft;2199 +arrowdownright;2198 +arrowdownwhite;21E9 +arrowheaddownmod;02C5 +arrowheadleftmod;02C2 +arrowheadrightmod;02C3 +arrowheadupmod;02C4 +arrowhorizex;F8E7 +arrowleft;2190 +arrowleftdbl;21D0 +arrowleftdblstroke;21CD +arrowleftoverright;21C6 +arrowleftwhite;21E6 +arrowright;2192 +arrowrightdblstroke;21CF +arrowrightheavy;279E +arrowrightoverleft;21C4 +arrowrightwhite;21E8 +arrowtableft;21E4 +arrowtabright;21E5 +arrowup;2191 +arrowupdn;2195 +arrowupdnbse;21A8 +arrowupdownbase;21A8 +arrowupleft;2196 +arrowupleftofdown;21C5 +arrowupright;2197 +arrowupwhite;21E7 +arrowvertex;F8E6 +asciicircum;005E +asciicircummonospace;FF3E +asciitilde;007E +asciitildemonospace;FF5E +ascript;0251 +ascriptturned;0252 +asmallhiragana;3041 +asmallkatakana;30A1 +asmallkatakanahalfwidth;FF67 +asterisk;002A +asteriskaltonearabic;066D +asteriskarabic;066D +asteriskmath;2217 +asteriskmonospace;FF0A +asterisksmall;FE61 +asterism;2042 +asuperior;F6E9 +asymptoticallyequal;2243 +at;0040 +atilde;00E3 +atmonospace;FF20 +atsmall;FE6B +aturned;0250 +aubengali;0994 +aubopomofo;3120 +audeva;0914 +augujarati;0A94 +augurmukhi;0A14 +aulengthmarkbengali;09D7 +aumatragurmukhi;0A4C +auvowelsignbengali;09CC +auvowelsigndeva;094C +auvowelsigngujarati;0ACC +avagrahadeva;093D +aybarmenian;0561 +ayin;05E2 +ayinaltonehebrew;FB20 +ayinhebrew;05E2 +b;0062 +babengali;09AC +backslash;005C +backslashmonospace;FF3C +badeva;092C +bagujarati;0AAC +bagurmukhi;0A2C +bahiragana;3070 +bahtthai;0E3F +bakatakana;30D0 +bar;007C +barmonospace;FF5C +bbopomofo;3105 +bcircle;24D1 +bdotaccent;1E03 +bdotbelow;1E05 +beamedsixteenthnotes;266C +because;2235 +becyrillic;0431 +beharabic;0628 +behfinalarabic;FE90 +behinitialarabic;FE91 +behiragana;3079 +behmedialarabic;FE92 +behmeeminitialarabic;FC9F +behmeemisolatedarabic;FC08 +behnoonfinalarabic;FC6D +bekatakana;30D9 +benarmenian;0562 +bet;05D1 +beta;03B2 +betasymbolgreek;03D0 +betdagesh;FB31 +betdageshhebrew;FB31 +bethebrew;05D1 +betrafehebrew;FB4C +bhabengali;09AD +bhadeva;092D +bhagujarati;0AAD +bhagurmukhi;0A2D +bhook;0253 +bihiragana;3073 +bikatakana;30D3 +bilabialclick;0298 +bindigurmukhi;0A02 +birusquare;3331 +blackcircle;25CF +blackdiamond;25C6 +blackdownpointingtriangle;25BC +blackleftpointingpointer;25C4 +blackleftpointingtriangle;25C0 +blacklenticularbracketleft;3010 +blacklenticularbracketleftvertical;FE3B +blacklenticularbracketright;3011 +blacklenticularbracketrightvertical;FE3C +blacklowerlefttriangle;25E3 +blacklowerrighttriangle;25E2 +blackrectangle;25AC +blackrightpointingpointer;25BA +blackrightpointingtriangle;25B6 +blacksmallsquare;25AA +blacksmilingface;263B +blacksquare;25A0 +blackstar;2605 +blackupperlefttriangle;25E4 +blackupperrighttriangle;25E5 +blackuppointingsmalltriangle;25B4 +blackuppointingtriangle;25B2 +blank;2423 +blinebelow;1E07 +block;2588 +bmonospace;FF42 +bobaimaithai;0E1A +bohiragana;307C +bokatakana;30DC +bparen;249D +bqsquare;33C3 +braceex;F8F4 +braceleft;007B +braceleftbt;F8F3 +braceleftmid;F8F2 +braceleftmonospace;FF5B +braceleftsmall;FE5B +bracelefttp;F8F1 +braceleftvertical;FE37 +braceright;007D +bracerightbt;F8FE +bracerightmid;F8FD +bracerightmonospace;FF5D +bracerightsmall;FE5C +bracerighttp;F8FC +bracerightvertical;FE38 +bracketleft;005B +bracketleftbt;F8F0 +bracketleftex;F8EF +bracketleftmonospace;FF3B +bracketlefttp;F8EE +bracketright;005D +bracketrightbt;F8FB +bracketrightex;F8FA +bracketrightmonospace;FF3D +bracketrighttp;F8F9 +breve;02D8 +brevebelowcmb;032E +brevecmb;0306 +breveinvertedbelowcmb;032F +breveinvertedcmb;0311 +breveinverteddoublecmb;0361 +bridgebelowcmb;032A +bridgeinvertedbelowcmb;033A +brokenbar;00A6 +bstroke;0180 +bsuperior;F6EA +btopbar;0183 +buhiragana;3076 +bukatakana;30D6 +bullet;2022 +bulletinverse;25D8 +bulletoperator;2219 +bullseye;25CE +c;0063 +caarmenian;056E +cabengali;099A +cacute;0107 +cadeva;091A +cagujarati;0A9A +cagurmukhi;0A1A +calsquare;3388 +candrabindubengali;0981 +candrabinducmb;0310 +candrabindudeva;0901 +candrabindugujarati;0A81 +capslock;21EA +careof;2105 +caron;02C7 +caronbelowcmb;032C +caroncmb;030C +carriagereturn;21B5 +cbopomofo;3118 +ccaron;010D +ccedilla;00E7 +ccedillaacute;1E09 +ccircle;24D2 +ccircumflex;0109 +ccurl;0255 +cdot;010B +cdotaccent;010B +cdsquare;33C5 +cedilla;00B8 +cedillacmb;0327 +cent;00A2 +centigrade;2103 +centinferior;F6DF +centmonospace;FFE0 +centoldstyle;F7A2 +centsuperior;F6E0 +chaarmenian;0579 +chabengali;099B +chadeva;091B +chagujarati;0A9B +chagurmukhi;0A1B +chbopomofo;3114 +cheabkhasiancyrillic;04BD +checkmark;2713 +checyrillic;0447 +chedescenderabkhasiancyrillic;04BF +chedescendercyrillic;04B7 +chedieresiscyrillic;04F5 +cheharmenian;0573 +chekhakassiancyrillic;04CC +cheverticalstrokecyrillic;04B9 +chi;03C7 +chieuchacirclekorean;3277 +chieuchaparenkorean;3217 +chieuchcirclekorean;3269 +chieuchkorean;314A +chieuchparenkorean;3209 +chochangthai;0E0A +chochanthai;0E08 +chochingthai;0E09 +chochoethai;0E0C +chook;0188 +cieucacirclekorean;3276 +cieucaparenkorean;3216 +cieuccirclekorean;3268 +cieuckorean;3148 +cieucparenkorean;3208 +cieucuparenkorean;321C +circle;25CB +circlemultiply;2297 +circleot;2299 +circleplus;2295 +circlepostalmark;3036 +circlewithlefthalfblack;25D0 +circlewithrighthalfblack;25D1 +circumflex;02C6 +circumflexbelowcmb;032D +circumflexcmb;0302 +clear;2327 +clickalveolar;01C2 +clickdental;01C0 +clicklateral;01C1 +clickretroflex;01C3 +club;2663 +clubsuitblack;2663 +clubsuitwhite;2667 +cmcubedsquare;33A4 +cmonospace;FF43 +cmsquaredsquare;33A0 +coarmenian;0581 +colon;003A +colonmonetary;20A1 +colonmonospace;FF1A +colonsign;20A1 +colonsmall;FE55 +colontriangularhalfmod;02D1 +colontriangularmod;02D0 +comma;002C +commaabovecmb;0313 +commaaboverightcmb;0315 +commaaccent;F6C3 +commaarabic;060C +commaarmenian;055D +commainferior;F6E1 +commamonospace;FF0C +commareversedabovecmb;0314 +commareversedmod;02BD +commasmall;FE50 +commasuperior;F6E2 +commaturnedabovecmb;0312 +commaturnedmod;02BB +compass;263C +congruent;2245 +contourintegral;222E +control;2303 +controlACK;0006 +controlBEL;0007 +controlBS;0008 +controlCAN;0018 +controlCR;000D +controlDC1;0011 +controlDC2;0012 +controlDC3;0013 +controlDC4;0014 +controlDEL;007F +controlDLE;0010 +controlEM;0019 +controlENQ;0005 +controlEOT;0004 +controlESC;001B +controlETB;0017 +controlETX;0003 +controlFF;000C +controlFS;001C +controlGS;001D +controlHT;0009 +controlLF;000A +controlNAK;0015 +controlRS;001E +controlSI;000F +controlSO;000E +controlSOT;0002 +controlSTX;0001 +controlSUB;001A +controlSYN;0016 +controlUS;001F +controlVT;000B +copyright;00A9 +copyrightsans;F8E9 +copyrightserif;F6D9 +cornerbracketleft;300C +cornerbracketlefthalfwidth;FF62 +cornerbracketleftvertical;FE41 +cornerbracketright;300D +cornerbracketrighthalfwidth;FF63 +cornerbracketrightvertical;FE42 +corporationsquare;337F +cosquare;33C7 +coverkgsquare;33C6 +cparen;249E +cruzeiro;20A2 +cstretched;0297 +curlyand;22CF +curlyor;22CE +currency;00A4 +cyrBreve;F6D1 +cyrFlex;F6D2 +cyrbreve;F6D4 +cyrflex;F6D5 +d;0064 +daarmenian;0564 +dabengali;09A6 +dadarabic;0636 +dadeva;0926 +dadfinalarabic;FEBE +dadinitialarabic;FEBF +dadmedialarabic;FEC0 +dagesh;05BC +dageshhebrew;05BC +dagger;2020 +daggerdbl;2021 +dagujarati;0AA6 +dagurmukhi;0A26 +dahiragana;3060 +dakatakana;30C0 +dalarabic;062F +dalet;05D3 +daletdagesh;FB33 +daletdageshhebrew;FB33 +dalethatafpatah;05D3 05B2 +dalethatafpatahhebrew;05D3 05B2 +dalethatafsegol;05D3 05B1 +dalethatafsegolhebrew;05D3 05B1 +dalethebrew;05D3 +dalethiriq;05D3 05B4 +dalethiriqhebrew;05D3 05B4 +daletholam;05D3 05B9 +daletholamhebrew;05D3 05B9 +daletpatah;05D3 05B7 +daletpatahhebrew;05D3 05B7 +daletqamats;05D3 05B8 +daletqamatshebrew;05D3 05B8 +daletqubuts;05D3 05BB +daletqubutshebrew;05D3 05BB +daletsegol;05D3 05B6 +daletsegolhebrew;05D3 05B6 +daletsheva;05D3 05B0 +daletshevahebrew;05D3 05B0 +dalettsere;05D3 05B5 +dalettserehebrew;05D3 05B5 +dalfinalarabic;FEAA +dammaarabic;064F +dammalowarabic;064F +dammatanaltonearabic;064C +dammatanarabic;064C +danda;0964 +dargahebrew;05A7 +dargalefthebrew;05A7 +dasiapneumatacyrilliccmb;0485 +dblGrave;F6D3 +dblanglebracketleft;300A +dblanglebracketleftvertical;FE3D +dblanglebracketright;300B +dblanglebracketrightvertical;FE3E +dblarchinvertedbelowcmb;032B +dblarrowleft;21D4 +dblarrowright;21D2 +dbldanda;0965 +dblgrave;F6D6 +dblgravecmb;030F +dblintegral;222C +dbllowline;2017 +dbllowlinecmb;0333 +dbloverlinecmb;033F +dblprimemod;02BA +dblverticalbar;2016 +dblverticallineabovecmb;030E +dbopomofo;3109 +dbsquare;33C8 +dcaron;010F +dcedilla;1E11 +dcircle;24D3 +dcircumflexbelow;1E13 +dcroat;0111 +ddabengali;09A1 +ddadeva;0921 +ddagujarati;0AA1 +ddagurmukhi;0A21 +ddalarabic;0688 +ddalfinalarabic;FB89 +dddhadeva;095C +ddhabengali;09A2 +ddhadeva;0922 +ddhagujarati;0AA2 +ddhagurmukhi;0A22 +ddotaccent;1E0B +ddotbelow;1E0D +decimalseparatorarabic;066B +decimalseparatorpersian;066B +decyrillic;0434 +degree;00B0 +dehihebrew;05AD +dehiragana;3067 +deicoptic;03EF +dekatakana;30C7 +deleteleft;232B +deleteright;2326 +delta;03B4 +deltaturned;018D +denominatorminusonenumeratorbengali;09F8 +dezh;02A4 +dhabengali;09A7 +dhadeva;0927 +dhagujarati;0AA7 +dhagurmukhi;0A27 +dhook;0257 +dialytikatonos;0385 +dialytikatonoscmb;0344 +diamond;2666 +diamondsuitwhite;2662 +dieresis;00A8 +dieresisacute;F6D7 +dieresisbelowcmb;0324 +dieresiscmb;0308 +dieresisgrave;F6D8 +dieresistonos;0385 +dihiragana;3062 +dikatakana;30C2 +dittomark;3003 +divide;00F7 +divides;2223 +divisionslash;2215 +djecyrillic;0452 +dkshade;2593 +dlinebelow;1E0F +dlsquare;3397 +dmacron;0111 +dmonospace;FF44 +dnblock;2584 +dochadathai;0E0E +dodekthai;0E14 +dohiragana;3069 +dokatakana;30C9 +dollar;0024 +dollarinferior;F6E3 +dollarmonospace;FF04 +dollaroldstyle;F724 +dollarsmall;FE69 +dollarsuperior;F6E4 +dong;20AB +dorusquare;3326 +dotaccent;02D9 +dotaccentcmb;0307 +dotbelowcmb;0323 +dotbelowcomb;0323 +dotkatakana;30FB +dotlessi;0131 +dotlessj;F6BE +dotlessjstrokehook;0284 +dotmath;22C5 +dottedcircle;25CC +doubleyodpatah;FB1F +doubleyodpatahhebrew;FB1F +downtackbelowcmb;031E +downtackmod;02D5 +dparen;249F +dsuperior;F6EB +dtail;0256 +dtopbar;018C +duhiragana;3065 +dukatakana;30C5 +dz;01F3 +dzaltone;02A3 +dzcaron;01C6 +dzcurl;02A5 +dzeabkhasiancyrillic;04E1 +dzecyrillic;0455 +dzhecyrillic;045F +e;0065 +eacute;00E9 +earth;2641 +ebengali;098F +ebopomofo;311C +ebreve;0115 +ecandradeva;090D +ecandragujarati;0A8D +ecandravowelsigndeva;0945 +ecandravowelsigngujarati;0AC5 +ecaron;011B +ecedillabreve;1E1D +echarmenian;0565 +echyiwnarmenian;0587 +ecircle;24D4 +ecircumflex;00EA +ecircumflexacute;1EBF +ecircumflexbelow;1E19 +ecircumflexdotbelow;1EC7 +ecircumflexgrave;1EC1 +ecircumflexhookabove;1EC3 +ecircumflextilde;1EC5 +ecyrillic;0454 +edblgrave;0205 +edeva;090F +edieresis;00EB +edot;0117 +edotaccent;0117 +edotbelow;1EB9 +eegurmukhi;0A0F +eematragurmukhi;0A47 +efcyrillic;0444 +egrave;00E8 +egujarati;0A8F +eharmenian;0567 +ehbopomofo;311D +ehiragana;3048 +ehookabove;1EBB +eibopomofo;311F +eight;0038 +eightarabic;0668 +eightbengali;09EE +eightcircle;2467 +eightcircleinversesansserif;2791 +eightdeva;096E +eighteencircle;2471 +eighteenparen;2485 +eighteenperiod;2499 +eightgujarati;0AEE +eightgurmukhi;0A6E +eighthackarabic;0668 +eighthangzhou;3028 +eighthnotebeamed;266B +eightideographicparen;3227 +eightinferior;2088 +eightmonospace;FF18 +eightoldstyle;F738 +eightparen;247B +eightperiod;248F +eightpersian;06F8 +eightroman;2177 +eightsuperior;2078 +eightthai;0E58 +einvertedbreve;0207 +eiotifiedcyrillic;0465 +ekatakana;30A8 +ekatakanahalfwidth;FF74 +ekonkargurmukhi;0A74 +ekorean;3154 +elcyrillic;043B +element;2208 +elevencircle;246A +elevenparen;247E +elevenperiod;2492 +elevenroman;217A +ellipsis;2026 +ellipsisvertical;22EE +emacron;0113 +emacronacute;1E17 +emacrongrave;1E15 +emcyrillic;043C +emdash;2014 +emdashvertical;FE31 +emonospace;FF45 +emphasismarkarmenian;055B +emptyset;2205 +enbopomofo;3123 +encyrillic;043D +endash;2013 +endashvertical;FE32 +endescendercyrillic;04A3 +eng;014B +engbopomofo;3125 +enghecyrillic;04A5 +enhookcyrillic;04C8 +enspace;2002 +eogonek;0119 +eokorean;3153 +eopen;025B +eopenclosed;029A +eopenreversed;025C +eopenreversedclosed;025E +eopenreversedhook;025D +eparen;24A0 +epsilon;03B5 +epsilontonos;03AD +equal;003D +equalmonospace;FF1D +equalsmall;FE66 +equalsuperior;207C +equivalence;2261 +erbopomofo;3126 +ercyrillic;0440 +ereversed;0258 +ereversedcyrillic;044D +escyrillic;0441 +esdescendercyrillic;04AB +esh;0283 +eshcurl;0286 +eshortdeva;090E +eshortvowelsigndeva;0946 +eshreversedloop;01AA +eshsquatreversed;0285 +esmallhiragana;3047 +esmallkatakana;30A7 +esmallkatakanahalfwidth;FF6A +estimated;212E +esuperior;F6EC +eta;03B7 +etarmenian;0568 +etatonos;03AE +eth;00F0 +etilde;1EBD +etildebelow;1E1B +etnahtafoukhhebrew;0591 +etnahtafoukhlefthebrew;0591 +etnahtahebrew;0591 +etnahtalefthebrew;0591 +eturned;01DD +eukorean;3161 +euro;20AC +evowelsignbengali;09C7 +evowelsigndeva;0947 +evowelsigngujarati;0AC7 +exclam;0021 +exclamarmenian;055C +exclamdbl;203C +exclamdown;00A1 +exclamdownsmall;F7A1 +exclammonospace;FF01 +exclamsmall;F721 +existential;2203 +ezh;0292 +ezhcaron;01EF +ezhcurl;0293 +ezhreversed;01B9 +ezhtail;01BA +f;0066 +fadeva;095E +fagurmukhi;0A5E +fahrenheit;2109 +fathaarabic;064E +fathalowarabic;064E +fathatanarabic;064B +fbopomofo;3108 +fcircle;24D5 +fdotaccent;1E1F +feharabic;0641 +feharmenian;0586 +fehfinalarabic;FED2 +fehinitialarabic;FED3 +fehmedialarabic;FED4 +feicoptic;03E5 +female;2640 +ff;FB00 +ffi;FB03 +ffl;FB04 +fi;FB01 +fifteencircle;246E +fifteenparen;2482 +fifteenperiod;2496 +figuredash;2012 +filledbox;25A0 +filledrect;25AC +finalkaf;05DA +finalkafdagesh;FB3A +finalkafdageshhebrew;FB3A +finalkafhebrew;05DA +finalkafqamats;05DA 05B8 +finalkafqamatshebrew;05DA 05B8 +finalkafsheva;05DA 05B0 +finalkafshevahebrew;05DA 05B0 +finalmem;05DD +finalmemhebrew;05DD +finalnun;05DF +finalnunhebrew;05DF +finalpe;05E3 +finalpehebrew;05E3 +finaltsadi;05E5 +finaltsadihebrew;05E5 +firsttonechinese;02C9 +fisheye;25C9 +fitacyrillic;0473 +five;0035 +fivearabic;0665 +fivebengali;09EB +fivecircle;2464 +fivecircleinversesansserif;278E +fivedeva;096B +fiveeighths;215D +fivegujarati;0AEB +fivegurmukhi;0A6B +fivehackarabic;0665 +fivehangzhou;3025 +fiveideographicparen;3224 +fiveinferior;2085 +fivemonospace;FF15 +fiveoldstyle;F735 +fiveparen;2478 +fiveperiod;248C +fivepersian;06F5 +fiveroman;2174 +fivesuperior;2075 +fivethai;0E55 +fl;FB02 +florin;0192 +fmonospace;FF46 +fmsquare;3399 +fofanthai;0E1F +fofathai;0E1D +fongmanthai;0E4F +forall;2200 +four;0034 +fourarabic;0664 +fourbengali;09EA +fourcircle;2463 +fourcircleinversesansserif;278D +fourdeva;096A +fourgujarati;0AEA +fourgurmukhi;0A6A +fourhackarabic;0664 +fourhangzhou;3024 +fourideographicparen;3223 +fourinferior;2084 +fourmonospace;FF14 +fournumeratorbengali;09F7 +fouroldstyle;F734 +fourparen;2477 +fourperiod;248B +fourpersian;06F4 +fourroman;2173 +foursuperior;2074 +fourteencircle;246D +fourteenparen;2481 +fourteenperiod;2495 +fourthai;0E54 +fourthtonechinese;02CB +fparen;24A1 +fraction;2044 +franc;20A3 +g;0067 +gabengali;0997 +gacute;01F5 +gadeva;0917 +gafarabic;06AF +gaffinalarabic;FB93 +gafinitialarabic;FB94 +gafmedialarabic;FB95 +gagujarati;0A97 +gagurmukhi;0A17 +gahiragana;304C +gakatakana;30AC +gamma;03B3 +gammalatinsmall;0263 +gammasuperior;02E0 +gangiacoptic;03EB +gbopomofo;310D +gbreve;011F +gcaron;01E7 +gcedilla;0123 +gcircle;24D6 +gcircumflex;011D +gcommaaccent;0123 +gdot;0121 +gdotaccent;0121 +gecyrillic;0433 +gehiragana;3052 +gekatakana;30B2 +geometricallyequal;2251 +gereshaccenthebrew;059C +gereshhebrew;05F3 +gereshmuqdamhebrew;059D +germandbls;00DF +gershayimaccenthebrew;059E +gershayimhebrew;05F4 +getamark;3013 +ghabengali;0998 +ghadarmenian;0572 +ghadeva;0918 +ghagujarati;0A98 +ghagurmukhi;0A18 +ghainarabic;063A +ghainfinalarabic;FECE +ghaininitialarabic;FECF +ghainmedialarabic;FED0 +ghemiddlehookcyrillic;0495 +ghestrokecyrillic;0493 +gheupturncyrillic;0491 +ghhadeva;095A +ghhagurmukhi;0A5A +ghook;0260 +ghzsquare;3393 +gihiragana;304E +gikatakana;30AE +gimarmenian;0563 +gimel;05D2 +gimeldagesh;FB32 +gimeldageshhebrew;FB32 +gimelhebrew;05D2 +gjecyrillic;0453 +glottalinvertedstroke;01BE +glottalstop;0294 +glottalstopinverted;0296 +glottalstopmod;02C0 +glottalstopreversed;0295 +glottalstopreversedmod;02C1 +glottalstopreversedsuperior;02E4 +glottalstopstroke;02A1 +glottalstopstrokereversed;02A2 +gmacron;1E21 +gmonospace;FF47 +gohiragana;3054 +gokatakana;30B4 +gparen;24A2 +gpasquare;33AC +gradient;2207 +grave;0060 +gravebelowcmb;0316 +gravecmb;0300 +gravecomb;0300 +gravedeva;0953 +gravelowmod;02CE +gravemonospace;FF40 +gravetonecmb;0340 +greater;003E +greaterequal;2265 +greaterequalorless;22DB +greatermonospace;FF1E +greaterorequivalent;2273 +greaterorless;2277 +greateroverequal;2267 +greatersmall;FE65 +gscript;0261 +gstroke;01E5 +guhiragana;3050 +guillemotleft;00AB +guillemotright;00BB +guilsinglleft;2039 +guilsinglright;203A +gukatakana;30B0 +guramusquare;3318 +gysquare;33C9 +h;0068 +haabkhasiancyrillic;04A9 +haaltonearabic;06C1 +habengali;09B9 +hadescendercyrillic;04B3 +hadeva;0939 +hagujarati;0AB9 +hagurmukhi;0A39 +haharabic;062D +hahfinalarabic;FEA2 +hahinitialarabic;FEA3 +hahiragana;306F +hahmedialarabic;FEA4 +haitusquare;332A +hakatakana;30CF +hakatakanahalfwidth;FF8A +halantgurmukhi;0A4D +hamzaarabic;0621 +hamzadammaarabic;0621 064F +hamzadammatanarabic;0621 064C +hamzafathaarabic;0621 064E +hamzafathatanarabic;0621 064B +hamzalowarabic;0621 +hamzalowkasraarabic;0621 0650 +hamzalowkasratanarabic;0621 064D +hamzasukunarabic;0621 0652 +hangulfiller;3164 +hardsigncyrillic;044A +harpoonleftbarbup;21BC +harpoonrightbarbup;21C0 +hasquare;33CA +hatafpatah;05B2 +hatafpatah16;05B2 +hatafpatah23;05B2 +hatafpatah2f;05B2 +hatafpatahhebrew;05B2 +hatafpatahnarrowhebrew;05B2 +hatafpatahquarterhebrew;05B2 +hatafpatahwidehebrew;05B2 +hatafqamats;05B3 +hatafqamats1b;05B3 +hatafqamats28;05B3 +hatafqamats34;05B3 +hatafqamatshebrew;05B3 +hatafqamatsnarrowhebrew;05B3 +hatafqamatsquarterhebrew;05B3 +hatafqamatswidehebrew;05B3 +hatafsegol;05B1 +hatafsegol17;05B1 +hatafsegol24;05B1 +hatafsegol30;05B1 +hatafsegolhebrew;05B1 +hatafsegolnarrowhebrew;05B1 +hatafsegolquarterhebrew;05B1 +hatafsegolwidehebrew;05B1 +hbar;0127 +hbopomofo;310F +hbrevebelow;1E2B +hcedilla;1E29 +hcircle;24D7 +hcircumflex;0125 +hdieresis;1E27 +hdotaccent;1E23 +hdotbelow;1E25 +he;05D4 +heart;2665 +heartsuitblack;2665 +heartsuitwhite;2661 +hedagesh;FB34 +hedageshhebrew;FB34 +hehaltonearabic;06C1 +heharabic;0647 +hehebrew;05D4 +hehfinalaltonearabic;FBA7 +hehfinalalttwoarabic;FEEA +hehfinalarabic;FEEA +hehhamzaabovefinalarabic;FBA5 +hehhamzaaboveisolatedarabic;FBA4 +hehinitialaltonearabic;FBA8 +hehinitialarabic;FEEB +hehiragana;3078 +hehmedialaltonearabic;FBA9 +hehmedialarabic;FEEC +heiseierasquare;337B +hekatakana;30D8 +hekatakanahalfwidth;FF8D +hekutaarusquare;3336 +henghook;0267 +herutusquare;3339 +het;05D7 +hethebrew;05D7 +hhook;0266 +hhooksuperior;02B1 +hieuhacirclekorean;327B +hieuhaparenkorean;321B +hieuhcirclekorean;326D +hieuhkorean;314E +hieuhparenkorean;320D +hihiragana;3072 +hikatakana;30D2 +hikatakanahalfwidth;FF8B +hiriq;05B4 +hiriq14;05B4 +hiriq21;05B4 +hiriq2d;05B4 +hiriqhebrew;05B4 +hiriqnarrowhebrew;05B4 +hiriqquarterhebrew;05B4 +hiriqwidehebrew;05B4 +hlinebelow;1E96 +hmonospace;FF48 +hoarmenian;0570 +hohipthai;0E2B +hohiragana;307B +hokatakana;30DB +hokatakanahalfwidth;FF8E +holam;05B9 +holam19;05B9 +holam26;05B9 +holam32;05B9 +holamhebrew;05B9 +holamnarrowhebrew;05B9 +holamquarterhebrew;05B9 +holamwidehebrew;05B9 +honokhukthai;0E2E +hookabovecomb;0309 +hookcmb;0309 +hookpalatalizedbelowcmb;0321 +hookretroflexbelowcmb;0322 +hoonsquare;3342 +horicoptic;03E9 +horizontalbar;2015 +horncmb;031B +hotsprings;2668 +house;2302 +hparen;24A3 +hsuperior;02B0 +hturned;0265 +huhiragana;3075 +huiitosquare;3333 +hukatakana;30D5 +hukatakanahalfwidth;FF8C +hungarumlaut;02DD +hungarumlautcmb;030B +hv;0195 +hyphen;002D +hypheninferior;F6E5 +hyphenmonospace;FF0D +hyphensmall;FE63 +hyphensuperior;F6E6 +hyphentwo;2010 +i;0069 +iacute;00ED +iacyrillic;044F +ibengali;0987 +ibopomofo;3127 +ibreve;012D +icaron;01D0 +icircle;24D8 +icircumflex;00EE +icyrillic;0456 +idblgrave;0209 +ideographearthcircle;328F +ideographfirecircle;328B +ideographicallianceparen;323F +ideographiccallparen;323A +ideographiccentrecircle;32A5 +ideographicclose;3006 +ideographiccomma;3001 +ideographiccommaleft;FF64 +ideographiccongratulationparen;3237 +ideographiccorrectcircle;32A3 +ideographicearthparen;322F +ideographicenterpriseparen;323D +ideographicexcellentcircle;329D +ideographicfestivalparen;3240 +ideographicfinancialcircle;3296 +ideographicfinancialparen;3236 +ideographicfireparen;322B +ideographichaveparen;3232 +ideographichighcircle;32A4 +ideographiciterationmark;3005 +ideographiclaborcircle;3298 +ideographiclaborparen;3238 +ideographicleftcircle;32A7 +ideographiclowcircle;32A6 +ideographicmedicinecircle;32A9 +ideographicmetalparen;322E +ideographicmoonparen;322A +ideographicnameparen;3234 +ideographicperiod;3002 +ideographicprintcircle;329E +ideographicreachparen;3243 +ideographicrepresentparen;3239 +ideographicresourceparen;323E +ideographicrightcircle;32A8 +ideographicsecretcircle;3299 +ideographicselfparen;3242 +ideographicsocietyparen;3233 +ideographicspace;3000 +ideographicspecialparen;3235 +ideographicstockparen;3231 +ideographicstudyparen;323B +ideographicsunparen;3230 +ideographicsuperviseparen;323C +ideographicwaterparen;322C +ideographicwoodparen;322D +ideographiczero;3007 +ideographmetalcircle;328E +ideographmooncircle;328A +ideographnamecircle;3294 +ideographsuncircle;3290 +ideographwatercircle;328C +ideographwoodcircle;328D +ideva;0907 +idieresis;00EF +idieresisacute;1E2F +idieresiscyrillic;04E5 +idotbelow;1ECB +iebrevecyrillic;04D7 +iecyrillic;0435 +ieungacirclekorean;3275 +ieungaparenkorean;3215 +ieungcirclekorean;3267 +ieungkorean;3147 +ieungparenkorean;3207 +igrave;00EC +igujarati;0A87 +igurmukhi;0A07 +ihiragana;3044 +ihookabove;1EC9 +iibengali;0988 +iicyrillic;0438 +iideva;0908 +iigujarati;0A88 +iigurmukhi;0A08 +iimatragurmukhi;0A40 +iinvertedbreve;020B +iishortcyrillic;0439 +iivowelsignbengali;09C0 +iivowelsigndeva;0940 +iivowelsigngujarati;0AC0 +ij;0133 +ikatakana;30A4 +ikatakanahalfwidth;FF72 +ikorean;3163 +ilde;02DC +iluyhebrew;05AC +imacron;012B +imacroncyrillic;04E3 +imageorapproximatelyequal;2253 +imatragurmukhi;0A3F +imonospace;FF49 +increment;2206 +infinity;221E +iniarmenian;056B +integral;222B +integralbottom;2321 +integralbt;2321 +integralex;F8F5 +integraltop;2320 +integraltp;2320 +intersection;2229 +intisquare;3305 +invbullet;25D8 +invcircle;25D9 +invsmileface;263B +iocyrillic;0451 +iogonek;012F +iota;03B9 +iotadieresis;03CA +iotadieresistonos;0390 +iotalatin;0269 +iotatonos;03AF +iparen;24A4 +irigurmukhi;0A72 +ismallhiragana;3043 +ismallkatakana;30A3 +ismallkatakanahalfwidth;FF68 +issharbengali;09FA +istroke;0268 +isuperior;F6ED +iterationhiragana;309D +iterationkatakana;30FD +itilde;0129 +itildebelow;1E2D +iubopomofo;3129 +iucyrillic;044E +ivowelsignbengali;09BF +ivowelsigndeva;093F +ivowelsigngujarati;0ABF +izhitsacyrillic;0475 +izhitsadblgravecyrillic;0477 +j;006A +jaarmenian;0571 +jabengali;099C +jadeva;091C +jagujarati;0A9C +jagurmukhi;0A1C +jbopomofo;3110 +jcaron;01F0 +jcircle;24D9 +jcircumflex;0135 +jcrossedtail;029D +jdotlessstroke;025F +jecyrillic;0458 +jeemarabic;062C +jeemfinalarabic;FE9E +jeeminitialarabic;FE9F +jeemmedialarabic;FEA0 +jeharabic;0698 +jehfinalarabic;FB8B +jhabengali;099D +jhadeva;091D +jhagujarati;0A9D +jhagurmukhi;0A1D +jheharmenian;057B +jis;3004 +jmonospace;FF4A +jparen;24A5 +jsuperior;02B2 +k;006B +kabashkircyrillic;04A1 +kabengali;0995 +kacute;1E31 +kacyrillic;043A +kadescendercyrillic;049B +kadeva;0915 +kaf;05DB +kafarabic;0643 +kafdagesh;FB3B +kafdageshhebrew;FB3B +kaffinalarabic;FEDA +kafhebrew;05DB +kafinitialarabic;FEDB +kafmedialarabic;FEDC +kafrafehebrew;FB4D +kagujarati;0A95 +kagurmukhi;0A15 +kahiragana;304B +kahookcyrillic;04C4 +kakatakana;30AB +kakatakanahalfwidth;FF76 +kappa;03BA +kappasymbolgreek;03F0 +kapyeounmieumkorean;3171 +kapyeounphieuphkorean;3184 +kapyeounpieupkorean;3178 +kapyeounssangpieupkorean;3179 +karoriisquare;330D +kashidaautoarabic;0640 +kashidaautonosidebearingarabic;0640 +kasmallkatakana;30F5 +kasquare;3384 +kasraarabic;0650 +kasratanarabic;064D +kastrokecyrillic;049F +katahiraprolongmarkhalfwidth;FF70 +kaverticalstrokecyrillic;049D +kbopomofo;310E +kcalsquare;3389 +kcaron;01E9 +kcedilla;0137 +kcircle;24DA +kcommaaccent;0137 +kdotbelow;1E33 +keharmenian;0584 +kehiragana;3051 +kekatakana;30B1 +kekatakanahalfwidth;FF79 +kenarmenian;056F +kesmallkatakana;30F6 +kgreenlandic;0138 +khabengali;0996 +khacyrillic;0445 +khadeva;0916 +khagujarati;0A96 +khagurmukhi;0A16 +khaharabic;062E +khahfinalarabic;FEA6 +khahinitialarabic;FEA7 +khahmedialarabic;FEA8 +kheicoptic;03E7 +khhadeva;0959 +khhagurmukhi;0A59 +khieukhacirclekorean;3278 +khieukhaparenkorean;3218 +khieukhcirclekorean;326A +khieukhkorean;314B +khieukhparenkorean;320A +khokhaithai;0E02 +khokhonthai;0E05 +khokhuatthai;0E03 +khokhwaithai;0E04 +khomutthai;0E5B +khook;0199 +khorakhangthai;0E06 +khzsquare;3391 +kihiragana;304D +kikatakana;30AD +kikatakanahalfwidth;FF77 +kiroguramusquare;3315 +kiromeetorusquare;3316 +kirosquare;3314 +kiyeokacirclekorean;326E +kiyeokaparenkorean;320E +kiyeokcirclekorean;3260 +kiyeokkorean;3131 +kiyeokparenkorean;3200 +kiyeoksioskorean;3133 +kjecyrillic;045C +klinebelow;1E35 +klsquare;3398 +kmcubedsquare;33A6 +kmonospace;FF4B +kmsquaredsquare;33A2 +kohiragana;3053 +kohmsquare;33C0 +kokaithai;0E01 +kokatakana;30B3 +kokatakanahalfwidth;FF7A +kooposquare;331E +koppacyrillic;0481 +koreanstandardsymbol;327F +koroniscmb;0343 +kparen;24A6 +kpasquare;33AA +ksicyrillic;046F +ktsquare;33CF +kturned;029E +kuhiragana;304F +kukatakana;30AF +kukatakanahalfwidth;FF78 +kvsquare;33B8 +kwsquare;33BE +l;006C +labengali;09B2 +lacute;013A +ladeva;0932 +lagujarati;0AB2 +lagurmukhi;0A32 +lakkhangyaothai;0E45 +lamaleffinalarabic;FEFC +lamalefhamzaabovefinalarabic;FEF8 +lamalefhamzaaboveisolatedarabic;FEF7 +lamalefhamzabelowfinalarabic;FEFA +lamalefhamzabelowisolatedarabic;FEF9 +lamalefisolatedarabic;FEFB +lamalefmaddaabovefinalarabic;FEF6 +lamalefmaddaaboveisolatedarabic;FEF5 +lamarabic;0644 +lambda;03BB +lambdastroke;019B +lamed;05DC +lameddagesh;FB3C +lameddageshhebrew;FB3C +lamedhebrew;05DC +lamedholam;05DC 05B9 +lamedholamdagesh;05DC 05B9 05BC +lamedholamdageshhebrew;05DC 05B9 05BC +lamedholamhebrew;05DC 05B9 +lamfinalarabic;FEDE +lamhahinitialarabic;FCCA +laminitialarabic;FEDF +lamjeeminitialarabic;FCC9 +lamkhahinitialarabic;FCCB +lamlamhehisolatedarabic;FDF2 +lammedialarabic;FEE0 +lammeemhahinitialarabic;FD88 +lammeeminitialarabic;FCCC +lammeemjeeminitialarabic;FEDF FEE4 FEA0 +lammeemkhahinitialarabic;FEDF FEE4 FEA8 +largecircle;25EF +lbar;019A +lbelt;026C +lbopomofo;310C +lcaron;013E +lcedilla;013C +lcircle;24DB +lcircumflexbelow;1E3D +lcommaaccent;013C +ldot;0140 +ldotaccent;0140 +ldotbelow;1E37 +ldotbelowmacron;1E39 +leftangleabovecmb;031A +lefttackbelowcmb;0318 +less;003C +lessequal;2264 +lessequalorgreater;22DA +lessmonospace;FF1C +lessorequivalent;2272 +lessorgreater;2276 +lessoverequal;2266 +lesssmall;FE64 +lezh;026E +lfblock;258C +lhookretroflex;026D +lira;20A4 +liwnarmenian;056C +lj;01C9 +ljecyrillic;0459 +ll;F6C0 +lladeva;0933 +llagujarati;0AB3 +llinebelow;1E3B +llladeva;0934 +llvocalicbengali;09E1 +llvocalicdeva;0961 +llvocalicvowelsignbengali;09E3 +llvocalicvowelsigndeva;0963 +lmiddletilde;026B +lmonospace;FF4C +lmsquare;33D0 +lochulathai;0E2C +logicaland;2227 +logicalnot;00AC +logicalnotreversed;2310 +logicalor;2228 +lolingthai;0E25 +longs;017F +lowlinecenterline;FE4E +lowlinecmb;0332 +lowlinedashed;FE4D +lozenge;25CA +lparen;24A7 +lslash;0142 +lsquare;2113 +lsuperior;F6EE +ltshade;2591 +luthai;0E26 +lvocalicbengali;098C +lvocalicdeva;090C +lvocalicvowelsignbengali;09E2 +lvocalicvowelsigndeva;0962 +lxsquare;33D3 +m;006D +mabengali;09AE +macron;00AF +macronbelowcmb;0331 +macroncmb;0304 +macronlowmod;02CD +macronmonospace;FFE3 +macute;1E3F +madeva;092E +magujarati;0AAE +magurmukhi;0A2E +mahapakhhebrew;05A4 +mahapakhlefthebrew;05A4 +mahiragana;307E +maichattawalowleftthai;F895 +maichattawalowrightthai;F894 +maichattawathai;0E4B +maichattawaupperleftthai;F893 +maieklowleftthai;F88C +maieklowrightthai;F88B +maiekthai;0E48 +maiekupperleftthai;F88A +maihanakatleftthai;F884 +maihanakatthai;0E31 +maitaikhuleftthai;F889 +maitaikhuthai;0E47 +maitholowleftthai;F88F +maitholowrightthai;F88E +maithothai;0E49 +maithoupperleftthai;F88D +maitrilowleftthai;F892 +maitrilowrightthai;F891 +maitrithai;0E4A +maitriupperleftthai;F890 +maiyamokthai;0E46 +makatakana;30DE +makatakanahalfwidth;FF8F +male;2642 +mansyonsquare;3347 +maqafhebrew;05BE +mars;2642 +masoracirclehebrew;05AF +masquare;3383 +mbopomofo;3107 +mbsquare;33D4 +mcircle;24DC +mcubedsquare;33A5 +mdotaccent;1E41 +mdotbelow;1E43 +meemarabic;0645 +meemfinalarabic;FEE2 +meeminitialarabic;FEE3 +meemmedialarabic;FEE4 +meemmeeminitialarabic;FCD1 +meemmeemisolatedarabic;FC48 +meetorusquare;334D +mehiragana;3081 +meizierasquare;337E +mekatakana;30E1 +mekatakanahalfwidth;FF92 +mem;05DE +memdagesh;FB3E +memdageshhebrew;FB3E +memhebrew;05DE +menarmenian;0574 +merkhahebrew;05A5 +merkhakefulahebrew;05A6 +merkhakefulalefthebrew;05A6 +merkhalefthebrew;05A5 +mhook;0271 +mhzsquare;3392 +middledotkatakanahalfwidth;FF65 +middot;00B7 +mieumacirclekorean;3272 +mieumaparenkorean;3212 +mieumcirclekorean;3264 +mieumkorean;3141 +mieumpansioskorean;3170 +mieumparenkorean;3204 +mieumpieupkorean;316E +mieumsioskorean;316F +mihiragana;307F +mikatakana;30DF +mikatakanahalfwidth;FF90 +minus;2212 +minusbelowcmb;0320 +minuscircle;2296 +minusmod;02D7 +minusplus;2213 +minute;2032 +miribaarusquare;334A +mirisquare;3349 +mlonglegturned;0270 +mlsquare;3396 +mmcubedsquare;33A3 +mmonospace;FF4D +mmsquaredsquare;339F +mohiragana;3082 +mohmsquare;33C1 +mokatakana;30E2 +mokatakanahalfwidth;FF93 +molsquare;33D6 +momathai;0E21 +moverssquare;33A7 +moverssquaredsquare;33A8 +mparen;24A8 +mpasquare;33AB +mssquare;33B3 +msuperior;F6EF +mturned;026F +mu;00B5 +mu1;00B5 +muasquare;3382 +muchgreater;226B +muchless;226A +mufsquare;338C +mugreek;03BC +mugsquare;338D +muhiragana;3080 +mukatakana;30E0 +mukatakanahalfwidth;FF91 +mulsquare;3395 +multiply;00D7 +mumsquare;339B +munahhebrew;05A3 +munahlefthebrew;05A3 +musicalnote;266A +musicalnotedbl;266B +musicflatsign;266D +musicsharpsign;266F +mussquare;33B2 +muvsquare;33B6 +muwsquare;33BC +mvmegasquare;33B9 +mvsquare;33B7 +mwmegasquare;33BF +mwsquare;33BD +n;006E +nabengali;09A8 +nabla;2207 +nacute;0144 +nadeva;0928 +nagujarati;0AA8 +nagurmukhi;0A28 +nahiragana;306A +nakatakana;30CA +nakatakanahalfwidth;FF85 +napostrophe;0149 +nasquare;3381 +nbopomofo;310B +nbspace;00A0 +ncaron;0148 +ncedilla;0146 +ncircle;24DD +ncircumflexbelow;1E4B +ncommaaccent;0146 +ndotaccent;1E45 +ndotbelow;1E47 +nehiragana;306D +nekatakana;30CD +nekatakanahalfwidth;FF88 +newsheqelsign;20AA +nfsquare;338B +ngabengali;0999 +ngadeva;0919 +ngagujarati;0A99 +ngagurmukhi;0A19 +ngonguthai;0E07 +nhiragana;3093 +nhookleft;0272 +nhookretroflex;0273 +nieunacirclekorean;326F +nieunaparenkorean;320F +nieuncieuckorean;3135 +nieuncirclekorean;3261 +nieunhieuhkorean;3136 +nieunkorean;3134 +nieunpansioskorean;3168 +nieunparenkorean;3201 +nieunsioskorean;3167 +nieuntikeutkorean;3166 +nihiragana;306B +nikatakana;30CB +nikatakanahalfwidth;FF86 +nikhahitleftthai;F899 +nikhahitthai;0E4D +nine;0039 +ninearabic;0669 +ninebengali;09EF +ninecircle;2468 +ninecircleinversesansserif;2792 +ninedeva;096F +ninegujarati;0AEF +ninegurmukhi;0A6F +ninehackarabic;0669 +ninehangzhou;3029 +nineideographicparen;3228 +nineinferior;2089 +ninemonospace;FF19 +nineoldstyle;F739 +nineparen;247C +nineperiod;2490 +ninepersian;06F9 +nineroman;2178 +ninesuperior;2079 +nineteencircle;2472 +nineteenparen;2486 +nineteenperiod;249A +ninethai;0E59 +nj;01CC +njecyrillic;045A +nkatakana;30F3 +nkatakanahalfwidth;FF9D +nlegrightlong;019E +nlinebelow;1E49 +nmonospace;FF4E +nmsquare;339A +nnabengali;09A3 +nnadeva;0923 +nnagujarati;0AA3 +nnagurmukhi;0A23 +nnnadeva;0929 +nohiragana;306E +nokatakana;30CE +nokatakanahalfwidth;FF89 +nonbreakingspace;00A0 +nonenthai;0E13 +nonuthai;0E19 +noonarabic;0646 +noonfinalarabic;FEE6 +noonghunnaarabic;06BA +noonghunnafinalarabic;FB9F +noonhehinitialarabic;FEE7 FEEC +nooninitialarabic;FEE7 +noonjeeminitialarabic;FCD2 +noonjeemisolatedarabic;FC4B +noonmedialarabic;FEE8 +noonmeeminitialarabic;FCD5 +noonmeemisolatedarabic;FC4E +noonnoonfinalarabic;FC8D +notcontains;220C +notelement;2209 +notelementof;2209 +notequal;2260 +notgreater;226F +notgreaternorequal;2271 +notgreaternorless;2279 +notidentical;2262 +notless;226E +notlessnorequal;2270 +notparallel;2226 +notprecedes;2280 +notsubset;2284 +notsucceeds;2281 +notsuperset;2285 +nowarmenian;0576 +nparen;24A9 +nssquare;33B1 +nsuperior;207F +ntilde;00F1 +nu;03BD +nuhiragana;306C +nukatakana;30CC +nukatakanahalfwidth;FF87 +nuktabengali;09BC +nuktadeva;093C +nuktagujarati;0ABC +nuktagurmukhi;0A3C +numbersign;0023 +numbersignmonospace;FF03 +numbersignsmall;FE5F +numeralsigngreek;0374 +numeralsignlowergreek;0375 +numero;2116 +nun;05E0 +nundagesh;FB40 +nundageshhebrew;FB40 +nunhebrew;05E0 +nvsquare;33B5 +nwsquare;33BB +nyabengali;099E +nyadeva;091E +nyagujarati;0A9E +nyagurmukhi;0A1E +o;006F +oacute;00F3 +oangthai;0E2D +obarred;0275 +obarredcyrillic;04E9 +obarreddieresiscyrillic;04EB +obengali;0993 +obopomofo;311B +obreve;014F +ocandradeva;0911 +ocandragujarati;0A91 +ocandravowelsigndeva;0949 +ocandravowelsigngujarati;0AC9 +ocaron;01D2 +ocircle;24DE +ocircumflex;00F4 +ocircumflexacute;1ED1 +ocircumflexdotbelow;1ED9 +ocircumflexgrave;1ED3 +ocircumflexhookabove;1ED5 +ocircumflextilde;1ED7 +ocyrillic;043E +odblacute;0151 +odblgrave;020D +odeva;0913 +odieresis;00F6 +odieresiscyrillic;04E7 +odotbelow;1ECD +oe;0153 +oekorean;315A +ogonek;02DB +ogonekcmb;0328 +ograve;00F2 +ogujarati;0A93 +oharmenian;0585 +ohiragana;304A +ohookabove;1ECF +ohorn;01A1 +ohornacute;1EDB +ohorndotbelow;1EE3 +ohorngrave;1EDD +ohornhookabove;1EDF +ohorntilde;1EE1 +ohungarumlaut;0151 +oi;01A3 +oinvertedbreve;020F +okatakana;30AA +okatakanahalfwidth;FF75 +okorean;3157 +olehebrew;05AB +omacron;014D +omacronacute;1E53 +omacrongrave;1E51 +omdeva;0950 +omega;03C9 +omega1;03D6 +omegacyrillic;0461 +omegalatinclosed;0277 +omegaroundcyrillic;047B +omegatitlocyrillic;047D +omegatonos;03CE +omgujarati;0AD0 +omicron;03BF +omicrontonos;03CC +omonospace;FF4F +one;0031 +onearabic;0661 +onebengali;09E7 +onecircle;2460 +onecircleinversesansserif;278A +onedeva;0967 +onedotenleader;2024 +oneeighth;215B +onefitted;F6DC +onegujarati;0AE7 +onegurmukhi;0A67 +onehackarabic;0661 +onehalf;00BD +onehangzhou;3021 +oneideographicparen;3220 +oneinferior;2081 +onemonospace;FF11 +onenumeratorbengali;09F4 +oneoldstyle;F731 +oneparen;2474 +oneperiod;2488 +onepersian;06F1 +onequarter;00BC +oneroman;2170 +onesuperior;00B9 +onethai;0E51 +onethird;2153 +oogonek;01EB +oogonekmacron;01ED +oogurmukhi;0A13 +oomatragurmukhi;0A4B +oopen;0254 +oparen;24AA +openbullet;25E6 +option;2325 +ordfeminine;00AA +ordmasculine;00BA +orthogonal;221F +oshortdeva;0912 +oshortvowelsigndeva;094A +oslash;00F8 +oslashacute;01FF +osmallhiragana;3049 +osmallkatakana;30A9 +osmallkatakanahalfwidth;FF6B +ostrokeacute;01FF +osuperior;F6F0 +otcyrillic;047F +otilde;00F5 +otildeacute;1E4D +otildedieresis;1E4F +oubopomofo;3121 +overline;203E +overlinecenterline;FE4A +overlinecmb;0305 +overlinedashed;FE49 +overlinedblwavy;FE4C +overlinewavy;FE4B +overscore;00AF +ovowelsignbengali;09CB +ovowelsigndeva;094B +ovowelsigngujarati;0ACB +p;0070 +paampssquare;3380 +paasentosquare;332B +pabengali;09AA +pacute;1E55 +padeva;092A +pagedown;21DF +pageup;21DE +pagujarati;0AAA +pagurmukhi;0A2A +pahiragana;3071 +paiyannoithai;0E2F +pakatakana;30D1 +palatalizationcyrilliccmb;0484 +palochkacyrillic;04C0 +pansioskorean;317F +paragraph;00B6 +parallel;2225 +parenleft;0028 +parenleftaltonearabic;FD3E +parenleftbt;F8ED +parenleftex;F8EC +parenleftinferior;208D +parenleftmonospace;FF08 +parenleftsmall;FE59 +parenleftsuperior;207D +parenlefttp;F8EB +parenleftvertical;FE35 +parenright;0029 +parenrightaltonearabic;FD3F +parenrightbt;F8F8 +parenrightex;F8F7 +parenrightinferior;208E +parenrightmonospace;FF09 +parenrightsmall;FE5A +parenrightsuperior;207E +parenrighttp;F8F6 +parenrightvertical;FE36 +partialdiff;2202 +paseqhebrew;05C0 +pashtahebrew;0599 +pasquare;33A9 +patah;05B7 +patah11;05B7 +patah1d;05B7 +patah2a;05B7 +patahhebrew;05B7 +patahnarrowhebrew;05B7 +patahquarterhebrew;05B7 +patahwidehebrew;05B7 +pazerhebrew;05A1 +pbopomofo;3106 +pcircle;24DF +pdotaccent;1E57 +pe;05E4 +pecyrillic;043F +pedagesh;FB44 +pedageshhebrew;FB44 +peezisquare;333B +pefinaldageshhebrew;FB43 +peharabic;067E +peharmenian;057A +pehebrew;05E4 +pehfinalarabic;FB57 +pehinitialarabic;FB58 +pehiragana;307A +pehmedialarabic;FB59 +pekatakana;30DA +pemiddlehookcyrillic;04A7 +perafehebrew;FB4E +percent;0025 +percentarabic;066A +percentmonospace;FF05 +percentsmall;FE6A +period;002E +periodarmenian;0589 +periodcentered;00B7 +periodhalfwidth;FF61 +periodinferior;F6E7 +periodmonospace;FF0E +periodsmall;FE52 +periodsuperior;F6E8 +perispomenigreekcmb;0342 +perpendicular;22A5 +perthousand;2030 +peseta;20A7 +pfsquare;338A +phabengali;09AB +phadeva;092B +phagujarati;0AAB +phagurmukhi;0A2B +phi;03C6 +phi1;03D5 +phieuphacirclekorean;327A +phieuphaparenkorean;321A +phieuphcirclekorean;326C +phieuphkorean;314D +phieuphparenkorean;320C +philatin;0278 +phinthuthai;0E3A +phisymbolgreek;03D5 +phook;01A5 +phophanthai;0E1E +phophungthai;0E1C +phosamphaothai;0E20 +pi;03C0 +pieupacirclekorean;3273 +pieupaparenkorean;3213 +pieupcieuckorean;3176 +pieupcirclekorean;3265 +pieupkiyeokkorean;3172 +pieupkorean;3142 +pieupparenkorean;3205 +pieupsioskiyeokkorean;3174 +pieupsioskorean;3144 +pieupsiostikeutkorean;3175 +pieupthieuthkorean;3177 +pieuptikeutkorean;3173 +pihiragana;3074 +pikatakana;30D4 +pisymbolgreek;03D6 +piwrarmenian;0583 +plus;002B +plusbelowcmb;031F +pluscircle;2295 +plusminus;00B1 +plusmod;02D6 +plusmonospace;FF0B +plussmall;FE62 +plussuperior;207A +pmonospace;FF50 +pmsquare;33D8 +pohiragana;307D +pointingindexdownwhite;261F +pointingindexleftwhite;261C +pointingindexrightwhite;261E +pointingindexupwhite;261D +pokatakana;30DD +poplathai;0E1B +postalmark;3012 +postalmarkface;3020 +pparen;24AB +precedes;227A +prescription;211E +primemod;02B9 +primereversed;2035 +product;220F +projective;2305 +prolongedkana;30FC +propellor;2318 +propersubset;2282 +propersuperset;2283 +proportion;2237 +proportional;221D +psi;03C8 +psicyrillic;0471 +psilipneumatacyrilliccmb;0486 +pssquare;33B0 +puhiragana;3077 +pukatakana;30D7 +pvsquare;33B4 +pwsquare;33BA +q;0071 +qadeva;0958 +qadmahebrew;05A8 +qafarabic;0642 +qaffinalarabic;FED6 +qafinitialarabic;FED7 +qafmedialarabic;FED8 +qamats;05B8 +qamats10;05B8 +qamats1a;05B8 +qamats1c;05B8 +qamats27;05B8 +qamats29;05B8 +qamats33;05B8 +qamatsde;05B8 +qamatshebrew;05B8 +qamatsnarrowhebrew;05B8 +qamatsqatanhebrew;05B8 +qamatsqatannarrowhebrew;05B8 +qamatsqatanquarterhebrew;05B8 +qamatsqatanwidehebrew;05B8 +qamatsquarterhebrew;05B8 +qamatswidehebrew;05B8 +qarneyparahebrew;059F +qbopomofo;3111 +qcircle;24E0 +qhook;02A0 +qmonospace;FF51 +qof;05E7 +qofdagesh;FB47 +qofdageshhebrew;FB47 +qofhatafpatah;05E7 05B2 +qofhatafpatahhebrew;05E7 05B2 +qofhatafsegol;05E7 05B1 +qofhatafsegolhebrew;05E7 05B1 +qofhebrew;05E7 +qofhiriq;05E7 05B4 +qofhiriqhebrew;05E7 05B4 +qofholam;05E7 05B9 +qofholamhebrew;05E7 05B9 +qofpatah;05E7 05B7 +qofpatahhebrew;05E7 05B7 +qofqamats;05E7 05B8 +qofqamatshebrew;05E7 05B8 +qofqubuts;05E7 05BB +qofqubutshebrew;05E7 05BB +qofsegol;05E7 05B6 +qofsegolhebrew;05E7 05B6 +qofsheva;05E7 05B0 +qofshevahebrew;05E7 05B0 +qoftsere;05E7 05B5 +qoftserehebrew;05E7 05B5 +qparen;24AC +quarternote;2669 +qubuts;05BB +qubuts18;05BB +qubuts25;05BB +qubuts31;05BB +qubutshebrew;05BB +qubutsnarrowhebrew;05BB +qubutsquarterhebrew;05BB +qubutswidehebrew;05BB +question;003F +questionarabic;061F +questionarmenian;055E +questiondown;00BF +questiondownsmall;F7BF +questiongreek;037E +questionmonospace;FF1F +questionsmall;F73F +quotedbl;0022 +quotedblbase;201E +quotedblleft;201C +quotedblmonospace;FF02 +quotedblprime;301E +quotedblprimereversed;301D +quotedblright;201D +quoteleft;2018 +quoteleftreversed;201B +quotereversed;201B +quoteright;2019 +quoterightn;0149 +quotesinglbase;201A +quotesingle;0027 +quotesinglemonospace;FF07 +r;0072 +raarmenian;057C +rabengali;09B0 +racute;0155 +radeva;0930 +radical;221A +radicalex;F8E5 +radoverssquare;33AE +radoverssquaredsquare;33AF +radsquare;33AD +rafe;05BF +rafehebrew;05BF +ragujarati;0AB0 +ragurmukhi;0A30 +rahiragana;3089 +rakatakana;30E9 +rakatakanahalfwidth;FF97 +ralowerdiagonalbengali;09F1 +ramiddlediagonalbengali;09F0 +ramshorn;0264 +ratio;2236 +rbopomofo;3116 +rcaron;0159 +rcedilla;0157 +rcircle;24E1 +rcommaaccent;0157 +rdblgrave;0211 +rdotaccent;1E59 +rdotbelow;1E5B +rdotbelowmacron;1E5D +referencemark;203B +reflexsubset;2286 +reflexsuperset;2287 +registered;00AE +registersans;F8E8 +registerserif;F6DA +reharabic;0631 +reharmenian;0580 +rehfinalarabic;FEAE +rehiragana;308C +rehyehaleflamarabic;0631 FEF3 FE8E 0644 +rekatakana;30EC +rekatakanahalfwidth;FF9A +resh;05E8 +reshdageshhebrew;FB48 +reshhatafpatah;05E8 05B2 +reshhatafpatahhebrew;05E8 05B2 +reshhatafsegol;05E8 05B1 +reshhatafsegolhebrew;05E8 05B1 +reshhebrew;05E8 +reshhiriq;05E8 05B4 +reshhiriqhebrew;05E8 05B4 +reshholam;05E8 05B9 +reshholamhebrew;05E8 05B9 +reshpatah;05E8 05B7 +reshpatahhebrew;05E8 05B7 +reshqamats;05E8 05B8 +reshqamatshebrew;05E8 05B8 +reshqubuts;05E8 05BB +reshqubutshebrew;05E8 05BB +reshsegol;05E8 05B6 +reshsegolhebrew;05E8 05B6 +reshsheva;05E8 05B0 +reshshevahebrew;05E8 05B0 +reshtsere;05E8 05B5 +reshtserehebrew;05E8 05B5 +reversedtilde;223D +reviahebrew;0597 +reviamugrashhebrew;0597 +revlogicalnot;2310 +rfishhook;027E +rfishhookreversed;027F +rhabengali;09DD +rhadeva;095D +rho;03C1 +rhook;027D +rhookturned;027B +rhookturnedsuperior;02B5 +rhosymbolgreek;03F1 +rhotichookmod;02DE +rieulacirclekorean;3271 +rieulaparenkorean;3211 +rieulcirclekorean;3263 +rieulhieuhkorean;3140 +rieulkiyeokkorean;313A +rieulkiyeoksioskorean;3169 +rieulkorean;3139 +rieulmieumkorean;313B +rieulpansioskorean;316C +rieulparenkorean;3203 +rieulphieuphkorean;313F +rieulpieupkorean;313C +rieulpieupsioskorean;316B +rieulsioskorean;313D +rieulthieuthkorean;313E +rieultikeutkorean;316A +rieulyeorinhieuhkorean;316D +rightangle;221F +righttackbelowcmb;0319 +righttriangle;22BF +rihiragana;308A +rikatakana;30EA +rikatakanahalfwidth;FF98 +ring;02DA +ringbelowcmb;0325 +ringcmb;030A +ringhalfleft;02BF +ringhalfleftarmenian;0559 +ringhalfleftbelowcmb;031C +ringhalfleftcentered;02D3 +ringhalfright;02BE +ringhalfrightbelowcmb;0339 +ringhalfrightcentered;02D2 +rinvertedbreve;0213 +rittorusquare;3351 +rlinebelow;1E5F +rlongleg;027C +rlonglegturned;027A +rmonospace;FF52 +rohiragana;308D +rokatakana;30ED +rokatakanahalfwidth;FF9B +roruathai;0E23 +rparen;24AD +rrabengali;09DC +rradeva;0931 +rragurmukhi;0A5C +rreharabic;0691 +rrehfinalarabic;FB8D +rrvocalicbengali;09E0 +rrvocalicdeva;0960 +rrvocalicgujarati;0AE0 +rrvocalicvowelsignbengali;09C4 +rrvocalicvowelsigndeva;0944 +rrvocalicvowelsigngujarati;0AC4 +rsuperior;F6F1 +rtblock;2590 +rturned;0279 +rturnedsuperior;02B4 +ruhiragana;308B +rukatakana;30EB +rukatakanahalfwidth;FF99 +rupeemarkbengali;09F2 +rupeesignbengali;09F3 +rupiah;F6DD +ruthai;0E24 +rvocalicbengali;098B +rvocalicdeva;090B +rvocalicgujarati;0A8B +rvocalicvowelsignbengali;09C3 +rvocalicvowelsigndeva;0943 +rvocalicvowelsigngujarati;0AC3 +s;0073 +sabengali;09B8 +sacute;015B +sacutedotaccent;1E65 +sadarabic;0635 +sadeva;0938 +sadfinalarabic;FEBA +sadinitialarabic;FEBB +sadmedialarabic;FEBC +sagujarati;0AB8 +sagurmukhi;0A38 +sahiragana;3055 +sakatakana;30B5 +sakatakanahalfwidth;FF7B +sallallahoualayhewasallamarabic;FDFA +samekh;05E1 +samekhdagesh;FB41 +samekhdageshhebrew;FB41 +samekhhebrew;05E1 +saraaathai;0E32 +saraaethai;0E41 +saraaimaimalaithai;0E44 +saraaimaimuanthai;0E43 +saraamthai;0E33 +saraathai;0E30 +saraethai;0E40 +saraiileftthai;F886 +saraiithai;0E35 +saraileftthai;F885 +saraithai;0E34 +saraothai;0E42 +saraueeleftthai;F888 +saraueethai;0E37 +saraueleftthai;F887 +sarauethai;0E36 +sarauthai;0E38 +sarauuthai;0E39 +sbopomofo;3119 +scaron;0161 +scarondotaccent;1E67 +scedilla;015F +schwa;0259 +schwacyrillic;04D9 +schwadieresiscyrillic;04DB +schwahook;025A +scircle;24E2 +scircumflex;015D +scommaaccent;0219 +sdotaccent;1E61 +sdotbelow;1E63 +sdotbelowdotaccent;1E69 +seagullbelowcmb;033C +second;2033 +secondtonechinese;02CA +section;00A7 +seenarabic;0633 +seenfinalarabic;FEB2 +seeninitialarabic;FEB3 +seenmedialarabic;FEB4 +segol;05B6 +segol13;05B6 +segol1f;05B6 +segol2c;05B6 +segolhebrew;05B6 +segolnarrowhebrew;05B6 +segolquarterhebrew;05B6 +segoltahebrew;0592 +segolwidehebrew;05B6 +seharmenian;057D +sehiragana;305B +sekatakana;30BB +sekatakanahalfwidth;FF7E +semicolon;003B +semicolonarabic;061B +semicolonmonospace;FF1B +semicolonsmall;FE54 +semivoicedmarkkana;309C +semivoicedmarkkanahalfwidth;FF9F +sentisquare;3322 +sentosquare;3323 +seven;0037 +sevenarabic;0667 +sevenbengali;09ED +sevencircle;2466 +sevencircleinversesansserif;2790 +sevendeva;096D +seveneighths;215E +sevengujarati;0AED +sevengurmukhi;0A6D +sevenhackarabic;0667 +sevenhangzhou;3027 +sevenideographicparen;3226 +seveninferior;2087 +sevenmonospace;FF17 +sevenoldstyle;F737 +sevenparen;247A +sevenperiod;248E +sevenpersian;06F7 +sevenroman;2176 +sevensuperior;2077 +seventeencircle;2470 +seventeenparen;2484 +seventeenperiod;2498 +seventhai;0E57 +sfthyphen;00AD +shaarmenian;0577 +shabengali;09B6 +shacyrillic;0448 +shaddaarabic;0651 +shaddadammaarabic;FC61 +shaddadammatanarabic;FC5E +shaddafathaarabic;FC60 +shaddafathatanarabic;0651 064B +shaddakasraarabic;FC62 +shaddakasratanarabic;FC5F +shade;2592 +shadedark;2593 +shadelight;2591 +shademedium;2592 +shadeva;0936 +shagujarati;0AB6 +shagurmukhi;0A36 +shalshelethebrew;0593 +shbopomofo;3115 +shchacyrillic;0449 +sheenarabic;0634 +sheenfinalarabic;FEB6 +sheeninitialarabic;FEB7 +sheenmedialarabic;FEB8 +sheicoptic;03E3 +sheqel;20AA +sheqelhebrew;20AA +sheva;05B0 +sheva115;05B0 +sheva15;05B0 +sheva22;05B0 +sheva2e;05B0 +shevahebrew;05B0 +shevanarrowhebrew;05B0 +shevaquarterhebrew;05B0 +shevawidehebrew;05B0 +shhacyrillic;04BB +shimacoptic;03ED +shin;05E9 +shindagesh;FB49 +shindageshhebrew;FB49 +shindageshshindot;FB2C +shindageshshindothebrew;FB2C +shindageshsindot;FB2D +shindageshsindothebrew;FB2D +shindothebrew;05C1 +shinhebrew;05E9 +shinshindot;FB2A +shinshindothebrew;FB2A +shinsindot;FB2B +shinsindothebrew;FB2B +shook;0282 +sigma;03C3 +sigma1;03C2 +sigmafinal;03C2 +sigmalunatesymbolgreek;03F2 +sihiragana;3057 +sikatakana;30B7 +sikatakanahalfwidth;FF7C +siluqhebrew;05BD +siluqlefthebrew;05BD +similar;223C +sindothebrew;05C2 +siosacirclekorean;3274 +siosaparenkorean;3214 +sioscieuckorean;317E +sioscirclekorean;3266 +sioskiyeokkorean;317A +sioskorean;3145 +siosnieunkorean;317B +siosparenkorean;3206 +siospieupkorean;317D +siostikeutkorean;317C +six;0036 +sixarabic;0666 +sixbengali;09EC +sixcircle;2465 +sixcircleinversesansserif;278F +sixdeva;096C +sixgujarati;0AEC +sixgurmukhi;0A6C +sixhackarabic;0666 +sixhangzhou;3026 +sixideographicparen;3225 +sixinferior;2086 +sixmonospace;FF16 +sixoldstyle;F736 +sixparen;2479 +sixperiod;248D +sixpersian;06F6 +sixroman;2175 +sixsuperior;2076 +sixteencircle;246F +sixteencurrencydenominatorbengali;09F9 +sixteenparen;2483 +sixteenperiod;2497 +sixthai;0E56 +slash;002F +slashmonospace;FF0F +slong;017F +slongdotaccent;1E9B +smileface;263A +smonospace;FF53 +sofpasuqhebrew;05C3 +softhyphen;00AD +softsigncyrillic;044C +sohiragana;305D +sokatakana;30BD +sokatakanahalfwidth;FF7F +soliduslongoverlaycmb;0338 +solidusshortoverlaycmb;0337 +sorusithai;0E29 +sosalathai;0E28 +sosothai;0E0B +sosuathai;0E2A +space;0020 +spacehackarabic;0020 +spade;2660 +spadesuitblack;2660 +spadesuitwhite;2664 +sparen;24AE +squarebelowcmb;033B +squarecc;33C4 +squarecm;339D +squarediagonalcrosshatchfill;25A9 +squarehorizontalfill;25A4 +squarekg;338F +squarekm;339E +squarekmcapital;33CE +squareln;33D1 +squarelog;33D2 +squaremg;338E +squaremil;33D5 +squaremm;339C +squaremsquared;33A1 +squareorthogonalcrosshatchfill;25A6 +squareupperlefttolowerrightfill;25A7 +squareupperrighttolowerleftfill;25A8 +squareverticalfill;25A5 +squarewhitewithsmallblack;25A3 +srsquare;33DB +ssabengali;09B7 +ssadeva;0937 +ssagujarati;0AB7 +ssangcieuckorean;3149 +ssanghieuhkorean;3185 +ssangieungkorean;3180 +ssangkiyeokkorean;3132 +ssangnieunkorean;3165 +ssangpieupkorean;3143 +ssangsioskorean;3146 +ssangtikeutkorean;3138 +ssuperior;F6F2 +sterling;00A3 +sterlingmonospace;FFE1 +strokelongoverlaycmb;0336 +strokeshortoverlaycmb;0335 +subset;2282 +subsetnotequal;228A +subsetorequal;2286 +succeeds;227B +suchthat;220B +suhiragana;3059 +sukatakana;30B9 +sukatakanahalfwidth;FF7D +sukunarabic;0652 +summation;2211 +sun;263C +superset;2283 +supersetnotequal;228B +supersetorequal;2287 +svsquare;33DC +syouwaerasquare;337C +t;0074 +tabengali;09A4 +tackdown;22A4 +tackleft;22A3 +tadeva;0924 +tagujarati;0AA4 +tagurmukhi;0A24 +taharabic;0637 +tahfinalarabic;FEC2 +tahinitialarabic;FEC3 +tahiragana;305F +tahmedialarabic;FEC4 +taisyouerasquare;337D +takatakana;30BF +takatakanahalfwidth;FF80 +tatweelarabic;0640 +tau;03C4 +tav;05EA +tavdages;FB4A +tavdagesh;FB4A +tavdageshhebrew;FB4A +tavhebrew;05EA +tbar;0167 +tbopomofo;310A +tcaron;0165 +tccurl;02A8 +tcedilla;0163 +tcheharabic;0686 +tchehfinalarabic;FB7B +tchehinitialarabic;FB7C +tchehmedialarabic;FB7D +tchehmeeminitialarabic;FB7C FEE4 +tcircle;24E3 +tcircumflexbelow;1E71 +tcommaaccent;0163 +tdieresis;1E97 +tdotaccent;1E6B +tdotbelow;1E6D +tecyrillic;0442 +tedescendercyrillic;04AD +teharabic;062A +tehfinalarabic;FE96 +tehhahinitialarabic;FCA2 +tehhahisolatedarabic;FC0C +tehinitialarabic;FE97 +tehiragana;3066 +tehjeeminitialarabic;FCA1 +tehjeemisolatedarabic;FC0B +tehmarbutaarabic;0629 +tehmarbutafinalarabic;FE94 +tehmedialarabic;FE98 +tehmeeminitialarabic;FCA4 +tehmeemisolatedarabic;FC0E +tehnoonfinalarabic;FC73 +tekatakana;30C6 +tekatakanahalfwidth;FF83 +telephone;2121 +telephoneblack;260E +telishagedolahebrew;05A0 +telishaqetanahebrew;05A9 +tencircle;2469 +tenideographicparen;3229 +tenparen;247D +tenperiod;2491 +tenroman;2179 +tesh;02A7 +tet;05D8 +tetdagesh;FB38 +tetdageshhebrew;FB38 +tethebrew;05D8 +tetsecyrillic;04B5 +tevirhebrew;059B +tevirlefthebrew;059B +thabengali;09A5 +thadeva;0925 +thagujarati;0AA5 +thagurmukhi;0A25 +thalarabic;0630 +thalfinalarabic;FEAC +thanthakhatlowleftthai;F898 +thanthakhatlowrightthai;F897 +thanthakhatthai;0E4C +thanthakhatupperleftthai;F896 +theharabic;062B +thehfinalarabic;FE9A +thehinitialarabic;FE9B +thehmedialarabic;FE9C +thereexists;2203 +therefore;2234 +theta;03B8 +theta1;03D1 +thetasymbolgreek;03D1 +thieuthacirclekorean;3279 +thieuthaparenkorean;3219 +thieuthcirclekorean;326B +thieuthkorean;314C +thieuthparenkorean;320B +thirteencircle;246C +thirteenparen;2480 +thirteenperiod;2494 +thonangmonthothai;0E11 +thook;01AD +thophuthaothai;0E12 +thorn;00FE +thothahanthai;0E17 +thothanthai;0E10 +thothongthai;0E18 +thothungthai;0E16 +thousandcyrillic;0482 +thousandsseparatorarabic;066C +thousandsseparatorpersian;066C +three;0033 +threearabic;0663 +threebengali;09E9 +threecircle;2462 +threecircleinversesansserif;278C +threedeva;0969 +threeeighths;215C +threegujarati;0AE9 +threegurmukhi;0A69 +threehackarabic;0663 +threehangzhou;3023 +threeideographicparen;3222 +threeinferior;2083 +threemonospace;FF13 +threenumeratorbengali;09F6 +threeoldstyle;F733 +threeparen;2476 +threeperiod;248A +threepersian;06F3 +threequarters;00BE +threequartersemdash;F6DE +threeroman;2172 +threesuperior;00B3 +threethai;0E53 +thzsquare;3394 +tihiragana;3061 +tikatakana;30C1 +tikatakanahalfwidth;FF81 +tikeutacirclekorean;3270 +tikeutaparenkorean;3210 +tikeutcirclekorean;3262 +tikeutkorean;3137 +tikeutparenkorean;3202 +tilde;02DC +tildebelowcmb;0330 +tildecmb;0303 +tildecomb;0303 +tildedoublecmb;0360 +tildeoperator;223C +tildeoverlaycmb;0334 +tildeverticalcmb;033E +timescircle;2297 +tipehahebrew;0596 +tipehalefthebrew;0596 +tippigurmukhi;0A70 +titlocyrilliccmb;0483 +tiwnarmenian;057F +tlinebelow;1E6F +tmonospace;FF54 +toarmenian;0569 +tohiragana;3068 +tokatakana;30C8 +tokatakanahalfwidth;FF84 +tonebarextrahighmod;02E5 +tonebarextralowmod;02E9 +tonebarhighmod;02E6 +tonebarlowmod;02E8 +tonebarmidmod;02E7 +tonefive;01BD +tonesix;0185 +tonetwo;01A8 +tonos;0384 +tonsquare;3327 +topatakthai;0E0F +tortoiseshellbracketleft;3014 +tortoiseshellbracketleftsmall;FE5D +tortoiseshellbracketleftvertical;FE39 +tortoiseshellbracketright;3015 +tortoiseshellbracketrightsmall;FE5E +tortoiseshellbracketrightvertical;FE3A +totaothai;0E15 +tpalatalhook;01AB +tparen;24AF +trademark;2122 +trademarksans;F8EA +trademarkserif;F6DB +tretroflexhook;0288 +triagdn;25BC +triaglf;25C4 +triagrt;25BA +triagup;25B2 +ts;02A6 +tsadi;05E6 +tsadidagesh;FB46 +tsadidageshhebrew;FB46 +tsadihebrew;05E6 +tsecyrillic;0446 +tsere;05B5 +tsere12;05B5 +tsere1e;05B5 +tsere2b;05B5 +tserehebrew;05B5 +tserenarrowhebrew;05B5 +tserequarterhebrew;05B5 +tserewidehebrew;05B5 +tshecyrillic;045B +tsuperior;F6F3 +ttabengali;099F +ttadeva;091F +ttagujarati;0A9F +ttagurmukhi;0A1F +tteharabic;0679 +ttehfinalarabic;FB67 +ttehinitialarabic;FB68 +ttehmedialarabic;FB69 +tthabengali;09A0 +tthadeva;0920 +tthagujarati;0AA0 +tthagurmukhi;0A20 +tturned;0287 +tuhiragana;3064 +tukatakana;30C4 +tukatakanahalfwidth;FF82 +tusmallhiragana;3063 +tusmallkatakana;30C3 +tusmallkatakanahalfwidth;FF6F +twelvecircle;246B +twelveparen;247F +twelveperiod;2493 +twelveroman;217B +twentycircle;2473 +twentyhangzhou;5344 +twentyparen;2487 +twentyperiod;249B +two;0032 +twoarabic;0662 +twobengali;09E8 +twocircle;2461 +twocircleinversesansserif;278B +twodeva;0968 +twodotenleader;2025 +twodotleader;2025 +twodotleadervertical;FE30 +twogujarati;0AE8 +twogurmukhi;0A68 +twohackarabic;0662 +twohangzhou;3022 +twoideographicparen;3221 +twoinferior;2082 +twomonospace;FF12 +twonumeratorbengali;09F5 +twooldstyle;F732 +twoparen;2475 +twoperiod;2489 +twopersian;06F2 +tworoman;2171 +twostroke;01BB +twosuperior;00B2 +twothai;0E52 +twothirds;2154 +u;0075 +uacute;00FA +ubar;0289 +ubengali;0989 +ubopomofo;3128 +ubreve;016D +ucaron;01D4 +ucircle;24E4 +ucircumflex;00FB +ucircumflexbelow;1E77 +ucyrillic;0443 +udattadeva;0951 +udblacute;0171 +udblgrave;0215 +udeva;0909 +udieresis;00FC +udieresisacute;01D8 +udieresisbelow;1E73 +udieresiscaron;01DA +udieresiscyrillic;04F1 +udieresisgrave;01DC +udieresismacron;01D6 +udotbelow;1EE5 +ugrave;00F9 +ugujarati;0A89 +ugurmukhi;0A09 +uhiragana;3046 +uhookabove;1EE7 +uhorn;01B0 +uhornacute;1EE9 +uhorndotbelow;1EF1 +uhorngrave;1EEB +uhornhookabove;1EED +uhorntilde;1EEF +uhungarumlaut;0171 +uhungarumlautcyrillic;04F3 +uinvertedbreve;0217 +ukatakana;30A6 +ukatakanahalfwidth;FF73 +ukcyrillic;0479 +ukorean;315C +umacron;016B +umacroncyrillic;04EF +umacrondieresis;1E7B +umatragurmukhi;0A41 +umonospace;FF55 +underscore;005F +underscoredbl;2017 +underscoremonospace;FF3F +underscorevertical;FE33 +underscorewavy;FE4F +union;222A +universal;2200 +uogonek;0173 +uparen;24B0 +upblock;2580 +upperdothebrew;05C4 +upsilon;03C5 +upsilondieresis;03CB +upsilondieresistonos;03B0 +upsilonlatin;028A +upsilontonos;03CD +uptackbelowcmb;031D +uptackmod;02D4 +uragurmukhi;0A73 +uring;016F +ushortcyrillic;045E +usmallhiragana;3045 +usmallkatakana;30A5 +usmallkatakanahalfwidth;FF69 +ustraightcyrillic;04AF +ustraightstrokecyrillic;04B1 +utilde;0169 +utildeacute;1E79 +utildebelow;1E75 +uubengali;098A +uudeva;090A +uugujarati;0A8A +uugurmukhi;0A0A +uumatragurmukhi;0A42 +uuvowelsignbengali;09C2 +uuvowelsigndeva;0942 +uuvowelsigngujarati;0AC2 +uvowelsignbengali;09C1 +uvowelsigndeva;0941 +uvowelsigngujarati;0AC1 +v;0076 +vadeva;0935 +vagujarati;0AB5 +vagurmukhi;0A35 +vakatakana;30F7 +vav;05D5 +vavdagesh;FB35 +vavdagesh65;FB35 +vavdageshhebrew;FB35 +vavhebrew;05D5 +vavholam;FB4B +vavholamhebrew;FB4B +vavvavhebrew;05F0 +vavyodhebrew;05F1 +vcircle;24E5 +vdotbelow;1E7F +vecyrillic;0432 +veharabic;06A4 +vehfinalarabic;FB6B +vehinitialarabic;FB6C +vehmedialarabic;FB6D +vekatakana;30F9 +venus;2640 +verticalbar;007C +verticallineabovecmb;030D +verticallinebelowcmb;0329 +verticallinelowmod;02CC +verticallinemod;02C8 +vewarmenian;057E +vhook;028B +vikatakana;30F8 +viramabengali;09CD +viramadeva;094D +viramagujarati;0ACD +visargabengali;0983 +visargadeva;0903 +visargagujarati;0A83 +vmonospace;FF56 +voarmenian;0578 +voicediterationhiragana;309E +voicediterationkatakana;30FE +voicedmarkkana;309B +voicedmarkkanahalfwidth;FF9E +vokatakana;30FA +vparen;24B1 +vtilde;1E7D +vturned;028C +vuhiragana;3094 +vukatakana;30F4 +w;0077 +wacute;1E83 +waekorean;3159 +wahiragana;308F +wakatakana;30EF +wakatakanahalfwidth;FF9C +wakorean;3158 +wasmallhiragana;308E +wasmallkatakana;30EE +wattosquare;3357 +wavedash;301C +wavyunderscorevertical;FE34 +wawarabic;0648 +wawfinalarabic;FEEE +wawhamzaabovearabic;0624 +wawhamzaabovefinalarabic;FE86 +wbsquare;33DD +wcircle;24E6 +wcircumflex;0175 +wdieresis;1E85 +wdotaccent;1E87 +wdotbelow;1E89 +wehiragana;3091 +weierstrass;2118 +wekatakana;30F1 +wekorean;315E +weokorean;315D +wgrave;1E81 +whitebullet;25E6 +whitecircle;25CB +whitecircleinverse;25D9 +whitecornerbracketleft;300E +whitecornerbracketleftvertical;FE43 +whitecornerbracketright;300F +whitecornerbracketrightvertical;FE44 +whitediamond;25C7 +whitediamondcontainingblacksmalldiamond;25C8 +whitedownpointingsmalltriangle;25BF +whitedownpointingtriangle;25BD +whiteleftpointingsmalltriangle;25C3 +whiteleftpointingtriangle;25C1 +whitelenticularbracketleft;3016 +whitelenticularbracketright;3017 +whiterightpointingsmalltriangle;25B9 +whiterightpointingtriangle;25B7 +whitesmallsquare;25AB +whitesmilingface;263A +whitesquare;25A1 +whitestar;2606 +whitetelephone;260F +whitetortoiseshellbracketleft;3018 +whitetortoiseshellbracketright;3019 +whiteuppointingsmalltriangle;25B5 +whiteuppointingtriangle;25B3 +wihiragana;3090 +wikatakana;30F0 +wikorean;315F +wmonospace;FF57 +wohiragana;3092 +wokatakana;30F2 +wokatakanahalfwidth;FF66 +won;20A9 +wonmonospace;FFE6 +wowaenthai;0E27 +wparen;24B2 +wring;1E98 +wsuperior;02B7 +wturned;028D +wynn;01BF +x;0078 +xabovecmb;033D +xbopomofo;3112 +xcircle;24E7 +xdieresis;1E8D +xdotaccent;1E8B +xeharmenian;056D +xi;03BE +xmonospace;FF58 +xparen;24B3 +xsuperior;02E3 +y;0079 +yaadosquare;334E +yabengali;09AF +yacute;00FD +yadeva;092F +yaekorean;3152 +yagujarati;0AAF +yagurmukhi;0A2F +yahiragana;3084 +yakatakana;30E4 +yakatakanahalfwidth;FF94 +yakorean;3151 +yamakkanthai;0E4E +yasmallhiragana;3083 +yasmallkatakana;30E3 +yasmallkatakanahalfwidth;FF6C +yatcyrillic;0463 +ycircle;24E8 +ycircumflex;0177 +ydieresis;00FF +ydotaccent;1E8F +ydotbelow;1EF5 +yeharabic;064A +yehbarreearabic;06D2 +yehbarreefinalarabic;FBAF +yehfinalarabic;FEF2 +yehhamzaabovearabic;0626 +yehhamzaabovefinalarabic;FE8A +yehhamzaaboveinitialarabic;FE8B +yehhamzaabovemedialarabic;FE8C +yehinitialarabic;FEF3 +yehmedialarabic;FEF4 +yehmeeminitialarabic;FCDD +yehmeemisolatedarabic;FC58 +yehnoonfinalarabic;FC94 +yehthreedotsbelowarabic;06D1 +yekorean;3156 +yen;00A5 +yenmonospace;FFE5 +yeokorean;3155 +yeorinhieuhkorean;3186 +yerahbenyomohebrew;05AA +yerahbenyomolefthebrew;05AA +yericyrillic;044B +yerudieresiscyrillic;04F9 +yesieungkorean;3181 +yesieungpansioskorean;3183 +yesieungsioskorean;3182 +yetivhebrew;059A +ygrave;1EF3 +yhook;01B4 +yhookabove;1EF7 +yiarmenian;0575 +yicyrillic;0457 +yikorean;3162 +yinyang;262F +yiwnarmenian;0582 +ymonospace;FF59 +yod;05D9 +yoddagesh;FB39 +yoddageshhebrew;FB39 +yodhebrew;05D9 +yodyodhebrew;05F2 +yodyodpatahhebrew;FB1F +yohiragana;3088 +yoikorean;3189 +yokatakana;30E8 +yokatakanahalfwidth;FF96 +yokorean;315B +yosmallhiragana;3087 +yosmallkatakana;30E7 +yosmallkatakanahalfwidth;FF6E +yotgreek;03F3 +yoyaekorean;3188 +yoyakorean;3187 +yoyakthai;0E22 +yoyingthai;0E0D +yparen;24B4 +ypogegrammeni;037A +ypogegrammenigreekcmb;0345 +yr;01A6 +yring;1E99 +ysuperior;02B8 +ytilde;1EF9 +yturned;028E +yuhiragana;3086 +yuikorean;318C +yukatakana;30E6 +yukatakanahalfwidth;FF95 +yukorean;3160 +yusbigcyrillic;046B +yusbigiotifiedcyrillic;046D +yuslittlecyrillic;0467 +yuslittleiotifiedcyrillic;0469 +yusmallhiragana;3085 +yusmallkatakana;30E5 +yusmallkatakanahalfwidth;FF6D +yuyekorean;318B +yuyeokorean;318A +yyabengali;09DF +yyadeva;095F +z;007A +zaarmenian;0566 +zacute;017A +zadeva;095B +zagurmukhi;0A5B +zaharabic;0638 +zahfinalarabic;FEC6 +zahinitialarabic;FEC7 +zahiragana;3056 +zahmedialarabic;FEC8 +zainarabic;0632 +zainfinalarabic;FEB0 +zakatakana;30B6 +zaqefgadolhebrew;0595 +zaqefqatanhebrew;0594 +zarqahebrew;0598 +zayin;05D6 +zayindagesh;FB36 +zayindageshhebrew;FB36 +zayinhebrew;05D6 +zbopomofo;3117 +zcaron;017E +zcircle;24E9 +zcircumflex;1E91 +zcurl;0291 +zdot;017C +zdotaccent;017C +zdotbelow;1E93 +zecyrillic;0437 +zedescendercyrillic;0499 +zedieresiscyrillic;04DF +zehiragana;305C +zekatakana;30BC +zero;0030 +zeroarabic;0660 +zerobengali;09E6 +zerodeva;0966 +zerogujarati;0AE6 +zerogurmukhi;0A66 +zerohackarabic;0660 +zeroinferior;2080 +zeromonospace;FF10 +zerooldstyle;F730 +zeropersian;06F0 +zerosuperior;2070 +zerothai;0E50 +zerowidthjoiner;FEFF +zerowidthnonjoiner;200C +zerowidthspace;200B +zeta;03B6 +zhbopomofo;3113 +zhearmenian;056A +zhebrevecyrillic;04C2 +zhecyrillic;0436 +zhedescendercyrillic;0497 +zhedieresiscyrillic;04DD +zihiragana;3058 +zikatakana;30B8 +zinorhebrew;05AE +zlinebelow;1E95 +zmonospace;FF5A +zohiragana;305E +zokatakana;30BE +zparen;24B5 +zretroflexhook;0290 +zstroke;01B6 +zuhiragana;305A +zukatakana;30BA +#--end + diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/FunctionType0.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/FunctionType0.java new file mode 100644 index 000000000..f8caa4e64 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/FunctionType0.java @@ -0,0 +1,444 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package com.sun.pdfview.function; + +import java.io.IOException; +import java.nio.ByteBuffer; + +import com.sun.pdfview.PDFDebugger; +import com.sun.pdfview.PDFObject; +import com.sun.pdfview.PDFParseException; + +/** + * A sampled function maps input values to output values by interpolating + * along a line or cubic between two known values. + */ +public class FunctionType0 extends PDFFunction { + /** the valid interpolation methods */ + protected static final int LINEAR_INTERPOLATION = 1; + protected static final int CUBIC_INTERPOLATION = 3; + + /** the size of each input dimension, as an array of m integers */ + private int[] size; + + /** the number of bits in each sample */ + private int bitsPerSample; + + /** the interpolation type, from the list above */ + private int order = 1; + + /** the optional encoding array, tells how to map input parameters to values */ + private float[] encode; + + /** the optional decoding array, tells how to map output parameters to values */ + private float[] decode; + + /** + * the actual samples, converted to integers. The first index is + * input values (from 0 to size[m - 1] * size[m - 2] * ... * size[0]), + * and the second is the output dimension within the sample (from 0 to n) + */ + private int[][] samples; + + /** Creates a new instance of FunctionType0 */ + protected FunctionType0() { + super (TYPE_0); + } + + /** Read the function information from a PDF Object */ + @Override + protected void parse(PDFObject obj) throws IOException { + // read the size array (required) + PDFObject sizeObj = obj.getDictRef("Size"); + if (sizeObj == null) { + throw new PDFParseException("Size required for function type 0!"); + } + PDFObject[] sizeAry = sizeObj.getArray(); + int[] size = new int[sizeAry.length]; + for (int i = 0; i < sizeAry.length; i++) { + size[i] = sizeAry[i].getIntValue(); + } + setSize(size); + + // read the # bits per sample (required) + PDFObject bpsObj = obj.getDictRef("BitsPerSample"); + if (bpsObj == null) { + throw new PDFParseException("BitsPerSample required for function type 0!"); + } + setBitsPerSample(bpsObj.getIntValue()); + + // read the order (optional) + PDFObject orderObj = obj.getDictRef("Order"); + if (orderObj != null) { + setOrder(orderObj.getIntValue()); + } + + // read the encode array (optional) + PDFObject encodeObj = obj.getDictRef("Encode"); + if (encodeObj != null) { + PDFObject[] encodeAry = encodeObj.getArray(); + float[] encode = new float[encodeAry.length]; + for (int i = 0; i < encodeAry.length; i++) { + encode[i] = encodeAry[i].getFloatValue(); + } + setEncode(encode); + } + + // read the decode array (optional) + PDFObject decodeObj = obj.getDictRef("Decode"); + if (decodeObj != null) { + PDFObject[] decodeAry = decodeObj.getArray(); + float[] decode = new float[decodeAry.length]; + for (int i = 0; i < decodeAry.length; i++) { + decode[i] = decodeAry[i].getFloatValue(); + } + setDecode(decode); + } + + // finally, read the samples + setSamples(readSamples(obj.getStreamBuffer())); + } + + /** + * Map from m input values to n output values. + * The number of inputs m must be exactly one half the size of the + * domain. The number of outputs should match one half the size of the + * range. + * + * @param inputs an array of m input values + * @param outputs an array of size n which will be filled + * with the output values, or null to return a new array + */ + @Override + protected void doFunction(float[] inputs, int inputOffset, + float[] outputs, int outputOffset) + { + // calculate the encoded values for each input + float[] encoded = new float[getNumInputs()]; + for (int i = 0; i < getNumInputs(); i++) { + // encode -- interpolate(x, domain<2i>, domain<2i + 1>, + // encode<2i>, encode<2i + 1>) + encoded[i] = interpolate(inputs[i + inputOffset], + getDomain(2 * i), + getDomain((2 * i) + 1), + getEncode(2 * i), + getEncode((2 * i) + 1)); + + // clip to size of sample table -- min(max(e, 0), size - 1) + encoded[i] = Math.max(encoded[i], 0); + encoded[i] = Math.min(encoded[i], this.size[i] - 1); + } + + // do some magic + for (int i = 0; i < getNumOutputs(); i++) { + if (getOrder() == 1) { + outputs[i + outputOffset] = multilinearInterpolate(encoded, i); + } else { + outputs[i + outputOffset] = multicubicInterpolate(encoded, i); + } + } + + // now adjust the output to be within range + for (int i = 0; i < outputs.length; i++) { + // decode -- interpolate(r, 0, 2^bps - 1, + // decode<2i>, decode<2i + 1>) + outputs[i + outputOffset] = interpolate(outputs[i + outputOffset], + 0, + (float) Math.pow(2, getBitsPerSample()) - 1, + getDecode(2 * i), + getDecode((2 * i) + 1)); + } + } + + /** + * Get the size of a given input dimension + * + * @param dimension the input dimension to get the size of + * @return the number of samples in the given dimension + */ + protected int getSize(int dimension) { + return this.size[dimension]; + } + + /** + * Set the size of all input dimensions + */ + protected void setSize(int[] size) { + this.size = size; + } + + + /** + * Get the number of bits per sample + */ + protected int getBitsPerSample() { + return this.bitsPerSample; + } + + /** + * Set the number of bits per sample + */ + protected void setBitsPerSample(int bits) { + this.bitsPerSample = bits; + } + + /** + * Get the interpolation type + */ + protected int getOrder() { + return this.order; + } + + /** + * Set the interpolation type + */ + protected void setOrder(int order) { + this.order = order; + } + + /** + * Get the encoding for a particular input parameter + * + * @param i the index into the encoding array, which has size 2 * m. + * the ith entry in the array has index 2i, + * 2i + 1 + * @return the encoding value if the encoding array is set, or the default + */ + protected float getEncode(int i) { + if (this.encode != null) { + return this.encode[i]; + } else if ((i % 2) == 0) { + return 0f; + } else { + return (getSize(i / 2) - 1); + } + } + + /** + * Set the encode array + */ + protected void setEncode(float[] encode) { + this.encode = encode; + } + + /** + * Get the decoding for a particular input parameter + * + * @param i the index into the decoding array, which has size 2 * n. + * the ith entry in the array has index 2i, + * 2i + 1 + * @return the decoding value if the decoding array is set, or the default + */ + protected float getDecode(int i) { + if (this.decode != null) { + return this.decode[i]; + } else { + return getRange(i); + } + } + + /** + * Set the decode array + */ + protected void setDecode(float[] decode) { + this.decode = decode; + } + + /** + * Get a component for a sample given m indices and output + * dimension. + * + * @param values an array of m values determining which sample + * to select + * @param od the output dimension (0 - n) to get the sample in + * @return the sample for the given values and index + */ + protected int getSample(int[] values, int od) { + int mult = 1; + int index = 0; + for (int i = 0; i < values.length; i++) { + index += mult * values[i]; + mult *= getSize(i); + } + + return this.samples[index][od]; + } + + /** + * Set the table of samples + */ + protected void setSamples(int[][] samples) { + this.samples = samples; + } + + /** + * Read the samples from the input stream. Each sample is made up + * of n components, each of which has length bitsPerSample + * bits. The samples are arranged by dimension, then range + */ + private int[][] readSamples(ByteBuffer buf) { + // calculate the number of samples in the table + int size = 1; + for (int i = 0; i < getNumInputs(); i++) { + size *= getSize(i); + } + + // create the samples table + int[][] samples = new int[size][getNumOutputs()]; + + + // the current location in the buffer, in bits from byteLoc + int bitLoc = 0; + + // the current location in the buffer, in bytes + int byteLoc = 0; + + // the current index in the samples array + int index = 0; + + for (int i = 0; i < getNumInputs(); i++) { + for (int j = 0; j < getSize(i); j++) { + for (int k = 0; k < getNumOutputs(); k++) { + /** [JK FIXME one bit at a time is really inefficient */ + int value = 0; + + int toRead = getBitsPerSample(); + byte curByte = buf.get(byteLoc); + + while (toRead > 0) { + int nextBit = ((curByte >> (7 - bitLoc)) & 0x1); + value |= nextBit << (toRead - 1); + + if (++bitLoc == 8) { + bitLoc = 0; + byteLoc++; + + if (toRead > 1) { + curByte = buf.get(byteLoc); + } + } + + toRead--; + } + + samples[index][k] = value; + } + + index++; + } + } + + return samples; + } + + /** + * Perform a piecewise multilinear interpolation. The provides a + * close approximation to the standard linear interpolation, at + * a far lower cost, since every element is not evaluated at every + * iteration. Instead, a walk of the most significant axes is performed, + * following the algorithm desribed at: + * http://osl.iu.edu/~tveldhui/papers/MAScThesis/node33.html + * + * @param encoded the encoded input values + * @param od the output dimension + */ + private float multilinearInterpolate(float[] encoded, int od) { + // first calculate the distances -- the differences between + // each encoded value and the integer below it. + float[] dists = new float[encoded.length]; + + for (int i = 0; i < dists.length; i++) { + dists[i] = (float) (encoded[i] - Math.floor(encoded[i])); + } + + // initialize the map of axes. Each bit in this map represents + // whether the control value in that dimension should be the integer + // above or below encoded[i] + int map = 0; + + // the initial values + float val = getSample(encoded, map, od); + float prev = val; + + // walk the axes + for (int i = 0; i < dists.length; i++) { + // find the largest value of dist remaining + int idx = 0; + float largest = -1; + for (int c = 0; c < dists.length; c++) { + if (dists[c] > largest) { + largest = dists[c]; + idx = c; + } + } + + // now find the sample with that axis set to 1 + map |= (0x1 << idx); + float cur = getSample(encoded, map, od); + + // calculate the value and remember it + val += dists[idx] * (cur - prev); + prev = val; + + // make sure we won't find this distance again + dists[idx] = -1; + } + + // voila + return val; + } + + /** + * Perform a multicubic interpolation + * + * @param encoded the encoded input values + * @param od the output dimension + */ + private float multicubicInterpolate(float[] encoded, int od) { + PDFDebugger.debug("Cubic interpolation not supported!"); + return multilinearInterpolate(encoded, od); + } + + /** + * Get a sample based on an array of encoded values and a control + * map. For each bit in the map, if that bit is 0 the integer below + * the encoded value is selected, or if the bit is 1, the interger + * above is selected. + * + * @param encoded the encoded values + * @param map the bit map of control values + * @param od the output dimension to read the sample for + */ + private float getSample(float[] encoded, int map, int od) { + int[] controls = new int[encoded.length]; + + // fill in the controls array with appropriate ints + for (int i = 0; i < controls.length; i++) { + if ((map & (0x1 << i)) == 0) { + controls[i] = (int) Math.floor(encoded[i]); + } else { + controls[i] = (int) Math.ceil(encoded[i]); + } + } + + // now return the actual sample + return getSample(controls, od); + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/FunctionType2.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/FunctionType2.java new file mode 100644 index 000000000..176006dcb --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/FunctionType2.java @@ -0,0 +1,150 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package com.sun.pdfview.function; + +import java.io.IOException; + +import com.sun.pdfview.PDFObject; +import com.sun.pdfview.PDFParseException; + +/** + * A type 2 function is an exponential interpolation function, which maps + * from one input value to n output values using a simple exponential + * formula. + */ +public class FunctionType2 extends PDFFunction { + /** the function's value at zero for the n outputs */ + private float[] c0 = new float[] { 0f }; + + /** the function's value at one for the n outputs */ + private float[] c1 = new float[] { 1f }; + + /** the exponent */ + private float n; + + /** Creates a new instance of FunctionType2 */ + public FunctionType2() { + super(TYPE_2); + } + + /** + * Read the zeros, ones and exponent + */ + @Override + protected void parse(PDFObject obj) throws IOException + { + // read the exponent (required) + PDFObject nObj = obj.getDictRef("N"); + if (nObj == null) { + throw new PDFParseException("Exponent required for function type 2!"); + } + setN(nObj.getFloatValue()); + + // read the zeros array (optional) + PDFObject cZeroObj = obj.getDictRef("C0"); + if (cZeroObj != null) { + PDFObject[] cZeroAry = cZeroObj.getArray(); + float[] cZero = new float[cZeroAry.length]; + for (int i = 0; i < cZeroAry.length; i++) { + cZero[i] = cZeroAry[i].getFloatValue(); + } + setC0(cZero); + } + + // read the ones array (optional) + PDFObject cOneObj = obj.getDictRef("C1"); + if (cOneObj != null) { + PDFObject[] cOneAry = cOneObj.getArray(); + float[] cOne = new float[cOneAry.length]; + for (int i = 0; i < cOneAry.length; i++) { + cOne[i] = cOneAry[i].getFloatValue(); + } + setC1(cOne); + } + } + + /** + * Calculate the function value for the input. For each output (j), + * the function value is: + * C0(j) + x^N * (C1(j) - C0(j)) + */ + @Override + protected void doFunction(float[] inputs, int inputOffset, + float[] outputs, int outputOffset) + { + // read the input value + float input = inputs[inputOffset]; + + // calculate the output values + for (int i = 0; i < getNumOutputs(); i++) { + outputs[i + outputOffset] = getC0(i) + + (float) (Math.pow(input, getN()) * (getC1(i) - getC0(i))); + } + } + + @Override + public int getNumOutputs() + { + // For Type 2 functions, the number of outputs is determined by the size of C0 (or C1). + return c0.length; + } + + /** + * Get the exponent + */ + public float getN() { + return this.n; + } + + /** + * Set the exponent + */ + protected void setN(float n) { + this.n = n; + } + + /** + * Get the values at zero + */ + public float getC0(int index) { + return this.c0[index]; + } + + /** + * Set the values at zero + */ + protected void setC0(float[] c0) { + this.c0 = c0; + } + + /** + * Get the values at one + */ + public float getC1(int index) { + return this.c1[index]; + } + + /** + * Set the values at one + */ + protected void setC1(float[] c1) { + this.c1 = c1; + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/FunctionType3.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/FunctionType3.java new file mode 100644 index 000000000..4694d7ba5 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/FunctionType3.java @@ -0,0 +1,183 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.sun.pdfview.function; + +import java.io.IOException; + +import com.sun.pdfview.PDFObject; +import com.sun.pdfview.PDFParseException; + +/** + * 3.9.3 - A stitching function define a stitching of the subdomains of + * several 1-input functions to produce a single new 1-input function. + * Since the resulting stitching function is a 1-input function, the + * domain is given by a two-element array, [ Domain0 Domain1 ]. + * + *
    + * Example 4.25
    + * 5 0 obj                          % Shading dictionary
    + *  << /ShadingType 3
    + *      /ColorSpace /DeviceCMYK
    + *      /Coords [ 0.0 0.0 0.096 0.0 0.0 1.0 00]% Concentric circles
    + *      /Function 10 0 R
    + *      /Extend [ true true ]
    + *  >>
    + * endobj
    + *
    + * 10 0 obj                         % Color function
    + *  << /FunctionType 3
    + *      /Domain [ 0.0 1.0 ]
    + *      /Functions [ 11 0 R 12 0 R ]
    + *      /Bounds [ 0.708 ]
    + *      /Encode [ 1.0 0.0 0.0 1.0 ]
    + *  >>
    + * endobj
    + *
    + * 11 0 obj                         % First subfunction
    + *  << /FunctionType 2
    + *      /Domain [ 0.0 1.0 ]
    + *      /C0 [ 0.929 0.357 1.000 0.298 ]
    + *      /C1 [ 0.631 0.278 1.000 0.027 ]
    + *      /N 1.048
    + *  >>
    + * endobj
    + *
    + * 12 0 obj                         % Second subfunction
    + *  << /FunctionType 2
    + *      /Domain [ 0.0 1.0 ]
    + *      /C0 [ 0.929 0.357 1.000 0.298 ]
    + *      /C1 [ 0.941 0.400 1.000 0.102 ]
    + *      /N 1.374
    + *  >>
    + * endobj
    + * 
    + */ +public class FunctionType3 extends PDFFunction { + + private PDFFunction[] functions; + private float[] bounds; + private float[] encode; + + /** Creates a new instance of FunctionType3 */ + protected FunctionType3() { + super(TYPE_3); + } + + /** + *

    Read the function information from a PDF Object.

    + *

    Required entries ( Table 3.38) (3200-1:2008:7.10.4, table: 41) + * are:

  • + * + * Functions array (Required) An array of k 1-input functions making up + * the stitching function. The output dimensionality of all functions + * must be the same, and compatible with the value of Range + * if Range is present.
  • + * + * Domainarray (Required) A 2 element array where + * Domain0 is less than Domain1. This is read by the + * PDFFunction superclass.
  • + * + * Bounds array (Required) An array of k-1 numbers that, + * in combination with Domain, define the intervals to which each + * function from the Functions array applies. Bounds elements + * must be in order of increasing value, and each value must be within + * the domain defined by >b>Domain.
  • + * + * Encode array (Required) An array of 2 * k numbers that, + * taken in pairs, map each subset of the domain defined by + * and the Bounds array to the domain of the corresponding function. + *
  • + */ + @Override + protected void parse(PDFObject obj) throws IOException { + // read the Functions array (required) + PDFObject functionsObj = obj.getDictRef("Functions"); + if (functionsObj == null) { + throw new PDFParseException("Functions required for function type 3!"); + } + PDFObject[] functionsAry = functionsObj.getArray(); + functions = new PDFFunction[functionsAry.length]; + for (int i = 0; i < functionsAry.length; i++) { + functions[i] = PDFFunction.getFunction(functionsAry[i]); + } + + // read the Bounds array (required) + PDFObject boundsObj = obj.getDictRef("Bounds"); + if (boundsObj == null) { + throw new PDFParseException("Bounds required for function type 3!"); + } + PDFObject[] boundsAry = boundsObj.getArray(); + bounds = new float[boundsAry.length + 2]; + if (bounds.length - 2 != functions.length - 1) { + throw new PDFParseException("Bounds array must be of length " + (functions.length - 1)); + } + + for (int i = 0; i < boundsAry.length; i++) { + bounds[i+1] = boundsAry[i].getFloatValue(); + } + bounds[0] = getDomain(0); + bounds[bounds.length-1] = getDomain(1); + + // read the encode array (required) + PDFObject encodeObj = obj.getDictRef("Encode"); + if (encodeObj == null) { + throw new PDFParseException("Encode required for function type 3!"); + } + PDFObject[] encodeAry = encodeObj.getArray(); + encode = new float[encodeAry.length]; + if (encode.length != 2*functions.length) { + throw new PDFParseException("Encode array must be of length " + 2*functions.length); + } + for (int i = 0; i < encodeAry.length; i++) { + encode[i] = encodeAry[i].getFloatValue(); + } + } + + /** + * + * @param inputs an array of 1 input values + * @param outputs an array of size n which will be filled + * with the output values, or null to return a new array + */ + @Override + protected void doFunction(float[] inputs, int inputOffset, + float[] outputs, int outputOffset) { + + float x = inputs[inputOffset]; + + // calculate the output values + int p = bounds.length - 2; + while (x < bounds[p]) p--; + x = interpolate(x, bounds[p], bounds[p+1], encode[2*p], encode[2*p + 1]); + float[] out = functions[p].calculate(new float[]{x}); + for (int i = 0; i < out.length; i++) { + outputs[i + outputOffset] = out[i]; + } + } + + @Override + public int getNumInputs() { + return 1; + } + + @Override + public int getNumOutputs() { + return functions[0].getNumOutputs(); + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/FunctionType4.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/FunctionType4.java new file mode 100644 index 000000000..d5c95d0fc --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/FunctionType4.java @@ -0,0 +1,121 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.sun.pdfview.function; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.*; + +import com.sun.pdfview.PDFObject; +import com.sun.pdfview.function.postscript.PostScriptParser; +import com.sun.pdfview.function.postscript.operation.OperationSet; +import com.sun.pdfview.function.postscript.operation.PostScriptOperation; + +/** + *

    A PostScript function is represented as a stream containing code + * written in a small subset of the PostScript language. + * This reference is taken from the (3200-1:2008:7.10.5)

    + * + * http://www.adobe.com/devnet/acrobat/pdfs/adobe_supplement_iso32000.pdf + *

    + */ +public class FunctionType4 extends PDFFunction { + + /** the list of tokens and sub-expressions. */ + private List tokens; + + /** the stack of operations. The stack contents should all be Comparable. */ + private Stack stack; + + /** Creates a new instance of FunctionType4 */ + protected FunctionType4() { + super(TYPE_4); + } + + /** Read the function information from a PDF Object */ + @Override + protected void parse(PDFObject obj) throws IOException { + ByteBuffer buf = obj.getStreamBuffer(); + + byte[] byteA = new byte[buf.remaining()]; + buf.get(byteA); + String scriptContent = new String(byteA, "UTF-8"); + this.tokens = new PostScriptParser().parse(scriptContent); + } + + /** + * Map from m input values to n output values. + * The number of inputs m must be exactly one half the size of the + * domain. The number of outputs should match one half the size of the + * range. + * + * @param inputs an array of m input values + * @param inputOffset the offset into the input array to read from + * @param outputs an array of size >= n which will be filled + * with the output values + * @param outputOffset the offset into the output array to write to + */ + @Override + protected void doFunction(float[] inputs, int inputOffset, float[] outputs, int outputOffset) { + prepareInitialStack(inputs, inputOffset); + for (Iterator iterator = this.tokens.iterator(); iterator.hasNext(); ) { + String token = iterator.next(); + PostScriptOperation op = OperationSet.getInstance().getOperation(token); + op.eval(this.stack); + } + assertResultIsCorrect(outputs, outputOffset); + prepareResult(outputs, outputOffset); + } + + /************************************************************************* + * @param outputs + * @param outputOffset + ************************************************************************/ + private void prepareResult(float[] outputs, int outputOffset) { + for (int i = outputOffset; i < outputs.length; i++) { + outputs[outputs.length-i-1] = ((Double)this.stack.pop()).floatValue(); + } + } + + /************************************************************************* + * Put all input values on the initial stack. + * All values are pushed as Double because we calculate internally with double. + * @param inputs + * @param inputOffset + ************************************************************************/ + + private void prepareInitialStack(float[] inputs, int inputOffset) { + this.stack = new Stack(); + for (int i = inputOffset; i < inputs.length; i++) { + this.stack.push(new Double(inputs[i])); + } + } + + /************************************************************************* + * @param outputs + * @param outputOffset + ************************************************************************/ + + private void assertResultIsCorrect(float[] outputs, int outputOffset) { + int expectedResults = outputs.length-outputOffset; + if (this.stack.size() != expectedResults) { + throw new IllegalStateException("Output does not match result "+expectedResults+"/"+this.stack); + } + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/PDFFunction.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/PDFFunction.java new file mode 100644 index 000000000..c596fa37f --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/PDFFunction.java @@ -0,0 +1,347 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +package com.sun.pdfview.function; + +import java.io.IOException; + +import com.sun.pdfview.PDFObject; +import com.sun.pdfview.PDFParseException; + +/** + *

    PDF Functions are defined in the reference as Section 3.9.

    + * + *

    A PDF function maps some set of m inputs into some set + * of n outputs. There are 4 types of functions: + *

    • Type 0: Sampled functions. (PDF 1.2)
      + * A sampled function (type 0) uses a table of sample values + * to define the function. Various techniques are used to + * interpolate values between the sample values + * (see Section 3.9.1, "Type 0 (Sampled) Functions").
    • + *
    • Type 2: Exponential Interpolation. (PDF 1.3)
      + * An exponential interpolation function (type 2) + * defines a set of coefficients for an exponential function + * (see Section 3.9.2, + * "Type 2 (Exponential Interpolation) Functions").
    • + *
    • Type 3: Stitching functions. (PDF 1.3)
      + * A stitching function (type 3) is a combination of + * other functions, partitioned across a domain + * (see Section 3.9.3, "Type 3 (Stitching) Functions").
    • + *
    • Type 4: Postscript calculations. (PDF 1.3)
      + * A PostScript calculator function (type 4) uses operators + * from the PostScript language to describe an arithmetic + * expression (see Section 3.9.4, + * "Type 4 (PostScript Calculator) Functions").
    • + *
    + *

    + * + *

    + * The function interface contains a single method, calculate which + * takes an array of m floats an interprets them into an array of + * n floats. + *

    + * PDFFunctions do not have accessible constructors. Instead, use the + * static getFunction() method to read a functions from a PDF Object. + * + */ +public abstract class PDFFunction { + + /** Sampled function */ + public static final int TYPE_0 = 0; + + /** Exponential interpolation function */ + public static final int TYPE_2 = 2; + + /** Stitching function. */ + public static final int TYPE_3 = 3; + + /** PostScript calculator function. */ + public static final int TYPE_4 = 4; + + /** the type of this function from the list of known types */ + private final int type; + + /** the input domain of this function, an array of 2 * m floats */ + private float[] domain; + + /** the output range of this functions, and array of 2 * n floats. + * required for type 0 and 4 functions + */ + private float[] range; + + /** Creates a new instance of PDFFunction */ + protected PDFFunction (int type) { + this.type = type; + } + + /** + * Get a PDFFunction from a PDFObject + */ + public static PDFFunction getFunction (PDFObject obj) + throws IOException { + PDFFunction function; + int type; + float[] domain = null; + float[] range = null; + + // read the function type (required) + PDFObject typeObj = obj.getDictRef ("FunctionType"); + if (typeObj == null) { + throw new PDFParseException ( + "No FunctionType specified in function!"); + } + type = typeObj.getIntValue (); + + // read the function's domain (required) + PDFObject domainObj = obj.getDictRef ("Domain"); + if (domainObj == null) { + throw new PDFParseException ("No Domain specified in function!"); + } + + PDFObject[] domainAry = domainObj.getArray (); + domain = new float[domainAry.length]; + for (int i = 0; i < domainAry.length; i++) { + domain[i] = domainAry[i].getFloatValue (); + } + + // read the function's range (optional) + PDFObject rangeObj = obj.getDictRef ("Range"); + if (rangeObj != null) { + PDFObject[] rangeAry = rangeObj.getArray (); + range = new float[rangeAry.length]; + for (int i = 0; i < rangeAry.length; i++) { + range[i] = rangeAry[i].getFloatValue (); + } + } + + // now create the acual function object + switch (type) { + case TYPE_0: + if (rangeObj == null) { + throw new PDFParseException ( + "No Range specified in Type 0 Function!"); + } + function = new FunctionType0 (); + break; + case TYPE_2: + function = new FunctionType2 (); + break; + case TYPE_3: + function = new FunctionType3 (); + break; + case TYPE_4: + if (rangeObj == null) { + throw new PDFParseException ( + "No Range specified in Type 4 Function!"); + } + function = new FunctionType4 (); + break; + default: + throw new PDFParseException ( + "Unsupported function type: " + type); + } + + // fill in the domain and optionally the range + function.setDomain (domain); + if (range != null) { + function.setRange (range); + } + + // now initialize the function + function.parse (obj); + + return function; + } + + /** + * Perform a linear interpolation. Given a value x, and two points, + * (xmin, ymin), (xmax, ymax), where xmin <= x <= xmax, calculate a value + * y on the line from (xmin, ymin) to (xmax, ymax). + * + * @param x the x value of the input + * @param xmin the minimum x value + * @param ymin the minimum y value + * @param xmax the maximum x value + * @param ymax the maximum y value + * @return the y value interpolated from the given x + */ + public static float interpolate(float x, float xmin, float xmax, + float ymin, float ymax) { + float value = (ymax - ymin) / (xmax - xmin); + value *= x - xmin; + value += ymin; + + return value; + } + + /** + * Get the type of this function + * + * @return one of the types of function (0-4) + */ + public int getType () { + return this.type; + } + + /** + * Get the number of inputs, m, required by this function + * + * @return the number of input values expected by this function + */ + public int getNumInputs () { + return (this.domain.length / 2); + } + + /** + * Get the number of outputs, n, returned by this function + * + * @return the number of output values this function will return + */ + public int getNumOutputs () { + if (this.range == null) { + return 0; + } + return (this.range.length / 2); + } + + /** + * Get a component of the domain of this function + * + * @param i the index into the domain array, which has size 2 * m. + * the ith entry in the array has index 2i, + * 2i + 1 + * @return the ith entry in the domain array + */ + protected float getDomain (int i) { + return this.domain[i]; + } + + /** + * Set the domain of this function + */ + protected void setDomain (float[] domain) { + this.domain = domain; + } + + /** + * Get a component of the range of this function + * + * @param i the index into the range array, which has size 2 * n. + * the ith entry in the array has index 2i, + * 2i + 1 + * @return the ith entry in the range array + */ + protected float getRange (int i) { + if (this.range == null) { + if ((i % 2) == 0) { + return Float.MIN_VALUE; + } else { + return Float.MAX_VALUE; + } + } + return this.range[i]; + } + + /** + * Set the range of this function + */ + protected void setRange (float[] range) { + this.range = range; + } + + /** + * Map from m input values to n output values. + * The number of inputs m must be exactly one half the size of the + * domain. The number of outputs should match one half the size of the + * range. + * + * @param inputs an array of >= m input values + * @return the array of n output values + */ + public float[] calculate (float[] inputs) { + float[] outputs = new float[getNumOutputs ()]; + calculate (inputs, 0, outputs, 0); + return outputs; + } + + /** + * Map from m input values to n output values. + * The number of inputs m must be exactly one half the size of the + * domain. The number of outputs should match one half the size of the + * range. + * + * @param inputs an array of >= m input values + * @param inputOffset the offset into the input array to read from + * @param outputs an array of size >= n which will be filled + * with the output values + * @param outputOffset the offset into the output array to write to + * @return the array of n output values + */ + public float[] calculate (float[] inputs, int inputOffset, + float[] outputs, int outputOffset) { + // check the inputs + if (inputs.length - inputOffset < getNumInputs ()) { + throw new IllegalArgumentException ( + "Wrong number of inputs to function!"); + } + + // check the outputs + if (this.range != null && outputs.length - outputOffset < getNumOutputs ()) { + throw new IllegalArgumentException ( + "Wrong number of outputs for function!"); + } + + // clip the inputs to domain + for (int i = 0; i < inputs.length; i++) { + // clip to the domain -- min(max(x, domain<2i>), domain<2i+1>) + inputs[i] = Math.max (inputs[i], getDomain (2 * i)); + inputs[i] = Math.min (inputs[i], getDomain ((2 * i) + 1)); + } + + // do the actual calculation + doFunction (inputs, inputOffset, outputs, outputOffset); + + // clip the outputs to range + for (int i = 0; this.range != null && i < outputs.length; i++) { + // clip to range -- min(max(r, range<2i>), range<2i + 1>) + outputs[i] = Math.max (outputs[i], getRange (2 * i)); + outputs[i] = Math.min (outputs[i], getRange ((2 * i) + 1)); + } + + return outputs; + } + + /** + * Subclasses must implement this method to perform the actual function + * on the given set of data. Note that the inputs are guaranteed to be + * clipped to the domain, while the outputs will be automatically clipped + * to the range after being returned from this function. + * + * @param inputs guaranteed to be at least as big as + * getNumInputs() and all values within range + * @param inputOffset the offset into the inputs array to read from + * @param outputs guaranteed to be at least as big as + * getNumOutputs(), but not yet clipped to domain + * @param outputOffset the offset into the output array to write to + */ + protected abstract void doFunction (float[] inputs, int inputOffset, + float[] outputs, int outputOffset); + + /** Read the function information from a PDF Object */ + protected abstract void parse (PDFObject obj) throws IOException; +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/PostScriptParser.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/PostScriptParser.java new file mode 100644 index 000000000..9a5179bdd --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/PostScriptParser.java @@ -0,0 +1,69 @@ +package com.sun.pdfview.function.postscript; + +import java.util.LinkedList; +import java.util.List; +import java.util.StringTokenizer; + +/***************************************************************************** + * Very simple post script parser / tokenizer + * + * @author Bernd Rosstauscher + * @since 22.10.2010 + ****************************************************************************/ + +public class PostScriptParser { + + /************************************************************************* + * Constructor + ************************************************************************/ + + public PostScriptParser() { + super(); + } + + /************************************************************************* + * Parses the given script and returns a list of tokens. + * @param scriptContent to parse. + * @return the list of tokens. + ************************************************************************/ + + public List parse(String scriptContent) { + List tokens = new LinkedList(); + StringTokenizer tok = new StringTokenizer(scriptContent, " \t\n\r"); + while (tok.hasMoreTokens()) { + String t = tok.nextToken(); + t = filterBlockStart(t); + t = filterBlockEnd(t); + if (t.length() > 0) { + tokens.add(t.trim()); + } + } + return tokens; + } + + /************************************************************************* + * @param t + * @return + ************************************************************************/ + private String filterBlockEnd(String t) { + if (t.endsWith("}")) { + t = t.substring(0, t.length()-1); + } + return t; + } + + /************************************************************************* + * @param t + * @return + ************************************************************************/ + private String filterBlockStart(String t) { + if (t.startsWith("{")) { + t = t.substring(1); + } + return t; + } + + + +} + diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Abs.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Abs.java new file mode 100644 index 000000000..ff57ecc72 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Abs.java @@ -0,0 +1,19 @@ +package com.sun.pdfview.function.postscript.operation; + +import java.util.Stack; + +final class Abs implements PostScriptOperation { + @Override + /** + * num1 abs num2

    + * + * The type of the result is the same as the type of num1, + * unless num1 is the smallest (most negative) integer, + * in which case the result is a real number.

    + * + * errors: stackunderflow, typecheck + */ + public void eval(Stack environment) { + environment.push(Math.abs((Double)environment.pop())); + } +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Add.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Add.java new file mode 100644 index 000000000..363d3eba9 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Add.java @@ -0,0 +1,19 @@ +package com.sun.pdfview.function.postscript.operation; + +import java.util.Stack; + +final class Add implements PostScriptOperation { + @Override + /** + * num1 num2 add sum

    + * + * If both operands are integers and the result is + * within integer range, the result is an integer; + * otherwise, the result is a real number.

    + * + * errors: stackunderflow, typecheck, undefinedresult + */ + public void eval(Stack environment) { + environment.push((Double)environment.pop() + (Double)environment.pop()); + } +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/And.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/And.java new file mode 100644 index 000000000..d28826e0b --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/And.java @@ -0,0 +1,20 @@ +package com.sun.pdfview.function.postscript.operation; + +import java.util.Stack; + +final class And implements PostScriptOperation { + @Override + /** + * bool1|int1 bool2|int2 and bool3|int3

    + * + * returns the logical conjunction of the operands + * if they are boolean. If the operands are integers, + * and returns the bitwise "and" of their binary + * representations.

    + * + * errors: stackunderflow, typecheck + */ + public void eval(Stack environment) { + environment.push((Long)environment.pop() & (Long)environment.pop()); + } +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Atan.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Atan.java new file mode 100644 index 000000000..c9993dc29 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Atan.java @@ -0,0 +1,30 @@ +package com.sun.pdfview.function.postscript.operation; + +import java.util.Stack; + + +final class Atan implements PostScriptOperation { + @Override + /** + * num den atan angle

    + * + * returns the angle (in degress between + * 0 and 360) whose tangent is num divided by den. + * Either num or den may be 0, but not both. The signs + * of num and den determine the quadrant in which the + * result will lie: positive num yeilds a result in the + * positive y plane, while a positive den yeilds a result in + * the positive x plane. The result is a real number.

    + * + * errors: stackunderflow, typecheck, undefinedresult + */ + public void eval(Stack environment) { + double den = (Double)environment.pop(); + double num = (Double)environment.pop(); + if (den == 0.0) { + environment.push(90.0); + } else { + environment.push(Math.toDegrees(Math.atan(num / den))); + } + } +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Bitshift.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Bitshift.java new file mode 100644 index 000000000..7168be9dc --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Bitshift.java @@ -0,0 +1,25 @@ +package com.sun.pdfview.function.postscript.operation; + +import java.util.Stack; + +final class Bitshift implements PostScriptOperation { + @Override + /** + * int1 shift bitshift int2

    + * + * shifts the binary representation of int1 left by + * shift bits and returns the result. Bits shifted out + * are lost; bits shifted in are 0. If shift is negative, + * a right shift by –shift bits is performed. + * This PostScriptOperation produces an arithmetically correct + * result only for positive values of int1. + * Both int1 and shift must be integers.

    + * + * errors: stackunderflow, typecheck + */ + public void eval(Stack environment) { + long shift = (Long)environment.pop(); + long int1 = (Long)environment.pop(); + environment.push(int1 << shift); + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Ceiling.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Ceiling.java new file mode 100644 index 000000000..97bf51c35 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Ceiling.java @@ -0,0 +1,19 @@ +package com.sun.pdfview.function.postscript.operation; + +import java.util.Stack; + +final class Ceiling implements PostScriptOperation { + @Override + /** + * num1 ceiling num2

    + * + * returns the least integer value greater than or equal + * to num1. The type of the result is the same as the type + * of the operand.

    + * + * errors: stackunderflow, typecheck + */ + public void eval(Stack environment) { + environment.push(Math.ceil((Double)environment.pop())); + } +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Copy.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Copy.java new file mode 100644 index 000000000..0b9740688 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Copy.java @@ -0,0 +1,64 @@ +package com.sun.pdfview.function.postscript.operation; + +import java.util.Stack; + final class Copy implements PostScriptOperation { + @Override + /** + * any1 ... anyn n copy any1 ... anyn any1 ... anyn + * array1 array2 copy subarray2
    + * string1 string2 copy substring2

    + * + * performs two entirely different functions, depending on the + * type of the topmost operand. + * In the first form, where the top element on the operand + * stack is a nonnegative integer n, copy pops n from the + * stack and duplicates the top n elements on the stack + * as shown above. This form of copy operates only on the + * objects themselves, not on the values of composite objects.

    + * + * Examples
    + * (a) (b) (c) 2 copy Þ (a) (b) (c) (b) (c)
    + * (a) (b) (c) 0 copy Þ (a) (b) (c)

    + * + * In the other forms, copy copies all the elements of the + * first composite object into the second. The composite + * object operands must be of the same type, except that + * a packed array can be copied into an array (and only into + * an array—copy cannot copy into packed arrays, because + * they are read-only). This form of copy copies the value of + * a composite object. This is quite different from dup and + * other operators that copy only the objects themselves + * (see Section 3.3.1, "Simple and Composite Objects"). + * However, copy performs only one level of copying. + * It does not apply recursively to elements that are + * themselves composite objects; instead, the values + * of those elements become shared. In the case of arrays or + * strings, the length of the second object must be at least as + * great as the first; copy returns the initial subarray or + * substring of the second operand into which the elements + * were copied. Any remaining elements of array2 or + * string2 are unaffected.

    + * + * Example:
    + * /a1 [1 2 3] def
    + * a1 dup length array copy Þ [1 2 3]

    + * + * errors: invalidaccess, rangecheck, stackoverflow, + * stackunderflow, typecheck + */ + public void eval(Stack environment) { + Number count = (Number) environment.pop(); +// ???? + Object[] buffer = new Object[count.intValue()]; + for (int i = 0; i < buffer.length; i++) { + buffer[i] = environment.pop(); + } + for (int i = 0; i < buffer.length; i++) { + environment.push(buffer[buffer.length-i-1]); + } + for (int i = 0; i < buffer.length; i++) { + environment.push(buffer[buffer.length-i-1]); + } + } + } + \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Cvi.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Cvi.java new file mode 100644 index 000000000..e7471041e --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Cvi.java @@ -0,0 +1,28 @@ +package com.sun.pdfview.function.postscript.operation; + +import java.util.Stack; +final class Cvi implements PostScriptOperation { + @Override + /** + * num cvi int or string cvi int

    + * + * takes an integer, real, or string and produces an + * integer result. If the operand is an integer, cvi + * simply returns it. If the operand is a real number, + * it truncates any fractional part (that is, rounds + * it toward 0) and converts it to an integer. + * If the operand is a string, cvi invokes the equivalent + * of the token operator to interpret the characters + * of the string as a number according to the PostScript + * syntax rules. If that number is a real number, cvi converts + * it to an integer. + * A rangecheck error occurs if a real number is too + * large to convert to an integer.

    + * + * errors: invalidaccess, rangecheck, stackunderflow, + * syntaxError, typecheck, + */ + public void eval(Stack environment) { + environment.push(environment.pop()); + } +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Cvr.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Cvr.java new file mode 100644 index 000000000..6035d0e77 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Cvr.java @@ -0,0 +1,26 @@ +package com.sun.pdfview.function.postscript.operation; + +import java.util.Stack; + +final class Cvr implements PostScriptOperation { + @Override + /** + * num cvr real or string cvr real

    + * + * (convert to real) takes an integer, real, or string + * object and produces a real result. If the operand + * is an integer, cvr converts it to a real number. + * If the operand is a real number, cvr simply returns it. + * If the operand is a string, cvr invokes the equivalent + * of the token operator to interpret the characters of + * the string as a number according to the PostScript + * syntax rules. If that number is an integer, cvr converts + * it to a real number.

    + * + * errors: invalidaccess, limitcheck, stackunderflow, + * syntaxerror, typecheck, undefinedresult + */ + public void eval(Stack environment) { + // YOUR CODE IN THIS SPACE + } +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Div.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Div.java new file mode 100644 index 000000000..88fc30f27 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Div.java @@ -0,0 +1,22 @@ +package com.sun.pdfview.function.postscript.operation; + +import java.util.Stack; + +final class Div implements PostScriptOperation { + @Override + /** + * num1 num2 div quotient

    + * + * divides num1 by num2, producing a result that is + * always a real number even if both operands are integers. + * Use idiv instead if the operands are integers and an + * integer result is desired.

    + * + * errors: stackunderflow, typecheck, undefinedresult + */ + public void eval(Stack environment) { + double num2 = (Double)environment.pop(); + double num1 = (Double)environment.pop(); + environment.push(num1 / num2); + } +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Dup.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Dup.java new file mode 100644 index 000000000..f08614da5 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Dup.java @@ -0,0 +1,22 @@ +package com.sun.pdfview.function.postscript.operation; + +import java.util.Stack; + +final class Dup implements PostScriptOperation { + @Override + /** + * any dup any any

    + * + * duplicates the top element on the operand stack. + * dup copies only the object; the value of a composite + * object is not copied but is shared. + * See Section 3.3, "Data Types and Objects."

    + * + * errors: stackoverflow, stackunderflow + */ + public void eval(Stack environment) { + Object obj = environment.pop(); + environment.push(obj); + environment.push(obj); + } +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Eq.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Eq.java new file mode 100644 index 000000000..e62a02ef4 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Eq.java @@ -0,0 +1,40 @@ +package com.sun.pdfview.function.postscript.operation; + +import java.util.Stack; + + +final class Eq implements PostScriptOperation { + @Override + /** + * any1 any2 eq bool

    + * + * pops two objects from the operand stack and pushes\ + * true if they are equal, or false if not. + * The definition of equality depends on the types of + * the objects being compared. + * Simple objects are equal if their types and values + * are the same. Strings are equal if their lengths and + * individual elements are equal. + * Other composite objects + * (arrays and dictionaries) are equal only if they share + * the same value. Separate values are considered unequal, + * even if all the components of those values are the + * same. + * This operator performs some type conversions. + * Integers and real numbers can be compared freely: + * an integer and a real number representing the same + * mathematical value are considered equal by eq. + * Strings and names can likewise be compared freely: + * a name defined by some sequence of characters is equal + * to a string whose elements are the same sequence of + * characters. + * The literal/executable and access attributes of + * objects are not considered in comparisons + * between objects.

    + * + * errors: invalidaccess, stackunderflow + */ + public void eval(Stack environment) { + environment.push(environment.pop().equals(environment.pop())); + } +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Exch.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Exch.java new file mode 100644 index 000000000..668efb509 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Exch.java @@ -0,0 +1,13 @@ +package com.sun.pdfview.function.postscript.operation; + +import java.util.Stack; + +final class Exch implements PostScriptOperation { + @Override + public void eval(Stack environment) { // any1 any2 exch any2 any1 - exchange top of stack + Object any1 = environment.pop(); + Object any2 = environment.pop(); + environment.push(any1); + environment.push(any2); + } +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Exp.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Exp.java new file mode 100644 index 000000000..acda23a87 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Exp.java @@ -0,0 +1,23 @@ +package com.sun.pdfview.function.postscript.operation; + +import java.util.Stack; + +final class Exp implements PostScriptOperation { + @Override + /** + * base exponent exp real

    + * + * raises base to the exponent power. The operands may be + * either integers or real numbers. If the exponent has a + * fractional part, the result is meaningful only if the + * base is nonnegative. The result is always a real number.

    + * + * errors: stackunderflow, typecheck, undefinedresult + */ + public void eval(Stack environment) { + double exponent = (Double)environment.pop(); + double base = (Double)environment.pop(); + environment.push(Math.pow(exponent, base)); + } + +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Expression.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Expression.java new file mode 100644 index 000000000..4f8af8e07 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Expression.java @@ -0,0 +1,17 @@ +package com.sun.pdfview.function.postscript.operation; + +import java.util.LinkedList; + + + +public class Expression extends LinkedList { + + @Override + public boolean equals(Object obj) { + if (obj instanceof Expression) { + // actually validate the list contents are the same expressions + return true; + } + return false; + } +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/False.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/False.java new file mode 100644 index 000000000..61e747d12 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/False.java @@ -0,0 +1,20 @@ +package com.sun.pdfview.function.postscript.operation; + +import java.util.Stack; + + +final class False implements PostScriptOperation { + @Override + /** + * false false

    + * + * pushes a boolean object whose value is false on the + * operand stack. false is not an operator; it is a name in + * systemdict associated with the boolean value false.

    + * + * errors: stackoverflow + */ + public void eval(Stack environment) { + environment.push(false); + } +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Floor.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Floor.java new file mode 100644 index 000000000..bf6b7a70f --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Floor.java @@ -0,0 +1,19 @@ +package com.sun.pdfview.function.postscript.operation; + +import java.util.Stack; + +final class Floor implements PostScriptOperation { + @Override + /** + * num1 floor num2

    + * + * returns the greatest integer value less than or equal + * to num1. The type of the result is the same as the type + * of the operand.

    + * + * errors: stackunderflow, typecheck + */ + public void eval(Stack environment) { + environment.push(Math.floor((Double)environment.pop())); + } +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Ge.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Ge.java new file mode 100644 index 000000000..7507a6b69 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Ge.java @@ -0,0 +1,30 @@ +package com.sun.pdfview.function.postscript.operation; + +import java.util.Stack; + + +final class Ge implements PostScriptOperation { + @Override + /** + * num1 num2 ge bool

    + * + * pops two objects from the operand stack and pushes true + * if the first operand is greater than or equal to the second, + * or false otherwise. If both operands are numbers, + * ge compares their mathematical values. If both operands + * are strings, ge compares them element by element, treating + * the elements as integers in the range 0 to 255, to determine + * whether the first string is lexically greater than or equal + * to the second. If the operands are of other types or one + * is a string and the other is a number, a typecheck + * error occurs.

    + * + * errors: invalidaccess, stackunderflow, typecheck + */ + public void eval(Stack environment) { + double num2 = (Double)environment.pop(); + double num1 = (Double)environment.pop(); + environment.push(num1 >= num2); + } +} + diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Gt.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Gt.java new file mode 100644 index 000000000..a6caf9330 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Gt.java @@ -0,0 +1,28 @@ +package com.sun.pdfview.function.postscript.operation; + +import java.util.Stack; + + +final class Gt implements PostScriptOperation { + @Override + /** + * num1 num2 gt bool

    + * + * pops two objects from the operand stack and pushes true + * if the first operand is greater than the second, or + * false otherwise. If both operands are numbers, gt compares + * their mathematical values. If both operands are strings, + * gt compares them element by element, treating the elements + * as integers in the range 0 to 255, to determine whether + * the first string is lexically greater than the second. + * If the operands are of other types or one is a string + * and the other is a number, a typecheck error occurs.

    + * + * errors: invalidaccess, stackunderflow, typecheck + */ + public void eval(Stack environment) { + double num2 = (Double)environment.pop(); + double num1 = (Double)environment.pop(); + environment.push(num1 > num2); + } +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Idiv.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Idiv.java new file mode 100644 index 000000000..aa03af451 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Idiv.java @@ -0,0 +1,22 @@ +package com.sun.pdfview.function.postscript.operation; + +import java.util.Stack; + +final class Idiv implements PostScriptOperation { + @Override + /** + * int1 int2 idiv quotient

    + * + * divides int1 by int2 and returns the integer part + * of the quotient, with any fractional part discarded. + * Both operands of idiv must be integers and the result + * is an integer.

    + * + * stackunderflow, typecheck, undefinedresult + */ + public void eval(Stack environment) { + long int2 = (Long)environment.pop(); + long int1 = (Long)environment.pop(); + environment.push(int1 / int2); + } +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/If.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/If.java new file mode 100644 index 000000000..9fd3635de --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/If.java @@ -0,0 +1,28 @@ +package com.sun.pdfview.function.postscript.operation; + +import java.util.Stack; + + +final class If implements PostScriptOperation { + @Override + /** + * bool {proc} if -

    + * + * removes both operands from the stack, then executes proc + * if bool is true. The if operator pushes no results of + * its own on the operand stack, but proc may do so (see + * Section 3.5, "Execution").

    + * + * Examples

    + * 3 4 lt {(3 is less than 4)} if

    + * + * errors: stackunderflow, typecheck + */ + public void eval(Stack environment) { + if ((Boolean)environment.pop()) { + environment.push(environment.pop()); + } else { + environment.pop(); + } + } +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/IfElse.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/IfElse.java new file mode 100644 index 000000000..ea96d3bfa --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/IfElse.java @@ -0,0 +1,32 @@ +package com.sun.pdfview.function.postscript.operation; + +import java.util.Stack; + +final class IfElse implements PostScriptOperation { + @Override + /** + * bool {expr1} {expr2} ifelse -

    + * + * removes all three operands from the stack, then + * executes proc1 if bool is true or proc2 if bool is false. + * The ifelse operator pushes no results of its own on the + * operand stack, but the procedure it executes may do so + * (see Section 3.5, "Execution").

    + * + * Examples

    + * 4 3 lt {(TruePart)} {(FalsePart)} ifelse
    + * results in FalsePart, since 4 is not less than 3

    + * + * errors: stackunderflow, typecheck + */ + public void eval(Stack environment) { + // execute expr1 if bool is true, expr2 if false + if ((Boolean)environment.pop()) { +// expression.push(popExpression()); + environment.pop(); + } else { + environment.pop(); +// expression.push(popExpression()); + } + } +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Index.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Index.java new file mode 100644 index 000000000..e7b470102 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Index.java @@ -0,0 +1,11 @@ +package com.sun.pdfview.function.postscript.operation; + +import java.util.Stack; + +final class Index implements PostScriptOperation { + @Override + public void eval(Stack environment) { // anyn ... any0 n index anyn ... any0 anyn + long n = Math.round((Double)environment.pop()); + environment.push(environment.get((int)(environment.size() - n - 1))); + } +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Le.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Le.java new file mode 100644 index 000000000..7f7c9e4cc --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Le.java @@ -0,0 +1,29 @@ +package com.sun.pdfview.function.postscript.operation; + +import java.util.Stack; + +final class Le implements PostScriptOperation { + @Override + /** + * num1 num2 le bool

    + * + * pops two objects from the operand stack and pushes true + * if the first operand is less than or equal to the second, + * or false otherwise. If both operands are numbers, le + * compares their mathematical values. If both operands are + * strings, le compares them element by element, treating + * the elements as integers in the range 0 to 255, + * to determine whether the first string is lexically less + * than or equal to the second. If the operands are of other + * types or one is a string and the other is a number, a + * typecheck error occurs.

    + * + * errors: invalidaccess, stackunderflow, typecheck + */ + public void eval(Stack environment) { + double num2 = (Double)environment.pop(); + double num1 = (Double)environment.pop(); + environment.push(num1 <= num2); + } +} + diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Ln.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Ln.java new file mode 100644 index 000000000..db4a0086a --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Ln.java @@ -0,0 +1,19 @@ +package com.sun.pdfview.function.postscript.operation; + +import java.util.Stack; + + +final class Ln implements PostScriptOperation { + @Override + /** + * num ln real

    + * + * returns the natural logarithm (base e) of num. + * The result is a real number.

    + * + * errors: rangecheck, stackunderflow, typecheck + */ + public void eval(Stack environment) { + environment.push(Math.log((Double)environment.pop())); + } +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Log.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Log.java new file mode 100644 index 000000000..0e93ef164 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Log.java @@ -0,0 +1,19 @@ +package com.sun.pdfview.function.postscript.operation; + +import java.util.Stack; + + +final class Log implements PostScriptOperation { + @Override + /** + * num log real

    + * + * returns the common logarithm (base 10) of num. + * The result is a real number.

    + * + * errors: rangecheck, stackunderflow, typecheck + */ + public void eval(Stack environment) { + environment.push(Math.log10((Double)environment.pop())); + } +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Lt.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Lt.java new file mode 100644 index 000000000..a46ecc967 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Lt.java @@ -0,0 +1,27 @@ +package com.sun.pdfview.function.postscript.operation; + +import java.util.Stack; + +final class Lt implements PostScriptOperation { + @Override + /** + * num1 num2 lt bool

    + * + * pops two objects from the operand stack and pushes true + * if the first operand is less than the second, or false + * otherwise. If both operands are numbers, lt compares + * their mathematical values. If both operands are strings, + * lt compares them element by element, treating the elements + * as integers in the range 0 to 255, to determine whether + * the first string is lexically less than the second. + * If the operands are of other types or one is a string + * and the other is a number, a typecheck error occurs.

    + * + * errors: invalidaccess, stackunderflow, typecheck + */ + public void eval(Stack environment) { + double num2 = (Double)environment.pop(); + double num1 = (Double)environment.pop(); + environment.push(num1 < num2); + } +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Mod.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Mod.java new file mode 100644 index 000000000..5ef8f1e7a --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Mod.java @@ -0,0 +1,24 @@ +package com.sun.pdfview.function.postscript.operation; + +import java.util.Stack; + + +final class Mod implements PostScriptOperation { + @Override + /** + * int1 int2 mod remainder

    + * + * returns the remainder that results from + * dividing int1 by int2. The sign of the result + * is the same as the sign of the dividend int1. + * Both operands must be integers and the result + * is an integer.

    + * + * errors: stackunderflow, typecheck, undefinedresult + */ + public void eval(Stack environment) { + long int2 = (Long)environment.pop(); + long int1 = (Long)environment.pop(); + environment.push(int1 % int2); + } +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Mul.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Mul.java new file mode 100644 index 000000000..c555a0375 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Mul.java @@ -0,0 +1,21 @@ +package com.sun.pdfview.function.postscript.operation; + +import java.util.Stack; + + +final class Mul implements PostScriptOperation { + @Override + /** + * num1 num2 mul product

    + * + * returns the product of num1 and num2. + * If both operands are integers and the result + * is within integer range, the result is an integer; + * otherwise, the result is a real number.

    + * + * errors: stackunderflow, typecheck, undefinedresult + */ + public void eval(Stack environment) { + environment.push((Double)environment.pop() * (Double)environment.pop()); + } +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Ne.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Ne.java new file mode 100644 index 000000000..fb9483684 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Ne.java @@ -0,0 +1,21 @@ +package com.sun.pdfview.function.postscript.operation; + +import java.util.Stack; + + +final class Ne implements PostScriptOperation { + @Override + /** + * any1 any2 ne bool

    + * + * pops two objects from the operand stack and pushes false + * if they are equal, or true if not. What it means for objects + * to be equal is presented in the description of the + * eq operator.

    + * + * errors: invalidaccess, stackunderflow + */ + public void eval(Stack environment) { + environment.push(!environment.pop().equals(environment.pop())); + } +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Neg.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Neg.java new file mode 100644 index 000000000..e3ddce6e0 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Neg.java @@ -0,0 +1,21 @@ +package com.sun.pdfview.function.postscript.operation; + +import java.util.Stack; + + +final class Neg implements PostScriptOperation { + @Override + /** + * num1 neg num2

    + * + * returns the negative of num1. The type of the result + * is the same as the type of num1 unless num1 is the + * smallest (most negative) integer, in which case the + * result is a real number.

    + * + * errors: stackunderflow, typecheck + */ + public void eval(Stack environment) { + environment.push(-(Double)environment.pop()); + } +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Not.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Not.java new file mode 100644 index 000000000..6642e6386 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Not.java @@ -0,0 +1,21 @@ +package com.sun.pdfview.function.postscript.operation; + +import java.util.Stack; + + +final class Not implements PostScriptOperation { + @Override + /** + * bool1|int1 not bool2|int2

    + * + * returns the logical negation of the operand if it is + * boolean. If the operand is an integer, not returns the + * bitwise complement (ones complement) of its binary + * representation.

    + * + * errors: stackunderflow, typecheck + */ + public void eval(Stack environment) { + environment.push(~(Long)environment.pop()); + } +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/OperationSet.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/OperationSet.java new file mode 100644 index 000000000..fbd702509 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/OperationSet.java @@ -0,0 +1,115 @@ +package com.sun.pdfview.function.postscript.operation; + +import java.util.HashMap; +import java.util.Map; + +public class OperationSet { + + /** the set of all Operations we support. These operations are defined + * in Appendix B - Operators.*/ + private Map operationSet = null; + + private static OperationSet instance; + + /************************************************************************* + * Constructor + ************************************************************************/ + + private OperationSet() { + super(); + initOperations(); + } + + /************************************************************************* + * @return + ************************************************************************/ + + public static synchronized OperationSet getInstance() { + if (instance == null) { + instance = new OperationSet(); + } + return instance; + } + + /************************************************************************* + * @param token + * @return + ************************************************************************/ + + public PostScriptOperation getOperation(String token) { + PostScriptOperation result = this.operationSet.get(token.trim().toLowerCase()); + if (result == null) { + result = new PushAsNumber(token); + } + return result; + + } + + + /** + * Initialize the operations that we can perform. + */ + private void initOperations() { + /** these operators consider the left hand arguments as deeper in + * the stack than the right hand arguments, thus the right-hand is + * is the top of the stack and is popped first. + * + * PostScriptOperation details in PostScript Language Reference Manual: + * http://www.adobe.com/products/postscript/pdfs/PLRM.pdf + * Chapter 8 - Operator Details + */ + if (this.operationSet == null) { + this.operationSet = new HashMap(); + + // Arithmetic Operators + this.operationSet.put("abs", new Abs()); + this.operationSet.put("add", new Add()); + this.operationSet.put("atan", new Atan()); + this.operationSet.put("ceiling", new Ceiling()); + this.operationSet.put("cvi", new Cvi()); + this.operationSet.put("cvr", new Cvr()); + this.operationSet.put("div", new Div()); + this.operationSet.put("exp", new Exp()); + this.operationSet.put("floor", new Floor()); + this.operationSet.put("idiv", new Idiv()); + this.operationSet.put("ln", new Ln()); + this.operationSet.put("log", new Log()); + this.operationSet.put("mod", new Mod()); + this.operationSet.put("mul", new Mul()); + this.operationSet.put("neg", new Neg()); + this.operationSet.put("round", new Round()); + this.operationSet.put("sin", new Sin()); + this.operationSet.put("sqrt", new Sqrt()); + this.operationSet.put("sub", new Sub()); + this.operationSet.put("truncate", new Truncate()); + + // Relational, boolean, and bitwise operators + this.operationSet.put("and", new And()); + this.operationSet.put("bitshift", new Bitshift()); + this.operationSet.put("eq", new Eq()); + this.operationSet.put("false", new False()); + this.operationSet.put("ge", new Ge()); + this.operationSet.put("gt",new Gt()); + this.operationSet.put("le", new Le()); + this.operationSet.put("lt", new Lt()); + this.operationSet.put("ne", new Ne()); + this.operationSet.put("not", new Not()); + this.operationSet.put("or", new Or()); + this.operationSet.put("true", new True()); + this.operationSet.put("xor", new Xor()); + + // Conditional Operators + this.operationSet.put("if", new If()); + this.operationSet.put("ifelse", new IfElse()); + + // Stack Operators + this.operationSet.put("copy", new Copy()); + this.operationSet.put("dup", new Dup()); + this.operationSet.put("exch", new Exch()); + this.operationSet.put("index", new Index()); + this.operationSet.put("pop", new Pop()); + this.operationSet.put("roll", new Roll()); + } + } + +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Or.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Or.java new file mode 100644 index 000000000..4f7fc3c11 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Or.java @@ -0,0 +1,20 @@ +package com.sun.pdfview.function.postscript.operation; + +import java.util.Stack; + + +final class Or implements PostScriptOperation { + @Override + /** + * bool1|int1 bool2|int2 or bool3|int3

    + * + * returns the logical disjunction of the operands if they + * are boolean. If the operands are integers, or returns + * the bitwise "inclusive or" of their binary representations.

    + * + * errors: stackunderflow, typecheck + */ + public void eval(Stack environment) { + environment.push((Long)environment.pop() | (Long)environment.pop()); + } +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Pop.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Pop.java new file mode 100644 index 000000000..1a371a9d9 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Pop.java @@ -0,0 +1,12 @@ +package com.sun.pdfview.function.postscript.operation; + +import java.util.Stack; + + +final class Pop implements PostScriptOperation { + @Override + public void eval(Stack environment) { // discard top element + environment.pop(); + } +} + diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/PostScriptOperation.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/PostScriptOperation.java new file mode 100644 index 000000000..dd7c899c1 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/PostScriptOperation.java @@ -0,0 +1,13 @@ +package com.sun.pdfview.function.postscript.operation; + +import java.util.Stack; + +public interface PostScriptOperation { + + /** + * evaluate the function, popping the stack as needed and pushing results. + */ + public void eval(Stack environment); + +} + diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/PushAsNumber.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/PushAsNumber.java new file mode 100644 index 000000000..c8dbc6317 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/PushAsNumber.java @@ -0,0 +1,35 @@ +package com.sun.pdfview.function.postscript.operation; + +import java.util.Stack; + + + +final class PushAsNumber implements PostScriptOperation { + + private String token; + + /************************************************************************* + * Constructor + * @param numberToken + ************************************************************************/ + + public PushAsNumber(String numberToken) { + super(); + this.token = numberToken; + } + + /************************************************************************* + * eval + * @see com.sun.pdfview.function.postscript.operation.PostScriptOperation#eval(java.util.Stack) + ************************************************************************/ + @Override + public void eval(Stack environment) { + try { + double number = Double.parseDouble(this.token); + environment.push(number); + } catch (NumberFormatException e) { + throw new IllegalArgumentException("PS token is not supported "+this.token); + } } + +} + diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Roll.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Roll.java new file mode 100644 index 000000000..d628ee5a6 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Roll.java @@ -0,0 +1,50 @@ +package com.sun.pdfview.function.postscript.operation; + +import java.util.Stack; + +final class Roll implements PostScriptOperation { + + public static int popAsInteger(Stack st) { + Object e = st.pop(); + if (e instanceof Double) { + double doubleVal = (Double) e; + return (int) doubleVal; + } else { + // error + return 0; + } + } + + @Override + public void eval(Stack environment) { + // anyn-1 ... any0 n j roll any(j-1)mod n ... anyn-1 ... any + // Roll n elements up j times + int j = popAsInteger(environment); + int n = popAsInteger(environment); + Object[] temp = new Object[n]; + + if (environment.size() < n) { + // error, cause by non-standard PS cmd, do nothing for compatibility + return; + } + + if (j >= 0) { + j %= n; + } else { + j = -j % n; + if (j != 0) + j = n - j; + } + for (int i = 0; i < n; ++i) { + temp[i] = environment.pop(); + } + + for (int i = j - 1; i > -1; --i) { + environment.push(temp[i]); + } + for (int i = n - 1; i > j - 1; --i) { + environment.push(temp[i]); + } + } + +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Round.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Round.java new file mode 100644 index 000000000..f8abe87db --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Round.java @@ -0,0 +1,21 @@ +package com.sun.pdfview.function.postscript.operation; + +import java.util.Stack; + +final class Round implements PostScriptOperation { + @Override + /** + * num1 round num2

    + * + * returns the integer value nearest to num1. + * If num1 is equally close to its two nearest + * integers, round returns the greater of the two. + * The type of the result is the same as + * the type of the operand.

    + * + * errors: stackunderflow, typecheck + */ + public void eval(Stack environment) { + environment.push(Math.round((Double)environment.pop())); + } +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Sin.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Sin.java new file mode 100644 index 000000000..fdc70a6a9 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Sin.java @@ -0,0 +1,20 @@ +package com.sun.pdfview.function.postscript.operation; + +import java.util.Stack; + + +final class Sin implements PostScriptOperation { + @Override + /** + * angle sin real

    + * + * returns the sine of angle, which is interpreted as an + * angle in degrees. The result is a real number.

    + * + * errors: stackunderflow, typecheck + */ + public void eval(Stack environment) { + double radians = Math.toRadians((Double)environment.pop()); + environment.push(Math.toDegrees(Math.sin(radians))); + } +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Sqrt.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Sqrt.java new file mode 100644 index 000000000..5064b2c99 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Sqrt.java @@ -0,0 +1,19 @@ +package com.sun.pdfview.function.postscript.operation; + +import java.util.Stack; + + +final class Sqrt implements PostScriptOperation { + @Override + /** + * num sqrt real

    + * + * returns the square root of num, which must be a + * nonnegative number. The result is a real number.

    + * + * errors: rangecheck, stackunderflow, typecheck + */ + public void eval(Stack environment) { + environment.push(Math.sqrt((Double)environment.pop())); + } +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Sub.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Sub.java new file mode 100644 index 000000000..2c1a26dbb --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Sub.java @@ -0,0 +1,23 @@ +package com.sun.pdfview.function.postscript.operation; + +import java.util.Stack; + + +final class Sub implements PostScriptOperation { + @Override + /** + * num1 num2 sub difference

    + * + * returns the result of subtracting num2 from num1. + * If both operands are integers and the result is within + * integer range, the result is an integer; otherwise, + * the result is a real number.

    + * + * errors: stackunderflow, typecheck, undefinedresult + */ + public void eval(Stack environment) { + double num2 = (Double)environment.pop(); + double num1 = (Double)environment.pop(); + environment.push(num1 - num2); + } +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/True.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/True.java new file mode 100644 index 000000000..77de5a7e5 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/True.java @@ -0,0 +1,20 @@ +package com.sun.pdfview.function.postscript.operation; + +import java.util.Stack; + + +final class True implements PostScriptOperation { + @Override + /** + * true true

    + * + * pushes a boolean object whose value is true on the operand + * stack. true is not an operator; it is a name in systemdict + * associated with the boolean value true.

    + * + * errors: stackoverflow + */ + public void eval(Stack environment) { + environment.push(true); + } +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Truncate.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Truncate.java new file mode 100644 index 000000000..c7bf09acc --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Truncate.java @@ -0,0 +1,21 @@ +package com.sun.pdfview.function.postscript.operation; + +import java.util.Stack; + + +final class Truncate implements PostScriptOperation { + @Override + /** + * num1 truncate num2

    + * + * truncates num1 toward 0 by removing its fractional part. + * The type of the result is the same as the type of the + * operand.

    + * + * errors: stackunderflow, typecheck + */ + public void eval(Stack environment) { + double num1 = (Double)environment.pop(); + environment.push((((long) num1) - num1)); + } +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Xor.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Xor.java new file mode 100644 index 000000000..d71895abf --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Xor.java @@ -0,0 +1,19 @@ +package com.sun.pdfview.function.postscript.operation; + +import java.util.Stack; + +final class Xor implements PostScriptOperation { + @Override + /** + * bool1|int1 bool2|int2 xor bool3|int3

    + * + * returns the logical "exclusive or" of the operands if they + * are boolean. If the operands are integers, xor returns the + * bitwise "exclusive or" of their binary representations.

    + * + * errors: stackunderflow, typecheck + */ + public void eval(Stack environment) { + environment.push((Long)environment.pop() ^ (Long)environment.pop()); + } +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/pattern/DummyShader.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/pattern/DummyShader.java new file mode 100644 index 000000000..07ea81946 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/pattern/DummyShader.java @@ -0,0 +1,25 @@ +package com.sun.pdfview.pattern; + +import java.awt.Color; +import java.io.IOException; + +import com.sun.pdfview.PDFObject; +import com.sun.pdfview.PDFPaint; + +public class DummyShader extends PDFShader { + + protected DummyShader(int type) { + super(type); + } + + @Override + public void parse(PDFObject shareObj) throws IOException { + + } + + @Override + public PDFPaint getPaint() { + return PDFPaint.getPaint(Color.PINK); + } + +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/pattern/PDFPattern.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/pattern/PDFPattern.java new file mode 100644 index 000000000..da58ecadb --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/pattern/PDFPattern.java @@ -0,0 +1,136 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package com.sun.pdfview.pattern; + + +import java.awt.geom.AffineTransform; +import java.io.IOException; +import java.util.Map; + +import com.sun.pdfview.PDFObject; +import com.sun.pdfview.PDFPaint; +import com.sun.pdfview.PDFParseException; + +/** + * The abstract superclass of all PDF Pattern types + * + */ +public abstract class PDFPattern { + + /** the pattern type (1 or 2) */ + private int type; + + /** the matrix to transform from pattern space to PDF space */ + private AffineTransform xform; + + /** Creates a new instance of PDFPattern */ + protected PDFPattern(int type) + { + this.type = type; + } + + /** + * Read a pattern from the given pattern stream + */ + public static PDFPattern getPattern(PDFObject patternObj, Map resources) + throws IOException + { + // see if the pattern is already cached + PDFPattern pattern = (PDFPattern) patternObj.getCache(); + if (pattern != null) { + return pattern; + } + + // get the pattern type + int type = patternObj.getDictRef("PatternType").getIntValue(); + + // read the pattern transform matrix + PDFObject matrix = patternObj.getDictRef("Matrix"); + AffineTransform xform = null; + if (matrix == null) { + xform = new AffineTransform(); + } else { + float elts[]= new float[6]; + for (int i = 0; i < elts.length; i++) { + elts[i] = matrix.getAt(i).getFloatValue(); + } + + xform = new AffineTransform(elts); + } + + switch (type) { + case 1: + pattern = new PatternType1(); + break; + case 2: + pattern = new PatternType2(); + break; + default: + throw new PDFParseException("Unknown pattern type " + type); + } + + // set the transform + pattern.setTransform(xform); + + // parse the pattern-specific data + pattern.parse(patternObj, resources); + + // set the cache + patternObj.setCache(pattern); + + return pattern; + } + + /** + * Get the type of this pattern + */ + public int getPatternType() { + return this.type; + } + + /** + * Get the transform associated with this pattern + */ + public AffineTransform getTransform() { + return this.xform; + } + + /** + * Set the transform associated with this pattern + */ + protected void setTransform(AffineTransform xform) { + this.xform = xform; + } + + /** + * Parse the pattern-specific information from the pdf object + * + * @param patternObj the pdfobject with data for this pattern + */ + protected abstract void parse(PDFObject patternObj, Map resources) + throws IOException; + + /** + * Returns paint that represents the selected pattern + * + * @param basePaint the background paint color, or null for none + */ + public abstract PDFPaint getPaint(PDFPaint basePaint); +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/pattern/PDFShader.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/pattern/PDFShader.java new file mode 100644 index 000000000..9909bed92 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/pattern/PDFShader.java @@ -0,0 +1,244 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package com.sun.pdfview.pattern; + +import java.awt.geom.Rectangle2D; +import java.io.IOException; +import java.util.Map; + +import com.sun.pdfview.PDFDebugger; +import com.sun.pdfview.PDFObject; +import com.sun.pdfview.PDFPaint; +import com.sun.pdfview.PDFParseException; +import com.sun.pdfview.colorspace.PDFColorSpace; + +/** + *

    A PDFShader fills a given region with a shading, such as a gradient.

    + * + *

    + * Shading Dictionaries (section 4.6)
    + * A shading dictionary specifies details of a particular gradient fill, + * including the type of shading to be used, the geometry of the area to + * be shaded, and the geometry of the gradient fill. Various shading types + * are available, depending on the value of the dictionary’s ShadingType entry: + * + *

  • Function-based shadings (type 1) define the color of every point in the + * domain using a mathematical function (not necessarily smooth or continuous).
  • + * + *
  • Axial shadings (type 2) define a color blend along a line between two + * points, optionally extended beyond the boundary points by continuing + * the boundary colors.
  • + * + *
  • Radial shadings (type 3) define a blend between two circles, + * optionally extended beyond the boundary circles by continuing the + * boundary colors. This type of shading is commonly used to represent + * three-dimensional spheres and cones.
  • + * + *
  • Free-form Gouraud-shaded triangle meshes (type 4) define a + * common construct used by many three-dimensional applications to + * represent complex colored and shaded shapes. Vertices are specified + * in free-form geometry.
  • + * + *
  • Lattice-form Gouraud-shaded triangle meshes (type 5) are based on + * the same geometrical construct as type 4 but with vertices specified + * as a pseudorectangular lattice.
  • + * + *
  • Coons patch meshes (type 6) construct a shading from one or more + * color patches, each bounded by four cubic Bézier curves.
  • + * + *
  • Tensor-product patch meshes (type 7) are similar to type 6 but + * with additional control points in each patch, affording greater + * control over color mapping.
  • + * + * Table 4.28 shows the entries that all shading dictionaries share + * in common; entries specific to particular shading types are + * described in the relevant sections below.

    + */ +public abstract class PDFShader { + + public final static int FUNCTION_SHADING = 1; + public final static int AXIAL_SHADING = 2; + public final static int RADIAL_SHADING = 3; + public final static int FREE_FORM_SHADING = 4; + public final static int LATTICE_SHADING = 5; + public final static int COONS_PATCH_MESH_SHADING = 6; + public final static int TENSOR_PRODUCTS_MESH_SHADING = 7; + + /** The tolerance for reevaluating the shading function again */ + public static float TOLERANCE = 1e-4f; + + /** the type of the shading (1 through 7)*/ + private final int type; + + /** the colorspace */ + private PDFColorSpace colorSpace; + + /** the background color */ + private PDFPaint background; + + /** the bounding box of the pattern */ + private Rectangle2D bbox; + + /** Creates a new instance of PDFShader */ + protected PDFShader(int type) { + this.type = type; + } + + + /** + * Parse a pdf shader into a shader object + */ + public static PDFShader getShader(PDFObject shaderObj, Map resources) + throws IOException + { + // first see if the shader is already cached + PDFShader shader = (PDFShader) shaderObj.getCache(); + if (shader != null) { + return shader; + } + + // read the type (required) + PDFObject typeObj = shaderObj.getDictRef("ShadingType"); + if (typeObj == null) { + throw new PDFParseException("No shader type defined!"); + } + int type = typeObj.getIntValue(); + + // create the shader + switch (type) { + case AXIAL_SHADING: + shader = new ShaderType2(); + break; + + case RADIAL_SHADING: + shader = new ShaderType3(); + break; + + case FUNCTION_SHADING: + case FREE_FORM_SHADING: + case LATTICE_SHADING: + case COONS_PATCH_MESH_SHADING: + case TENSOR_PRODUCTS_MESH_SHADING: + default: + shader = new DummyShader(type); + } + + // read the color space (required) + PDFObject csObj = shaderObj.getDictRef("ColorSpace"); + if (csObj == null) { + throw new PDFParseException("No colorspace defined!"); + } + PDFColorSpace cs = PDFColorSpace.getColorSpace(csObj, resources); + shader.setColorSpace(cs); + + // read the background color (optional) + PDFObject bgObj = shaderObj.getDictRef("Background"); + if (bgObj != null) { + PDFObject[] bgObjs = bgObj.getArray(); + float[] bgArray = new float[bgObjs.length]; + for (int i = 0; i < bgArray.length; i++) { + bgArray[i] = bgObjs[i].getFloatValue(); + } + PDFPaint paint = cs.getPaint(bgArray); + shader.setBackground(paint); + } + + // read the bounding box (optional) + PDFObject bboxObj = shaderObj.getDictRef("BBox"); + if (bboxObj != null) { + PDFObject[] rectObj = bboxObj.getArray(); + float minX = rectObj[0].getFloatValue(); + float minY = rectObj[1].getFloatValue(); + float maxX = rectObj[2].getFloatValue(); + float maxY = rectObj[3].getFloatValue(); + + Rectangle2D bbox = + new Rectangle2D.Float(minX, minY, maxX - minX, maxY - minY); + shader.setBBox(bbox); + } + + // parse the shader-specific attributes + shader.parse(shaderObj); + + // set the cache + shaderObj.setCache(shader); + + return shader; + } + + /** + * Get the type + */ + public int getType() { + return this.type; + } + + /** + * Get the color space + */ + public PDFColorSpace getColorSpace() { + return this.colorSpace; + } + + /** + * Set the color space + */ + protected void setColorSpace(PDFColorSpace colorSpace) { + this.colorSpace = colorSpace; + } + + /** + * Get the background color + */ + public PDFPaint getBackground() { + return this.background; + } + + /** + * Set the background color + */ + protected void setBackground(PDFPaint background) { + this.background = background; + } + + /** + * Get the bounding box + */ + public Rectangle2D getBBox() { + return this.bbox; + } + + /** + * Set the bounding box + */ + protected void setBBox(Rectangle2D bbox) { + this.bbox = bbox; + } + + /** + * Parse the shader-specific data + */ + public abstract void parse(PDFObject shareObj) throws IOException; + + /** + * Returns paint that represents the selected shader + */ + public abstract PDFPaint getPaint(); +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/pattern/PatternType1.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/pattern/PatternType1.java new file mode 100644 index 000000000..dfd88d95c --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/pattern/PatternType1.java @@ -0,0 +1,407 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package com.sun.pdfview.pattern; + +import java.awt.AlphaComposite; +import java.awt.Graphics2D; +import java.awt.Paint; +import java.awt.PaintContext; +import java.awt.Rectangle; +import java.awt.RenderingHints; +import java.awt.Shape; +import java.awt.Transparency; +import java.awt.color.ColorSpace; +import java.awt.geom.AffineTransform; +import java.awt.geom.GeneralPath; +import java.awt.geom.NoninvertibleTransformException; +import java.awt.geom.Rectangle2D; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.ComponentColorModel; +import java.awt.image.DataBuffer; +import java.awt.image.Raster; +import java.awt.image.WritableRaster; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import com.sun.pdfview.PDFObject; +import com.sun.pdfview.PDFPage; +import com.sun.pdfview.PDFPaint; +import com.sun.pdfview.PDFParser; +import com.sun.pdfview.PDFRenderer; + +/** + * A type 1 (tiling) pattern + */ +public class PatternType1 extends PDFPattern { + /** paint types */ + public static final int PAINT_COLORED = 1; + public static final int PAINT_UNCOLORED = 2; + + /** tiling types */ + public static final int TILE_CONSTANT = 1; + public static final int TILE_NODISTORT = 2; + public static final int TILE_FASTER = 3; + + /** the resources used by the image we will tile */ + private HashMap resources; + + /** the paint type (colored or uncolored) */ + private int paintType; + + /** the tiling type (constant, no distort or faster) */ + private int tilingType; + + /** the bounding box of the tile, in tile space */ + private Rectangle2D bbox; + + /** the horiztonal tile spacing, in tile space */ + private int xStep; + + /** the vertical spacing, in tile space */ + private int yStep; + + /** the stream data */ + private byte[] data; + + /** Creates a new instance of PatternType1 */ + public PatternType1() { + super(1); + } + + /** + * Parse the pattern from the PDFObject + * + * Note the resources passed in are ignored... + */ + @Override + protected void parse(PDFObject patternObj, Map rsrc) throws IOException + { + this.data = patternObj.getStream(); + + this.resources = patternObj.getDictRef("Resources").getDictionary(); + this.paintType = patternObj.getDictRef("PaintType").getIntValue(); + this.tilingType = patternObj.getDictRef("TilingType").getIntValue(); + + PDFObject bboxObj = patternObj.getDictRef("BBox"); + this.bbox= new Rectangle2D.Float(bboxObj.getAt(0).getFloatValue(), + bboxObj.getAt(1).getFloatValue(), + bboxObj.getAt(2).getFloatValue(), + bboxObj.getAt(3).getFloatValue()); + + this.xStep = patternObj.getDictRef("XStep").getIntValue(); + this.yStep = patternObj.getDictRef("YStep").getIntValue(); + } + + /** + * Create a PDFPaint from this pattern and set of components. + * This creates a buffered image of this pattern using + * the given paint, then uses that image to create the correct + * TexturePaint to use in the PDFPaint. + * + * @param basePaint the base paint to use, or null if not needed + */ + @Override + public PDFPaint getPaint(PDFPaint basePaint) { + // create the outline of the pattern in user space by creating + // a box with width xstep and height ystep. Transform that + // box using the pattern's matrix to get the user space + // bounding box + Rectangle2D anchor = new Rectangle2D.Double(getBBox().getMinX(), + getBBox().getMinY(), + getXStep(), + getYStep()); + //anchor = getTransform().createTransformedShape(anchor).getBounds2D(); + + // now create a page bounded by the pattern's user space size + final PDFPage page = new PDFPage(getBBox(), 0); + + // set the base paint if there is one + if (basePaint != null) { + page.addFillPaint(basePaint); + page.addStrokePaint(basePaint); + } + + // undo the page's transform to user space + /* + AffineTransform xform = + new AffineTransform(1, 0, 0, -1, 0, getYStep()); + //new AffineTransform(1, 0, 0, -1, 0, getBBox().getHeight()); + page.addXform(xform); + */ + + // now parse the pattern contents + PDFParser prc = new PDFParser(page, this.data, getResources()); + prc.go(true); + + int width = (int) getBBox().getWidth(); + int height = (int) getBBox().getHeight(); + + // get actual image + Paint paint = new Paint() { + @Override + public PaintContext createContext(ColorModel cm, + Rectangle deviceBounds, + Rectangle2D userBounds, + AffineTransform xform, + RenderingHints hints) + { + ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB); + ColorModel model = new ComponentColorModel(cs, + true, + false, + Transparency.TRANSLUCENT, + DataBuffer.TYPE_BYTE); + + Rectangle2D devBBox = + xform.createTransformedShape(userBounds).getBounds2D(); + + double[] steps = new double[] { getXStep(), getYStep() }; + xform.deltaTransform(steps, 0, steps, 0, 1); + + int width = (int) Math.ceil(devBBox.getWidth()); + int height = (int) Math.ceil(devBBox.getHeight()); + + BufferedImage img = (BufferedImage) page.getImage(width, height, + null, null, + false, true); + + return new Type1PaintContext(model, devBBox, + (float) steps[0], + (float) steps[1], + img.getData()); + } + + @Override + public int getTransparency() { + return Transparency.TRANSLUCENT; + } + }; + + + return new TilingPatternPaint(paint, this); + } + + /** get the associated resources */ + public HashMap getResources() { + return this.resources; + } + + /** get the paint type */ + public int getPaintType() { + return this.paintType; + } + + /** get the tiling type */ + public int getTilingType() { + return this.tilingType; + } + + /** get the bounding box */ + public Rectangle2D getBBox() { + return this.bbox; + } + + /** get the x step */ + public int getXStep() { + return this.xStep; + } + + /** get the y step */ + public int getYStep() { + return this.yStep; + } + + /** + * This class overrides PDFPaint to paint in the pattern coordinate space + */ + static class TilingPatternPaint extends PDFPaint { + /** the pattern to paint */ + private PatternType1 pattern; + + /** Create a tiling pattern paint */ + public TilingPatternPaint(Paint paint, PatternType1 pattern) { + super (paint); + + this.pattern = pattern; + } + + /** + * fill a path with the paint, and record the dirty area. + * @param state the current graphics state + * @param g the graphics into which to draw + * @param s the path to fill + * @param drawn a Rectangle2D into which the dirty area (area drawn) + * will be added. + */ + @Override + public Rectangle2D fill(PDFRenderer state, Graphics2D g, + GeneralPath s) { + // first transform s into device space + AffineTransform at = g.getTransform(); + Shape xformed = s.createTransformedShape(at); + + // push the graphics state so we can restore it + state.push(); + + // set the transform to be the inital transform concatentated + // with the pattern matrix + state.setTransform(state.getInitialTransform()); + state.transform(this.pattern.getTransform()); + + // now figure out where the shape should be + try { + at = state.getTransform().createInverse(); + } catch (NoninvertibleTransformException nte) { + // oh well (?) + } + xformed = at.createTransformedShape(xformed); + + // set the paint and draw the xformed shape + g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER)); + g.setPaint(getPaint()); + g.fill(xformed); + + // restore the graphics state + state.pop(); + + // return the area changed + return s.createTransformedShape(g.getTransform()).getBounds2D(); + } + } + + /** + * A simple paint context that uses an existing raster in device + * space to generate pixels + */ + class Type1PaintContext implements PaintContext { + /** the color model */ + private ColorModel colorModel; + + /** the anchor box */ + private Rectangle2D bbox; + + /** the x offset */ + private float xstep; + + /** the y offset */ + private float ystep; + + /** the image data, as a raster in device coordinates */ + private Raster data; + + /** + * Create a paint context + */ + Type1PaintContext(ColorModel colorModel, Rectangle2D bbox, + float xstep, float ystep, Raster data) + { + this.colorModel = colorModel; + this.bbox = bbox; + this.xstep = xstep; + this.ystep = ystep; + this.data = data; + } + + @Override + public void dispose() { + this.colorModel = null; + this.bbox = null; + this.data = null; + } + + @Override + public ColorModel getColorModel() { + return this.colorModel; + } + + @Override + public Raster getRaster(int x, int y, int w, int h) { + ColorSpace cs = getColorModel().getColorSpace(); + + int numComponents = cs.getNumComponents(); + + // all the data, plus alpha channel + int[] imgData = new int[w * h * (numComponents + 1)]; + + // the x and y step, as ints + int useXStep = (int) Math.abs(Math.ceil(this.xstep)); + int useYStep = (int) Math.abs(Math.ceil(this.ystep)); + + // a completely transparent pixel (alpha of 0) + int[] emptyPixel = new int[numComponents + 1]; + int[] usePixel = new int[numComponents + 1]; + + // for each device coordinate + for (int j = 0; j < h; j++) { + for (int i = 0; i < w; i ++) { + // figure out what pixel we are at relative to the image + int xloc = (x + i) - (int) Math.ceil(this.bbox.getX()); + int yloc = (y + j) - (int) Math.ceil(this.bbox.getY()); + + //if useXStep is 0, we would divide through 0 so instead xloc is set to 0 + if(useXStep == 0) { + xloc = 0; + } + else { + xloc %= useXStep; + } + + //if useYStep is 0, we would divide through 0 so instead yloc is set to 0 + if(useYStep == 0) { + yloc = 0; + } + else { + yloc %= useYStep; + } + + if (xloc < 0) { + xloc = useXStep + xloc; + } + if (yloc < 0) { + yloc = useYStep + yloc; + } + + int[] pixel = emptyPixel; + + // check if we are inside the image + if (xloc < this.data.getWidth() && + yloc < this.data.getHeight()) { + pixel = this.data.getPixel(xloc, yloc, usePixel); + } + + int base = (j * w + i) * (numComponents + 1); + for (int c = 0; c < pixel.length; c++) { + imgData[base + c] = pixel[c]; + } + } + } + + WritableRaster raster = + getColorModel().createCompatibleWritableRaster(w, h); + raster.setPixels(0, 0, w, h, imgData); + + Raster child = raster.createTranslatedChild(x, y); + + return child; + } + } +} diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/pattern/PatternType2.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/pattern/PatternType2.java new file mode 100644 index 000000000..de461053c --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/pattern/PatternType2.java @@ -0,0 +1,64 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package com.sun.pdfview.pattern; + +import java.io.IOException; +import java.util.Map; + +import com.sun.pdfview.PDFObject; +import com.sun.pdfview.PDFPaint; + +/** + * A type 1 (tiling) pattern + */ +public class PatternType2 extends PDFPattern { + + /** the shader */ + private PDFShader shader; + + /** Creates a new instance of PatternType1 */ + public PatternType2() { + super(2); + } + + /** + * Parse the pattern from the PDFObject + * + * Note the resources passed in are ignored... + */ + @Override + protected void parse(PDFObject patternObj, Map rsrc) throws IOException + { + this.shader = PDFShader.getShader(patternObj.getDictRef("Shading"), rsrc); + } + + /** + * Create a PDFPaint from this pattern and set of components. + * This creates a buffered image of this pattern using + * the given paint, then uses that image to create the correct + * TexturePaint to use in the PDFPaint. + * + * @param basePaint the base paint to use, or null if not needed + */ + @Override + public PDFPaint getPaint(PDFPaint basePaint) { + return shader.getPaint(); + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/pattern/ShaderType2.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/pattern/ShaderType2.java new file mode 100644 index 000000000..87155522c --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/pattern/ShaderType2.java @@ -0,0 +1,396 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package com.sun.pdfview.pattern; + +import java.awt.Paint; +import java.awt.PaintContext; +import java.awt.Rectangle; +import java.awt.RenderingHints; +import java.awt.Transparency; +import java.awt.color.ColorSpace; +import java.awt.geom.AffineTransform; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.awt.image.ColorModel; +import java.awt.image.ComponentColorModel; +import java.awt.image.DataBuffer; +import java.awt.image.Raster; +import java.awt.image.WritableRaster; +import java.io.IOException; + +import com.sun.pdfview.PDFObject; +import com.sun.pdfview.PDFPaint; +import com.sun.pdfview.PDFParseException; +import com.sun.pdfview.colorspace.PDFColorSpace; +import com.sun.pdfview.function.PDFFunction; + +/** + * A shader that performs axial shader based on a function. + */ +public class ShaderType2 extends PDFShader { + /** the start of the axis */ + private Point2D axisStart; + + /** the end of the axis */ + private Point2D axisEnd; + + /** the domain minimum */ + private float minT = 0f; + + /** the domain maximum */ + private float maxT = 1f; + + /** whether to extend the start of the axis */ + private boolean extendStart = false; + + /** whether to extend the end of the axis */ + private boolean extendEnd = false; + + /** functions, as an array of either 1 or n functions */ + private PDFFunction[] functions; + + /** Creates a new instance of ShaderType2 */ + public ShaderType2() { + super(2); + } + + /** + * Parse the shader-specific data + */ + @Override + public void parse(PDFObject shaderObj) throws IOException + { + // read the axis coordinates (required) + PDFObject coordsObj = shaderObj.getDictRef("Coords"); + if (coordsObj == null) { + throw new PDFParseException("No coordinates found!"); + } + PDFObject[] coords = coordsObj.getArray(); + Point2D start = new Point2D.Float(coords[0].getFloatValue(), + coords[1].getFloatValue()); + Point2D end = new Point2D.Float(coords[2].getFloatValue(), + coords[3].getFloatValue()); + setAxisStart(start); + setAxisEnd(end); + + // read the domain (optional) + PDFObject domainObj = shaderObj.getDictRef("Domain"); + if (domainObj != null) { + PDFObject[] domain = domainObj.getArray(); + setMinT(domain[0].getFloatValue()); + setMaxT(domain[1].getFloatValue()); + } + + // read the functions (required) + PDFObject functionObj = shaderObj.getDictRef("Function"); + if (functionObj == null) { + throw new PDFParseException("No function defined for shader!"); + } + PDFObject[] functionArray = functionObj.getArray(); + PDFFunction[] functions = new PDFFunction[functionArray.length]; + for (int i = 0; i < functions.length; i++) { + functions[i] = PDFFunction.getFunction(functionArray[i]); + } + setFunctions(functions); + + // read the extend array (optional) + PDFObject extendObj = shaderObj.getDictRef("Extend"); + if (extendObj != null) { + PDFObject[] extendArray = extendObj.getArray(); + setExtendStart(extendArray[0].getBooleanValue()); + setExtendEnd(extendArray[1].getBooleanValue()); + } + + } + + /** + * Create a paint that paints this pattern + */ + @Override + public PDFPaint getPaint() { + return PDFPaint.getPaint(new Type2Paint()); + } + + /** + * Get the start of the axis + */ + public Point2D getAxisStart() { + return this.axisStart; + } + + /** + * Set the start of the axis + */ + protected void setAxisStart(Point2D axisStart) { + this.axisStart = axisStart; + } + + /** + * Get the end of the axis + */ + public Point2D getAxisEnd() { + return this.axisEnd; + } + + /** + * Set the start of the axis + */ + protected void setAxisEnd(Point2D axisEnd) { + this.axisEnd = axisEnd; + } + + /** + * Get the domain minimum + */ + public float getMinT() { + return this.minT; + } + + /** + * Set the domain minimum + */ + protected void setMinT(float minT) { + this.minT = minT; + } + + /** + * Get the domain maximum + */ + public float getMaxT() { + return this.maxT; + } + + /** + * Set the domain maximum + */ + protected void setMaxT(float maxT) { + this.maxT = maxT; + } + + /** + * Get whether to extend the start of the axis + */ + public boolean getExtendStart() { + return this.extendStart; + } + + /** + * Set whether to extend the start of the axis + */ + protected void setExtendStart(boolean extendStart) { + this.extendStart = extendStart; + } + + /** + * Get whether to extend the end of the axis + */ + public boolean getExtendEnd() { + return this.extendEnd; + } + + /** + * Set whether to extend the end of the axis + */ + protected void setExtendEnd(boolean extendEnd) { + this.extendEnd = extendEnd; + } + + /** + * Get the functions associated with this shader + */ + public PDFFunction[] getFunctions() { + return this.functions; + } + + /** + * Set the functions associated with this shader + */ + protected void setFunctions(PDFFunction[] functions) { + this.functions = functions; + } + + /** + * A subclass of paint that uses this shader to generate a paint + */ + class Type2Paint implements Paint { + public Type2Paint() { + } + + /** create a paint context */ + @Override + public PaintContext createContext(ColorModel cm, + Rectangle deviceBounds, + Rectangle2D userBounds, + AffineTransform xform, + RenderingHints hints) + { + ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB); + ColorModel model = new ComponentColorModel(cs, + true, + false, + Transparency.TRANSLUCENT, + DataBuffer.TYPE_BYTE); + + Point2D devStart = xform.transform(getAxisStart(), null); + Point2D devEnd = xform.transform(getAxisEnd(), null); + + return new Type2PaintContext(model, devStart, devEnd); + } + + @Override + public int getTransparency() { + return Transparency.TRANSLUCENT; + } + } + + /** + * A simple paint context that uses an existing raster in device + * space to generate pixels + */ + class Type2PaintContext implements PaintContext { + /** the color model */ + private ColorModel colorModel; + + /** the start of the axis */ + private Point2D start; + + /** the end of the axis */ + private Point2D end; + + + private float dt1t0; + private double dx1x0, dy1y0, sqdx1x0psqdy1y0; + + /** + * Create a paint context + */ + Type2PaintContext(ColorModel colorModel, Point2D start, Point2D end) { + this.colorModel = colorModel; + this.start = start; + this.end = end; + + //pre calculate some often used values + dt1t0 = getMaxT() - getMinT(); + dx1x0 = end.getX() - start.getX(); + dy1y0 = end.getY() - start.getY(); + sqdx1x0psqdy1y0 = dx1x0*dx1x0 + dy1y0*dy1y0; + } + + @Override + public void dispose() { + this.colorModel = null; + } + + @Override + public ColorModel getColorModel() { + return this.colorModel; + } + + @Override + public Raster getRaster(int x, int y, int w, int h) { + ColorSpace cs = getColorModel().getColorSpace(); + PDFColorSpace shadeCSpace = getColorSpace(); + + + PDFFunction functions[] = getFunctions(); + int numComponents = cs.getNumComponents(); + + float x0 = (float) this.start.getX(); + float y0 = (float) this.start.getY(); + + float[] inputs = new float[1]; + float[] outputs = new float[shadeCSpace.getNumComponents()]; + float[] outputRBG = new float[numComponents]; + + // all the data, plus alpha channel + int[] data = new int[w * h * (numComponents + 1)]; + + // for each device coordinate + for (int j = 0; j < h; j++) { + for (int i = 0; i < w; i += 1) { + boolean render = true; + // find t for that user coordinate + float xp = getXPrime(i + x, j + y, x0, y0); + float t = 0; + if (xp >= 0 && xp <= 1) t = getMinT() + (dt1t0 * xp); + else if (xp < 0 && extendStart) t = getMinT(); + else if (xp > 1 && extendEnd) t = getMaxT(); + else render = false; + + if (render) { + // calculate the pixel values at t + inputs[0] = t; + if (functions.length == 1) { + functions[0].calculate(inputs, 0, outputs, 0); + } else { + for (int c = 0; c < functions.length; c++) { + functions[c].calculate(inputs, 0, outputs, c); + } + } + if (functions[0].getNumOutputs() != numComponents) { + //CMYK + outputRBG = shadeCSpace.getColorSpace().toRGB(outputs); + } + else outputRBG = outputs; + + int base = (j * w + i) * (numComponents + 1); + for (int c = 0; c < numComponents; c++) { + data[base + c] = (int) (outputRBG[c] * 255); + } + data[base + numComponents] = 255; + } + } + } + + WritableRaster raster = + getColorModel().createCompatibleWritableRaster(w, h); + raster.setPixels(0, 0, w, h, data); + + Raster child = raster.createTranslatedChild(x, y); + return child; + } + + /** + * x' = (x1 - x0) * (x - x0) + (y1 - y0) * (y - y0) + * ------------------------------------------- + * (x1 - x0)^2 + (y1 - y0)^2 + */ + private float getXPrime(float x, float y, float x0, float y0) { + + double tp = ((dx1x0* (x - x0)) + (dy1y0 * (y - y0))) / sqdx1x0psqdy1y0; + + return (float) tp; + } + + /** + * t = t0 + (t1 - t0) x x' + */ + private float getT(float xp) { + + if (xp < 0) { + return getMinT(); + } else if (xp > 1) { + return getMaxT(); + } else { + return getMinT() + (dt1t0 * xp); + } + } + } +} \ No newline at end of file diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/pattern/ShaderType3.java b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/pattern/ShaderType3.java new file mode 100644 index 000000000..5902193f7 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/pattern/ShaderType3.java @@ -0,0 +1,389 @@ +/* + * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, + * Santa Clara, California 95054, U.S.A. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package com.sun.pdfview.pattern; + +import java.awt.Paint; +import java.awt.PaintContext; +import java.awt.Rectangle; +import java.awt.RenderingHints; +import java.awt.Transparency; +import java.awt.color.ColorSpace; +import java.awt.geom.AffineTransform; +import java.awt.geom.NoninvertibleTransformException; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.awt.image.ColorModel; +import java.awt.image.ComponentColorModel; +import java.awt.image.DataBuffer; +import java.awt.image.Raster; +import java.awt.image.WritableRaster; +import java.io.IOException; + +import com.sun.pdfview.BaseWatchable; +import com.sun.pdfview.PDFObject; +import com.sun.pdfview.PDFPaint; +import com.sun.pdfview.PDFParseException; +import com.sun.pdfview.colorspace.PDFColorSpace; +import com.sun.pdfview.function.PDFFunction; + +/** + * A shader that performs radial shader based on a function. + */ +public class ShaderType3 extends PDFShader { + /** the center of the first circle */ + private Point2D center1; + + /** the center of the second circle */ + private Point2D center2; + + /** the radius of the first circle */ + private float radius1; + + /** the radius of the second circle */ + private float radius2; + + /** the domain minimum */ + private float minT = 0f; + + /** the domain maximum */ + private float maxT = 1f; + + /** whether to extend the start of the axis */ + private boolean extendStart = false; + + /** whether to extend the end of the axis */ + private boolean extendEnd = false; + + /** functions, as an array of either 1 or n functions */ + private PDFFunction[] functions; + + /** Creates a new instance of ShaderType2 */ + public ShaderType3() { + super(3); + } + + /** + * Parse the shader-specific data + */ + @Override + public void parse(PDFObject shaderObj) throws IOException + { + // read the axis coordinates (required) + PDFObject coordsObj = shaderObj.getDictRef("Coords"); + if (coordsObj == null) { + throw new PDFParseException("No coordinates found!"); + } + PDFObject[] coords = coordsObj.getArray(); + center1 = new Point2D.Float(coords[0].getFloatValue(), + coords[1].getFloatValue()); + center2 = new Point2D.Float(coords[3].getFloatValue(), + coords[4].getFloatValue()); + radius1 = coords[2].getFloatValue(); + radius2 = coords[5].getFloatValue(); + + // read the domain (optional) + PDFObject domainObj = shaderObj.getDictRef("Domain"); + if (domainObj != null) { + PDFObject[] domain = domainObj.getArray(); + setMinT(domain[0].getFloatValue()); + setMaxT(domain[1].getFloatValue()); + } + + // read the functions (required) + PDFObject functionObj = shaderObj.getDictRef("Function"); + if (functionObj == null) { + throw new PDFParseException("No function defined for shader!"); + } + PDFObject[] functionArray = functionObj.getArray(); + PDFFunction[] functions = new PDFFunction[functionArray.length]; + for (int i = 0; i < functions.length; i++) { + functions[i] = PDFFunction.getFunction(functionArray[i]); + } + setFunctions(functions); + + // read the extend array (optional) + PDFObject extendObj = shaderObj.getDictRef("Extend"); + if (extendObj != null) { + PDFObject[] extendArray = extendObj.getArray(); + setExtendStart(extendArray[0].getBooleanValue()); + setExtendEnd(extendArray[1].getBooleanValue()); + } + } + + /** + * Create a paint that paints this pattern + */ + @Override + public PDFPaint getPaint() { + return PDFPaint.getPaint(new Type3Paint()); + } + + + /** + * Get the domain minimum + */ + public float getMinT() { + return this.minT; + } + + /** + * Set the domain minimum + */ + protected void setMinT(float minT) { + this.minT = minT; + } + + /** + * Get the domain maximum + */ + public float getMaxT() { + return this.maxT; + } + + /** + * Set the domain maximum + */ + protected void setMaxT(float maxT) { + this.maxT = maxT; + } + + /** + * Get whether to extend the start of the axis + */ + public boolean getExtendStart() { + return this.extendStart; + } + + /** + * Set whether to extend the start of the axis + */ + protected void setExtendStart(boolean extendStart) { + this.extendStart = extendStart; + } + + /** + * Get whether to extend the end of the axis + */ + public boolean getExtendEnd() { + return this.extendEnd; + } + + /** + * Set whether to extend the end of the axis + */ + protected void setExtendEnd(boolean extendEnd) { + this.extendEnd = extendEnd; + } + + /** + * Get the functions associated with this shader + */ + public PDFFunction[] getFunctions() { + return this.functions; + } + + /** + * Set the functions associated with this shader + */ + protected void setFunctions(PDFFunction[] functions) { + this.functions = functions; + } + + /** + * A subclass of paint that uses this shader to generate a paint + */ + class Type3Paint implements Paint { + public Type3Paint() { + } + + /** create a paint context */ + @Override + public PaintContext createContext(ColorModel cm, + Rectangle deviceBounds, + Rectangle2D userBounds, + AffineTransform xform, + RenderingHints hints) + { + ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB); + ColorModel model = new ComponentColorModel(cs, + true, + false, + Transparency.TRANSLUCENT, + DataBuffer.TYPE_BYTE); + + return new Type3PaintContext(model, xform); + } + + @Override + public int getTransparency() { + return Transparency.TRANSLUCENT; + } + } + + /** + * A simple paint context that uses an existing raster in device + * space to generate pixels + */ + class Type3PaintContext implements PaintContext { + /** the color model */ + private ColorModel colorModel; + + /** the transformation */ + private AffineTransform invXform; + + private final double dx1x0, dy1y0, dr1r0, sqr0, denom; + + /** + * Create a paint context + */ + Type3PaintContext(ColorModel colorModel, AffineTransform xform) { + this.colorModel = colorModel; + + //Precalculate some often needed values; + dx1x0 = center2.getX() - center1.getX(); + dy1y0 = center2.getY() - center1.getY(); + dr1r0 = radius2 - radius1; + sqr0 = radius1*radius1; + denom = dx1x0*dx1x0 + dy1y0*dy1y0 - dr1r0*dr1r0; + + try { + this.invXform = xform.createInverse(); + } + catch (NoninvertibleTransformException e) { + BaseWatchable.getErrorHandler().publishException(e); + } + } + + @Override + public void dispose() { + this.colorModel = null; + } + + @Override + public ColorModel getColorModel() { + return this.colorModel; + } + + @Override + public Raster getRaster(int x, int y, int w, int h) { + ColorSpace cs = getColorModel().getColorSpace(); + PDFColorSpace shadeCSpace = getColorSpace(); + + PDFFunction functions[] = getFunctions(); + + int numComponents = cs.getNumComponents(); + + float[] c1 = new float[2]; + + float[] inputs = new float[1]; + float[] outputs = new float[shadeCSpace.getNumComponents()]; + float[] outputRBG = new float[numComponents]; + + // all the data, plus alpha channel + int[] data = new int[w * h * (numComponents + 1)]; + float lastInput = Float.POSITIVE_INFINITY; + final float tol = TOLERANCE * (getMaxT() - getMinT()); + + final int advance = 1; + // for each device coordinate + for (int j = 0; j < h; j++) { + for (int i = 0; i < w; i += advance) { + //Get point in user space + invXform.transform(new float[]{x + i, y + j}, 0, c1, 0, 1); + boolean render = true; + float[] s = calculateInputValues(c1[0], c1[1]); + //s[0] <= s[1] holds + //if (s[0] >= 0 && s[1] <= 1) s[1] = s[1]; + if (s[1] >= 0 && s[1] <= 1) s[1] = s[1]; + else if (extendEnd == true && s[1] >= 0 && radius1 + s[1]*dr1r0 >= 0) { + s[1] = s[1]; + } + else if (s[0] >= 0 && s[0] <= 1) s[1] = s[0]; + else if (extendStart == true && s[1] <= 0 && radius1 + s[1]*dr1r0 >= 0) { + s[1] = s[1]; + } + else if (extendStart == true && s[0] <= 1 && radius1 + s[0]*dr1r0 >= 0) { + s[1] = s[0]; + } + else render = false; + + if (render) { + float t = (getMinT() + s[1]*(getMaxT() - getMinT())); + // calculate the pixel values at t + inputs[0] = t; + if (Math.abs(lastInput - t) > tol) { + + if (functions.length == 1) { + functions[0].calculate(inputs, 0, outputs, 0); + } else { + for (int c = 0; c < functions.length; c++) { + functions[c].calculate(inputs, 0, outputs, c); + } + } + + if (!shadeCSpace.getColorSpace().isCS_sRGB()) { + //Can be quite slow + outputRBG = shadeCSpace.getColorSpace().toRGB(outputs); + } + else outputRBG = outputs; + + lastInput = t; + } + int base = (j * w + i) * (numComponents + 1); + for (int c = 0; c < numComponents; c++) { + data[base + c] = (int) (outputRBG[c] * 255); + } + data[base + numComponents] = 255; + } + } + } + + WritableRaster raster = + getColorModel().createCompatibleWritableRaster(w, h); + raster.setPixels(0, 0, w, h, data); + + Raster child = raster.createTranslatedChild(x, y); + return child; + } + + /** + * From Adobe Technical Note #5600: + * + * Given a geometric coordinate position (x, y) in or along the gradient gradient fill, + * the corresponding value of s can be determined by solving the quadratic + * constraint equation: + * + * [x - xc(s)]2 + [y - yc(s)]2 = [r(s)]2 + * + * The following code calculates the 2 possible values of s. + * + * @return Two possible values of s with s[0] <= s[1] + */ + private float[] calculateInputValues(float x, float y) { + double p = -(x - center1.getX())*dx1x0 -(y - center1.getY())*dy1y0 - radius1*dr1r0; + double q = (Math.pow(x - center1.getX(), 2) + Math.pow(y - center1.getY(), 2) - sqr0); + double root = Math.sqrt(p*p - denom*q); + float root1 = (float) ((-p + root)/denom); + float root2 = (float) ((-p - root)/denom); + if (denom < 0) return new float[]{root1, root2}; + else return new float[]{root2, root1}; + } + } +} diff --git a/openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/BaseFonts.properties b/openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/BaseFonts.properties new file mode 100644 index 000000000..465943338 --- /dev/null +++ b/openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/BaseFonts.properties @@ -0,0 +1,57 @@ +# Sample ResourceBundle properties file + +Courier.file=n022003l.pfb + +Courier.length=96263 + +Courier-Bold.file=n022004l.pfb + +Courier-Bold.length=120373 + +Courier-BoldOblique.file=n022024l.pfb + +Courier-BoldOblique.length=114228 + +Courier-Oblique.file=n022023l.pfb + +Courier-Oblique.length=101133 + +Helvetica.file=n019003l.pfb + +Helvetica.length=68590 + +Helvetica-Bold.file=n019004l.pfb + +Helvetica-Bold.length=72400 + +Helvetica-BoldOblique.file=n019024l.pfb + +Helvetica-BoldOblique.length=73879 + +Helvetica-Oblique.file=n019023l.pfb + +Helvetica-Oblique.length=71719 + +Times-Roman.file=n021003l.pfb + +Times-Roman.length=113206 + +Times-Bold.file=n021004l.pfb + +Times-Bold.length=108822 + +Times-BoldItalic.file=n021024l.pfb + +Times-BoldItalic.length=96211 + +Times-Italic.file=n021023l.pfb + +Times-Italic.length=108217 + +Symbol.file=s050000l.pfb + +Symbol.length=32213 + +ZapfDingbats.file=d050000l.pfb + +ZapfDingbats.length=45955 diff --git a/openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/d050000l.pfb b/openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/d050000l.pfb new file mode 100644 index 0000000000000000000000000000000000000000..4a3c386d292d5609de78d1bb0c44b9c40c688f88 GIT binary patch literal 45955 zcmb@sWmFtYlgEo|a0$-fE;Bem0>NE_2X}V~7F-hC-2%abTY^gnE`i`4g1g(D;o0|r z-FrXmId{*=hg5ZU^{>0C{?p7Ef9QH_C@2~VB~=y?6MG|5341#i79cA-KS0dV&fLh* z#TmfP4z}63P-tl0IGGx{SlZi(8M>JA1Jqni0gA>h03aXuA0HnI4d9KvgQt_FxrGZr zT}1<+YH#M^Zs=sn{LBxY$OAC)gp7md|Ljs|f@E>^B2n4mgN| zlRbEbEqDwZOv&Ea#o5@&(!m7)-c?CV;vY^I3qu#k-p-cbVSv3Ec&3THv8%1AoeMaY zAtVfV)Wy)!&Kclh>H&7z1B^@oCYH_)Hin+yy}`j8oGc$PT%EzGcp_j1IGLIoI+@s* zIy-~IfMY{$=joh~rT;m-p@V~s=i_So$65a}Sh_fy+L*DT072kA!AUeSHMg`wVS}V! z+Rn@#0A&BiZ{q6kpD{O6r^gGT|F42z0CO0c*xT870!&QJP}mggUBGt^p#NWFl@;)R zmel`)l>VP2^#3HC|NoNtKNIrQj`UCe{a<9~f5wq;wXsn!v<0X3UrqRbO)<2!wDJ7! zlm6!%4bw+ypjR<9ceOEe`k%wnE{5Q$6|pl1cR4#NxcneBW$7$o>0xT3Wa(mT0WdSP z0XOucU)|2c)XB!u&J^5!kKGMm;Q?1NWXZonY8IBp)^^|~0dR0X4w>4S{Ew1_l=~wz z+rKA!jG+YXOBXdy2QbM$K{e#fHVZ`l>?M)y}4C3Mj7&&;G1=7GAAOM@QgCV#%!Tx_d8~`>$;FHM- zHbGA&7sO_@z({W&3gz$XAs2q5r@fD^(8d_v%a00Oz6;z0<3?9V1VGCl!tJt964ay=409f1o1 z2x9*?AQuD>^aRZHc!5vA;LL!>pMb%M1KUr)To6Fe6Au>z5cCAh1>pld@o_`=Ku>(! z5Wc7B+z`BHvmtcPCPUz!&cgk8c~58Ieq?(#4q@YXHV$FqcseULgbiF$|4Al{sJdefq#K-ekeNTKm5I)W)J{|}k z=Mx_fiYgK5#+(YeV?J1@#}B55fm7sDEt;AGo0YwIO`qg8J8n@PP~JUmL;)E~tNP2p_nh z{R%he2QH|8Z3rK@qW)t8*&%@3Pk=zMaDg39gg~%VfE`bWKz0Zt zxUimLKp?rFAR)~Nc05r6*&&$V+Im_7;RF}glLG<@uC6BsgcMv}|2n|07O>+PDOgj$ zj%TFc_YSy`z<5tXJjAH2-?LkMlnzJ= z|Al{44@eH5JdlkbNqq7^b^<=Xl>d^EXSebwBtZ6OeBgvbRy_j*XB_MSXW=O_`2KY>&fsZl+1U+MZ6dK?&Wd(w>4d!{Ktw3

    )odrG$5Ad1N0{I{%2;_Li z%m=AKAovsf-#g@cWPYZ%K)y%jXNn8tdt`p5xj??hI((+OKyV#HB0p<9a3MoH&ngOB z$q>&|MS&i*2>48WL62ete5SvUhYNVsGX;k9JH+!;^N{w2c%JSV^e9NcXF3deR3zXt zB?f_O8?x$&83e9vi06qJ1g=tu=Na>(DgmDJ#vpWP=_B3evy-Mt)Q%;4{$%JxUbtnQDXn(Wqy#4FY!-Xm%_q+z;j@nm5V(&Zk)PcdxR1adaR2_h>c5`G&+hP_$1zx8 zp62|+{OmR!AIK1ed7AUjt^RY;|NhN^x}Bw?tEsdYfQub`72tA){1ImC>f{9ew&d~K z3GiQT|FIvx1u`}DFf~T=hxwcZ1-11FdDKAYms+RA>?qqSn)B{sxUHjJzS_Csusz0Z!Ura%MFX9vHClxQGZ7X= zie8x>%I~+{>M&PbCmUK!uK@8A0_oR#qQ&9)lJ{r|4>+ZZ|MoW^o9ZxYtlc%f zcVR;A>Jkru)>n+*y!cz9R>R1=-63!@rhDlau|kYsw3j@m^?P+D?w^pg-;|15r{{k_ z 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´D`^A-#(-DNgJTEu#mS8jGAQpq;M)V3b?^=|A<8_pl z@g8%!U%saS#`5}dD_#}}f?!ROm$H-j&hwu*aoXU&%>N4v4E`53Kt=>3Ffr&z1Sb6S RUzlKQ3>p)R4?`uN{0{-b@1Otx literal 0 HcmV?d00001 diff --git a/openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/n019004l.pfb b/openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/n019004l.pfb new file mode 100644 index 0000000000000000000000000000000000000000..94a302084fd6b7233c56b61f286144e3af0a7ff2 GIT binary patch literal 72400 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ℜ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 X>}cj{j|X+NbaQuhwe+{O3Pk@OK^QiE literal 0 HcmV?d00001 diff --git a/openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/n019023l.pfb b/openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/n019023l.pfb new file mode 100644 index 0000000000000000000000000000000000000000..b124a58df34f1db8110355a021f404a328e96dd1 GIT binary patch literal 71719 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

    ? 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 BxiA0# literal 0 HcmV?d00001 diff --git a/openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/n019024l.pfb b/openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/n019024l.pfb new file mode 100644 index 0000000000000000000000000000000000000000..1a9d6f5b109573ae3fdfdb66d797923df030b28b GIT binary patch literal 73879 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 z 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 S__RcXzj7!C~@y-|6nJXL`O> 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%0DkMmD1hB1grN=BL;LANsdwXDjLd*V(rc3rKJY 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 +==V=q@1-#nK4wq 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 z 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 z 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 literal 0 HcmV?d00001 diff --git a/openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/n022003l.pfb b/openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/n022003l.pfb new file mode 100644 index 0000000000000000000000000000000000000000..ecd871af7e4fa855bfcf30ea5b9d5bccaa40217d GIT binary patch literal 96263 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 OYy~)ed5oY3l$E%3$*32hhVb)29pVK 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 VI$FVaIsS2SwsZXBV`1tK`X6&nC|Cdh literal 0 HcmV?d00001 diff --git a/openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/n022004l.pfb b/openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/n022004l.pfb new file mode 100644 index 0000000000000000000000000000000000000000..da2d22c5e45d94cd68078452e2a8012295012963 GIT binary patch literal 120373 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%0AfbjZk-gm|Rwyq>IM{&IRoEU1B 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 literal 0 HcmV?d00001 diff --git a/openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/n022023l.pfb b/openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/n022023l.pfb new file mode 100644 index 0000000000000000000000000000000000000000..b0edaf25e0fa6da6b45a336bef5b49af84952a59 GIT binary patch literal 101133 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 literal 0 HcmV?d00001 diff --git a/openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/n022024l.pfb b/openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/n022024l.pfb new file mode 100644 index 0000000000000000000000000000000000000000..f32adb41c0dda34d7e67f9ac05df829fc9198709 GIT binary patch literal 114228 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%0AkLG=2b0;gh!lI*bxnSzKk)fghR(&aQ$N9 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 b*u~A!-q^(!#@EH%)y>hx+~3+F2=spd%iA{@ literal 0 HcmV?d00001 diff --git a/openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/s050000l.pfb b/openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/s050000l.pfb new file mode 100644 index 0000000000000000000000000000000000000000..3c1672306d175c2cd970446f383056af9aa8797d GIT binary patch literal 32213 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 A;Q#;t literal 0 HcmV?d00001 diff --git a/openpdf-pdfrenderer/src/test/java/PdfRendererToImageTest.java b/openpdf-pdfrenderer/src/test/java/PdfRendererToImageTest.java new file mode 100644 index 000000000..a9e0c0f70 --- /dev/null +++ b/openpdf-pdfrenderer/src/test/java/PdfRendererToImageTest.java @@ -0,0 +1,120 @@ +/* + * Copyright 2024 Andreas Røsdal. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'OpenPDF'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999-2008 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000-2008 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * https://github.com/LibrePDF/OpenPDF + */ + +import com.lowagie.text.Document; +import com.lowagie.text.DocumentException; +import com.lowagie.text.Paragraph; +import com.lowagie.text.pdf.PdfWriter; +import org.junit.jupiter.api.Test; +import com.sun.pdfview.PDFFile; +import com.sun.pdfview.PDFPage; +import com.sun.pdfview.PDFRenderer; + +import javax.imageio.ImageIO; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.nio.ByteBuffer; + +import static org.junit.jupiter.api.Assertions.assertNotNull; + +public class PdfRendererToImageTest { + + @Test + public void testPDFRenderToImage() throws DocumentException, IOException { + // Step 1: Create a sample PDF using OpenPDF + byte[] pdfBytes = createSamplePdf(); + + // Step 2: Load the PDF using PDFRenderer + PDFFile pdfFile = new PDFFile(ByteBuffer.wrap(pdfBytes)); + + // Ensure there is at least one page in the PDF + int numPages = pdfFile.getNumPages(); + assert(numPages > 0); + + // Use the correct page index (PDFRenderer typically uses 1-based indexing) + PDFPage page = pdfFile.getPage(1, true); // Fetch the first page + + // Step 3: Setup the dimensions for the output image + int width = (int) page.getBBox().getWidth(); + int height = (int) page.getBBox().getHeight(); + BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); + Graphics2D g2d = image.createGraphics(); + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); + + // Step 4: Render the page to the image + Rectangle rect = new Rectangle(0, 0, width, height); + PDFRenderer renderer = new PDFRenderer(page, g2d, rect, null, Color.WHITE); + renderer.run(); + + // Step 5: Save the image to a file (for verification) + File outputfile = new File("pdf-to-image-test-output.png"); + ImageIO.write(image, "png", outputfile); + + // Step 6: Assert that the image is not null + assertNotNull(image, "Image should not be null"); + + // Cleanup graphics object + g2d.dispose(); + } + + private byte[] createSamplePdf() throws DocumentException, IOException { + // Use OpenPDF to create a simple PDF in memory + Document document = new Document(); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + PdfWriter.getInstance(document, baos); + + document.open(); + document.add(new Paragraph("Hello, World! This is a test PDF.")); + document.close(); + + return baos.toByteArray(); + } +} diff --git a/pdf-swing/pom.xml b/pdf-swing/pom.xml index c794b5a60..daae6ea29 100644 --- a/pdf-swing/pom.xml +++ b/pdf-swing/pom.xml @@ -21,8 +21,9 @@ ${project.version} - org.swinglabs - pdf-renderer + com.github.librepdf + openpdf-pdfrenderer + ${project.version} org.dom4j diff --git a/pom.xml b/pom.xml index 2d65973e5..183ba65bb 100644 --- a/pom.xml +++ b/pom.xml @@ -50,6 +50,7 @@ pdf-swing pdf-toolbox openpdf-fonts-extra + openpdf-pdfrenderer @@ -136,11 +137,6 @@ jcommon ${jcommon.version} - - org.swinglabs - pdf-renderer - ${pdf-renderer.version} - org.dom4j dom4j From d5631dc1602117f194d73ec91603ca25678fb089 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20R=C3=B8sdal?= <41650711+andreasrosdal@users.noreply.github.com> Date: Sat, 17 Aug 2024 09:27:12 +0200 Subject: [PATCH 2/7] Add RegionPdfTextExtractor. --- .../text/pdf/parser/PdfTextExtractor.java | 6 +- .../parser/RegionPdfContentStreamHandler.java | 127 ++++++++++++++ .../pdf/parser/RegionPdfTextExtractor.java | 145 ++++++++++++++++ .../parser/RegionPdfTextExtractorTest.java | 163 ++++++++++++++++++ openpdf/src/test/resources/invoice-1.pdf | Bin 0 -> 41894 bytes 5 files changed, 438 insertions(+), 3 deletions(-) create mode 100644 openpdf/src/main/java/com/lowagie/text/pdf/parser/RegionPdfContentStreamHandler.java create mode 100644 openpdf/src/main/java/com/lowagie/text/pdf/parser/RegionPdfTextExtractor.java create mode 100644 openpdf/src/test/java/com/lowagie/text/pdf/parser/RegionPdfTextExtractorTest.java create mode 100644 openpdf/src/test/resources/invoice-1.pdf diff --git a/openpdf/src/main/java/com/lowagie/text/pdf/parser/PdfTextExtractor.java b/openpdf/src/main/java/com/lowagie/text/pdf/parser/PdfTextExtractor.java index 756ddc064..cd8c0e909 100644 --- a/openpdf/src/main/java/com/lowagie/text/pdf/parser/PdfTextExtractor.java +++ b/openpdf/src/main/java/com/lowagie/text/pdf/parser/PdfTextExtractor.java @@ -77,12 +77,12 @@ public class PdfTextExtractor { /** * The PdfReader that holds the PDF file. */ - private final PdfReader reader; + protected final PdfReader reader; /** * The {@link TextAssembler} that will receive render notifications and provide resultant text */ - private final TextAssembler renderListener; + protected final TextAssembler renderListener; /** * Creates a new Text Extractor object, using a {@link TextAssembler} as the render listener @@ -122,7 +122,7 @@ public PdfTextExtractor(PdfReader reader, TextAssembler renderListener) { * @return a byte array with the effective content stream of a page * @throws IOException */ - private byte[] getContentBytesForPage(int pageNum) throws IOException { + protected byte[] getContentBytesForPage(int pageNum) throws IOException { try (RandomAccessFileOrArray ignored = reader.getSafeFile()) { PdfDictionary pageDictionary = reader.getPageN(pageNum); PdfObject contentObject = pageDictionary.get(PdfName.CONTENTS); diff --git a/openpdf/src/main/java/com/lowagie/text/pdf/parser/RegionPdfContentStreamHandler.java b/openpdf/src/main/java/com/lowagie/text/pdf/parser/RegionPdfContentStreamHandler.java new file mode 100644 index 000000000..9d4ce4e94 --- /dev/null +++ b/openpdf/src/main/java/com/lowagie/text/pdf/parser/RegionPdfContentStreamHandler.java @@ -0,0 +1,127 @@ +/* + * Copyright 2024 OpenPDF + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'OpenPDF'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999-2008 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000-2008 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * https://github.com/LibrePDF/OpenPDF + */ +package com.lowagie.text.pdf.parser; + +import com.lowagie.text.pdf.PdfArray; +import com.lowagie.text.pdf.PdfDictionary; +import com.lowagie.text.pdf.PdfLiteral; +import com.lowagie.text.pdf.PdfNumber; +import com.lowagie.text.pdf.PdfObject; +import com.lowagie.text.pdf.PdfString; + +import java.awt.Rectangle; +import java.util.List; + +/** + * Stream handler for reading a specific part of a PDF document. + * + * @since 2.1.4 + */ +public class RegionPdfContentStreamHandler extends PdfContentStreamHandler { + private Rectangle boundingBox; + + public RegionPdfContentStreamHandler(TextAssembler renderListener) { + super(renderListener); + } + + /** + * Sets the bounding box to filter text extraction. If boundingBox is null, + * no filtering will be applied. + * 0,0 is in the bottom left part of the page. + */ + public void setBoundingBox(float x, float y, float width, float height) { + this.boundingBox = new Rectangle((int) x, (int) y, (int) width, (int) height); + } + + /** + * Overrides the invokeOperator method to include bounding box checking. + */ + @Override + public void invokeOperator(PdfLiteral operator, List operands, PdfDictionary resources) { + String op = operator.toString(); + + if ("Tj".equals(op)) { + // Single text string to show + PdfString text = (PdfString) operands.get(0); + float[] textPosition = getCurrentTextPosition(); + if (boundingBox == null || isWithinBoundingBox(textPosition[0], textPosition[1])) { + displayPdfString(text); + } + } else if ("TJ".equals(op)) { + // Array of text strings and positioning adjustments + PdfArray array = (PdfArray) operands.get(0); + float[] textPosition = getCurrentTextPosition(); + if (boundingBox == null || isWithinBoundingBox(textPosition[0], textPosition[1])) { + for (PdfObject obj : array.getElements()) { + if (obj instanceof PdfString) { + displayPdfString((PdfString) obj); + } else if (obj instanceof PdfNumber) { + applyTextAdjust(((PdfNumber) obj).floatValue()); + } + } + } + } else { + // Handle other operators as before + super.invokeOperator(operator, operands, resources); + } + } + + /** + * Checks if a text element is within the bounding box. + */ + private boolean isWithinBoundingBox(float textX, float textY) { + return boundingBox != null && boundingBox.contains(textX, textY); + } + + /** + * Method to get the current text position based on the text matrix. + */ + private float[] getCurrentTextPosition() { + Matrix textMatrix = getCurrentTextMatrix(); + return new float[]{textMatrix.get(Matrix.I31), textMatrix.get(Matrix.I32)}; + } +} \ No newline at end of file diff --git a/openpdf/src/main/java/com/lowagie/text/pdf/parser/RegionPdfTextExtractor.java b/openpdf/src/main/java/com/lowagie/text/pdf/parser/RegionPdfTextExtractor.java new file mode 100644 index 000000000..e0f0ac437 --- /dev/null +++ b/openpdf/src/main/java/com/lowagie/text/pdf/parser/RegionPdfTextExtractor.java @@ -0,0 +1,145 @@ +/* + * Copyright 2024 OpenPDF + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'OpenPDF'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999-2008 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000-2008 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * https://github.com/LibrePDF/OpenPDF + */ + +package com.lowagie.text.pdf.parser; + +import com.lowagie.text.pdf.*; + +import java.io.IOException; + +/** + * Extracts text from a specific region of a PDF file. + * + * @since 2.0.4 + */ +public class RegionPdfTextExtractor extends PdfTextExtractor { + + public RegionPdfTextExtractor(PdfReader reader) { + super(reader); + } + + public RegionPdfTextExtractor(PdfReader reader, TextAssembler renderListener) { + super(reader, renderListener); + } + + /** + * Extracts text from a specific area of a page of a PDF document. + * + * 0,0 is the bottom left part of the page. + */ + public String getTextFromPageArea(int page, float x, float y, float width, float height) throws IOException { + PdfDictionary pageDict = reader.getPageN(page); + if (pageDict == null) { + return ""; + } + PdfDictionary resources = pageDict.getAsDict(PdfName.RESOURCES); + + renderListener.reset(); + renderListener.setPage(page); + RegionPdfContentStreamHandler handler = new RegionPdfContentStreamHandler(renderListener); + handler.setBoundingBox(x, y, width, height); + processContent(getContentBytesForPage(page), resources, handler); + return handler.getResultantText(); + } + + /** + * Gets the height of the specified page. + */ + public float getPageHeight(int page) throws IOException { + PdfDictionary pageDict = reader.getPageN(page); + if (pageDict == null) { + throw new IOException("Page dictionary not found for page: " + page); + } + PdfArray mediaBox = pageDict.getAsArray(PdfName.MEDIABOX); + if (mediaBox == null || mediaBox.size() < 4) { + throw new IOException("MediaBox not found or invalid for page: " + page); + } + PdfNumber lowerLeftY = mediaBox.getAsNumber(1); + PdfNumber upperRightY = mediaBox.getAsNumber(3); + return upperRightY.floatValue() - lowerLeftY.floatValue(); + } + + /** + * Gets the width of the specified page. + */ + public float getPageWidth(int page) throws IOException { + PdfDictionary pageDict = reader.getPageN(page); + if (pageDict == null) { + throw new IOException("Page dictionary not found for page: " + page); + } + PdfArray mediaBox = pageDict.getAsArray(PdfName.MEDIABOX); + if (mediaBox == null || mediaBox.size() < 4) { + throw new IOException("MediaBox not found or invalid for page: " + page); + } + PdfNumber lowerLeftX = mediaBox.getAsNumber(0); + PdfNumber upperRightX = mediaBox.getAsNumber(2); + return upperRightX.floatValue() - lowerLeftX.floatValue(); + } + + public static String extractDateFromText(String text, String keyword) { + int keywordIndex = text.indexOf(keyword); + if (keywordIndex != -1) { + // Extract the date assuming it's after the keyword + String afterKeyword = text.substring(keywordIndex + keyword.length()).trim(); + String[] parts = afterKeyword.split("\\s+"); + if (parts.length > 0) { + // If the first part is not a valid date, continue searching + for (String part : parts) { + if (part.matches("\\d{4}-\\d{2}-\\d{2}")) { + return part; // Return the date in the format YYYY-MM-DD + } + } + } + } + return null; + } + + + public static String cleanExtractedText(String text) { + return text.replaceAll("\\s+", " ").trim(); + } +} diff --git a/openpdf/src/test/java/com/lowagie/text/pdf/parser/RegionPdfTextExtractorTest.java b/openpdf/src/test/java/com/lowagie/text/pdf/parser/RegionPdfTextExtractorTest.java new file mode 100644 index 000000000..ec1362593 --- /dev/null +++ b/openpdf/src/test/java/com/lowagie/text/pdf/parser/RegionPdfTextExtractorTest.java @@ -0,0 +1,163 @@ +/* + * Copyright 2024 Andreas Røsdal. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 + * (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + * + * The Original Code is 'OpenPDF'. + * + * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by + * the Initial Developer are Copyright (C) 1999-2008 by Bruno Lowagie. + * All Rights Reserved. + * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer + * are Copyright (C) 2000-2008 by Paulo Soares. All Rights Reserved. + * + * Contributor(s): all the names of the contributors are added in the source code + * where applicable. + * + * Alternatively, the contents of this file may be used under the terms of the + * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the + * provisions of LGPL are applicable instead of those above. If you wish to + * allow use of your version of this file only under the terms of the LGPL + * License and not to allow others to use your version of this file under + * the MPL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the LGPL. + * If you do not delete the provisions above, a recipient may use your version + * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MPL as stated above or under the terms of the GNU + * Library General Public License as published by the Free Software Foundation; + * either version 2 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more + * details. + * + * If you didn't download this code from the following link, you should check if + * you aren't using an obsolete version: + * https://github.com/LibrePDF/OpenPDF + */ + +package com.lowagie.text.pdf.parser; +import com.lowagie.text.pdf.PdfReader; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static org.junit.jupiter.api.Assertions.*; + +public class RegionPdfTextExtractorTest { + + private PdfReader pdfReader; + + @BeforeEach + public void setUp() throws Exception { + // Load the PDF file from the resources directory + InputStream inputStream = getClass().getClassLoader().getResourceAsStream("invoice-1.pdf"); + assertNotNull(inputStream, "PDF file not found in resources"); + pdfReader = new PdfReader(inputStream); + } + + @Test + public void testExtractInvoiceFields() throws Exception { + RegionPdfTextExtractor extractor = new RegionPdfTextExtractor(pdfReader); + float pageHeight = extractor.getPageHeight(1); + + // Extract the company name + float xCompanyName = 10.0f; + float yCompanyName = pageHeight - 70; + float widthCompanyName = 500.0f; + float heightCompanyName = 50.0f; + String companyName = extractor.getTextFromPageArea(1, xCompanyName, yCompanyName, widthCompanyName, heightCompanyName); + assertNotNull(companyName, "Company name should not be null"); + System.out.println("Company Name: " + companyName); + assertTrue(companyName.contains("Rør og Rygg Entreprenør AS"), "Extracted text should contain the company name"); + + // Adjusted extraction coordinates for the invoice number + float xInvoiceNumber = 10.0f; + float yInvoiceNumber = pageHeight - 250; + float widthInvoiceNumber = 500.0f; + float heightInvoiceNumber = 150.0f; + String invoiceNumberRegion = extractor.getTextFromPageArea(1, xInvoiceNumber, yInvoiceNumber, widthInvoiceNumber, heightInvoiceNumber); + assertNotNull(invoiceNumberRegion, "Invoice number region should not be null"); + System.out.println("Extracted Invoice Number Region Text: " + invoiceNumberRegion); + + // Check for invoice number + assertTrue(invoiceNumberRegion.contains("Fakturanr."), "Extracted text should contain the invoice number"); + + // Extract the invoice date + String invoiceDate = RegionPdfTextExtractor.extractDateFromText(invoiceNumberRegion, "Fakturadato"); + assertNotNull(invoiceDate, "Invoice date should not be null"); + System.out.println("Invoice Date: " + invoiceDate); + assertTrue(invoiceDate.contains("2024-04-04"), "Extracted text should contain the invoice date"); + + // Expand the search area for the due date + float xDueDate = 10.0f; + float yDueDate = pageHeight - 350; // Move down the Y-coordinate to cover more area + float widthDueDate = 500.0f; + float heightDueDate = 150.0f; // Increase the height to capture a larger area + String dueDateRegion = extractor.getTextFromPageArea(1, xDueDate, yDueDate, widthDueDate, heightDueDate); + assertNotNull(dueDateRegion, "Due date region should not be null"); + System.out.println("Extracted Due Date Region Text: " + dueDateRegion); + + // Extract the due date (enhanced) + String dueDate = RegionPdfTextExtractor.extractDateFromText(dueDateRegion, "Forfallsdato"); + assertNotNull(dueDate, "Due date should not be null"); + System.out.println("Due Date: " + dueDate); + assertTrue(dueDate.contains("2024-04-07"), "Extracted text should contain the due date"); + + // Extract the payable amount with a wider region and clean-up + float xAmount = 10.0f; + float yAmount = pageHeight - 500; + float widthAmount = 600.0f; + float heightAmount = 100.0f; + String amountRegion = extractor.getTextFromPageArea(1, xAmount, yAmount, widthAmount, heightAmount); + assertNotNull(amountRegion, "Amount region should not be null"); + System.out.println("Extracted Payable Amount Region Text: " + amountRegion); + + // Clean the extracted text + String cleanedAmountRegion = RegionPdfTextExtractor.cleanExtractedText(amountRegion); + + // Use regex to find all payable amounts + Pattern pattern = Pattern.compile("\\d{1,3}(?: \\d{3})*,\\d{2}"); + Matcher matcher = pattern.matcher(cleanedAmountRegion); + + List amounts = new ArrayList<>(); + while (matcher.find()) { + amounts.add(matcher.group()); + } + + // Ensure we have at least one amount + assertFalse(amounts.isEmpty(), "Extracted text should contain at least one payable amount"); + + // Find the correct payable amount by context or by matching the expected value + String expectedAmount = "44 139,26"; + String payableAmount = amounts.stream() + .filter(amount -> amount.equals(expectedAmount)) + .findFirst() + .orElse(null); + + assertNotNull(payableAmount, "Payable amount should not be null"); + System.out.println("Payable Amount: " + payableAmount); + assertTrue(payableAmount.equals(expectedAmount), "Extracted text should match the expected payable amount"); + + // Ensure the currency is present + assertTrue(cleanedAmountRegion.contains("NOK"), "Extracted text should contain the currency NOK"); + } + + + + +} \ No newline at end of file diff --git a/openpdf/src/test/resources/invoice-1.pdf b/openpdf/src/test/resources/invoice-1.pdf new file mode 100644 index 0000000000000000000000000000000000000000..9074e23b452db23d5affe956a5fd92263d6bb954 GIT binary patch literal 41894 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¨b6TvnC*+M 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 literal 0 HcmV?d00001 From 138341c93fc5a333955888e59e825382120b0b34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20R=C3=B8sdal?= <41650711+andreasrosdal@users.noreply.github.com> Date: Sat, 17 Aug 2024 09:37:33 +0200 Subject: [PATCH 3/7] Commends about openpdf-pdfrenderer. --- README.md | 3 +++ openpdf-pdfrenderer/README.md | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 56cd92c4f..63cb89623 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,7 @@ Some of the features of OpenPDF include: * Table Support: The library facilitates the creation of tables in PDF documents. * Encryption: You can encrypt PDF documents for security purposes. * Page Layout: OpenPDF allows you to set the page size, orientation, and other layout properties. +* Convert PDF files to images using [openpdf-pdfrenderer](openpdf-pdfrenderer). ## Use OpenPDF as Maven dependency @@ -69,6 +70,8 @@ Add this to your pom.xml file to use the latest version of OpenPDF: You can find also a nice explanation of these licenses under https://itsfoss.com/open-source-licenses-explained/ +openpdf-pdfrenderer is licensed with GNU Lesser General Public License (LGPL), Version 2.1 only. + We want OpenPDF to consist of source code which is consistently licensed with the LGPL and MPL licences only. This also means that any new contributions to the project must have a dual LGPL and MPL license only. diff --git a/openpdf-pdfrenderer/README.md b/openpdf-pdfrenderer/README.md index 680c5b0ea..c1643117e 100644 --- a/openpdf-pdfrenderer/README.md +++ b/openpdf-pdfrenderer/README.md @@ -9,7 +9,7 @@ License: GNU Lesser General Public License --- -This is a fork of [pdf-renderer](http://java.net/projects/pdf-renderer) (covered by the LGPL-2.1 license) for improvement purposes. +This is a fork of https://github.com/katjas/PDFrenderer which is based on [pdf-renderer](http://java.net/projects/pdf-renderer) (covered by the LGPL-2.1 license) for improvement purposes. The principal objective of the fork is to improve the original PDF renderer. The original version is able to handle most of the PDF 1.4 features, but has several bugs and missing functionality. From 618268fdda8b024a72702d3e5d538890a24214e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20R=C3=B8sdal?= <41650711+andreasrosdal@users.noreply.github.com> Date: Sat, 17 Aug 2024 09:57:47 +0200 Subject: [PATCH 4/7] Rename package to com.github.librepdf.pdfrenderer. --- .../librepdf/pdfrenderer}/BaseWatchable.java | 2 +- .../pdfrenderer}/ByteBufferInputStream.java | 2 +- .../librepdf/pdfrenderer}/Cache.java | 2 +- .../librepdf/pdfrenderer}/Configuration.java | 2 +- .../librepdf/pdfrenderer}/HexDump.java | 2 +- .../Identity8BitCharsetEncoder.java | 2 +- .../librepdf/pdfrenderer}/ImageInfo.java | 2 +- .../librepdf/pdfrenderer}/NameTree.java | 2 +- .../librepdf/pdfrenderer}/OutlineNode.java | 4 +-- .../librepdf/pdfrenderer}/PDFCmd.java | 2 +- .../librepdf/pdfrenderer}/PDFDebugger.java | 2 +- .../librepdf/pdfrenderer}/PDFDestination.java | 2 +- .../pdfrenderer}/PDFDocCharsetEncoder.java | 2 +- .../pdfrenderer}/PDFErrorHandler.java | 2 +- .../librepdf/pdfrenderer}/PDFFile.java | 24 +++++++------- .../librepdf/pdfrenderer}/PDFImage.java | 17 +++++----- .../pdfrenderer}/PDFImageParseException.java | 2 +- .../librepdf/pdfrenderer}/PDFObject.java | 8 ++--- .../librepdf/pdfrenderer}/PDFPage.java | 6 ++-- .../librepdf/pdfrenderer}/PDFPaint.java | 2 +- .../pdfrenderer}/PDFParseException.java | 2 +- .../librepdf/pdfrenderer}/PDFParser.java | 26 +++++++-------- .../librepdf/pdfrenderer}/PDFRenderer.java | 12 +++---- .../librepdf/pdfrenderer}/PDFShapeCmd.java | 2 +- .../librepdf/pdfrenderer}/PDFStringUtil.java | 2 +- .../librepdf/pdfrenderer}/PDFTextFormat.java | 6 ++-- .../librepdf/pdfrenderer}/PDFXref.java | 2 +- .../pdfrenderer}/PdfSubByteSampleModel.java | 2 +- .../librepdf/pdfrenderer}/RefImage.java | 2 +- .../librepdf/pdfrenderer}/Watchable.java | 2 +- .../pdfrenderer}/action/GoToAction.java | 8 ++--- .../pdfrenderer}/action/GoToEAction.java | 8 ++--- .../pdfrenderer}/action/GoToRAction.java | 6 ++-- .../pdfrenderer}/action/LaunchAction.java | 6 ++-- .../pdfrenderer}/action/PDFAction.java | 6 ++-- .../action/PdfObjectParseUtil.java | 8 ++--- .../pdfrenderer}/action/UriAction.java | 4 +-- .../annotation/AnnotationBorderStyle.java | 4 +-- .../annotation/AnnotationType.java | 4 +-- .../annotation/CircleAnnotation.java | 4 +-- .../annotation/FreetextAnnotation.java | 4 +-- .../annotation/LinkAnnotation.java | 12 +++---- .../annotation/MarkupAnnotation.java | 14 ++++---- .../annotation/PDFAnnotation.java | 9 +++--- .../annotation/SquareAnnotation.java | 4 +-- .../annotation/StampAnnotation.java | 6 ++-- .../annotation/TextMarkupAnnotation.java | 17 +++------- .../annotation/WidgetAnnotation.java | 14 ++++---- .../colorspace/AltColorSpace.java | 4 +-- .../colorspace/AlternateColorSpace.java | 6 ++-- .../colorspace/CMYKColorSpace.java | 2 +- .../pdfrenderer}/colorspace/CalGrayColor.java | 4 +-- .../pdfrenderer}/colorspace/CalRGBColor.java | 6 ++-- .../pdfrenderer}/colorspace/IndexedColor.java | 6 ++-- .../pdfrenderer}/colorspace/LabColor.java | 4 +-- .../colorspace/MaskColorSpace.java | 4 +-- .../colorspace/PDFColorSpace.java | 10 +++--- .../pdfrenderer}/colorspace/PatternSpace.java | 8 ++--- .../colorspace/YCCKColorSpace.java | 2 +- .../pdfrenderer}/colorspace/sGray.icc | Bin .../pdfrenderer}/decode/ASCII85Decode.java | 8 ++--- .../pdfrenderer}/decode/ASCIIHexDecode.java | 8 ++--- .../librepdf/pdfrenderer}/decode/CCITTCodes | 0 .../pdfrenderer}/decode/CCITTFaxDecode.java | 6 ++-- .../pdfrenderer}/decode/CCITTFaxDecoder.java | 2 +- .../pdfrenderer}/decode/DCTDecode.java | 6 ++-- .../pdfrenderer}/decode/FlateDecode.java | 6 ++-- .../pdfrenderer}/decode/ImageDataDecoder.java | 2 +- .../pdfrenderer}/decode/JPXDecode.java | 6 ++-- .../pdfrenderer}/decode/LZWDecode.java | 6 ++-- .../pdfrenderer}/decode/PDFDecoder.java | 8 ++--- .../pdfrenderer}/decode/PNGPredictor.java | 2 +- .../pdfrenderer}/decode/Predictor.java | 6 ++-- .../pdfrenderer}/decode/RunLengthDecode.java | 6 ++-- .../pdfrenderer}/decode/TIFFPredictor.java | 2 +- .../decrypt/CryptFilterDecrypter.java | 6 ++-- ...ryptionUnsupportedByPlatformException.java | 2 +- ...cryptionUnsupportedByProductException.java | 2 +- .../decrypt/IdentityDecrypter.java | 6 ++-- .../PDFAuthenticationFailureException.java | 4 +-- .../pdfrenderer}/decrypt/PDFDecrypter.java | 8 ++--- .../decrypt/PDFDecrypterFactory.java | 8 ++--- .../pdfrenderer}/decrypt/PDFPassword.java | 8 ++--- .../decrypt/StandardDecrypter.java | 8 ++--- .../UnsupportedEncryptionException.java | 2 +- .../pdfrenderer}/font/BuiltinFont.java | 6 ++-- .../pdfrenderer}/font/CIDFontType0.java | 8 ++--- .../pdfrenderer}/font/CIDFontType2.java | 4 +-- .../librepdf/pdfrenderer}/font/FlPoint.java | 2 +- .../pdfrenderer}/font/FontSupport.java | 2 +- .../pdfrenderer}/font/NativeFont.java | 30 +++++++++--------- .../pdfrenderer}/font/OutlineFont.java | 4 +-- .../librepdf/pdfrenderer}/font/PDFFont.java | 16 ++++------ .../pdfrenderer}/font/PDFFontDescriptor.java | 5 ++- .../pdfrenderer}/font/PDFFontEncoding.java | 9 +++--- .../librepdf/pdfrenderer}/font/PDFGlyph.java | 6 ++-- .../librepdf/pdfrenderer}/font/TTFFont.java | 26 +++++++-------- .../librepdf/pdfrenderer}/font/Type0Font.java | 6 ++-- .../pdfrenderer}/font/Type1CFont.java | 6 ++-- .../librepdf/pdfrenderer}/font/Type1Font.java | 8 ++--- .../librepdf/pdfrenderer}/font/Type3Font.java | 14 ++++---- .../pdfrenderer}/font/cid/PDFCMap.java | 6 ++-- .../pdfrenderer}/font/cid/ToUnicodeMap.java | 6 ++-- .../pdfrenderer}/font/ttf/AdobeGlyphList.java | 2 +- .../librepdf/pdfrenderer}/font/ttf/CMap.java | 4 +-- .../pdfrenderer}/font/ttf/CMapFormat0.java | 2 +- .../pdfrenderer}/font/ttf/CMapFormat4.java | 4 +-- .../pdfrenderer}/font/ttf/CMapFormat6.java | 2 +- .../pdfrenderer}/font/ttf/CmapTable.java | 4 +-- .../librepdf/pdfrenderer}/font/ttf/Glyf.java | 2 +- .../pdfrenderer}/font/ttf/GlyfCompound.java | 2 +- .../pdfrenderer}/font/ttf/GlyfSimple.java | 2 +- .../pdfrenderer}/font/ttf/GlyfTable.java | 2 +- .../pdfrenderer}/font/ttf/HeadTable.java | 2 +- .../pdfrenderer}/font/ttf/HheaTable.java | 2 +- .../pdfrenderer}/font/ttf/HmtxTable.java | 2 +- .../pdfrenderer}/font/ttf/LocaTable.java | 2 +- .../pdfrenderer}/font/ttf/MaxpTable.java | 2 +- .../pdfrenderer}/font/ttf/NameTable.java | 2 +- .../pdfrenderer}/font/ttf/PostTable.java | 4 +-- .../pdfrenderer}/font/ttf/TrueTypeFont.java | 6 ++-- .../pdfrenderer}/font/ttf/TrueTypeTable.java | 2 +- .../font/ttf/resource/glyphlist.txt | 0 .../pdfrenderer}/function/FunctionType0.java | 8 ++--- .../pdfrenderer}/function/FunctionType2.java | 6 ++-- .../pdfrenderer}/function/FunctionType3.java | 8 ++--- .../pdfrenderer}/function/FunctionType4.java | 10 +++--- .../pdfrenderer}/function/PDFFunction.java | 6 ++-- .../function/postscript/PostScriptParser.java | 2 +- .../function/postscript/operation/Abs.java | 2 +- .../function/postscript/operation/Add.java | 2 +- .../function/postscript/operation/And.java | 2 +- .../function/postscript/operation/Atan.java | 2 +- .../postscript/operation/Bitshift.java | 2 +- .../postscript/operation/Ceiling.java | 2 +- .../function/postscript/operation/Copy.java | 2 +- .../function/postscript/operation/Cvi.java | 2 +- .../function/postscript/operation/Cvr.java | 2 +- .../function/postscript/operation/Div.java | 2 +- .../function/postscript/operation/Dup.java | 2 +- .../function/postscript/operation/Eq.java | 2 +- .../function/postscript/operation/Exch.java | 2 +- .../function/postscript/operation/Exp.java | 2 +- .../postscript/operation/Expression.java | 2 +- .../function/postscript/operation/False.java | 2 +- .../function/postscript/operation/Floor.java | 2 +- .../function/postscript/operation/Ge.java | 2 +- .../function/postscript/operation/Gt.java | 2 +- .../function/postscript/operation/Idiv.java | 2 +- .../function/postscript/operation/If.java | 2 +- .../function/postscript/operation/IfElse.java | 2 +- .../function/postscript/operation/Index.java | 2 +- .../function/postscript/operation/Le.java | 2 +- .../function/postscript/operation/Ln.java | 2 +- .../function/postscript/operation/Log.java | 2 +- .../function/postscript/operation/Lt.java | 2 +- .../function/postscript/operation/Mod.java | 2 +- .../function/postscript/operation/Mul.java | 2 +- .../function/postscript/operation/Ne.java | 2 +- .../function/postscript/operation/Neg.java | 2 +- .../function/postscript/operation/Not.java | 2 +- .../postscript/operation/OperationSet.java | 2 +- .../function/postscript/operation/Or.java | 2 +- .../function/postscript/operation/Pop.java | 2 +- .../operation/PostScriptOperation.java | 2 +- .../postscript/operation/PushAsNumber.java | 4 +-- .../function/postscript/operation/Roll.java | 2 +- .../function/postscript/operation/Round.java | 2 +- .../function/postscript/operation/Sin.java | 2 +- .../function/postscript/operation/Sqrt.java | 2 +- .../function/postscript/operation/Sub.java | 2 +- .../function/postscript/operation/True.java | 2 +- .../postscript/operation/Truncate.java | 2 +- .../function/postscript/operation/Xor.java | 2 +- .../pdfrenderer}/pattern/DummyShader.java | 6 ++-- .../pdfrenderer}/pattern/PDFPattern.java | 8 ++--- .../pdfrenderer}/pattern/PDFShader.java | 11 +++---- .../pdfrenderer}/pattern/PatternType1.java | 12 +++---- .../pdfrenderer}/pattern/PatternType2.java | 6 ++-- .../pdfrenderer}/pattern/ShaderType2.java | 12 +++---- .../pdfrenderer}/pattern/ShaderType3.java | 14 ++++---- .../font/res/BaseFonts.properties | 0 .../pdfrenderer}/font/res/d050000l.pfb | Bin .../pdfrenderer}/font/res/n019003l.pfb | Bin .../pdfrenderer}/font/res/n019004l.pfb | Bin .../pdfrenderer}/font/res/n019023l.pfb | Bin .../pdfrenderer}/font/res/n019024l.pfb | Bin .../pdfrenderer}/font/res/n021003l.pfb | Bin .../pdfrenderer}/font/res/n021004l.pfb | Bin .../pdfrenderer}/font/res/n021023l.pfb | Bin .../pdfrenderer}/font/res/n021024l.pfb | Bin .../pdfrenderer}/font/res/n022003l.pfb | Bin .../pdfrenderer}/font/res/n022004l.pfb | Bin .../pdfrenderer}/font/res/n022023l.pfb | Bin .../pdfrenderer}/font/res/n022024l.pfb | Bin .../pdfrenderer}/font/res/s050000l.pfb | Bin .../src/test/java/PdfRendererToImageTest.java | 6 ++-- .../com/lowagie/rups/model/PageLoader.java | 4 +-- 198 files changed, 439 insertions(+), 455 deletions(-) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/BaseWatchable.java (99%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/ByteBufferInputStream.java (98%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/Cache.java (99%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/Configuration.java (99%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/HexDump.java (98%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/Identity8BitCharsetEncoder.java (97%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/ImageInfo.java (98%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/NameTree.java (99%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/OutlineNode.java (94%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/PDFCmd.java (97%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/PDFDebugger.java (99%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/PDFDestination.java (99%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/PDFDocCharsetEncoder.java (98%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/PDFErrorHandler.java (86%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/PDFFile.java (98%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/PDFImage.java (98%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/PDFImageParseException.java (90%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/PDFObject.java (99%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/PDFPage.java (99%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/PDFPaint.java (98%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/PDFParseException.java (96%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/PDFParser.java (99%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/PDFRenderer.java (99%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/PDFShapeCmd.java (99%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/PDFStringUtil.java (99%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/PDFTextFormat.java (98%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/PDFXref.java (99%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/PdfSubByteSampleModel.java (99%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/RefImage.java (97%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/Watchable.java (98%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/action/GoToAction.java (83%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/action/GoToEAction.java (97%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/action/GoToRAction.java (94%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/action/LaunchAction.java (99%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/action/PDFAction.java (95%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/action/PdfObjectParseUtil.java (94%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/action/UriAction.java (93%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/annotation/AnnotationBorderStyle.java (94%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/annotation/AnnotationType.java (96%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/annotation/CircleAnnotation.java (88%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/annotation/FreetextAnnotation.java (89%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/annotation/LinkAnnotation.java (88%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/annotation/MarkupAnnotation.java (95%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/annotation/PDFAnnotation.java (97%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/annotation/SquareAnnotation.java (88%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/annotation/StampAnnotation.java (92%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/annotation/TextMarkupAnnotation.java (83%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/annotation/WidgetAnnotation.java (96%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/colorspace/AltColorSpace.java (94%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/colorspace/AlternateColorSpace.java (94%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/colorspace/CMYKColorSpace.java (97%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/colorspace/CalGrayColor.java (97%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/colorspace/CalRGBColor.java (98%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/colorspace/IndexedColor.java (96%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/colorspace/LabColor.java (97%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/colorspace/MaskColorSpace.java (96%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/colorspace/PDFColorSpace.java (96%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/colorspace/PatternSpace.java (93%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/colorspace/YCCKColorSpace.java (98%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/colorspace/sGray.icc (100%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/decode/ASCII85Decode.java (95%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/decode/ASCIIHexDecode.java (94%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/decode/CCITTCodes (100%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/decode/CCITTFaxDecode.java (95%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/decode/CCITTFaxDecoder.java (99%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/decode/DCTDecode.java (95%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/decode/FlateDecode.java (95%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/decode/ImageDataDecoder.java (98%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/decode/JPXDecode.java (94%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/decode/LZWDecode.java (97%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/decode/PDFDecoder.java (97%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/decode/PNGPredictor.java (99%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/decode/Predictor.java (96%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/decode/RunLengthDecode.java (94%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/decode/TIFFPredictor.java (99%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/decrypt/CryptFilterDecrypter.java (97%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/decrypt/EncryptionUnsupportedByPlatformException.java (96%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/decrypt/EncryptionUnsupportedByProductException.java (96%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/decrypt/IdentityDecrypter.java (92%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/decrypt/PDFAuthenticationFailureException.java (92%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/decrypt/PDFDecrypter.java (95%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/decrypt/PDFDecrypterFactory.java (98%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/decrypt/PDFPassword.java (97%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/decrypt/StandardDecrypter.java (99%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/decrypt/UnsupportedEncryptionException.java (96%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/font/BuiltinFont.java (98%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/font/CIDFontType0.java (91%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/font/CIDFontType2.java (99%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/font/FlPoint.java (97%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/font/FontSupport.java (99%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/font/NativeFont.java (94%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/font/OutlineFont.java (98%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/font/PDFFont.java (97%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/font/PDFFontDescriptor.java (99%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/font/PDFFontEncoding.java (97%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/font/PDFGlyph.java (95%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/font/TTFFont.java (93%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/font/Type0Font.java (93%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/font/Type1CFont.java (99%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/font/Type1Font.java (99%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/font/Type3Font.java (94%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/font/cid/PDFCMap.java (95%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/font/cid/ToUnicodeMap.java (98%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/font/ttf/AdobeGlyphList.java (99%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/font/ttf/CMap.java (98%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/font/ttf/CMapFormat0.java (98%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/font/ttf/CMapFormat4.java (99%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/font/ttf/CMapFormat6.java (98%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/font/ttf/CmapTable.java (98%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/font/ttf/Glyf.java (99%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/font/ttf/GlyfCompound.java (99%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/font/ttf/GlyfSimple.java (99%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/font/ttf/GlyfTable.java (98%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/font/ttf/HeadTable.java (99%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/font/ttf/HheaTable.java (99%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/font/ttf/HmtxTable.java (98%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/font/ttf/LocaTable.java (98%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/font/ttf/MaxpTable.java (99%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/font/ttf/NameTable.java (99%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/font/ttf/PostTable.java (99%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/font/ttf/TrueTypeFont.java (98%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/font/ttf/TrueTypeTable.java (99%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/font/ttf/resource/glyphlist.txt (100%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/function/FunctionType0.java (98%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/function/FunctionType2.java (96%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/function/FunctionType3.java (96%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/function/FunctionType4.java (92%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/function/PDFFunction.java (98%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/function/postscript/PostScriptParser.java (96%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/function/postscript/operation/Abs.java (86%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/function/postscript/operation/Add.java (87%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/function/postscript/operation/And.java (87%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/function/postscript/operation/Atan.java (92%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/function/postscript/operation/Bitshift.java (91%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/function/postscript/operation/Ceiling.java (86%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/function/postscript/operation/Copy.java (97%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/function/postscript/operation/Cvi.java (93%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/function/postscript/operation/Cvr.java (92%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/function/postscript/operation/Div.java (89%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/function/postscript/operation/Dup.java (88%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/function/postscript/operation/Eq.java (95%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/function/postscript/operation/Exch.java (83%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/function/postscript/operation/Exp.java (90%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/function/postscript/operation/Expression.java (81%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/function/postscript/operation/False.java (85%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/function/postscript/operation/Floor.java (86%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/function/postscript/operation/Ge.java (93%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/function/postscript/operation/Gt.java (92%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/function/postscript/operation/Idiv.java (88%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/function/postscript/operation/If.java (89%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/function/postscript/operation/IfElse.java (92%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/function/postscript/operation/Index.java (82%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/function/postscript/operation/Le.java (93%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/function/postscript/operation/Ln.java (84%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/function/postscript/operation/Log.java (84%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/function/postscript/operation/Lt.java (92%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/function/postscript/operation/Mod.java (89%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/function/postscript/operation/Mul.java (88%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/function/postscript/operation/Ne.java (87%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/function/postscript/operation/Neg.java (87%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/function/postscript/operation/Not.java (87%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/function/postscript/operation/OperationSet.java (98%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/function/postscript/operation/Or.java (87%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/function/postscript/operation/Pop.java (72%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/function/postscript/operation/PostScriptOperation.java (75%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/function/postscript/operation/PushAsNumber.java (84%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/function/postscript/operation/Roll.java (93%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/function/postscript/operation/Round.java (88%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/function/postscript/operation/Sin.java (86%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/function/postscript/operation/Sqrt.java (85%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/function/postscript/operation/Sub.java (89%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/function/postscript/operation/True.java (85%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/function/postscript/operation/Truncate.java (87%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/function/postscript/operation/Xor.java (88%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/pattern/DummyShader.java (68%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/pattern/PDFPattern.java (94%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/pattern/PDFShader.java (96%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/pattern/PatternType1.java (97%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/pattern/PatternType2.java (92%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/pattern/ShaderType2.java (97%) rename openpdf-pdfrenderer/src/main/java/com/{sun/pdfview => github/librepdf/pdfrenderer}/pattern/ShaderType3.java (97%) rename openpdf-pdfrenderer/src/main/resources/com/{sun/pdfview => github/librepdf/pdfrenderer}/font/res/BaseFonts.properties (100%) rename openpdf-pdfrenderer/src/main/resources/com/{sun/pdfview => github/librepdf/pdfrenderer}/font/res/d050000l.pfb (100%) rename openpdf-pdfrenderer/src/main/resources/com/{sun/pdfview => github/librepdf/pdfrenderer}/font/res/n019003l.pfb (100%) rename openpdf-pdfrenderer/src/main/resources/com/{sun/pdfview => github/librepdf/pdfrenderer}/font/res/n019004l.pfb (100%) rename openpdf-pdfrenderer/src/main/resources/com/{sun/pdfview => github/librepdf/pdfrenderer}/font/res/n019023l.pfb (100%) rename openpdf-pdfrenderer/src/main/resources/com/{sun/pdfview => github/librepdf/pdfrenderer}/font/res/n019024l.pfb (100%) rename openpdf-pdfrenderer/src/main/resources/com/{sun/pdfview => github/librepdf/pdfrenderer}/font/res/n021003l.pfb (100%) rename openpdf-pdfrenderer/src/main/resources/com/{sun/pdfview => github/librepdf/pdfrenderer}/font/res/n021004l.pfb (100%) rename openpdf-pdfrenderer/src/main/resources/com/{sun/pdfview => github/librepdf/pdfrenderer}/font/res/n021023l.pfb (100%) rename openpdf-pdfrenderer/src/main/resources/com/{sun/pdfview => github/librepdf/pdfrenderer}/font/res/n021024l.pfb (100%) rename openpdf-pdfrenderer/src/main/resources/com/{sun/pdfview => github/librepdf/pdfrenderer}/font/res/n022003l.pfb (100%) rename openpdf-pdfrenderer/src/main/resources/com/{sun/pdfview => github/librepdf/pdfrenderer}/font/res/n022004l.pfb (100%) rename openpdf-pdfrenderer/src/main/resources/com/{sun/pdfview => github/librepdf/pdfrenderer}/font/res/n022023l.pfb (100%) rename openpdf-pdfrenderer/src/main/resources/com/{sun/pdfview => github/librepdf/pdfrenderer}/font/res/n022024l.pfb (100%) rename openpdf-pdfrenderer/src/main/resources/com/{sun/pdfview => github/librepdf/pdfrenderer}/font/res/s050000l.pfb (100%) diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/BaseWatchable.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/BaseWatchable.java similarity index 99% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/BaseWatchable.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/BaseWatchable.java index 6c79bbd50..34f7525f4 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/BaseWatchable.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/BaseWatchable.java @@ -16,7 +16,7 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview; +package com.github.librepdf.pdfrenderer; /** * An abstract implementation of the watchable interface, that is extended diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/ByteBufferInputStream.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/ByteBufferInputStream.java similarity index 98% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/ByteBufferInputStream.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/ByteBufferInputStream.java index 862870008..55f244e7d 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/ByteBufferInputStream.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/ByteBufferInputStream.java @@ -16,7 +16,7 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview; +package com.github.librepdf.pdfrenderer; import java.io.IOException; import java.io.InputStream; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/Cache.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/Cache.java similarity index 99% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/Cache.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/Cache.java index ec2a08df8..e0bf4b92f 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/Cache.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/Cache.java @@ -16,7 +16,7 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview; +package com.github.librepdf.pdfrenderer; import java.awt.image.BufferedImage; import java.lang.ref.SoftReference; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/Configuration.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/Configuration.java similarity index 99% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/Configuration.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/Configuration.java index e17bf3011..4c1d5c17c 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/Configuration.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/Configuration.java @@ -1,4 +1,4 @@ -package com.sun.pdfview; +package com.github.librepdf.pdfrenderer; /** * Since there is no context that is passed between the various classes that diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/HexDump.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/HexDump.java similarity index 98% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/HexDump.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/HexDump.java index 5421d78b4..def6ce790 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/HexDump.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/HexDump.java @@ -16,7 +16,7 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview; +package com.github.librepdf.pdfrenderer; import java.io.IOException; import java.io.RandomAccessFile; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/Identity8BitCharsetEncoder.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/Identity8BitCharsetEncoder.java similarity index 97% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/Identity8BitCharsetEncoder.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/Identity8BitCharsetEncoder.java index 75cfef220..5a039c826 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/Identity8BitCharsetEncoder.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/Identity8BitCharsetEncoder.java @@ -17,7 +17,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview; +package com.github.librepdf.pdfrenderer; import java.nio.charset.CharsetEncoder; import java.nio.charset.CoderResult; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/ImageInfo.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/ImageInfo.java similarity index 98% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/ImageInfo.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/ImageInfo.java index a17bdd4ac..60d04f66a 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/ImageInfo.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/ImageInfo.java @@ -16,7 +16,7 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview; +package com.github.librepdf.pdfrenderer; import java.awt.geom.Rectangle2D; import java.awt.Color; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/NameTree.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/NameTree.java similarity index 99% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/NameTree.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/NameTree.java index 8b41a2606..2ca215f6c 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/NameTree.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/NameTree.java @@ -18,7 +18,7 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview; +package com.github.librepdf.pdfrenderer; import java.io.IOException; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/OutlineNode.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/OutlineNode.java similarity index 94% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/OutlineNode.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/OutlineNode.java index 977527cac..ba70d1cf2 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/OutlineNode.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/OutlineNode.java @@ -16,11 +16,11 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview; +package com.github.librepdf.pdfrenderer; import javax.swing.tree.DefaultMutableTreeNode; -import com.sun.pdfview.action.PDFAction; +import com.github.librepdf.pdfrenderer.action.PDFAction; public class OutlineNode extends DefaultMutableTreeNode { // the name of this node diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFCmd.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/PDFCmd.java similarity index 97% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFCmd.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/PDFCmd.java index 3cb0f82ea..97de13f43 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFCmd.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/PDFCmd.java @@ -16,7 +16,7 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview; +package com.github.librepdf.pdfrenderer; import java.awt.geom.Rectangle2D; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFDebugger.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/PDFDebugger.java similarity index 99% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFDebugger.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/PDFDebugger.java index 92e23c2e0..9c3b3d883 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFDebugger.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/PDFDebugger.java @@ -1,4 +1,4 @@ -package com.sun.pdfview; +package com.github.librepdf.pdfrenderer; import java.awt.Rectangle; import java.awt.geom.GeneralPath; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFDestination.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/PDFDestination.java similarity index 99% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFDestination.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/PDFDestination.java index 18a5a2136..a3804d850 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFDestination.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/PDFDestination.java @@ -16,7 +16,7 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview; +package com.github.librepdf.pdfrenderer; import java.io.IOException; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFDocCharsetEncoder.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/PDFDocCharsetEncoder.java similarity index 98% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFDocCharsetEncoder.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/PDFDocCharsetEncoder.java index 03a3b186d..f067186e0 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFDocCharsetEncoder.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/PDFDocCharsetEncoder.java @@ -16,7 +16,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview; +package com.github.librepdf.pdfrenderer; import java.nio.ByteBuffer; import java.nio.CharBuffer; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFErrorHandler.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/PDFErrorHandler.java similarity index 86% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFErrorHandler.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/PDFErrorHandler.java index 64a10a246..833d6fe56 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFErrorHandler.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/PDFErrorHandler.java @@ -1,4 +1,4 @@ -package com.sun.pdfview; +package com.github.librepdf.pdfrenderer; /** * Simple class to handle exceptions - as default we just print the stack trace diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFFile.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/PDFFile.java similarity index 98% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFFile.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/PDFFile.java index 27cd2d8da..f77c83499 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFFile.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/PDFFile.java @@ -16,7 +16,7 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview; +package com.github.librepdf.pdfrenderer; import java.awt.geom.Rectangle2D; import java.io.IOException; @@ -29,17 +29,17 @@ import java.util.Map; import java.util.StringTokenizer; -import com.sun.pdfview.action.GoToAction; -import com.sun.pdfview.action.PDFAction; -import com.sun.pdfview.annotation.PDFAnnotation; -import com.sun.pdfview.decrypt.EncryptionUnsupportedByPlatformException; -import com.sun.pdfview.decrypt.EncryptionUnsupportedByProductException; -import com.sun.pdfview.decrypt.IdentityDecrypter; -import com.sun.pdfview.decrypt.PDFAuthenticationFailureException; -import com.sun.pdfview.decrypt.PDFDecrypter; -import com.sun.pdfview.decrypt.PDFDecrypterFactory; -import com.sun.pdfview.decrypt.PDFPassword; -import com.sun.pdfview.decrypt.UnsupportedEncryptionException; +import com.github.librepdf.pdfrenderer.action.GoToAction; +import com.github.librepdf.pdfrenderer.action.PDFAction; +import com.github.librepdf.pdfrenderer.annotation.PDFAnnotation; +import com.github.librepdf.pdfrenderer.decrypt.EncryptionUnsupportedByPlatformException; +import com.github.librepdf.pdfrenderer.decrypt.EncryptionUnsupportedByProductException; +import com.github.librepdf.pdfrenderer.decrypt.IdentityDecrypter; +import com.github.librepdf.pdfrenderer.decrypt.PDFAuthenticationFailureException; +import com.github.librepdf.pdfrenderer.decrypt.PDFDecrypter; +import com.github.librepdf.pdfrenderer.decrypt.PDFDecrypterFactory; +import com.github.librepdf.pdfrenderer.decrypt.PDFPassword; +import com.github.librepdf.pdfrenderer.decrypt.UnsupportedEncryptionException; /** * An encapsulation of a .pdf file. The methods of this class diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFImage.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/PDFImage.java similarity index 98% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFImage.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/PDFImage.java index c9f1fe0f9..6c426cf15 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFImage.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/PDFImage.java @@ -16,7 +16,7 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview; +package com.github.librepdf.pdfrenderer; import java.awt.Color; import java.awt.Graphics; @@ -56,16 +56,15 @@ import javax.imageio.metadata.IIOMetadata; import javax.imageio.metadata.IIOMetadataFormatImpl; +import com.github.librepdf.pdfrenderer.colorspace.AlternateColorSpace; +import com.github.librepdf.pdfrenderer.colorspace.IndexedColor; +import com.github.librepdf.pdfrenderer.colorspace.PDFColorSpace; +import com.github.librepdf.pdfrenderer.colorspace.YCCKColorSpace; +import com.github.librepdf.pdfrenderer.decode.PDFDecoder; +import com.github.librepdf.pdfrenderer.function.FunctionType0; import org.w3c.dom.Attr; import org.w3c.dom.Node; -import com.sun.pdfview.colorspace.AlternateColorSpace; -import com.sun.pdfview.colorspace.IndexedColor; -import com.sun.pdfview.colorspace.PDFColorSpace; -import com.sun.pdfview.colorspace.YCCKColorSpace; -import com.sun.pdfview.decode.PDFDecoder; -import com.sun.pdfview.function.FunctionType0; - /** * Encapsulates a PDF Image */ @@ -99,7 +98,7 @@ public class PDFImage { /** * Create an instance of a PDFImage - * @throws IOException if {@link PDFDecoder} throws one while evaluating if the image is a Jpeg + * @throws IOException if {@link PDFDecoder} throws one while evaluating if the image is a Jpeg */ protected PDFImage(PDFObject imageObj) throws IOException { this.imageObj = imageObj; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFImageParseException.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/PDFImageParseException.java similarity index 90% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFImageParseException.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/PDFImageParseException.java index 04facc5a4..dde56c72e 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFImageParseException.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/PDFImageParseException.java @@ -1,4 +1,4 @@ -package com.sun.pdfview; +package com.github.librepdf.pdfrenderer; import java.io.IOException; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFObject.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/PDFObject.java similarity index 99% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFObject.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/PDFObject.java index 81a11be07..6d4747711 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFObject.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/PDFObject.java @@ -16,7 +16,7 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview; +package com.github.librepdf.pdfrenderer; import java.io.IOException; import java.lang.ref.SoftReference; @@ -29,9 +29,9 @@ import java.util.Map; import java.util.Set; -import com.sun.pdfview.decode.PDFDecoder; -import com.sun.pdfview.decrypt.IdentityDecrypter; -import com.sun.pdfview.decrypt.PDFDecrypter; +import com.github.librepdf.pdfrenderer.decode.PDFDecoder; +import com.github.librepdf.pdfrenderer.decrypt.IdentityDecrypter; +import com.github.librepdf.pdfrenderer.decrypt.PDFDecrypter; /** * a class encapsulating all the possibilities of content for diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFPage.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/PDFPage.java similarity index 99% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFPage.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/PDFPage.java index ae44df772..c2d1a3c30 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFPage.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/PDFPage.java @@ -16,7 +16,7 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview; +package com.github.librepdf.pdfrenderer; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Dimension; @@ -36,8 +36,8 @@ import java.util.List; import java.util.Map; -import com.sun.pdfview.annotation.AnnotationType; -import com.sun.pdfview.annotation.PDFAnnotation; +import com.github.librepdf.pdfrenderer.annotation.AnnotationType; +import com.github.librepdf.pdfrenderer.annotation.PDFAnnotation; /** * A PDFPage encapsulates the parsed commands required to render a diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFPaint.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/PDFPaint.java similarity index 98% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFPaint.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/PDFPaint.java index c75a8179d..a5eef2d3b 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFPaint.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/PDFPaint.java @@ -16,7 +16,7 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview; +package com.github.librepdf.pdfrenderer; import java.awt.Color; import java.awt.Graphics2D; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFParseException.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/PDFParseException.java similarity index 96% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFParseException.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/PDFParseException.java index eefb190e4..c3464fd82 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFParseException.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/PDFParseException.java @@ -16,7 +16,7 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview; +package com.github.librepdf.pdfrenderer; import java.io.IOException; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFParser.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/PDFParser.java similarity index 99% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFParser.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/PDFParser.java index f11b42fb7..e80a294b3 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFParser.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/PDFParser.java @@ -16,7 +16,7 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview; +package com.github.librepdf.pdfrenderer; import static java.awt.geom.Path2D.WIND_EVEN_ODD; import java.awt.geom.AffineTransform; @@ -34,12 +34,12 @@ import java.util.HashMap; import java.util.Stack; -import com.sun.pdfview.PDFDebugger.DebugStopException; -import com.sun.pdfview.colorspace.PDFColorSpace; -import com.sun.pdfview.colorspace.PatternSpace; -import com.sun.pdfview.decode.PDFDecoder; -import com.sun.pdfview.font.PDFFont; -import com.sun.pdfview.pattern.PDFShader; +import com.github.librepdf.pdfrenderer.colorspace.PDFColorSpace; +import com.github.librepdf.pdfrenderer.colorspace.PatternSpace; +import com.github.librepdf.pdfrenderer.decode.PDFDecoder; +import com.github.librepdf.pdfrenderer.font.PDFFont; +import com.github.librepdf.pdfrenderer.pattern.PDFShader; +import com.github.librepdf.pdfrenderer.PDFDebugger.DebugStopException; /** * PDFParser is the class that parses a PDF content stream and @@ -450,17 +450,17 @@ public int iterate() throws Exception { this.cmds = this.pageRef.get(); if (this.cmds == null) { PDFDebugger.debug("Page gone. Stopping", 10); - return Watchable.STOPPED; + return STOPPED; } Object obj; try { obj = parseObject(); } catch (DebugStopException e) { - return Watchable.STOPPED; + return STOPPED; } // if there's nothing left to parse, we're done if (obj == null) { - return Watchable.COMPLETED; + return COMPLETED; } if (obj instanceof Tok) { // it's a command. figure out what to do. @@ -875,7 +875,7 @@ public int iterate() throws Exception { // release or reference to the page object, so that it can be // gc'd if it is no longer in use this.cmds = null; - return Watchable.RUNNING; + return RUNNING; } /** @@ -1033,7 +1033,7 @@ private void doXObject(PDFObject obj) throws IOException { private void doImage(PDFObject obj) throws IOException { if (!PDFDebugger.DISABLE_IMAGES) { if (PDFDebugger.DEBUG_IMAGES) { - final boolean jpegDecode = PDFDecoder.isLastFilter(obj, PDFDecoder.DCT_FILTERS); + final boolean jpegDecode = PDFDecoder.isLastFilter(obj, PDFDecoder.DCT_FILTERS); if (jpegDecode) { PDFDebugger.debug("Image is JPEG"); } else { @@ -1524,7 +1524,7 @@ public Object clone() { @Override protected void setStatus(int status) { - if(status == BaseWatchable.COMPLETED) { + if(status == COMPLETED) { if(!addAnnotation){ // corresponding push in constructor PDFPage this.cmds.addPop(); diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFRenderer.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/PDFRenderer.java similarity index 99% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFRenderer.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/PDFRenderer.java index 16f89a6a9..e74d8ae7b 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFRenderer.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/PDFRenderer.java @@ -16,7 +16,7 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview; +package com.github.librepdf.pdfrenderer; import java.awt.AlphaComposite; import java.awt.BasicStroke; @@ -705,7 +705,7 @@ public void setup() { public int iterate() throws Exception { // make sure we have a page to render if (this.page == null) { - return Watchable.COMPLETED; + return COMPLETED; } // check if this renderer is based on a weak reference to a graphics @@ -715,7 +715,7 @@ public int iterate() throws Exception { bi = this.imageRef.get(); if (bi == null) { PDFDebugger.debug("Image went away. Stopping"); - return Watchable.STOPPED; + return STOPPED; } this.g = bi.createGraphics(); @@ -725,9 +725,9 @@ public int iterate() throws Exception { // just return, but check if we'return really finished or not if (this.currentCommand >= this.page.getCommandCount()) { if (this.page.isFinished()) { - return Watchable.COMPLETED; + return COMPLETED; } else { - return Watchable.NEEDS_DATA; + return NEEDS_DATA; } } @@ -761,7 +761,7 @@ public int iterate() throws Exception { // if we need to stop, it will be caught at the start of the next // iteration. - return Watchable.RUNNING; + return RUNNING; } /** diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFShapeCmd.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/PDFShapeCmd.java similarity index 99% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFShapeCmd.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/PDFShapeCmd.java index 5f9932aef..64d22ebe6 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFShapeCmd.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/PDFShapeCmd.java @@ -16,7 +16,7 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview; +package com.github.librepdf.pdfrenderer; import java.awt.BasicStroke; import java.awt.geom.AffineTransform; import java.awt.geom.GeneralPath; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFStringUtil.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/PDFStringUtil.java similarity index 99% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFStringUtil.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/PDFStringUtil.java index 75a408f03..76961d790 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFStringUtil.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/PDFStringUtil.java @@ -16,7 +16,7 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview; +package com.github.librepdf.pdfrenderer; import java.io.*; import java.nio.CharBuffer; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFTextFormat.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/PDFTextFormat.java similarity index 98% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFTextFormat.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/PDFTextFormat.java index d6fab0774..8777dd252 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFTextFormat.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/PDFTextFormat.java @@ -16,7 +16,7 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview; +package com.github.librepdf.pdfrenderer; import java.awt.Color; import java.awt.geom.AffineTransform; @@ -25,8 +25,8 @@ import java.util.Iterator; import java.util.List; -import com.sun.pdfview.font.PDFFont; -import com.sun.pdfview.font.PDFGlyph; +import com.github.librepdf.pdfrenderer.font.PDFFont; +import com.github.librepdf.pdfrenderer.font.PDFGlyph; /** * a class encapsulating the text state diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFXref.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/PDFXref.java similarity index 99% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFXref.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/PDFXref.java index 74f66dd42..6f587e070 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PDFXref.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/PDFXref.java @@ -16,7 +16,7 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview; +package com.github.librepdf.pdfrenderer; import java.lang.ref.SoftReference; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PdfSubByteSampleModel.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/PdfSubByteSampleModel.java similarity index 99% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PdfSubByteSampleModel.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/PdfSubByteSampleModel.java index 16f286464..7e50ff6bb 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/PdfSubByteSampleModel.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/PdfSubByteSampleModel.java @@ -18,7 +18,7 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview; +package com.github.librepdf.pdfrenderer; import java.awt.image.DataBuffer; import java.awt.image.SampleModel; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/RefImage.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/RefImage.java similarity index 97% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/RefImage.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/RefImage.java index 07e645190..93cd087a7 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/RefImage.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/RefImage.java @@ -16,7 +16,7 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview; +package com.github.librepdf.pdfrenderer; import java.awt.Graphics2D; import java.awt.image.BufferedImage; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/Watchable.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/Watchable.java similarity index 98% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/Watchable.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/Watchable.java index f412e9ddd..1c2186e6f 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/Watchable.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/Watchable.java @@ -16,7 +16,7 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview; +package com.github.librepdf.pdfrenderer; /** * An interface for rendering or parsing, which can be stopped and started. diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/action/GoToAction.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/action/GoToAction.java similarity index 83% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/action/GoToAction.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/action/GoToAction.java index ebdcf0478..82cd91116 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/action/GoToAction.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/action/GoToAction.java @@ -1,10 +1,10 @@ -package com.sun.pdfview.action; +package com.github.librepdf.pdfrenderer.action; import java.io.IOException; -import com.sun.pdfview.PDFObject; -import com.sun.pdfview.PDFDestination; -import com.sun.pdfview.PDFParseException; +import com.github.librepdf.pdfrenderer.PDFObject; +import com.github.librepdf.pdfrenderer.PDFDestination; +import com.github.librepdf.pdfrenderer.PDFParseException; /** * An action which specifies going to a particular destination diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/action/GoToEAction.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/action/GoToEAction.java similarity index 97% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/action/GoToEAction.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/action/GoToEAction.java index 2ed4ef886..46c944845 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/action/GoToEAction.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/action/GoToEAction.java @@ -1,11 +1,11 @@ -package com.sun.pdfview.action; +package com.github.librepdf.pdfrenderer.action; import java.io.IOException; import java.util.ArrayList; -import com.sun.pdfview.PDFDestination; -import com.sun.pdfview.PDFObject; -import com.sun.pdfview.PDFParseException; +import com.github.librepdf.pdfrenderer.PDFDestination; +import com.github.librepdf.pdfrenderer.PDFObject; +import com.github.librepdf.pdfrenderer.PDFParseException; /***************************************************************************** * Action directing to a location within an embedded PDF document diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/action/GoToRAction.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/action/GoToRAction.java similarity index 94% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/action/GoToRAction.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/action/GoToRAction.java index e04d21624..515db6bfb 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/action/GoToRAction.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/action/GoToRAction.java @@ -1,9 +1,9 @@ -package com.sun.pdfview.action; +package com.github.librepdf.pdfrenderer.action; import java.io.IOException; -import com.sun.pdfview.PDFDestination; -import com.sun.pdfview.PDFObject; +import com.github.librepdf.pdfrenderer.PDFDestination; +import com.github.librepdf.pdfrenderer.PDFObject; /***************************************************************************** * Action directing to a location within another PDF document diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/action/LaunchAction.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/action/LaunchAction.java similarity index 99% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/action/LaunchAction.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/action/LaunchAction.java index 9b5a8640a..ccf928bfd 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/action/LaunchAction.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/action/LaunchAction.java @@ -1,9 +1,9 @@ -package com.sun.pdfview.action; +package com.github.librepdf.pdfrenderer.action; import java.io.IOException; -import com.sun.pdfview.PDFObject; -import com.sun.pdfview.PDFParseException; +import com.github.librepdf.pdfrenderer.PDFObject; +import com.github.librepdf.pdfrenderer.PDFParseException; /***************************************************************************** * Action for launching an application, mostly used to open a file. diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/action/PDFAction.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/action/PDFAction.java similarity index 95% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/action/PDFAction.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/action/PDFAction.java index 43e8c168e..6fdd01064 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/action/PDFAction.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/action/PDFAction.java @@ -17,12 +17,12 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.action; +package com.github.librepdf.pdfrenderer.action; import java.io.IOException; -import com.sun.pdfview.PDFObject; -import com.sun.pdfview.PDFParseException; +import com.github.librepdf.pdfrenderer.PDFObject; +import com.github.librepdf.pdfrenderer.PDFParseException; /** * The common super-class of all PDF actions. diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/action/PdfObjectParseUtil.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/action/PdfObjectParseUtil.java similarity index 94% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/action/PdfObjectParseUtil.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/action/PdfObjectParseUtil.java index 4d73fc659..3a51e8cb5 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/action/PdfObjectParseUtil.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/action/PdfObjectParseUtil.java @@ -1,10 +1,10 @@ -package com.sun.pdfview.action; +package com.github.librepdf.pdfrenderer.action; import java.io.IOException; -import com.sun.pdfview.PDFDestination; -import com.sun.pdfview.PDFObject; -import com.sun.pdfview.PDFParseException; +import com.github.librepdf.pdfrenderer.PDFDestination; +import com.github.librepdf.pdfrenderer.PDFObject; +import com.github.librepdf.pdfrenderer.PDFParseException; /***************************************************************************** * Utility class for parsing values from a PDFObject diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/action/UriAction.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/action/UriAction.java similarity index 93% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/action/UriAction.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/action/UriAction.java index 7eb5da9b6..6786da950 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/action/UriAction.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/action/UriAction.java @@ -1,8 +1,8 @@ -package com.sun.pdfview.action; +package com.github.librepdf.pdfrenderer.action; import java.io.IOException; -import com.sun.pdfview.PDFObject; +import com.github.librepdf.pdfrenderer.PDFObject; /***************************************************************************** * URI action, containing a web link diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/AnnotationBorderStyle.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/annotation/AnnotationBorderStyle.java similarity index 94% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/AnnotationBorderStyle.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/annotation/AnnotationBorderStyle.java index c69c97b51..93da4ba92 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/AnnotationBorderStyle.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/annotation/AnnotationBorderStyle.java @@ -1,8 +1,8 @@ -package com.sun.pdfview.annotation; +package com.github.librepdf.pdfrenderer.annotation; import java.io.IOException; -import com.sun.pdfview.PDFObject; +import com.github.librepdf.pdfrenderer.PDFObject; /** * Annotation border style diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/AnnotationType.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/annotation/AnnotationType.java similarity index 96% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/AnnotationType.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/annotation/AnnotationType.java index 1632ce8f1..97eaf9571 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/AnnotationType.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/annotation/AnnotationType.java @@ -1,6 +1,6 @@ -package com.sun.pdfview.annotation; +package com.github.librepdf.pdfrenderer.annotation; -import com.sun.pdfview.Configuration; +import com.github.librepdf.pdfrenderer.Configuration; /** * @author Bernd Rosstauscher diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/CircleAnnotation.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/annotation/CircleAnnotation.java similarity index 88% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/CircleAnnotation.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/annotation/CircleAnnotation.java index 2b55f2e85..df48b8cd2 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/CircleAnnotation.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/annotation/CircleAnnotation.java @@ -1,8 +1,8 @@ -package com.sun.pdfview.annotation; +package com.github.librepdf.pdfrenderer.annotation; import java.io.IOException; -import com.sun.pdfview.PDFObject; +import com.github.librepdf.pdfrenderer.PDFObject; /***************************************************************************** * PDF annotation for a circle diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/FreetextAnnotation.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/annotation/FreetextAnnotation.java similarity index 89% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/FreetextAnnotation.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/annotation/FreetextAnnotation.java index 193271491..d96cd18c6 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/FreetextAnnotation.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/annotation/FreetextAnnotation.java @@ -1,8 +1,8 @@ -package com.sun.pdfview.annotation; +package com.github.librepdf.pdfrenderer.annotation; import java.io.IOException; -import com.sun.pdfview.PDFObject; +import com.github.librepdf.pdfrenderer.PDFObject; /***************************************************************************** * PDF annotation describing a free text diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/LinkAnnotation.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/annotation/LinkAnnotation.java similarity index 88% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/LinkAnnotation.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/annotation/LinkAnnotation.java index 939d2ec0d..10a31ac29 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/LinkAnnotation.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/annotation/LinkAnnotation.java @@ -1,12 +1,12 @@ -package com.sun.pdfview.annotation; +package com.github.librepdf.pdfrenderer.annotation; import java.io.IOException; -import com.sun.pdfview.PDFDestination; -import com.sun.pdfview.PDFObject; -import com.sun.pdfview.PDFParseException; -import com.sun.pdfview.action.GoToAction; -import com.sun.pdfview.action.PDFAction; +import com.github.librepdf.pdfrenderer.PDFDestination; +import com.github.librepdf.pdfrenderer.PDFObject; +import com.github.librepdf.pdfrenderer.PDFParseException; +import com.github.librepdf.pdfrenderer.action.GoToAction; +import com.github.librepdf.pdfrenderer.action.PDFAction; /***************************************************************************** * PDF annotation describing a link to either a location within the current diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/MarkupAnnotation.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/annotation/MarkupAnnotation.java similarity index 95% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/MarkupAnnotation.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/annotation/MarkupAnnotation.java index fb1d055e1..fecb96abe 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/MarkupAnnotation.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/annotation/MarkupAnnotation.java @@ -1,4 +1,4 @@ -package com.sun.pdfview.annotation; +package com.github.librepdf.pdfrenderer.annotation; import java.awt.geom.AffineTransform; import java.awt.geom.Rectangle2D; @@ -8,12 +8,12 @@ import java.util.HashMap; import java.util.List; -import com.sun.pdfview.PDFCmd; -import com.sun.pdfview.PDFImage; -import com.sun.pdfview.PDFObject; -import com.sun.pdfview.PDFPage; -import com.sun.pdfview.PDFParseException; -import com.sun.pdfview.PDFParser; +import com.github.librepdf.pdfrenderer.PDFCmd; +import com.github.librepdf.pdfrenderer.PDFImage; +import com.github.librepdf.pdfrenderer.PDFObject; +import com.github.librepdf.pdfrenderer.PDFPage; +import com.github.librepdf.pdfrenderer.PDFParseException; +import com.github.librepdf.pdfrenderer.PDFParser; /***************************************************************************** * PDF annotation describing a all kind of "markup" annotations which are visible diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/PDFAnnotation.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/annotation/PDFAnnotation.java similarity index 97% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/PDFAnnotation.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/annotation/PDFAnnotation.java index 9832e7f82..fca3ea997 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/PDFAnnotation.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/annotation/PDFAnnotation.java @@ -1,4 +1,4 @@ -package com.sun.pdfview.annotation; +package com.github.librepdf.pdfrenderer.annotation; import java.awt.geom.AffineTransform; import java.awt.geom.Rectangle2D; @@ -9,10 +9,9 @@ import java.util.ArrayList; import java.util.List; -import com.sun.pdfview.Configuration; -import com.sun.pdfview.PDFCmd; -import com.sun.pdfview.PDFObject; -import com.sun.pdfview.PDFParseException; +import com.github.librepdf.pdfrenderer.PDFCmd; +import com.github.librepdf.pdfrenderer.PDFObject; +import com.github.librepdf.pdfrenderer.PDFParseException; /***************************************************************************** * Encapsulate a PDF annotation. This is only the super-class of PDF annotations, diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/SquareAnnotation.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/annotation/SquareAnnotation.java similarity index 88% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/SquareAnnotation.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/annotation/SquareAnnotation.java index 88f3a5b19..15f1c077d 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/SquareAnnotation.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/annotation/SquareAnnotation.java @@ -1,8 +1,8 @@ -package com.sun.pdfview.annotation; +package com.github.librepdf.pdfrenderer.annotation; import java.io.IOException; -import com.sun.pdfview.PDFObject; +import com.github.librepdf.pdfrenderer.PDFObject; /***************************************************************************** * PDF annotation for a square diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/StampAnnotation.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/annotation/StampAnnotation.java similarity index 92% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/StampAnnotation.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/annotation/StampAnnotation.java index 4d297fc42..b9d2f65a5 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/StampAnnotation.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/annotation/StampAnnotation.java @@ -1,10 +1,10 @@ -package com.sun.pdfview.annotation; +package com.github.librepdf.pdfrenderer.annotation; import java.io.IOException; import java.util.List; -import com.sun.pdfview.PDFCmd; -import com.sun.pdfview.PDFObject; +import com.github.librepdf.pdfrenderer.PDFCmd; +import com.github.librepdf.pdfrenderer.PDFObject; /***************************************************************************** * PDF annotation describing a stamp diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/TextMarkupAnnotation.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/annotation/TextMarkupAnnotation.java similarity index 83% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/TextMarkupAnnotation.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/annotation/TextMarkupAnnotation.java index 21d99d423..a8923c83d 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/TextMarkupAnnotation.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/annotation/TextMarkupAnnotation.java @@ -1,22 +1,15 @@ -package com.sun.pdfview.annotation; +package com.github.librepdf.pdfrenderer.annotation; import java.awt.Rectangle; -import java.awt.geom.AffineTransform; import java.awt.geom.GeneralPath; -import java.awt.geom.Rectangle2D; -import java.awt.geom.Rectangle2D.Float; import java.io.IOException; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import com.sun.pdfview.PDFCmd; -import com.sun.pdfview.PDFImage; -import com.sun.pdfview.PDFObject; -import com.sun.pdfview.PDFPage; -import com.sun.pdfview.PDFParseException; -import com.sun.pdfview.PDFParser; -import com.sun.pdfview.PDFShapeCmd; +import com.github.librepdf.pdfrenderer.PDFCmd; +import com.github.librepdf.pdfrenderer.PDFObject; +import com.github.librepdf.pdfrenderer.PDFPage; +import com.github.librepdf.pdfrenderer.PDFShapeCmd; /***************************************************************************** * PDF annotation describing a text markup: Highlight, Underline, Squiggle, StrikeOut diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/WidgetAnnotation.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/annotation/WidgetAnnotation.java similarity index 96% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/WidgetAnnotation.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/annotation/WidgetAnnotation.java index 21e4740ae..b63e8910f 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/annotation/WidgetAnnotation.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/annotation/WidgetAnnotation.java @@ -1,4 +1,4 @@ -package com.sun.pdfview.annotation; +package com.github.librepdf.pdfrenderer.annotation; import java.awt.geom.AffineTransform; import java.awt.geom.Rectangle2D; @@ -8,12 +8,12 @@ import java.util.HashMap; import java.util.List; -import com.sun.pdfview.PDFCmd; -import com.sun.pdfview.PDFImage; -import com.sun.pdfview.PDFObject; -import com.sun.pdfview.PDFPage; -import com.sun.pdfview.PDFParseException; -import com.sun.pdfview.PDFParser; +import com.github.librepdf.pdfrenderer.PDFCmd; +import com.github.librepdf.pdfrenderer.PDFImage; +import com.github.librepdf.pdfrenderer.PDFObject; +import com.github.librepdf.pdfrenderer.PDFPage; +import com.github.librepdf.pdfrenderer.PDFParseException; +import com.github.librepdf.pdfrenderer.PDFParser; /** * PDF annotation describing a widget. diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/AltColorSpace.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/colorspace/AltColorSpace.java similarity index 94% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/AltColorSpace.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/colorspace/AltColorSpace.java index f4c157cc1..0c795f14f 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/AltColorSpace.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/colorspace/AltColorSpace.java @@ -1,8 +1,8 @@ -package com.sun.pdfview.colorspace; +package com.github.librepdf.pdfrenderer.colorspace; import java.awt.color.ColorSpace; -import com.sun.pdfview.function.PDFFunction; +import com.github.librepdf.pdfrenderer.function.PDFFunction; /***************************************************************************** * Color Space implementation for handling the PDF AlternateColorSpace. diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/AlternateColorSpace.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/colorspace/AlternateColorSpace.java similarity index 94% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/AlternateColorSpace.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/colorspace/AlternateColorSpace.java index d0deab603..9df5dc937 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/AlternateColorSpace.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/colorspace/AlternateColorSpace.java @@ -17,12 +17,12 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.colorspace; +package com.github.librepdf.pdfrenderer.colorspace; import java.awt.color.ColorSpace; -import com.sun.pdfview.PDFPaint; -import com.sun.pdfview.function.PDFFunction; +import com.github.librepdf.pdfrenderer.PDFPaint; +import com.github.librepdf.pdfrenderer.function.PDFFunction; /** * A color space that uses another color space to return values, and a diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/CMYKColorSpace.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/colorspace/CMYKColorSpace.java similarity index 97% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/CMYKColorSpace.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/colorspace/CMYKColorSpace.java index e5345b112..1a297dfc6 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/CMYKColorSpace.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/colorspace/CMYKColorSpace.java @@ -1,4 +1,4 @@ -package com.sun.pdfview.colorspace; +package com.github.librepdf.pdfrenderer.colorspace; import java.awt.color.ColorSpace; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/CalGrayColor.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/colorspace/CalGrayColor.java similarity index 97% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/CalGrayColor.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/colorspace/CalGrayColor.java index 667707939..f7e1365a1 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/CalGrayColor.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/colorspace/CalGrayColor.java @@ -17,12 +17,12 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.colorspace; +package com.github.librepdf.pdfrenderer.colorspace; import java.awt.color.ColorSpace; import java.io.IOException; -import com.sun.pdfview.PDFObject; +import com.github.librepdf.pdfrenderer.PDFObject; /** * A ColorSpace for calibrated gray diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/CalRGBColor.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/colorspace/CalRGBColor.java similarity index 98% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/CalRGBColor.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/colorspace/CalRGBColor.java index 5c69689c5..b75dc705f 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/CalRGBColor.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/colorspace/CalRGBColor.java @@ -19,13 +19,13 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.colorspace; +package com.github.librepdf.pdfrenderer.colorspace; import java.awt.color.ColorSpace; import java.io.IOException; -import com.sun.pdfview.PDFObject; -import com.sun.pdfview.function.FunctionType0; +import com.github.librepdf.pdfrenderer.PDFObject; +import com.github.librepdf.pdfrenderer.function.FunctionType0; /** * A ColorSpace for calibrated RGB diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/IndexedColor.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/colorspace/IndexedColor.java similarity index 96% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/IndexedColor.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/colorspace/IndexedColor.java index e37d38815..efa9bfc30 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/IndexedColor.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/colorspace/IndexedColor.java @@ -16,13 +16,13 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.colorspace; +package com.github.librepdf.pdfrenderer.colorspace; import java.awt.Color; import java.io.IOException; -import com.sun.pdfview.PDFObject; -import com.sun.pdfview.PDFPaint; +import com.github.librepdf.pdfrenderer.PDFObject; +import com.github.librepdf.pdfrenderer.PDFPaint; /** * A PDFColorSpace for an IndexedColor model diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/LabColor.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/colorspace/LabColor.java similarity index 97% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/LabColor.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/colorspace/LabColor.java index 1f1ca1dbe..6a9f62f4f 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/LabColor.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/colorspace/LabColor.java @@ -17,12 +17,12 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.colorspace; +package com.github.librepdf.pdfrenderer.colorspace; import java.awt.color.ColorSpace; import java.io.IOException; -import com.sun.pdfview.PDFObject; +import com.github.librepdf.pdfrenderer.PDFObject; /** * A ColorSpace for Lab color diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/MaskColorSpace.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/colorspace/MaskColorSpace.java similarity index 96% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/MaskColorSpace.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/colorspace/MaskColorSpace.java index fb107c006..f8595fbb5 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/MaskColorSpace.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/colorspace/MaskColorSpace.java @@ -17,12 +17,12 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.colorspace; +package com.github.librepdf.pdfrenderer.colorspace; import java.awt.Color; import java.awt.color.ColorSpace; -import com.sun.pdfview.PDFPaint; +import com.github.librepdf.pdfrenderer.PDFPaint; /** * A color space used to implement masks. For now, the only type of mask diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/PDFColorSpace.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/colorspace/PDFColorSpace.java similarity index 96% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/PDFColorSpace.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/colorspace/PDFColorSpace.java index 5a0772470..f68520308 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/PDFColorSpace.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/colorspace/PDFColorSpace.java @@ -16,7 +16,7 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.colorspace; +package com.github.librepdf.pdfrenderer.colorspace; import java.awt.Color; import java.awt.color.ColorSpace; @@ -26,10 +26,10 @@ import java.io.IOException; import java.util.Map; -import com.sun.pdfview.PDFObject; -import com.sun.pdfview.PDFPaint; -import com.sun.pdfview.PDFParseException; -import com.sun.pdfview.function.PDFFunction; +import com.github.librepdf.pdfrenderer.PDFObject; +import com.github.librepdf.pdfrenderer.PDFPaint; +import com.github.librepdf.pdfrenderer.PDFParseException; +import com.github.librepdf.pdfrenderer.function.PDFFunction; /** diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/PatternSpace.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/colorspace/PatternSpace.java similarity index 93% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/PatternSpace.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/colorspace/PatternSpace.java index 784a3bc67..7c6b2c770 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/PatternSpace.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/colorspace/PatternSpace.java @@ -17,14 +17,14 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.colorspace; +package com.github.librepdf.pdfrenderer.colorspace; import java.io.IOException; import java.util.Map; -import com.sun.pdfview.PDFObject; -import com.sun.pdfview.PDFPaint; -import com.sun.pdfview.pattern.PDFPattern; +import com.github.librepdf.pdfrenderer.PDFObject; +import com.github.librepdf.pdfrenderer.PDFPaint; +import com.github.librepdf.pdfrenderer.pattern.PDFPattern; /** * A PatternSpace fills with a pattern, the name of which is diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/YCCKColorSpace.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/colorspace/YCCKColorSpace.java similarity index 98% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/YCCKColorSpace.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/colorspace/YCCKColorSpace.java index 659214775..50fabff05 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/YCCKColorSpace.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/colorspace/YCCKColorSpace.java @@ -17,7 +17,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.colorspace; +package com.github.librepdf.pdfrenderer.colorspace; import java.awt.color.ColorSpace; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/sGray.icc b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/colorspace/sGray.icc similarity index 100% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/colorspace/sGray.icc rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/colorspace/sGray.icc diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/ASCII85Decode.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decode/ASCII85Decode.java similarity index 95% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/ASCII85Decode.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decode/ASCII85Decode.java index fb1d4f166..aee628448 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/ASCII85Decode.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decode/ASCII85Decode.java @@ -15,14 +15,14 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.decode; +package com.github.librepdf.pdfrenderer.decode; import java.io.ByteArrayOutputStream; import java.nio.ByteBuffer; -import com.sun.pdfview.PDFFile; -import com.sun.pdfview.PDFObject; -import com.sun.pdfview.PDFParseException; +import com.github.librepdf.pdfrenderer.PDFFile; +import com.github.librepdf.pdfrenderer.PDFObject; +import com.github.librepdf.pdfrenderer.PDFParseException; /** * decode ASCII85 text into a byte array. diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/ASCIIHexDecode.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decode/ASCIIHexDecode.java similarity index 94% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/ASCIIHexDecode.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decode/ASCIIHexDecode.java index b3afacd00..b71baac08 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/ASCIIHexDecode.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decode/ASCIIHexDecode.java @@ -17,11 +17,11 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.decode; +package com.github.librepdf.pdfrenderer.decode; -import com.sun.pdfview.PDFFile; -import com.sun.pdfview.PDFObject; -import com.sun.pdfview.PDFParseException; +import com.github.librepdf.pdfrenderer.PDFFile; +import com.github.librepdf.pdfrenderer.PDFObject; +import com.github.librepdf.pdfrenderer.PDFParseException; import java.io.ByteArrayOutputStream; import java.nio.ByteBuffer; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/CCITTCodes b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decode/CCITTCodes similarity index 100% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/CCITTCodes rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decode/CCITTCodes diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/CCITTFaxDecode.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decode/CCITTFaxDecode.java similarity index 95% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/CCITTFaxDecode.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decode/CCITTFaxDecode.java index d6748a803..0a3a8b465 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/CCITTFaxDecode.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decode/CCITTFaxDecode.java @@ -1,10 +1,10 @@ -package com.sun.pdfview.decode; +package com.github.librepdf.pdfrenderer.decode; import java.io.IOException; import java.nio.ByteBuffer; -import com.sun.pdfview.PDFDebugger; -import com.sun.pdfview.PDFObject; +import com.github.librepdf.pdfrenderer.PDFDebugger; +import com.github.librepdf.pdfrenderer.PDFObject; public class CCITTFaxDecode { diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/CCITTFaxDecoder.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decode/CCITTFaxDecoder.java similarity index 99% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/CCITTFaxDecoder.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decode/CCITTFaxDecoder.java index 0cbfdc0c1..381485c56 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/CCITTFaxDecoder.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decode/CCITTFaxDecoder.java @@ -62,7 +62,7 @@ * You acknowledge that Software is not designed,licensed or intended for use in * the design, construction, operation or maintenance of any nuclear facility. */ -package com.sun.pdfview.decode; +package com.github.librepdf.pdfrenderer.decode; public class CCITTFaxDecoder { static int[] table1 = { 0x00, // 0 bits are left in first byte - SHOULD diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/DCTDecode.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decode/DCTDecode.java similarity index 95% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/DCTDecode.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decode/DCTDecode.java index ca56b9372..026c014e1 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/DCTDecode.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decode/DCTDecode.java @@ -1,4 +1,4 @@ -package com.sun.pdfview.decode; +package com.github.librepdf.pdfrenderer.decode; import java.awt.Image; import java.awt.Toolkit; @@ -11,8 +11,8 @@ import javax.imageio.ImageIO; import javax.swing.ImageIcon; -import com.sun.pdfview.PDFObject; -import com.sun.pdfview.PDFParseException; +import com.github.librepdf.pdfrenderer.PDFObject; +import com.github.librepdf.pdfrenderer.PDFParseException; /** * Decode a DCT encoded array into a byte array. This class uses Java's diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/FlateDecode.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decode/FlateDecode.java similarity index 95% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/FlateDecode.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decode/FlateDecode.java index 29354a101..16b4d0623 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/FlateDecode.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decode/FlateDecode.java @@ -16,7 +16,7 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.decode; +package com.github.librepdf.pdfrenderer.decode; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -24,8 +24,8 @@ import java.util.zip.DataFormatException; import java.util.zip.Inflater; -import com.sun.pdfview.PDFObject; -import com.sun.pdfview.PDFParseException; +import com.github.librepdf.pdfrenderer.PDFObject; +import com.github.librepdf.pdfrenderer.PDFParseException; /** * decode a deFlated byte array diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/ImageDataDecoder.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decode/ImageDataDecoder.java similarity index 98% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/ImageDataDecoder.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decode/ImageDataDecoder.java index f34b27483..b56623e87 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/ImageDataDecoder.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decode/ImageDataDecoder.java @@ -1,4 +1,4 @@ -package com.sun.pdfview.decode; +package com.github.librepdf.pdfrenderer.decode; import java.awt.Graphics; import java.awt.image.BufferedImage; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/JPXDecode.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decode/JPXDecode.java similarity index 94% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/JPXDecode.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decode/JPXDecode.java index 7750dcec9..5ddd549eb 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/JPXDecode.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decode/JPXDecode.java @@ -16,7 +16,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.decode; +package com.github.librepdf.pdfrenderer.decode; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; @@ -28,8 +28,8 @@ import javax.imageio.ImageReader; import javax.imageio.stream.MemoryCacheImageInputStream; -import com.sun.pdfview.PDFObject; -import com.sun.pdfview.PDFParseException; +import com.github.librepdf.pdfrenderer.PDFObject; +import com.github.librepdf.pdfrenderer.PDFParseException; /** * decode a JPX encoded imagestream into a byte array. This class uses Java's diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/LZWDecode.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decode/LZWDecode.java similarity index 97% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/LZWDecode.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decode/LZWDecode.java index 8200ca4c7..6cf708390 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/LZWDecode.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decode/LZWDecode.java @@ -16,14 +16,14 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.decode; +package com.github.librepdf.pdfrenderer.decode; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.nio.ByteBuffer; -import com.sun.pdfview.PDFObject; -import com.sun.pdfview.PDFParseException; +import com.github.librepdf.pdfrenderer.PDFObject; +import com.github.librepdf.pdfrenderer.PDFParseException; /** * decode an LZW-encoded array of bytes. LZW is a patented algorithm. diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/PDFDecoder.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decode/PDFDecoder.java similarity index 97% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/PDFDecoder.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decode/PDFDecoder.java index 49a135603..056143f60 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/PDFDecoder.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decode/PDFDecoder.java @@ -16,7 +16,7 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.decode; +package com.github.librepdf.pdfrenderer.decode; import java.io.IOException; import java.nio.ByteBuffer; @@ -24,9 +24,9 @@ import java.util.HashSet; import java.util.Set; -import com.sun.pdfview.PDFObject; -import com.sun.pdfview.PDFParseException; -import com.sun.pdfview.decrypt.PDFDecrypterFactory; +import com.github.librepdf.pdfrenderer.decrypt.PDFDecrypterFactory; +import com.github.librepdf.pdfrenderer.PDFObject; +import com.github.librepdf.pdfrenderer.PDFParseException; /** * A PDF Decoder encapsulates all the methods of decoding a stream of bytes diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/PNGPredictor.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decode/PNGPredictor.java similarity index 99% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/PNGPredictor.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decode/PNGPredictor.java index 116260173..8c5f40c05 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/PNGPredictor.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decode/PNGPredictor.java @@ -17,7 +17,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.decode; +package com.github.librepdf.pdfrenderer.decode; import java.nio.ByteBuffer; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/Predictor.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decode/Predictor.java similarity index 96% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/Predictor.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decode/Predictor.java index 4bd043e1f..97965fce6 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/Predictor.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decode/Predictor.java @@ -17,13 +17,13 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.decode; +package com.github.librepdf.pdfrenderer.decode; import java.io.IOException; import java.nio.ByteBuffer; -import com.sun.pdfview.PDFObject; -import com.sun.pdfview.PDFParseException; +import com.github.librepdf.pdfrenderer.PDFObject; +import com.github.librepdf.pdfrenderer.PDFParseException; /** * The abstract superclass of various predictor objects that undo well-known diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/RunLengthDecode.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decode/RunLengthDecode.java similarity index 94% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/RunLengthDecode.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decode/RunLengthDecode.java index 41ff6bf00..23414e162 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/RunLengthDecode.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decode/RunLengthDecode.java @@ -16,13 +16,13 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.decode; +package com.github.librepdf.pdfrenderer.decode; import java.io.ByteArrayOutputStream; import java.nio.ByteBuffer; -import com.sun.pdfview.PDFObject; -import com.sun.pdfview.PDFParseException; +import com.github.librepdf.pdfrenderer.PDFObject; +import com.github.librepdf.pdfrenderer.PDFParseException; /** * decode an array of Run Length encoded bytes into a byte array diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/TIFFPredictor.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decode/TIFFPredictor.java similarity index 99% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/TIFFPredictor.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decode/TIFFPredictor.java index 648431602..5e245cadb 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decode/TIFFPredictor.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decode/TIFFPredictor.java @@ -19,7 +19,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.decode; +package com.github.librepdf.pdfrenderer.decode; import java.io.IOException; import java.nio.ByteBuffer; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/CryptFilterDecrypter.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decrypt/CryptFilterDecrypter.java similarity index 97% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/CryptFilterDecrypter.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decrypt/CryptFilterDecrypter.java index 85e7a9d84..6c91c5e53 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/CryptFilterDecrypter.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decrypt/CryptFilterDecrypter.java @@ -17,13 +17,13 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.decrypt; +package com.github.librepdf.pdfrenderer.decrypt; import java.nio.ByteBuffer; import java.util.Map; -import com.sun.pdfview.PDFObject; -import com.sun.pdfview.PDFParseException; +import com.github.librepdf.pdfrenderer.PDFObject; +import com.github.librepdf.pdfrenderer.PDFParseException; /** * Implements Version 4 standard decryption, whereby the Encrypt dictionary diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/EncryptionUnsupportedByPlatformException.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decrypt/EncryptionUnsupportedByPlatformException.java similarity index 96% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/EncryptionUnsupportedByPlatformException.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decrypt/EncryptionUnsupportedByPlatformException.java index 433c4b809..0dbb9e914 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/EncryptionUnsupportedByPlatformException.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decrypt/EncryptionUnsupportedByPlatformException.java @@ -16,7 +16,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.decrypt; +package com.github.librepdf.pdfrenderer.decrypt; /** * Identifies that the specified encryption mechanism, though supported by the diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/EncryptionUnsupportedByProductException.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decrypt/EncryptionUnsupportedByProductException.java similarity index 96% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/EncryptionUnsupportedByProductException.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decrypt/EncryptionUnsupportedByProductException.java index 8e96b8c22..8fe14aab3 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/EncryptionUnsupportedByProductException.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decrypt/EncryptionUnsupportedByProductException.java @@ -17,7 +17,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.decrypt; +package com.github.librepdf.pdfrenderer.decrypt; /** * Identifies that the specified encryption mechanism is not diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/IdentityDecrypter.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decrypt/IdentityDecrypter.java similarity index 92% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/IdentityDecrypter.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decrypt/IdentityDecrypter.java index 517bbd90d..0b4b65ba9 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/IdentityDecrypter.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decrypt/IdentityDecrypter.java @@ -17,12 +17,12 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.decrypt; +package com.github.librepdf.pdfrenderer.decrypt; import java.nio.ByteBuffer; -import com.sun.pdfview.PDFObject; -import com.sun.pdfview.PDFParseException; +import com.github.librepdf.pdfrenderer.PDFObject; +import com.github.librepdf.pdfrenderer.PDFParseException; /** * Performs identity decryption; that is, inputs aren't encrypted and diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/PDFAuthenticationFailureException.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decrypt/PDFAuthenticationFailureException.java similarity index 92% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/PDFAuthenticationFailureException.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decrypt/PDFAuthenticationFailureException.java index 8d2fbd50c..d3ab8885a 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/PDFAuthenticationFailureException.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decrypt/PDFAuthenticationFailureException.java @@ -16,9 +16,9 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.decrypt; +package com.github.librepdf.pdfrenderer.decrypt; -import com.sun.pdfview.PDFParseException; +import com.github.librepdf.pdfrenderer.PDFParseException; /** * Identifies that the supplied password was incorrect or non-existent diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/PDFDecrypter.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decrypt/PDFDecrypter.java similarity index 95% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/PDFDecrypter.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decrypt/PDFDecrypter.java index 63144767b..002453907 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/PDFDecrypter.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decrypt/PDFDecrypter.java @@ -17,13 +17,13 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.decrypt; +package com.github.librepdf.pdfrenderer.decrypt; import java.nio.ByteBuffer; -import com.sun.pdfview.PDFObject; -import com.sun.pdfview.PDFParseException; -import com.sun.pdfview.PDFStringUtil; +import com.github.librepdf.pdfrenderer.PDFObject; +import com.github.librepdf.pdfrenderer.PDFParseException; +import com.github.librepdf.pdfrenderer.PDFStringUtil; /** * A decrypter decrypts streams and strings in a PDF document. {@link diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/PDFDecrypterFactory.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decrypt/PDFDecrypterFactory.java similarity index 98% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/PDFDecrypterFactory.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decrypt/PDFDecrypterFactory.java index 17742925d..9bfc40803 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/PDFDecrypterFactory.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decrypt/PDFDecrypterFactory.java @@ -16,15 +16,15 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.decrypt; +package com.github.librepdf.pdfrenderer.decrypt; import java.io.IOException; import java.util.HashMap; import java.util.Iterator; import java.util.Map; -import com.sun.pdfview.PDFObject; -import com.sun.pdfview.PDFParseException; +import com.github.librepdf.pdfrenderer.PDFObject; +import com.github.librepdf.pdfrenderer.PDFParseException; /** * Produces a {@link PDFDecrypter} for documents given a (possibly non-existent) @@ -59,7 +59,7 @@ public class PDFDecrypterFactory { * @return The decryptor that should be used for all encrypted data in the * PDF * @throws IOException will typically be a {@link - * com.sun.pdfview.PDFParseException}, indicating an IO problem, an error + * PDFParseException}, indicating an IO problem, an error * in the structure of the document, or a failure to obtain various ciphers * from the installed JCE providers * @throws EncryptionUnsupportedByPlatformException if the encryption diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/PDFPassword.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decrypt/PDFPassword.java similarity index 97% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/PDFPassword.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decrypt/PDFPassword.java index 7f953121b..9850155a2 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/PDFPassword.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decrypt/PDFPassword.java @@ -16,11 +16,11 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.decrypt; +package com.github.librepdf.pdfrenderer.decrypt; -import com.sun.pdfview.PDFDocCharsetEncoder; -import com.sun.pdfview.Identity8BitCharsetEncoder; -import com.sun.pdfview.PDFStringUtil; +import com.github.librepdf.pdfrenderer.PDFDocCharsetEncoder; +import com.github.librepdf.pdfrenderer.Identity8BitCharsetEncoder; +import com.github.librepdf.pdfrenderer.PDFStringUtil; import java.util.*; import java.nio.charset.CodingErrorAction; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/StandardDecrypter.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decrypt/StandardDecrypter.java similarity index 99% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/StandardDecrypter.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decrypt/StandardDecrypter.java index b67296e3c..8af610c56 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/StandardDecrypter.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decrypt/StandardDecrypter.java @@ -16,7 +16,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.decrypt; +package com.github.librepdf.pdfrenderer.decrypt; import java.io.IOException; import java.nio.ByteBuffer; @@ -38,9 +38,9 @@ import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; -import com.sun.pdfview.PDFObject; -import com.sun.pdfview.PDFParseException; -import com.sun.pdfview.PDFStringUtil; +import com.github.librepdf.pdfrenderer.PDFObject; +import com.github.librepdf.pdfrenderer.PDFParseException; +import com.github.librepdf.pdfrenderer.PDFStringUtil; /** * Standard simple decrypter for versions 1, 2 and 4 of the Standard diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/UnsupportedEncryptionException.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decrypt/UnsupportedEncryptionException.java similarity index 96% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/UnsupportedEncryptionException.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decrypt/UnsupportedEncryptionException.java index 62cd35ad2..6a00233b5 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/decrypt/UnsupportedEncryptionException.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/decrypt/UnsupportedEncryptionException.java @@ -17,7 +17,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.decrypt; +package com.github.librepdf.pdfrenderer.decrypt; /** * Identifies that the specified encryption mechanism is not diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/BuiltinFont.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/BuiltinFont.java similarity index 98% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/BuiltinFont.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/BuiltinFont.java index 99f149d4a..18ee364ef 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/BuiltinFont.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/BuiltinFont.java @@ -16,7 +16,7 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.font; +package com.github.librepdf.pdfrenderer.font; import java.awt.Font; import java.io.IOException; @@ -24,7 +24,7 @@ import java.util.Map; import java.util.Properties; -import com.sun.pdfview.PDFObject; +import com.github.librepdf.pdfrenderer.PDFObject; /** * This class represents the 14 built-in fonts. It reads these fonts @@ -177,7 +177,7 @@ private void parseFont(String baseFont) throws IOException { // load the base fonts properties files, if it isn't already loaded if (props == null) { props = new Properties(); - props.load(BuiltinFont.class.getResourceAsStream("/com/sun/pdfview/font/res/BaseFonts.properties")); + props.load(BuiltinFont.class.getResourceAsStream("/com/github/librepdf/pdfrenderer/font/res/BaseFonts.properties")); } // make sure we're a known font diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/CIDFontType0.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/CIDFontType0.java similarity index 91% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/CIDFontType0.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/CIDFontType0.java index f0eafee48..caa9a549f 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/CIDFontType0.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/CIDFontType0.java @@ -1,10 +1,10 @@ -package com.sun.pdfview.font; +package com.github.librepdf.pdfrenderer.font; import java.io.IOException; -import com.sun.pdfview.PDFObject; -import com.sun.pdfview.font.cid.PDFCMap; -import com.sun.pdfview.font.ttf.AdobeGlyphList; +import com.github.librepdf.pdfrenderer.font.cid.PDFCMap; +import com.github.librepdf.pdfrenderer.font.ttf.AdobeGlyphList; +import com.github.librepdf.pdfrenderer.PDFObject; /***************************************************************************** * At the moment this is not fully supported to parse CID based fonts diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/CIDFontType2.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/CIDFontType2.java similarity index 99% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/CIDFontType2.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/CIDFontType2.java index 17355e5a5..4e3bd166e 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/CIDFontType2.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/CIDFontType2.java @@ -16,7 +16,7 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.font; +package com.github.librepdf.pdfrenderer.font; import java.awt.geom.GeneralPath; import java.io.IOException; @@ -24,7 +24,7 @@ import java.util.HashMap; import java.util.Map; -import com.sun.pdfview.PDFObject; +import com.github.librepdf.pdfrenderer.PDFObject; /** * a font object derived from a CID font. diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/FlPoint.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/FlPoint.java similarity index 97% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/FlPoint.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/FlPoint.java index f68d5d72c..c25c31159 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/FlPoint.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/FlPoint.java @@ -17,7 +17,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.font; +package com.github.librepdf.pdfrenderer.font; /** * A floating-point Point, with public fields. Also contains a flag diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/FontSupport.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/FontSupport.java similarity index 99% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/FontSupport.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/FontSupport.java index c6f767933..ad9553cef 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/FontSupport.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/FontSupport.java @@ -16,7 +16,7 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.font; +package com.github.librepdf.pdfrenderer.font; /** * some constants and utility functions for font support. diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/NativeFont.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/NativeFont.java similarity index 94% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/NativeFont.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/NativeFont.java index a79b6c3f2..64ad790b4 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/NativeFont.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/NativeFont.java @@ -16,7 +16,7 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.font; +package com.github.librepdf.pdfrenderer.font; import java.awt.Font; import java.awt.FontFormatException; @@ -29,20 +29,20 @@ import java.io.IOException; import java.nio.ByteBuffer; -import com.sun.pdfview.BaseWatchable; -import com.sun.pdfview.PDFDebugger; -import com.sun.pdfview.PDFObject; -import com.sun.pdfview.PDFParseException; -import com.sun.pdfview.font.ttf.CMap; -import com.sun.pdfview.font.ttf.CMapFormat0; -import com.sun.pdfview.font.ttf.CMapFormat4; -import com.sun.pdfview.font.ttf.CmapTable; -import com.sun.pdfview.font.ttf.HeadTable; -import com.sun.pdfview.font.ttf.HmtxTable; -import com.sun.pdfview.font.ttf.NameTable; -import com.sun.pdfview.font.ttf.PostTable; -import com.sun.pdfview.font.ttf.TrueTypeFont; -import com.sun.pdfview.font.ttf.TrueTypeTable; +import com.github.librepdf.pdfrenderer.BaseWatchable; +import com.github.librepdf.pdfrenderer.PDFDebugger; +import com.github.librepdf.pdfrenderer.PDFObject; +import com.github.librepdf.pdfrenderer.PDFParseException; +import com.github.librepdf.pdfrenderer.font.ttf.CMap; +import com.github.librepdf.pdfrenderer.font.ttf.CMapFormat0; +import com.github.librepdf.pdfrenderer.font.ttf.CMapFormat4; +import com.github.librepdf.pdfrenderer.font.ttf.CmapTable; +import com.github.librepdf.pdfrenderer.font.ttf.HeadTable; +import com.github.librepdf.pdfrenderer.font.ttf.HmtxTable; +import com.github.librepdf.pdfrenderer.font.ttf.NameTable; +import com.github.librepdf.pdfrenderer.font.ttf.PostTable; +import com.github.librepdf.pdfrenderer.font.ttf.TrueTypeFont; +import com.github.librepdf.pdfrenderer.font.ttf.TrueTypeTable; /** * a font object derived from a true type font. diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/OutlineFont.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/OutlineFont.java similarity index 98% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/OutlineFont.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/OutlineFont.java index 3c0024b42..d8d08a58a 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/OutlineFont.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/OutlineFont.java @@ -16,13 +16,13 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.font; +package com.github.librepdf.pdfrenderer.font; import java.awt.geom.GeneralPath; import java.awt.geom.Point2D; import java.io.IOException; -import com.sun.pdfview.PDFObject; +import com.github.librepdf.pdfrenderer.PDFObject; /** * Supports width operations for Type1, Type1C, TrueType and Type3 fonts diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/PDFFont.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/PDFFont.java similarity index 97% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/PDFFont.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/PDFFont.java index 2ed2aef58..5c132cfbd 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/PDFFont.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/PDFFont.java @@ -16,7 +16,7 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.font; +package com.github.librepdf.pdfrenderer.font; import java.io.File; import java.io.FilenameFilter; @@ -29,14 +29,12 @@ import java.util.Map; import java.util.regex.Pattern; -import com.sun.pdfview.BaseWatchable; -import com.sun.pdfview.PDFDebugger; -import com.sun.pdfview.PDFObject; -import com.sun.pdfview.PDFParseException; -import com.sun.pdfview.PDFRenderer; -import com.sun.pdfview.font.cid.PDFCMap; -import com.sun.pdfview.font.cid.ToUnicodeMap; -import com.sun.pdfview.font.ttf.TrueTypeFont; +import com.github.librepdf.pdfrenderer.font.cid.PDFCMap; +import com.github.librepdf.pdfrenderer.font.ttf.TrueTypeFont; +import com.github.librepdf.pdfrenderer.BaseWatchable; +import com.github.librepdf.pdfrenderer.PDFDebugger; +import com.github.librepdf.pdfrenderer.PDFObject; +import com.github.librepdf.pdfrenderer.PDFParseException; /** * a Font definition for PDF files diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/PDFFontDescriptor.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/PDFFontDescriptor.java similarity index 99% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/PDFFontDescriptor.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/PDFFontDescriptor.java index 84763ff86..40fe06439 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/PDFFontDescriptor.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/PDFFontDescriptor.java @@ -16,13 +16,12 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.font; +package com.github.librepdf.pdfrenderer.font; import java.awt.geom.Rectangle2D; import java.io.IOException; -import com.sun.pdfview.PDFObject; -import com.sun.pdfview.PDFParser; +import com.github.librepdf.pdfrenderer.PDFObject; /** * diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/PDFFontEncoding.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/PDFFontEncoding.java similarity index 97% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/PDFFontEncoding.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/PDFFontEncoding.java index a0b7b3af2..c15fb6aa2 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/PDFFontEncoding.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/PDFFontEncoding.java @@ -16,7 +16,7 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.font; +package com.github.librepdf.pdfrenderer.font; import java.io.IOException; import java.util.ArrayList; @@ -24,10 +24,9 @@ import java.util.List; import java.util.Map; -import com.sun.pdfview.PDFDebugger; -import com.sun.pdfview.PDFObject; -import com.sun.pdfview.PDFRenderer; -import com.sun.pdfview.font.cid.PDFCMap; +import com.github.librepdf.pdfrenderer.font.cid.PDFCMap; +import com.github.librepdf.pdfrenderer.PDFObject; +import com.github.librepdf.pdfrenderer.PDFRenderer; /** * The PDFFont encoding encapsulates the mapping from character codes diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/PDFGlyph.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/PDFGlyph.java similarity index 95% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/PDFGlyph.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/PDFGlyph.java index 9452db286..6777911b4 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/PDFGlyph.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/PDFGlyph.java @@ -16,14 +16,14 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.font; +package com.github.librepdf.pdfrenderer.font; import java.awt.geom.AffineTransform; import java.awt.geom.GeneralPath; import java.awt.geom.Point2D; -import com.sun.pdfview.PDFPage; -import com.sun.pdfview.PDFShapeCmd; +import com.github.librepdf.pdfrenderer.PDFPage; +import com.github.librepdf.pdfrenderer.PDFShapeCmd; /** * A single glyph in a stream of PDF text, which knows how to write itself diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/TTFFont.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/TTFFont.java similarity index 93% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/TTFFont.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/TTFFont.java index 05f0ecb99..d326568ee 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/TTFFont.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/TTFFont.java @@ -16,7 +16,7 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.font; +package com.github.librepdf.pdfrenderer.font; import java.awt.geom.AffineTransform; import java.awt.geom.GeneralPath; @@ -27,18 +27,18 @@ import java.nio.channels.FileChannel; import java.util.Collection; -import com.sun.pdfview.PDFObject; -import com.sun.pdfview.font.ttf.AdobeGlyphList; -import com.sun.pdfview.font.ttf.CMap; -import com.sun.pdfview.font.ttf.CmapTable; -import com.sun.pdfview.font.ttf.Glyf; -import com.sun.pdfview.font.ttf.GlyfCompound; -import com.sun.pdfview.font.ttf.GlyfSimple; -import com.sun.pdfview.font.ttf.GlyfTable; -import com.sun.pdfview.font.ttf.HeadTable; -import com.sun.pdfview.font.ttf.HmtxTable; -import com.sun.pdfview.font.ttf.PostTable; -import com.sun.pdfview.font.ttf.TrueTypeFont; +import com.github.librepdf.pdfrenderer.PDFObject; +import com.github.librepdf.pdfrenderer.font.ttf.AdobeGlyphList; +import com.github.librepdf.pdfrenderer.font.ttf.CMap; +import com.github.librepdf.pdfrenderer.font.ttf.CmapTable; +import com.github.librepdf.pdfrenderer.font.ttf.Glyf; +import com.github.librepdf.pdfrenderer.font.ttf.GlyfCompound; +import com.github.librepdf.pdfrenderer.font.ttf.GlyfSimple; +import com.github.librepdf.pdfrenderer.font.ttf.GlyfTable; +import com.github.librepdf.pdfrenderer.font.ttf.HeadTable; +import com.github.librepdf.pdfrenderer.font.ttf.HmtxTable; +import com.github.librepdf.pdfrenderer.font.ttf.PostTable; +import com.github.librepdf.pdfrenderer.font.ttf.TrueTypeFont; /** * A true-type font diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/Type0Font.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/Type0Font.java similarity index 93% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/Type0Font.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/Type0Font.java index be732831e..667e4af55 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/Type0Font.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/Type0Font.java @@ -17,11 +17,11 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.font; +package com.github.librepdf.pdfrenderer.font; import java.io.IOException; -import com.sun.pdfview.PDFObject; +import com.github.librepdf.pdfrenderer.PDFObject; /** * Type 0 fonts are composite fonts with a CMAP to map between @@ -46,7 +46,7 @@ public Type0Font(String baseFont, PDFObject fontObj, this.fonts = new PDFFont[descendantFonts.length]; for (int i = 0; i < descendantFonts.length; i++) { - PDFFont descFont = PDFFont.getFont(descendantFonts[i], null); + PDFFont descFont = getFont(descendantFonts[i], null); if (descFont instanceof CIDFontType0) { ((CIDFontType0)descFont).parseToUnicodeMap(fontObj); } diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/Type1CFont.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/Type1CFont.java similarity index 99% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/Type1CFont.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/Type1CFont.java index a5368590f..048b3f761 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/Type1CFont.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/Type1CFont.java @@ -16,15 +16,15 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.font; +package com.github.librepdf.pdfrenderer.font; import java.awt.geom.AffineTransform; import java.awt.geom.GeneralPath; import java.awt.geom.NoninvertibleTransformException; import java.io.IOException; -import com.sun.pdfview.PDFDebugger; -import com.sun.pdfview.PDFObject; +import com.github.librepdf.pdfrenderer.PDFDebugger; +import com.github.librepdf.pdfrenderer.PDFObject; /** * A representation, with parser, of an Adobe Type 1C font. diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/Type1Font.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/Type1Font.java similarity index 99% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/Type1Font.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/Type1Font.java index 835c3c04c..91d166c44 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/Type1Font.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/Type1Font.java @@ -16,7 +16,7 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.font; +package com.github.librepdf.pdfrenderer.font; import java.awt.geom.AffineTransform; import java.awt.geom.GeneralPath; @@ -27,9 +27,9 @@ import java.util.Map; import java.util.TreeMap; -import com.sun.pdfview.PDFDebugger; -import com.sun.pdfview.PDFFile; -import com.sun.pdfview.PDFObject; +import com.github.librepdf.pdfrenderer.PDFDebugger; +import com.github.librepdf.pdfrenderer.PDFFile; +import com.github.librepdf.pdfrenderer.PDFObject; /** * A representation, with parser, of an Adobe Type 1 font. diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/Type3Font.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/Type3Font.java similarity index 94% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/Type3Font.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/Type3Font.java index 5ff41d724..d77565797 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/Type3Font.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/Type3Font.java @@ -16,7 +16,7 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.font; +package com.github.librepdf.pdfrenderer.font; import java.awt.geom.AffineTransform; import java.awt.geom.GeneralPath; @@ -26,12 +26,12 @@ import java.util.HashMap; import java.util.Map; -import com.sun.pdfview.BaseWatchable; -import com.sun.pdfview.PDFDebugger; -import com.sun.pdfview.PDFFile; -import com.sun.pdfview.PDFObject; -import com.sun.pdfview.PDFPage; -import com.sun.pdfview.PDFParser; +import com.github.librepdf.pdfrenderer.BaseWatchable; +import com.github.librepdf.pdfrenderer.PDFDebugger; +import com.github.librepdf.pdfrenderer.PDFFile; +import com.github.librepdf.pdfrenderer.PDFObject; +import com.github.librepdf.pdfrenderer.PDFPage; +import com.github.librepdf.pdfrenderer.PDFParser; /** * A Type 3 Font, in which each glyph consists of a sequence of PDF diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/cid/PDFCMap.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/cid/PDFCMap.java similarity index 95% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/cid/PDFCMap.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/cid/PDFCMap.java index b2f719548..9d5a0bd22 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/cid/PDFCMap.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/cid/PDFCMap.java @@ -16,13 +16,13 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.font.cid; +package com.github.librepdf.pdfrenderer.font.cid; import java.io.IOException; import java.util.HashMap; -import com.sun.pdfview.PDFDebugger; -import com.sun.pdfview.PDFObject; +import com.github.librepdf.pdfrenderer.PDFDebugger; +import com.github.librepdf.pdfrenderer.PDFObject; /** * A CMap maps from a character in a composite font to a font/glyph number diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/cid/ToUnicodeMap.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/cid/ToUnicodeMap.java similarity index 98% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/cid/ToUnicodeMap.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/cid/ToUnicodeMap.java index 86bf865c5..f26ad94c9 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/cid/ToUnicodeMap.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/cid/ToUnicodeMap.java @@ -1,4 +1,4 @@ -package com.sun.pdfview.font.cid; +package com.github.librepdf.pdfrenderer.font.cid; import java.io.BufferedReader; import java.io.IOException; @@ -9,7 +9,7 @@ import java.util.List; import java.util.Map; -import com.sun.pdfview.PDFObject; +import com.github.librepdf.pdfrenderer.PDFObject; /***************************************************************************** * Parses a CMAP and builds a lookup table to map CMAP based codes to unicode. @@ -270,7 +270,7 @@ private Character parseChar(String charDef) { /************************************************************************* * map - * @see com.sun.pdfview.font.cid.PDFCMap#map(char) + * @see PDFCMap#map(char) ************************************************************************/ @Override public char map(char src) { diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/AdobeGlyphList.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/ttf/AdobeGlyphList.java similarity index 99% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/AdobeGlyphList.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/ttf/AdobeGlyphList.java index c0f508623..db2f7121b 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/AdobeGlyphList.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/ttf/AdobeGlyphList.java @@ -1,4 +1,4 @@ -package com.sun.pdfview.font.ttf; +package com.github.librepdf.pdfrenderer.font.ttf; import java.io.*; import java.util.*; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/CMap.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/ttf/CMap.java similarity index 98% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/CMap.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/ttf/CMap.java index 3cfc46aac..8e13fbd07 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/CMap.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/ttf/CMap.java @@ -18,11 +18,11 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.font.ttf; +package com.github.librepdf.pdfrenderer.font.ttf; import java.nio.ByteBuffer; -import com.sun.pdfview.PDFDebugger; +import com.github.librepdf.pdfrenderer.PDFDebugger; /** * diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/CMapFormat0.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/ttf/CMapFormat0.java similarity index 98% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/CMapFormat0.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/ttf/CMapFormat0.java index 88b9488c9..e935cf122 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/CMapFormat0.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/ttf/CMapFormat0.java @@ -19,7 +19,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.font.ttf; +package com.github.librepdf.pdfrenderer.font.ttf; import java.nio.ByteBuffer; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/CMapFormat4.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/ttf/CMapFormat4.java similarity index 99% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/CMapFormat4.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/ttf/CMapFormat4.java index f467c6972..92fec6cdc 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/CMapFormat4.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/ttf/CMapFormat4.java @@ -19,7 +19,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.font.ttf; +package com.github.librepdf.pdfrenderer.font.ttf; import java.nio.ByteBuffer; import java.util.Collections; @@ -27,8 +27,6 @@ import java.util.SortedMap; import java.util.TreeMap; -import com.sun.pdfview.font.ttf.CMapFormat4.Segment; - /** * * @author jkaplan diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/CMapFormat6.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/ttf/CMapFormat6.java similarity index 98% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/CMapFormat6.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/ttf/CMapFormat6.java index e5b41197e..536ac4471 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/CMapFormat6.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/ttf/CMapFormat6.java @@ -17,7 +17,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.font.ttf; +package com.github.librepdf.pdfrenderer.font.ttf; import java.nio.ByteBuffer; import java.util.*; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/CmapTable.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/ttf/CmapTable.java similarity index 98% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/CmapTable.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/ttf/CmapTable.java index 5754af659..1eae96953 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/CmapTable.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/ttf/CmapTable.java @@ -16,7 +16,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.font.ttf; +package com.github.librepdf.pdfrenderer.font.ttf; import java.nio.ByteBuffer; import java.util.ArrayList; @@ -26,7 +26,7 @@ import java.util.SortedMap; import java.util.TreeMap; -import com.sun.pdfview.PDFDebugger; +import com.github.librepdf.pdfrenderer.PDFDebugger; /** * Represents the TTF "cmap" table diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/Glyf.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/ttf/Glyf.java similarity index 99% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/Glyf.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/ttf/Glyf.java index a20a20bec..e0d6a33ed 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/Glyf.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/ttf/Glyf.java @@ -17,7 +17,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.font.ttf; +package com.github.librepdf.pdfrenderer.font.ttf; import java.nio.ByteBuffer; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/GlyfCompound.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/ttf/GlyfCompound.java similarity index 99% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/GlyfCompound.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/ttf/GlyfCompound.java index b4c9ba65a..b4add4587 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/GlyfCompound.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/ttf/GlyfCompound.java @@ -17,7 +17,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.font.ttf; +package com.github.librepdf.pdfrenderer.font.ttf; import java.nio.ByteBuffer; import java.util.ArrayList; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/GlyfSimple.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/ttf/GlyfSimple.java similarity index 99% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/GlyfSimple.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/ttf/GlyfSimple.java index 67a1f8442..494774959 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/GlyfSimple.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/ttf/GlyfSimple.java @@ -17,7 +17,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.font.ttf; +package com.github.librepdf.pdfrenderer.font.ttf; import java.nio.ByteBuffer; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/GlyfTable.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/ttf/GlyfTable.java similarity index 98% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/GlyfTable.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/ttf/GlyfTable.java index 41818f9f1..ee97f7cc5 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/GlyfTable.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/ttf/GlyfTable.java @@ -16,7 +16,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.font.ttf; +package com.github.librepdf.pdfrenderer.font.ttf; import java.nio.ByteBuffer; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/HeadTable.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/ttf/HeadTable.java similarity index 99% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/HeadTable.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/ttf/HeadTable.java index e42cefff6..e8d66eb26 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/HeadTable.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/ttf/HeadTable.java @@ -17,7 +17,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.font.ttf; +package com.github.librepdf.pdfrenderer.font.ttf; import java.nio.ByteBuffer; import java.util.Date; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/HheaTable.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/ttf/HheaTable.java similarity index 99% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/HheaTable.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/ttf/HheaTable.java index 4af3d9ea2..647cd027c 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/HheaTable.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/ttf/HheaTable.java @@ -17,7 +17,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.font.ttf; +package com.github.librepdf.pdfrenderer.font.ttf; import java.nio.ByteBuffer; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/HmtxTable.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/ttf/HmtxTable.java similarity index 98% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/HmtxTable.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/ttf/HmtxTable.java index f630206e7..49dc2ddde 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/HmtxTable.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/ttf/HmtxTable.java @@ -16,7 +16,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.font.ttf; +package com.github.librepdf.pdfrenderer.font.ttf; import java.nio.ByteBuffer; import java.util.Arrays; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/LocaTable.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/ttf/LocaTable.java similarity index 98% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/LocaTable.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/ttf/LocaTable.java index 3a47d0e01..61b391002 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/LocaTable.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/ttf/LocaTable.java @@ -17,7 +17,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.font.ttf; +package com.github.librepdf.pdfrenderer.font.ttf; import java.nio.ByteBuffer; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/MaxpTable.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/ttf/MaxpTable.java similarity index 99% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/MaxpTable.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/ttf/MaxpTable.java index c1b634674..643c29dc6 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/MaxpTable.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/ttf/MaxpTable.java @@ -16,7 +16,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.font.ttf; +package com.github.librepdf.pdfrenderer.font.ttf; import java.nio.ByteBuffer; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/NameTable.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/ttf/NameTable.java similarity index 99% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/NameTable.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/ttf/NameTable.java index 30c776362..d152df4d9 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/NameTable.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/ttf/NameTable.java @@ -17,7 +17,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.font.ttf; +package com.github.librepdf.pdfrenderer.font.ttf; import java.nio.ByteBuffer; import java.nio.charset.Charset; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/PostTable.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/ttf/PostTable.java similarity index 99% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/PostTable.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/ttf/PostTable.java index 9a8514a58..598ae68a1 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/PostTable.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/ttf/PostTable.java @@ -17,12 +17,12 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.font.ttf; +package com.github.librepdf.pdfrenderer.font.ttf; import java.nio.ByteBuffer; import java.util.Arrays; -import com.sun.pdfview.PDFDebugger; +import com.github.librepdf.pdfrenderer.PDFDebugger; /** * Model the TrueType Post table diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/TrueTypeFont.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/ttf/TrueTypeFont.java similarity index 98% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/TrueTypeFont.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/ttf/TrueTypeFont.java index ffecda80a..eebcf870d 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/TrueTypeFont.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/ttf/TrueTypeFont.java @@ -16,7 +16,7 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.font.ttf; +package com.github.librepdf.pdfrenderer.font.ttf; import java.awt.Font; import java.io.ByteArrayInputStream; @@ -30,8 +30,8 @@ import java.util.SortedMap; import java.util.TreeMap; -import com.sun.pdfview.BaseWatchable; -import com.sun.pdfview.PDFDebugger; +import com.github.librepdf.pdfrenderer.BaseWatchable; +import com.github.librepdf.pdfrenderer.PDFDebugger; /** * diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/TrueTypeTable.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/ttf/TrueTypeTable.java similarity index 99% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/TrueTypeTable.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/ttf/TrueTypeTable.java index f89d1c37b..c88223840 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/TrueTypeTable.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/ttf/TrueTypeTable.java @@ -15,7 +15,7 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.font.ttf; +package com.github.librepdf.pdfrenderer.font.ttf; import java.nio.ByteBuffer; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/resource/glyphlist.txt b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/ttf/resource/glyphlist.txt similarity index 100% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/font/ttf/resource/glyphlist.txt rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/font/ttf/resource/glyphlist.txt diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/FunctionType0.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/FunctionType0.java similarity index 98% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/FunctionType0.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/FunctionType0.java index f8caa4e64..b56738b7c 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/FunctionType0.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/FunctionType0.java @@ -17,14 +17,14 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.function; +package com.github.librepdf.pdfrenderer.function; import java.io.IOException; import java.nio.ByteBuffer; -import com.sun.pdfview.PDFDebugger; -import com.sun.pdfview.PDFObject; -import com.sun.pdfview.PDFParseException; +import com.github.librepdf.pdfrenderer.PDFDebugger; +import com.github.librepdf.pdfrenderer.PDFObject; +import com.github.librepdf.pdfrenderer.PDFParseException; /** * A sampled function maps input values to output values by interpolating diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/FunctionType2.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/FunctionType2.java similarity index 96% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/FunctionType2.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/FunctionType2.java index 176006dcb..686ceb218 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/FunctionType2.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/FunctionType2.java @@ -17,12 +17,12 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.function; +package com.github.librepdf.pdfrenderer.function; import java.io.IOException; -import com.sun.pdfview.PDFObject; -import com.sun.pdfview.PDFParseException; +import com.github.librepdf.pdfrenderer.PDFObject; +import com.github.librepdf.pdfrenderer.PDFParseException; /** * A type 2 function is an exponential interpolation function, which maps diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/FunctionType3.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/FunctionType3.java similarity index 96% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/FunctionType3.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/FunctionType3.java index 4694d7ba5..3d8f824d9 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/FunctionType3.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/FunctionType3.java @@ -16,12 +16,12 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.function; +package com.github.librepdf.pdfrenderer.function; import java.io.IOException; -import com.sun.pdfview.PDFObject; -import com.sun.pdfview.PDFParseException; +import com.github.librepdf.pdfrenderer.PDFObject; +import com.github.librepdf.pdfrenderer.PDFParseException; /** * 3.9.3 - A stitching function define a stitching of the subdomains of @@ -114,7 +114,7 @@ protected void parse(PDFObject obj) throws IOException { PDFObject[] functionsAry = functionsObj.getArray(); functions = new PDFFunction[functionsAry.length]; for (int i = 0; i < functionsAry.length; i++) { - functions[i] = PDFFunction.getFunction(functionsAry[i]); + functions[i] = getFunction(functionsAry[i]); } // read the Bounds array (required) diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/FunctionType4.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/FunctionType4.java similarity index 92% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/FunctionType4.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/FunctionType4.java index d5c95d0fc..b54f066ba 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/FunctionType4.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/FunctionType4.java @@ -16,16 +16,16 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.function; +package com.github.librepdf.pdfrenderer.function; import java.io.IOException; import java.nio.ByteBuffer; import java.util.*; -import com.sun.pdfview.PDFObject; -import com.sun.pdfview.function.postscript.PostScriptParser; -import com.sun.pdfview.function.postscript.operation.OperationSet; -import com.sun.pdfview.function.postscript.operation.PostScriptOperation; +import com.github.librepdf.pdfrenderer.function.postscript.PostScriptParser; +import com.github.librepdf.pdfrenderer.function.postscript.operation.OperationSet; +import com.github.librepdf.pdfrenderer.function.postscript.operation.PostScriptOperation; +import com.github.librepdf.pdfrenderer.PDFObject; /** *

    A PostScript function is represented as a stream containing code diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/PDFFunction.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/PDFFunction.java similarity index 98% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/PDFFunction.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/PDFFunction.java index c596fa37f..eb93ba84e 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/PDFFunction.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/PDFFunction.java @@ -16,12 +16,12 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.function; +package com.github.librepdf.pdfrenderer.function; import java.io.IOException; -import com.sun.pdfview.PDFObject; -import com.sun.pdfview.PDFParseException; +import com.github.librepdf.pdfrenderer.PDFObject; +import com.github.librepdf.pdfrenderer.PDFParseException; /** *

    PDF Functions are defined in the reference as Section 3.9.

    diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/PostScriptParser.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/PostScriptParser.java similarity index 96% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/PostScriptParser.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/PostScriptParser.java index 9a5179bdd..bb20a7c07 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/PostScriptParser.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/PostScriptParser.java @@ -1,4 +1,4 @@ -package com.sun.pdfview.function.postscript; +package com.github.librepdf.pdfrenderer.function.postscript; import java.util.LinkedList; import java.util.List; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Abs.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Abs.java similarity index 86% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Abs.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Abs.java index ff57ecc72..a44e0be5a 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Abs.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Abs.java @@ -1,4 +1,4 @@ -package com.sun.pdfview.function.postscript.operation; +package com.github.librepdf.pdfrenderer.function.postscript.operation; import java.util.Stack; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Add.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Add.java similarity index 87% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Add.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Add.java index 363d3eba9..c5a3c7ad0 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Add.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Add.java @@ -1,4 +1,4 @@ -package com.sun.pdfview.function.postscript.operation; +package com.github.librepdf.pdfrenderer.function.postscript.operation; import java.util.Stack; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/And.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/And.java similarity index 87% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/And.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/And.java index d28826e0b..a9255b603 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/And.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/And.java @@ -1,4 +1,4 @@ -package com.sun.pdfview.function.postscript.operation; +package com.github.librepdf.pdfrenderer.function.postscript.operation; import java.util.Stack; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Atan.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Atan.java similarity index 92% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Atan.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Atan.java index c9993dc29..8123f8d41 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Atan.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Atan.java @@ -1,4 +1,4 @@ -package com.sun.pdfview.function.postscript.operation; +package com.github.librepdf.pdfrenderer.function.postscript.operation; import java.util.Stack; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Bitshift.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Bitshift.java similarity index 91% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Bitshift.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Bitshift.java index 7168be9dc..886358e44 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Bitshift.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Bitshift.java @@ -1,4 +1,4 @@ -package com.sun.pdfview.function.postscript.operation; +package com.github.librepdf.pdfrenderer.function.postscript.operation; import java.util.Stack; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Ceiling.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Ceiling.java similarity index 86% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Ceiling.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Ceiling.java index 97bf51c35..90127cd9e 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Ceiling.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Ceiling.java @@ -1,4 +1,4 @@ -package com.sun.pdfview.function.postscript.operation; +package com.github.librepdf.pdfrenderer.function.postscript.operation; import java.util.Stack; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Copy.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Copy.java similarity index 97% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Copy.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Copy.java index 0b9740688..b35551f6c 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Copy.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Copy.java @@ -1,4 +1,4 @@ -package com.sun.pdfview.function.postscript.operation; +package com.github.librepdf.pdfrenderer.function.postscript.operation; import java.util.Stack; final class Copy implements PostScriptOperation { diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Cvi.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Cvi.java similarity index 93% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Cvi.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Cvi.java index e7471041e..a1b5e881e 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Cvi.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Cvi.java @@ -1,4 +1,4 @@ -package com.sun.pdfview.function.postscript.operation; +package com.github.librepdf.pdfrenderer.function.postscript.operation; import java.util.Stack; final class Cvi implements PostScriptOperation { diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Cvr.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Cvr.java similarity index 92% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Cvr.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Cvr.java index 6035d0e77..2e70f65f4 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Cvr.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Cvr.java @@ -1,4 +1,4 @@ -package com.sun.pdfview.function.postscript.operation; +package com.github.librepdf.pdfrenderer.function.postscript.operation; import java.util.Stack; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Div.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Div.java similarity index 89% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Div.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Div.java index 88fc30f27..534d468d8 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Div.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Div.java @@ -1,4 +1,4 @@ -package com.sun.pdfview.function.postscript.operation; +package com.github.librepdf.pdfrenderer.function.postscript.operation; import java.util.Stack; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Dup.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Dup.java similarity index 88% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Dup.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Dup.java index f08614da5..9c92dc6e4 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Dup.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Dup.java @@ -1,4 +1,4 @@ -package com.sun.pdfview.function.postscript.operation; +package com.github.librepdf.pdfrenderer.function.postscript.operation; import java.util.Stack; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Eq.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Eq.java similarity index 95% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Eq.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Eq.java index e62a02ef4..4b90f2975 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Eq.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Eq.java @@ -1,4 +1,4 @@ -package com.sun.pdfview.function.postscript.operation; +package com.github.librepdf.pdfrenderer.function.postscript.operation; import java.util.Stack; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Exch.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Exch.java similarity index 83% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Exch.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Exch.java index 668efb509..de80471dc 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Exch.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Exch.java @@ -1,4 +1,4 @@ -package com.sun.pdfview.function.postscript.operation; +package com.github.librepdf.pdfrenderer.function.postscript.operation; import java.util.Stack; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Exp.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Exp.java similarity index 90% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Exp.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Exp.java index acda23a87..425287973 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Exp.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Exp.java @@ -1,4 +1,4 @@ -package com.sun.pdfview.function.postscript.operation; +package com.github.librepdf.pdfrenderer.function.postscript.operation; import java.util.Stack; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Expression.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Expression.java similarity index 81% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Expression.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Expression.java index 4f8af8e07..f8ef93fd5 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Expression.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Expression.java @@ -1,4 +1,4 @@ -package com.sun.pdfview.function.postscript.operation; +package com.github.librepdf.pdfrenderer.function.postscript.operation; import java.util.LinkedList; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/False.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/False.java similarity index 85% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/False.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/False.java index 61e747d12..346624c48 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/False.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/False.java @@ -1,4 +1,4 @@ -package com.sun.pdfview.function.postscript.operation; +package com.github.librepdf.pdfrenderer.function.postscript.operation; import java.util.Stack; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Floor.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Floor.java similarity index 86% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Floor.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Floor.java index bf6b7a70f..6c7016720 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Floor.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Floor.java @@ -1,4 +1,4 @@ -package com.sun.pdfview.function.postscript.operation; +package com.github.librepdf.pdfrenderer.function.postscript.operation; import java.util.Stack; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Ge.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Ge.java similarity index 93% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Ge.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Ge.java index 7507a6b69..5a6747e6e 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Ge.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Ge.java @@ -1,4 +1,4 @@ -package com.sun.pdfview.function.postscript.operation; +package com.github.librepdf.pdfrenderer.function.postscript.operation; import java.util.Stack; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Gt.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Gt.java similarity index 92% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Gt.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Gt.java index a6caf9330..ffdf9a216 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Gt.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Gt.java @@ -1,4 +1,4 @@ -package com.sun.pdfview.function.postscript.operation; +package com.github.librepdf.pdfrenderer.function.postscript.operation; import java.util.Stack; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Idiv.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Idiv.java similarity index 88% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Idiv.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Idiv.java index aa03af451..0797c2084 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Idiv.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Idiv.java @@ -1,4 +1,4 @@ -package com.sun.pdfview.function.postscript.operation; +package com.github.librepdf.pdfrenderer.function.postscript.operation; import java.util.Stack; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/If.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/If.java similarity index 89% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/If.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/If.java index 9fd3635de..e5cb0e0d4 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/If.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/If.java @@ -1,4 +1,4 @@ -package com.sun.pdfview.function.postscript.operation; +package com.github.librepdf.pdfrenderer.function.postscript.operation; import java.util.Stack; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/IfElse.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/IfElse.java similarity index 92% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/IfElse.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/IfElse.java index ea96d3bfa..b72340e90 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/IfElse.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/IfElse.java @@ -1,4 +1,4 @@ -package com.sun.pdfview.function.postscript.operation; +package com.github.librepdf.pdfrenderer.function.postscript.operation; import java.util.Stack; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Index.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Index.java similarity index 82% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Index.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Index.java index e7b470102..b6cc8b71f 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Index.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Index.java @@ -1,4 +1,4 @@ -package com.sun.pdfview.function.postscript.operation; +package com.github.librepdf.pdfrenderer.function.postscript.operation; import java.util.Stack; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Le.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Le.java similarity index 93% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Le.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Le.java index 7f7c9e4cc..de204ede8 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Le.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Le.java @@ -1,4 +1,4 @@ -package com.sun.pdfview.function.postscript.operation; +package com.github.librepdf.pdfrenderer.function.postscript.operation; import java.util.Stack; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Ln.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Ln.java similarity index 84% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Ln.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Ln.java index db4a0086a..ba000b10c 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Ln.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Ln.java @@ -1,4 +1,4 @@ -package com.sun.pdfview.function.postscript.operation; +package com.github.librepdf.pdfrenderer.function.postscript.operation; import java.util.Stack; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Log.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Log.java similarity index 84% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Log.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Log.java index 0e93ef164..e63a12535 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Log.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Log.java @@ -1,4 +1,4 @@ -package com.sun.pdfview.function.postscript.operation; +package com.github.librepdf.pdfrenderer.function.postscript.operation; import java.util.Stack; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Lt.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Lt.java similarity index 92% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Lt.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Lt.java index a46ecc967..1029c4d47 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Lt.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Lt.java @@ -1,4 +1,4 @@ -package com.sun.pdfview.function.postscript.operation; +package com.github.librepdf.pdfrenderer.function.postscript.operation; import java.util.Stack; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Mod.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Mod.java similarity index 89% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Mod.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Mod.java index 5ef8f1e7a..fdd5d5955 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Mod.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Mod.java @@ -1,4 +1,4 @@ -package com.sun.pdfview.function.postscript.operation; +package com.github.librepdf.pdfrenderer.function.postscript.operation; import java.util.Stack; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Mul.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Mul.java similarity index 88% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Mul.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Mul.java index c555a0375..eafe73267 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Mul.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Mul.java @@ -1,4 +1,4 @@ -package com.sun.pdfview.function.postscript.operation; +package com.github.librepdf.pdfrenderer.function.postscript.operation; import java.util.Stack; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Ne.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Ne.java similarity index 87% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Ne.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Ne.java index fb9483684..2029c6ae9 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Ne.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Ne.java @@ -1,4 +1,4 @@ -package com.sun.pdfview.function.postscript.operation; +package com.github.librepdf.pdfrenderer.function.postscript.operation; import java.util.Stack; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Neg.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Neg.java similarity index 87% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Neg.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Neg.java index e3ddce6e0..b25a6c29f 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Neg.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Neg.java @@ -1,4 +1,4 @@ -package com.sun.pdfview.function.postscript.operation; +package com.github.librepdf.pdfrenderer.function.postscript.operation; import java.util.Stack; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Not.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Not.java similarity index 87% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Not.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Not.java index 6642e6386..8f825f000 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Not.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Not.java @@ -1,4 +1,4 @@ -package com.sun.pdfview.function.postscript.operation; +package com.github.librepdf.pdfrenderer.function.postscript.operation; import java.util.Stack; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/OperationSet.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/OperationSet.java similarity index 98% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/OperationSet.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/OperationSet.java index fbd702509..13e961731 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/OperationSet.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/OperationSet.java @@ -1,4 +1,4 @@ -package com.sun.pdfview.function.postscript.operation; +package com.github.librepdf.pdfrenderer.function.postscript.operation; import java.util.HashMap; import java.util.Map; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Or.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Or.java similarity index 87% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Or.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Or.java index 4f7fc3c11..6e348ad4e 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Or.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Or.java @@ -1,4 +1,4 @@ -package com.sun.pdfview.function.postscript.operation; +package com.github.librepdf.pdfrenderer.function.postscript.operation; import java.util.Stack; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Pop.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Pop.java similarity index 72% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Pop.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Pop.java index 1a371a9d9..c912b9fab 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Pop.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Pop.java @@ -1,4 +1,4 @@ -package com.sun.pdfview.function.postscript.operation; +package com.github.librepdf.pdfrenderer.function.postscript.operation; import java.util.Stack; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/PostScriptOperation.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/PostScriptOperation.java similarity index 75% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/PostScriptOperation.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/PostScriptOperation.java index dd7c899c1..e9528a4e5 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/PostScriptOperation.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/PostScriptOperation.java @@ -1,4 +1,4 @@ -package com.sun.pdfview.function.postscript.operation; +package com.github.librepdf.pdfrenderer.function.postscript.operation; import java.util.Stack; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/PushAsNumber.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/PushAsNumber.java similarity index 84% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/PushAsNumber.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/PushAsNumber.java index c8dbc6317..3387b427a 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/PushAsNumber.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/PushAsNumber.java @@ -1,4 +1,4 @@ -package com.sun.pdfview.function.postscript.operation; +package com.github.librepdf.pdfrenderer.function.postscript.operation; import java.util.Stack; @@ -20,7 +20,7 @@ public PushAsNumber(String numberToken) { /************************************************************************* * eval - * @see com.sun.pdfview.function.postscript.operation.PostScriptOperation#eval(java.util.Stack) + * @see PostScriptOperation#eval(java.util.Stack) ************************************************************************/ @Override public void eval(Stack environment) { diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Roll.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Roll.java similarity index 93% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Roll.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Roll.java index d628ee5a6..47f375d33 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Roll.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Roll.java @@ -1,4 +1,4 @@ -package com.sun.pdfview.function.postscript.operation; +package com.github.librepdf.pdfrenderer.function.postscript.operation; import java.util.Stack; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Round.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Round.java similarity index 88% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Round.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Round.java index f8abe87db..51d189cac 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Round.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Round.java @@ -1,4 +1,4 @@ -package com.sun.pdfview.function.postscript.operation; +package com.github.librepdf.pdfrenderer.function.postscript.operation; import java.util.Stack; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Sin.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Sin.java similarity index 86% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Sin.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Sin.java index fdc70a6a9..0c7b9ad73 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Sin.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Sin.java @@ -1,4 +1,4 @@ -package com.sun.pdfview.function.postscript.operation; +package com.github.librepdf.pdfrenderer.function.postscript.operation; import java.util.Stack; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Sqrt.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Sqrt.java similarity index 85% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Sqrt.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Sqrt.java index 5064b2c99..b46842396 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Sqrt.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Sqrt.java @@ -1,4 +1,4 @@ -package com.sun.pdfview.function.postscript.operation; +package com.github.librepdf.pdfrenderer.function.postscript.operation; import java.util.Stack; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Sub.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Sub.java similarity index 89% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Sub.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Sub.java index 2c1a26dbb..f0a603016 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Sub.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Sub.java @@ -1,4 +1,4 @@ -package com.sun.pdfview.function.postscript.operation; +package com.github.librepdf.pdfrenderer.function.postscript.operation; import java.util.Stack; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/True.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/True.java similarity index 85% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/True.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/True.java index 77de5a7e5..4e5664ce2 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/True.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/True.java @@ -1,4 +1,4 @@ -package com.sun.pdfview.function.postscript.operation; +package com.github.librepdf.pdfrenderer.function.postscript.operation; import java.util.Stack; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Truncate.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Truncate.java similarity index 87% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Truncate.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Truncate.java index c7bf09acc..50e7b58e9 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Truncate.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Truncate.java @@ -1,4 +1,4 @@ -package com.sun.pdfview.function.postscript.operation; +package com.github.librepdf.pdfrenderer.function.postscript.operation; import java.util.Stack; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Xor.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Xor.java similarity index 88% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Xor.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Xor.java index d71895abf..8d96804fa 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/function/postscript/operation/Xor.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/function/postscript/operation/Xor.java @@ -1,4 +1,4 @@ -package com.sun.pdfview.function.postscript.operation; +package com.github.librepdf.pdfrenderer.function.postscript.operation; import java.util.Stack; diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/pattern/DummyShader.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/pattern/DummyShader.java similarity index 68% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/pattern/DummyShader.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/pattern/DummyShader.java index 07ea81946..3b12353c8 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/pattern/DummyShader.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/pattern/DummyShader.java @@ -1,10 +1,10 @@ -package com.sun.pdfview.pattern; +package com.github.librepdf.pdfrenderer.pattern; import java.awt.Color; import java.io.IOException; -import com.sun.pdfview.PDFObject; -import com.sun.pdfview.PDFPaint; +import com.github.librepdf.pdfrenderer.PDFObject; +import com.github.librepdf.pdfrenderer.PDFPaint; public class DummyShader extends PDFShader { diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/pattern/PDFPattern.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/pattern/PDFPattern.java similarity index 94% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/pattern/PDFPattern.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/pattern/PDFPattern.java index da58ecadb..f80580335 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/pattern/PDFPattern.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/pattern/PDFPattern.java @@ -17,16 +17,16 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.pattern; +package com.github.librepdf.pdfrenderer.pattern; import java.awt.geom.AffineTransform; import java.io.IOException; import java.util.Map; -import com.sun.pdfview.PDFObject; -import com.sun.pdfview.PDFPaint; -import com.sun.pdfview.PDFParseException; +import com.github.librepdf.pdfrenderer.PDFObject; +import com.github.librepdf.pdfrenderer.PDFPaint; +import com.github.librepdf.pdfrenderer.PDFParseException; /** * The abstract superclass of all PDF Pattern types diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/pattern/PDFShader.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/pattern/PDFShader.java similarity index 96% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/pattern/PDFShader.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/pattern/PDFShader.java index 9909bed92..dc570c916 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/pattern/PDFShader.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/pattern/PDFShader.java @@ -17,17 +17,16 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.pattern; +package com.github.librepdf.pdfrenderer.pattern; import java.awt.geom.Rectangle2D; import java.io.IOException; import java.util.Map; -import com.sun.pdfview.PDFDebugger; -import com.sun.pdfview.PDFObject; -import com.sun.pdfview.PDFPaint; -import com.sun.pdfview.PDFParseException; -import com.sun.pdfview.colorspace.PDFColorSpace; +import com.github.librepdf.pdfrenderer.colorspace.PDFColorSpace; +import com.github.librepdf.pdfrenderer.PDFObject; +import com.github.librepdf.pdfrenderer.PDFPaint; +import com.github.librepdf.pdfrenderer.PDFParseException; /** *

    A PDFShader fills a given region with a shading, such as a gradient.

    diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/pattern/PatternType1.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/pattern/PatternType1.java similarity index 97% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/pattern/PatternType1.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/pattern/PatternType1.java index dfd88d95c..98115ed04 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/pattern/PatternType1.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/pattern/PatternType1.java @@ -17,7 +17,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.pattern; +package com.github.librepdf.pdfrenderer.pattern; import java.awt.AlphaComposite; import java.awt.Graphics2D; @@ -42,11 +42,11 @@ import java.util.HashMap; import java.util.Map; -import com.sun.pdfview.PDFObject; -import com.sun.pdfview.PDFPage; -import com.sun.pdfview.PDFPaint; -import com.sun.pdfview.PDFParser; -import com.sun.pdfview.PDFRenderer; +import com.github.librepdf.pdfrenderer.PDFObject; +import com.github.librepdf.pdfrenderer.PDFPage; +import com.github.librepdf.pdfrenderer.PDFPaint; +import com.github.librepdf.pdfrenderer.PDFParser; +import com.github.librepdf.pdfrenderer.PDFRenderer; /** * A type 1 (tiling) pattern diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/pattern/PatternType2.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/pattern/PatternType2.java similarity index 92% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/pattern/PatternType2.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/pattern/PatternType2.java index de461053c..67995a781 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/pattern/PatternType2.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/pattern/PatternType2.java @@ -17,13 +17,13 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.pattern; +package com.github.librepdf.pdfrenderer.pattern; import java.io.IOException; import java.util.Map; -import com.sun.pdfview.PDFObject; -import com.sun.pdfview.PDFPaint; +import com.github.librepdf.pdfrenderer.PDFObject; +import com.github.librepdf.pdfrenderer.PDFPaint; /** * A type 1 (tiling) pattern diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/pattern/ShaderType2.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/pattern/ShaderType2.java similarity index 97% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/pattern/ShaderType2.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/pattern/ShaderType2.java index 87155522c..41bcf434e 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/pattern/ShaderType2.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/pattern/ShaderType2.java @@ -17,7 +17,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.pattern; +package com.github.librepdf.pdfrenderer.pattern; import java.awt.Paint; import java.awt.PaintContext; @@ -35,11 +35,11 @@ import java.awt.image.WritableRaster; import java.io.IOException; -import com.sun.pdfview.PDFObject; -import com.sun.pdfview.PDFPaint; -import com.sun.pdfview.PDFParseException; -import com.sun.pdfview.colorspace.PDFColorSpace; -import com.sun.pdfview.function.PDFFunction; +import com.github.librepdf.pdfrenderer.colorspace.PDFColorSpace; +import com.github.librepdf.pdfrenderer.function.PDFFunction; +import com.github.librepdf.pdfrenderer.PDFObject; +import com.github.librepdf.pdfrenderer.PDFPaint; +import com.github.librepdf.pdfrenderer.PDFParseException; /** * A shader that performs axial shader based on a function. diff --git a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/pattern/ShaderType3.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/pattern/ShaderType3.java similarity index 97% rename from openpdf-pdfrenderer/src/main/java/com/sun/pdfview/pattern/ShaderType3.java rename to openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/pattern/ShaderType3.java index 5902193f7..a4a233722 100644 --- a/openpdf-pdfrenderer/src/main/java/com/sun/pdfview/pattern/ShaderType3.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/pattern/ShaderType3.java @@ -17,7 +17,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -package com.sun.pdfview.pattern; +package com.github.librepdf.pdfrenderer.pattern; import java.awt.Paint; import java.awt.PaintContext; @@ -36,12 +36,12 @@ import java.awt.image.WritableRaster; import java.io.IOException; -import com.sun.pdfview.BaseWatchable; -import com.sun.pdfview.PDFObject; -import com.sun.pdfview.PDFPaint; -import com.sun.pdfview.PDFParseException; -import com.sun.pdfview.colorspace.PDFColorSpace; -import com.sun.pdfview.function.PDFFunction; +import com.github.librepdf.pdfrenderer.colorspace.PDFColorSpace; +import com.github.librepdf.pdfrenderer.function.PDFFunction; +import com.github.librepdf.pdfrenderer.BaseWatchable; +import com.github.librepdf.pdfrenderer.PDFObject; +import com.github.librepdf.pdfrenderer.PDFPaint; +import com.github.librepdf.pdfrenderer.PDFParseException; /** * A shader that performs radial shader based on a function. diff --git a/openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/BaseFonts.properties b/openpdf-pdfrenderer/src/main/resources/com/github/librepdf/pdfrenderer/font/res/BaseFonts.properties similarity index 100% rename from openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/BaseFonts.properties rename to openpdf-pdfrenderer/src/main/resources/com/github/librepdf/pdfrenderer/font/res/BaseFonts.properties diff --git a/openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/d050000l.pfb b/openpdf-pdfrenderer/src/main/resources/com/github/librepdf/pdfrenderer/font/res/d050000l.pfb similarity index 100% rename from openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/d050000l.pfb rename to openpdf-pdfrenderer/src/main/resources/com/github/librepdf/pdfrenderer/font/res/d050000l.pfb diff --git a/openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/n019003l.pfb b/openpdf-pdfrenderer/src/main/resources/com/github/librepdf/pdfrenderer/font/res/n019003l.pfb similarity index 100% rename from openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/n019003l.pfb rename to openpdf-pdfrenderer/src/main/resources/com/github/librepdf/pdfrenderer/font/res/n019003l.pfb diff --git a/openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/n019004l.pfb b/openpdf-pdfrenderer/src/main/resources/com/github/librepdf/pdfrenderer/font/res/n019004l.pfb similarity index 100% rename from openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/n019004l.pfb rename to openpdf-pdfrenderer/src/main/resources/com/github/librepdf/pdfrenderer/font/res/n019004l.pfb diff --git a/openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/n019023l.pfb b/openpdf-pdfrenderer/src/main/resources/com/github/librepdf/pdfrenderer/font/res/n019023l.pfb similarity index 100% rename from openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/n019023l.pfb rename to openpdf-pdfrenderer/src/main/resources/com/github/librepdf/pdfrenderer/font/res/n019023l.pfb diff --git a/openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/n019024l.pfb b/openpdf-pdfrenderer/src/main/resources/com/github/librepdf/pdfrenderer/font/res/n019024l.pfb similarity index 100% rename from openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/n019024l.pfb rename to openpdf-pdfrenderer/src/main/resources/com/github/librepdf/pdfrenderer/font/res/n019024l.pfb diff --git a/openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/n021003l.pfb b/openpdf-pdfrenderer/src/main/resources/com/github/librepdf/pdfrenderer/font/res/n021003l.pfb similarity index 100% rename from openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/n021003l.pfb rename to openpdf-pdfrenderer/src/main/resources/com/github/librepdf/pdfrenderer/font/res/n021003l.pfb diff --git a/openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/n021004l.pfb b/openpdf-pdfrenderer/src/main/resources/com/github/librepdf/pdfrenderer/font/res/n021004l.pfb similarity index 100% rename from openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/n021004l.pfb rename to openpdf-pdfrenderer/src/main/resources/com/github/librepdf/pdfrenderer/font/res/n021004l.pfb diff --git a/openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/n021023l.pfb b/openpdf-pdfrenderer/src/main/resources/com/github/librepdf/pdfrenderer/font/res/n021023l.pfb similarity index 100% rename from openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/n021023l.pfb rename to openpdf-pdfrenderer/src/main/resources/com/github/librepdf/pdfrenderer/font/res/n021023l.pfb diff --git a/openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/n021024l.pfb b/openpdf-pdfrenderer/src/main/resources/com/github/librepdf/pdfrenderer/font/res/n021024l.pfb similarity index 100% rename from openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/n021024l.pfb rename to openpdf-pdfrenderer/src/main/resources/com/github/librepdf/pdfrenderer/font/res/n021024l.pfb diff --git a/openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/n022003l.pfb b/openpdf-pdfrenderer/src/main/resources/com/github/librepdf/pdfrenderer/font/res/n022003l.pfb similarity index 100% rename from openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/n022003l.pfb rename to openpdf-pdfrenderer/src/main/resources/com/github/librepdf/pdfrenderer/font/res/n022003l.pfb diff --git a/openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/n022004l.pfb b/openpdf-pdfrenderer/src/main/resources/com/github/librepdf/pdfrenderer/font/res/n022004l.pfb similarity index 100% rename from openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/n022004l.pfb rename to openpdf-pdfrenderer/src/main/resources/com/github/librepdf/pdfrenderer/font/res/n022004l.pfb diff --git a/openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/n022023l.pfb b/openpdf-pdfrenderer/src/main/resources/com/github/librepdf/pdfrenderer/font/res/n022023l.pfb similarity index 100% rename from openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/n022023l.pfb rename to openpdf-pdfrenderer/src/main/resources/com/github/librepdf/pdfrenderer/font/res/n022023l.pfb diff --git a/openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/n022024l.pfb b/openpdf-pdfrenderer/src/main/resources/com/github/librepdf/pdfrenderer/font/res/n022024l.pfb similarity index 100% rename from openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/n022024l.pfb rename to openpdf-pdfrenderer/src/main/resources/com/github/librepdf/pdfrenderer/font/res/n022024l.pfb diff --git a/openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/s050000l.pfb b/openpdf-pdfrenderer/src/main/resources/com/github/librepdf/pdfrenderer/font/res/s050000l.pfb similarity index 100% rename from openpdf-pdfrenderer/src/main/resources/com/sun/pdfview/font/res/s050000l.pfb rename to openpdf-pdfrenderer/src/main/resources/com/github/librepdf/pdfrenderer/font/res/s050000l.pfb diff --git a/openpdf-pdfrenderer/src/test/java/PdfRendererToImageTest.java b/openpdf-pdfrenderer/src/test/java/PdfRendererToImageTest.java index a9e0c0f70..0b6018887 100644 --- a/openpdf-pdfrenderer/src/test/java/PdfRendererToImageTest.java +++ b/openpdf-pdfrenderer/src/test/java/PdfRendererToImageTest.java @@ -50,9 +50,9 @@ import com.lowagie.text.Paragraph; import com.lowagie.text.pdf.PdfWriter; import org.junit.jupiter.api.Test; -import com.sun.pdfview.PDFFile; -import com.sun.pdfview.PDFPage; -import com.sun.pdfview.PDFRenderer; +import com.github.librepdf.pdfrenderer.PDFFile; +import com.github.librepdf.pdfrenderer.PDFPage; +import com.github.librepdf.pdfrenderer.PDFRenderer; import javax.imageio.ImageIO; import java.awt.*; diff --git a/pdf-swing/src/main/java/com/lowagie/rups/model/PageLoader.java b/pdf-swing/src/main/java/com/lowagie/rups/model/PageLoader.java index ed12c5499..e3bccead0 100644 --- a/pdf-swing/src/main/java/com/lowagie/rups/model/PageLoader.java +++ b/pdf-swing/src/main/java/com/lowagie/rups/model/PageLoader.java @@ -20,8 +20,8 @@ package com.lowagie.rups.model; -import com.sun.pdfview.PDFFile; -import com.sun.pdfview.PDFPage; +import com.github.librepdf.pdfrenderer.PDFFile; +import com.github.librepdf.pdfrenderer.PDFPage; /** * Loads all the PDFPage objects for SUN's PDF Renderer in Background. From a1a45f215028949153ee38bba3894db172b71bef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20R=C3=B8sdal?= <41650711+andreasrosdal@users.noreply.github.com> Date: Sat, 17 Aug 2024 14:09:17 +0200 Subject: [PATCH 5/7] Update of PdfRendererToImageTest. --- openpdf-pdfrenderer/README.md | 2 +- .../github/librepdf/pdfrenderer/PDFImage.java | 1286 ++--------------- .../src/test/java/PdfRendererToImageTest.java | 133 +- .../src/test/resources/invoice-1.pdf | Bin 0 -> 41894 bytes .../test/resources/pdfsmartcopy_bec_image.pdf | Bin 0 -> 208584 bytes 5 files changed, 161 insertions(+), 1260 deletions(-) create mode 100644 openpdf-pdfrenderer/src/test/resources/invoice-1.pdf create mode 100644 openpdf-pdfrenderer/src/test/resources/pdfsmartcopy_bec_image.pdf diff --git a/openpdf-pdfrenderer/README.md b/openpdf-pdfrenderer/README.md index c1643117e..3cab63b64 100644 --- a/openpdf-pdfrenderer/README.md +++ b/openpdf-pdfrenderer/README.md @@ -3,7 +3,7 @@ openpdf-pdfrenderer PDF to Image renderer for OpenPDF. -Because every PDF library should be able to create a PNG from a PDF. +Because every fine PDF library should be able to create a PNG image from a PDF page. License: GNU Lesser General Public License diff --git a/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/PDFImage.java b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/PDFImage.java index 6c426cf15..5bfe5f360 100644 --- a/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/PDFImage.java +++ b/openpdf-pdfrenderer/src/main/java/com/github/librepdf/pdfrenderer/PDFImage.java @@ -6,1350 +6,226 @@ * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + package com.github.librepdf.pdfrenderer; -import java.awt.Color; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.Image; -import java.awt.Point; -import java.awt.Transparency; -import java.awt.color.ColorSpace; -import java.awt.color.ICC_ColorSpace; -import java.awt.geom.AffineTransform; -import java.awt.image.AffineTransformOp; -import java.awt.image.BufferedImage; -import java.awt.image.ColorConvertOp; -import java.awt.image.ColorModel; -import java.awt.image.ComponentColorModel; -import java.awt.image.DataBuffer; -import java.awt.image.DataBufferByte; -import java.awt.image.DataBufferInt; -import java.awt.image.IndexColorModel; -import java.awt.image.MultiPixelPackedSampleModel; -import java.awt.image.PackedColorModel; -import java.awt.image.PixelInterleavedSampleModel; -import java.awt.image.Raster; -import java.awt.image.RasterFormatException; -import java.awt.image.SampleModel; -import java.awt.image.WritableRaster; +import java.awt.*; +import java.awt.image.*; import java.io.IOException; import java.nio.ByteBuffer; -import java.util.Arrays; -import java.util.Iterator; import java.util.Map; -import javax.imageio.IIOException; import javax.imageio.ImageIO; import javax.imageio.ImageReadParam; import javax.imageio.ImageReader; -import javax.imageio.metadata.IIOMetadata; -import javax.imageio.metadata.IIOMetadataFormatImpl; -import com.github.librepdf.pdfrenderer.colorspace.AlternateColorSpace; import com.github.librepdf.pdfrenderer.colorspace.IndexedColor; import com.github.librepdf.pdfrenderer.colorspace.PDFColorSpace; -import com.github.librepdf.pdfrenderer.colorspace.YCCKColorSpace; import com.github.librepdf.pdfrenderer.decode.PDFDecoder; -import com.github.librepdf.pdfrenderer.function.FunctionType0; -import org.w3c.dom.Attr; -import org.w3c.dom.Node; -/** - * Encapsulates a PDF Image - */ public class PDFImage { - private static int[][] GREY_TO_ARGB = new int[8][]; - - /** - * color key mask. Array of start/end pairs of ranges of color components to - * mask out. If a component falls within any of the ranges it is clear. - */ private int[] colorKeyMask = null; - /** the width of this image in pixels */ private int width; - /** the height of this image in pixels */ private int height; - /** the colorspace to interpret the samples in */ private PDFColorSpace colorSpace; - /** the number of bits per sample component */ private int bpc; - /** whether this image is a mask or not */ private boolean imageMask = false; - /** the SMask image, if any */ private PDFImage sMask; - /** the decode array */ private float[] decode; - /** the actual image data */ private final PDFObject imageObj; - /** true if the image is in encoded in JPEG*/ private final boolean jpegDecode; - - /** - * Create an instance of a PDFImage - * @throws IOException if {@link PDFDecoder} throws one while evaluating if the image is a Jpeg - */ + protected PDFImage(PDFObject imageObj) throws IOException { this.imageObj = imageObj; this.jpegDecode = PDFDecoder.isLastFilter(imageObj, PDFDecoder.DCT_FILTERS); } - /** - * Read a PDFImage from an image dictionary and stream - * - * @param obj - * the PDFObject containing the image's dictionary and stream - * @param resources - * the current resources - * @param useAsSMask - * - flag for switching colors in case image is used as sMask - * internally this is needed for handling transparency in smask - * images. - */ public static PDFImage createImage(PDFObject obj, Map resources, boolean useAsSMask) throws IOException { - // create the image PDFImage image = new PDFImage(obj); + image.setWidth(obj.getDictRef("Width").getIntValue()); + image.setHeight(obj.getDictRef("Height").getIntValue()); - // get the width (required) - PDFObject widthObj = obj.getDictRef("Width"); - if (widthObj == null) { - throw new PDFParseException("Unable to read image width: " + obj); - } - image.setWidth(widthObj.getIntValue()); - - // get the height (required) - PDFObject heightObj = obj.getDictRef("Height"); - if (heightObj == null) { - throw new PDFParseException("Unable to get image height: " + obj); - } - image.setHeight(heightObj.getIntValue()); - - // figure out if we are an image mask (optional) - PDFObject imageMaskObj = obj.getDictRef("ImageMask"); - if (imageMaskObj != null) { - image.setImageMask(imageMaskObj.getBooleanValue()); - } - // read the bpc and colorspace (required except for masks) - if (image.isImageMask()) { + if (obj.getDictRef("ImageMask") != null) { + image.setImageMask(obj.getDictRef("ImageMask").getBooleanValue()); image.setBitsPerComponent(1); - // create the indexed color space for the mask - // [PATCHED by michal.busta@gmail.com] - default value od Decode - // according to PDF spec. is [0, 1] - // so the color arry should be: - // [PATCHED by XOND] - switched colors in case the image is used as - // SMask for another image, otherwise transparency isn't - // handled correctly. - Color[] colors = useAsSMask ? new Color[] { Color.WHITE, Color.BLACK } - : new Color[] { Color.BLACK, Color.WHITE }; - PDFObject imageMaskDecode = obj.getDictRef("Decode"); - if (imageMaskDecode != null) { - PDFObject[] decodeArray = imageMaskDecode.getArray(); - float decode0 = decodeArray[0].getFloatValue(); - if (decode0 == 1.0f) { - colors = useAsSMask ? new Color[] { Color.BLACK, Color.WHITE } - : new Color[] { Color.WHITE, Color.BLACK }; - } - - /* - * float[] decode = new float[decodeArray.length]; for (int i = - * 0; i < decodeArray.length; i++) { decode[i] = - * decodeArray[i].getFloatValue(); } image.setDecode(decode); - */ - } - - image.setColorSpace(new IndexedColor(colors)); + image.setColorSpace(new IndexedColor(useAsSMask ? new Color[]{Color.WHITE, Color.BLACK} : new Color[]{Color.BLACK, Color.WHITE})); } else { - // get the bits per component (required) - PDFObject bpcObj = obj.getDictRef("BitsPerComponent"); - if (bpcObj == null) { - throw new PDFParseException("Unable to get bits per component: " + obj); - } - image.setBitsPerComponent(bpcObj.getIntValue()); - - // get the color space (required) - PDFObject csObj = obj.getDictRef("ColorSpace"); - if (csObj == null) { - throw new PDFParseException("No ColorSpace for image: " + obj); + image.setBitsPerComponent(obj.getDictRef("BitsPerComponent").getIntValue()); + image.setColorSpace(PDFColorSpace.getColorSpace(obj.getDictRef("ColorSpace"), resources)); + if (obj.getDictRef("Decode") != null) { + image.setDecode(parseDecodeArray(obj.getDictRef("Decode").getArray())); } - - PDFColorSpace cs = PDFColorSpace.getColorSpace(csObj, resources); - image.setColorSpace(cs); - - // read the decode array - PDFObject decodeObj = obj.getDictRef("Decode"); - if (decodeObj != null) { - PDFObject[] decodeArray = decodeObj.getArray(); - - float[] decode = new float[decodeArray.length]; - for (int i = 0; i < decodeArray.length; i++) { - decode[i] = decodeArray[i].getFloatValue(); - } - - image.setDecode(decode); - } - - // read the soft mask. - // If ImageMask is true, this entry must not be present. - // (See implementation note 52 in Appendix H.) - PDFObject sMaskObj = obj.getDictRef("SMask"); - if (sMaskObj == null) { - // try the explicit mask, if there is no SoftMask - sMaskObj = obj.getDictRef("Mask"); - } - - if (sMaskObj != null) { - if (sMaskObj.getType() == PDFObject.STREAM) { - try { - PDFImage sMaskImage = PDFImage.createImage(sMaskObj, resources, true); - image.setSMask(sMaskImage); - } catch (IOException ex) { - PDFDebugger.debug("ERROR: there was a problem parsing the mask for this object"); - PDFDebugger.dump(obj); - BaseWatchable.getErrorHandler().publishException(ex); - } - } else if (sMaskObj.getType() == PDFObject.ARRAY) { - // retrieve the range of the ColorKeyMask - // colors outside this range will not be painted. - try { - image.setColorKeyMask(sMaskObj); - } catch (IOException ex) { - PDFDebugger.debug("ERROR: there was a problem parsing the color mask for this object"); - PDFDebugger.dump(obj); - BaseWatchable.getErrorHandler().publishException(ex); - } - } + if (obj.getDictRef("SMask") != null) { + image.setSMask(PDFImage.createImage(obj.getDictRef("SMask"), resources, true)); } } - return image; } - /** - * Get the image that this PDFImage generates. - * - * @return a buffered image containing the decoded image data - * @throws PDFImageParseException - */ public BufferedImage getImage() throws PDFImageParseException { try { BufferedImage bi = (BufferedImage) this.imageObj.getCache(); - if (bi == null) { byte[] data = imageObj.getStream(); - ByteBuffer jpegBytes = null; - if (this.jpegDecode) { - // if we're lucky, the stream will have just the DCT - // filter applied to it, and we'll have a reference to - // an underlying mapped file, so we'll manage to avoid - // a copy of the encoded JPEG bytes - jpegBytes = imageObj.getStreamBuffer(PDFDecoder.DCT_FILTERS); - } - // parse the stream data into an actual image + ByteBuffer jpegBytes = this.jpegDecode ? imageObj.getStreamBuffer(PDFDecoder.DCT_FILTERS) : null; bi = parseData(data, jpegBytes); this.imageObj.setCache(bi); } return bi; } catch (IOException ioe) { - // let the caller know that there was a problem parsing the image - throw new PDFImageParseException("Error reading image: "+ioe.getMessage(), ioe); + throw new PDFImageParseException("Error reading image: " + ioe.getMessage(), ioe); } } - /** - *

    - * Parse the image stream into a buffered image. Note that this is - * guaranteed to be called after all the other setXXX methods have been - * called. - *

    - * - *

    - * NOTE: the color convolving is extremely slow on large images. It would be - * good to see if it could be moved out into the rendering phases, where we - * might be able to scale the image down first.

    RGB - // transformation when reading JPEGs does not adhere to the spec. - // We're just going to let java read this in - as it is, the - // standard - // jpeg reader looks for the specific Adobe marker header so that - // it may apply the transform, so that's good. If that marker - // isn't present, then it also applies a number of other heuristics - // to determine whether the transform should be applied. - // (http://java.sun.com/javase/6/docs/api/javax/imageio/metadata/doc-files/jpeg_metadata.html) - // In practice, it probably almost always does the right thing here, - // though note that the present or default value of the - // ColorTransform - // dictionary entry is not being observed, so there is scope for - // error. Hopefully the JAI reader does the same. - - // We might need to attempt this with multiple readers, so let's - // remember where the jpeg data starts - jpegData.mark(); - - JpegDecoder decoder = new JpegDecoder(jpegData, cm); - - IOException decodeEx = null; - try { - bi = decoder.decode(); - } catch (IOException e) { - decodeEx = e; - // The native readers weren't able to process the image. - // One common situation is that the image is YCCK/CMYK encoded, - // which isn't supported by the default jpeg readers. - // We've got a work-around we can attempt, though: - decoder.ycckcmykDecodeMode(true); - try { - bi = decoder.decode(); - } catch (IOException e2) { - // It probably wasn't the YCCK/CMYK issue! - // try the "old" implementation - bi = parseData(data, null); - return bi; - } - } - - // the decoder may have requested installation of a new color model - cm = decoder.getColorModel(); - - // make these immediately unreachable, as the referenced - // jpeg data might be quite large - jpegData = null; - decoder = null; - - if (bi == null) { - // This isn't pretty, but it's what's been happening - // previously, so we'll preserve it for the time - // being. At least we'll offer a hint now! - assert decodeEx != null; - throw new IOException(decodeEx.getMessage() + ". Maybe installing JAI for expanded image format " - + "support would help?", decodeEx); - } + bi = decodeJPEG(jpegData, cm); } else { - // create the data buffer DataBuffer db = new DataBufferByte(data, data.length); - // pick a color model, based on the number of components and - // bits per component - cm = getColorModel(); - - // create a compatible raster + // Check if the data array is large enough SampleModel sm = cm.createCompatibleSampleModel(getWidth(), getHeight()); - WritableRaster raster; - try { - raster = Raster.createWritableRaster(sm, db, new Point(0, 0)); - } catch (RasterFormatException e) { - int tempExpectedSize = getWidth() * getHeight() * getColorSpace().getNumComponents() - * Math.max(8, getBitsPerComponent()) / 8; - - if (tempExpectedSize < 3) { - tempExpectedSize = 3; - } - if (tempExpectedSize > data.length) { - byte[] tempLargerData = new byte[tempExpectedSize]; - System.arraycopy(data, 0, tempLargerData, 0, data.length); - db = new DataBufferByte(tempLargerData, tempExpectedSize); - raster = Raster.createWritableRaster(sm, db, new Point(0, 0)); - } else { - throw e; - } + int expectedSize = sm.getWidth() * sm.getHeight() * sm.getNumBands(); + if (data.length < expectedSize) { + throw new IOException("Data array too small, expected at least " + expectedSize + " bytes."); } - /* - * Workaround for a bug on the Mac -- a class cast exception in - * drawImage() due to the wrong data buffer type (?) - */ - bi = null; - if (cm instanceof IndexColorModel) { - IndexColorModel icm = (IndexColorModel) cm; - - // choose the image type based on the size - int type = BufferedImage.TYPE_BYTE_BINARY; - if (getBitsPerComponent() == 8) { - type = BufferedImage.TYPE_BYTE_INDEXED; - } - - // create the image with an explicit indexed color model. - bi = new BufferedImage(getWidth(), getHeight(), type, icm); - - // set the data explicitly as well - bi.setData(raster); - } else if (cm.getPixelSize() == 1 && cm.getNumComponents() == 1) { - // If the image is black and white only, convert it into - // BYTE_GRAY - // format - // This is a lot faster compared to just drawing the original - // image - - // Are pixels decoded? - int[] cc = new int[] { 0, 1 }; - PDFObject o = imageObj.getDictRef("Decode"); - if (o != null && o.getAt(0) != null) { - cc[0] = o.getAt(0).getIntValue(); - cc[1] = o.getAt(1).getIntValue(); - } - - final byte[] ncc = new byte[] { (byte) -cc[0], (byte) -cc[1] }; - - bi = biColorToGrayscale(raster, ncc); - // Return when there is no SMask - if (getSMask() == null) - return bi; - } else { - // Raster is already in a format which is supported by Java2D, - // such as RGB or Gray. - bi = new BufferedImage(cm, raster, true, null); - } + WritableRaster raster = Raster.createWritableRaster(sm, db, null); + bi = new BufferedImage(cm, raster, true, null); } - // hack to avoid *very* slow conversion - ColorSpace cs = cm.getColorSpace(); - ColorSpace rgbCS = ColorSpace.getInstance(ColorSpace.CS_sRGB); - if (isGreyscale(cs) && bpc <= 8 && getDecode() == null && jpegData == null - && Configuration.getInstance().isConvertGreyscaleImagesToArgb()) { - bi = convertGreyscaleToArgb(data, bi); - } else if (!isImageMask() && cs instanceof ICC_ColorSpace && !cs.equals(rgbCS) - && !Configuration.getInstance().isAvoidColorConvertOp()) { - ColorConvertOp op = new ColorConvertOp(cs, rgbCS, null); - - BufferedImage converted = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB); - - bi = op.filter(bi, converted); + if (sMask != null) { + bi = applySMask(bi, sMask.getImage()); } - else if (cs.getType() == ColorSpace.TYPE_CMYK) { - // convert to ARGB for faster drawing without ColorConvertOp - BufferedImage converted = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB); - Graphics2D graphics = converted.createGraphics(); - graphics.drawImage(bi,0,0,null); - graphics.dispose(); - bi = converted; - } - - // add in the alpha data supplied by the SMask, if any - PDFImage sMaskImage = getSMask(); - if (sMaskImage != null) { - BufferedImage si = null; - try { - int w = bi.getWidth(); - int h = bi.getHeight(); - // if the bitmap is only a few pixels it just defines the color - boolean maskOnly = (w <= 2); - if (maskOnly) { - // use size of mask - si = sMaskImage.getImage(); - w = si.getWidth(); - h = si.getHeight(); - } - else if (sMaskImage.getHeight() != h && sMaskImage.getWidth() != w) { - // in case the two images do not have the same size, scale - if (sMaskImage.getHeight()*sMaskImage.getWidth() > w*h) { - // upscale image - si = sMaskImage.getImage(); - w = si.getWidth(); - h = si.getHeight(); - int hints = Image.SCALE_FAST; - Image scaledInstance = bi.getScaledInstance(w, h, hints ); - bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); - Graphics graphics = bi.createGraphics(); - graphics.drawImage(scaledInstance, 0, 0, null); - graphics.dispose(); - } - else { - // upscale mask - si = scaleSMaskImage(sMaskImage); - } - } - else { - si = sMaskImage.getImage(); - } - PDFDebugger.debugImage(si, "smask" + this.imageObj.getObjNum()); - BufferedImage outImage = new BufferedImage(w,h, BufferedImage.TYPE_INT_ARGB); - PDFDebugger.debugImage(si, "outImage" + this.imageObj.getObjNum()); - int[] srcArray = new int[w]; - int[] maskArray = new int[w]; - - for (int i = 0; i < h; i++) { - if (maskOnly) { - // use first pixel color from image - Arrays.fill(srcArray, bi.getRGB(0,0)); - } - else { - // pixel row from image - bi.getRGB(0, i, w, 1, srcArray, 0, w); - } - // pixel row from mask - si.getRGB(0, i, w, 1, maskArray, 0, w); - - for (int j = 0; j < w; j++) { - int ac = 0xff000000; - // alpha from mask with color from image - maskArray[j] = ((maskArray[j] & 0xff) << 24) | (srcArray[j] & ~ac); - } - // write pixel row - outImage.setRGB(0, i, w, 1, maskArray, 0, w); - } - - bi = outImage; - } catch (PDFImageParseException e) { - PDFDebugger.debug("Error parsing sMask image caused by:" + e.getMessage(), 100); - } - } - - PDFDebugger.debugImage(bi, "result" + this.imageObj.getObjNum()); return bi; } - /** - * Scale the softmask image to the size of the actual image - * - * @param sMaskImage - * @return - * @throws PDFImageParseException - */ - private BufferedImage scaleSMaskImage(PDFImage sMaskImage) throws PDFImageParseException { - BufferedImage before = sMaskImage.getImage(); - int w = before.getWidth(); - int h = before.getHeight(); - - if (PDFDebugger.DEBUG_IMAGES) { - PDFDebugger.debug("Scaling image from " + w + "/" + h + " to " + this.width + "/" + this.height); - } - BufferedImage after = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); - AffineTransform at = new AffineTransform(); - - at.scale(((double) this.width / w), ((double) this.height / h)); - - AffineTransformOp scaleOp = new AffineTransformOp(at, AffineTransformOp.TYPE_BILINEAR); - return scaleOp.filter(before, after); - } - private boolean isGreyscale(ColorSpace aCs) { - return aCs == PDFColorSpace.getColorSpace(PDFColorSpace.COLORSPACE_GRAY).getColorSpace(); + private BufferedImage decodeJPEG(ByteBuffer jpegData, ColorModel cm) throws IOException { + ImageReader jpegReader = ImageIO.getImageReadersByFormatName("jpeg").next(); + jpegReader.setInput(ImageIO.createImageInputStream(new ByteBufferInputStream(jpegData)), true, false); + ImageReadParam param = new ImageReadParam(); + param.setDestination(new BufferedImage(cm, cm.createCompatibleWritableRaster(getWidth(), getHeight()), true, null)); + return jpegReader.read(0, param); } - private BufferedImage convertGreyscaleToArgb(byte[] data, BufferedImage bi) { - // we use an optimised greyscale colour conversion, as with scanned - // greyscale/mono documents consisting of nothing but page-size - // images, using the ICC converter is perhaps 15 times slower than this - // method. Using an example scanned, mainly monochrome document, on this - // developer's machine pages took an average of 3s to render using the - // ICC converter filter, and around 115ms using this method. We use - // pre-calculated tables generated using the ICC converter to map - // between - // each possible greyscale value and its desired value in sRGB. - // We also try to avoid going through SampleModels, WritableRasters or - // BufferedImages as that takes about 3 times as long. - final int[] convertedPixels = new int[getWidth() * getHeight()]; - final WritableRaster r = bi.getRaster(); - int i = 0; - final int[] greyToArgbMap = getGreyToArgbMap(bpc); - if (bpc == 1) { - int calculatedLineBytes = (getWidth() + 7) / 8; - int rowStartByteIndex; - // avoid hitting the WritableRaster for the common 1 bpc case - if (greyToArgbMap[0] == 0 && greyToArgbMap[1] == 0xFFFFFFFF) { - // optimisation for common case of a direct map to full white - // and black, using bit twiddling instead of consulting the - // greyToArgb map - for (int y = 0; y < getHeight(); ++y) { - // each row is byte-aligned - rowStartByteIndex = y * calculatedLineBytes; - for (int x = 0; x < getWidth(); ++x) { - final byte b = data[rowStartByteIndex + x / 8]; - final int white = b >> (7 - (x & 7)) & 1; - // if white == 0, white - 1 will be 0xFFFFFFFF, - // which when xored with 0xFFFFFF will produce 0 - // if white == 1, white - 1 will be 0, - // which when xored with 0xFFFFFF will produce 0xFFFFFF - // (ignoring the top two bytes, which are always set - // high anyway) - convertedPixels[i] = 0xFF000000 | ((white - 1) ^ 0xFFFFFF); - ++i; - } - } - } else { - // 1 bpc case where we can't bit-twiddle and need to consult - // the map - for (int y = 0; y < getHeight(); ++y) { - rowStartByteIndex = y * calculatedLineBytes; - for (int x = 0; x < getWidth(); ++x) { - final byte b = data[rowStartByteIndex + x / 8]; - final int val = b >> (7 - (x & 7)) & 1; - convertedPixels[i] = greyToArgbMap[val]; - ++i; - } - } - } - } else { - for (int y = 0; y < getHeight(); ++y) { - for (int x = 0; x < getWidth(); ++x) { - final int greyscale = r.getSample(x, y, 0); - convertedPixels[i] = greyToArgbMap[greyscale]; - ++i; - } + private BufferedImage applySMask(BufferedImage bi, BufferedImage smask) { + int w = bi.getWidth(); + int h = bi.getHeight(); + BufferedImage combined = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); + for (int y = 0; y < h; y++) { + for (int x = 0; x < w; x++) { + int rgb = bi.getRGB(x, y); + int alpha = smask.getRGB(x, y) & 0xFF; + combined.setRGB(x, y, (alpha << 24) | (rgb & 0xFFFFFF)); } } - - final ColorModel ccm = ColorModel.getRGBdefault(); - return new BufferedImage(ccm, - Raster.createPackedRaster(new DataBufferInt(convertedPixels, convertedPixels.length), getWidth(), - getHeight(), getWidth(), ((PackedColorModel) ccm).getMasks(), null), - false, null); + return combined; } - private static int[] getGreyToArgbMap(int numBits) { - assert numBits <= 8; - int[] argbVals = GREY_TO_ARGB[numBits - 1]; - if (argbVals == null) { - argbVals = createGreyToArgbMap(numBits); + private ColorModel createColorModel() { + if (colorSpace instanceof IndexedColor) { + return createIndexedColorModel((IndexedColor) colorSpace); + } else { + int[] bits = new int[colorSpace.getNumComponents()]; + for (int i = 0; i < bits.length; i++) { + bits[i] = bpc; + } + return new ComponentColorModel(colorSpace.getColorSpace(), bits, false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE); } - return argbVals; } - /** - * Create a map from all bit-patterns of a certain depth greyscale to the - * corresponding sRGB values via the ICC colorr converter. - * - * @param numBits - * the number of greyscale bits - * @return a 2^bits array of standard 32-bit ARGB fits for each greyscale - * value at that bitdepth - */ - private static int[] createGreyToArgbMap(int numBits) { - final ColorSpace greyCs = PDFColorSpace.getColorSpace(PDFColorSpace.COLORSPACE_GRAY).getColorSpace(); + private ColorModel createIndexedColorModel(IndexedColor ics) { + byte[] components = ics.getColorComponents(); + int num = ics.getCount(); - byte[] greyVals = new byte[1 << numBits]; - for (int i = 0; i < greyVals.length; ++i) { - greyVals[i] = (byte) (i & 0xFF); + if (decode != null) { + components = applyDecodeArray(components, decode); } - final int[] argbVals = new int[greyVals.length]; - final int mask = (1 << numBits) - 1; - final WritableRaster inRaster = Raster.createPackedRaster(new DataBufferByte(greyVals, greyVals.length), - greyVals.length, 1, greyVals.length, new int[] { mask }, null); - - final BufferedImage greyImage = new BufferedImage(new PdfComponentColorModel(greyCs, new int[] { numBits }), - inRaster, false, null); - - final ColorModel ccm = ColorModel.getRGBdefault(); - final WritableRaster outRaster = Raster.createPackedRaster(new DataBufferInt(argbVals, argbVals.length), - argbVals.length, 1, argbVals.length, ((PackedColorModel) ccm).getMasks(), null); - final BufferedImage srgbImage = new BufferedImage(ccm, outRaster, false, null); - - final ColorConvertOp op = new ColorConvertOp(greyCs, ColorSpace.getInstance(ColorSpace.CS_sRGB), null); - - op.filter(greyImage, srgbImage); - - GREY_TO_ARGB[numBits - 1] = argbVals; - return argbVals; + return new IndexColorModel(bpc, num, components, 0, false); } - /** - * Creates a new image of type {@link TYPE_BYTE_GRAY} which represents the - * given raster - * - * @param raster - * Raster of an image with just two colors, bitwise encoded - * @param ncc - * Array with two entries that describe the corresponding gray - * values - */ - private BufferedImage biColorToGrayscale(final WritableRaster raster, final byte[] ncc) { - - final byte[] bufferO = ((DataBufferByte) raster.getDataBuffer()).getData(); - - BufferedImage converted = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_BYTE_GRAY); - - byte[] buffer = ((DataBufferByte) converted.getRaster().getDataBuffer()).getData(); - int i = 0; - final int height = converted.getHeight(); - final int width = converted.getWidth(); - for (int y = 0; y < height; y++) { - int base = y * width + 7; - if ((y + 1) * width < buffer.length) { - for (int x = 0; x < width; x += 8) { - final byte bits = bufferO[i]; - i++; - for (byte j = 7; j >= 0; j--) { - if (buffer.length <= (base - j)) { - break; - } - final int c = ((bits >>> j) & 1); - buffer[base - j] = ncc[c]; - } - base += 8; - } - } else { - for (int x = 0; x < width; x += 8) { - final byte bits = bufferO[i]; - i++; - for (byte j = 7; j >= 0; j--) { - if (base - j >= buffer.length) - break; - buffer[base - j] = ncc[((bits >>> j) & 1)]; - } - base += 8; - } - } + private static byte[] applyDecodeArray(byte[] components, float[] decode) { + byte[] normComps = new byte[components.length]; + for (int i = 0; i < components.length / 3; i++) { + int idx = (int) ((decode[i * 2] * (components.length - 1)) / (decode[(i * 2) + 1] - decode[i * 2])); + normComps[i * 3] = components[idx * 3]; + normComps[(i * 3) + 1] = components[(idx * 3) + 1]; + normComps[(i * 3) + 2] = components[(idx * 3) + 2]; } - return converted; + return normComps; + } + + private static float[] parseDecodeArray(PDFObject[] decodeArray) { + float[] decode = new float[decodeArray.length]; + for (int i = 0; i < decodeArray.length; i++) { + try { + decode[i] = decodeArray[i].getFloatValue(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + return decode; } - /** - * Get the image's width - */ public int getWidth() { return this.width; } - /** - * Set the image's width - */ protected void setWidth(int width) { this.width = width; } - /** - * Get the image's height - */ public int getHeight() { return this.height; } - /** - * Set the image's height - */ protected void setHeight(int height) { this.height = height; } - /** - * set the color key mask. It is an array of start/end entries to indicate - * ranges of color indicies that should be masked out. - * - * @param maskArrayObject - */ - private void setColorKeyMask(PDFObject maskArrayObject) throws IOException { - PDFObject[] maskObjects = maskArrayObject.getArray(); - this.colorKeyMask = null; - int[] masks = new int[maskObjects.length]; - for (int i = 0; i < masks.length; i++) { - masks[i] = maskObjects[i].getIntValue(); - } - this.colorKeyMask = masks; - } - - /** - * Get the colorspace associated with this image, or null if there isn't one - */ - protected PDFColorSpace getColorSpace() { - return this.colorSpace; - } - - /** - * Set the colorspace associated with this image - */ protected void setColorSpace(PDFColorSpace colorSpace) { this.colorSpace = colorSpace; } - /** - * Get the number of bits per component sample - */ - protected int getBitsPerComponent() { - return this.bpc; - } - - /** - * Set the number of bits per component sample - */ protected void setBitsPerComponent(int bpc) { this.bpc = bpc; } - /** - * Return whether or not this is an image mask - */ public boolean isImageMask() { return this.imageMask; } - /** - * Set whether or not this is an image mask - */ public void setImageMask(boolean imageMask) { this.imageMask = imageMask; } - /** - * Return the soft mask associated with this image - */ public PDFImage getSMask() { return this.sMask; } - /** - * Set the soft mask image - */ protected void setSMask(PDFImage sMask) { this.sMask = sMask; } - /** - * Get the decode array - */ - protected float[] getDecode() { - return this.decode; - } - - /** - * Set the decode array - */ protected void setDecode(float[] decode) { this.decode = decode; } - - /** - * get a Java ColorModel consistent with the current color space, number of - * bits per component and decode array - * - * @param bpc - * the number of bits per component - */ - private ColorModel getColorModel() { - PDFColorSpace cs = getColorSpace(); - - if (cs instanceof IndexedColor) { - IndexedColor ics = (IndexedColor) cs; - - byte[] components = ics.getColorComponents(); - int num = ics.getCount(); - - // process the decode array - if (this.decode != null) { - byte[] normComps = new byte[components.length]; - - // move the components array around - for (int i = 0; i < num; i++) { - byte[] orig = new byte[1]; - orig[0] = (byte) i; - - float[] res = normalize(orig, null, 0); - int idx = (int) res[0]; - - normComps[i * 3] = components[idx * 3]; - normComps[(i * 3) + 1] = components[(idx * 3) + 1]; - normComps[(i * 3) + 2] = components[(idx * 3) + 2]; - } - - components = normComps; - } - - // make sure the size of the components array is 2 ^ numBits - // since if it's not, Java will complain - int correctCount = 1 << getBitsPerComponent(); - if (correctCount < num) { - byte[] fewerComps = new byte[correctCount * 3]; - - System.arraycopy(components, 0, fewerComps, 0, correctCount * 3); - - components = fewerComps; - num = correctCount; - } - if (this.colorKeyMask == null || this.colorKeyMask.length == 0) { - return new IndexColorModel(getBitsPerComponent(), num, components, 0, false); - } else { - byte[] aComps = new byte[num * 4]; - int idx = 0; - for (int i = 0; i < num; i++) { - aComps[idx++] = components[(i * 3)]; - aComps[idx++] = components[(i * 3) + 1]; - aComps[idx++] = components[(i * 3) + 2]; - aComps[idx++] = (byte) 0xFF; - } - for (int i = 0; i < this.colorKeyMask.length; i += 2) { - for (int j = this.colorKeyMask[i]; j <= this.colorKeyMask[i + 1]; j++) { - aComps[(j * 4) + 3] = 0; // make transparent - } - } - return new IndexColorModel(getBitsPerComponent(), num, aComps, 0, true); - } - } else if (cs instanceof AlternateColorSpace) { - // ColorSpace altCS = new AltColorSpace(((AlternateColorSpace) - // cs).getFunktion(), cs.getColorSpace()); - ColorSpace altCS = cs.getColorSpace(); - int[] bits = new int[altCS.getNumComponents()]; - for (int i = 0; i < bits.length; i++) { - bits[i] = getBitsPerComponent(); - } - return new DecodeComponentColorModel(altCS, bits); - } else { - // If the image is a JPEG, then CMYK color space has been converted to RGB in DCTDecode - if (this.jpegDecode && cs.getColorSpace().getType() == ColorSpace.TYPE_CMYK) { - ColorSpace rgbCS = ColorSpace.getInstance(ColorSpace.CS_sRGB); - int[] bits = new int[rgbCS.getNumComponents()]; - for (int i = 0; i < bits.length; i++) { - bits[i] = getBitsPerComponent(); - } - return new DecodeComponentColorModel(rgbCS, bits); - } - ColorSpace colorSpace = cs.getColorSpace(); - int[] bits = new int[colorSpace.getNumComponents()]; - for (int i = 0; i < bits.length; i++){ - bits[i] = getBitsPerComponent(); - } - - return new DecodeComponentColorModel(cs.getColorSpace(), bits); - } - } - - /** - * Normalize an array of values to match the decode array - */ - private float[] normalize(byte[] pixels, float[] normComponents, int normOffset) { - if (normComponents == null) { - normComponents = new float[normOffset + pixels.length]; - } - - float[] decodeArray = getDecode(); - - for (int i = 0; i < pixels.length; i++) { - int val = pixels[i] & 0xff; - int pow = ((int) Math.pow(2, getBitsPerComponent())) - 1; - float ymin = decodeArray[i * 2]; - float ymax = decodeArray[(i * 2) + 1]; - - normComponents[normOffset + i] = FunctionType0.interpolate(val, 0, pow, ymin, ymax); - } - - return normComponents; - } - - /** - * A wrapper for ComponentColorSpace which normalizes based on the decode - * array. - */ - class DecodeComponentColorModel extends ComponentColorModel { - - public DecodeComponentColorModel(ColorSpace cs, int[] bpc) { - super(cs, bpc, false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE); - - if (bpc != null) { - this.pixel_bits = bpc.length * bpc[0]; - } - } - - @Override - public SampleModel createCompatibleSampleModel(int width, int height) { - // workaround -- create a MultiPixelPackedSample models for - // single-sample, less than 8bpp color models - if (getNumComponents() == 1 && getPixelSize() < 8) { - return new MultiPixelPackedSampleModel(getTransferType(), width, height, getPixelSize()); - } - - return super.createCompatibleSampleModel(width, height); - } - - @Override - public boolean isCompatibleRaster(Raster raster) { - if (getNumComponents() == 1 && getPixelSize() < 8) { - SampleModel sm = raster.getSampleModel(); - - if (sm instanceof MultiPixelPackedSampleModel) { - return (sm.getSampleSize(0) == getPixelSize()); - } else { - return false; - } - } - - return super.isCompatibleRaster(raster); - } - - @Override - public float[] getNormalizedComponents(Object pixel, float[] normComponents, int normOffset) { - if (getDecode() == null) { - return super.getNormalizedComponents(pixel, normComponents, normOffset); - } - - return normalize((byte[]) pixel, normComponents, normOffset); - } - } - - /** - * get a Java ColorModel consistent with the current color space, number of - * bits per component and decode array - * - * @param bpc - * the number of bits per component - */ - private ColorModel createColorModel() { - PDFColorSpace cs = getColorSpace(); - - if (cs instanceof IndexedColor) { - IndexedColor ics = (IndexedColor) cs; - - byte[] components = ics.getColorComponents(); - int num = ics.getCount(); - - // process the decode array - if (decode != null) { - byte[] normComps = new byte[components.length]; - - // move the components array around - for (int i = 0; i < num; i++) { - byte[] orig = new byte[1]; - orig[0] = (byte) i; - - float[] res = normalize(orig, null, 0); - int idx = (int) res[0]; - - normComps[i * 3] = components[idx * 3]; - normComps[(i * 3) + 1] = components[(idx * 3) + 1]; - normComps[(i * 3) + 2] = components[(idx * 3) + 2]; - } - - components = normComps; - } - - // make sure the size of the components array is 2 ^ numBits - // since if it's not, Java will complain - int correctCount = 1 << getBitsPerComponent(); - if (correctCount < num) { - byte[] fewerComps = new byte[correctCount * 3]; - - System.arraycopy(components, 0, fewerComps, 0, correctCount * 3); - - components = fewerComps; - num = correctCount; - } - if (colorKeyMask == null || colorKeyMask.length == 0) { - return new IndexColorModel(getBitsPerComponent(), num, components, 0, false); - } else { - byte[] aComps = new byte[num * 4]; - int idx = 0; - for (int i = 0; i < num; i++) { - aComps[idx++] = components[(i * 3)]; - aComps[idx++] = components[(i * 3) + 1]; - aComps[idx++] = components[(i * 3) + 2]; - aComps[idx++] = (byte) 0xFF; - } - for (int i = 0; i < colorKeyMask.length; i += 2) { - for (int j = colorKeyMask[i]; j <= colorKeyMask[i + 1]; j++) { - aComps[(j * 4) + 3] = 0; // make transparent - } - } - return new IndexColorModel(getBitsPerComponent(), num, aComps, 0, true); - } - } else { - int[] bits = new int[cs.getNumComponents()]; - for (int i = 0; i < bits.length; i++) { - bits[i] = getBitsPerComponent(); - } - - return decode != null ? new DecodeComponentColorModel(cs.getColorSpace(), bits) - : new PdfComponentColorModel(cs.getColorSpace(), bits); - } - } - - /** - * Decodes jpeg data, possibly attempting a manual YCCK decode if requested. - * Users should use {@link #getColorModel()} to see which color model should - * now be used after a successful decode. - */ - private class JpegDecoder { - /** The jpeg bytes */ - private final ByteBuffer jpegData; - /** The color model employed */ - private ColorModel cm; - /** Whether the YCCK/CMYK decode work-around should be used */ - private boolean ycckcmykDecodeMode = false; - - /** - * Class constructor - * - * @param jpegData - * the JPEG data - * @param cm - * the color model as presented in the PDF - */ - private JpegDecoder(ByteBuffer jpegData, ColorModel cm) { - this.jpegData = jpegData; - this.cm = cm; - } - - /** - * Identify whether the decoder should operate in YCCK/CMYK decode mode, - * whereby the YCCK Chroma is specifically looked for and the color - * model is changed to support converting raw YCCK color values, working - * around a lack of YCCK/CMYK report in the standard Java jpeg readers. - * Non-YCCK images will not be decoded while in this mode. - * - * @param ycckcmykDecodeMode - */ - public void ycckcmykDecodeMode(boolean ycckcmykDecodeMode) { - this.ycckcmykDecodeMode = ycckcmykDecodeMode; - } - - /** - * Get the color model that should be used now - * - * @return - */ - public ColorModel getColorModel() { - return cm; - } - - /** - * Attempt to decode the jpeg data - * - * @return the successfully decoded image - * @throws IOException - * if the image couldn't be decoded due to a lack of support - * or some IO problem - */ - private BufferedImage decode() throws IOException { - - ImageReadParam readParam = null; - if (getDecode() != null) { - // we have to allocate our own buffered image so that we can - // install our colour model which will do the desired decode - readParam = new ImageReadParam(); - SampleModel sm = cm.createCompatibleSampleModel(getWidth(), getHeight()); - final WritableRaster raster = Raster.createWritableRaster(sm, new Point(0, 0)); - readParam.setDestination(new BufferedImage(cm, raster, true, null)); - } - - Iterator jpegReaderIt = ImageIO.getImageReadersByFormatName("jpeg"); - IIOException lastIioEx = null; - while (jpegReaderIt.hasNext()) { - try { - final ImageReader jpegReader = jpegReaderIt.next(); - jpegReader.setInput(ImageIO.createImageInputStream(new ByteBufferInputStream(jpegData)), true, - false); - try { - return readImage(jpegReader, readParam); - } catch (Exception e) { - if (e instanceof IIOException) { - throw (IIOException) e; - } - // Any other exceptions here are probably due to - // internal - // problems with the image reader. - // A concrete example of this happening is described - // here: - // http://java.net/jira/browse/PDF_RENDERER-132 where - // JAI imageio extension throws an - // IndexOutOfBoundsException on progressive JPEGs. - // We'll just treat it as an IIOException for - // convenience - // and hopefully a subsequent reader can handle it - throw new IIOException("Internal reader error?", e); - } finally { - jpegReader.dispose(); - } - } catch (IIOException e) { - // its most likely complaining about an unsupported image - // type; hopefully the next image reader will be able to - // understand it - jpegData.reset(); - lastIioEx = e; - } - } - - throw lastIioEx; - - } - - private BufferedImage readImage(ImageReader jpegReader, ImageReadParam param) throws IOException { - if (ycckcmykDecodeMode) { - // The standard Oracle Java JPEG readers can't deal with CMYK - // YCCK encoded images - // without a little help from us. We'll try and pick up such - // instances and work around it. - final IIOMetadata imageMeta = jpegReader.getImageMetadata(0); - if (imageMeta != null) { - final Node standardMeta = imageMeta.getAsTree(IIOMetadataFormatImpl.standardMetadataFormatName); - if (standardMeta != null) { - final Node chroma = getChild(standardMeta, "Chroma"); - if (chroma != null) { - final Node csType = getChild(chroma, "ColorSpaceType"); - if (csType != null) { - final Attr csTypeNameNode = (Attr) csType.getAttributes().getNamedItem("name"); - if (csTypeNameNode != null) { - final String typeName = csTypeNameNode.getValue(); - final boolean YCCK; - if ((YCCK = "YCCK".equals(typeName)) || "CMYK".equals(typeName)) { - // If it's a YCCK image, then we can - // coax a workable image out of it - // by grabbing the raw raster and - // installing a YCCK converting - // color space wrapper around the - // existing (CMYK) color space; this - // will - // do the YCCK conversion for us - // - // If it's a CMYK image - just raster it - // in existing CMYK color space - - // first make sure we can get the - // unadjusted raster - final Raster raster = jpegReader.readRaster(0, param); - - if (YCCK) { - // and now use it with a YCCK - // converting color space. - PDFImage.this.colorSpace = new PDFColorSpace( - new YCCKColorSpace(colorSpace.getColorSpace())); - // re-calculate the color model - // since the color space has changed - cm = PDFImage.this.createColorModel(); - } - - return new BufferedImage(cm, Raster.createWritableRaster( - raster.getSampleModel(), raster.getDataBuffer(), null), true, null); - - } - } - } - } - } - } - - throw new IIOException("Neither YCCK nor CMYK image"); - - } else { - - if (param != null && param.getDestination() != null) { - // if we've already set up a destination image then we'll - // use it - return jpegReader.read(0, param); - } else { - // otherwise we'll create a new buffered image with the - // desired color model - //return new BufferedImage(cm, jpegReader.read(0, param).getRaster(), true, null); - BufferedImage bi = jpegReader.read(0, param); - try { - return new BufferedImage(cm, bi.getRaster(), true, null); - } catch (IllegalArgumentException raster_ByteInterleavedRaster) { - BufferedImage bi2 = new BufferedImage(bi.getWidth(), bi.getHeight(), - BufferedImage.TYPE_BYTE_INDEXED, - new IndexColorModel(8, 1, new byte[] { 0 }, new byte[] { 0 }, new byte[] { 0 }, 0)); - cm = bi2.getColorModel(); - return bi2; - } - } - } - - } - - /** - * Get a named child node - * - * @param aNode - * the node - * @param aChildName - * the name of the child node - * @return the first direct child node with that name or null if it - * doesn't exist - */ - private Node getChild(Node aNode, String aChildName) { - for (int i = 0; i < aNode.getChildNodes().getLength(); ++i) { - final Node child = aNode.getChildNodes().item(i); - if (child.getNodeName().equals(aChildName)) { - return child; - } - } - return null; - } - } - - /** - * A wrapper for ComponentColorSpace which normalizes based on the decode - * array. - */ - static class PdfComponentColorModel extends ComponentColorModel { - - int bitsPerComponent; - - public PdfComponentColorModel(ColorSpace cs, int[] bpc) { - super(cs, bpc, false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE); - - pixel_bits = bpc.length * bpc[0]; - this.bitsPerComponent = bpc[0]; - } - - @Override - public SampleModel createCompatibleSampleModel(int width, int height) { - - if (bitsPerComponent >= 8) { - assert bitsPerComponent == 8 || bitsPerComponent == 16; - final int numComponents = getNumComponents(); - int[] bandOffsets = new int[numComponents]; - for (int i = 0; i < numComponents; i++) { - bandOffsets[i] = i; - } - return new PixelInterleavedSampleModel(getTransferType(), width, height, numComponents, - width * numComponents, bandOffsets); - } else { - switch (getPixelSize()) { - case 1: - case 2: - case 4: - // pixels don't span byte boundaries, so we can use the - // standard multi pixel - // packing, which offers a slight performance advantage over - // the other sample - // model, which must consider such cases. Given that sample - // model interactions - // can dominate processing, this small distinction is - // worthwhile - return new MultiPixelPackedSampleModel(getTransferType(), width, height, getPixelSize()); - default: - // pixels will cross byte boundaries - assert getTransferType() == DataBuffer.TYPE_BYTE; - return new PdfSubByteSampleModel(width, height, getNumComponents(), bitsPerComponent); - } - } - } - - @Override - public boolean isCompatibleRaster(Raster raster) { - if (bitsPerComponent < 8 || getNumComponents() == 1) { - SampleModel sm = raster.getSampleModel(); - return sm.getSampleSize(0) == bitsPerComponent; - } - return super.isCompatibleRaster(raster); - } - - } -} \ No newline at end of file +} diff --git a/openpdf-pdfrenderer/src/test/java/PdfRendererToImageTest.java b/openpdf-pdfrenderer/src/test/java/PdfRendererToImageTest.java index 0b6018887..1e30038bf 100644 --- a/openpdf-pdfrenderer/src/test/java/PdfRendererToImageTest.java +++ b/openpdf-pdfrenderer/src/test/java/PdfRendererToImageTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2024 Andreas Røsdal. + * Copyright 2024 OpenPDF * * The contents of this file are subject to the Mozilla Public License Version 1.1 * (the "License"); you may not use this file except in compliance with the License. @@ -9,13 +9,13 @@ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the License. * - * The Original Code is 'OpenPDF'. + * The Original Code is 'iText, a free JAVA-PDF library'. * * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by - * the Initial Developer are Copyright (C) 1999-2008 by Bruno Lowagie. + * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. * All Rights Reserved. * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer - * are Copyright (C) 2000-2008 by Paulo Soares. All Rights Reserved. + * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. * * Contributor(s): all the names of the contributors are added in the source code * where applicable. @@ -45,10 +45,8 @@ * https://github.com/LibrePDF/OpenPDF */ -import com.lowagie.text.Document; -import com.lowagie.text.DocumentException; -import com.lowagie.text.Paragraph; -import com.lowagie.text.pdf.PdfWriter; + +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import com.github.librepdf.pdfrenderer.PDFFile; import com.github.librepdf.pdfrenderer.PDFPage; @@ -60,61 +58,88 @@ import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.nio.ByteBuffer; -import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.*; public class PdfRendererToImageTest { - @Test - public void testPDFRenderToImage() throws DocumentException, IOException { - // Step 1: Create a sample PDF using OpenPDF - byte[] pdfBytes = createSamplePdf(); - - // Step 2: Load the PDF using PDFRenderer - PDFFile pdfFile = new PDFFile(ByteBuffer.wrap(pdfBytes)); - - // Ensure there is at least one page in the PDF - int numPages = pdfFile.getNumPages(); - assert(numPages > 0); - - // Use the correct page index (PDFRenderer typically uses 1-based indexing) - PDFPage page = pdfFile.getPage(1, true); // Fetch the first page - - // Step 3: Setup the dimensions for the output image - int width = (int) page.getBBox().getWidth(); - int height = (int) page.getBBox().getHeight(); - BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); - Graphics2D g2d = image.createGraphics(); - g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); - - // Step 4: Render the page to the image - Rectangle rect = new Rectangle(0, 0, width, height); - PDFRenderer renderer = new PDFRenderer(page, g2d, rect, null, Color.WHITE); - renderer.run(); - - // Step 5: Save the image to a file (for verification) - File outputfile = new File("pdf-to-image-test-output.png"); - ImageIO.write(image, "png", outputfile); - - // Step 6: Assert that the image is not null - assertNotNull(image, "Image should not be null"); - - // Cleanup graphics object - g2d.dispose(); + private byte[][] pdfBytesArray; + + @BeforeEach + public void setUp() throws Exception { + // Array of PDF file names + String[] pdfFiles = {"invoice-1.pdf", "pdfsmartcopy_bec_image.pdf"}; + pdfBytesArray = new byte[pdfFiles.length][]; + + // Load each PDF file from the resources directory and convert it to bytes + for (int i = 0; i < pdfFiles.length; i++) { + try (InputStream inputStream = getClass().getClassLoader().getResourceAsStream(pdfFiles[i])) { + assertNotNull(inputStream, "PDF file not found in resources: " + pdfFiles[i]); + pdfBytesArray[i] = readPdfToByteArray(inputStream); + } + } } - private byte[] createSamplePdf() throws DocumentException, IOException { - // Use OpenPDF to create a simple PDF in memory - Document document = new Document(); + private byte[] readPdfToByteArray(InputStream inputStream) throws IOException { + // Read the entire InputStream into a ByteArrayOutputStream, then convert to byte[] ByteArrayOutputStream baos = new ByteArrayOutputStream(); - PdfWriter.getInstance(document, baos); + byte[] buffer = new byte[1024]; + int length; + while ((length = inputStream.read(buffer)) != -1) { + baos.write(buffer, 0, length); + } + return baos.toByteArray(); + } - document.open(); - document.add(new Paragraph("Hello, World! This is a test PDF.")); - document.close(); + @Test + public void testPDFRenderToImage() throws IOException { + String[] pdfFiles = {"invoice-1.pdf", "pdfsmartcopy_bec_image.pdf"}; - return baos.toByteArray(); + for (int i = 0; i < pdfBytesArray.length; i++) { + byte[] pdfBytes = pdfBytesArray[i]; + + // Step 1: Load the PDF using PDFRenderer + PDFFile pdfFile = new PDFFile(ByteBuffer.wrap(pdfBytes)); + + // Ensure there is at least one page in the PDF + int numPages = pdfFile.getNumPages(); + assertTrue(numPages > 0, "PDF should contain at least one page"); + + // Use the correct page index (PDFRenderer typically uses 1-based indexing) + PDFPage page = pdfFile.getPage(1, true); // Fetch the first page + + // Step 2: Setup the dimensions for the output image + int width = (int) page.getBBox().getWidth(); + int height = (int) page.getBBox().getHeight(); + BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); + Graphics2D g2d = image.createGraphics(); + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); + + // Step 3: Render the page to the image + Rectangle rect = new Rectangle(0, 0, width, height); + PDFRenderer renderer = new PDFRenderer(page, g2d, rect, null, Color.WHITE); + + renderer.run(); + + // Step 4: Save the image to a file (for verification) + File outputfile = new File("pdf-to-image-test-output-" + pdfFiles[i] + ".png"); + ImageIO.write(image, "png", outputfile); + + // Step 5: Verify that the image was saved correctly + assertTrue(outputfile.exists(), "Output image file should exist for " + pdfFiles[i]); + assertTrue(outputfile.length() > 0, "Output image file should not be empty for " + pdfFiles[i]); + + // Step 6: Load the image back and check its properties + BufferedImage loadedImage = ImageIO.read(outputfile); + assertNotNull(loadedImage, "Loaded image should not be null for " + pdfFiles[i]); + assertEquals(width, loadedImage.getWidth(), "Image width should match the PDF page width for " + pdfFiles[i]); + assertEquals(height, loadedImage.getHeight(), "Image height should match the PDF page height for " + pdfFiles[i]); + + // Cleanup graphics object + g2d.dispose(); + } } } diff --git a/openpdf-pdfrenderer/src/test/resources/invoice-1.pdf b/openpdf-pdfrenderer/src/test/resources/invoice-1.pdf new file mode 100644 index 0000000000000000000000000000000000000000..9074e23b452db23d5affe956a5fd92263d6bb954 GIT binary patch literal 41894 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¨b6TvnC*+M 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 literal 0 HcmV?d00001 diff --git a/openpdf-pdfrenderer/src/test/resources/pdfsmartcopy_bec_image.pdf b/openpdf-pdfrenderer/src/test/resources/pdfsmartcopy_bec_image.pdf new file mode 100644 index 0000000000000000000000000000000000000000..63d56fd199f67b882d820ee302b49728e4c6ec8b GIT binary patch literal 208584 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 AFaQ7m literal 0 HcmV?d00001 From 8e940135356f56a308b6fbd1166aaffbf3c5b14f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20R=C3=B8sdal?= <41650711+andreasrosdal@users.noreply.github.com> Date: Sat, 17 Aug 2024 14:59:54 +0200 Subject: [PATCH 6/7] Add test case for https://github.com/LibrePDF/OpenPDF/issues/1199 --- .../com/lowagie/text/pdf/ReadPDFR5Test.java | 36 ++++++++++++++++++ openpdf/src/test/resources/r-equals-5.pdf | Bin 0 -> 2881 bytes 2 files changed, 36 insertions(+) create mode 100644 openpdf/src/test/java/com/lowagie/text/pdf/ReadPDFR5Test.java create mode 100644 openpdf/src/test/resources/r-equals-5.pdf diff --git a/openpdf/src/test/java/com/lowagie/text/pdf/ReadPDFR5Test.java b/openpdf/src/test/java/com/lowagie/text/pdf/ReadPDFR5Test.java new file mode 100644 index 000000000..c17f447b6 --- /dev/null +++ b/openpdf/src/test/java/com/lowagie/text/pdf/ReadPDFR5Test.java @@ -0,0 +1,36 @@ +package com.lowagie.text.pdf; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + + +import java.io.IOException; +import java.io.InputStream; + +/** + * Test case for https://github.com/LibrePDF/OpenPDF/issues/1199 + */ +public class ReadPDFR5Test { + + @Test + @Disabled + void testReadEncryptionREquals5() throws IOException { + InputStream inputStream = getClass().getClassLoader().getResourceAsStream("r-equals-5.pdf"); + Assertions.assertNotNull(inputStream, "PDF file not found"); + + PdfReader pdfReader = null; + + try { + pdfReader = new PdfReader(inputStream); + pdfReader.close(); + + + } finally { + if (pdfReader != null) { + pdfReader.close(); + } + + } + } +} diff --git a/openpdf/src/test/resources/r-equals-5.pdf b/openpdf/src/test/resources/r-equals-5.pdf new file mode 100644 index 0000000000000000000000000000000000000000..b0b57ddbdb264b55e998f4f1c5ba23afd9f7f481 GIT binary patch literal 2881 zcmc&$dsGzH8COY<$@*wgjmNa+WI$GSsW7jd*&Poq!t#(eEQ+QK>g>+!vI09gI}0M3 z*wPw>pn*t*Y7~{CRS`9sB1()XQHiL4)CZ{=P~!tD*boE_?Y#>~B~AKYbI;ki_kQ<# z-TVFS@2)a7D8vW%B^AonwhK)P3c(Q3v{>QihlbcvWkEtiQaM=&63ikmppk;zDkmc( zN$d3vSrWK3#VYbv)yNSC&uqNlCaljZOYT@avgYFBSqCs>SA^l*s1c8`o|OGbtKV## zzR=P#;Yv#GzK4ID|4uboGKH_SHXZGJ`BCqeN6k;V=eCSHdwE09tE%eo`0ePmBJD`ER$?p1$3bDfYhE^6hR-=q%-)$k8btWB0`^ zaF1lpuUn*C#b0j92#gA~PV8c}-FKrdZoWi3^I!4x)p7aXjNBpzc1CZlI2AU&xAT*w z3B88-os$}rEn&sUW9v)DZQg&@K^!?EdDJcECSaZu-|#7(Iq}(~h}IM7rq@>{PP6)+ zRPl>43b6S{?Z>cKl+=f76ZQ6UP!&JP?d z7{O9#hDu@(?XqB(9SAIw5seaf8y6@pOT@sG#tB~xG(^kv50cPWP6FBp=~6Zd4$&!@ z1qUoG@B=#>Vc?oxkH$)(IbM(v-N1ZK<`MzeTLrxyW(4!lf~Efr4NUWc&}c6#uqL^; zA3|!QJ%4GdN~u_n&iUuxYff#=%B^Zn_WsKm!<3wxqT2!I{)#bOAx}lNsv*Kn_hF>J z&%Cg!&eO$T7|+E-9IfiR-dASo9M#;4R~k%z{TP|8kFDK#s%!5|@0yG~T$*83;rM{p z{PI5UUC=$H?BdTowj;mUbf+L5t5b z;|aE5jlYdJRXJ+HJ5k%-y)!SSdCGgGkKaNAOFo`mzqaT7Z+_NZl=lA04rBe{b>umo*p{#=cR{b_ zy#ZW%*(Tb904=EC?PoCz2R{sQ0O&~<4Osf_u^3J+Ubmx~>dC$meg1C6mX^xwEp^!> zvzj$+VpX%_Sd1XmsLP)y{je(xIRy95Mc@-ALmVQYJQaMX)#W!o_}jHRUlQkhNs0;jQ7FX5mMYXXT6z`*%Fd18!HUhmIeB58hbgaU_Gk zLT||0@ua9LI%1_btPz`fXiNhYTT4LBm88yk7`9 zM_48&4H6aPv;n7qoI`+Qht3vK(*@aP=Fng}c*<;cD>~0+53oCI&*#xxngA#fjdz-4 z$bK+oygxW}F%%pBkFzm^03MB(c~>9cl#_$g0p+4WqB&-XU`GuhQD{JLd;o7HR42nB3cS~57U)BLtnRQnEm7u%KNMw`=E7T5eE2ia(eUSd zbPH6J?Bbfg1NVfaA|LfO?!62|n&`%dYBVMoQ9&`#C&vP0~5QCm&~j;o6DKqaQ2?qT~Y?@NgTK&an^FE_FRDsMG97ox;AFJZjXaYhF)oGa|SQHq76AJh)_BVv4D3U@f$bbx|Xuxf-A@=7on)oj=8ld_` zJxqfG7!H$RICz_f$r$4MGKvBie^C$D;sCnCWg0;E!( zoYpWpN~^VCCX&zqgwh0~qj^ThQCeKXaau;pFua!3a2hiu(1O`wu@EMTwqO)P5?T|X z152a^7X(Jf3p$;~!s~zf43f|=yG2A?51SD+iXu26$Tn!aZMgs-15l*2L00iGh?3x= Z^Tm8M3Wv-|vI|uNL2DICWpGT0;@=^Z5&{4K literal 0 HcmV?d00001 From be7ee11578d2f195d889913f03ee396779217bad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20R=C3=B8sdal?= <41650711+andreasrosdal@users.noreply.github.com> Date: Sat, 17 Aug 2024 15:06:15 +0200 Subject: [PATCH 7/7] Add changelog. --- changelogs/2.0.4.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 changelogs/2.0.4.md diff --git a/changelogs/2.0.4.md b/changelogs/2.0.4.md new file mode 100644 index 000000000..bf9dc15cd --- /dev/null +++ b/changelogs/2.0.4.md @@ -0,0 +1,7 @@ +# 2.0.4 + +## Changes + +* Add openpdf-pdfrenderer for exporting PDF files as images. It is a fork of https://github.com/katjas/PDFrenderer +* Add RegionPdfTextExtractor for extracting text on a specific part of a page in a PDF document. +* Add test case for LibrePDF#1199 r = 5 encryption. \ No newline at end of file

    H4*K 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